What it does
An official list is a versioned set of rules (ADR-0016): every quantity cites its source, date and version, and a published version never changes. The app ships DE-2025.10 and EU-72H from @varu/preparedness; the same two are seeded as published rows, and newer versions come from the editor.
An editorial Organization curates a country's list (list_curator, set by the seed or an admin). Its Members with the Org role editor and two-factor sign-in work on a draft: it starts from the country's current version (or the EU fallback), they add, change or remove rules, and the screen shows "changes only" against that base. Request review locks the draft and records the author's sign-off; a second, different editor approves; then either publishes. Publishing inserts the version and its rules and cites both reviewers (RNF12). A correction is a new version id.
Procedures
| Procedure | Who | Failures |
|---|---|---|
lists.current · GET /api/lists/{country} | anyone, no account | NOT_FOUND (no list, not even the EU fallback) |
lists.version · GET /api/lists/{country}/versions/{versionId} | anyone | NOT_FOUND |
lists.changesSince · GET /api/lists/{country}/changes?since= | anyone | NOT_FOUND (unknown since) |
lists.editor.overview, lists.editor.draft | editor with 2FA in the Active Organization | FORBIDDEN, NOT_FOUND |
lists.editor.createDraft | editor with 2FA in the curating Organization | FORBIDDEN (not curated), CONFLICT (version id taken) |
lists.editor.saveRule, lists.editor.removeRule | same | CONFLICT (draft in review or published) |
lists.editor.requestReview | same | CONFLICT (not editing) |
lists.editor.approve | a different editor | CONFLICT (not in review, already signed) |
lists.editor.publish | same | CONFLICT with data: { have, need } under two distinct sign-offs |
Every editor write is audited (list.draft_created, list.rule_changed, list.review_requested, list.signed_off, list.published).
Data and isolation
| Table | Tenant access |
|---|---|
list_curator | select own Organization's rows; written by the system only |
list_draft, list_draft_rule | the curating Organization; a published draft admits no update |
list_sign_off | insert-only, an editor signs only for themself |
list_version, list_version_rule | select for everyone; insert only by the curating Organization with two distinct sign-offs (policy); no UPDATE/DELETE grant, and a trigger refuses UPDATE, DELETE and TRUNCATE for every role |
Migrations: 20261106193939_lists (tables, policies) and 20261106193946_lists_grants_immutable_seed (grants, immutability triggers, the two shipped versions). lists.procedures.test.ts checks that the seeded rows equal the package.
Key files
packages/api/src/features/lists/lists.procedures.tspackages/api/src/features/lists/lists.service.tspackages/db/src/schema/lists.tspackages/preparedness/src/diff.ts("changes only")apps/web/src/features/lists/lists.page.tsx(D-Editor,/official-list)apps/web/src/routes/api/lists/$.ts(plain HTTP GETs)