docs(ws3): record session 1c completion (boundaries enforcement)

- ARCH-CONSOLIDATION-2026-04.md: add Sessie 1c entry under WS-3 voortgang
- CLAUDE.md: add Frontend import boundaries section
- BACKLOG.md: add four follow-up tickets
  - TECH-AXIOS-STORE-COUPLING
  - TECH-DELETE-DEAD-VIEWS
  - TECH-WS3-BOUNDARIES-SUBZONES
  - TECH-WS3-BOUNDARIES-ROUTER-ZONE

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-04-30 23:52:15 +02:00
parent fe3a2e1a52
commit 9cccbe08ce
3 changed files with 175 additions and 0 deletions

View File

@@ -268,6 +268,24 @@ you are using available components rather than building custom ones.
- Never: TypeScript `any` type (use proper types, generics, or `unknown` with type guards)
- Never: import axios directly in a component (use `src/lib/axios.ts` via a composable)
## Frontend import boundaries (apps/app/)
`apps/app/` enforces a layered import architecture via
`eslint-plugin-boundaries`. Ten zones (`types` → `utils` → `lib` →
`plugins` / `composables` / `stores` / `navigation` → `components` →
`layouts` → `pages`); each zone may only import from the zones below
it in the matrix. Vendored `@core/` and `@layouts/` are exempt.
Cross-zone violations are lint errors, not warnings.
Matrix details + rationale: `dev-docs/WS-3-SESSION-1C-AUDIT.md`.
Config: `apps/app/.eslintrc.cjs`.
When adding a new file: pick the zone first. If your file imports
from a zone the matrix forbids, the structural answer is usually to
hoist a type to `types/` or extract a helper to `utils/` /
`composables/` — not to disable the rule. Per-line disables are
allowed only with a `TODO TECH-*` reference to a backlog item.
## Order of work for each new module
1. Create and run migration(s)

View File

@@ -551,6 +551,30 @@ Zie §4 voor scope en stappen.
drie geplande wijzigingen, doorschuiven naar follow-up. WS-3 lint
cleanup workstream effectief afgerond; sessie 1c
(eslint-plugin-boundaries) kan starten op een schone baseline.
- **Sessie 1c (2026-04-30)** — _import-boundaries enforcement, klaar._
`eslint-plugin-boundaries@6.0.2` (MIT, ESLint ≥6 peer-dep, Node ≥18.18)
toegevoegd als directe devDep aan `apps/app/package.json` per de
TECH-PORTAL-ESLINT-DEPS lesson, en geactiveerd in `apps/app/.eslintrc.cjs`
met layered-architecture matrix: 10 zones (`types`, `utils`, `lib`,
`plugins`, `composables`, `stores`, `navigation`, `components`, `layouts`,
`pages`) met richtgevende edges (rationale + bewijs in
`dev-docs/WS-3-SESSION-1C-AUDIT.md`). Vendored `@core/`, `@layouts/`,
het dode `views/` bestand en orchestratie-roots `App.vue` + `main.ts`
staan in `boundaries/ignore`. Vier `lib → stores` violations in
`lib/axios.ts` (regels 3, 4, 61, 72) gemarkeerd met per-line
`eslint-disable-next-line` comments referencerend naar
`TECH-AXIOS-STORE-COUPLING` — de structurele decoupling van axios is
bewust uitgesteld naar een dedicated sessie omdat het architectuurwerk
is, geen tooling-cleanup. Boundary-rule blijft `error`, matrix blijft
strict; toekomstige `lib/X.ts` schrijvers stoten alsnog tegen de regel.
Lint baseline 0 errors / 0 warnings; build smoke groen; Vitest groen
(49 tests). Drie backlog-items aangemaakt voor toekomstige actie:
`TECH-AXIOS-STORE-COUPLING` (decouple axios), `TECH-DELETE-DEAD-VIEWS`
(verwijder `src/views/`), `TECH-WS3-BOUNDARIES-SUBZONES` (sub-zone
enforcement na PR-B), `TECH-WS3-BOUNDARIES-ROUTER-ZONE` (matrix-update
wanneer `plugins/1.router/` naar `router/` verhuist). WS-3 lint cleanup
+ boundaries enforcement effectief afgerond; volgende WS-3 stap is PR-B
(portal merge) zodra WS-6 sessie 2 in main is geland.
**Klaar-criteria:**
- `apps/portal/` is verwijderd

