Internal operations platform for the DALI Lab. Single React Router 7 app (dali-api/) that serves the UI, the JSON API, and the Hocuspocus realtime collab server. Originally a hiring tool, now expanding to projects, members, partners, calendar, and education.
| Layer | Tech |
|---|---|
| App | React Router 7 (full-stack), React 19, TypeScript |
| DB | Postgres 16 on Neon, Prisma 7 (@prisma/adapter-neon / @prisma/adapter-pg) |
| Realtime | Hocuspocus + Yjs + Tiptap, Redis for fan-out |
| Auth | Google OAuth, Dartmouth CAS, opaque session cookies + Bearer headers |
| Styling | Tailwind CSS 4 |
| Runtime | Node 22, npm |
| Tests | Vitest (unit), Playwright (e2e) |
| Deploy | Fly.io, branches dev → staging → prod |
dali-api/
app/
hiring/ cycles, reviewers, interviews, delibs, decisions
admin-console/ members, domains, role assignment
projects/ project list, staffing
members/ directory, user profiles
partners/ partner portal
calendar/ scheduling
collab/ Hocuspocus server + Yjs persistence
routes/ shared routes (auth, portal, oauth, uploads)
components/ shared UI
lib/ db client, auth, server utilities
prisma/ schema.prisma, migrations/, seed.ts
e2e/ Playwright specs
.github/workflows/ CI/CD
docker-compose.yml local Postgres + API + Prisma Studio
Prereqs: Docker, Node 22, a repo-root .env containing GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET.
docker compose upBrings up Postgres, runs prisma db push --force-reset && prisma db seed, then starts the dev server on :3001, the collab server on :3002, and Prisma Studio on :5555.
Bare metal (your own Postgres):
cd dali-api
npm install
npm run db:reset:local # destroys local DB
npm run devSkip login during dev at /dev-login (dev-only route, gated to non-prod builds).
Run from dali-api/.
| Task | Command |
|---|---|
| Unit tests | npm test |
| E2E tests | npm run test:e2e (needs a seeded Postgres) |
| Typecheck | npm run typecheck |
| Build | npm run build |
| Dev server | npm run dev |
| Reset local DB | npm run db:reset:local |
No ESLint/Prettier is wired up.
| Env | Branch | Fly app | Neon branch | DB on deploy |
|---|---|---|---|---|
| Dev | dev |
dali-api-dev |
development |
wipe → migrate → seed |
| Staging | staging |
dali-api-staging |
staging |
restore from prod → migrate |
| Prod | prod |
dali-api-prod |
production |
migrate only |
Promotion is staged: PRs merge to dev, then promote-to-staging.yml and promote-to-prod.yml move code forward. Per-PR previews spin up their own Neon branch + Fly app via preview-deploy.yml and tear down on close.
Authoring rules:
- Edit
prisma/schema.prisma, thennpx prisma migrate dev --name <change>. - Commit schema and migration in the same PR.
- Never edit or delete an applied migration. Fix forward with a new one.
- Flag data-losing migrations (drops, non-null without default) in the PR description.
Runtime uses the pooled DATABASE_URL. prisma migrate needs a non-pooled URL (advisory locks don't survive PgBouncer transaction pooling); prisma.config.ts auto-derives it from DATABASE_URL or honors an explicit DIRECT_URL. Full detail: dali-api/prisma/MIGRATIONS.md.
Failures on these block merge:
test.yml— Vitest + Playwright against a real Postgres service container.build-check.yml— Docker build via flyctl.migration-check.yml— schema/migration drift, deleted-migration guard, pgfence safety analysis.codeql.yml— static security scan.preview-deploy.yml— per-PR Neon + Fly preview (only blocks if it fails specifically).
/login— Google OAuth or Dartmouth CAS./portal/*— applicant portal (lighter layout, no internal nav)./oauth/*— DALI OS acts as an OAuth provider for thedali-os-mcpintegration (authorize,token,revoke,callback/*).- Browser auth uses the
__dali_sidHttpOnly cookie; API/MCP clients sendAuthorization: Bearer <session_id>. Both resolve to one indexed lookup against theSessiontable (app/lib/session.ts). SeeSESSION_AUTH_PLAN.mdfor the model. Never log session ids, OAuth codes, or.envcontents.
Tiptap documents are CRDT-synced through the Hocuspocus server (app/collab/server.ts) using Yjs, with Redis for multi-instance fan-out and Postgres for persistence. Schema changes to collaboratively edited documents can pass tests locally and still break document sync in prod — flag any such change in the PR description.
CLAUDE.md— conventions for Claude-driven PRs.dali-api/prisma/MIGRATIONS.md— full migration/Neon URL detail.dali-api/README.md— deploy detail + per-endpoint rate limits.expansion_plan.md,CYCLE_REDESIGN_SPEC.md,SCHEDULING.md— design docs.dali-os-mcp.md— MCP integration.