Monorepo for the ScalpScan Phase 1 Dashboard (Case 1 & Case 2), per the PRD.
backend/ Node.js + Express + Prisma + PostgreSQL
frontend/ Next.js 14 (App Router) + Tailwind + Recharts
docs/ PRD, sample Becon payload, and UI design mocks
CLAUDE.md Architecture & security posture for future sessions
- Node 20+
- Docker (for local Postgres)
# Backend
cd backend
cp .env.example .env
docker compose up -d # starts Postgres on :5432
npm install
npx prisma migrate dev --name init # creates tables
npm run seed # seeds Customer A (Case 1) and Customer B (Case 2)
npm run dev # http://localhost:4000
# Frontend (new terminal)
cd frontend
cp .env.example .env.local
npm install
npm run dev # http://localhost:3000http://localhost:3000/dashboard→ Case 1 (first scan, starting-point)http://localhost:3000/dashboard?c=b1111111-2222-3333-4444-555555555555→ Case 2 (4 scans, alcohol-Minox)http://localhost:3000/hair-progress?c=b1111111-2222-3333-4444-555555555555→ per-scan photo grid
cd backend
npm test- Create a new Railway project, add a Postgres plugin; Railway will inject
DATABASE_URL. - New service → GitHub repo → select this repo, set root directory to
backend/. - Set env vars on the service:
NODE_ENV=productionFRONTEND_ORIGIN=https://<your-vercel-domain>(comma-separated allowlist is supported)BECON_WEBHOOK_SECRET=<openssl rand -hex 32>(enforced in prod)AUTH_SIGNING_SECRET=<openssl rand -hex 32>(enforced in prod)
- Deploy. Railway runs
npx prisma migrate deploy && npm starton boot (seerailway.json). - Once healthy at
GET /health, grab the public URL for Vercel's env vars.
- Vercel → New Project → import this repo, root directory =
frontend/. - Framework preset: Next.js (auto-detected).
- Environment Variables:
NEXT_PUBLIC_API_BASE=https://<your-railway-domain>DEMO_CUSTOMER_ID=0314683c-44c2-4383-b94d-efaaa5b4e7c8(optional)
- Deploy.
The backend's
FRONTEND_ORIGINCORS allowlist must include the Vercel preview + production domains, otherwise requests from the browser will be blocked by CORS.
- Helmet,
express-rate-limit, CORS allowlist, and sanitized errors on the backend. - HMAC-gated webhook (
x-becon-signature) + HMAC-gated customer identity (x-traya-signature) when the respective secrets are set. - Strict CSP + HSTS on the frontend via
next.config.mjs.
Full security model in CLAUDE.md → "Auth / customer scoping" + "Production security posture".