● Zion Boggan
repos/Docket/docs/ARCHITECTURE.md
zionboggan.com ↗
68 lines · markdown
History for this file →
1
# Docket -  Architecture
2
 
3
## Shape
4
```
5
            POLLERS (Python)                 API + WEB (Next.js)
6
  Congress.gov ─┐                          ┌─ Next.js app (PWA, dark-first)
7
  GovInfo ──────┤                          │   /register (feed)  /bill/[id]
8
  USAspending ──┤→ normalize → Postgres ──→│   /spending  /states
9
  Treasury ─────┤   (actions, bills,       │   /how-we-pick  /who-pays
10
  House/Senate ─┤    awards, members,      │
11
  OpenStates ───┘    votes, raw_events)    └─ /api (read) → events feed
12
            │                                        │
13
            └── change-detection ──→ events ──→ alerts (ntfy + web-push)
14
```
15
 
16
## Services
17
1. **ingest** (Python) -  one poller module per source (`pollers/congress.py`, `usaspending.py`, `treasury.py`, `govinfo.py`, `votes_house.py`, `votes_senate.py`, `openstates.py`), each idempotent, rate-budget aware, with Congress.gov scraper fallback. A scheduler (cron/APScheduler) runs them at the cadences in `DATA_SOURCES.md`.
18
2. **change-detection** -  diffs each poll against stored `updateDate`/hash, writes normalized `actions` + emits `events`.
19
3. **summaries** (Phase 2) -  extraction-template pipeline; banned-words + Polarization-Index gate before publish. MVP ships structured fields only.
20
4. **web/api** (Next.js) -  read API over SQLite/Postgres for the feed + entity pages; the brand-pack UI.
21
5. **alerts** -  topic/agency/threshold subscriptions → ntfy + web-push. No party-based subscriptions.
22
 
23
## Data model (Postgres, draft)
24
- `bills` (id, source, externalId, congress/session, number, title, sponsor_id, status, policy_area, updated_at, source_url)
25
- `actions` (id, bill_id?, source, action_type, action_date, chamber, text, dollar_amount?, affected_estimate?, source_url) -  the spine of the feed
26
- `votes` (id, bill_id, chamber, date, yea, nay, present, result, source_url) + `vote_positions` (vote_id, member_id, position)
27
- `members` (id, name, party, state, chamber, source_url)
28
- `awards` (id, source, externalId, agency, recipient, amount, action_date, program, source_url)
29
- `fiscal` (metric, date, value, source_url) -  debt/deficit/outlays
30
- `states` (code, name, openstates_coverage_level, last_seen) -  powers the coverage map
31
- `events` (id, ref_type, ref_id, action_date, dollar_amount, affected_estimate, action_type) -  the ranked feed source (rule #3: ONLY these fields feed ranking)
32
- `raw_events` (source, externalId, payload jsonb, fetched_at) -  provenance
33
- `subscriptions` (user_id, kind[topic|agency|threshold|bill|state|member], value)
34
 
35
### Full-spectrum additions (2026-06-26)
36
- `amendments` (id, congress, type[HAMDT|SAMDT], number, bill_id, sponsor_id, status, agreed_method[recorded|voice|uc|null], text?, source_url)
37
- `bill_versions` (id, bill_id, version_code[ih|rh|eh|eas|enr|…], govinfo_package_id, fetched_at, text_ref) -  the diff inputs
38
- `bill_diffs` (id, bill_id, from_version, to_version, section_id, change[added|removed|amended], snippet, rider_flag bool, source_url) -  powers "what got slipped in"
39
- `procedural_events` (id, bill_id?, kind[voice_vote|unanimous_consent|cloture|suspension|mtr|discharge], date, chamber, detail, members_jsonb?, source_url) -  parsed from CREC; `members` null when no individual record exists
40
- `lobbying` (id, registrant, client, covered_bill_id?, amount_range, period, source_url) -  LDA.gov
41
- `executive_actions` (id, type[eo|nprm|final_rule|notice], title, agency, fr_doc_number, date, source_url) -  Federal Register
42
- `apportionments` (id, agency, account, appropriated, apportioned, status[released|delayed|withheld], date, source_url→.max.gov) -  the impound tracker
43
- `state_coverage` (state, source[openstates|legiscan], data_type, last_scrape, confidence[ok|stale|missing]) -  the honesty layer
44
 
45
**Hard constraint:** every user-facing row exposes a non-null `source_url` whose host is allowlisted (neutrality rule #1, enforced by test). For aggregator-sourced rows (OpenStates/LegiScan/OpenOMB/Lambda), `source_url` points to the **underlying official record**, not the aggregator (DATA_SOURCES.md third-party rule).
46
 
47
### What-changed pipeline (the signature feature)
48
Per bill: `/related/BILLS-{id}` → fetch each version XML → section-parse + align (id + fuzzy heading) → diff → write `bill_diffs` (added/removed/amended), run rider keyword regex on appropriations-bill added sections → `rider_flag`. Surfaced as a "What changed / what was added" view + a per-section diff. Conference reports diffed against last engrossed version. Voice-vote/UC additions labeled "no individual record."
49
 
50
## Ranking (neutrality rule #3)
51
`score(event) = f(actionDate, dollarAmount, affectedEstimate, actionType)` -  no engagement/news/social inputs. Pure function, unit-tested to reference only those four fields.
52
 
53
## Build/run hosts
54
- **Frontend:** Next.js dev server; `npm run dev` from the repo root.
55
- **Backend:** Python ingest; `python -m ingest.run` from `services/ingest/`.
56
- **Database:** SQLite for dev/staging; Postgres for production (Phase 1+).
57
- **Deploy target:** Cloudflare front + self-hosted API backend.
58
 
59
## Phases (see PLAN.md §8 for detail)
60
0. ✅ Brand + clickable shell (fake data) - DONE
61
1. Federal ingest spine → real feed (read-only) -  DONE backend (USAspending/votes); **NEXT: wire read-API so frontend shows real data**
62
2. **Full bills/laws**: Congress.gov bills + GovInfo full text → bill pages + lookup/search (federal)
63
3. **"What got slipped in"**: bill_versions + diff pipeline + rider flags -  the signature feature
64
4. **Closed-door layer**: CREC parsing (voice votes/UC/procedural) + Federal Register + lobbying + apportionment impound tracker
65
5. **State granular**: OpenStates + LegiScan + per-state confidence scores
66
6. **Accessibility modes**: Readable/Light + Plain Mode + plain-language summaries (docs/ACCESSIBILITY.md)
67
7. Alerts + accounts (topic/state/member/bill follows)
68
8. Trust pages + launch