Files
apf_portal/docs/decisions/0002-adopt-nx-monorepo-apps-preset.md
Julien Gautier 0e58e32d29 chore: relocate ADRs from decisions/ to docs/decisions/ to consolidate documentation
Move the ADR folder under docs/ alongside the rest of the project
documentation. Convention (flat folder, globally-sequential 4-digit
numbering, tags-based categorization, MADR 4.0.0 format) is unchanged
- only the path moved.

- git mv decisions docs/decisions preserves history for all 18 ADRs +
  README + template (19 files renamed in this commit).
- ADR-0001 amended in-place with a dated note documenting the
  relocation. Status remains 'accepted' - the location detail
  changed, the decision did not.
- All cross-references updated:
  - CLAUDE.md (~17 ADR links + 3 mentions of decisions/ in the Project
    rules section)
  - docs/README.md (now references decisions/ as a sibling under docs/)
  - docs/setup/03-angular-nx-monorepo.md (paths shortened from
    ../../decisions/ to ../decisions/, since setup/ and decisions/ are
    now both inside docs/)
  - docs/decisions/0003 ../CLAUDE.md adjusted to ../../CLAUDE.md
    (one extra level of nesting)
  - docs/decisions/template.md mention of the README path
  - notes/asvs-level-decision-briefing-rssi.md mention of the index

Sanity verified: every ADR link in CLAUDE.md, docs/setup/03, and
docs/decisions/0001 resolves to an existing file. pnpm nx run-many
-t lint passes on 8 projects.
2026-04-30 18:57:59 +02:00

94 lines
4.6 KiB
Markdown

---
status: accepted
date: 2026-04-29
decision-makers: R&D Lead
tags: [infrastructure, frontend, backend]
---
# Adopt Nx monorepo with the `apps` preset
## Context and Problem Statement
`apf-portal` will host two cooperating runtime artifacts from day one — an Angular SPA frontend and a Node.js BFF backend — and is expected to grow with feature libraries shared between them (auth, data-access, UI primitives). Strongly-typed contracts must travel from back to front without round-tripping through a published package, dependency hygiene must be enforceable, and CI must run only on what changed.
How do we structure the repository so both apps coexist with shared libraries, builds and tests run incrementally, and the tooling is mainstream enough to be supported long-term?
## Decision Drivers
- Two cooperating runtimes (Angular + NestJS), both TypeScript, sharing types and contracts on the wire.
- Need for incremental, cached builds and tests on what changed (`affected`-style workflow).
- Long-term enterprise track record — no exotic stack.
- Compatibility with `pnpm` (already mandated by project setup).
- Enforceable dependency boundaries between apps and libs.
## Considered Options
- **Polyrepos** — separate repository per runtime.
- **Nx with the `apps` preset** — generic multi-tech workspace, plugins added as needed (`@nx/angular`, `@nx/nest`).
- **Nx with the `angular-monorepo` preset** — front-first preset, BFF grafted on later.
- **Turborepo + pnpm workspaces** — lighter alternative to Nx.
- **pnpm workspaces alone** — manual orchestration, no monorepo tool.
## Decision Outcome
Chosen option: **Nx monorepo with the `apps` preset, managed by pnpm**.
The workspace will host:
- `apps/portal-shell` — Angular SPA frontend (see [ADR-0004](0004-frontend-stack-angular-csr-zoneless-signals.md));
- `apps/portal-bff` — NestJS BFF backend (see [ADR-0005](0005-backend-stack-nestjs.md));
- `libs/shared/<scope>` and `libs/feature/<name>` for shared and feature code (see [ADR-0003](0003-workspace-and-app-naming-convention.md)).
Plugins enabled at bootstrap: `@nx/angular`, `@nx/nest`, `@nx/eslint`, `@nx/vite` (Vitest).
### Consequences
- Good, because front and back share types, lint config, formatter, and test runner with no extra plumbing.
- Good, because Nx's project graph + `affected` make CI fast and frugal as the codebase grows.
- Good, because the `apps` preset stays neutral — neither runtime is privileged in workspace structure.
- Good, because Nx is mainstream, used by major enterprises, and actively maintained by Nrwl.
- Bad, because Nx adds a non-trivial conceptual surface (executors, generators, project graph) — a one-time learning cost.
- Bad, because monorepos require discipline to keep dependency boundaries clean — mitigated by Nx's `enforce-module-boundaries` lint rule.
### Confirmation
- Workspace is bootstrapped with `pnpm dlx create-nx-workspace@latest apf-portal --preset=apps --pm=pnpm`.
- `nx.json` has `@nx/eslint/enforce-module-boundaries` enabled and configured against the project tags.
- CI runs `pnpm nx affected -t lint test build` on every push.
## Pros and Cons of the Options
### Polyrepos
- Good, because each runtime has independent versioning and CI scope.
- Bad, because sharing TypeScript types across repos requires a published package (overhead, version drift).
- Bad, because cross-cutting changes (e.g. adjusting an auth claim shape) touch two repos and two PRs.
### Nx with `apps` preset (chosen)
- Good, because runtime-agnostic — Angular and Node coexist as peers.
- Good, because Nx provides build orchestration, caching, generators, and lint boundaries out of the box.
### Nx with `angular-monorepo` preset
- Good, because faster initial setup for a front-first project.
- Bad, because the preset implies the project is "an Angular workspace" — the BFF feels grafted, the workspace `package.json` ends up biased toward Angular tooling.
### Turborepo
- Good, because lighter, no codegen surface.
- Neutral, because caching/affected is comparable.
- Bad, because no first-class Angular plugin; both runtimes would need manual integration.
- Bad, because smaller enterprise track record than Nx.
### pnpm workspaces alone
- Good, because no extra tool to learn.
- Bad, because no caching, no `affected`, no generators — every piece reinvented by hand (the bricolage we're forbidden).
## More Information
- Nx documentation: https://nx.dev
- Nx `apps` preset: https://nx.dev/getting-started/intro
- Related ADRs: [ADR-0003](0003-workspace-and-app-naming-convention.md), [ADR-0004](0004-frontend-stack-angular-csr-zoneless-signals.md), [ADR-0005](0005-backend-stack-nestjs.md), ADR-0017 (CI/CD, future).