The UX design for the anonymous + personalized California-legislature dashboard. One surface, two personas: anonymous sees a chronological overview of upcoming legislation; logged-in users set a ZIP → find legislators → watch them + opt into topics, and matching bills float to the top. This is the design a backend/frontend engineer implements — not the build itself.
Open decisions (for the orchestrator / owner — not silently assumed)
D1 · Auth method.
Recommended: minimal email + local account (D1a), with OAuth (Google/Apple) offered as an alternative for residents who don't want a new password (D1b).
The preferences/personalization shape is identical under either — that's the point of keeping auth out of the data contract. /person, /prefs, /watch, /topics just need a bearer token.
D2 · ZIP vs. full address as the primary input + data-source provenance/freshness.
Design position (flagged, not decided): a ZIP alone cannot reliably resolve a California district — zips straddle Assembly/Senate boundaries (e.g., 95602 Auburn ≈ 31% A-1 / 69% A-5). The authoritative path is findyourrep.legislature.ca.gov by full address; ZIP-district boundaries come from published datasets (Legislature / data.ca.gov, Esri zip-derived).
Recommended: ZIP as the fast path with an automatic "verify by address / pick a district manually" fallback on ambiguous/zero/out-of-state; consider making address the primary input if we don't want to ship "possibly wrong district" personalization. Owner must decide which is primary and ratify the data source + its redistricting refresh cadence re: the correlation lane.
D3 · Ranking weights.
Design default: score = 3·(author watched) + 2·(sits-in watched legislator's committee) + 2·(opted-in tag matches) + 1·(home-chamber). Weights are tunable; owner may adjust, but the band-membership rule (score > 0 = relevant) is the contract the build must keep stable.