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

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.

Set 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

Keycloak can take 15–30 seconds after containers start. Until the realm endpoint responds, login redirects may fail. Check: 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

← Home