- TypeScript 47.1%
- CSS 27%
- HTML 16.1%
- Python 8.5%
- Makefile 0.6%
- Other 0.7%
|
|
||
|---|---|---|
| apps | ||
| assets | ||
| docs | ||
| scripts | ||
| tests | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| CLAUDE.md | ||
| design-system.html | ||
| design.md | ||
| docker-compose.yml | ||
| Dockerfile | ||
| index.html | ||
| llms.txt | ||
| Makefile | ||
| mise.toml | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| robots.txt | ||
| sitemap.xml | ||
| TODONEXT.md | ||
| turbo.json | ||
| vitest.config.ts | ||
aec2027
Campaign landing page for "L'Avenir en Commun" (Jean-Luc Mélenchon, presidential
election 2027 / La France Insoumise). Canonical domain: aec2027.fr.
Repo layout
The repo is an npm-workspaces + Turborepo monorepo (apps/*):
apps/web/— the Next.js app (App Router, TypeScript, Vitest). This is the site.apps/backend/— an empty placeholder for a possible future in-repo backend.
See CLAUDE.md for the full design-system conventions and docs/plans/ for
in-progress planning artifacts.
Running locally without Docker
npm install # installs all workspaces
npm run dev # turbo run dev -> apps/web's `next dev`, http://localhost:3000
A Makefile wraps the common tasks — run make to list the targets.
Running with Docker
docker compose up app # http://localhost:3000 (+ the audio origin)
docker compose --profile test run --rm test # apps/web's typecheck + test suite
Without compose:
docker build . # production image (runner target)
docker build --target test . # test image
There are no build args: every page is force-dynamic, so nothing about the
audio origin or the open-dataec API is baked into the image. Configure both
through environment: at run time (see below) — changing the audio host doesn't
need a rebuild.
docker compose up app also starts audio, a dev-only nginx:alpine origin
on http://localhost:8081 that serves apps/web/public/audio/ over HTTP. It
exists so the app can be exercised against real, multi-megabyte narration without
committing it to git or rebuilding to change it — the directory is bind-mounted
read-only, its contents are gitignored, and .dockerignore keeps them out of the
image. Production points AUDIO_CDN_BASE_URL at object storage instead. See
apps/web/public/audio/README.md.
Testing
npm run typecheck # via Turborepo
npm run test # via Turborepo — same commands the Docker `test` target runs
Environment variables
All three are runtime values (docker-compose.yml's environment:), never
build args. apps/web/.env.example documents them for non-Docker runs.
OPEN_DATAEC_API_URL(optional) — base URL of the open-dataec API. Fetched server-side only, so a Docker-internal hostname likehttp://open-dataec:3000is fine. Falls back tohttp://localhost:3000. Seeapps/web/lib/dataec.ts.AUDIO_CDN_BASE_URL(optional) — base URL of the narration audio origin. Unlike the above, this one is emitted into the HTML as an<audio>src and fetched by the browser, so it must be reachable from the visitor's browser — neverhttp://audio:80. Unset means Next.js servesapps/web/public/audio/<slug>.mp3itself. Compose defaults it to the devaudioservice,http://localhost:8081/audio. Seeapps/web/lib/audio.ts.AUDIO_AVAILABLE_SLUGS(optional) — comma-separated chapter slugs that actually have a recording. Empty by default: no narration exists yet (2026-07-26), so no listen button renders anywhere rather than offering one that 404s. Malformed entries are ignored. Seeapps/web/lib/audioAvailability.ts.
Whatever origin serves the audio must honour HTTP Range requests — the
player's slider and ±15 s buttons seek mid-file. Next.js's public/ handler,
nginx, and object storage all do.