canopy-enrollment Data Model
On this page
Cross-link: canopy-enrollment API Reference · Source: migrations/
Tables
| Table | Purpose |
|---|---|
|
One row per SNAP household enrollment created off an approved determination. Carries the |
|
Per-month issuance ledger. One row per (enrollment, benefit_month) — enforced by |
|
THE adverse action (epic &72 plan §Design spine): its id IS the |
|
Versioned notice records — the action’s CURRENT legal dates are the latest version with |
|
One row per (action, appeal) with MONOTONIC transitions enforced by the store’s guarded upsert: |
|
Append-only receipt ledger for the action (a DB trigger rejects UPDATE/DELETE) — what arrived, when, from where; consumers derive state from links/status, signals are the audit receipts. |
|
Per-service transactional outbox (ADR-018), schema single-sourced in |
|
Per-service consumer inbox (#433 / ADR-018 amendment). |
|
Per- |
|
Append-only reopen receipts for the NARROW Chart 3730.1 periodic-report reopen: one row per reopened ENACTED |
|
Wall-clock window fence for the service’s daily scheduler tick(s) ( |
Cross-service FKs (ADR-001 boundary)
Per ADR-001, canopy-enrollment holds no Postgres-level foreign keys to other services. The columns marked FK → canopy-persons / FK → canopy-snap / FK → canopy-applications above are application-level foreign keys: canopy-enrollment trusts the upstream (canopy-eligibility orchestrator + canopy-snap) to supply real IDs but does not enforce existence in canopy_enrollment. Cross-service IDs the service holds are household_id, determination_id, and application_id.
Retention
SNAP issuance ledger falls under 7 CFR 274.6 — case records (including issuance history) must be retained for 3 years from the last activity in the case. snap_benefit_issuances is the authoritative ledger for the 3-year window; rows are not deleted in production. partial_retention + retained_through on snap_enrollments drive PAMMS 2415 mid-month closure semantics per #407 so downstream overpayment math can distinguish retained vs recoverable months without re-deriving from the issuance ledger.
Indexes
-
idx_snap_enrollments_household— household-scoped enrollment lookup -
idx_snap_enrollments_status(partial,WHERE status='pending_issuance') — issuance-pipeline due-queue -
snap_enrollments_one_live_per_household(partial UNIQUE,WHERE active AND status IN ('pending_issuance','active','suspended')) — #1130: the one-live-enrollment-per-household invariant, structural (the reopen successor gate and the create paths are check-then-act without it) -
idx_snap_issuances_enrollment_month— UNIQUE; enforces one issuance row per (enrollment, benefit_month) -
idx_snap_issuances_expiry(partial,WHERE expunged_at IS NULL AND issuance_status='issued') — expungement-sweeper hot path -
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
-
20260730000000_enrollment_reopens.sql— #1108 (epic &72 MR 5.3): theenrollment_reopensappend-only reopen receipts,UNIQUE(adverse_action_id) -
20260801000000_one_live_enrollment_per_household.sql— #1130: deterministic duplicate resolution (keep earliest live per household, deactivate + revision-bump the rest) + thesnap_enrollments_one_live_per_householdpartial unique -
20260729000000_periodic_report_completion_tombstones.sql— #1107 (epic &72 MR 5.2):periodic_report_completionstombstone table, PK(certification_id, generation) -
20260401000000_create_enrollment_tables.sql— original schema (snap_enrollments, snap_benefit_issuances; status / type / amount CHECK constraints; lifecycle + expungement indexes) -
20260723000000_adverse_action_entity.sql— #1095 adverse-action entity (the four tables above +snap_enrollments.lifecycle_revision+ the first-of-monthbenefit_monthCHECK) -
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 -
20260511000000_add_partial_retention_to_snap_enrollments.sql— #407 / PAMMS 2415 mid-month closure columns (partial_retention,retained_through) -
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) -
20260724000000_head_of_household.sql— #1096 (epic &72 MR 1.2):snap_enrollments.head_of_household_person_id(the legal-recipient snapshot source) + the P8 one-open-action-per-enrollment partial unique (idx_one_open_action_per_enrollment) -
20260728000000_notice_evidence_binding.sql— #1101 (epic &72 MR 3.1): partial UNIQUE(adverse_action_id, notice_id)making the notice.generated/notice.dispatched evidence upserts order-independent -
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.