docs: add development.md as the day-to-day reference for working on apf_portal
CI / check (push) Failing after 2s
CI / commits (push) Has been skipped
CI / perf (push) Failing after 12s
CI / a11y (push) Failing after 2s
CI / scan (push) Failing after 1m44s

A new contributor (or returning lead) opening the repo gets:
- the final repo layout, with one-line annotations per top-level dir
- the prerequisite tooling list (Node 24 LTS, pnpm 10, mkcert,
  optional local Trivy/gitleaks, Docker for Postgres)
- the fresh-clone setup steps (clone, pnpm install, prisma generate,
  sanity check)
- the daily commands organised by intent: serve, test (incl. single
  file), lint, build, generate (apps / libs / components), Prisma,
  the four ci:* scripts that mirror the CI gates
- the conventional commit cycle end-to-end (branch naming, hook
  enforcement, PR gates, squash-merge, release tagging)
- a 'where to look' table cross-linking the project rules
  (CLAUDE.md), the ADRs, the setup guides, and the personal notes
- an explicit 'to be added' section listing what the doc will grow
  into (local infra Docker Compose, auth dev-loop, component
  patterns, debugging tips, release workflow, Renovate policy)

The doc is intentionally non-exhaustive at v1 - it captures what a
contributor needs today and is structured to grow as the workflow
sharpens. Indexed in docs/README.md under a new 'Daily development'
section, separate from the one-off onboarding guides under
docs/setup/.
This commit is contained in:
Julien Gautier
2026-04-30 19:58:37 +02:00
parent be7187d5f2
commit b69d3a2206
2 changed files with 279 additions and 0 deletions
+4
View File
@@ -11,6 +11,10 @@ This is the entry point to all project documentation. It is maintained automatic
## Sections ## Sections
### Daily development
- [development.md](development.md) — repo layout, prerequisites, initial setup, daily commands, conventional commit cycle. Day-to-day reference for working on the project.
### Onboarding & environment ### Onboarding & environment
Setup guides for new contributors: Setup guides for new contributors:
+275
View File
@@ -0,0 +1,275 @@
# Development guide
This document is the day-to-day reference for working on `apf_portal`. It covers the repo layout, the prerequisites, the initial setup from a fresh clone, and the commands you'll run during a typical development cycle. It is meant to grow — add sections as the team's workflow does.
For decision rationale, see the [ADRs](decisions/). For onboarding the local environment (terminal, Node, pnpm), see [setup/](setup/).
---
## 1. Repo layout
```
apf_portal/
├── .gitea/workflows/ # CI pipelines (ADR-0015)
│ ├── ci.yml # per-PR + push to main: check / scan / commits / perf / a11y
│ └── security-scheduled.yml # weekly full-tree scan + prod Lighthouse
├── .github/ # Nx AI-tooling skills, prompts, agents (Nx-managed)
├── .husky/ # local git hooks (ADR-0007)
│ ├── pre-commit # → pnpm exec lint-staged
│ └── commit-msg # → pnpm exec commitlint
├── apps/
│ ├── portal-shell/ # Angular 21 SPA (zoneless, standalone, Signals, Vitest, SCSS)
│ │ ├── public/ # static assets
│ │ ├── src/ # entry, app config, routes, styles
│ │ ├── postcss.config.js # Tailwind PostCSS plugin
│ │ └── project.json # Nx project config (build, serve, test, lint targets)
│ ├── portal-shell-e2e/ # Playwright e2e for portal-shell
│ ├── portal-bff/ # NestJS 11 BFF (Express adapter, ValidationPipe, Jest)
│ │ ├── src/ # main, app module, controllers, services
│ │ ├── prisma/schema.prisma # Prisma 7 schema (postgresql)
│ │ ├── prisma.config.ts # Prisma 7 TS config (loads DATABASE_URL from .env)
│ │ ├── .env.example # env-vars catalog (committed); .env stays gitignored
│ │ └── project.json
│ └── portal-bff-e2e/ # Jest e2e for portal-bff
├── libs/
│ ├── feature/<name>/ # vertical feature libs (e.g. feature-auth)
│ └── shared/<scope>/ # cross-cutting libs (tokens, ui, util)
├── docs/
│ ├── README.md # doc index
│ ├── decisions/ # ADRs (MADR 4.0.0)
│ ├── setup/ # local-environment onboarding (Zsh, pnpm, Nx workspace)
│ └── development.md # this file
├── notes/ # personal scratchpad (gitignored)
├── CLAUDE.md # project rules + architecture summary
├── commitlint.config.cjs # Conventional Commits config
├── eslint.config.mjs # workspace ESLint with module boundaries
├── lighthouserc.js # Lighthouse CI thresholds (ADR-0017)
├── nx.json # Nx workspace config
├── package.json # workspace deps + scripts
├── pnpm-workspace.yaml # apps/* + libs/**
├── tsconfig.base.json # shared TS strict config
└── vitest.workspace.ts # Vitest workspace projects
```
The conventions that govern this layout are recorded in:
- [ADR-0002](decisions/0002-adopt-nx-monorepo-apps-preset.md) — Nx workspace shape
- [ADR-0003](decisions/0003-workspace-and-app-naming-convention.md) — naming convention (`portal-shell`, `portal-bff`, `feature-<name>`, `shared-<scope>`)
- [ADR-0007](decisions/0007-pre-commit-hooks-and-conventional-commits.md) — local hooks
- [ADR-0015](decisions/0015-cicd-gitea-actions.md) — CI/CD shape
---
## 2. Prerequisites
A working dev machine for `apf_portal` needs:
| Tool | Why | How |
| -------------------------------------------------- | ---------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
| **WSL 2 + Debian** (Windows) or Linux/macOS native | All commands assume a POSIX shell | see [setup/01](setup/01-wsl-terminal-setup.md) |
| **Node.js 24** (latest LTS) | Runtime, pinned in `.nvmrc` | `nvm install 24 && nvm use` (see [setup/02](setup/02-dev-web-stack.md)) |
| **pnpm 10+** | Mandatory package manager (no npm/yarn lockfile) | `corepack enable && corepack prepare pnpm@latest --activate` |
| **Git ≥ 2.40** | Husky 9 + signed commits eventually | usually default |
| **mkcert** | Local HTTPS for cookie-prefix `__Host-` (ADR-0009) | `apt install mkcert` then `mkcert -install` |
| **Trivy** _(optional, locally)_ | Dep vuln scan when running `ci:scan` locally; CI uses an action | `apt install trivy` or [trivy install docs](https://trivy.dev/) |
| **gitleaks** _(optional, locally)_ | Same pattern; CI uses an action | `apt install gitleaks` or [gitleaks install docs](https://github.com/gitleaks/gitleaks#installing) |
| **Docker** | For Postgres + Redis containers in dev (until on-prem infra ADR lands) | Docker Desktop on Windows, Docker Engine on Linux |
Work inside the WSL filesystem (`~/Works/...`), never `/mnt/c/...` — the latter has severe I/O penalties that break Nx caching.
---
## 3. Initial setup from a fresh clone
```bash
git clone gitea@git.unespace.com:julien/apf_portal.git
cd apf_portal
# Install deps (also runs `husky` to wire git hooks)
pnpm install
# Generate the Prisma client (until you set up the DB it errors on
# missing DATABASE_URL — that's expected; the generation only reads
# the schema, not the DB).
cd apps/portal-bff && pnpm exec prisma generate && cd ../..
# Sanity check
pnpm nx run-many -t lint test build
```
For the BFF to actually run end-to-end, you'll also need:
```bash
# .env from .env.example, then fill in DATABASE_URL with your local Postgres
cp apps/portal-bff/.env.example apps/portal-bff/.env
# Local Postgres via Docker (one-liner; will be replaced by a Docker Compose file in a later doc)
docker run -d --name apf-postgres -p 5432:5432 \
-e POSTGRES_USER=portal -e POSTGRES_PASSWORD=portal -e POSTGRES_DB=portal_dev \
postgres:17-alpine
```
A proper local-dev infra spec (Postgres HA-like, Redis, OTel collector) will land with the on-prem infrastructure ADR; in the meantime the one-liner above is sufficient to run the BFF.
---
## 4. Daily commands
### Run the apps
```bash
pnpm nx serve portal-shell # http://localhost:4200 (Angular dev server)
pnpm nx serve portal-bff # http://localhost:3000/api (NestJS)
```
Both can run in parallel in two terminals; the SPA proxies API calls to the BFF in dev.
### Test
```bash
pnpm nx test portal-shell # Vitest (single run; --configuration=watch for watch mode)
pnpm nx test portal-bff # Jest
pnpm nx run-many -t test # all projects
pnpm nx affected -t test # only projects affected since main
```
Run a single Vitest file:
```bash
pnpm nx test portal-shell --testFile=src/app/app.spec.ts
```
### Lint, type-check, format
```bash
pnpm nx lint portal-shell # one project
pnpm nx run-many -t lint # all projects
pnpm nx affected -t lint # affected only
pnpm nx affected -t lint --fix # auto-fix where possible
pnpm nx affected -t type-check # explicit type-check (independent of test/build)
pnpm nx format:write # apply Prettier
pnpm nx format:check # CI-style verification
```
### Build
```bash
pnpm nx build portal-shell # development build
pnpm nx build portal-shell --configuration=production # production build
pnpm nx run-many -t build
pnpm nx affected -t build
```
### Generate
```bash
# Component in portal-shell
pnpm nx g @nx/angular:component <name> --project=portal-shell --standalone
# Service / controller / module in portal-bff
pnpm nx g @nx/nest:service <name> --project=portal-bff
pnpm nx g @nx/nest:controller <name> --project=portal-bff
# New shared lib (TS-only, consumable by both apps)
pnpm nx g @nx/js:library --name=shared-<scope> --directory=libs/shared/<scope> \
--bundler=tsc --unitTestRunner=vitest \
--tags="scope:shared,type:shared" --no-interactive
# New Angular feature lib (front-only)
pnpm nx g @nx/angular:library --name=feature-<name> --directory=libs/feature/<name> \
--standalone=true --unitTestRunner=vitest-analog \
--tags="scope:portal-shell,type:feature" --no-interactive
```
> Sweep generated files for `process.env.X` (dot notation) → `process.env['X']` (bracket notation), required by the strict-TS option `noPropertyAccessFromIndexSignature: true`. The Nx generators don't emit bracket form.
### Prisma
```bash
# Regenerate the typed client after schema changes
cd apps/portal-bff && pnpm exec prisma generate && cd ../..
# Create and apply a migration in dev
cd apps/portal-bff && pnpm exec prisma migrate dev --name <migration-name> && cd ../..
# Deploy migrations in prod (run by deploy pipeline, not locally)
cd apps/portal-bff && pnpm exec prisma migrate deploy && cd ../..
# Inspect the dev DB
cd apps/portal-bff && pnpm exec prisma studio && cd ../..
```
### CI scripts (runnable locally)
Mirror what the CI does on every PR:
```bash
pnpm ci:check # nx affected -t format:check lint test build
pnpm ci:audit # pnpm audit --audit-level=moderate
pnpm ci:commits # commitlint on the PR commit range (uses $COMMIT_LINT_FROM, defaults to origin/main)
pnpm ci:perf # production build + Lighthouse CI against the static-served bundle
```
`ci:scan` (Trivy + gitleaks) is currently invoked from CI YAML rather than as a `pnpm` script — those tools are Go binaries without clean npm wrappers. Run them locally if you've installed the binaries.
---
## 5. Conventional commit cycle
1. Branch from `main` with a short slug:
```bash
git switch -c feat/portal-shell/auth-login # or fix/..., chore/..., docs/...
```
2. Commit using **Conventional Commits**. The local `commit-msg` hook (commitlint) rejects anything else.
```
feat(portal-shell): add login flow stub
fix(portal-bff): correct env var bracket access
chore: bump @nx/* to 22.7.2
docs(decisions): add ADR-0018 for security baseline
```
`pre-commit` runs `lint-staged` → Prettier on staged files. Lint and tests stay in CI.
3. Push and open a PR against `main`. The CI runs:
- `check` (lint, type-check, test, build on affected)
- `scan` (audit, Trivy, gitleaks)
- `commits` (commitlint on the PR commit range)
- `perf` (Lighthouse on the production bundle)
- `a11y` (axe-core; placeholder until first real screens)
All five must be green to merge. PR title must itself be a Conventional Commits message — it becomes the squash-merge subject ([ADR-0015](decisions/0015-cicd-gitea-actions.md)).
4. Squash-merge into `main`. Branch is auto-deleted. Linear history maintained.
5. To cut a release: tag `vX.Y.Z` on `main`. The `release.yml` workflow will pick it up (currently a stub; populated alongside the on-prem deploy ADR).
---
## 6. Where to look
| Question | Doc |
| ------------------------------------------- | ---------------------------------------------------------------------------- |
| Project rules and the why behind them | [CLAUDE.md](../CLAUDE.md) |
| All ADRs (decisions index) | [docs/decisions/README.md](decisions/README.md) |
| Initial environment setup (Zsh, Node, pnpm) | [docs/setup/](setup/) |
| RSSI briefing for ASVS / HDS / etc. | `notes/asvs-level-decision-briefing-rssi.md` (gitignored, personal) |
| The dev-team rationale for the UI stack | `notes/argumentaire-stack-ui-spartan-cdk-tailwind.md` (gitignored, personal) |
---
## 7. To be added
This doc is intentionally not exhaustive on day one. Sections that will land as the project grows:
- **Local infra recipe** — Docker Compose for Postgres + Redis + (later) OTel Collector.
- **Auth dev-loop** — once the Microsoft 365 Developer tenant is provisioned, the workflow for testing OIDC locally.
- **Component patterns** — the in-house spartan-style components (CDK + Tailwind) as they ship, with a11y notes per component.
- **Debugging tips** — Angular DevTools, NestJS inspector, Prisma query log, OTel trace inspection.
- **Release workflow** — once the on-prem deploy ADR lands.
- **Renovate / dep update policy** — when Renovate is configured.