Cross-product deployment topology and release order live in the internal workspace's OPS-3, which is not published. This file is the CodeRoastWeb-specific runbook for local development, Vite/Netlify, API base configuration, and browser deployment checks.
Install dependencies once:
npm installStart the Vite dev server:
npm run devDefault URL: http://localhost:5173.
When developing the Lab, run CodeRoastServer on localhost:8080. Vite proxies API and WebSocket traffic to it.
npm run dev:phone opens phone.html, a phone-sized frame around the running dev server. It sits at the repo root beside index.html, not in public/: the production build copies public/ whole and has one HTML entry, index.html, so a page at the root is served by the dev server and never shipped.
| Command | Purpose |
|---|---|
npm run dev |
Vite dev server with HMR. |
npm run build |
TypeScript project build, Vite production bundle, then the site checks over dist/. |
npm run preview |
Serve dist/ locally for production preview. |
npm run lint |
ESLint over the repo. |
npm test |
Vitest test suite once. |
npm run test:watch |
Vitest watch mode. |
The REST base is resolved in src/services/api.ts:
const API_BASE = import.meta.env.VITE_API_BASE || '/api/v1'vite.config.ts proxies:
/api -> http://localhost:8080
/api/v1/ws -> ws://localhost:8080
The front end keeps the full /api/v1/* prefix. The backend should expose versioned routes directly.
netlify.toml sets:
VITE_API_BASE = "https://api.coderoast.fr/api/v1"The WebSocket client converts that to wss://api.coderoast.fr/api/v1/ws/engine?....
If production moves to a different API host, update VITE_API_BASE in the hosting environment and keep the /api/v1 suffix unless the backend version changes.
npm run buildBuild output lands in dist/. The build command runs tsc -b before Vite bundling, so type errors fail deployment.
The build then judges its own output before it reports success: the siteGate Vite plugin (src/siteChecks/vitePlugin.ts) runs the same verdict src/test/firstPartyAssets.test.ts asserts (src/siteChecks/builtSite.ts). Its nine arms: every emitted file is readable by the scanner, and the scanner still reaches every construct the build carries; no load names an origin but the site's own and api.coderoast.fr; every own-origin resource is an emitted file; the self-hosted fonts are complete and emitted byte-identical; the bundle carries the declared API base; every emitted showcase log is a sample src/assets/sift-showcase/MANIFEST.json digests; and index.html carries the build identity. A fault in any arm fails npm run build, and with it the Netlify deploy, and removes dist/, so a refused build leaves nothing to upload. The error names each offending file, URL or digest. A clean build logs coderoast-site-gate: 9/9 arms clean.
dist/index.html carries <meta name="coderoast-web-build" content="…">: the 40-hex commit the build was made from, suffixed -dirty when a tracked file differs from that commit or the build read a file git does not track (src/siteChecks/buildIdentity.ts). The build log prints the identity and, when it is dirty, every path that made it so. To read what coderoast.fr serves:
curl -s https://coderoast.fr/ | grep -o '<meta name="coderoast-web-build" content="[^"]*"'npm run previewDefault preview URL: http://localhost:4173.
Use preview to catch React Router, asset, and environment-variable issues before pushing hosting changes.
The checked-in netlify.toml is the canonical static hosting config:
[build]
command = "npm run build"
publish = "dist"
[[redirects]]
from = "/*"
to = "/index.html"
status = 200The redirect is required because React Router owns client-side routes such as /lab, /logcraft, and /legal/privacy.
Static asset headers:
/assets/*receives long immutable caching;*.jsis forced to JavaScript content type;*.wasmis forced to WebAssembly content type for future assets.
The hosted Lab needs a reachable CodeRoastServer instance, with CORS allowing the deployed web
origin and its scenario roots configured (CODEROAST_LOGCRAFT_SCENARIO_PATH,
CODEROAST_INSIGHT_SCENARIO_PATH).
The route set is NOT enumerated here. CodeRoastServer's technical_docs/api/server_api_contract.md
owns it, and the registrations in its server/src/**/*_controller.hpp are the ground truth beneath
that. This list used to be mirrored here and it rotted: it named /api/v1/users and
/api/v1/tiers, and both 404 in production — /tiers is a page on this site, never an API route,
and /users was absorbed into /whoami. A mirror of someone else's enumeration goes stale silently,
and a route inventory that is wrong anywhere is untrustworthy everywhere. (CodeRoastServer is not a
published repository.)
- Run
npm test. - Run
npm run lint. - Run
npm run build. - Confirm
VITE_API_BASEpoints to the intended API host. - Confirm the API host accepts the web origin through CORS.
- Confirm WebSocket upgrades work from the deployed origin.
- Open
/lab, create an engine from a starter scenario, and verify snapshots arrive.
| Symptom | Likely cause | Fix |
|---|---|---|
/lab returns 404 after refresh |
Missing SPA redirect | Keep Netlify /* -> /index.html 200. |
| API works locally but not in production | Missing or wrong VITE_API_BASE |
Set full https://host/api/v1. |
| WebSocket connects locally but not hosted | API host rejects upgrade or uses wrong scheme | Ensure wss:// is reachable and routed to /api/v1/ws/engine. |
| Tier buttons enabled but server denies | Front-end permission mirror drifted | Update src/utils/permissions.ts and CodeRoastServer permission keys together. |
| Scenario list empty | CodeRoastServer lacks the matching scenario root | Set CODEROAST_LOGCRAFT_SCENARIO_PATH or CODEROAST_INSIGHT_SCENARIO_PATH on the server. |