Local development
Run PostgreSQL and Keycloak in Docker, then the React Router app on the host with hot module replacement (port 5173). Docker must be available for site management features (container create/start/stop).
Prerequisites
- Node.js 22+
- npm (bundled with Node)
- Docker and Docker Compose
Quick start
You only need Node.js 22+, npm, and Docker with Compose. No
.env.local file is required — defaults match the local compose file and the app’s fallbacks.
git clone https://github.com/03c/jigsaw.git
cd jigsaw
npm install
npm run dev
npm run dev regenerates the dev Keycloak realm, starts PostgreSQL + Keycloak via
docker-compose.dev.yml, waits until Keycloak’s OIDC endpoint responds, runs
drizzle-kit push, then starts Vite with HMR.
SKIP_DEV_SERVICES=1 before npm run dev to only run the app (no Docker) — useful
for UI-only work; login and database features need the stack.
Optional: .env.local
Copy .env.local.example to
.env.local when you need to override URLs, secrets, or (on Windows) the Docker socket path. If the
file exists, it is loaded for npm run dev, realm generation, and passed to Docker Compose (via
scripts/dev-compose.mjs) for dev:services:*.
Dev server only
If containers are already running and the schema is applied:
npm run dev:app
Application: http://localhost:5173 · Keycloak: http://localhost:8080
curl -sf http://localhost:8080/realms/jigsaw/.well-known/openid-configuration | head -c 120
Useful npm scripts
| Script | Description |
|---|---|
npm run dev |
Local Docker services, wait for Keycloak, db:push, then Vite + HMR |
npm run dev:app |
Vite + HMR only (services must already be up) |
npm run build |
Production build to build/ |
npm run start |
Serve production build (port 3000) |
npm run typecheck |
Route typegen + TypeScript |
npm run dev:services:up / down |
Start/stop local PostgreSQL + Keycloak |
npm run db:push |
Apply Drizzle schema (non-destructive) |
npm run db:studio |
Drizzle Studio GUI |
Windows (Docker Desktop)
If the app cannot talk to Docker, create .env.local and set
DOCKER_SOCKET_PATH=//./pipe/docker_engine (see .env.local.example).
CI E2E (same compose file)
GitHub Actions E2E uses the same docker-compose.dev.yml with
--profile e2e to also build and run the panel container on port 3000 for Playwright.
Further reading
- AGENTS.md — contributor-oriented guide
- Contributing