Desktop ERP for a metal heat-treating / finishing job shop — scheduling, quality, and fulfillment. Long-term goal: replace Visual Shop.
Proprietary — the source is published for reference only. See LICENSE.
TypeScript monorepo (npm workspaces):
packages/domain— pure shared core (types, selectors, formatting, seed data); no I/O.apps/web— React 18 + Vite + Zustand + React Router. Reads/writes data through aDataGatewayseam:InMemoryGateway(seed data, the default) orHttpGateway(the live API, used whenVITE_API_URLis set).apps/api— Fastify 5 + PostgreSQL 16 + Drizzle ORM, run undertsx. JWT auth + RBAC, operator-PIN identity, rate-limiting. DB tests use Testcontainers.
Specs and plans live in docs/superpowers/{specs,plans}/; design reference in
docs/design-reference/.
The web app runs against in-memory seed data, so no backend is needed:
npm install
npm run dev # serve apps/web (InMemoryGateway)
npm test # all workspace tests (domain + web + api*)
npm run typecheck
npm run lint
npm run build # build the web app* the apps/api suite uses Testcontainers and needs Docker running.
Copy the env templates and fill them in (real .env files are gitignored):
cp apps/api/.env.example apps/api/.env # DATABASE_URL, JWT_SECRET, OPERATOR_PIN_PEPPER, …
cp apps/web/.env.example apps/web/.env # VITE_API_URL=http://localhost:3001Then bring up Postgres, migrate, seed, and run both:
docker compose -f apps/api/docker-compose.yml up -d # Postgres on :5433
npm run -s db:migrate -w @tempyr/api
npm run -s db:seed -w @tempyr/api
npm run -s start -w @tempyr/api # API on :3001
npm run dev -w @tempyr/web # web reads VITE_API_URL from apps/web/.envIn production the API fails fast at startup unless JWT_SECRET and
OPERATOR_PIN_PEPPER are set to strong, non-default values, and db:seed
refuses to run unless ALLOW_PROD_SEED=true with non-default credentials —
see apps/api/.env.example.
See CONTRIBUTING.md for the spec → plan → implementation workflow.