refactor(mandaat): rename the mandaat schemas and their data contract to mandate - #817
Merged
Merged
Conversation
INCOMPLETE. The four schemas, their eight properties, the slug map and the
column migration are done and verified. The 716 code references across 56 files
are NOT. Merging this state gives every one of them a silent null read: the
schema declares `mandate`, the code still asks for `mandaat`, and OpenRegister
returns null rather than erroring.
Committed so the ownership analysis and the migration boundary are not lost.
DONE — all four owners, one register scope
mandaat -> mandate (61-mandaat-matrix)
mandaatGebruik -> mandateUsage (61-mandaat-matrix)
mandaatEscalatie -> mandateEscalation (61-mandaat-matrix)
mandaatRegeling -> mandateArrangement (30-beschikking)
mandaatNummer -> mandateNumber mandaatId -> mandateId
mandaatVersieId -> mandateVersionId targetMandaatId -> targetMandateId
mandaatGroepen -> mandateGroups ondermandaatToegestaan -> subMandateAllowed
mandaatNiveau -> mandateLevel mandaatGegeven -> mandateGranted
Verified after: 0 procest-scoped schemas or top-level properties still carry
`mandaat`. Ownership was checked per property BEFORE editing — each is declared
by exactly one schema, and all four schemas sit in the `procest` register, so
the register-scoped migration covers every owner. That is the condition the
wettelijkeGrondslag slice established and it is satisfied here.
SLUG MAP: keys follow the new slugs, VALUES deliberately unchanged. Each value
is the appconfig key holding that schema's numeric id on existing installs;
renaming it orphans the id and the schema silently resolves to nothing.
DELIBERATELY EXCLUDED
- `akkoord-mandaat` is a lifecycle ENUM VALUE, i.e. stored data. Renaming it
rewrites every row — a separate, riskier migration, same call as
openconnector#1213 and procest#815.
- `mandaatregelingId` and the `mandaatNiveau` inside `mandateGranted` are
NESTED under an object property, so they live in that column's JSON rather
than as columns. A column rename cannot reach them; they need a JSON-rewrite
migration. Documented in the map.
TO FINISH: 716 references in lib/ and src/ across 56 files — the four Mandaat*
PHP service/controller classes, MandaatRegistryService, MandaatEscalatieService,
MandaatCheckService, MandaatImportService, and the Vue files
(MandaatMatrixTab, MandaatEditor, MandaatImportPanel). Then this is mergeable.
Note MandaatCsvParser::REQUIRED_COLUMNS and the CSV headers are an external
input contract — alias both spellings rather than breaking operator files.
Continues f8a55fa. Renames the schema PROPERTY READS that break when the schema half lands: mandaatGroepen -> mandateGroups (MandaatVerifier, 3 sites) and mandaatGegeven -> mandateGranted (BeschikkingService, 2 sites). MandaatCsvParser::REQUIRED_COLUMNS deliberately NOT renamed and now documented in place. Those are CSV HEADERS — an external input contract operators' files already use. I renamed it, then reverted: it would reject every import file in the field. MandaatImportService maps headers onto the renamed properties and accepts either spelling, which is the pattern used for wettelijkeGrondslag and omschrijving. STILL WIP DO NOT MERGE — the remaining data-contract sites (MandaatCheckService, MandaatGebruikService, MandaatEscalatieService, MandaatGuard, and 6 Vue files) are not done.
Every code site that READS or WRITES a renamed schema property now agrees with the schema. Combined with f8a55fa and 4c5a187, this branch is coherent: schema, migration and data contract all move together. WHAT THIS IS NOT. The Mandaat* class names, file names and local variables are still Dutch — roughly 650 references. They are cosmetic: nothing resolves through them at runtime, so they can follow in their own change without risk. The 66 references that actually BREAK are the ones handled here, and isolating that subset is what made the slice finishable. DATA SITES MOVED MandaatVerifier mandaatGroepen -> mandateGroups (3) BeschikkingService mandaatGegeven -> mandateGranted (2) MandaatGebruikService mandaatId -> mandateId, mandaatVersieId -> mandateVersionId, and the findAll filter MandaatEscalatieService targetMandaatId -> targetMandateId MandaatImportService the payload key, and two reads of stored objects 6 Vue files mandaatNummer -> mandateNumber, mandaatNiveau -> mandateLevel, mandaatGegeven -> mandateGranted DELIBERATELY NOT MOVED, each for a measured reason - MandaatCsvParser::REQUIRED_COLUMNS and every $row['...'] read: CSV HEADERS, an external input contract operators' files already use. I renamed REQUIRED_COLUMNS, then reverted — it would reject every import file in the field. Now documented in place. - `['mandaatId' => ...]` in MandaatEscalatieService: an INTERNAL return-array key from resolveEscalationPath(), not a schema property. - `mandaatNiveau` INSIDE mandateGranted, and `mandaatregelingId`: nested under an object property, so JSON within a column rather than columns. A column rename cannot reach them; they need a JSON-rewrite migration. The outer key moves, the inner does not — asserted that way in BeschikkingServiceTest. - `akkoord-mandaat`: a lifecycle ENUM VALUE, i.e. stored data. VERIFIED - phpunit: 1882 tests, 6393 assertions green (5 skipped, same as baseline). Four tests failed first and were fixed: three BeschikkingServiceTest cases on the mandateGranted/mandateGroups fixtures, one MandaatEscalatieServiceTest on targetMandateId. - php -l clean on every changed file; all JSON parses. - phpcs: 58 errors across the changed files against a 106-error baseline on the two test files — phpcbf cleared pre-existing debt while fixing my alignment. Both lib/ services are at 0 errors. - 0 procest-scoped schemas or top-level properties still carry `mandaat`.
rubenvdlinde
requested review from
SudoThijn,
WilcoLouwerse,
bbrands02,
remko48 and
rjzondervan
as code owners
August 12, 2026 09:28
Contributor
Quality Report — ConductionNL/procest @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ❌ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| check-vue3-compile | ✅ | ||||
| test-l10n | ✅ | ||||
| composer | ✅ | ✅ 100/100 | |||
| npm | ✅ | ✅ 552/552 | |||
| PHPUnit | ✅ | ||||
| Newman | ⏭️ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ❌ |
Quality workflow — 2026-08-12 09:45 UTC
Download the full PDF report from the workflow artifacts.
rubenvdlinde
added a commit
that referenced
this pull request
Aug 12, 2026
…ticeOfDefault* (#818) Replaces #810, which was branched from a stale stack: its diff carried a dozen files that #803/#804/#806/#809/#816/#817 have since landed, so rebasing it meant resolving 8 conflicts across controllers, services, tests and a Postman collection. Branched fresh from development this does the same work as a 40-reference change across 10 files with zero conflicts. IngebrekestellingService -> NoticeOfDefaultService IngebrekestellingController -> NoticeOfDefaultController registerIngebrekestelling() -> registerNoticeOfDefault() ROUTE NAMES MOVE, URLs DO NOT. A route name resolves to its controller class, so `ingebrekestelling#register` had to become `noticeOfDefault#register` or the router 500s on that endpoint. The URLs stay `/api/termijn/ingebrekestellingen`: that is the published contract and moving it is a breaking change for every consumer — a separate decision from this rename. Both route names were verified to resolve to NoticeOfDefaultController.php after the change. NOT IN THIS CHANGE: the `ingebrekestelling` SCHEMA in 60-termijnbewaking.json, its reference property, and the `ingebrekestelling-ontvangen` lifecycle enum value. The schema is a data contract — renaming it needs an ownership check and a column migration, and the enum value is stored data. Class names carry no data and move independently, which is why this is a clean slice. VERIFIED - phpunit: 1882 tests, 6393 assertions green (5 skipped, same as baseline). - php -l clean on every changed file; the Postman collection still parses. - Route names resolve: both noticeOfDefault#* map to a file that exists. - Residual grep finds no IngebrekestellingService / IngebrekestellingController / registerIngebrekestelling anywhere in lib/, tests/ or appinfo/. - phpcs: 6 errors across the four changed files against a 386-error baseline. My edit added 5; phpcbf fixed those and cleared pre-existing debt with them.
This was referenced Aug 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Applies the ratified mandaat = mandate rename to all four schemas, their eight properties, the slug map, the column migration, and every code site that reads or writes those properties.
The 66-vs-716 split
mandaatappears 716 times across 56 files. Only 66 of those break when the schema moves — property reads, filter keys, slug strings. The other ~650 are class names, file names and local variables: nothing resolves through them at runtime.This PR does the 66. Isolating that subset is what made the slice finishable in one pass; the cosmetic renames can follow without risk.
Schemas — all four owners, one register scope
mandaatmandatemandaatGebruikmandateUsagemandaatEscalatiemandateEscalationmandaatRegelingmandateArrangementPlus
mandaatNummer→mandateNumber,mandaatId→mandateId,mandaatVersieId→mandateVersionId,targetMandaatId→targetMandateId,mandaatGroepen→mandateGroups,ondermandaatToegestaan→subMandateAllowed,mandaatNiveau→mandateLevel,mandaatGegeven→mandateGranted.Ownership was checked per property before editing: each is declared by exactly one schema, and all four schemas sit in the
procestregister — so the register-scoped migration covers every owner. That is the condition #816 established, and it is satisfied here rather than assumed.Slug map keys follow the new slugs; values deliberately unchanged — each is the appconfig key holding that schema's numeric id on existing installs, and renaming it orphans the id.
Deliberately not moved, each for a measured reason
MandaatCsvParser::REQUIRED_COLUMNS, every$row['...']) — an external input contract. I renamedREQUIRED_COLUMNS, then reverted: it would reject every operator import file in the field. Documented in place.['mandaatId' => ...]inMandaatEscalatieService— an internal return-array key fromresolveEscalationPath(), not a schema property.mandaatNiveauinsidemandateGranted, andmandaatregelingId— nested under an object property, so they live in that column's JSON rather than as columns. A column rename cannot reach them; they need a JSON-rewrite migration. The outer key moves, the inner does not — andBeschikkingServiceTestnow asserts exactly that.akkoord-mandaat— a lifecycle enum value, i.e. stored data. Renaming rewrites every row.Verification
BeschikkingServiceTestcases on themandateGranted/mandateGroupsfixtures, oneMandaatEscalatieServiceTestontargetMandateIdphp -lclean on every changed file; all JSON parseslib/services are at 0.mandaatFollow-ups
The ~650 cosmetic references (the four
Mandaat*service classes,MandaatMatrixController,MandaatRegistryService, the Vue file names) and the nested-JSON migration are separate changes.