Files
PocketVeto/PocketVeto — Feature Roadmap.md
Jack Levy 0de8c83987 feat: weekly digest + local-time quiet hours
Weekly Digest (send_weekly_digest Celery task):
- Runs every Monday 8:30 AM UTC via beat schedule
- Queries all followed bills updated in the past 7 days per user
- Sends low-priority ntfy push (Priority: low, Tags: newspaper,calendar)
- Creates a NotificationEvent (weekly_digest type) for RSS feed visibility
- Admin can trigger immediately via POST /api/admin/trigger-weekly-digest
- Manual Controls panel now includes "Send Weekly Digest" button

Local-time quiet hours:
- Browser auto-detects IANA timezone via Intl.DateTimeFormat().resolvedOptions().timeZone
- Timezone saved to notification_prefs alongside quiet_hours_start/end on Save
- Dispatcher converts UTC → user's local time (zoneinfo stdlib) before hour comparison
- Falls back to UTC if timezone absent or unrecognised
- Quiet hours UI: 12-hour AM/PM selectors, shows detected timezone as hint
- Clearing quiet hours also clears stored timezone

Co-Authored-By: Jack Levy
2026-03-01 22:04:54 -05:00

12 KiB
Raw Blame History

Roadmap

  • Docker Stack — PostgreSQL, Redis, FastAPI, Celery, Next.js, Nginx fully containerized
  • Bill Polling — Congress.gov incremental sync every 30 min, filtered to legislation that can become law
  • Document Fetching — GovInfo bill text retrieval with smart truncation for token budgets
  • LLM Analysis — Multi-provider AI briefs (OpenAI, Anthropic, Gemini, Ollama) with amendment diffing
  • News Correlation — NewsAPI + Google News RSS articles linked to bills via topic tags
  • Trend Scoring — Composite zeitgeist score (0100) from NewsAPI + Google News + Google Trends, nightly
  • Full-text Search — PostgreSQL tsvector search across bills and members
  • Follows — Per-user follows for bills, members, and topics
  • Dashboard — Personalized feed + trending bills
  • Multi-user Auth — JWT email/password auth, admin role, user management panel
  • Admin Panel — LLM provider switching, pipeline stats, manual task triggers
  • Citations — Every AI brief key point and risk cites the section + verbatim quote from bill text
  • Citation UI — § chips expand inline to show quote + GovInfo source link
  • Party Badges — Solid red/blue/slate badges readable in light and dark mode
  • Nginx DNS Fix — Resolver directive prevents stale-IP 502s after container restarts
  • Sponsor Linking — Poller fetches bill detail for sponsor; backfill task fixes existing bills
  • Member Search — "First Last" and "Last, First" both match via PostgreSQL split_part()
  • Search Spaces — Removed .trim() on keystroke that ate spaces in search inputs
  • Mobile UI — Responsive layout: sidebar collapses, cards stack, touch-friendly controls
  • Member BIO & Photo — Display member headshots (photo_url already stored, not yet shown in UI)
  • Bill Action Fetching — BillAction table populated via Congress.gov actions endpoint; nightly batch + event-driven on bill change
  • What Changed (Amendment Briefs) — BriefPanel surfaces amendment briefs with "What Changed" badge and collapsible version history
  • 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)
  • Admin Reprocess — POST /api/admin/bills/{bill_id}/reprocess queues document + action fetches for a specific bill
  • LLM Model Picker — live model list fetched from each provider's API; custom model name fallback
  • Admin Health Panel — bill pipeline breakdown table, external API health tests with latency, manual controls with status dots + task polling
  • Chamber Badges — amber/gold for Senate, slate/silver for House; applied on bill cards and detail pages
  • Action History Fallback — shows latest_action_date/text while full history loads; full timeline once fetched
  • Backfill All Actions — admin task to fetch action history for all pre-existing bills
  • Notifications (Phase 1) — ntfy dispatch, RSS feed, per-user settings UI, 5-min dispatcher beat task
  • 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.)
  • Follow Modes — neutral | pocket_veto | pocket_boost on the follows table; FollowButton mode selector with descriptions and tooltips
  • Public Browsing — unauthenticated guests browse bills, members, topics, and trending dashboard; AuthModal gates follow/interactive actions; sidebar and nav adapt to guest state
  • 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
  • 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)

  • 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.
  • Fact vs Inference Labelinglabel: "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 / Watchlistscollections (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).
  • Personal Notesbill_notes table (user_id, bill_id, content, stance, tags, pinned). Shown on bill detail page. Private; optionally pin to top of the bill detail view.
  • 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.
  • 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.
  • 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
  • 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 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

Yes — thats a solid idea if its 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 youll 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”
  • “Dont 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")

Dont store it server-side unless you already have user accounts and its part of preferences.

Backlog item (checkboxes)

  • First-visit welcome UI (banner/card — guests only, shown on dashboard)
  • Dismiss + “dont show again” (localStorage pv_seen_welcome)
  • 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.