| client | ||
| docs | ||
| server | ||
| shared | ||
| .dockerignore | ||
| .gitignore | ||
| .nvmrc | ||
| .woodpecker.yml | ||
| AGENTS.md | ||
| CLAUDE.md | ||
| CONTRIBUTING.md | ||
| dev.sh | ||
| docker-compose.yml | ||
| Dockerfile | ||
| LICENSE | ||
| NOTICE.md | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
Le Grand Concours
Version: 1.0.0-alpha
A real-time, server-side multiplayer general knowledge game inspired by the French TV show Le Grand Concours.
Asymmetric play: one host runs the game, players compete, eliminated players become spectators.
The three rounds — first round, second round and final — are playable. See the game rules and the implementation notes.
Quick start
With Docker (recommended)
docker compose up --build
Open http://localhost:3000.
The whole app runs as a single Node/Fastify container that serves the built
Vue client, Socket.IO and /health on port 3000. For a VPS, put a
TLS-terminating reverse proxy (Caddy, Traefik or nginx) in front of it.
Local development
Requires Node.js 24 (nvm use if you have nvm).
chmod +x dev.sh
./dev.sh
- Client: http://localhost:5173
- Server: http://localhost:3000
Tests
The repository is an npm workspace: install everything once from the root.
npm ci # installs shared, server and client
npm run typecheck # all workspaces
npm test # all workspaces
npm run test:coverage # server + client coverage
npm run build # build all workspaces
npm run test:e2e # Playwright (client)
Per-package commands still work too, e.g. npm run test:coverage --workspace=server
or cd server && npm test.
Server tests use node:test and Jest to cover the room store, the three round
state machines, qualification cuts, role-specific state projections, the question
bank validator, and Socket.io integration. Client tests use Vitest for components
and Playwright for real host/player browser flows. Coverage thresholds are
non-regression floors enforced in CI.
Game overview
| Round | Format | Details |
|---|---|---|
| Round 1 | MCQ | 20 questions · 4 answers · 5 s timer · 1 pt/correct answer · Scoreboard at Q5, Q10, Q15, Q20 |
| Round 2 | Codebreaker + Categories | T9 word decoding sets the play order · 12 categories · 90 s each |
| Finale | Le Tableau | T9 opener sets order · 12-cell board · 1/2/3 pts by difficulty · 3 mystery cells (×2) |
The host configures how many candidates qualify for round 2 (default 6); the final always seats the top 3. Qualifications, eliminations and tie-breaks are decided by the server.
Host flow (Round 1)
Show question → Show answers → Start timer (5 s) → Reveal → Next question
└─ Scoreboard every 5 questions
Tech stack
| Layer | Technology |
|---|---|
| Backend | Node.js 24 · Fastify v5 · Socket.io v4 |
| Frontend | TypeScript · Vite · Vue 3 (Composition API) |
| Tests | node:test · Jest · Vitest · Playwright |
| Serving | Fastify static (production, single origin) · Vite dev server (local) |
| Containers | Docker (single app image) · docker compose · external TLS reverse proxy |
| CI/CD | Forgejo · Woodpecker CI |
| Fonts | Trasandina W03 · Gilroy |
Project structure
le-grand-concours/
├── package.json # npm workspace root (shared · server · client)
├── shared/
│ └── src/ # typed socket and game-state contracts
├── server/
│ └── src/
│ ├── socket/handlers/ # room & game event handlers
│ └── modules/
│ ├── room/ # room store (in-memory) + tests
│ ├── game/
│ │ ├── game.state.ts # state builder + broadcaster + tests
│ │ ├── round.engine.ts # per-round engine interface + registry
│ │ ├── qualification.ts # qualification cuts and tie-breaks
│ │ └── rounds/ # round1.ts / round2.ts / round3.ts (+ engines, tests)
│ └── question/ # question bank (JSON) + validator + tests
├── client/
│ └── src/
│ ├── composables/useSocket.ts # singleton socket + reactive state
│ ├── views/
│ │ ├── Home.vue
│ │ ├── Game.vue # role dispatcher
│ │ └── roles/ # Host · Player · Spectator
│ └── components/ # QuestionCard · Timer · Scoreboard · CategoryBoard ·
│ # Codebreaker · CategoryTurn · Round2Scoreboard ·
│ # FinalBoard · FinalStandings (+ tests)
├── docs/ # game rules & implementation notes
├── original/ # reference assets — not committed (fonts, images)
├── Dockerfile # single multi-stage application image
├── .woodpecker.yml # CI/CD pipeline (Woodpecker · Kaniko)
└── docker-compose.yml
Contributing
See CONTRIBUTING.md.
License & assets
The source code is licensed under MIT — Reza Drouin.
⚠️ The MIT license covers the code only. The fonts (Trasandina W03, Gilroy), the logo, the background and the reference PowerPoint engine are third-party assets under separate rights and are not redistributable by default. This project is an unofficial adaptation and is not affiliated with TF1 or Sony Pictures Television. Commercial distribution is not allowed until those rights are cleared.
See NOTICE.md for the licensing scope and docs/ASSETS.md
for the full asset inventory. The proprietary assets are not committed; the project can
run without them (system fallback font, no background/logo).