Generate the four phase-4 libraries:
- libs/shared/tokens (project name shared-tokens) - plain TS lib via
@nx/js:library; will host the a11y design tokens (palette,
contrast tiers, spacing, motion) once Tailwind lands in phase 5;
consumable by both apps; tagged scope:shared, type:shared.
- libs/shared/util (shared-util) - plain TS lib for cross-cutting
utility code; tagged scope:shared, type:shared.
- libs/shared/ui (shared-ui) - Angular standalone library that will
host the spartan-ng components copy-pasted in phase 5; Angular-only
so tagged scope:portal-shell, type:shared. unitTestRunner=
vitest-analog because vitest-angular requires a buildable lib.
- libs/feature/auth (feature-auth) - placeholder Angular standalone
feature lib to demonstrate the type:feature pattern; tagged
scope:portal-shell, type:feature.
@nx/enforce-module-boundaries depConstraints replaced (root
eslint.config.mjs) with the rules from ADR-0003:
scope:portal-shell -> scope:portal-shell, scope:shared
scope:portal-bff -> scope:portal-bff, scope:shared
scope:shared -> scope:shared
type:app -> type:feature, type:shared
type:feature -> type:feature, type:shared
type:shared -> type:shared
This forbids portal-shell from importing portal-bff code (and vice
versa) and prevents shared libs from depending on feature libs.
Project names follow the convention of ADR-0003 (feature-<name> /
shared-<scope>) by passing --name explicitly to the generator; the Nx
22 default takes only the last directory segment.
Sanity check: pnpm nx run-many -t lint and -t test pass for the 8
projects (4 apps/e2e + 4 libs).
Side effects from the generators: tsconfig.base.json paths populated
with the lib import aliases; nx.json gains vite/playwright plugin
entries; .gitignore picks up vitest.config.*.timestamp* (Vitest temp
files); package.json gains @analogjs/vitest-angular and related
devDeps; pnpm-lock.yaml regenerated. Two eslint-disable comments in
portal-bff-e2e support files were trimmed by lint --fix - those files
already lint clean without the directive.
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).
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.