feat: per-user notifications (ntfy + RSS), deduplicated actions, backfill task

Notifications:
- New /notifications page accessible to all users (ntfy + RSS config)
- ntfy now supports no-auth, Bearer token, and HTTP Basic auth (for ACL-protected self-hosted servers)
- RSS enabled/disabled independently of ntfy; token auto-generated on first GET
- Notification settings removed from admin-only Settings page; replaced with link card
- Sidebar adds Notifications nav link for all users
- notification_dispatcher.py: fan-out now marks RSS events dispatched independently

Action history:
- Migration 0012: deduplicates existing bill_actions rows and adds UNIQUE(bill_id, action_date, action_text)
- congress_poller.py: replaces existence-check inserts with ON CONFLICT DO NOTHING (race-condition safe)
- Added backfill_all_bill_actions task (no date filter) + admin endpoint POST /backfill-all-actions

Authored-By: Jack Levy
This commit is contained in:
Jack Levy
2026-03-01 12:04:13 -05:00
parent 91790fd798
commit 2e2fefb795
22 changed files with 1006 additions and 164 deletions

View File

@@ -76,3 +76,89 @@
- [ ] **Source Viewer Option B** — in-app bill text viewer with cited passage highlighted and scroll-to-anchor. Deferred pending UX review of Option A (GovInfo link).
- [ ] **Raw Diff Panel** — Python `difflib` diff between stored document versions, shown as collapsible "Raw Changes" below amendment brief. Zero API calls. Deferred — AI amendment brief is the primary "what changed" story.
- [ ] **Shareable Collection Subscriptions** — "Follow this collection" mechanic so other users can subscribe to a public collection and get its bills added to their feed.
- [ ] Pocket Veto mode (follow stance) — toggle on a bill to treat it as “I dont want this to pass”; adds to watchlist and triggers milestone alerts (committee report-out, calendared, vote scheduled, passed chamber, etc.)
- [ ] Pocket Veto notification rules — alert only on advancement milestones + failure outcomes (failed committee / failed floor / stalled)
- [ ] Follow modes — support Neutral (normal follow) + Pocket Veto now; optional Pocket Boost later
- [ ] UI: FollowButton becomes FollowMode selector (Neutral / Pocket Veto) with explanation tooltip
### PocketVeto function
#### How it should work (so its useful and not cringey)
Instead of “follow/unfollow,” each bill gets a **Follow Mode**:
- **Follow** (neutral): “Keep me posted on meaningful changes.”
- **Pocket Veto** (oppose): “Alert me if this bill is advancing toward passage.”
- (Optional later) **Pocket Boost** (support): “Alert me when action is needed / when its in trouble.” also suggest an action the user can take to let their representatives know that you support this bill.
For Pocket Veto specifically, the key is **threshold alerts**, not spam:
- **Committee referral**
- **Committee hearing scheduled**
- **Markup scheduled**
- **Reported out of committee**
- **Placed on calendar**
- **Floor vote scheduled**
- **Passed chamber**
- **Conference / reconciliation activity**
- **Sent to President**
- **Signed / Vetoed**
And the “failed” side:
- **Failed in committee**
- **Failed floor vote**
- **Stalled** (no action for X days while similar bills move)
#### Why its valuable for “normal people”
Most people dont want to follow politics continuously. They want:
- “Tell me if the bad thing is about to happen.”
Thats exactly what Pocket Veto mode does.
#### Guardrail to keep it non-partisan / non-toxic
Make it explicit in UI copy:
- Its a **personal alert preference**, not a moral label.
- It doesnt publish your stance unless you share it.
#### Data model addition (simple)
Add fields to `follows` (or a new table):
- `follow_mode`: `neutral | pocket_veto | pocket_boost`
- `alert_sensitivity`: `low | medium | high` (optional)
Then alert rules can be:
- neutral: material changes
- pocket_veto: only “advancing toward passage” milestones
- pocket_boost: “action points” + milestones