Commit Graph

8 Commits

Author SHA1 Message Date
Jack Levy
d0da0b8dce feat: Member Effectiveness Score + Representation Alignment View (v0.9.9)
Member Effectiveness Score
- New BillCosponsor table (migration 0018) with per-bill co-sponsor
  party data required for the bipartisan multiplier
- bill_category column on Bill (substantive | commemorative | administrative)
  set by a cheap one-shot LLM call after each brief is generated
- effectiveness_score / percentile / tier columns on Member
- New bill_classifier.py worker with 5 tasks:
    classify_bill_category  — triggered from llm_processor after brief
    fetch_bill_cosponsors   — triggered from congress_poller on new bill
    calculate_effectiveness_scores — nightly at 5 AM UTC
    backfill_bill_categories / backfill_all_bill_cosponsors — one-time
- Scoring: distance-traveled pts × bipartisan (1.5×) × substance (0.1×
  for commemorative) × leadership (1.2× for committee chairs)
- Percentile normalised within (seniority tier × party) buckets
- Effectiveness card on member detail page with colour-coded bar
- Admin panel: 3 new backfill/calculate controls in Maintenance section

Representation Alignment View
- New GET /api/alignment endpoint: cross-references user's stanced bill
  follows (pocket_veto/pocket_boost) with followed members' vote positions
- Efficient bulk queries — no N+1 loops
- New /alignment page with ranked member list and alignment bars
- Alignment added to sidebar nav (auth-required)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-14 18:05:09 -04:00
Jack Levy
48771287d3 feat: ZIP → rep lookup, member page redesign, letter improvements
ZIP lookup (GET /api/members/by-zip/{zip}):
- Two-step geocoding: Nominatim (ZIP → lat/lng) then Census TIGERweb
  Legislative identify (lat/lng → congressional district via GEOID)
- Handles at-large states (AK, DE, MT, ND, SD, VT, WY)
- Added rep_lookup health check to admin External API Health panel

congress_api.py fixes:
- parse_member_from_api: normalize state full name → 2-letter code
  (Congress.gov returns "Florida", DB expects "FL")
- parse_member_from_api: read district from top-level data field,
  not current_term (district is not inside the term object)

Celery beat: schedule sync_members daily at 1 AM UTC so chamber,
district, and contact info stay current without manual triggering

Members page redesign: photo avatars, party/state/chamber chips,
phone + website links, ZIP lookup form to find your reps

Draft letter improvements: pass rep_name from ZIP lookup so letter
opens with "Dear Representative Franklin," instead of generic salutation;
add has_document filter to bills list endpoint

UX additions: HelpTip component, How It Works page, "How it works"
sidebar nav link, collections page description copy

Authored-By: Jack Levy
2026-03-02 15:47:46 -05:00
Jack Levy
9e5ac9b33d feat: collections, watchlists, and shareable links (v0.9.0)
Phase 3 completion — Personal Workflow feature set is now complete.

Collections / Watchlists:
- New tables: collections (UUID share_token, slug, public/private) and
  collection_bills (unique bill-per-collection constraint)
- Full CRUD API at /api/collections with bill add/remove endpoints
- Public share endpoint /api/collections/share/{token} (no auth)
- /collections list page with inline create form and delete
- /collections/[id] detail page: inline rename, public toggle,
  copy-share-link, bill search/add/remove
- CollectionPicker bookmark-icon popover on bill detail pages
- Collections nav link in sidebar (auth-required)

Shareable Brief Links:
- share_token UUID column on bill_briefs (backfilled on migration)
- Unified public share router at /api/share (brief + collection)
- /share/brief/[token] — minimal layout, full AIBriefCard, CTAs
- /share/collection/[token] — minimal layout, bill list, CTA
- Share2 button in BriefPanel header row, "Link copied!" flash

AuthGuard: /collections → AUTH_REQUIRED; /share prefix → NO_SHELL_PATHS

Authored-By: Jack Levy
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 23:23:45 -05:00
Jack Levy
ddd74a02d5 feat(public_page): allow unauthenticated browsing with auth-gated interactivity
- Add get_optional_user dependency; dashboard returns guest-safe payload
- AuthGuard only redirects /following and /notifications for guests
- Sidebar hides auth-required nav items and shows Sign In/Register for guests
- Dashboard shows trending bills as "Most Popular" for unauthenticated visitors
- FollowButton opens AuthModal instead of acting when not signed in
- Members page pins followed members at the top for quick unfollowing
- useFollows skips API call and invalidates dashboard on follow/unfollow

Authored-By: Jack Levy
2026-03-01 15:54:54 -05:00
Jack Levy
2e2fefb795 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
2026-03-01 12:04:13 -05:00
Jack Levy
37339d6950 feat(ui): add mobile-responsive layout with hamburger drawer
Adds MobileHeader with hamburger button (left-aligned) that opens a
slide-in sidebar drawer on mobile. Desktop layout is unchanged. All
hardcoded multi-column grids updated with responsive Tailwind breakpoints.

Co-Authored-By: Jack Levy
2026-02-28 23:58:28 -05:00
Jack Levy
5b73b60d9e Add multi-user auth system and admin panel
- User model with email/hashed_password/is_admin/notification_prefs
- JWT auth: POST /api/auth/register, /login, /me
- First registered user auto-promoted to admin
- Migration 0005: users table + user_id FK on follows (clears global follows)
- Follows, dashboard, settings, admin endpoints all require authentication
- Admin endpoints (settings writes, celery triggers) require is_admin
- Frontend: login/register pages, Zustand auth store (localStorage persist)
- AuthGuard component gates all app routes, shows app shell only when authed
- Sidebar shows user email + logout; Admin nav link visible to admins only
- Admin panel (/settings): user list with delete + promote/demote, LLM config,
  data source settings, and manual celery controls

Authored-By: Jack Levy
2026-02-28 21:44:34 -05:00
Jack Levy
e418dd9ae0 Initial commit 2026-02-28 21:08:19 -05:00