Monorepo with:
apps/web: Next.js 15 + React 19apps/api: NestJS + tRPCpackages/db: Prisma + PostgreSQLpackages/shared: shared Zod schemas and types
| Tool | Purpose |
|---|---|
| NestJS | HTTP server framework and DI container |
| tRPC v11 | End-to-end typesafe API layer |
| Prisma | ORM and database migrations |
| PostgreSQL | Primary database |
| Zod | Runtime schema validation (shared with frontend) |
| Resend | Transactional email delivery |
| PDFKit | PDF generation for daily summary reports |
| tsx | TypeScript execution for dev and scripts |
| Tool | Purpose |
|---|---|
| Next.js 15 | React framework with App Router |
| React 19 | UI library |
| tRPC React Query | Data fetching with full type inference |
| TanStack Query v5 | Async state and cache management |
| Radix UI | Accessible headless UI primitives (Select, Checkbox, Label) |
| React Flow / xyflow | Visual workflow builder canvas |
| Sonner | Toast notifications (system alerts + in-app toasts) |
| Zod | Form and input validation |
| Tailwind CSS v4 | Utility-first CSS |
| Package | Contents |
|---|---|
@repo/shared |
Zod schemas and inferred TypeScript types shared between API and web |
@repo/db |
Prisma client, generated types, and DB singleton |
| Tool | Purpose |
|---|---|
| pnpm | Monorepo package manager with workspaces |
| TypeScript 5 | Static typing across all packages |
| Vitest | Unit and integration testing |
| Testing Library | React component testing |
| Prettier | Code formatting |
| Docker | Local PostgreSQL container |
- Node.js
>= 20 - pnpm
>= 9 - Docker Desktop or Docker Engine
pnpm installDATABASE_URL="postgresql://postgres:postgres@localhost:5432/mydb?schema=public"
PORT=3001
CORS_ORIGIN=http://localhost:3000
NEXT_PUBLIC_API_URL=http://localhost:3001
# Optional: email via Resend
RESEND_API_KEY=
RESEND_FROM_EMAIL=onboarding@resend.devNotes:
apps/apireads the root.env.apps/webusesNEXT_PUBLIC_API_URLto point to the backend.- Without Resend configured, the app works normally; only real email delivery is skipped.
pnpm db:uppnpm db:pushRegenerate the Prisma client manually if needed:
pnpm db:generatepnpm --filter @repo/db seedThe seed creates example metrics, workflows, and recipients. It deletes existing records before recreating them.
pnpm devThis generates and builds the shared packages, then starts both apps/api and apps/web.
| URL | Description |
|---|---|
http://localhost:3000 |
Web app |
http://localhost:3001/health |
API health check |
http://localhost:3001/trpc |
tRPC endpoint |
http://localhost:3000/metrics |
Metrics manager |
http://localhost:3000/history |
Event history |
http://localhost:3000/summary |
Daily summary |
pnpm install
pnpm db:up
pnpm db:push
pnpm --filter @repo/db seed
pnpm devpnpm dev # web + api in parallel
pnpm dev:api # api only
pnpm dev:web # web only
pnpm build # full production build
pnpm test # run all workspace tests
pnpm db:up # start postgres container
pnpm db:down # stop postgres container
pnpm db:push # sync schema without migration
pnpm db:migrate # create and run a migration
pnpm db:generate # regenerate Prisma clientRun the daily summary manually:
pnpm --filter @repo/api summary:dev.
├── apps
│ ├── api # NestJS + tRPC backend
│ └── web # Next.js frontend
├── packages
│ ├── db # Prisma schema and client
│ ├── shared # Zod schemas shared across apps
│ └── trpc # tRPC router type exports
├── docker-compose.yml
└── package.json
Web app cannot reach the API — check that pnpm dev started the backend on port 3001, that NEXT_PUBLIC_API_URL points to it, and that CORS_ORIGIN includes http://localhost:3000.
Prisma cannot connect — check that Docker is running, that pnpm db:up started Postgres, and that DATABASE_URL matches the container credentials.
Metrics do not appear — run the seed or create metrics manually at /metrics.
Made by nhnvrr with Claude.