Add Prisma 7 + nestjs-prisma. The schema lives at
apps/portal-bff/prisma/schema.prisma with provider postgresql; the new
prisma-client generator (Prisma 7 default) outputs the typed client to
apps/portal-bff/generated/prisma/ which is gitignored.
apps/portal-bff/src/app/app.module.ts imports PrismaModule.forRoot
({ isGlobal: true }) so PrismaService is injectable across the BFF
without per-module imports.
apps/portal-bff/.env.example documents DATABASE_URL with a local-dev
default, plus a forward list of env vars introduced by upcoming phases
and ADRs (auth, sessions, MFA, observability, audit, downstream APIs)
- catalog reference, not implementation. The actual .env stays
gitignored at both repo root and app levels.
prisma.config.ts (Prisma 7's TypeScript config) is committed; it loads
DATABASE_URL via dotenv. Schema and migrations paths are pinned to
prisma/ relative to the bff app.
PostgreSQL provisioning, RLS policies for the dual-audience design,
the dedicated audit schema with role grants (audit_owner / audit_writer
/ audit_reader / audit_archiver per ADR-0013), and column-level
encryption for L3-scoped data are out of scope of this commit -
they belong with the future on-prem infrastructure ADR.
Add the @nx/angular, @nx/nest, @nx/vite, @nx/eslint plugins, then
generate the two apps. Adjust the empty-template tsconfig.base.json
to be Angular-compatible (drop project references and customConditions
that the empty-template defaults to but Angular doesn't support; keep
the strict-TS extensions from ADR-0004).
apps/portal-shell (Angular 21):
- standalone APIs, routing, SCSS, esbuild
- vitest-angular as unitTestRunner, playwright for e2e
- strict mode
- tags scope:portal-shell, type:app
- app.config.ts wired with provideZonelessChangeDetection() per
ADR-0004 (Angular 21 + Nx 22 generates without zone.js by default)
apps/portal-bff (NestJS 11):
- Express adapter (default per ADR-0005)
- Jest as unitTestRunner
- tags scope:portal-bff, type:app
- main.ts wired with a global ValidationPipe configured
whitelist + forbidNonWhitelisted + transform per ADR-0005
- Phase-2 security additions (helmet, CORS, sessions, CSRF, rate
limit, auth guards, error filter) deferred to their respective
ADRs - placeholder comment in main.ts
Workspace dependencies: class-validator + class-transformer added
(required by NestJS ValidationPipe at runtime). Nx-generated
.gitignore additions (.angular, __screenshots__) merged into ours.
.vscode/extensions.json and launch.json added by Nx are kept (do not
override our existing settings.json).
Initialize the Nx 22 monorepo via copy-from-scratch (the
create-nx-workspace 'apps' preset is now mapped to nrwl/empty-template
in Nx 22). Workspace files extracted from a scratch generation and
adapted to the project:
- package.json: name 'apf-portal' (renamed from @org/source default)
- tsconfig.base.json: customConditions aligned to apf-portal; strict TS
extended per ADR-0004 with noUncheckedIndexedAccess,
exactOptionalPropertyTypes, noPropertyAccessFromIndexSignature
- nx.json: nxCloudId stripped (on-prem, no Nx Cloud SaaS)
- .prettierrc: project convention (singleQuote, semi, printWidth 100)
- pnpm-workspace.yaml: apps/* and libs/** for the integrated layout
- pnpm-lock.yaml committed
Plugins for Angular, NestJS, Vite, ESLint will be added in the next
phase when apps are generated. The auto-generated CLAUDE.md / AGENTS.md
/ .claude/ / .github/ from the bootstrap were intentionally not
carried over (we keep our own CLAUDE.md and use Gitea, not GitHub).