dorfteich/docs/architecture/adr/0006-nestjs-prisma-backend.md
Claude Fable 5 0629411966 Add architecture documentation, ADRs, and operations concept
Initial deliverable of the architecture phase: 16 ADRs (stack, CRDT
collaboration, plugin sandbox, import/export, backups, CI/CD), data
model, permission model, real-time collaboration and plugin concepts,
deployment/operations/security documentation, and the milestone roadmap
that the implementation issues are derived from.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 14:36:16 +02:00

2.6 KiB
Raw Blame History

ADR 0006: NestJS + Prisma for the API server

  • Status: accepted
  • Date: 2026-07-04

Context

The API server carries most business logic: auth, permission resolution, pond/page/label CRUD, quotas, import/export orchestration, plugin management, e-mail, admin functions. Stories are implemented by many independent contributors in 0.52 day slices; the framework must make module boundaries, dependency injection, validation, and testing conventions explicit so parallel work does not collide.

Decision

  • NestJS (Express adapter) structures apps/api into feature modules that mirror the domain: auth, users, ponds, pages, labels, permissions, search, uploads, import-export, plugins, quotas, comments, notifications, admin, setup, mail, health.
  • Prisma is the ORM: schema-first data model (schema.prisma is the single source of truth, mirrored in data-model.md), generated type-safe client, prisma migrate for migrations (applied automatically at startup, ADR 0002). Raw SQL is allowed where Prisma falls short (FTS queries, ADR 0010; Yjs state upserts).
  • API style: REST + JSON under /api/v1, request/response validated with Zod schemas from packages/shared (single definition for client and server). OpenAPI document generated from these schemas for documentation.
  • Cross-cutting rules:
    • Every route passes an authentication guard and a permission guard that calls the shared resolution algorithm (permissions.md) — no ad-hoc permission checks inside handlers.
    • All external side effects (mail, conversion sidecars) go through dedicated injectable services so tests can fake them.

Consequences

  • Stories can say "add endpoint X in module Y, guard with permission Z" and be implemented without architectural decisions; NestJS's DI and testing utilities give a uniform unit/e2e test pattern (Vitest + supertest).
  • Prisma migrations serialize schema changes; stories touching the schema must be sequenced (flagged in issue dependencies).
  • NestJS adds some boilerplate per module; we accept this for the consistency it buys in a many-contributors setting.

Alternatives considered

  • Fastify/Express hand-rolled: less boilerplate, but every contributor invents structure; consistency would depend on discipline instead of framework rails. Rejected for this team model.
  • tRPC: excellent DX for a closed SPA+API pair, but a REST API is a deliberate product feature for self-hosters and integrations.
  • Drizzle: fine ORM, but Prisma's schema file + migration story is the most widely known and the easiest to review.