This repo is a Next.js + tRPC + Prisma TypeScript app with a React UI and Zustand state. It runs locally with Dockerized Postgres and a mock Auth0 server; prod is Netlify + Neon.
- Next.js serves both UI and API. UI page routes live under
src/pages, referencing component code insrc/web. API routers undersrc/api/routers. Core shared types live insrc/commonand DB access insrc/db. - Data flow: UI components use Zustand stores and React Query to call tRPC. See diagrams in
design-docs/:- Architecture by env:
design-docs/architecture-by-env.md - Data flow:
design-docs/data-flow.md(client → tRPC → Prisma → Postgres) - Diagram rendering pipeline:
design-docs/diagram-rendering.md
- Architecture by env:
- tRPC is initialized in
src/api/trpc.tswith Sentry middleware. Example router:src/api/routers/topic.ts(CRUD +updateDiagram). - State: Zustand stores with custom middleware: persist + devtools + zundo (undo/redo) + app-specific
apiSyncerto diff-and-sync to server.- Example store:
src/web/topic/diagramStore/store.ts - API sync middleware:
src/web/topic/diagramStore/apiSyncerMiddleware.ts(usesmicrodiff, callstopic.updateDiagram). - Topic meta store:
src/web/topic/topicStore/store.ts(noticeapiSyncer.pause()/resume()during loads).
- Example store:
- Zustand pattern: separate actions from store, only export custom hooks (see
design-docs/state-management.md). Selectors often usecreateWithEqualityFnand shallow/deep equality to avoid rerenders. - Server sync: any
setStateon a non-playground topic will triggerapiSyncerto compute CRUD diffs for nodes/edges/scores and calltrpc.topic.updateDiagram. Pause sync (e.g. when switching topics) viauseTopicStore.apiSyncer.pause(). - Types: Zod schemas in
src/common/*enforce I/O contracts. - Prefer Tailwind utility classes over styling with Emotion.
- Paths: TS path aliases with
@/…are enabled (Vitest usesvite-tsconfig-paths). - Auth: Auth0 in hosted envs; local uses
mock-auth(accepts any username/password; use seeded user authId likeoauth-test-user). - Observability: Sentry wraps all tRPC routes (
src/api/trpc.ts), sets transaction namestrpc/{type}/{path}. - Commit messages follow Conventional Commits enforced by
commitlint.config.cjs. - Prefer functional-style programming generally, but prefer
.forEachover.reduce
- Setup and run locally (Docker required):
npm run setup:local(installs deps, seeds DB, builds mock-auth)npm run dev(starts DB, mock-auth, Next.js on localhost)
- Update after pulling:
npm run update(migrations + new deps) - Tests:
npm run test(Vitest; configured invitest.config.tsusingscripts/setupTests.ts) - Lint/typecheck:
npm run lint,npm run check-types(strict ESLint incl. functional rules) - E2E (Playwright in container):
npm run e2e:buildthennpm run e2e:test:regression(requires Docker Desktop 4.29+ with host networking; seee2e/READMEscripts ine2e/) - Prisma/migrations:
- Generate up/down from schema:
npm run migration:generate - Apply latest locally:
npm run migration:run(regenerates client; may prompt to reset if drift) - Deploy (no drift checks):
npm run migration:deploy; rollback last:npm run migration:rollback
- Generate up/down from schema:
- tRPC routers: add procedures in
src/api/routers/*, reuse Zod schemas fromsrc/common/*. Exampletopic.updateDiagramhandles bulk diffs with auth checks and a single transaction. - Frontend state: update stores under
src/web/**/store.ts; if persisting to DB, route changes through the store soapiSyncercan compute diffs. - API for LLMs/automation: hit
GET /api/panelfor router docs. For schema/examples,GET /api/trpc/topicAI.getPromptData(seesrc/api/README.md).
- High-level docs/diagrams:
design-docs/* - Topic graph helpers:
src/web/topic/utils/*(e.g.,diagram,graph, filters) - Example diff-to-API conversion:
src/web/topic/utils/apiConversion.ts