Local development¶
Hot-reload setup¶
# Spin up PostgreSQL (+ Garage S3) for local dev
docker compose up -d postgres garage
# Backend (terminal A)
cd server
cp .env.example .env
cargo run
# Frontend (terminal B)
cd client
corepack enable
pnpm install
pnpm dev
Open http://localhost:5173. The Vite dev server proxies /api/* and /api/ws to the Rust backend on :3000.
pnpm exclusively
FigureCollector is pnpm-only. Never run npm install — it would create a divergent package-lock.json that confuses the build.
Garage one-time init¶
Garage is an S3-compatible distributed object store from Deuxfleurs — lighter than MinIO and designed for federated self-hosting. After the first docker compose up garage:
# Wait until Garage announces its node ID, then capture it
NODE=$(docker compose exec garage /garage status \
| awk '/^[a-f0-9]{16}/ {print $1; exit}')
# Single-node layout (1 GB usable, zone "dc1")
docker compose exec garage /garage layout assign "$NODE" -z dc1 -c 1G
docker compose exec garage /garage layout apply --version 1
# Create the bucket the backend will use
docker compose exec garage /garage bucket create figurecollector
# Mint an access key, then grant it RW on the bucket
docker compose exec garage /garage key create local-dev
docker compose exec garage /garage bucket allow figurecollector --read --write --key local-dev
The key create step prints an Access Key ID and Secret Access Key — paste them into server/.env under S3_ACCESS_KEY and S3_SECRET_KEY. Region stays garage, endpoint http://garage:3902, path-style required.
Filesystem fallback
If you don't want to bother with Garage in dev, leave the S3_* env vars unset and uploads will land on disk under ./data/uploads. The backend auto-detects the absence of S3 credentials.
Fully containerised dev¶
Builds both images (backend FROM scratch, frontend distroless) and runs them with the full hardening profile. Slower iteration but matches production exactly.
Useful when:
- You want to test the production CSP, security headers, and CSP nonce flow.
- You changed
server/Dockerfileorclient/Dockerfileand want to verify the build still produces a working scratch / distroless image. - You're reproducing an issue that only shows up under the read-only filesystem.
Running tests¶
# Backend
cd server
cargo test --workspace
# Frontend
cd client
pnpm lint
pnpm build # production build, verifies CSP + chunking
Lint cleanliness is non-negotiable — the build pipeline rejects new warnings.