79eee77594
Set up the foundation for the adastra-portal project: - CLAUDE.md captures durable project rules (quality bar, security/perf/a11y as first-class, language, commit conventions, ADR proactivity). - docs/ and decisions/ scaffolding with maintained indexes (docs/README.md and decisions/README.md), MADR 4.0.0 template, and tag vocabulary. - Phase-1 ADRs (0001-0006) lock structural choices: ADR usage, Nx monorepo with the apps preset, naming convention (adastra-portal / portal-shell / portal-bff), Angular CSR/zoneless/Signals/Vitest, NestJS over Express, PostgreSQL with Prisma. - docs/setup/ guides translated to English. - .gitignore covers Node/Nx artifacts and the personal notes/ scratchpad. The Nx workspace itself is not yet bootstrapped; that step is gated on a revised setup guide aligned with the ADRs.
120 lines
5.6 KiB
Markdown
120 lines
5.6 KiB
Markdown
---
|
|
status: accepted
|
|
date: 2026-04-29
|
|
decision-makers: R&D Lead
|
|
tags: [data, backend]
|
|
---
|
|
|
|
# Persistence — PostgreSQL with Prisma
|
|
|
|
## Context and Problem Statement
|
|
|
|
The BFF owns two persistent concerns: session state (covered by Redis in the future ADR-0009) and **business data** owned directly by the portal — the portal is not a pure proxy. Business data is relational, multi-audience (workforce vs. external customers), audit-sensitive, and must run on-prem.
|
|
|
|
Which database engine and which data-access layer do we adopt?
|
|
|
|
## Decision Drivers
|
|
|
|
* On-prem deployment (no managed-service shortcut).
|
|
* Multi-audience data with strict isolation between workforce and customer scopes (Row-Level Security desirable).
|
|
* ACID transactions and a well-understood operational story (HA, backup, point-in-time recovery).
|
|
* TypeScript-first developer experience for the BFF.
|
|
* Long-term licensing safety — open source, no recent license-change risk (e.g. SSPL).
|
|
|
|
## Considered Options
|
|
|
|
### Database engine
|
|
|
|
* **PostgreSQL** (latest stable major). (Chosen.)
|
|
* MariaDB / MySQL.
|
|
* SQL Server (would imply Microsoft licensing terms).
|
|
* MongoDB / DocumentDB (rejected — not a fit for relational, audit-heavy business data; SSPL concerns).
|
|
|
|
### Data-access layer
|
|
|
|
* **Prisma** (latest stable major). (Chosen.)
|
|
* Drizzle.
|
|
* Kysely.
|
|
* TypeORM.
|
|
* Plain `pg` driver + hand-written SQL.
|
|
|
|
## Decision Outcome
|
|
|
|
Chosen options: **PostgreSQL** as the engine, **Prisma** as the data-access layer.
|
|
|
|
The engine is pinned to the latest stable major at workspace bootstrap, and tracks the upstream support window thereafter.
|
|
|
|
Prisma is wired into NestJS via the `nestjs-prisma` integration, with a dedicated `PrismaService` extending `PrismaClient` and exposed through DI. Migrations are managed by `prisma migrate`, committed to the repository, validated in CI, and applied through a controlled deployment step (covered by a future infrastructure ADR).
|
|
|
|
### Consequences
|
|
|
|
* Good, because PostgreSQL is the de facto enterprise open-source RDBMS — mature HA, replication, RLS, JSONB, full-text search.
|
|
* Good, because RLS gives a strong substrate for the workforce/customer isolation called for by ADR-0007 (identity model, future).
|
|
* Good, because Prisma's schema-first model is a single source of truth, with type generation and a readable migration log.
|
|
* Good, because Prisma's NestJS integration is well-trodden territory.
|
|
* Bad, because Prisma adds a generated client and a query engine binary — operational surface to ship and version.
|
|
* Bad, because Prisma's escape hatch for advanced PostgreSQL features (advanced CTEs, window functions, RLS policies) is `$queryRaw` — usable, but a reminder that not everything goes through the ORM. We will not fight Prisma when raw SQL is the right tool.
|
|
* Neutral, because Drizzle is a credible "à la pointe" alternative; we accept the more conservative choice for now and re-evaluate at the next major architectural review.
|
|
|
|
### Confirmation
|
|
|
|
* `apps/portal-bff` depends on `prisma` and `@prisma/client`.
|
|
* A single `schema.prisma` lives at `apps/portal-bff/prisma/schema.prisma`.
|
|
* `nestjs-prisma`'s `PrismaModule` is imported globally in the BFF.
|
|
* CI runs `prisma validate` and `prisma migrate diff` against the staging schema.
|
|
* Database engine version is pinned in deployment manifests.
|
|
|
|
## Pros and Cons of the Options
|
|
|
|
### PostgreSQL (chosen)
|
|
|
|
* Good, because mature, open source under the PostgreSQL License (permissive), broad on-prem operational tooling.
|
|
* Good, because RLS is first-class — directly serves multi-audience isolation.
|
|
* Good, because JSONB + relational hybrid suits BFF data shapes.
|
|
* Bad, because operational complexity (HA, backups, tuning) must be owned — true of any on-prem RDBMS.
|
|
|
|
### MariaDB / MySQL
|
|
|
|
* Good, because operationally well-known.
|
|
* Bad, because feature gap vs. PostgreSQL (RLS, JSON ergonomics, CTE maturity, generated columns).
|
|
|
|
### MongoDB
|
|
|
|
* Good, because the document model fits some BFF caches.
|
|
* Bad, because business data here is relational; forcing a document store would push joins into the application — bricolage.
|
|
* Bad, because the SSPL license raises enterprise legal complications.
|
|
|
|
### Prisma (chosen)
|
|
|
|
* Good, because schema-first declarative, strong DX, type generation, mainstream in 2026.
|
|
* Good, because a mature NestJS integration exists.
|
|
* Bad, because the query engine binary adds a deployment artifact.
|
|
* Bad, because some PostgreSQL features require `$queryRaw`.
|
|
|
|
### Drizzle
|
|
|
|
* Good, because lighter, closer to SQL, faster, type-safe.
|
|
* Bad, because younger (2022) — smaller enterprise track record than Prisma. Kept on the watch list for re-evaluation.
|
|
|
|
### Kysely
|
|
|
|
* Good, because elegant query-builder, no ORM magic, fully type-safe.
|
|
* Bad, because no schema/migrations of its own — must be paired with another tool, increasing surface area.
|
|
|
|
### TypeORM
|
|
|
|
* Good, because long-standing default in NestJS history.
|
|
* Bad, because design issues (decorator hell, runtime metadata fragility, migration story) and slowing maintenance — community momentum has shifted to Prisma and Drizzle.
|
|
|
|
### Plain `pg` driver + hand-written SQL
|
|
|
|
* Good, because zero abstraction; full control.
|
|
* Bad, because every cross-cutting concern (transactions, connection pooling, type mapping, migrations) is hand-built — the very bricolage we are forbidden.
|
|
|
|
## More Information
|
|
|
|
* PostgreSQL: https://www.postgresql.org/
|
|
* Prisma: https://www.prisma.io/
|
|
* `nestjs-prisma`: https://nestjs-prisma.dev/
|
|
* Related ADRs: [ADR-0005](0005-backend-stack-nestjs.md), ADR-0007 (identity model + RLS use, future), ADR-0009 (sessions in Redis, future), future infrastructure ADRs (Postgres HA, backup).
|