Add a local-officials lookup to the council page - #138
Conversation
|
Pushed one improvement: when the city's website is resolved, the council search link is now restricted to that domain ( |
# Conflicts: # webapp/src/components/FindOfficials.vue
|
Two more additions after using it for a while: City suggestions. Typing now offers a dropdown of matching places through the existing A use-my-location button in the field. It needs a small Verified against a local run: suggestion select, Enter with free text, ZIP entry, and blur (which must do nothing) all behave; |
|
Follow-up on the suggestions after real use: labels are now the "Newnan, Georgia" form (place + state as the primary line, county as a secondary line — the two-line pattern most location boxes use, and what the FlockHopper search already does), deduped, instead of echoing Nominatim's full display_name. And counties are now suggestible and handled properly — county commissions approve sheriff ALPR contracts, so "coweta county" resolves to Coweta County, Georgia with "Board of Commissioners"/"commissioners" wording and its own site-restricted search (found www.coweta.ga.us via the same OSM/Wikidata chain). Cities keep the council wording. |
# Conflicts: # webapp/src/components/FindOfficials.vue
Closes #136.
The council page explains how to petition your local officials, but nothing on the site helps you figure out who they are — if you don't already know who to email, you probably won't email anyone. This adds a "Find Who to Contact" card at the top of
/council. (This started as two stacked PRs; folded into one since they're really one feature. #139 is closed in favor of this.)What you get
Type a city, county, or ZIP — with suggestions as you pause ("springfield" offers all the Springfields, "Newnan, Georgia" style labels with the county as a secondary line) — or hit the location button, and the card shows:
osm_type/osm_id, so the component reads the boundary relation'swebsitetag from the OSM API, falling back to Wikidata's P856 claim. It's pleasant that the answer usually comes straight out of OSM, and coverage is genuinely good — verified real official domains for Denver, NYC, KC, St. Louis, Winston-Salem, O'Fallon MO, London KY, Newnan GA (newnanga.gov), Coweta County (coweta.ga.us), and more.city council members contact site:www.denvergov.org) — city sites are where the actual rosters with names and emails live, so this lands one click away. Counties get commissioner wording throughout, since county commissions are who approve sheriff ALPR contracts.OpenStatesClientin the API (same shape as the other env-gated upstream clients, disk-cached by coordinates for 24h so the free-tier rate limit is a non-issue). Without anOPENSTATES_API_KEYconfigured,/officials404s and the UI falls back to a plain legislator-finder link — merging this changes nothing until you add a key (free, ~2 min at https://open.pluralpolicy.com/accounts/profile/). If you'd rather not hold a key at all, this could instead bake Open States' bulk data into a district-keyed JSON like the alpr-counts pipeline — happy to rework it that way.Backend additions to the Fastify API:
/officials(Open States proxy),/geocode/reverse(for the location button; Nominatim/reverseat city zoom, cached like search).Design constraints that shaped it
/geocode/multi, as word-level disambiguation. Suggestions clear on each keystroke so a fast Enter can't select a stale item.v-comboboxcommits typed text to its model on keystrokes and blur, so nothing is wired to string model updates — free-text searches happen only on Enter or the button; only a menu selection resolves through the model.QA
Ran an adversarial battery (gibberish, emoji,
<script>injection, SQL strings, ZIP+4, invalid/overlong ZIPs, "washington", "toronto" (correctly stays US: Toronto, Iowa), "brooklyn", street addresses, apostrophes/hyphens/diacritics, whole states, 300-char strings). Two real bugs surfaced and are fixed:websitetag off as the city's — "1234" resolved to a highway and offered a transit agency as "Official Mount Vernon website". Now anything that isn't itself a municipality resolves to its containing city first, and only a municipality's own element can vouch for a website.javascript:/data:rejected; scheme-lesswww.example.govvalues, common in OSM, get https).Correctness of the legislator lookup, verified without a key: for Newnan, GA, the city centroid and its ZIP both land in Senate District 6 / House District 70 per the Census Bureau's district boundaries, and Open States' public
peoplerepo has those seats held by Sen. Matt Brass and Rep. Lynn Smith — which is who a production lookup would return. (The upstream itself is exercised with stubbed fetch inbun test— 14 pass — plus a stubbed live server run in the browser; I don't have an Open States account of my own.)bun run build-onlypasses;vue-tscfails only on theApp.vue/plugin-vue errors already broken on master (same ones #133 ran into).