View File

@@ -622,6 +622,139 @@ TECH-ESLINT-V9-MIGRATION zijn natuurlijke kandidaten).
---
### TECH-AXIOS-STORE-COUPLING — Decouple lib/axios.ts from stores layer
**Aanleiding:** WS-3 sessie 1c (eslint-plugin-boundaries enforcement)
constateerde dat `apps/app/src/lib/axios.ts` 4 imports heeft uit `stores/`
(2 statisch op regel 3-4 voor `useNotificationStore` /
`useOrganisationStore`, 2 dynamisch op regel 61, 72 voor
`useImpersonationStore` / `useAuthStore` uit 1b-iii). De `lib → stores`
edge schendt de layered-architecture matrix. Om sessie 1c on-time te
landen zijn de 4 sites gemarkeerd met `eslint-disable-next-line` +
verwijzing naar dit backlog-item; de structurele fix is bewust uitgesteld
naar een dedicated sessie omdat het architectuurwerk is, geen tooling-
cleanup.
**Wat:**
- Decouple `lib/axios.ts` van stores zodat het puur HTTP-infrastructuur
wordt. Twee paden, kies bij refactor:
- **Approach 1 (preferred starting point):** `lib/axios.ts` exporteert
de axios-instance plus een `registerInterceptors(client, deps)`
functie die callbacks accepteert (`onAuthFail`,
`onImpersonationDrop`, `getActiveOrgId`, `notify(message, level)`).
Een nieuwe `plugins/axios-bindings.ts` (mag `stores` importeren per
matrix) roept `registerInterceptors` aan bij app-init met closures
over de stores.
- **Approach 2 (fallback):** event-bus / callback registry; axios.ts
emit-eert semantische events (`auth-failed`, `needs-org-header`,
`notify-error`) en `plugins/axios-bindings.ts` subscribet.
- Verwijder alle 4 `eslint-disable-next-line` comments uit
`lib/axios.ts`.
- Tests moeten dekken: X-Organisation-Id header injection, 401/403
logout flow, impersonation revocation flow, error toast op 4xx/5xx.
- Optioneel: meteen ook de static/dynamic import-split in axios.ts
uniformeren (nu inconsistent om legacy 1b-iii-redenen).
**Prioriteit:** Middel — geen blokker voor andere workstreams, maar elke
maand dat dit blijft staan is een vlek op de boundaries-enforcement
geloofwaardigheid. Aanbevolen: meelift met de eerste WS-3 PR die `lib/`
of `plugins/` raakt, of een dedicated 2-3 uur sessie na WS-6 sluiting.
---
### TECH-DELETE-DEAD-VIEWS — Verwijder src/views/ uit apps/app/
**Aanleiding:** WS-3 sessie 1c audit (`dev-docs/WS-3-SESSION-1C-AUDIT.md`
§A.1) constateerde dat `apps/app/src/views/` precies één bestand bevat
(`views/pages/authentication/AuthProvider.vue`) met nul importers in de
hele repo. Het is overgebleven Vuexy-template dode code. De §4.2
post-consolidatie target layout drop `views/` volledig. Het bestand is
nu in `boundaries/ignore` opgenomen om sessie 1c te laten landen, maar
de natuurlijke vervolgstap is fysieke verwijdering.
**Wat:**
- Verwijder `apps/app/src/views/` recursief.
- Verwijder de bijbehorende `'src/views/**'` regel uit
`apps/app/.eslintrc.cjs` `boundaries/ignore`.
- Verifieer dat `pnpm lint`, `pnpm build` en `pnpm test` groen blijven.
- Eén commit: `chore(cleanup): delete dead Vuexy views/ directory`.
**Prioriteit:** Laag — triviaal cleanup-item, kan in elke gerelateerde
housekeeping-sprint meeliften (bijvoorbeeld vóór of na WS-3 PR-B).
---
### TECH-WS3-BOUNDARIES-SUBZONES — Sub-zone import-boundaries inside components/ and pages/
**Aanleiding:** WS-3 sessie 1c heeft top-level zone-boundaries in
`apps/app/` neergezet via `eslint-plugin-boundaries`. De `/dev-docs/ARCH-CONSOLIDATION-2026-04.md`
§4.2 target layout introduceert sub-zones binnen die top-level zones —
specifiek `components/{organizer,portal,shared}/` en
`pages/{(auth),portal,register,events,persons,organisations,platform}/`.
De architecturale intent is dat `components/portal` niet uit
`components/organizer` mag importeren (en vice versa), met `shared` als
de gemeenschappelijke uitgang. Sessie 1c heeft die sub-zone
enforcement bewust uitgesteld omdat de sub-folders nog niet bestaan;
pre-emptieve rules op niet-bestaande directories worden stille dode
config die drift.
**Wat:**
- **Precondition:** WS-3 PR-B is gemerged en de §4.2 sub-folder
structuur is gelandt (`components/{organizer,portal,shared}/` en
`pages/{(auth),portal,...}/` bestaan fysiek met content).
- Breid `boundaries/elements` in `apps/app/.eslintrc.cjs` uit met:
- `{ type: 'components-organizer', pattern: 'src/components/organizer/**' }`
- `{ type: 'components-portal', pattern: 'src/components/portal/**' }`
- `{ type: 'components-shared', pattern: 'src/components/shared/**' }`
- (ontworpen sub-zones voor `pages/` analoog)
- Voeg per-sub-zone rules toe: `components-portal` en
`components-organizer` mogen beide uit `components-shared` importeren,
maar niet uit elkaar. `pages/portal/` mag niet uit `pages/events/`
(en de andere organizer-pages) importeren, en omgekeerd.
- Resolve violations die bij eerste activatie naar boven komen.
- ETA: 1-2 uur zodra precondities ervoor liggen.
**Prioriteit:** Middel — preventieve architectuur-discipline voor de
multi-tenant context-isolatie tussen organizer en portal UI-paden.
Zonder deze rules is de kans groot dat een ontwikkelaar tijdens een
PR-B follow-up onbewust portal- en organizer-componenten verstrengelt.
---
### TECH-WS3-BOUNDARIES-ROUTER-ZONE — Add `router/` zone to boundaries matrix
**Aanleiding:** WS-3 sessie 1c audit (§3 forward-compatibility) flagde
dat de §4.2 target layout `src/plugins/1.router/` vervangt door een
flat `src/router/`. De huidige boundaries-matrix in
`apps/app/.eslintrc.cjs` mapt router-files naar de `plugins` zone
(omdat ze fysiek in `src/plugins/1.router/` zitten). Zodra de
verhuizing plaatsvindt — geplant in een latere WS-3 PR — moet de
matrix-config dat reflecteren, anders vallen router-files buiten de
`boundaries/elements` mapping en flag-stormt de plugin met "no rule
found".
**Wat:** In dezelfde commit/PR die `src/plugins/1.router/` naar
`src/router/` verhuist:
- Voeg toe aan `boundaries/elements` in `apps/app/.eslintrc.cjs`:
```js
{ type: 'router', pattern: 'src/router/**' },
```
Plaats vóór `plugins` in de array (first-match-wins ordering).
- Voeg toe aan `boundaries/element-types` rules:
```js
{ from: 'router', allow: ['types', 'utils', 'lib', 'plugins', 'stores'] },
```
- Verifieer `pnpm lint` blijft op 0 problemen.
**Trigger:** "src/plugins/1.router/" → "src/router/" verhuizing (latere
WS-3 PR, vermoedelijk PR-B als die de router-tree consolideert).
**Prioriteit:** Laag — geen actie tot de verhuizing plaatsvindt; dan
verplicht 5-minute follow-up.
---
### TECH-08 — Paginated response meta wordt weggegooid in organizer composables
**Aanleiding:** `apps/app/src/composables/api/useSections.ts` en