canopy-snap Data Model
On this page
Cross-link: canopy-snap API Reference · Source: migrations/
Tables
| Table | Purpose |
|---|---|
|
SNAP application intake records. One row per application received from canopy-eligibility. Carries the orchestrator’s |
|
Signed SNAP determinations. Carries the lifecycle |
|
Immutable determination input snapshots (T1-10). One row per determination (PK = FK |
|
Per-value DEK store for crypto-shred redaction. One row per per-determination DEK: |
|
Legacy IEVS verification outcomes — |
|
Categorical-eligibility participation records per PAMMS 3030 / 7 CFR 273.2(j)(2)+(j)(3). One row per |
|
Student-exclusion screening per 7 CFR 273.5. |
|
ABAWD time-limit tracking per 7 USC §2015(o) / 7 CFR 273.24. One row per ABAWD; |
|
Monthly ABAWD work-activity reports — one row per |
|
Annual discretionary-exemption pool per fiscal year (7 CFR 273.24(g)). |
|
Per-person discretionary-exemption grants. FK to |
|
FNS-approved geographic waiver areas (7 CFR 273.24(f)). |
|
36-month ABAWD time clock as a single row per |
|
Special-situations disqualification screenings — drug felony (7 CFR 273.11(m)), fleeing felon (273.11(n)), probation/parole violator (273.11(n)), striker (273.11(e)). Discriminator: |
|
IEVS income-match results per |
|
Discrepancies between self-reported and IEVS-verified income. FK to |
|
SAVE-source immigration-status outcomes. Per ADR-004, the raw SAVE query lives transiently in canopy-verification; only the eligibility-relevant outcome lands here. Carries |
|
Transitional SNAP (TSNAP) certification windows when a household exits TANF cash assistance. Five months of frozen benefits per 7 CFR 273.26. Carries the |
|
Per-program overpayment claims. Byte-identical schema across all five program services. |
|
One or more repayment plans per claim. |
|
Append-only ledger of recoupment events. FK to |
|
Append-only principal corrections. FK to |
|
Audit + idempotency record of a worker-actioned overpayment recompute-from-snapshot — one row per recompute attempt that resolved a corpus. Unique |
|
Per-service transactional outbox (ADR-018), schema single-sourced in |
|
Per-service consumer inbox (#433 / ADR-018 amendment). |
Cross-service FKs (ADR-001 boundary)
Per ADR-001, canopy-snap holds no Postgres-level foreign keys to other services. The DB-level FKs in this schema are intra-database only: snap_determinations.application_id → snap_applications(id), snap_determinations.previous_determination_id → snap_determinations(id) (the ADR-028 §57 supersession self-FK), determination_snapshots.determination_id → snap_determinations(id), abawd_monthly_activity.abawd_tracking_id → abawd_tracking(id), abawd_discretionary_exemption_grants.exemption_pool_id → abawd_discretionary_exemptions(id), ievs_discrepancies.match_result_id → ievs_match_results(id), repayment_plans.overpayment_claim_id → overpayment_claims(id), recoupment_ledger.overpayment_claim_id → overpayment_claims(id), and recoupment_ledger.repayment_plan_id → repayment_plans(id). Every other UUID column referencing a foreign service — household_id / person_id (canopy-persons), application_id on snap_applications and ievs_* and citizenship_verifications (canopy-applications), overpayment_claims.determination_id (this service’s own snap_determinations but unconstrained because the column also accepts cross-service determinations during overpayment back-rebill flows) — is application-level only.
Retention
canopy-snap does NOT hold FTI. IEVS-sourced wage / UI / SSA-income data is a separate authorization (7 USC §2025(e); SNAP-specific CMA with SSA) and lives in ievs_match_results, ievs_discrepancies, and ievs_verification_data — sited in canopy-snap per ADR-004 and never replicated to other services' databases. IEVS retention follows the FNS schedule (3-year minimum for access logs and match results). SNAP record retention proper is 7 CFR 272.1(f): 3 years from the end of the fiscal year. The longer of the two governs; archive moves are operator-driven, not migration-driven (ADR-016 forward-only).
Indexes
-
idx_snap_applications_{household,application,status}— application list endpoints -
idx_snap_determinations_{application,household,status,determined_at}— determination list + audit replay -
idx_snap_determinations_previous_unique— partial UNIQUE onprevious_determination_id WHERE NOT NULL(ADR-028 §57: a one-to-one supersession chain — at most one determination supersedes a given prior) -
idx_determination_snapshots_as_of— input-snapshot lookup by evaluation date (ADR-028) -
idx_ievs_verification_data_{person,source}— legacy IEVS lookups -
idx_snap_participations_{person,household,program}andidx_unique_participation(unique, partial,WHERE active = true) — categorical eligibility -
idx_snap_student_{person,household}— student-exclusion lookups -
abawd_tracking_person_active(unique, partial,WHERE active = true),idx_abawd_tracking_{household,status}— ABAWD live state -
abawd_activity_month(unique,(person_id, benefit_month)) — monthly activity report uniqueness -
idx_abawd_clock_person,idx_abawd_clock_person_period(unique) — 36-month time clock -
snap_disqual_screening_household_idx,snap_disqual_screening_type_idx(partial,WHERE active = true) — disqualification screening lookups -
ievs_results_{application,person,source}andidx_unique_ievs_match(unique) — IEVS match results -
ievs_discrepancies_{application,person,status}(partial on pending) — discrepancy worklist -
idx_citizenship_verification_{application,person}— citizenship/SAVE lookups -
idx_tsnap_{household,end_date}— TSNAP certification listings -
overpayment_claims_status,repayment_plans_by_claim,recoupment_ledger_by_claim— overpayment lifecycle queries -
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
-
20260326000000_create_snap_tables.sql— original schema (snap_applications,snap_determinations,ievs_verification_data) -
20260328000000_create_snap_categorical.sql—snap_program_participations+snap_student_statusfor categorical eligibility (7 CFR 273.2(j)) -
20260329000000_create_abawd_tables.sql— ABAWD core (abawd_tracking,abawd_monthly_activity,abawd_discretionary_exemptions,abawd_discretionary_exemption_grants,abawd_waiver_areas) -
20260329000001_create_disqualification_screenings.sql—snap_disqualification_screenings(drug felony / fleeing felon / probation+parole / striker) -
20260330000000_create_ievs_tables.sql—ievs_match_results+ievs_discrepancies(ADR-004; replaces / augments legacyievs_verification_data) -
20260330000001_create_citizenship_verification.sql—citizenship_verificationsfor SAVE outcomes (ADR-004 — raw SAVE stays in canopy-verification) -
20260402000000_add_constraints.sql— uniqueness fixes from test-coverage audit (idx_unique_participation,idx_unique_ievs_match) -
20260407000000_create_abawd_time_clock.sql— PAMMS 3355 15-status time clock JSONB -
20260414000000_create_tsnap_certifications.sql— TSNAP transitional benefits (7 CFR 273.26) -
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 -
20260510000001_create_overpayments.sql— canonical overpayment schema (claims, plans, ledger) per PAMMS 9000 / 7 CFR 273.18 -
20260516000000_create_event_inbox.sql— #433 consumer-side inbox (ADR-018 amendment) -
20260620000000_add_discrepancy_resolved_by_sub.sql—ievs_discrepancies.resolved_by_subworker-attribution column (T1-9 #677) -
20260621000000_create_determination_snapshots.sql—snap_determinations.snapshot_hashcolumn + the immutabledetermination_snapshotstable + its append-only trigger (T1-10 #678; ADR-028) -
20260622000000_add_previous_determination_id.sql—snap_determinations.previous_determination_idsupersession self-FK + the one-to-one partial-unique index (T2-1 Half B #683; ADR-028 §57) -
20260624140000_create_redaction_keys.sql— the per-serviceredaction_keystable + its one-way-tombstone trigger (T2-6 #687, ADR-036) -
20260627000000_create_overpayment_recomputes.sql— theoverpayment_recomputesaudit/idempotency table for replay-based overpayment recompute (T2-8 #681, ADR-028 §70); unique(baseline_determination_id, correction_as_of)+ a(household_id, covered_period_start, covered_period_end)overlap-guard index -
20260727000000_claim_provenance_adjustments.sql— #1104 (epic &72 MR 4.1): claim provenance columns + partial UNIQUEs (assessment_id,source_event_id), the void path, and the append-onlyclaim_adjustmentstable; canonical copy incrates/canopy-overpayments/migrations/, byte-parity asserted by the crate’s tests -
20260630000000_add_ievs_resolved_fact_id.sql—ievs_discrepancies.resolved_fact_idnullable column: the canopy-personsfact_idthe worker authored on accept, a race-free discrepancy↔fact link + retry idempotency (#876, T1-9 #677); no index / no cross-service FK (ADR-001) -
20260902000000_overpayment_claims_keyset_idx.sql— #1222 (scale audit M11):overpayment_claims_keyset (created_at DESC, id DESC)serving the roll-up keyset page; transactionalCREATE INDEX(notCONCURRENTLY— the sqlx migrator’s advisory lock deadlocks againstCONCURRENTLY’s snapshot wait); canonical copy in `crates/canopy-overpayments/migrations/, byte-parity asserted by the crate’s tests
All migrations are forward-only per ADR-016.
snap_determinations.trigger (#1213, migration 20261121000000_snap_determinations_trigger.sql)
Nullable TEXT, CHECK-pinned to the six D9 kebab-case spellings (an always-running test mirrors the
CHECK against DeterminationTrigger::ALL). Signed on the envelope, stored on the row, carried
additively on the read DTO, hearing view, and determination.completed.snap.