- Entered
- 2026-10-01
- First commit
- 2026-10-01
on-record
App · public record · live
What French deputies actually do, on the record, not what they say.
How French deputies actually vote, vote by vote. Every public vote of the Assemblée nationale, explained in plain French for readers who never followed a session, each figure traced back to the official record.
- TypeScript
- React
- Zod
- GitHub Actions
- Cloudflare Pages
- Vitest
- Entered
- 2026-10-01Live
- First commit
- 2026-10-01Project docs and build plan
- Commits
- 28on main, read 2026-10-02
- Coverage
- 28%lines run by the ingest, web and protocol tests, read 2026-10-02
- House packages
- 11 of 11installed from npm
What shipped
- Every public vote of every deputy, with the group they sat in on the day of the vote. No ranking and no score: every figure links to the votes it counts, and every page cites its official source.
- No server and no database: a nightly GitHub Actions job asks the Assemblée’s open data whether anything changed, rebuilds only what did and deploys. A night without a new vote downloads nothing and deploys nothing.
- The host publishes 20,000 files per deployment, and there are over 8,000 votes: they ship in blocks, one file per deputy, small indexes for lists and search, and the build checks its whole output against a budget.
- About 750 pages prerendered by the very loaders the browser runs, a fake fetch answering their data during the build, each with its own head tags and a place in the sitemap.
- Find your deputy from your commune or your address, in French, light and dark.
How it works
no server, a nightly job asks what changed
As the compiler reads it
Set the way an editor shows it: a wavy line is a build that refuses, a violet line is what the compiler works out on its own.
export const isNewerVersion = ({ cached, downloaded }: { cached: SourceValidators | null downloaded: SourceValidators }): boolean => { if (cached?.lastModified == null || downloaded.lastModified === null) { return true } return ( Date.parse(downloaded.lastModified) > Date.parse(cached.lastModified) ) }
History
Straight from the git log, abridged: 7 of 28 commits, newest first.
- Link scrutins to their legislative file from the files dataset
- Show who votes with whom on the compare page
- Find my deputy from a commune or an address
- Prerender pages with their head, sitemap and share card
- Nightly refresh and deploy workflow
- Ingest Assembly votes into datasets
- Project docs and build planFirst commit
Installs
11 of the 11 house packages, from npm, down to the compiler and linter settings.
- @adrienlcp/react-routerThe router provider every app takes.0.1.1
- @adrienlcp/i18nTranslates, and knows at compile time what each message asks for.0.3.0
- @adrienlcp/theme-preferenceKeeps the chosen theme from flashing, down to the phone’s toolbar.0.3.0
- @adrienlcp/browserCopies to the clipboard even over plain HTTP, where the Clipboard API does not exist.0.1.1
- @adrienlcp/reactThe context helpers every React app starts from.0.3.0
- @adrienlcp/react-ariaThe focus ring and class composition over react-aria-components.0.1.0
- @adrienlcp/stylesThe reset and shared styles every project starts from.0.5.0
- @adrienlcp/resultSays whether something worked, without throwing and without null.0.1.0
- @adrienlcp/safe-storageTakes the throw out of localStorage and returns a Result instead.0.1.0
- @adrienlcp/tsconfigThe compiler settings every project extends.0.1.0
- @adrienlcp/biome-configThe linter and formatter settings every project extends.0.1.0