Commit Graph

3 Commits

Author SHA1 Message Date
Julien Gautier 428d19f60f feat(portal-bff): ai-client skeleton — vendored protos + grpc client + Principal mapper
CI / commits (pull_request) Successful in 3m34s
CI / scan (pull_request) Successful in 3m47s
CI / check (pull_request) Successful in 6m15s
CI / a11y (pull_request) Successful in 2m26s
Docs site / build (pull_request) Successful in 1m7s
CI / perf (pull_request) Successful in 4m33s
Lands the BFF-side skeleton for the apf-ai-service relay per ADR-0024,
step 2 of the chantier (skeleton + tests against an in-process fake
gRPC server; no live HTTP endpoint yet — that ships in the SSE-bridge
PR).

What ships:

- contract/proto vendoring at apps/portal-bff/src/grpc/proto/apf-ai/
  (common, chat, rag, ingestion, models). pnpm run grpc:sync refreshes
  from the sibling apf-ai-service tree; both .proto and the ts-proto
  TypeScript stubs under grpc/gen/ are committed for hermetic builds
  and reviewable diffs.
- Codegen via pnpm run grpc:codegen using grpc-tools' bundled protoc
  and ts-proto (outputServices=grpc-js, esModuleInterop, forceLong,
  useOptionals=messages). Generated tree is excluded from Prettier
  and ESLint so hand-rules do not chase codegen output.
- assertAiServiceConfig() pre-flight validator alongside the other
  config validators (AI_SERVICE_GRPC_ENDPOINT, AI_SERVICE_CLIENT_ID,
  AI_SERVICE_GRPC_TLS).
- AiClientModule provides ChatClient / RagClient / IngestionClient /
  ModelsClient wrappers, a GrpcMetadataBuilder that stamps every call
  with x-client-id + x-correlation-id (W3C trace-id from OTel when a
  span is active, explicit override or UUID fallback otherwise), and
  a PrincipalMapper that hashes the Entra oid via HashUserIdService
  so the proto Principal.subject matches audit.events.actor_id_hash
  exactly (ADR-0013 cross-reference contract).
- Specs cover: env validator, principal mapper, metadata builder
  (OTel span / override / fallback paths), chat client streaming +
  cancellation against an in-process fake gRPC ChatService, rag
  client unary happy path + error propagation, and module bootstrap.

AiClientModule is NOT imported in AppModule yet — the SSE-bridge
controller and its live route ship in the next PR.
2026-05-19 20:50:04 +02:00
Julien Gautier bea5e1954f chore: generate portal-shell and portal-bff apps per ADR-0004 / ADR-0005
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).
2026-04-30 16:12:42 +02:00
Julien Gautier 64ea72b321 chore: bootstrap Nx workspace per ADR-0002
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).
2026-04-30 16:07:11 +02:00