canopy-appeals Data Model
On this page
Cross-link: canopy-appeals API Reference · Source: migrations/
Tables
| Table | Purpose |
|---|---|
|
Fair-hearing request rows under 7 CFR 273.15. One row per hearing request. Carries the requestor ( |
|
P13 (#1099): household-requested postponements of the 60-day decision SOP. One append-only row per postponement ( |
|
Per-appeal event log. One row per state transition or operator note tied to an appeal — request received, hearing scheduled, hearing held, decision rendered, etc. Carries |
|
The continued-benefits overpayment assessment as a recorded entity — replaces the |
|
Per-issuance itemization under an assessment. |
|
The #1105 worker’s queue (live since MR 4.2), on the #1091 |
|
Intentional Program Violation case file under 7 CFR 273.16. One row per IPV referral. Carries the subject ( |
|
Per-IPV-case event log. One row per state transition or operator note tied to an IPV case. Carries |
|
Per-service transactional outbox (ADR-018), schema single-sourced in |
|
Per-service consumer inbox (#433 / ADR-018 amendment). |
|
Wall-clock window fence for the service’s daily scheduler tick(s) ( |
Cross-service FKs (ADR-001 boundary)
Per ADR-001, canopy-appeals holds no Postgres-level foreign keys to other services. The columns marked FK → canopy-persons / FK → canopy-applications / FK → canopy-notices / FK → program service above are application-level foreign keys: canopy-appeals trusts the upstream services to supply real IDs but does not enforce existence in canopy_appeals. Cross-service IDs the service holds are household_id, requestor_person_id, person_id, application_id, determination_id, notice_id, overpayment_claim_id, hearing_officer_id, referred_by, and recorded_by.
Retention
Continued-benefits records under 7 CFR 273.15(k) and IPV / ADH records under 7 CFR 273.16 are civil-rights / due-process artifacts and carry no archival ceiling — they remain available for the life of the program. Operational retention is the maximum of (a) 3 years from last case activity per 7 CFR 274.6, (b) the disqualification end date plus 3 years for IPV cases, and (c) any pending or active civil-rights / appeal proceeding referencing the row. Rows are not deleted in production. Hash-chained audit linkage (FTI audit, ADR-014) does not apply here — canopy-appeals does not store FTI.
Indexes
-
idx_appeals_household— household-scoped appeal lookup -
idx_appeals_status(partial,WHERE status IN ('pending', 'scheduled')) — 90-day-clock work queue -
idx_appeals_determination— appeals-by-determination lookup (notice cross-link) -
idx_appeal_timeline_appeal— per-appeal timeline scan,(appeal_id, event_date) -
idx_ipv_cases_person— person-scoped IPV history -
idx_ipv_cases_household— household-scoped IPV lookup -
idx_ipv_cases_status(partial,WHERE active = true) — active-case work queue -
idx_ipv_timeline_case— per-IPV-case timeline scan,(ipv_case_id, occurred_at) -
event_outbox_*— the three generated partial outbox indexes (drainer hot path, lease-aware claim, ADR-039 held-skip); documented once in the data-models index -
event_inbox_unprocessed_idx(partial,WHERE processed_at IS NULL) — replay / janitor hot path
Migration files
-
20260401000000_create_appeals_tables.sql— fair-hearing schema (appeal_requests withcontinued_benefits_eligibleGENERATED STORED column, appeal_timeline_events; status + determination indexes) -
20260402000000_create_ipv_tables.sql— IPV / ADH schema (ipv_cases, ipv_timeline_events; status + allegation CHECK constraints) -
20260508000000_create_event_outbox.sql+20260518004851_event_outbox_lease_columns.sql+20260713000000_event_outbox_hold.sql— the generated ADR-039 single-sourced outbox migrations (cargo xtask outbox-migrations --write); documented once in the data-models index -
20260516000000_create_event_inbox.sql— #433 consumer-side inbox (ADR-018 amendment) -
20260720000000_event_inbox_parking.sql— #1089 parked-state columns +idx_event_inbox_parked(generated, single-sourced with the outbox; see the event-delivery protocol) -
20260725000000_action_bound_filing.sql— #1098 (epic &72 MR 2.1):adverse_action_id, the Chart B2cb_*election block, the GENERATEDcontinued_benefits_eligiblereplaced by a plain backfilled column, theprogramCHECK, and the pending-stay / per-action indexes -
20260726000000_decision_withdrawal_lifecycle.sql— #1099 (epic &72 MR 2.2): decision signed/received dates + actor, the typed decision vocabulary (legacy values mapped, unknowns quarantined indecision_legacy/legacy_unmapped), 7 CFR 273.15(j) dismissal fields, the P12 withdrawal lifecycle columns, the P2 cessation record, theappeal_postponementstable, and the P13 60-day due-date recompute for open rows -
20260727000000_cb_assessment_schema.sql— #1104 (epic &72 MR 4.1): thecb_assessments/cb_assessment_lines/assessment_workentity trio — P2 windows, the P6 billable-once partial unique, P7 post-cessation itemization, the one-active-per-appeal partial unique, and the UNIQUE-per-appeal work queue -
20260728000000_assessment_worker_cutover.sql— #1105 (epic &72 MR 4.2):withdrawal_finalizedjoins both cessation-reason CHECK vocabularies (P12 liable disposition records a P2 cessation), plus the acknowledgment scanner’sidx_cb_assessments_unackedpartial index -
20260903000000_cb_assessment_sweep_cursors.sql— #1224 (scale audit M5, §B6-iii): the per-sweep progressing cursors (action_verified_at,claim_reemitted_at) + their NULLS FIRST partial indexes; transactionalCREATE INDEX(notCONCURRENTLY— the sqlx migrator’s advisory lock deadlocks against `CONCURRENTLY’s snapshot wait) -
20260905000000_create_scheduler_runs.sql— the generated #1211 window-fence table (single-sourced incrates/canopy-db/scheduler-migrations/); documented once in the data-models index
All migrations are forward-only per ADR-016.