docs(setup): add Debian 13 dev-VM setup procedure + scripts + devcontainer (#220)
## Summary Adds a full Debian 13 dev-VM setup procedure ([docs/setup/01-dev-debian-vm-setup.md](docs/setup/01-dev-debian-vm-setup.md)) + 10 modular idempotent setup scripts + a systemd template + a `.devcontainer/` spec, in preparation for the new dev VM (`10.100.201.21`) replacing the WSL-based workflow. Both IDE flows (VSCode Remote-SSH + Devcontainer) and both Node toolchains (nvm on host + devcontainer image) are available — devs pick per task. Adjacent context (does not ship here, planned follow-up): - **Preview infra on the GitLab VM (`10.100.201.10`)** — same `dev.compose.yml`, deployed by CI on `main`. Doc placeholder in §8.6. - **GitLab Runner migration** (act_runner Gitea → GitLab Runner Docker executor) — bundled with the Gitea → GitLab cutover. - **Private dotfiles repo** (`apf/dotfiles`) — `~/.zshrc`, `~/.p10k.zsh`, `~/.tmux.conf` versioned. `80-dotfiles.sh` is already structured to fall back to a `~/.dotfiles/` clone when present. No application-code changes. No CI gate impact (doc + scripts + devcontainer spec only). ## What lands | Path | Change | | --- | --- | | `docs/setup/01-dev-debian-vm-setup.md` | **New.** Step-by-step doc: workstation prep (SSH agent + VSCode Remote-SSH + fonts), bootstrap orchestrator, per-script effects, project clone, infra boot, IDE flow A / B / C, apf-ai-service .NET appendix, troubleshooting. | | `docs/setup/02-wsl-terminal-setup.md` | Renamed from `01-wsl-terminal-setup.md`. No content change. | | `docs/setup/03-dev-web-stack.md` | Renamed from `02-dev-web-stack.md`. No content change. | | `docs/setup/04-angular-nx-monorepo.md` | Renamed from `03-angular-nx-monorepo.md`. No content change. | | `docs/setup/README.md` | **New.** Index of the `docs/setup/` folder. | | `docs/setup/scripts/lib.sh` | **New.** Shared helpers — colour-coded log/ok/warn/err/skip, `apt_install` skipping already-installed, `ensure_line` idempotent append, `confirm` prompt. | | `docs/setup/scripts/bootstrap.sh` | **New.** Orchestrator running scripts 10..80 in order with confirmation prompts. | | `docs/setup/scripts/10-base-packages.sh` | **New.** apt update + base packages (curl, wget, git, build-essential, …). | | `docs/setup/scripts/20-zsh.sh` | **New.** zsh + Oh My Zsh (RUNZSH=no, no shell hijack) + Powerlevel10k + `zsh-autosuggestions` + `zsh-syntax-highlighting`. Patches `~/.zshrc` (theme, plugins, fzf hook). | | `docs/setup/scripts/30-cli-tools.sh` | **New.** `bat eza fd-find ripgrep fzf zoxide ncdu keychain` + `jq yq httpie make tree htop tmux direnv dnsutils unzip rsync`. Symlinks Debian-renamed binaries (`batcat`→`bat`, `fdfind`→`fd`) into `~/.local/bin` so notes/aliases.zsh works as-is. | | `docs/setup/scripts/40-node.sh` | **New.** nvm v0.40.1 + Node from `.nvmrc` (currently 24) + corepack enable + pnpm warmed from `package.json#packageManager`. | | `docs/setup/scripts/50-docker.sh` | **New.** Docker CE + compose plugin from docker.com apt repo, user added to `docker` group, `docker.service` enabled at boot. Pinned GPG key + repo line for Debian Trixie. | | `docs/setup/scripts/60-tuning.sh` | **New.** `fs.inotify.max_user_watches=524288` (Vite/Nx watch ceiling), optional 4 GB swapfile, optional hostname rename (only prompts on generic hostnames like `debian13`). | | `docs/setup/scripts/70-hardening.sh` | **New.** Best-effort UFW (`allow OpenSSH` only) + unattended-upgrades on security channel + fail2ban + sshd drop-in (`PermitRootLogin no`, `PasswordAuthentication no`, `AllowAgentForwarding yes`). Probes before applying, validates `sshd -t` before reloading, skips cleanly if infra already locked the box down. | | `docs/setup/scripts/80-dotfiles.sh` | **New.** Symlinks `notes/aliases.zsh` → `~/.oh-my-zsh/custom/aliases.zsh` (backs up an existing target). Copies `notes/gitconfig.txt` to `~/.gitconfig`, prompts for identity, applies via `git config --global user.name/email`. | | `docs/setup/systemd/apf-portal-infra@.service` | **New.** Template systemd unit auto-starting `./infra/local/dev.sh up` at boot. Install: `enable apf-portal-infra@$USER.service`. | | `.devcontainer/devcontainer.json` | **New.** VSCode Dev Container spec on `mcr.microsoft.com/devcontainers/typescript-node:1-24-bookworm`. `docker-outside-of-docker` feature + `--network=apf-portal-dev` so DNS to `postgres`/`redis`/`otel-collector` works. `initializeCommand` fails fast if `dev.sh up` hasn't been run yet. Forwarded ports labelled. Six dev extensions pre-installed. | | `.devcontainer/post-create.sh` | **New.** `corepack enable && pnpm install --frozen-lockfile`. | | `CLAUDE.md` | "Environment conventions" rewritten: documents the two envs (`local` / `development`) + hybrid sub-mode + the two IDE flows (Remote-SSH / Devcontainer), points at the new VM setup doc and the legacy WSL doc. | ## Key choices - **Idempotent scripts, individually runnable.** Each script probes before doing anything (apt package already installed? plugin already cloned? UFW already active? sshd drop-in already present?). Bootstrap is the orchestrator; each script also runs standalone. Re-running after a partial setup is safe and reports `↪ skip` for the no-op cases. - **No private key on the VM — SSH agent forwarding instead.** `~/.ssh/config` on the workstation carries `ForwardAgent yes`; the VM never holds long-lived secrets. Same future pattern for GPG signing (covered in §8.5 as appendix). `keychain` is installed by `30-cli-tools.sh` as a fallback for scenarios where agent forwarding is not available (CI runners, scripts). - **Hardening is "best-effort, probe-first".** Some infra teams ship pre-hardened VMs; this script doesn't fight that. UFW already active? Print rules and skip. unattended-upgrades already on? Skip. SSH already locked down? Skip. Each section validates before reloading so a misconfig can't take SSH offline. - **Devcontainer assumes infra-on-host.** The container runs on the VM but talks to postgres / redis / otel **on the same VM's host docker daemon** through the shared `apf-portal-dev` Compose network. `initializeCommand` fails fast with a clear message if `./infra/local/dev.sh up` hasn't been run yet — better than puzzling `ECONNREFUSED` errors at runtime. - **`60-tuning.sh` raises inotify to 524288.** Default Debian limit is 8K; Vite/Nx in this monorepo blow past that. The setting is persisted in `/etc/sysctl.d/99-apf-portal.conf` so it survives reboot. - **Hybrid mode (workstation IDE + VM infra) is a documented sub-mode.** SSH `LocalForward` directives on 5432/6379/4317/4318 expose the VM's infra services as `localhost:*` on the workstation. Latency cost: 5-15 ms per query, fine for daily work; for long-running flows, wrap in `tmux` or use `autossh`. ## Notes for the reviewer - **Renaming the existing setup docs (01→02, 02→03, 03→04) is the only "destructive" change.** `git log --follow` still works because of `git mv`. Diff shows up as renames, not delete-and-add. - **The brief asked for `bat eza fd-find ripgrep fzf zoxide docker keychain ncdu git`.** `git` is installed by `10-base-packages.sh` (every other script needs it). Everything else lives in `30-cli-tools.sh` + `50-docker.sh`. The "fullstack-dev extras" (`jq yq httpie make tree htop tmux direnv dnsutils unzip rsync`) are additions I proposed in the lock-in question and that you greenlit (full scope) — easy to trim if any of them turn out to be unwanted. - **Both Node toolchains in parallel** — nvm on the VM (via `40-node.sh`) **and** devcontainer in the repo. Devs can use either; both read the same `.nvmrc` + `packageManager` pin so the version stays consistent. - **The systemd unit is a TEMPLATE** (`apf-portal-infra@.service`) — install once, enable per-user (`enable apf-portal-infra@$USER.service`). This is the right shape for a shared VM with multiple devs eventually, even if today only one user uses it. - **No PR-body Co-Authored-By trailer, no Generated-with-Claude footer**, per the project rule. ## Test plan Manual (no automated test exists for this kind of setup work): - [ ] On a fresh Debian 13 VM: `git clone …`, `./docs/setup/scripts/bootstrap.sh`, answer prompts, end up with zsh + Powerlevel10k + all the requested CLI tools + Node 24 + pnpm 10.33.4 + Docker on PATH. - [ ] `./infra/local/dev.sh up` boots successfully against the VM's local docker daemon. - [ ] `pnpm install` + `pnpm exec nx run-many -t lint test --parallel=3` passes on the VM. - [ ] VSCode Remote-SSH from a workstation: connect, open `~/Works/apf_portal`, run `pnpm exec nx serve portal-bff`, confirm reaches `postgres:5432`. - [ ] VSCode Dev Containers from the same workstation: `Reopen in Container`, image builds, `postCreateCommand` runs `pnpm install`, dev server reaches postgres through the `apf-portal-dev` network. - [ ] Hybrid mode: SSH tunnel from workstation, `pnpm exec nx serve portal-bff` locally, confirm postgres reachable via `localhost:5432`. - [x] `pnpm exec prettier --check` clean on the touched markdown files. - [x] Scripts pass `bash -n` (syntax check) — verified during writing. ## What's next - Validate by walking through this doc on the actual VM `10.100.201.21`. Any friction surfaced becomes a follow-up PR (`docs(setup): ...`). - Once the dev VM is operational, return to **ADR-0027 Implementation PR 1** (Region / Delegation / Structure Prisma schema + inline reference-data migration) — paused since the start of this PR. - Set up the **private dotfiles repo** (`apf/dotfiles`) as a small follow-up, then teach `80-dotfiles.sh` to prefer the dotfiles repo over `notes/`. - When migrating to GitLab: PR pair — (a) `git remote set-url` doc updates here, (b) `infra/gitlab-runners/` replacing `infra/ci-runners.compose.yml`. - Future: deploy the **shared preview infra** on `vm-gitlab` (10.100.201.10) — CI-driven, separate PR. --------- Co-authored-by: Julien Gautier <julien.gautier@apf.asso.fr> Reviewed-on: #220
This commit was merged in pull request #220.
This commit is contained in:
@@ -0,0 +1,356 @@
|
||||
# 🏗️ Bootstrap the Nx monorepo for apf-portal
|
||||
|
||||
> **Status.** Aligned with phase-1 ADRs ([0002](../decisions/0002-adopt-nx-monorepo-apps-preset.md), [0003](../decisions/0003-workspace-and-app-naming-convention.md), [0004](../decisions/0004-frontend-stack-angular-csr-zoneless-signals.md), [0005](../decisions/0005-backend-stack-nestjs.md), [0006](../decisions/0006-persistence-postgresql-prisma.md)). Replaces the original placeholder-based draft.
|
||||
|
||||
## Goal
|
||||
|
||||
Scaffold the `apf-portal` Nx monorepo containing:
|
||||
|
||||
- `apps/portal-shell` — Angular SPA frontend (CSR, standalone, zoneless, Signals, Vitest, SCSS, strict TS).
|
||||
- `apps/portal-bff` — NestJS BFF backend (Express adapter, global `ValidationPipe`, Jest test runner).
|
||||
- `libs/feature/<name>` and `libs/shared/<scope>` — feature and shared libraries.
|
||||
|
||||
Out of scope here (covered by later phases): authentication (Entra ID), sessions (Redis), observability (Pino + OpenTelemetry), audit trail, accessibility / performance / security baselines in CI, downstream API integration, on-prem infrastructure stack.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- WSL + Zsh — see [01-wsl-terminal-setup.md](01-wsl-terminal-setup.md).
|
||||
- Node.js latest LTS + pnpm via corepack — see [02-dev-web-stack.md](02-dev-web-stack.md).
|
||||
- Working tree under the WSL filesystem (`~/dev/`, `~/Works/`), never `/mnt/c/`.
|
||||
- The repository `apf-portal` already exists locally with the ADRs and docs committed (you are reading one of them).
|
||||
|
||||
---
|
||||
|
||||
## 1) Initialize the Nx workspace inside the existing repository
|
||||
|
||||
The repository already carries documentation, ADRs, `.vscode/`, and `.gitignore`. `create-nx-workspace` always generates into a _new_ directory, so we generate next to the repo and copy the workspace files in.
|
||||
|
||||
```bash
|
||||
# 1. Generate a clean Nx workspace next to the repo
|
||||
cd ~/dev # or any scratch location outside the repo
|
||||
pnpm dlx create-nx-workspace@latest apf-portal-bootstrap \
|
||||
--preset=apps \
|
||||
--pm=pnpm \
|
||||
--ci=skip \
|
||||
--useGitHub=false
|
||||
|
||||
# 2. Copy the workspace files into the existing repo
|
||||
cd apf-portal-bootstrap
|
||||
cp -v package.json pnpm-workspace.yaml nx.json tsconfig.base.json \
|
||||
.prettierrc .prettierignore .editorconfig \
|
||||
eslint.config.mjs \
|
||||
~/Works/apf_portal/
|
||||
|
||||
# 3. Drop the scratch workspace
|
||||
cd ~ && rm -rf ~/dev/apf-portal-bootstrap
|
||||
```
|
||||
|
||||
The `apps` preset is generic — it does not privilege a runtime ([ADR-0002](../decisions/0002-adopt-nx-monorepo-apps-preset.md)). Plugins are added in step 2.
|
||||
|
||||
Verify:
|
||||
|
||||
```bash
|
||||
cd ~/Works/apf_portal
|
||||
pnpm install
|
||||
ls nx.json package.json tsconfig.base.json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2) Install Angular and Node plugins
|
||||
|
||||
```bash
|
||||
pnpm add -D @nx/angular @nx/nest @nx/vite @nx/eslint @nx/js
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3) Generate the frontend app — `portal-shell`
|
||||
|
||||
```bash
|
||||
pnpm nx g @nx/angular:application portal-shell \
|
||||
--directory=apps/portal-shell \
|
||||
--routing=true \
|
||||
--standalone=true \
|
||||
--style=scss \
|
||||
--bundler=esbuild \
|
||||
--unitTestRunner=vitest \
|
||||
--e2eTestRunner=playwright \
|
||||
--strict=true \
|
||||
--tags="scope:portal-shell,type:app"
|
||||
```
|
||||
|
||||
### Enable zoneless change detection (ADR-0004)
|
||||
|
||||
Edit `apps/portal-shell/src/app/app.config.ts`:
|
||||
|
||||
```typescript
|
||||
import { ApplicationConfig, provideZonelessChangeDetection } from '@angular/core';
|
||||
import { provideRouter } from '@angular/router';
|
||||
import { routes } from './app.routes';
|
||||
|
||||
export const appConfig: ApplicationConfig = {
|
||||
providers: [provideZonelessChangeDetection(), provideRouter(routes)],
|
||||
};
|
||||
```
|
||||
|
||||
Remove every reference to `zone.js`:
|
||||
|
||||
- delete any `import 'zone.js'` from `apps/portal-shell/src/main.ts` and `apps/portal-shell/src/test-setup.ts`;
|
||||
- drop `zone.js` from any `polyfills` array in `apps/portal-shell/project.json`;
|
||||
- check the lockfile no longer pulls `zone.js`.
|
||||
|
||||
Verify:
|
||||
|
||||
```bash
|
||||
grep -RIn "zone.js" apps/portal-shell || echo "no zone.js references — OK"
|
||||
```
|
||||
|
||||
### Strict TypeScript (workspace-wide)
|
||||
|
||||
In `tsconfig.base.json`:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"exactOptionalPropertyTypes": true,
|
||||
"noImplicitOverride": true,
|
||||
"noPropertyAccessFromIndexSignature": true,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4) Generate the backend app — `portal-bff`
|
||||
|
||||
```bash
|
||||
pnpm nx g @nx/nest:application portal-bff \
|
||||
--directory=apps/portal-bff \
|
||||
--unitTestRunner=jest \
|
||||
--tags="scope:portal-bff,type:app"
|
||||
```
|
||||
|
||||
> **Test runner note.** NestJS ships with Jest. Vitest unification across the monorepo is possible (via `@nx/vite:configuration`) and remains a future option — no ADR yet.
|
||||
|
||||
### Wire the global `ValidationPipe` (ADR-0005)
|
||||
|
||||
Edit `apps/portal-bff/src/main.ts`:
|
||||
|
||||
```typescript
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import { ValidationPipe } from '@nestjs/common';
|
||||
import { AppModule } from './app/app.module';
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create(AppModule);
|
||||
|
||||
app.useGlobalPipes(
|
||||
new ValidationPipe({
|
||||
whitelist: true,
|
||||
forbidNonWhitelisted: true,
|
||||
transform: true,
|
||||
}),
|
||||
);
|
||||
|
||||
// Phase-2 security ADRs will add: helmet, CORS allowlist, cookie-session,
|
||||
// CSRF protection, rate limiting, auth guards, structured error filter.
|
||||
|
||||
await app.listen(process.env.PORT ?? 3000);
|
||||
}
|
||||
bootstrap();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5) Add PostgreSQL + Prisma (ADR-0006)
|
||||
|
||||
```bash
|
||||
pnpm add -D prisma
|
||||
pnpm add @prisma/client nestjs-prisma
|
||||
|
||||
mkdir -p apps/portal-bff/prisma
|
||||
pnpm exec prisma init \
|
||||
--datasource-provider postgresql \
|
||||
--schema apps/portal-bff/prisma/schema.prisma
|
||||
```
|
||||
|
||||
Wire `PrismaModule` in `apps/portal-bff/src/app/app.module.ts`:
|
||||
|
||||
```typescript
|
||||
import { Module } from '@nestjs/common';
|
||||
import { PrismaModule } from 'nestjs-prisma';
|
||||
|
||||
@Module({
|
||||
imports: [PrismaModule.forRoot({ isGlobal: true })],
|
||||
})
|
||||
export class AppModule {}
|
||||
```
|
||||
|
||||
Commit a `.env.example` (the actual `.env` is git-ignored):
|
||||
|
||||
```dotenv
|
||||
DATABASE_URL="postgresql://portal:portal@localhost:5432/portal_dev?schema=public"
|
||||
```
|
||||
|
||||
> **Out of scope.** PostgreSQL provisioning (HA, backups, RLS policies for the dual-audience model) and Prisma migration deployment will be handled by infrastructure ADRs (phase 3).
|
||||
|
||||
---
|
||||
|
||||
## 6) Generate the first libraries
|
||||
|
||||
Convention ([ADR-0003](../decisions/0003-workspace-and-app-naming-convention.md)):
|
||||
|
||||
- `libs/feature/<name>` for vertical features;
|
||||
- `libs/shared/<scope>` for cross-cutting concerns.
|
||||
|
||||
Examples:
|
||||
|
||||
```bash
|
||||
# Frontend feature lib
|
||||
pnpm nx g @nx/angular:library feature-auth \
|
||||
--directory=libs/feature/auth \
|
||||
--standalone=true \
|
||||
--tags="scope:portal-shell,type:feature"
|
||||
|
||||
# Shared UI lib (frontend-only)
|
||||
pnpm nx g @nx/angular:library shared-ui \
|
||||
--directory=libs/shared/ui \
|
||||
--standalone=true \
|
||||
--tags="scope:portal-shell,type:shared"
|
||||
|
||||
# Shared utility lib (consumed by both apps)
|
||||
pnpm nx g @nx/js:library shared-util \
|
||||
--directory=libs/shared/util \
|
||||
--tags="scope:shared,type:shared"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7) Enforce module boundaries
|
||||
|
||||
In `eslint.config.mjs`, configure `@nx/enforce-module-boundaries` with the project tags above:
|
||||
|
||||
```js
|
||||
{
|
||||
'@nx/enforce-module-boundaries': [
|
||||
'error',
|
||||
{
|
||||
depConstraints: [
|
||||
{ sourceTag: 'scope:portal-shell', onlyDependOnLibsWithTags: ['scope:portal-shell', 'scope:shared'] },
|
||||
{ sourceTag: 'scope:portal-bff', onlyDependOnLibsWithTags: ['scope:portal-bff', 'scope:shared'] },
|
||||
{ sourceTag: 'type:app', onlyDependOnLibsWithTags: ['type:feature', 'type:shared'] },
|
||||
{ sourceTag: 'type:feature', onlyDependOnLibsWithTags: ['type:feature', 'type:shared'] },
|
||||
{ sourceTag: 'type:shared', onlyDependOnLibsWithTags: ['type:shared'] },
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
This prevents `portal-shell` from importing `portal-bff` code (and vice versa), and keeps `shared-*` libraries free of feature-level dependencies.
|
||||
|
||||
---
|
||||
|
||||
## 8) Prettier, git hooks, and Conventional Commits
|
||||
|
||||
See [ADR-0007](../decisions/0007-pre-commit-hooks-and-conventional-commits.md) for the rationale (Husky + lint-staged + commitlint with Conventional Commits).
|
||||
|
||||
`.prettierrc` (project-wide):
|
||||
|
||||
```json
|
||||
{
|
||||
"singleQuote": true,
|
||||
"semi": true,
|
||||
"printWidth": 100
|
||||
}
|
||||
```
|
||||
|
||||
Install Husky, lint-staged, commitlint:
|
||||
|
||||
```bash
|
||||
pnpm add -D husky lint-staged @commitlint/cli @commitlint/config-conventional
|
||||
pnpm exec husky init
|
||||
```
|
||||
|
||||
`.husky/pre-commit`:
|
||||
|
||||
```bash
|
||||
pnpm exec lint-staged
|
||||
```
|
||||
|
||||
`.husky/commit-msg`:
|
||||
|
||||
```bash
|
||||
pnpm exec commitlint --edit "$1"
|
||||
```
|
||||
|
||||
`commitlint.config.cjs` (workspace root):
|
||||
|
||||
```js
|
||||
module.exports = { extends: ['@commitlint/config-conventional'] };
|
||||
```
|
||||
|
||||
`package.json` excerpt:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": { "prepare": "husky" },
|
||||
"lint-staged": {
|
||||
"*.{ts,html,scss,md,json}": ["pnpm nx format:write --uncommitted"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9) CI/CD
|
||||
|
||||
The pipeline targets the Gitea repository (`gitea@git.unespace.com:julien/apf_portal.git`). Pipeline shape (Gitea Actions vs. third-party runner) and branch protection are deferred to phase-3 ADRs (planned: ADR-0017). Locally, the equivalent of the future CI check is:
|
||||
|
||||
```bash
|
||||
pnpm nx affected -t lint test build
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10) Daily workflow
|
||||
|
||||
```bash
|
||||
# Dev servers
|
||||
pnpm nx serve portal-shell # http://localhost:4200
|
||||
pnpm nx serve portal-bff # http://localhost:3000
|
||||
|
||||
# Tests
|
||||
pnpm nx test portal-shell # Vitest
|
||||
pnpm nx test portal-bff # Jest
|
||||
|
||||
# Quality sweeps
|
||||
pnpm nx run-many -t lint test # full
|
||||
pnpm nx affected -t lint test build # only what changed since main
|
||||
|
||||
# Generators
|
||||
pnpm nx g @nx/angular:component <name> --project=portal-shell --standalone
|
||||
pnpm nx g @nx/nest:resource <name> --project=portal-bff
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## What this guide does _not_ cover (yet)
|
||||
|
||||
| Concern | Phase |
|
||||
| ------------------------------------------------------------------------------------------ | ----- |
|
||||
| Authentication (Entra ID workforce + External ID) | 2 |
|
||||
| Sessions / cache (Redis self-hosted) | 2 |
|
||||
| Downstream API access (existing apps) | 2 |
|
||||
| Observability (Pino + OpenTelemetry + W3C) | 2 |
|
||||
| Audit trail | 2 |
|
||||
| Accessibility baseline (WCAG 2.2 AA + axe-core in CI) | 3 |
|
||||
| Performance budgets (Lighthouse CI) | 3 |
|
||||
| Security baseline (CSP, dep / secret scanning, OWASP ASVS) | 3 |
|
||||
| CI/CD on Gitea | 3 |
|
||||
| On-prem infrastructure stack (orchestration, Postgres HA, Redis HA, observability backend) | 3 |
|
||||
Reference in New Issue
Block a user