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.
5.0 KiB
5.0 KiB
status, date, decision-makers, tags
| status | date | decision-makers | tags | |
|---|---|---|---|---|
| accepted | 2026-04-29 | R&D Lead |
|
Frontend stack — Angular (latest LTS), standalone, zoneless, Signals, CSR-only, Vitest
Context and Problem Statement
The portal's frontend (portal-shell) is a single-page application that aggregates access to existing applications and progressively integrates re-developed features. It sits fully behind authentication: no public content. We need to fix the framework, the rendering mode, the change-detection model, and the test runner now, so subsequent ADRs (auth flow, observability, accessibility, performance budgets) can build on a stable foundation.
What frontend stack maximizes alignment with our backend (NestJS), gives us first-class accessibility and performance hooks, and is enterprise-stable for a long-lived project?
Decision Drivers
- Architectural alignment with NestJS (DI, decorators, modules, RxJS) — minimizes cognitive distance for the team.
- Performance and accessibility as first-class concerns from day one.
- Long-term enterprise stability (no pre-1.0, no exotic stack).
- End-to-end type safety.
- No public surface — all content gated by authentication, which removes the usual SSR drivers (SEO, anonymous LCP).
Considered Options
- Angular (latest LTS) — standalone, zoneless, Signals, CSR, Vitest. (Chosen.)
- Angular with SSR (
@angular/ssr). - React + Next.js (or Vite + React Router).
- Vue + Nuxt.
- Svelte + SvelteKit.
Decision Outcome
Chosen option: Angular at the latest LTS major, with the following modern defaults:
- Standalone APIs — no
NgModules. Configuration is composed via providers; routing is functional. - Zoneless change detection — no
Zone.js. Change detection is driven by Signals and explicitmarkForCheckwhere needed. - Signals — primary reactive primitive for component state. RxJS retained for async streams (HTTP, events).
- Vitest — unit and component test runner (Karma is deprecated upstream).
- CSR only — no SSR for v1. Reconsider only if a measured performance metric requires it.
- SCSS for styles. Design-token strategy to be defined in a future ADR.
- Strict TypeScript across the workspace (
strict: true,noUncheckedIndexedAccess: true).
Consequences
- Good, because the team works with a single mental model across front and back (DI, decorators, RxJS).
- Good, because zoneless + Signals removes Zone.js overhead and gives finer-grained, more predictable reactivity.
- Good, because Vitest is significantly faster than Karma and shares the Vite toolchain Nx already uses.
- Good, because CSR keeps the BFF free of SSR concerns (no auth-aware rendering, no double-fetch, no hydration debugging) — simpler operational surface.
- Bad, because Angular's release cadence is brisk; the project commits to staying on LTS rather than skipping versions.
- Bad, because zoneless and Signals are recent — though stable, the broader Angular ecosystem still includes Zone-dependent libraries that must be vetted before adoption.
- Bad, because CSR yields a minimal initial HTML payload; this must be paired with strong performance budgets (covered by ADR-0015, future).
Confirmation
package.jsonpins Angular to the current LTS major.app.config.tsregistersprovideZonelessChangeDetection()(or its current stable equivalent) and standalone routing.tsconfig.base.jsonsetsstrict: trueandnoUncheckedIndexedAccess: true.- CI runs
pnpm nx test portal-shell(Vitest). - No
import 'zone.js'anywhere in the codebase. @angular/ssris not installed.
Pros and Cons of the Options
Angular CSR (chosen)
- Good, because alignment with NestJS minimizes context-switching for the team.
- Good, because mature, enterprise-supported (Google + community).
- Good, because Signals + zoneless make Angular's reactivity competitive with React/Vue.
- Bad, because verbosity is higher than minimalist frameworks.
Angular SSR
- Good, because better TTFB and accessibility on first paint for unauthenticated content.
- Bad, because we have no unauthenticated content — the gain is essentially zero.
- Bad, because SSR-with-auth introduces non-trivial complexity (cookie-aware fetch, hydration with secured data).
React + Next.js
- Good, because large ecosystem, fast iteration.
- Bad, because no architectural alignment with NestJS — different DI/state paradigms.
- Bad, because Next.js's defaults push toward server components and edge rendering, which conflict with our on-prem, all-authenticated profile.
Vue + Nuxt / Svelte + SvelteKit
- Good, because lighter syntax, strong DX.
- Bad, because no DI alignment with NestJS.
- Bad, because smaller enterprise-grade community than Angular or React.
More Information
- Angular zoneless change detection: https://angular.dev/guide/experimental/zoneless
- Angular Signals: https://angular.dev/guide/signals
- Vitest with Nx: https://nx.dev/nx-api/vite
- Related ADRs: ADR-0005, ADR-0008 (auth flow, future), ADR-0014 (accessibility, future), ADR-0015 (performance budgets, future).