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
Context
Raised during review of #1732: audit check logic uses
projectConfig(e.g.maxPersonAge,minReviewPersonAge), but the admin UI displays messages viat('audits:' + errorCode)from staticlocales/*/audits.json— not fromaudit.message.Today:
errorCodeis the stable identifier (DB primary key component, i18n key).audit.messageis persisted insv_audits.messagebut not displayed inAuditDisplay/ValidationAuditFilter.message(check code) andaudits.json(UI).Two parallel pipelines (do not conflate)
Pipeline 1 — Named audit checks
PersonAuditChecks.ts,HomeAuditChecks.ts, etc. These checks do not interact withconvertParamsErrorsToAudits.Pipeline 2 —
convertParamsErrorsToAudits(validateParams failures)convertParamsErrorsToAudits:Error[]fromvalidateParams(via survey object factories whencreatefails).PersonAuditChecks, etc.).errorCodefromslugify(error.message)and copieserror.messageintoaudit.message.Intended role:
validateParamsis 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.ageviaisPositiveInteger(see #1725 / validateParams), without a dedicatedP_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
errorCodeis acceptable for this edge-case path.Impact of proposed cleanup
convertParamsErrorsToAuditsmessagefrom named checks (P_I_AgeTooHigh, etc.)errorCodekeyssv_audits.messagecolumn entirelyProposed work (in scope)
1. i18n interpolation in admin UI — named audit checks only
locales/*/audits.json, e.g."P_I_AgeTooHigh": "Person age is too high (max {{maxPersonAge}})".projectConfiginAuditDisplayandValidationAuditFilter(and any other audit message renderers).packages/evolution-backend/src/services/audits/auditChecks/README.md.2. Cleanup
audit.messageon named audit checksmessage(redundant witherrorCode+ locales). No impact onconvertParamsErrorsToAudits.Audit.messageinevolution-common(currently says "i18n key" — incorrect).Out of scope / low priority (for now)
convertParamsErrorsToAuditsslug codes) — edge-case data integrity signal, not reviewer-facing UX priority.convertParamsErrorsToAuditsto stable explicit error codes.sv_audits.messagecolumn.Related