Files
apf_portal/docs/decisions/README.md
T
julien 670f6303fe
CI / check (push) Successful in 2m0s
CI / commits (push) Has been skipped
CI / scan (push) Successful in 2m22s
CI / a11y (push) Successful in 3m11s
CI / perf (push) Successful in 6m15s
Docs site / build (push) Successful in 5m11s
docs(adr-0028): accept CI/CD + git hosting migration to GitLab (#227)
## Summary

Promotes [ADR-0028](docs/decisions/0028-migrate-cicd-and-git-hosting-to-gitlab.md) from `proposed` to `accepted`. Shipped as `proposed` in [#226](#226); no open question left on either drivers, considered options, or the 4-phase migration sequence. Same shape as [#219](#219) (ADR-0026 + ADR-0027 acceptance).

Once merged, **Phase 1** of the migration (`mirror-and-bootstrap` — repos pushed to GitLab, branch protection / MR templates / deploy keys / Renovate reconfig) is unblocked.

## What lands

| File | Change |
| --- | --- |
| `docs/decisions/0028-migrate-cicd-and-git-hosting-to-gitlab.md` | Frontmatter `status: proposed → accepted`. |
| `docs/decisions/0015-cicd-gitea-actions.md` | **Status-update note** added at the top, right under the title — calls out that the platform choice "Gitea Actions" is superseded by ADR-0028, while the rest of ADR-0015's architectural principles (trunk-based + squash, all-gates-blocking, thin YAML, on-prem runners, signed commits, Conventional Commits) carry over unchanged. ADR-0015 stays `accepted`. |
| `docs/decisions/README.md` | ADR-0028 row: `proposed → accepted`. |
| `CLAUDE.md` | Roll-up bumped to `ADRs 0001 → 0028 accepted` with a one-sentence explanation that ADR-0028 supersedes only ADR-0015's platform choice. **CI/CD architecture bullet rewritten** to reflect the accepted-but-not-yet-implemented state — "Gitea Actions today, migrating to GitLab CE on `vm-gitlab` per ADR-0028 (4-phase rollout in follow-up PRs)". The architectural detail (gates list, thin YAML, signed commits) was preserved; only the platform headline and the act_runner→GitLab Runner line are touched. Also corrected: `ci:scan` (which doesn't exist as a script) → the real script names (`ci:catalogue-drift`, `ci:audit`, `ci:perf`, `ci:gzip-budgets`). |

## Notes for the reviewer

- **No new Architecture bullet for ADR-0028 itself.** The decision is a *platform shift* for the existing CI/CD architecture, not a new architectural concern — so it folds into the existing ADR-0015 bullet rather than adding a sibling.
- **The annotation pattern on ADR-0015** (status-update blockquote at the top) is the canonical MADR way to handle partial supersession without changing the frontmatter status. The architectural principles are still accepted; only the platform implementation moves. A future reader hitting ADR-0015 first sees the redirect immediately.
- **The CLAUDE.md script-list correction** is a side-fix — `ci:scan` is not a real script name; the actual gates are `ci:check`, `ci:catalogue-drift`, `ci:audit`, `ci:commits`, `ci:perf`, `ci:gzip-budgets`. Updated in the same touch since the bullet was being rewritten anyway.
- **No code changes**, so no `pnpm ci:check` impact. `pnpm exec prettier --check` clean on the four touched files.

## Test plan

- [x] `pnpm exec prettier --check` — clean on the four touched files.
- [x] ADR-0015 → ADR-0028 cross-reference resolves (the new blockquote link).
- [x] `ADRs 0001 → 0028 accepted` matches reality (`grep '^status: ' docs/decisions/*.md` shows everything below 0029 as `accepted`).
- [ ] **Review focus** — the ADR-0015 status-update note phrasing, the CLAUDE.md CI/CD bullet rewrite (especially the "carry over" wording), the roll-up sentence about partial supersession.

## What's next (post-merge)

1. **Phase 1 — `mirror-and-bootstrap`** — `git push --mirror gitlab` for `apf_portal` and the proto vendoring in `apf-ai-service`. GitLab side: groups, projects, branch protection (mirror Gitea's), MR templates, deploy keys, Renovate reconfigured for GitLab. **No `.gitlab-ci.yml` yet** — Gitea pipelines continue to gate. Ops work primarily; the only PR-shaped output is a Renovate config update on the apf-portal repo if its host detection changes.
2. **Phase 2 — `gitlab-ci-pipeline`** — `.gitlab-ci.yml` lands alongside `.gitea/workflows/ci.yml`. Both pipelines run in parallel for ~1 calendar week. GitLab Runner registered on `vm-gitlab`.
3. **Phase 3 — `cutover`** — remotes flip in CLAUDE.md, READMEs, `docs/setup/01-dev-debian-vm-setup.md` §8.3. `.gitea/workflows/` + `infra/ci-runners.compose.yml` deleted, Gitea read-only / archive.
4. **Phase 4 — `cleanup`** — stale references sweep, required signed-commits on `main` enabled.

In parallel — once you've finished walking through the dev VM bootstrap — the paused **ADR-0027 PR 1** (Region / Delegation / Structure Prisma schema + inline seed) and **ADR-0026 PR 1** (Person / User / UserScope schema + provisioner) can ship on Gitea; they're decoupled from the migration and don't need to wait for it.

---------

Co-authored-by: Julien Gautier <julien.gautier@apf.asso.fr>
Reviewed-on: #227
2026-05-26 10:54:55 +02:00

75 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Architectural Decision Records
This project records architecturally-significant decisions as **ADRs** in the [MADR 4.0.0](https://github.com/adr/madr) format. References: [adr.github.io](https://adr.github.io/).
## Why ADRs
ADRs capture the _why_ behind a decision — context, drivers, options considered, trade-offs accepted — at the moment the decision is made. They make architecture reviewable, onboarding faster, and prevent the same debate from being re-litigated later.
## Conventions
- **Format:** MADR 4.0.0. Start from [template.md](template.md).
- **Filename:** `NNNN-kebab-case-title.md`, e.g. `0007-adopt-tailwind-for-design-tokens.md`.
- **Numbering:** globally sequential 4-digit prefix. Numbers never reset, never get reused — even when an ADR is superseded or deprecated.
- **Layout:** flat folder. ADRs are not nested into category subfolders; topical organization happens via tags.
- **Tags:** every ADR carries a `tags:` array in the MADR frontmatter, drawn from the [tag vocabulary](#tag-vocabulary) below. An ADR may carry several tags. Propose new tags (or renames) in the same PR that needs them; never invent ad-hoc tags inline.
- **Status lifecycle:** `proposed``accepted` → optionally `deprecated` or `superseded by [ADR-NNNN](NNNN-other.md)`. Update the YAML frontmatter; never delete an ADR.
- **Index maintenance:** every ADR addition or status change must update the [Index](#index) below in the same commit.
## When to write an ADR
Write one whenever a development decision is non-trivial: tool or library choice, framework pattern, security control, perf budget, a11y target, naming convention, deprecation, breaking change, or any choice that future contributors would benefit from understanding the _why_ of.
## Tag vocabulary
The vocabulary below is the source of truth. It is intentionally coarse — propose extensions only when an existing tag genuinely doesn't fit, and avoid overly narrow tags.
| Tag | Scope |
| ---------------- | ------------------------------------------------------------------- |
| `frontend` | UI, Angular, components, design system, client-side state |
| `backend` | API, BFF, server-side services |
| `security` | AuthN, AuthZ, sessions, CSP, dependency scanning, secret management |
| `performance` | Perf budgets, caching, bundle size, Lighthouse |
| `accessibility` | WCAG, a11y testing, keyboard, ARIA, contrast |
| `infrastructure` | CI/CD, hosting, deployment, runtime |
| `observability` | Logs, metrics, traces, correlation IDs, monitoring |
| `data` | Persistence, schemas, migrations, data flow |
| `process` | Team conventions, workflows, repo policy |
> _Status: starter vocabulary, to be refined as ADRs accumulate. Update this table whenever a tag is added, renamed, or retired._
## Index
ADRs are listed in numerical order. To slice by topic, filter on the `Tags` column.
| # | Title | Status | Tags | Date |
| ------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | -------- | -------------------------------------------------------------- | ---------- |
| [0001](0001-use-adrs-to-record-architectural-decisions.md) | Use ADRs to record architectural decisions | accepted | `process` | 2026-04-29 |
| [0002](0002-adopt-nx-monorepo-apps-preset.md) | Adopt Nx monorepo with the `apps` preset | accepted | `infrastructure`, `frontend`, `backend` | 2026-04-29 |
| [0003](0003-workspace-and-app-naming-convention.md) | Workspace and app naming convention | accepted | `process` | 2026-04-29 |
| [0004](0004-frontend-stack-angular-csr-zoneless-signals.md) | Frontend stack — Angular (latest LTS), standalone, zoneless, Signals, CSR-only, Vitest | accepted | `frontend` | 2026-04-29 |
| [0005](0005-backend-stack-nestjs.md) | Backend stack — NestJS over Express, Fastify, Hono | accepted | `backend` | 2026-04-29 |
| [0006](0006-persistence-postgresql-prisma.md) | Persistence — PostgreSQL with Prisma | accepted | `data`, `backend` | 2026-04-29 |
| [0007](0007-pre-commit-hooks-and-conventional-commits.md) | Pre-commit hooks and Conventional Commits | accepted | `process` | 2026-04-29 |
| [0008](0008-identity-model-entra-workforce-dual-audience.md) | Identity model — multi-tenant Entra ID for workforce, dual-audience design for future External ID | accepted | `security`, `data` | 2026-04-29 |
| [0009](0009-auth-flow-oidc-pkce-msal-node.md) | Authentication flow — OIDC Authorization Code + PKCE via MSAL Node, BFF session pattern | accepted | `security`, `backend` | 2026-04-29 |
| [0010](0010-session-management-redis.md) | Session management — opaque session IDs in cookies, payload in self-hosted Redis with AES-GCM at rest | accepted | `security`, `backend`, `infrastructure` | 2026-04-29 |
| [0011](0011-mfa-enforcement-entra-conditional-access.md) | MFA enforcement — Entra ID Conditional Access baseline, BFF claim sanity-check, step-up hooks designed-in | accepted | `security` | 2026-04-29 |
| [0012](0012-observability-pino-opentelemetry.md) | Observability — Pino structured logs + OpenTelemetry tracing, W3C Trace Context propagation, stdout + collector | accepted | `observability`, `backend`, `frontend` | 2026-04-29 |
| [0013](0013-audit-trail-separated-postgres-append-only.md) | Audit trail — separated append-only Postgres schema, decoupled from app logs | accepted | `security`, `observability`, `data` | 2026-04-29 |
| [0014](0014-downstream-api-access-obo-pattern.md) | Downstream API access — On-Behalf-Of pattern, unified `DownstreamApiClient`, audience-aware authorization | accepted | `security`, `backend` | 2026-04-29 |
| [0015](0015-cicd-gitea-actions.md) | CI/CD pipeline — Gitea Actions, trunk-based + squash-merge, thin YAML over portable scripts | accepted | `infrastructure`, `process` | 2026-04-30 |
| [0016](0016-accessibility-baseline-wcag-aa-targeted-aaa.md) | Accessibility baseline — WCAG 2.2 AA + targeted AAA, Angular CDK + spartan-ng + Tailwind, APF panel testing | accepted | `accessibility`, `frontend`, `process` | 2026-04-30 |
| [0017](0017-performance-budgets-lighthouse-ci.md) | Performance budgets — Core Web Vitals + Lighthouse CI gates, bundle budgets, BFF p95/p99 SLOs | accepted | `performance`, `frontend`, `backend`, `process` | 2026-04-30 |
| [0018](0018-environment-configuration-strategy.md) | Environment configuration — Angular `environment.ts`, BFF env vars, audit pool split | accepted | `frontend`, `backend`, `infrastructure`, `process` | 2026-05-10 |
| [0019](0019-internationalisation-angular-localize.md) | Internationalisation — `@angular/localize`, build-time per-locale bundles, `/fr` + `/en` path-based routing | accepted | `frontend`, `accessibility`, `performance`, `process` | 2026-05-11 |
| [0020](0020-portal-admin-app.md) | `portal-admin` — dedicated SPA for portal administration, sharing the existing BFF | accepted | `frontend`, `backend`, `security`, `infrastructure`, `process` | 2026-05-11 |
| [0021](0021-phase-2-security-baseline.md) | Phase-2 security baseline — helmet, CORS allowlist, double-submit CSRF, rate limiting, structured error envelope | accepted | `security`, `backend` | 2026-05-13 |
| [0022](0022-docs-site-vitepress.md) | Documentation site — VitePress + Mermaid plugin, separate static deployment | accepted | `process`, `infrastructure` | 2026-05-15 |
| [0023](0023-charts-d3-observable-plot.md) | Charts + dashboards — D3 + Observable Plot wrapped in `libs/shared/charts` | accepted | `frontend`, `accessibility`, `performance` | 2026-05-16 |
| [0024](0024-ai-service-relay-grpc-sse-bridge.md) | AI service relay — vendored gRPC protos, NestJS gRPC client, SSE bridge to the SPA, POC unsigned principal | accepted | `backend`, `security`, `observability` | 2026-05-19 |
| [0025](0025-authorization-model-privileges-roles-scopes.md) | Authorization model — three orthogonal axes (privileges × functional roles × scopes), Entra-backed | accepted | `security`, `backend`, `data` | 2026-05-20 |
| [0026](0026-person-user-portal-data-model.md) | `Person` golden record + `User` portal-account — portal-side identity model | accepted | `data`, `backend`, `security` | 2026-05-24 |
| [0027](0027-portal-side-organisational-hierarchy.md) | Portal-side organisational hierarchy — `Structure` with kind discriminator and nullable FINESS / SIRET | accepted | `data`, `backend` | 2026-05-24 |
| [0028](0028-migrate-cicd-and-git-hosting-to-gitlab.md) | Migrate CI/CD + git hosting from Gitea to GitLab self-hosted | accepted | `infrastructure`, `process` | 2026-05-26 |