- bill_notes table (migration 0014): user_id, bill_id, content, pinned,
created_at, updated_at; unique constraint (user_id, bill_id)
- BillNote SQLAlchemy model with back-refs on User and Bill
- GET/PUT/DELETE /api/notes/{bill_id} — auth-required, one note per (user, bill)
- NotesPanel component: collapsible, auto-resize textarea, pin toggle,
save + delete; shows last-saved date and pin indicator in collapsed header
- Pinned notes render above BriefPanel; unpinned render below DraftLetterPanel
- Guests see nothing (token guard in component + query disabled)
Co-Authored-By: Jack Levy
216 lines
12 KiB
Markdown
216 lines
12 KiB
Markdown
## Roadmap
|
||
|
||
- [x] Docker Stack — PostgreSQL, Redis, FastAPI, Celery, Next.js, Nginx fully containerized
|
||
- [x] Bill Polling — Congress.gov incremental sync every 30 min, filtered to legislation that can become law
|
||
- [x] Document Fetching — GovInfo bill text retrieval with smart truncation for token budgets
|
||
- [x] LLM Analysis — Multi-provider AI briefs (OpenAI, Anthropic, Gemini, Ollama) with amendment diffing
|
||
- [x] News Correlation — NewsAPI + Google News RSS articles linked to bills via topic tags
|
||
- [x] Trend Scoring — Composite zeitgeist score (0–100) from NewsAPI + Google News + Google Trends, nightly
|
||
- [x] Full-text Search — PostgreSQL tsvector search across bills and members
|
||
- [x] Follows — Per-user follows for bills, members, and topics
|
||
- [x] Dashboard — Personalized feed + trending bills
|
||
- [x] Multi-user Auth — JWT email/password auth, admin role, user management panel
|
||
- [x] Admin Panel — LLM provider switching, pipeline stats, manual task triggers
|
||
- [x] Citations — Every AI brief key point and risk cites the section + verbatim quote from bill text
|
||
- [x] Citation UI — § chips expand inline to show quote + GovInfo source link
|
||
- [x] Party Badges — Solid red/blue/slate badges readable in light and dark mode
|
||
- [x] Nginx DNS Fix — Resolver directive prevents stale-IP 502s after container restarts
|
||
- [x] Sponsor Linking — Poller fetches bill detail for sponsor; backfill task fixes existing bills
|
||
- [x] Member Search — "First Last" and "Last, First" both match via PostgreSQL split_part()
|
||
- [x] Search Spaces — Removed .trim() on keystroke that ate spaces in search inputs
|
||
- [x] Mobile UI — Responsive layout: sidebar collapses, cards stack, touch-friendly controls
|
||
- [x] Member BIO & Photo — Display member headshots (photo_url already stored, not yet shown in UI)
|
||
- [x] Bill Action Fetching — BillAction table populated via Congress.gov actions endpoint; nightly batch + event-driven on bill change
|
||
- [x] What Changed (Amendment Briefs) — BriefPanel surfaces amendment briefs with "What Changed" badge and collapsible version history
|
||
- [x] Source Viewer — "View source" link in § citation popover opens GovInfo document in new tab (Option A; Option B = in-app highlighted viewer deferred pending UX review)
|
||
- [x] Admin Reprocess — POST /api/admin/bills/{bill_id}/reprocess queues document + action fetches for a specific bill
|
||
- [x] LLM Model Picker — live model list fetched from each provider's API; custom model name fallback
|
||
- [x] Admin Health Panel — bill pipeline breakdown table, external API health tests with latency, manual controls with status dots + task polling
|
||
- [x] Chamber Badges — amber/gold for Senate, slate/silver for House; applied on bill cards and detail pages
|
||
- [x] Action History Fallback — shows latest_action_date/text while full history loads; full timeline once fetched
|
||
- [x] Backfill All Actions — admin task to fetch action history for all pre-existing bills
|
||
- [x] Notifications (Phase 1) — ntfy dispatch, RSS feed, per-user settings UI, 5-min dispatcher beat task
|
||
- [x] Brief Regeneration UI — admin button to delete existing briefs for a bill and re-queue LLM processing. Useful for improving citation/diff logic without a full re-poll. (Backend reprocess endpoint already exists.)
|
||
- [x] Follow Modes — `neutral | pocket_veto | pocket_boost` on the `follows` table; FollowButton mode selector with descriptions and tooltips
|
||
- [x] Public Browsing — unauthenticated guests browse bills, members, topics, and trending dashboard; AuthModal gates follow/interactive actions; sidebar and nav adapt to guest state
|
||
- [x] Draft Letter Generator — collapsible panel on bill detail pages; select up to 3 cited brief points, stance auto-fills from follow mode, recipient derived from chamber, ZIP optional and never stored; calls configured LLM provider
|
||
- [x] Bill Text Status Indicators — BillCard shows Brief / Pending / No text badge; backed by a single batch query on the list endpoint
|
||
|
||
---
|
||
|
||
## To Do
|
||
|
||
---
|
||
|
||
### Phase 2 — High Impact *(can run in parallel after Phase 1)*
|
||
|
||
- [x] **Change-driven Alerts** — milestone keywords expanded (markup, conference, referral tier); topic followers now receive bill_updated milestone events; committee referral events delivered to pocket_veto/boost but suppressed for neutral; all three follow types covered for both tiers.
|
||
- [x] **Fact vs Inference Labeling** — `label: "cited_fact" | "inference"` on every cited key_point and risk; prompt engineering updated for all providers; "Inferred" badge in citation UI; backfill task for existing briefs.
|
||
|
||
---
|
||
|
||
### Phase 3 — Personal Workflow
|
||
|
||
- [ ] **Collections / Watchlists** — `collections` (id, user_id, name, slug, is_public) + `collection_bills` join table. UI to create/manage collections and filter dashboard by collection. Shareable via public slug URL (read-only for non-owners).
|
||
- [x] **Personal Notes** — `bill_notes` table (user_id, bill_id, content, pinned). Collapsible panel on bill detail page. Pinned notes float above the brief. Private — auth-gated, never shown to guests.
|
||
- [ ] **Shareable Links** — UUID token on briefs and collections → public read-only view, no login required. Same token system for both. No expiry by default. UUID (not sequential) to prevent enumeration.
|
||
- [x] **Weekly Digest** — Celery beat task (Monday 8:30 AM UTC), queries followed bills for changes in the past 7 days, formats a low-noise summary, dispatches via ntfy + RSS. Admin can trigger immediately from Manual Controls.
|
||
|
||
---
|
||
|
||
### Phase 4 — Accountability
|
||
|
||
- [ ] **Votes & Committees** — fetch roll-call votes and committee referrals/actions from Congress.gov. New `bill_votes` table. UI: timeline entries for committee actions (already partially populated from bill actions) + vote results filterable by followed members and topics.
|
||
- [ ] **Member Effectiveness Score** — nightly Celery task; transparent formula: sponsored bills count, bills advanced through stages, co-sponsored, committee participation, "bills enacted" metric. Stored in `member_scores` table. Displayed on member profile with formula explanation.
|
||
- [ ] **Representation Alignment View** — for each followed member, show how their votes and actions align with the user's followed topics. Based purely on followed members (no ZIP/district storage). Neutral presentation — no scorecard dunking.
|
||
|
||
---
|
||
|
||
### Phase 5 — Polish *(slot in anytime, independent)*
|
||
|
||
- [ ] **Search Improvements** — filters on global search (bill type, status, chamber, date range); search within a member's sponsored bills; topic-scoped search.
|
||
- [ ] **Desktop View** — wider multi-column layout optimized for large screens (sticky sidebar, expanded grid, richer bill detail layout).
|
||
- [ ] **first_name / last_name Backfill** — Celery task to populate empty first/last from stored "Last, First" `name` field via split.
|
||
|
||
---
|
||
|
||
### Later / Backlog
|
||
|
||
- [ ] **Notification Channels v2** — email (SMTP), Discord webhook, Telegram bot (after ntfy + RSS v1 ships)
|
||
- [ ] **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.
|
||
- [x] Pocket Veto mode (follow stance) — toggle on a bill to treat it as “I don’t want this to pass”; adds to watchlist and triggers milestone alerts
|
||
- [x] Follow modes — Neutral + Pocket Veto + Pocket Boost; FollowButton is a mode selector with explanation tooltips
|
||
- [ ] Pocket Veto notification rules — alert only on advancement milestones + failure outcomes (failed committee / failed floor / stalled) — notification dispatcher needs to filter by follow_mode
|
||
|
||
|
||
### PocketVeto function
|
||
|
||
#### How it should work (so it’s 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 it’s 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 it’s valuable for “normal people”
|
||
|
||
Most people don’t want to follow politics continuously. They want:
|
||
|
||
- “Tell me if the bad thing is about to happen.”
|
||
That’s exactly what Pocket Veto mode does.
|
||
|
||
|
||
#### Guardrail to keep it non-partisan / non-toxic
|
||
|
||
Make it explicit in UI copy:
|
||
|
||
- It’s a **personal alert preference**, not a moral label.
|
||
|
||
- It doesn’t 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
|
||
|
||
|
||
Yes — that’s a solid idea **if it’s done as a “welcome + how it works” nudge**, not an annoying pop-up that blocks the UI.
|
||
|
||
A toast can work, but for a first-time user you’ll usually get better results with a **dismissible banner** or a **one-time “welcome” card** on the dashboard, because:
|
||
|
||
* toasts disappear (people miss them)
|
||
* first-run onboarding usually needs at least one click (“Got it” / “Start here”)
|
||
|
||
### Best pattern (low effort, high impact)
|
||
|
||
**First visit → show a dismissible Welcome card/banner** (top of dashboard) with:
|
||
|
||
* 1 sentence purpose
|
||
* 3 bullets of key features
|
||
* 2 buttons: **“Add my first follow”** and **“See a demo bill”**
|
||
* “Don’t show again” checkbox (or implicit on dismiss)
|
||
|
||
You can still use a toast, but make it:
|
||
|
||
* sticky until dismissed
|
||
* or paired with a banner/card
|
||
|
||
### What it should say (copy you can paste)
|
||
|
||
**Title:** Welcome to PocketVeto
|
||
**Body (tight):**
|
||
|
||
* Follow bills, members, or topics (low-noise)
|
||
* See *what changed* in plain English
|
||
* Verify every claim with **Back to Source** citations
|
||
**Buttons:** “Add a follow” | “Load demo”
|
||
|
||
### Implementation detail (no creepy tracking)
|
||
|
||
Store a simple flag:
|
||
|
||
* `localStorage.setItem("pv_seen_welcome", "1")`
|
||
|
||
Don’t store it server-side unless you already have user accounts and it’s part of preferences.
|
||
|
||
### Backlog item (checkboxes)
|
||
|
||
* [x] First-visit welcome UI (banner/card — guests only, shown on dashboard)
|
||
* [x] Dismiss + “don’t show again” (localStorage `pv_seen_welcome`)
|
||
* [x] CTA: Browse Bills
|
||
* [ ] CTA: Load demo data (optional)
|
||
* [ ] Link: “How it works” page/modal (optional)
|
||
|
||
If you tell me your UI stack (sounds like Next.js + shadcn/ui), I can give you a drop-in component for a clean welcome card + toast behavior.
|