# Terminal 1 — API on :5000
cd server
npm install
# provide the required env vars (or SKIP_CONFIG_CHECK=1 for a no-secrets boot)
ADMIN_PASSWORD=dev SESSION_SECRET=dev DATA_DIR=./.data npm start
# Terminal 2 — Vite dev server on :5173 (proxies /api to :5000)
cd client
npm install
npm run devOpen http://localhost:5173. Without a Docker daemon, /api/containers returns
503 (expected), but auth, history, pins, settings, and the UI all work.
cd server && npm test # node --test (reconcile, containers-service, auth, registry, urlguard, …)
cd client && npm run build # production bundle -> client/dist/ (includes the PWA service worker)The build context must be the repo root:
docker build -f server/Dockerfile -t dockpull .server/— Express API. Talks to the Docker socket (dockerode+docker composeviaspawn, never a shell string), checks registries, stores state in SQLite (better-sqlite3). Entry pointserver/src/index.js.client/— React + Vite SPA (mobile-first, installable PWA). Same-origin/api.API_CONTRACT.md— the authoritative endpoint/field reference. Keep it in sync with route changes.SECURITY.md— threat model and operator hardening guidance.
:latest is published from every push to main (multi-arch: linux/amd64 +
linux/arm64). Cutting a version tag (git tag v1.2.0 && git push origin v1.2.0)
publishes pinned :1.2.0 / :1.2 images and creates a GitHub Release with
auto-generated notes. Bump version in server/package.json +
client/package.json (and their lockfiles) to match the tag.