A website that uses the free French government open data to visualize laws: who voted them, when, and their subjects.
- The latest votes, drawn as an hemicycle, with the position of every political group and of every deputy
- Bills currently being discussed, with their progress (commission → floor → Sénat → CMP → Conseil constitutionnel → promulgation) and next scheduled sitting
- Promulgated laws with their number and links to Assemblée nationale / Sénat / Légifrance
- Group profiles and a "who votes like whom" agreement matrix; a page per group (members, cohesion, closest groups)
- A page per deputy: constituency, group history, participation, how often they vote against their group, and every vote
- 59 themes (light, dark, high-contrast, colour-blind-safe, neon, brutalist…) with a live-preview picker
Frontend only: Angular 21 + TypeScript, no backend, no database. Hosted on GitHub Pages.
npm install
npm start # http://localhost:4200In development, with no data file present, the app falls back to mock data (clearly flagged in the UI). To use the real data locally:
npm run data # writes public/data/snapshot.json (gitignored)
npm startOther commands: npm test, npm run build. In development the sidebar has a switch between demo and official data.
Mock data is development-only. It is removed from the production bundle at build time (define MOCK_ALLOWED in angular.json), and the production site never falls back to it: if the official data can't be loaded it shows a "Données indisponibles" error.
The Assemblée nationale publishes its open data as bulk JSON archives at https://data.assemblee-nationale.fr: no account and no API key. Browsers can't read those archives directly (tens of MB, no CORS), and a static site has no server, so:
GitHub Action (daily) Browser
scripts/build-data.mjs LawDataService
├ Scrutins.json.zip (every vote, by group) ├ GET data/snapshot.json ── ok ──▶ real data
├ Dossiers_Legislatifs.json.zip (bills, stages) └ missing / failed ─▶ dev: mock-data.ts · prod: error page
└ AMO30 acteurs/organes (groups, colours, deputies)
├▶ public/data/snapshot.json (~1.4 MB, same shape as models.ts `Snapshot`)
├▶ public/data/deputes/<id>.json (one deputy's votes, fetched by their page)
└▶ public/data/scrutins/<id>.json (one vote, deputy by deputy, fetched by its page)
src/app/core/models.ts is the contract; the snapshot builder and the mock generator both produce a Snapshot.
Subjects (health, security, …) are derived from titles by keyword in the builder: the source data has no topic field.
Nothing is needed today. If you want to go further:
| Source | What it adds | What you need |
|---|---|---|
| Légifrance API (via PISTE) | Full legal text of promulgated laws, JORF | A PISTE account + an application → client_id / client_secret (OAuth). |
| Sénat open data (https://data.senat.fr) | Sénat votes | No key. |
| data.gouv.fr API | Other datasets | No key for reading. |
Never put a PISTE secret in the Angular code: it would ship to every visitor. Store it as a GitHub Actions secret
(PISTE_CLIENT_ID, PISTE_CLIENT_SECRET) and use it in scripts/build-data.mjs, so it stays server-side at build time.
.github/workflows/deploy.yml tests, fetches the data, builds and deploys on every push to main, on pull requests
(build + test only), and every day at 05:17 UTC so the data stays fresh.
One-time setup: repository Settings → Pages → Build and deployment → Source: GitHub Actions.
The site is served at https://<user>.github.io/<repo>/ (the base path is taken from the repository name).
Deep links work through a 404.html copy of index.html.
src/themes is the theme system (54 definition files, 59 themes, in src/themes/definitions). A theme sets colour tokens,
radii, shadows, border style, density, fonts and effects; ThemeService applies them as CSS variables on <html> and
src/styles.css turns those into the design system. To add one, drop a file in src/themes/definitions
(defineTheme({...}), default export): npm start / npm run build regenerate the index
(scripts/gen-theme-index.mjs) and it appears in the picker.
design/sketch.html is the hi-fi sketch the UI was built from (open it in a browser; it uses the same tokens as the themes).
- Angular 21 (not 22): Angular 22 requires Node ≥ 22.22, and this repo also builds on older Node 22. Upgrade with
ng update. .npmrcsetslegacy-peer-depsto sidestep an npm 10.9.0 bug (Cannot read properties of null (reading 'edgesOut')).- Independent project, not affiliated with any public administration. Data: Licence Ouverte / Etalab.