From 83821b1bd56a79abb3d4cf3c07c88a94db4ad71a Mon Sep 17 00:00:00 2001 From: "bert.hausmans" Date: Fri, 24 Apr 2026 11:51:28 +0200 Subject: [PATCH] docs(architecture): land consolidation sprint briefing document Adds ARCH-CONSOLIDATION-2026-04.md as the authoritative reference for the upcoming 8-workstream architecture consolidation sprint: purpose registry cleanup, ULID consistency, JSON column split, binding infrastructure, FormBindingApplicator, single-SPA consolidation to crewli.app, observability foundation, docs consolidation. Sprint scope, leading principles, workstream ordering, and chat-transition protocol are captured in the document. Follow-up chats will start from this document as primary context. Also updates BACKLOG.md with an active-sprint marker pointing to the briefing. --- dev-docs/ARCH-CONSOLIDATION-2026-04.md | 590 +++++++++++++++++++++++++ dev-docs/BACKLOG.md | 8 + 2 files changed, 598 insertions(+) create mode 100644 dev-docs/ARCH-CONSOLIDATION-2026-04.md diff --git a/dev-docs/ARCH-CONSOLIDATION-2026-04.md b/dev-docs/ARCH-CONSOLIDATION-2026-04.md new file mode 100644 index 00000000..ebca7859 --- /dev/null +++ b/dev-docs/ARCH-CONSOLIDATION-2026-04.md @@ -0,0 +1,590 @@ +# Crewli — Architectuur Consolidatie Sprint (april 2026) + +> **Status:** briefing document, vertrekpunt van de consolidatie-sprint. +> **Doelgroep:** Bert (product owner + solo dev), Claude (architect/PM rol in chat), Claude Code (executie). +> **Positie t.o.v. andere docs:** dit document is tijdelijk. Na afronding van de sprint wordt +> de inhoud gedistribueerd over `/CLAUDE.md`, `/dev-docs/SCHEMA.md`, `/dev-docs/ARCH-*.md` en +> `/dev-docs/dev-guide.md`. Tijdens de sprint is het de enkele bron van waarheid voor wát +> we aan het doen zijn en waaróm. + +--- + +## 0. Context in één alinea + +Crewli is een multi-tenant SaaS-platform voor festival- en event-personeelsbeheer +(vrijwilligers, crew, artiesten, leveranciers, pers, gasten). Pre-launch. Geen +gebruikers, geen live data, geen tijdsdruk. Ambitie: een enterprise-grade product +dat binnen Stichting Echt Feesten gebruikt wordt en daarna bredere markt op +kan. Het fundament is vandaag op ~80% — functioneel grotendeels aanwezig, +architecturaal op sommige plekken een compromis dat onder productie-druk had +moeten standhouden. Dit document legt vast hoe we die laatste 20% invullen +voordat we aan de 4 kern-workflows (EVENT_REGISTRATION, ARTIST_ADVANCE, +SUPPLIER_INTAKE en één generiek type) beginnen. + +--- + +## 1. Leidende principes voor de sprint + +Deze principes zijn toetssteen voor elke beslissing tijdens de consolidatie. +Bij twijfel tijdens executie: teruglezen, toetsen, beslissen. + +**P1 — Enterprise betekent discipline in scope, niet afwezigheid van scope.** +We bouwen een fundament dat 23 denkbare purposes aan kan, maar we implementeren +er nu 4. De rest is vocabulaire, geen functionaliteit. Elke feature die niet +onmisbaar is voor het fundament of voor de 4 kern-workflows wordt op de backlog +gezet met duidelijke trigger-conditie ("als X, dan bouwen we Y"). + +**P2 — Queryable data krijgt eigen kolommen of tabellen. JSON is uitsluitend +voor echt opaque config.** Herinterpretatie van het bestaande principe: strenger +toepassen. Validatieregels, conditional logic, field options, bindings — allemaal +eigen tabellen. `settings` JSON krimpt fors. + +**P3 — ULID overal. Zonder uitzonderingen.** Ook pivot-tabellen. Ook logging-tabellen. +Consistent = onderhoudbaar = veilig. + +**P4 — Polymorfe relaties zijn een bewust architectuur-patroon, geen kludge.** +`form_schemas.owner_type/owner_id` en `form_submissions.subject_type/subject_id` +blijven polymorf. Nieuwe polymorfe relaties voegen we toe waar het domein dit +rechtvaardigt (niet speculatief). + +**P5 — Eén SPA, twee hostnames.** Geen twee SPAs. Geen drie. Herconsolidatie +van `apps/portal/` in `apps/app/` met domein-gebaseerde routing. Zie §4. + +**P6 — End-to-end-werkend hoofdpad voor fancy features.** FormBindingApplicator ++ Person-creation + entity-updates zijn eerste-klas fundament, niet een addendum. +Geen enkele fancy feature (conditional logic, webhooks, delegation) mag afgerond +heten zolang de basis-pipeline niet volledig gebouwd en getest is. + +**P7 — Observability is fundament, geen nice-to-have.** Een enterprise-product +zonder gestructureerde logging, error tracking en performance monitoring is geen +enterprise-product. Deze laag wordt in de sprint neergezet. + +**P8 — Documentatie loopt synchroon met code.** Elke sprint-PR wijzigt of +creëert dev-docs. Geen "docs volgen later". Dit is al praktijk bij Crewli en +blijft zo. + +--- + +## 2. De drie valstrikken, en hoe we ze tegenhouden + +De grote risico's van een open-ended consolidatie-sprint zijn bekend. Expliciet +benoemen zodat we ze kunnen herkennen als ze zich voordoen. + +**Valstrik 1 — Scope-creep tijdens refactor.** "We zijn toch bezig in deze code, +laten we ook X meenemen." Weerstand: X komt op `/dev-docs/BACKLOG.md` met +trigger-conditie, wordt niet mee-genomen. Enige uitzondering: X is een directe +blocker voor het huidige consolidatie-werkpakket. + +**Valstrik 2 — Gold-plating.** Iets verder perfectioneren dan nodig. Elke +refactor-actie moet een concrete trigger hebben: "dit veroorzaakt drift in Y" +of "dit blokkeert feature Z" of "dit is een security-risico". "Dit kan +eleganter" is geen geldige trigger. + +**Valstrik 3 — Feature-sprawl verkapt als fundering.** "Als we toch bezig zijn +met bindings, laten we ook een binding-designer-UI bouwen." Nee. Fundering = +datamodel + services + tests. Features komen daarna, in de 4-workflow-build. + +**Bij elke nieuwe ingeving tijdens de sprint stelt Claude de drie vragen:** +1. Is dit een scope-uitbreiding? → backlog +2. Is dit elegantie-verbetering zonder concrete trigger? → niet doen +3. Is dit een feature verkleed als fundering? → naar na de consolidatie + +--- + +## 3. Vastgelegde besluiten (niet ter discussie in deze sprint) + +Deze beslissingen zijn genomen en worden *niet* opnieuw geopend. Voor volgende +chats: behandel deze als gegeven. + +1. **Binding als eerste-klas burger.** Aparte `form_field_bindings` tabel met + typed kolommen: `field_id`, `target_entity`, `target_attribute`, `merge_strategy`, + `trust_level`. Eén veld kan meerdere bindings hebben (multi-binding scenarios). + Details in §6.1. + +2. **FormBindingApplicator als hoofdpad.** Nieuwe service die na + `FormSubmissionSubmitted` bindings doorloopt en entities bijwerkt. Inclusief + automatische Person-creation bij public EVENT_REGISTRATION submissions + zonder subject. Details in §6.2. + +3. **Denormalized columns op `form_submissions`.** `event_id`, `organisation_id` + en `submitted_by_user_id` zijn al aanwezig of worden toegevoegd als directe + foreign keys, niet alleen via schema-joins. Details in §6.3. + +4. **Purpose registry in config, geen `custom` escape.** Afgeslankte set van + 7 purposes voor v1.0: EVENT_REGISTRATION, ARTIST_ADVANCE, SUPPLIER_INTAKE, + POST_EVENT_EVALUATION, INCIDENT_REPORT, SIGNATURE_CONTRACT, USER_PROFILE. + Registry leeft in `config/form_builder/purposes.php` + typed value-objects. + Nieuwe purposes vereisen een migratie + listener — dat is correct, niet + lastig. Details in §6.4. + +5. **ULID consistent overal, ook pivots.** Bestaande integer-PK-pivots worden + gemigreerd. Opsporings-pas in week 1 van de sprint. Details in §6.5. + +6. **Eigen tabellen voor `validation_rules`, `conditional_logic`, + `form_fields.options`.** Typed, queryable. `form_schemas.settings` krimpt + naar echt opaque config (rendering hints). Details in §6.6. + +7. **Eén SPA op één domein.** `apps/portal/` wordt een route-tree binnen + `apps/app/`. Alles op `crewli.app`. Route-guards bepalen welke layout, + welke context, welke permissies. Multi-role users krijgen een context- + switcher in de nav-balk. Details in §4. + +8. **Observability foundation.** Sentry voor error tracking, structured + logging via Laravel's context, performance monitoring via Laravel Telescope + (dev) + Sentry Performance (prod). Details in §6.7. + +9. **Enterprise scope betekent 4 kern-workflows voor v1.0.** Niet 23. De + overige purposes in de registry zijn vocabulaire zonder implementatie; + zij krijgen implementatie wanneer een concrete klant-case dit rechtvaardigt. + +--- + +## 4. Het één-SPA besluit: uitvoerbaar overzicht + +Gekozen architectuur: **één codebase, één build, één domein.** + +### 4.1 Hostnames +- `crewli.app` — alle gebruikers, alle rollen, één SPA +- `api.crewli.app` — Laravel backend (ongewijzigd) +- `docs.crewli.app` — VitePress docs (ongewijzigd) + +Rationale: vrijwilligers en organizers zijn verschillende rollen binnen +hetzelfde product, niet verschillende producten op hetzelfde platform. Dit volgt +het patroon van Slack/Linear/Notion/GitHub, waar alle gebruikers onder één +domein werken en de UI zich aanpast aan rol + context. Subdomeinen per rol (zoals +Shopify/Stripe) worden pas zinvol wanneer er fundamenteel verschillende producten +zijn — niet ons geval. + +### 4.2 Directory-structuur na consolidatie + +``` +apps/ + app/ ← enige Vue SPA + src/ + pages/ + (auth)/ ← login, forgot-password, MFA + portal/ ← wat nu in apps/portal/src/pages/ zit + my-shifts/ + availability/ + profile/ + ... + register/ ← publieke formulier-flow (niet ingelogd) + [public_token].vue + events/ ← organizer: events + sub-pages + persons/ ← organizer: persons overview + organisations/ ← organizer: settings + platform/ ← super-admin (role:super_admin) + index.vue ← post-login landing of context-switcher + components/ + organizer/ ← organizer-only componenten + portal/ ← portal-only componenten + shared/ ← gedeeld tussen beide + composables/ + forms/ ← voormalige packages/form-schema/ komt hier + ... + layouts/ + OrganizerLayout.vue ← voor organizer routes, met organizer-nav + PortalLayout.vue ← voor portal routes, met portal-nav + PublicLayout.vue ← voor /register/* routes, minimaal + router/ + index.ts ← route-guards bepalen layout + toegang + routes.ts ← één route-tree, layout per section + plugins/ + theme.ts ← context-based Vuetify theme injectie + portal/ ← verdwijnt na sprint + api/ ← ongewijzigd +packages/ + form-schema/ ← verdwijnt, inhoud verhuist naar apps/app/src/composables/forms/ +``` + +### 4.3 Routing en context-switching + +Er is geen hostname-detectie. Routes bepalen alles: + +```ts +// Conceptueel — definitieve implementatie in sprint +const routes = [ + // Publiek (geen auth) + { path: '/login', component: LoginPage, meta: { layout: 'PublicLayout' } }, + { path: '/register/:publicToken', component: PublicFormPage, meta: { layout: 'PublicLayout' } }, + { path: '/forgot-password', component: ForgotPasswordPage, meta: { layout: 'PublicLayout' } }, + + // Portal routes (auth required, any role) + { + path: '/portal', + meta: { layout: 'PortalLayout', requiresAuth: true, context: 'portal' }, + children: [ + { path: 'my-shifts', component: MyShiftsPage }, + { path: 'availability', component: AvailabilityPage }, + { path: 'profile', component: ProfilePage }, + ], + }, + + // Organizer routes (auth + organizer role) + { + path: '/', + meta: { layout: 'OrganizerLayout', requiresAuth: true, context: 'organizer', + requiresRole: 'organizer' }, + children: [ + { path: '', component: OrganizerDashboard }, + { path: 'events', component: EventsList }, + // ... etc + ], + }, + + // Platform admin (auth + super_admin role) + { + path: '/platform', + meta: { layout: 'OrganizerLayout', requiresAuth: true, requiresRole: 'super_admin' }, + children: [...] + }, +] +``` + +**Post-login landing voor multi-role gebruikers:** +- Enkel portal-rol → redirect naar `/portal/my-shifts` +- Enkel organizer-rol → redirect naar `/` (dashboard) +- Beide rollen → landing-page op `/` met twee kaarten (Portal / Organizer) óf + direct naar laatst-gebruikte context (lokaal opgeslagen als preference) + +**Context-switcher in nav-balk** voor multi-role users: +- Permanent zichtbaar in OrganizerLayout en PortalLayout +- Eén klik switch naar andere context +- Vergelijkbaar met Slack's workspace-switcher + +### 4.4 Wat blijft werken ongewijzigd + +- Sanctum session auth (één cookie, één domein) — simpeler dan eerst gedacht +- Portal-token-auth voor publieke routes (`/register/{public_token}`, + `/public/forms/...` API-endpoints) — blijft als aparte middleware +- Impersonation — blijft binnen organizer-tree +- API-calls naar `api.crewli.app` — ongewijzigd + +**Wat wegvalt door één-domein-keuze:** cross-domain cookie isolation is niet meer +nodig. De `CookieBearerToken`-middleware per app (uit AUTH_ARCHITECTURE.md) mag +vereenvoudigd worden in de sprint — dit wordt meegenomen onder WS-3. + +### 4.5 Wat dit kost + +Reële inschatting: 2-4 dagen werk in de consolidatie-sprint. +- 1 dag: directory-structuur omzetten, imports repareren +- 1 dag: router + layouts + route-guards + context-switcher +- 1 dag: theming per context, Vuetify-config, auth-cleanup +- 1 dag: testen, deploy-config verifiëren + +Iets simpeler dan bij het hostname-alternatief omdat we geen hostname-detector +hoeven te bouwen en omdat cross-domain cookie complexiteit vervalt. + +### 4.6 Toekomst-deur openhouden + +Als later één van deze drie scenario's optreedt, kunnen we alsnog splitsen +zonder dat we vandaag te vroeg gesplitst hadden: + +- Portal wil SSR voor SEO → portal splitsen naar Nuxt op aparte subdomain +- Een third product (marketplace, kassa-app) verschijnt → apart project op + eigen subdomain +- Whitelabel per organisatie met eigen subdomain → routing-laag erboven + +Geen van deze scenario's is vandaag aan de orde. Splitsen vanuit één SPA is +goed te doen wanneer nodig (één tot twee weken werk). + +--- + +## 5. Prioriteitsvolgorde werkstromen + +De consolidatie-sprint kent **acht werkstromen** (afgekort WS). Ze worden in +deze volgorde uitgevoerd, met waar mogelijk parallelle PRs binnen een werkstroom. + +**WS-1 — Opsporings-pas (1 dag)** +Volledige scan van de codebase op: niet-ULID primary keys, JSON-kolommen met +queryable data die ik nog niet geïdentificeerd heb, polymorfe relaties die +inconsistent zijn. Output: een definitieve lijst van te migreren items. +Gaat voor alle andere werkstromen, omdat latere WS-en hun scope ervan +afhangen. + +**WS-2 — Purpose registry + legacy purpose-cleanup (2-3 dagen)** +Van 23 naar 7 purposes. Registry in config. Typed value-objects. Migratie +die bestaande `form_schemas` opschoont (alle schemas met "weg te halen" +purposes → archief of delete, afhankelijk van of er seed-data hangt). + +**WS-3 — Eén SPA consolidatie (3-5 dagen)** +Zoals in §4. Kan deels parallel aan WS-4 en WS-5 want raakt vooral +frontend. Apart maken van frontend-consolidatie en backend-consolidatie +vermijdt rebase-hel. + +**WS-4 — ULID-consistentie + denormalized submission columns (2-3 dagen)** +Pivot-tabellen naar ULID. `event_id`, `organisation_id` op submissions +(en elders waar de opsporings-pas ze vindt). + +**WS-5 — JSON-kolom-opsplitsing (4-6 dagen)** +Vier sub-werkstromen die in serie moeten (elk heeft data-migratie): +- WS-5a — `form_field_bindings` tabel +- WS-5b — `form_field_validation_rules` tabel +- WS-5c — `form_field_conditional_logic` tabel +- WS-5d — `form_field_options` tabel + +**WS-6 — Binding-pipeline / FormBindingApplicator (4-5 dagen)** +Nieuwe service. Listener. Person-creation-flow. Guardrails in +FormSchemaService. Volledige testdekking voor alle 7 purposes (ook als +ze nog geen functionaliteit hebben — tests verifiëren dat de binding- +infrastructuur ze ondersteunt). + +**WS-7 — Observability foundation (2-3 dagen)** +Sentry SDK (backend + frontend). Structured logging conventies. Telescope +voor dev. Performance monitoring. Runbook voor incident response. + +**WS-8 — Documentatie-consolidatie (2-3 dagen)** +`/CLAUDE.md` bijwerken met nieuwe conventies. `/dev-docs/SCHEMA.md` volledige +rewrite naar v2.0 met nieuwe tabellen. `/dev-docs/ARCH-FORM-BUILDER.md` +bijwerken. Nieuwe `/dev-docs/ARCH-BINDINGS.md`. Nieuwe +`/dev-docs/ARCH-OBSERVABILITY.md`. `/dev-docs/BACKLOG.md` opschonen: +verwijderen wat door de sprint is opgelost, expliciet markeren wat na +de sprint nog wordt opgepakt. + +**Totale inschatting sprint:** 22-32 dagen werk. +**Doorlooptijd bij actieve inzet:** 4-6 weken. +**Aantal PRs:** 25-35, veel zijn klein en focused. + +--- + +## 6. Per werkstroom: scope, uitkomst, klaar-criteria + +### 6.1 WS-5a — form_field_bindings + +**Scope:** Nieuwe tabel `form_field_bindings`. Vrije `binding` JSON-kolom op +`form_fields` wordt vervangen door een queryable relatie. Eén veld kan meerdere +bindings hebben. + +**Tabel-ontwerp (concept, finetunen in sprint):** +``` +form_field_bindings: + id (ulid, primary) + form_field_id (ulid, foreign, cascade) + target_entity (string, 50) -- 'person', 'artist', 'company', 'user' + target_attribute (string, 100) -- 'email', 'first_name', 'stage_name', etc. + merge_strategy (enum) -- 'overwrite', 'append', 'replace', 'first_write_wins' + trust_level (int, default 50) -- 0-100, hoger = dominanter bij conflict + is_identity_key (bool, default false)-- wordt gebruikt voor person-matching? + created_at, updated_at + unique (form_field_id, target_entity, target_attribute) +``` + +**Uitkomst:** +- Bestaande `binding` JSON-data gemigreerd naar rijen in deze tabel +- Builder-UI (later) kan een dropdown tonen gevuld uit binding-registry +- Backend kan queryen "welke velden binden aan `person.email`" +- Conflict-strategie per binding expliciet + +**Klaar-criteria:** +- Migratie loopt vooruit én terug zonder data-verlies +- Feature tests: schema create → binding toevoegen → submission submit → entity updated +- `form_fields.binding` JSON-kolom verdwenen +- ARCH-BINDINGS.md geschreven met complete uitleg + +### 6.2 WS-6 — FormBindingApplicator + +**Scope:** Nieuwe service `App\Services\FormBuilder\FormBindingApplicator`. Nieuwe +listener `App\Listeners\FormBuilder\ApplyBindingsOnFormSubmit`. Person-creation- +helper. Update van `FormSchemaService` met pre-publish-validation. + +**Uitkomst:** +- Bij elke `FormSubmissionSubmitted` worden alle bindings doorlopen +- Voor elke binding: lookup value in submission, haal merge-strategie op, + update target entity +- Bij public EVENT_REGISTRATION zonder subject: creëer Person, zet als + subject op submission, voer dan bindings uit +- Identity-match draait na binding-applicatie op nieuwe Person +- Alle actions gelogged in activity log met bron-submission + +**Klaar-criteria:** +- Test: public registratie → Person aangemaakt met alle binding-attributen +- Test: authenticated update-submission → bestaande Person bijgewerkt +- Test: conflict (twee submissions, zelfde email-binding, verschillende waarde) + → last-write-wins met activity log entry +- Test: tag-picker additief (niet overschrijvend) +- Test: schema met AVAILABILITY_PICKER zonder event-koppeling kan niet publiceren +- Test: EVENT_REGISTRATION schema zonder email-binding kan niet publiceren + +### 6.3 WS-4 — Denormalized submission columns + +**Scope:** Kolommen `event_id` (nullable), `organisation_id` (niet-nullable), +`submitted_by_user_id` (bestaat al) op `form_submissions`. Observer vult ze bij +create. Backfill-script voor bestaande submissies (indien aanwezig in seed-data). + +**Uitkomst:** +- Queries zoals "alle submissions voor event X" worden directe queries, geen joins +- Analytics / reporting kan efficiënt draaien +- Multi-event reuse scenario's (ARTIST_ADVANCE) werken: één schema, submissies + naar meerdere events + +**Klaar-criteria:** +- Feature tests: submission krijgt correcte event_id en organisation_id +- Scope-middleware gebruikt event_id direct (waar relevant) +- SCHEMA.md bijgewerkt + +### 6.4 WS-2 — Purpose registry + +**Scope:** `app/FormBuilder/Purposes/PurposeDefinition.php` (value object). +`config/form_builder/purposes.php` (registry). `PurposeRegistry` service. +`form_schemas.purpose` blijft een string-kolom, maar `custom_purpose_slug` +kolom verdwijnt. + +**Purposes v1.0:** +1. `event_registration` — vrijwilligers/crew aanmelden, subject=Person +2. `artist_advance` — artiesten advance invullen, subject=Artist +3. `supplier_intake` — leveranciers onboarding, subject=Company +4. `post_event_evaluation` — feedback na afloop, subject=Person +5. `incident_report` — incidenten melden, subject=Person +6. `signature_contract` — contracten ondertekenen, subject=User +7. `user_profile` — profiel-updates, subject=User + +**Uitkomst:** +- Purposes zijn data-driven: je kunt in config een nieuwe toevoegen zonder + enum-migratie, maar je moet wel bewust zijn dat een nieuwe purpose meestal + een listener vereist +- Elke PurposeDefinition heeft: label, subject_type, default_submission_mode, + allows_public_access, required_bindings (lijst van bindings die het schema + moet hebben om publiceerbaar te zijn) + +**Klaar-criteria:** +- Tests voor elke purpose: kan schema gecreëerd worden, kan gepubliceerd worden + (met juiste bindings), submit-flow werkt end-to-end +- ARCH-FORM-BUILDER.md bijgewerkt + +### 6.5 WS-4 — ULID-consistentie + +**Scope:** Alle pivot-tabellen met integer PK → ULID. Opsporings-pas (WS-1) +definieert de exacte lijst. Data-migratie per tabel. + +**Uitkomst:** Consistent ID-gebruik. Geen ID-enumeration-risico meer. +Eenvormig test-patroon. + +**Klaar-criteria:** +- Alle primary keys in business-schema zijn ULID +- Alle foreign keys consistent +- Tests lopen door + +### 6.6 WS-5b/c/d — Remaining JSON-splits + +Dezelfde aanpak als WS-5a maar voor: +- `form_field_validation_rules` (targeting `validation_rules` JSON) +- `form_field_conditional_logic` (targeting `conditional_logic` JSON, met + AND/OR tree structuur) +- `form_field_options` (targeting `options` JSON, met position + label + + metadata per optie) + +**Conditional logic verdient speciale aandacht.** AND/OR trees in een relationele +tabel zijn niet triviaal. Overweging in de sprint: platte lijst met +`logical_group_id` vs recursieve tabel met `parent_id`. Beslissing tijdens +WS-5c, niet vooruit. + +### 6.7 WS-7 — Observability + +**Scope:** +- Sentry SDK installeren in `apps/api/` (Laravel) en `apps/app/` (Vue) +- Structured logging convention: alle logs via `Log::channel('structured')` + met context (organisation_id, user_id, request_id) +- Laravel Telescope in dev only +- Sentry Performance voor transaction tracking in prod +- Runbook in `dev-docs/RUNBOOK.md` met: hoe te reageren op alerts, waar + logs te vinden, hoe een error te tracen + +**Klaar-criteria:** +- Test: geforceerde exception in een controller verschijnt in Sentry (staging) +- Test: elke request heeft een unique request_id in logs +- Telescope werkt in dev, niet in prod + +### 6.8 WS-3 — Eén SPA consolidatie + +Zie §4 voor scope en stappen. + +**Klaar-criteria:** +- `apps/portal/` is verwijderd +- Beide hostnames serveren correcte route-tree +- Auth werkt op beide hostnames met isolatie +- Alle bestaande tests in apps/app/ draaien groen +- Nieuwe tests voor hostname-detectie +- Deploy-config (DirectAdmin) verifieert beide hostnames + +--- + +## 7. Starten van de volgende chat + +Deze chat wordt afgesloten. De volgende chat start met een dichte briefing die +**exact dit document** en de volgende meta-instructie als context geeft. + +**Opening-prompt voor de volgende chat (kopieer letterlijk):** + +``` +Nieuwe chat in project Crewli. We beginnen de architectuur-consolidatie-sprint +zoals vastgelegd in /dev-docs/ARCH-CONSOLIDATION-2026-04.md (lees dat document +eerst uit Gitea, main branch). + +Context: +- Pre-launch. Geen gebruikers, geen tijdsdruk. Doel: enterprise-grade fundament. +- 8 werkstromen (WS-1 t/m WS-8). We starten met WS-1: opsporings-pas. +- Ik wil dat je ook /CLAUDE.md en /dev-docs/SCHEMA.md leest voor basiscontext, + en kort aangeeft wat je hebt begrepen. + +Verzoek voor deze eerste chat: +1. Bevestig dat je het consolidatie-document en CLAUDE.md hebt gelezen. +2. Lever de prompt voor WS-1 (opsporings-pas). Deze moet een Claude Code opdracht + zijn die het hele codebase doorloopt op: + - Primary keys die geen ULID zijn + - JSON-kolommen met queryable data die niet in §6 zijn benoemd + - Polymorfe relaties die inconsistent gemodelleerd zijn + - Overige architectuur-smells die we in de consolidatie moeten meenemen +3. Output van WS-1 is een rapport (Markdown), geen code. Op basis daarvan + beslissen we of de scope van andere werkstromen aanpassing behoeft. + +Regels die tijdens de sprint gelden: +- Elke nieuwe ingeving: toets aan de drie valstrikken in §2 van het + consolidatie-document. Bij twijfel: backlog. +- Elke architectuur-keuze tijdens executie: toets aan de principes in §1. +- Geen scope-uitbreiding zonder expliciete go van mij. + +Bevestig dat je klaar bent voor WS-1. +``` + +--- + +## 8. Verwijzingen naar bestaand materiaal + +Voor de volgende chat is het nuttig dat deze documenten als achtergrond +beschikbaar zijn (niet allemaal lezen, maar weten dat ze bestaan): + +- `/CLAUDE.md` — projectafspraken, zero-compromise regels +- `/dev-docs/SCHEMA.md` v2.1 — huidig database-schema +- `/dev-docs/ARCH-FORM-BUILDER.md` — bestaande form-builder architectuur +- `/dev-docs/AUTH_ARCHITECTURE.md` — dual-mode auth, cross-app isolation +- `/dev-docs/VUEXY_COMPONENTS.md` — frontend component-bibliotheek +- `/dev-docs/BACKLOG.md` — bestaande backlog, wordt opgeschoond in WS-8 + +--- + +## 9. Openstaand (niet in scope van consolidatie-sprint) + +Om expliciet te zijn over wat *niet* in deze sprint gebeurt: + +- Implementatie van de 4 kern-workflows (komt erna als aparte sprint S3c...S3f) +- Nieuwe UI-modules (komt erna) +- Marketplace / subscription / billing (toekomst) +- Mobile app (toekomst) +- Locale-uitbreiding voorbij NL/EN (komt wanneer marktbehoefte concreet is) +- Performance-optimalisatie voorbij observability foundation (wanneer metrics + dit rechtvaardigen) + +--- + +## 10. Sign-off ruimte + +Voor Bert om te bevestigen voordat we de volgende chat starten: + +- [ ] Leidende principes §1 akkoord +- [ ] Vastgelegde besluiten §3 akkoord +- [ ] SPA-consolidatie §4 akkoord +- [ ] Werkstroom-volgorde §5 akkoord +- [ ] Purposes v1.0 lijst §6.4 akkoord +- [ ] Openings-prompt §7 klaar om te gebruiken + +Na jouw sign-off commit ik dit document naar de repo en sluiten we deze chat. diff --git a/dev-docs/BACKLOG.md b/dev-docs/BACKLOG.md index 5010f6bf..c2b204f9 100644 --- a/dev-docs/BACKLOG.md +++ b/dev-docs/BACKLOG.md @@ -6,6 +6,14 @@ > **Gebruik:** Voeg nieuwe items toe als ze tijdens development ontstaan. > Geef elk item een prioriteit en fase zodra je het gaat oppakken. +## Architectuur consolidatie sprint (actief) + +Zie `dev-docs/ARCH-CONSOLIDATION-2026-04.md` voor volledige scope, principes en +werkstroomvolgorde. Sprint gestart april 2026, 8 werkstromen, 22-32 dagen werk +totaal. Tijdens de sprint worden bestaande backlog-items die door de sprint +worden opgelost daar expliciet gemarkeerd, en krijgen items die na de sprint +worden opgepakt een `[post-consolidatie]` tag. + --- ## Fase 3 — Geplande features