Skip to main content

Untyped string vocabularies couple frontend and backend

The app is threaded with magic string vocabularies that must match exactly between the browser, the edge functions, and the database — but are enforced by nothing. A one-character drift fails silently (blank labels, empty filters, no-op queries) and only at runtime.

Examples:

  • event_typeuseAuditLog.EVENT_LABELS hardcodes 13 Portuguese labels keyed by event strings the backend must emit verbatim (phase_changed, gate_approved, dossier_export_created, …). Unknown types fall back to raw snake_case.
  • Drifting filter subsetCaseAuditLog's EVENT_TYPES dropdown lists only 9 of the 13, so portal_link_* and dossier_export_* events can never be filtered even though they render.
  • entity_type — filter list is CASE, CHECKLIST_ITEM, DOCUMENT, EVIDENCE, PORTAL, but code writes DOSSIER_EXPORT (not in the list → unfilterable) and defaults to CASE. Casing must match exactly.
  • metadata keysMetadataDisplay special-cases {from, to, reason, title, phase}; if the backend writes old/new instead of from/to, the "A → B" display vanishes into a raw JSON blob.
  • Dossier export status — UI polls only while some export is "generating" and maps pending/generating/ready/failed to badges; different backend strings mean polling never stops/starts.
  • Checklist status — dossier offers only items with status === "approved"; a different literal yields an empty checklist silently.
  • Edge-function names & body shape"generate-dossier", "log-auth-event", "invite-user", "setup-company" are string-invoked; bodies are snake_case (case_id, include_audit_log, …) manually remapped from camelCase in the hooks.
  • Every case-status write casts as any (e.g. status: "ARCHIVED" as any), bypassing the TS enum — so even the type system doesn't catch drift.

The tacit assumption: all these vocabularies stay in sync by discipline. There is no shared schema, codegen, or test.

Rebuild implication

Define these enums once (shared contract / generated types) and derive labels, filters, and validation from that single source. Server should reject unknown values, not the UI silently drop them.