Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions src/menu-layout.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"spdx-license": "EUPL-1.2",
"spdx-copyright": "2026 Conduction B.V.",
"description": "Canonical navigation layout applied AFTER all manifest.d fragments merge (see applyMenuRelocations in main.js). Fragments stay the source of WHAT exists in the menu (ADR-037); this file is the single place deciding WHERE entries live. relocations: sourceId -> targetGroupId (groups dissolve into the target, leaves move under it). removals: leaf menu-entry ids retired as duplicate navigation — their PAGES stay routable for deep links and e2e specs. settingsSection: top-level config/definition/admin ids lifted into Nextcloud's settings foldout (NcAppNavigationSettings gear, outside the scrollable nav) — see applySettingsSection in main.js; operational/report/dashboard items stay in the main nav. integrationsSection: ids of links whose target is ANOTHER APP, moved out of the navigation entirely into the Integrations section of the per-user settings modal (ADR-110) — such a link can never be the active route and reads as this app's feature when it sits in the nav; gate each on visibleIf.appInstalled so the section never advertises a link into an app the instance does not have.",
"removalsCoverageNote": "Of the 8 entries in `removals`, ONE needs no waiver: `Voorstellen` is reachable because `CaseDetail`'s `case-voorstellen` widget carries `viewAllRoute: /voorstellen`, which gate-53 follows as a real navigation edge. SIX are waived in `removalsReplacedBy` above. ONE (`BesluitvormingAgenda`) is deliberately NOT waived and stays a live gate-53 finding — see the end of this note. The six waivers rest on two documented architecture changes, and each was re-verified against the ASSEMBLED manifest rather than taken from this note's earlier prose. (1) `case-type-navigation` (commit d6824aa20) replaced the standalone Bezwaar/Beroep/Subsidie nav with case-type children resolved dynamically onto the `Cases` page's `folderSidebar`. Measured: `Bezwaren`, `Beroepen` and `Subsidies` are each `type: index` over register `dossiq` / schema `case` whose only narrowing is `filter: { caseType: <uuid> }`, and `Cases` is the same register/schema with `folderSidebar.filterField: caseType` sourced from the `caseType` schema — so picking that folder on `Cases` produces the same rows the retired page produced, the same filter field over the same data rather than an approximation. `BezwaarBeroepOverview` is a card grid whose own `_note` already records that objections/appeals are case types under Cases. `CaseMap` is superseded by `Cases`' `viewModes: [table, cards, map]` plus `mapConfig`; the retired page's full-screen split layout is a presentation difference and its case-type filter sidebar is the `folderSidebar`. (2) `consume-decidesk-besluitvorming-leaf` (commit d2df51b8b) moved decision-making to decidesk, surfaced in dossiq as the `besluitvorming` sidebar tab (`BesluitvormingLeafTab`) and the `case-decidesk-decisions` widget on `CaseDetail`. `Advice` was an index over schema `adviesAanvraag`; per-case advice now reaches the user through that leaf, so `CaseDetail` is its replacement inside dossiq, while the CROSS-CASE advice queue is decidesk's by design because dossiq no longer owns that model. THE SEVENTH IS CROSS-APP, AND ITS EVIDENCE IS RECORDED HERE BECAUSE THE GATE CANNOT CHECK IT: `BesluitvormingAgenda` (route `AgendaCompiler`) -> `decidesk:MeetingDetail`. `AgendaCompiler` is a bespoke meeting-agenda compiler — it assembles a meeting agenda from selected proposals with drag-ordering and section grouping — which is a cross-case, meeting-level surface. It emphatically did NOT move to `CaseDetail`: a string walk of this app's assembled manifest finds `agenda` / `vergadering` / `meeting` on exactly two pages, `AgendaCompiler` and `VergaderingDetail`, both themselves off the menu, and on no widget or sidebar tab of `CaseDetail`. Naming `CaseDetail` would have made this map assert something untrue, and the same-app check could not have caught it — it verifies the named page exists and is reachable, never that it does the job. It moved to decidesk, with the rest of decision-making, under `consume-decidesk-besluitvorming-leaf`. The cross-app form `<appId>:<PageId>` is deliberately weaker than the same-app form: the gate checks only that `decidesk` is a known fleet app id and is not this app, and it CANNOT check that `MeetingDetail` exists there, is reachable there, is installed, or carries this functionality — nor can this waiver ever rot. So the review judgement it defers to was done by hand and is written down here to be re-checkable: measured against decidesk `origin/development` @ 830e3d87, page `MeetingDetail` (`/meetings/:id`) exists and carries a `meeting-agenda` custom widget titled `Agenda`, alongside `meeting-stats-agenda-items`, `meeting-decisions`, `meeting-minutes` and `meeting-votes`; it is the detail page of `Meetings`, which is a live entry in decidesk's own menu. Note that dossiq declares NO manifest dependency on decidesk (`dependencies: [openregister]`), deliberately — decidesk is an optional peer and `BesluitvormingLeafTab` degrades gracefully when it is absent — so nothing in THIS repo corroborates the claim and the gate says so in its WARN. Do not add a dependency to quieten that warning; it would change runtime semantics to flatter a gate."
"removalsCoverageNote": "Of the 8 entries in `removals`, ONE needs no waiver: `Voorstellen` is reachable because `CaseDetail`'s `case-voorstellen` widget carries `viewAllRoute: /voorstellen`, which gate-53 follows as a real navigation edge. SIX are waived in `removalsReplacedBy` above. ONE (`BesluitvormingAgenda`) is deliberately NOT waived and stays a live gate-53 finding — see the end of this note. The six waivers rest on two documented architecture changes, and each was re-verified against the ASSEMBLED manifest rather than taken from this note's earlier prose. (1) `case-type-navigation` (commit d6824aa20) replaced the standalone Bezwaar/Beroep/Subsidie nav with case-type children resolved dynamically onto the `Cases` page's `folderSidebar`. Measured: `Bezwaren`, `Beroepen` and `Subsidies` are each `type: index` over register `dossiq` / schema `case` whose only narrowing is `filter: { caseType: <uuid> }`, and `Cases` is the same register/schema with `folderSidebar.filterField: caseType` sourced from the `caseType` schema — so picking that folder on `Cases` produces the same rows the retired page produced, the same filter field over the same data rather than an approximation. `BezwaarBeroepOverview` is a card grid whose own `_note` already records that objections/appeals are case types under Cases. `CaseMap` is superseded by `Cases`' `viewModes: [table, cards, map]` plus `mapConfig`; the retired page's full-screen split layout is a presentation difference and its case-type filter sidebar is the `folderSidebar`. (2) `consume-decidesk-besluitvorming-leaf` (commit d2df51b8b) moved decision-making to decidesk, surfaced in dossiq as the `besluitvorming` sidebar tab (`BesluitvormingLeafTab`) and the `case-decidesk-decisions` widget on `CaseDetail`. `Advice` was an index over schema `adviesAanvraag`; per-case advice now reaches the user through that leaf, so `CaseDetail` is its replacement inside dossiq, while the CROSS-CASE advice queue is decidesk's by design because dossiq no longer owns that model. THE SEVENTH IS CROSS-APP, AND ITS EVIDENCE IS RECORDED HERE BECAUSE THE GATE CANNOT CHECK IT: `BesluitvormingAgenda` (route `AgendaCompiler`) -> `decidesk:MeetingDetail`. `AgendaCompiler` is a bespoke meeting-agenda compiler — it assembles a meeting agenda from selected proposals with drag-ordering and section grouping — which is a cross-case, meeting-level surface. It emphatically did NOT move to `CaseDetail`: a string walk of this app's assembled manifest finds `agenda` / `vergadering` / `meeting` on exactly two pages, `AgendaCompiler` and `VergaderingDetail`, both themselves off the menu, and on no widget or sidebar tab of `CaseDetail`. Naming `CaseDetail` would have made this map assert something untrue, and the same-app check could not have caught it — it verifies the named page exists and is reachable, never that it does the job. It moved to decidesk, with the rest of decision-making, under `consume-decidesk-besluitvorming-leaf`. The cross-app form `<appId>:<PageId>` is deliberately weaker than the same-app form: the gate checks only that `decidesk` is a known fleet app id and is not this app, and it CANNOT check that `MeetingDetail` exists there, is reachable there, is installed, or carries this functionality — nor can this waiver ever rot. So the review judgement it defers to was done by hand and is written down here to be re-checkable: measured against decidesk `origin/development` @ 830e3d87, page `MeetingDetail` (`/meetings/:id`) exists and carries a `meeting-agenda` custom widget titled `Agenda`, alongside `meeting-stats-agenda-items`, `meeting-decisions`, `meeting-minutes` and `meeting-votes`; it is the detail page of `Meetings`, which is a live entry in decidesk's own menu. Note that dossiq declares NO manifest dependency on decidesk (`dependencies: [openregister]`), deliberately — decidesk is an optional peer and `BesluitvormingLeafTab` degrades gracefully when it is absent — so nothing in THIS repo corroborates the claim and the gate says so in its WARN. Do not add a dependency to quieten that warning; it would change runtime semantics to flatter a gate. ADDED 2026-08-31 — `TenantsMenu` -> `openregister:organisation`, the NINTH removal and the SECOND cross-app one. gate-53 warns that a cross-app waiver is a REDUCED GUARANTEE it cannot verify and cannot rot, so the review judgement is written down here to be re-checkable, exactly as BesluitvormingAgenda's is. Measured against the running instance on 2026-08-31: openregister declares page id `organisation` (route `/organisation`, type custom) and a live menu entry `Organisations` pointing at it, and ships OrganisationsIndex.vue / OrganisationDetails.vue / JoinOrganisation.vue. Unlike the decidesk case, dossiq DOES declare a manifest dependency on openregister, so the target app is guaranteed present. The dossiq `tenant` schema is already marked DEPRECATED in dossiq_register.json (\"Tenant identity now lives on OpenRegister's Organisation entity; retained only so pre-migration rows remain readable until sunset\") and `occ dossiq:migrate-tenants` moves the rows; this removal retires the menu entry that outlived that migration. The instance carries 0 tenant rows."
},
"removalsReplacedBy": {
"BezwaarBeroepGroup": "Cases",
Expand All @@ -12,7 +12,8 @@
"SubsidiesGroup": "Cases",
"CaseMap": "Cases",
"Advice": "CaseDetail",
"BesluitvormingAgenda": "decidesk:MeetingDetail"
"BesluitvormingAgenda": "decidesk:MeetingDetail",
"TenantsMenu": "openregister:organisation"
},
"relocations": {
"MyWork": "WorkGroup",
Expand All @@ -29,7 +30,8 @@
"CaseMap",
"Voorstellen",
"Advice",
"BesluitvormingAgenda"
"BesluitvormingAgenda",
"TenantsMenu"
],
"settingsSection": [
"PartnersMenu",
Expand Down
Loading