16 KiB
title, description, status, owner, created, supersedes-sections-of
| title | description | status | owner | created | supersedes-sections-of |
|---|---|---|---|---|---|
| ARCH Consolidation — Architect Decisions Addendum (2026-04-24) | Beslissingen op de 6 architect-vragen uit het WS-1 rapport | binding | architect | 2026-04-24 | /dev-docs/ARCH-CONSOLIDATION-2026-04.md §5 (scope inschattingen) |
ARCH Consolidation — Architect Decisions Addendum (2026-04-24)
Context
Op 2026-04-24 leverde WS-1 (opsporings-pas) een rapport met 45 bevindingen en 6 architect-vragen. Dit addendum legt de beantwoording van die vragen vast én corrigeert waar nodig de werkstroom-scope. Dit document is bindend voor WS-2 t/m WS-8.
Bronnen:
/dev-docs/ARCH-CONSOLIDATION-2026-04.md— sprint charter (§1 principes, §3 vastgelegde besluiten, §5 werkstromen)/dev-docs/ARCH-CONSOLIDATION-WS1-REPORT.md— opsporings-rapport (45 bevindingen)
Het charter blijft ongewijzigd. §5 inschattingen worden in dit addendum herzien. §3 vastgestelde besluiten worden bevestigd (niet gewijzigd) — de architect-precisering op besluit 5 die tijdens review was overwogen is verworpen: besluit 5 blijft exact zoals geformuleerd.
Samenvatting beslissingen
| Q | Onderwerp | Besluit |
|---|---|---|
| Q1 | ULID voor 11 non-ULID tabellen | Alle 11 migreren naar ULID. Charter §3 besluit 5 blijft exact zoals geformuleerd; geen exceptions. |
| Q2 | OrganisationScope strategie | FK-chain scope extension. Denormalisatie alleen op tabellen die rapportage-hot zijn. Charter §3 besluit 3 bevestigd als enige uitzondering op basis van meetbaar rapportage-gebruik. |
| Q3 | WS-5 scope | Vier committed splits op form_fields + drie library-mirror splits. role_restrictions blijft JSON. |
| Q4 | Sanctum personal_access_tokens morph |
Ongewijzigd laten. Framework-polymorfie valt buiten de domain morph-map. Documenteren in WS-8. |
| Q5 | SCHEMA.md rewrite-shape | Aparte /dev-docs/ARCH-PLANNED-MODULES.md voor tabellen zonder migratie. SCHEMA.md wordt strict "waarheid van wat bestaat in de database". |
| Q6 | subject_type allow-list |
Consolideren onder WS-2 purpose registry. Compile-time test dwingt morph-map-alignment met purpose-registry af. |
Q1 — ULID voor 11 non-ULID tabellen
Besluit: Alle 11 tabellen uit Categorie A van het WS-1 rapport worden naar ULID gemigreerd. Charter §3 besluit 5 ("ULID consistent overal, ook pivots, ook logging-tabellen") blijft ongewijzigd. Geen exceptions.
Tabellen:
| ID | Tabel | Categorie |
|---|---|---|
| A-01 | organisation_user |
Pure pivot, geen model |
| A-02 | event_user_roles |
Pure pivot, geen model |
| A-03 | crowd_list_persons |
Pure pivot, geen model |
| A-04 | event_person_activations |
Pure pivot, geen model |
| A-05 | user_organisation_tags |
Pivot met model |
| A-06 | person_section_preferences |
Pivot met model |
| A-07 | mfa_backup_codes |
Ephemeral data |
| A-08 | mfa_email_codes |
Ephemeral data |
| A-09 | form_submission_section_statuses |
Pivot met model |
| A-10 | form_values |
EAV hot path |
| A-11 | form_value_options |
EAV hot path |
Motivatie:
- Pre-launch window: geen data-migratie, geen downtime, geen backfill-pijn. Dit is het enige moment waarop consistentie gratis is. Een half jaar later met productie-data kost hetzelfde werk weekenden met downtime.
- Performance-argumenten zijn theoretisch op Crewli's schaal: EAV join-performance tussen int en ULID keys is verwaarloosbaar bij de volumes waar Crewli zich op richt (enkele miljoenen
form_valuesper festival-jaar, ruim binnen MySQL + goede indexen op ULID). - Consistentie-winst is concreet en blijvend: elke uitzondering introduceert cognitieve belasting ("waarom is deze tabel anders?") die besluit 5 juist wil voorkomen.
- Valstrik 2 (gold-plating) niet van toepassing: dit is geen elegantie-verbetering, dit is uitvoering van een reeds genomen besluit.
Scope-impact: WS-4 migreert 11 PK's in plaats van 0 of 2.
Migratie-notes voor WS-4:
- Voor tabellen met een model (
UserOrganisationTag,PersonSectionPreference,MfaBackupCode,MfaEmailCode,FormSubmissionSectionStatus,FormValue,FormValueOption):HasUlidstrait toevoegen. - Voor pure pivots zonder model (
organisation_user,event_user_roles,crowd_list_persons,event_person_activations):$table->ulid('id')->primary()in de migratie, geen model nodig. - Inline migratie-commentaar "int AI for join performance" wordt vervangen door de ULID-migratie zelf; geen extra rationale-documentatie in de migratie.
Q2 — OrganisationScope strategie
Besluit: OrganisationScope wordt uitgebreid met een declaratieve FK-chain strategy. Denormalisatie van organisation_id blijft beperkt tot tabellen die meetbaar rapportage-hot zijn.
Concreet:
form_submissionsbehoudt denormalizedorganisation_id(per charter §3 besluit 3 — bevestigd als bewuste exception voor rapportage-queries: dashboards, CSV-exports, aggregerende counts over duizenden rijen).- Andere form-builder child tables krijgen geen eigen
organisation_idkolom; zij gebruiken FK-chain via hun parent:form_schema_sections→ viaform_schemas.organisation_idform_fields→ viaform_schemas.organisation_idform_values→ viaform_submissions.organisation_id(denormalized parent)form_value_options→ viaform_submissions.organisation_idform_submission_section_statuses→ viaform_submissions.organisation_idform_submission_delegations→ viaform_submissions.organisation_idform_schema_webhooks→ viaform_schemas.organisation_idform_webhook_deliveries→ viaform_submissions.organisation_id
Shape van de scope-extensie (concept — implementatie-details in WS-4):
class FormField extends Model
{
use HasUlids;
protected static function tenantScopeStrategy(): array
{
return ['via' => FormSchema::class, 'fk' => 'form_schema_id'];
}
}
OrganisationScope leest de strategy en bouwt de JOIN automatisch op.
Motivatie:
- Normalisatie-zuiverheid:
organisation_idheeft één bron van waarheid (form_schemas,events, enz.). Denormalisatie introduceert synchronisatie-risico en dubbele boekhouding. - Single responsibility:
OrganisationScopeblijft de multi-tenant guard. Geen gedeelde verantwoordelijkheid tussen observer + scope over 8 tabellen. - Toekomstbestendig: hetzelfde patroon werkt straks automatisch voor accreditation, briefings en andere modules met sub-tabellen. Eén scope-klasse uitbreiding, geen migraties per module.
- Denormalisatie-uitzondering gerechtvaardigd:
form_submissionsis rapportage-hot. De denormalisatie is een meetbare performance-optimalisatie voor aggregerende queries, geen "veilig-voor-het-geval-dat" patroon.
Rapportage-hotness criterium: een tabel krijgt alleen denormalized organisation_id als er regelmatig aggregerende queries rechtstreeks op draaien (counts, group-by, exports over duizenden rijen). Alle andere tabellen gebruiken FK-chain via hun parent.
Scope-impact: WS-4 krijgt één scope-klasse uitbreiding + scope-registratie op 9 form-builder child models + 5 event-data models (uit WS-1 rapport D-04: ShiftAssignment, ShiftWaitlist, VolunteerAvailability, PersonSectionPreference, PersonIdentityMatch). Geen 8 extra kolom-migraties.
Q3 — WS-5 scope
Besluit: WS-5 splitst de vier committed kolommen op form_fields (per charter §3 besluit 6) én de drie library-mirrors op form_field_library. role_restrictions blijft JSON.
Te splitsen:
| Bron kolom | Doel tabel | Sub-WS |
|---|---|---|
form_fields.binding |
form_field_bindings |
WS-5a |
form_fields.validation_rules |
form_field_validation_rules |
WS-5b |
form_fields.conditional_logic |
form_field_conditional_logic |
WS-5c |
form_fields.options |
form_field_options |
WS-5d |
form_field_library.default_binding |
form_field_bindings (met owner discriminator) |
WS-5a |
form_field_library.validation_rules |
form_field_validation_rules (met owner discriminator) |
WS-5b |
form_field_library.options |
form_field_options (met owner discriminator) |
WS-5d |
Blijft JSON:
form_fields.role_restrictions— kleine set Spatie rol-strings. Geen FK-partner mogelijk (rollen zijn strings in Spatie-permission, geen aparte tabel-PK's). Niet queryable in practice. Relationele splitsing levert geen architectuur-winst.form_fields.translations,form_field_library.translations— flat key-value bags per locale, nooit queried. Splitsen is speculatief.
Motivatie:
- Consistent relationeel form-builder domein: library en fields delen dezelfde onderliggende tabellen voor options, bindings en validation rules. Twee stijlen in hetzelfde domein is inconsistent.
- Library-entries krijgen een discriminator (exacte shape in WS-5a — ofwel
owner_typeenum (field|library), ofwel een paar nullable FK's (form_field_idORform_field_library_id)). Discriminator-keuze wordt in WS-5a besloten op basis van query-patterns. FormFieldService::insertFromLibrarykopieert rijen tussen library-entries en field-entries in plaats van JSON te hydrateren. Natuurlijk werk binnen WS-5; geen aparte PR.
Scope-impact: WS-5 wordt ~7-8 dagen in plaats van 4-6. Drie extra sub-werkstromen voor de library-mirrors passen binnen de bestaande WS-5a/b/d PR-structuur (library valt onder dezelfde PR als de corresponderende field-split).
Q4 — Sanctum personal_access_tokens
Besluit: De Sanctum-default voor tokenable_type / tokenable_id (FQCN in DB, geen morph-map entry) blijft ongewijzigd.
Motivatie:
- Framework-polymorfie valt buiten de domain morph-map conventie. Een alias toevoegen introduceert onderhoudsschuld bij elke Sanctum-upgrade.
- Domain polymorfie (
form_schemas.owner_type,form_submissions.subject_type) blijft strict in morph-map geregistreerd; dit besluit raakt daar niet aan.
Documentatie-actie (WS-8): in de ARCH-documentatie wordt een expliciete regel opgenomen:
De
enforceMorphMap-conventie geldt voor domain polymorfe relaties. Framework-relaties (Sanctumtokenable_type, Spatieactivitylog.subject_type, Spatieactivitylog.causer_type) volgen hun framework-defaults en zijn expliciet uitgezonderd van de morph-map conventie.
Q5 — SCHEMA.md rewrite-shape
Besluit: WS-8 extraheert alle tabellen-zonder-migratie uit SCHEMA.md naar een apart document /dev-docs/ARCH-PLANNED-MODULES.md. SCHEMA.md wordt strict "waarheid van wat bestaat in de database".
Te verplaatsen tabellen (uit WS-1 rapport bevinding D-01):
- §3.5.4 Volunteer Profile & History:
volunteer_festival_history,post_festival_evaluations,festival_retrospectives - §3.5.6 Accreditation Engine:
accreditation_categories,accreditation_items,event_accreditation_items,accreditation_assignments,access_zones,access_zone_days,person_access_zones - §3.5.7 Artists & Advancing:
performances,stages,stage_days,advance_submissions,artist_contacts,artist_riders,itinerary_items - §3.5.8 Communication & Briefings:
briefing_templates,briefings,briefing_sends,communication_campaigns,messages,message_replies,broadcast_messages,broadcast_message_targets - §3.5.9 Check-In & Operational:
check_ins,show_day_absence_alerts,scanners,inventory_items,event_info_blocks,event_info_block_crowd_types,production_requests,material_requests
Onderhoud-pattern:
- Bij elke PR die een planned-module tabel aanmaakt verhuist de betreffende sectie van
ARCH-PLANNED-MODULES.mdnaarSCHEMA.md. Dit wordt onderdeel van de PR-template checklist. ARCH-PLANNED-MODULES.mdbehoudt de index/soft-delete/FK-intent zoals vastgelegd in de originele SCHEMA.md rijen, zodat de planning-informatie niet verloren gaat.- SCHEMA.md Rule 4 (required indexes) verwijst alleen nog naar bestaande tabellen na de rewrite.
Motivatie:
- Enterprise documentatie-discipline: onboarding developers zien direct wat er in de DB staat, zonder ruis van planning.
- SCHEMA.md Rule 4 consistent: required indexes kunnen niet meer verwijzen naar fantoom-tabellen.
- Planned-modules eigen evolutie: kan sneller bijgewerkt worden zonder SCHEMA-ruis.
Scope-impact: WS-8 wordt ~4-5 dagen in plaats van 2-3.
Q6 — subject_type allow-list
Besluit: De allow-list uit config/form_subjects.php wordt opgeheven en geconsolideerd onder de purpose-registry in WS-2. PurposeDefinition heeft per charter §3 besluit 4 al een subject_type veld; dat wordt de enige bron van waarheid.
Concreet (uitvoering in WS-2):
config/form_subjects.phpverdwijnt na WS-2.StoreFormSubmissionRequestleidt toegestanesubject_typewaarden af uitPurposeRegistry::allSubjectTypes().AppServiceProvider::bootbouwt de morph-map deels vanuit de purpose-registry (per purpose een subject-type entry) + framework-entries (activity-log subjects/causers, Sanctum uitgezonderd).- Compile-time guard: een unit-test faalt als een
subject_typeinPurposeRegistryniet in de morph-map staat, of vice versa. Dit vervangt de huidige "developer discipline" afspraak.
Motivatie:
- Eén bron van waarheid voor subject-semantiek. Geen twee-bestanden-sync met impliciete koppeling.
- Verstevigt charter §3 besluit 4:
PurposeDefinitionwordt écht de volledige purpose-specificatie.
Scope-impact: WS-2 krijgt ~halve dag extra werk. De migratie zelf is klein; het compile-time consistency testje is het echte werk.
Herziene werkstroom-scope en inschatting
Charter §5 inschattingen zijn op basis van dit addendum herzien:
| WS | Onderwerp | Charter inschatting | Herzien |
|---|---|---|---|
| WS-1 | Opsporings-pas | 1 dag | 1 dag (afgerond 2026-04-24) |
| WS-2 | Purpose registry | 2-3 dagen | 2-3 dagen + Q6 consolidatie (~halve dag) |
| WS-3 | Één SPA consolidatie | 3-5 dagen | 3-5 dagen (ongewijzigd) |
| WS-4 | ULID + denormalized submission columns + scope | 2-3 dagen | 5-6 dagen (Q1 elf ULID migraties + Q2 scope extension + scope-registratie op 14 models + D-05 Person SoftDeletes verify) |
| WS-5 | JSON-kolom-opsplitsing | 4-6 dagen | 7-8 dagen (Q3 library-mirrors toegevoegd aan WS-5a/b/d) |
| WS-6 | FormBindingApplicator | 4-5 dagen | 4-5 dagen (ongewijzigd) |
| WS-7 | Observability foundation | 2-3 dagen | 2-3 dagen + D-06 activity_log indexes |
| WS-8 | Documentatie-consolidatie | 2-3 dagen | 4-5 dagen (Q4 framework-exception + Q5 planned-modules extractie + PK-decisions doc) |
Totale herziene inschatting: 28-38 dagen werk (charter had 22-32 dagen). Toename van ~6 dagen, volledig verklaard door de strict-enterprise invulling van Q1, Q2 en Q3.
Werkstroom-volgorde ongewijzigd: WS-1 → WS-2 → WS-3 (parallel mogelijk met WS-4/5) → WS-4 → WS-5 → WS-6 → WS-7 → WS-8.
Openstaande bevindingen zonder architect-beslissing
WS-1 rapport Categorie D bevindingen die geen architect-beslissing vereisten en in de relevante werkstromen worden meegenomen:
| ID | Bevinding | Werkstroom |
|---|---|---|
| D-03 | Form-builder child models registreren OrganisationScope niet | WS-4 (als onderdeel van Q2 uitvoering) |
| D-04 (event-data subset) | ShiftAssignment / ShiftWaitlist / VolunteerAvailability / PersonSectionPreference / PersonIdentityMatch zonder scope | WS-4 |
| D-04 (user/admin subset) | MFA / TrustedDevice / UserProfile / EmailLog / OrganisationEmailSettings etc. | backlog, per-model ticket |
| D-05 | Person SoftDeletes verificatie | WS-4 |
| D-06 | activity_log (subject_type, subject_id) en (causer_type, causer_id) indexes |
WS-7 |
| D-07 | Morph map forward-looking entries documentatie-link | WS-8 |
Verwijzingen
/dev-docs/ARCH-CONSOLIDATION-2026-04.md— sprint charter (§1 principes, §3 vastgestelde besluiten blijven ongewijzigd; §5 inschattingen herzien in dit addendum)./dev-docs/ARCH-CONSOLIDATION-WS1-REPORT.md— bron van alle 45 bevindingen waarnaar dit addendum verwijst.
Sign-off
- Architect review: akkoord per Claude Chat sessie 2026-04-24, iteratief verscherpt over drie rondes (initial → strict-enterprise op Q1/Q3 → FK-chain correctie op Q2).
- Product owner: akkoord per Bert Hausmans 2026-04-24.
Volgende stap: prompt opstellen voor WS-2 (Purpose registry) met Q6-consolidatie als integraal onderdeel van de werkstroom.