Skip to content

Audits: i18n interpolation in admin UI and cleanup of audit.message #1741

Description

@kaligrafy

Context

Raised during review of #1732: audit check logic uses projectConfig (e.g. maxPersonAge, minReviewPersonAge), but the admin UI displays messages via t('audits:' + errorCode) from static locales/*/audits.json — not from audit.message.

Today:

  • errorCode is the stable identifier (DB primary key component, i18n key).
  • audit.message is persisted in sv_audits.message but not displayed in AuditDisplay / ValidationAuditFilter.
  • Named audit checks duplicate text in message (check code) and audits.json (UI).

Two parallel pipelines (do not conflate)

Pipeline 1 — Named audit checks

PersonAuditChecks.P_I_AgeTooHigh(context)
  → { errorCode: 'P_I_AgeTooHigh', message: '...', ... }
  → sv_audits
  → UI: t('audits:P_I_AgeTooHigh')   // message is ignored

PersonAuditChecks.ts, HomeAuditChecks.ts, etc. These checks do not interact with convertParamsErrorsToAudits.

Pipeline 2 — convertParamsErrorsToAudits (validateParams failures)

Person.create(attrs) fails
  → errors: [ new Error('Person validateParams: age should be a positive integer') ]
  → convertParamsErrorsToAudits(errors, { objectType, objectUuid })
  → { errorCode: slugify(message), message: error.message, ... }
  → sv_audits
  → UI: t('audits:person-validateparams-age-should-be-a-positive-integer')  // usually missing from audits.json

convertParamsErrorsToAudits:

  • Reads Error[] from validateParams (via survey object factories when create fails).
  • Does not read named audit check registries (PersonAuditChecks, etc.).
  • Generates errorCode from slugify(error.message) and copies error.message into audit.message.

Intended role: validateParams is a pre-check that response data and types are structurally valid before survey objects are built. In normal operation (respondent flows through the legitimate UI), these errors should not occur — real-time validation and typed widgets prevent invalid values from being saved. They mainly surface when stored JSON has been altered outside the UI (manual DB edits, bad imports, API tampering, legacy/corrupt data).

This is the path that covers cases like invalid person.age via isPositiveInteger (see #1725 / validateParams), without a dedicated P_I_* check — because the person may not exist in the survey object tree at all.

Priority note: improving display or i18n for validateParams slug errors is not a priority for now. English slug / raw errorCode is acceptable for this edge-case path.

Impact of proposed cleanup

Change Impact on named audit checks Impact on convertParamsErrorsToAudits
Remove message from named checks (P_I_AgeTooHigh, etc.) None on logic; removes redundancy None — separate pipeline
i18n interpolation in admin UI Fixes display for named errorCode keys Not planned — see priority note above
Drop sv_audits.message column entirely None on named checks Would affect what is stored for pipeline 2; defer until needed

Proposed work (in scope)

1. i18n interpolation in admin UI — named audit checks only

  • Support placeholders in locales/*/audits.json, e.g. "P_I_AgeTooHigh": "Person age is too high (max {{maxPersonAge}})".
  • Pass interpolation context from projectConfig in AuditDisplay and ValidationAuditFilter (and any other audit message renderers).
  • Document the convention in packages/evolution-backend/src/services/audits/auditChecks/README.md.

2. Cleanup audit.message on named audit checks

  • For named audit checks: stop requiring / setting message (redundant with errorCode + locales). No impact on convertParamsErrorsToAudits.
  • Fix outdated JSDoc on Audit.message in evolution-common (currently says "i18n key" — incorrect).

Out of scope / low priority (for now)

  • validateParams audit display or translation (convertParamsErrorsToAudits slug codes) — edge-case data integrity signal, not reviewer-facing UX priority.
  • Refactoring convertParamsErrorsToAudits to stable explicit error codes.
  • Dropping sv_audits.message column.
  • Migrating existing DB rows or renaming stored messages.
  • Changing real-time widget validations (separate system).

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions