diff --git a/openspec/changes/bezwaar-beroep-cards-collapse/proposal.md b/openspec/changes/bezwaar-beroep-cards-collapse/proposal.md index ea60ac6d5..38f08e96e 100644 --- a/openspec/changes/bezwaar-beroep-cards-collapse/proposal.md +++ b/openspec/changes/bezwaar-beroep-cards-collapse/proposal.md @@ -1,5 +1,16 @@ # Proposal: bezwaar-beroep-cards-collapse +> **SUPERSEDED 2026-09-02.** The landing page this change delivered +> (`BezwaarBeroepOverview`, route `/bezwaar-beroep`) has been deleted, along with +> its manifest fragment, its Vue component and its registry entry. Every one of +> its four cards had stopped resolving: `BezwaarDecisions` and +> `BezwaarAdviceRequests` were retired by `case-type-navigation`, and `Bezwaren` +> and `Beroepen` were retired as pages on 2026-09-02 because each was an index +> over register `dossiq` and schema `case` narrowed by a `caseType` that sits +> under `_caseTypes_disabled`, so both listed nothing. Objections and appeals are +> case types on `Cases`. Their detail routes `/bezwaren/:id` and `/beroepen/:id` +> stay registered. Read this file as history, not as a description of the app. + ## Summary Collapse the **Bezwaar & Beroep** group (`BezwaarBeroepGroup`) in the dossiq navigation into a single top-level menu item that links to a new card-grid landing page. Each of the four former child leaves (`Bezwaren`, `Beroepen`, `BezwaarDecisions`, `BezwaarAdviceRequests`) is rendered as a card on that landing page. All former leaf page routes remain registered and reachable as deep links; only the navigation nesting changes. This change follows the ADR-044 "Menu architecture" cards-collapse rule. diff --git a/openspec/specs/advice-management/spec.md b/openspec/specs/advice-management/spec.md index 51f28edc7..ad949c71b 100644 --- a/openspec/specs/advice-management/spec.md +++ b/openspec/specs/advice-management/spec.md @@ -12,22 +12,21 @@ Advice management lets behandelaars request, track, and process internal and ext ## Requirements -**Advice Page Render (UI surface)** - -### Requirement: Advice index page render - -The Advice (adviezen) index page (`CnIndexPage`, route `/advice`) SHALL mount and -render its stable list shell on navigation — the Cards/Table view toggle, an "Add" -create button, a per-row "Actions" control, and an empty-state message when no -advice requests are visible — independently of whether the OpenRegister collection -returns rows. - -#### Scenario: Advice index page renders list shell -- **GIVEN** an authenticated user on the Dossiq app -- **WHEN** they navigate to the Advice page -- **THEN** the Cards/Table view-mode toggle MUST be visible -- **AND** an "Add" create button MUST be visible -- **AND** the page MUST NOT show an Internal Server Error +**Advice surface (UI surface)** + +### Requirement: Advice surface + +Per-case advice SHALL reach the user through the `besluitvorming` leaf on +CaseDetail and the `case-decidesk-decisions` widget. `/advice/:id` SHALL stay +registered so every advice detail link keeps resolving. + +REPLACED 2026-09-02. The standalone `/advice` index page is retired, not hidden. +`consume-decidesk-besluitvorming-leaf` moved decision-making to decidesk, which +owns the `adviesAanvraag` model and the CROSS-CASE advice queue by design. dossiq +keeps the per-case view and the detail route. A dossiq-side list over a model +dossiq no longer owns is the duplication that change set out to remove. + +@e2e exclude The per-case surface is covered by the besluitvorming leaf specs; the cross-case queue is decidesk's and is not a dossiq surface to test. **ADDED Requirements** diff --git a/openspec/specs/bezwaar-lifecycle/spec.md b/openspec/specs/bezwaar-lifecycle/spec.md index 41357151c..1f1ef153a 100644 --- a/openspec/specs/bezwaar-lifecycle/spec.md +++ b/openspec/specs/bezwaar-lifecycle/spec.md @@ -12,22 +12,23 @@ Defines the end-to-end bezwaar (objection) lifecycle: the pre-seeded Bezwaar cas ## Requirements -**Bezwaren Page Render (UI surface)** - -### Requirement: Bezwaren index page render - -The Bezwaren (objections) index page (`CnIndexPage`, route `/bezwaren`) SHALL mount -and render its stable list shell on navigation — the Cards/Table view toggle, an -"Add" create button, a per-row "Actions" control, and an empty-state message when -no objection cases are visible — independently of whether the OpenRegister -collection returns rows. - -#### Scenario: Bezwaren index page renders list shell -- **GIVEN** an authenticated user on the Dossiq app -- **WHEN** they navigate to the Bezwaren page -- **THEN** the Cards/Table view-mode toggle MUST be visible -- **AND** an "Add" create button MUST be visible -- **AND** the page MUST NOT show an Internal Server Error +**Bezwaren list surface (UI surface)** + +### Requirement: Bezwaren list surface + +Objections SHALL be listed on the Cases page, narrowed to the Bezwaar case type. +`/bezwaren/:id` SHALL stay registered so every objection detail link keeps +resolving. + +REPLACED 2026-09-02. The standalone `/bezwaren` index page is retired, not hidden. +It was an index over register `dossiq` and schema `case` whose only narrowing was +`filter: { caseType: }`. Cases carries the same register and the same +schema, and narrows the same field through its `folderSidebar` +(`filterField: caseType`). Picking the Bezwaar folder returns the rows the retired +page returned, so this is the same query on the same data rather than an +approximation. + +@e2e exclude The list shell is covered by `case-management/spec.md#cases-index-page-renders-list-shell`, which drives the same `CnIndexPage` over the same register and schema. **ADDED Requirements** diff --git a/openspec/specs/dossiq-config-to-settings/spec.md b/openspec/specs/dossiq-config-to-settings/spec.md index 9073a9ee6..b52dd96d8 100644 --- a/openspec/specs/dossiq-config-to-settings/spec.md +++ b/openspec/specs/dossiq-config-to-settings/spec.md @@ -85,6 +85,12 @@ Neither SHALL be added to the `SettingsGroup` relocations. ### Requirement: REQ-PCTS-004 — Relocated Pages Stay Routable Every page whose nav leaf is relocated SHALL remain reachable by its existing route after the change. + +AMENDED 2026-09-02. One exception: the `/settings/parafeerroutes` INDEX page is retired outright. +dossiq#1666 moved parafering to the decision app and retired the local engine, so the design screen +invited edits that reach nothing that runs. `/settings/parafeerroutes/:id` stays registered, so a +reader can still open a legacy route object, and the audit context naming `parafeerrouteId` keeps +resolving. dossiq SHALL NOT change any page `id`, `route`, `type` or `component` as part of this relocation; the change SHALL touch only the menu structure (`src/manifest.json#menu`, `src/menu-layout.json`) and the `Legesberekeningen` section flag. @@ -92,7 +98,7 @@ change SHALL touch only the menu structure (`src/manifest.json#menu`, `src/menu- #### Scenario: Deep links to relocated config pages still resolve - **GIVEN** the configuration leaves have been relocated under `SettingsGroup` -- **WHEN** a user navigates directly to `/settings/tenants`, `/settings/parafeerroutes`, +- **WHEN** a user navigates directly to `/settings/tenants`, `/settings/parafeerroutes/:id`, `/settings/wms-layers`, `/settings/workflow-definitions`, `/settings/automatic-actions`, `/settings/lhs-matrices`, `/legesverordeningen`, `/tenant-onboarding`, `/leges/verordeningen` or `/settings` - **THEN** each route SHALL resolve to its existing page diff --git a/openspec/specs/objections-appeals-nav-group/spec.md b/openspec/specs/objections-appeals-nav-group/spec.md index a280bab6b..c2ecafd21 100644 --- a/openspec/specs/objections-appeals-nav-group/spec.md +++ b/openspec/specs/objections-appeals-nav-group/spec.md @@ -56,18 +56,26 @@ contiguous run (`Bezwaren`=45, `Beroepen`=46, `BezwaarDecisions`=47, `BezwaarAdv ### Requirement: REQ-POAG-003 — Every Grouped Page Stays Routable (Relocation Moves The Entry, Not The Page) -dossiq SHALL keep every objections-and-appeals page routable at its existing route after the -grouping. Relocation SHALL move only the menu entry; the `pages[]` declarations and their routes — -`/bezwaren` (+`/bezwaren/:id`), `/beroepen` (+`/beroepen/:id`), `/bezwaar-decisions` -(+`/bezwaar-decisions/:id`), `/bezwaar-advice-requests` (+`/bezwaar-advice-requests/:id`), -`/settings/bezwaar-committees` (+`/settings/bezwaar-committees/:id`) — SHALL remain registered and -reachable by direct URL and e2e specs. No page SHALL be added to `src/menu-layout.json#removals`. +dossiq SHALL keep every objections-and-appeals DETAIL page routable at its existing route. +Relocation moves only the menu entry, so `/bezwaar-decisions` (+`/bezwaar-decisions/:id`), +`/bezwaar-advice-requests` (+`/bezwaar-advice-requests/:id`), `/settings/bezwaar-committees` +(+`/settings/bezwaar-committees/:id`), `/bezwaren/:id` and `/beroepen/:id` SHALL remain registered +and reachable by direct URL and e2e specs. + +AMENDED 2026-09-02. The `/bezwaren` and `/beroepen` INDEX pages are retired outright, not hidden. +Each was an index over register `dossiq` and schema `case` whose only narrowing was +`filter: { caseType: }`, and Cases carries the same register, the same schema and the same +narrowing through its `folderSidebar` (`filterField: caseType`). A second list over identical data +is the duplication this grouping set out to remove, so hiding the entry stopped half way. Detail +routes stay, so every objection and appeal link keeps resolving. The original clause forbidding a +`src/menu-layout.json#removals` entry now holds for a different reason: there is no entry left to +remove. #### Scenario: Deep links to grouped pages still resolve - **GIVEN** the grouping has shipped -- **WHEN** a user navigates directly to `/bezwaren`, `/beroepen`, `/bezwaar-decisions`, - `/bezwaar-advice-requests`, or `/settings/bezwaar-committees` +- **WHEN** a user navigates directly to `/bezwaar-decisions`, `/bezwaar-advice-requests`, or + `/settings/bezwaar-committees` - **THEN** the corresponding page SHALL load - **AND** the page route SHALL be unchanged from before the grouping diff --git a/openspec/specs/parafeerroute-engine/spec.md b/openspec/specs/parafeerroute-engine/spec.md index 67f7d1255..1d0c459f0 100644 --- a/openspec/specs/parafeerroute-engine/spec.md +++ b/openspec/specs/parafeerroute-engine/spec.md @@ -55,18 +55,27 @@ The system SHALL execute parafeerroute steps in sequential order. Each step SHAL - **AND** the step 4 actor SHALL receive a Nextcloud notification - **AND** the voorstel updatedAt SHALL be refreshed -### Requirement: Admin Parafeerroute Configuration +### Requirement: Admin parafeerroute configuration -The system SHALL provide an admin UI for creating and managing parafeerroutes. Routes SHALL be linkable to case types and voorstel types. +Approval routes SHALL be authored in the decision app. dossiq raises a voorstel's +chain there and records the outcome, and SHALL NOT offer a local authoring surface. + +AMENDED 2026-09-02. dossiq#1666 moved the parafering RUNTIME to decidiq and retired +the local engine with no facade, including the dossiq-side flow projection that +dossiq#1632 had introduced. So there is no dossiq authoring surface left to keep, +and the `/settings/parafeerroutes` index page is retired with it: editing a route +object here would reach nothing that runs. `/settings/parafeerroutes/:id` stays +registered so a reader can still open a legacy route object, and so the frozen +`procest.parafering.*` audit trail that names `parafeerrouteId` keeps resolving. **Feature tier**: V1 -#### Scenario: Create a new parafeerroute +#### Scenario: Create a new approval route -- **WHEN** the beheerder navigates to admin settings and opens the "Parafeerroutes" tab +- **WHEN** the beheerder authors the approval route in the decision app - **THEN** the beheerder SHALL be able to create a new route with a name - **AND** the beheerder SHALL be able to add steps with: step type (advies/parafering/accordering), actor type (user/group/role), actor selection, mandatory flag -- **AND** the beheerder SHALL be able to reorder steps via drag-and-drop +- **AND** the beheerder SHALL be able to reorder steps on the canvas #### Scenario: Link route to case type diff --git a/src/components/bezwaar/BezwaarBeroepOverview.vue b/src/components/bezwaar/BezwaarBeroepOverview.vue deleted file mode 100644 index eca156366..000000000 --- a/src/components/bezwaar/BezwaarBeroepOverview.vue +++ /dev/null @@ -1,152 +0,0 @@ - - - - - - - - - diff --git a/src/manifest.d/bezwaar-beroep-cards.json b/src/manifest.d/bezwaar-beroep-cards.json deleted file mode 100644 index cbac7865a..000000000 --- a/src/manifest.d/bezwaar-beroep-cards.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "_meta": { - "spdx-license": "EUPL-1.2", - "spdx-copyright": "2026 Conduction B.V.", - "change": "bezwaar-beroep-cards-collapse", - "frozen-register-slug": "The `register` value below is deliberately still `procest` after the procest -> dossiq app-id rename. It is the OpenRegister register SLUG, not this app's id, and OpenRegister resolves registers by slug — renaming it would address a register that does not exist and orphan every stored objection and appeal, silently (the page renders, the list is just empty).", - "adr": "ADR-044 cards-collapse — menu group replaced by a direct link to a card-grid landing page", - "description": "Bezwaar & Beroep cards-collapse: the BezwaarBeroepGroup is converted to a direct menu link pointing to the new BezwaarBeroepOverview card-grid page. Each of the four former child leaves (Bezwaren, Beroepen, BezwaarDecisions, BezwaarAdviceRequests) is rendered as a navigable card on the landing page. All four former leaf page routes remain registered and reachable as deep links (ADR-044 hard invariant). Their menu entries are suppressed via removals in src/menu-layout.json." - }, - "menu": [ - { "id": "BezwaarBeroepGroup", "route": "BezwaarBeroepOverview" } - ], - "pages": [ - { - "id": "BezwaarBeroepOverview", - "route": "/bezwaar-beroep", - "type": "custom", - "title": "Bezwaar & Beroep", - "_note": "Bespoke objections & appeals cards-landing (ADR-044) — a card grid over the four former leaf routes; kept routable as a deep link though removed from the menu (objections/appeals are case types under Cases).", - "component": "BezwaarBeroepOverview", - "config": { - "register": "dossiq" - } - } - ] -} diff --git a/src/manifest.json b/src/manifest.json index e504e164d..6e7d14f79 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -236,20 +236,6 @@ "route": "WorkflowBoard", "order": 35 }, - { - "id": "Bezwaren", - "label": "Objections", - "icon": "FileAlertOutline", - "route": "Bezwaren", - "order": 45 - }, - { - "id": "Beroepen", - "label": "Appeals", - "icon": "ScaleBalance", - "route": "Beroepen", - "order": 46 - }, { "id": "AnalyticsGroup", "label": "Reports", @@ -286,13 +272,6 @@ "route": "Voorstellen", "order": 70 }, - { - "id": "Advice", - "label": "Advice", - "icon": "CommentOutline", - "route": "Advice", - "order": 75 - }, { "id": "SettingsGroup", "label": "Settings", @@ -324,14 +303,6 @@ "order": 98, "permission": "admin" }, - { - "id": "ParafeerroutesMenu", - "label": "Approval routes", - "icon": "SitemapOutline", - "route": "Parafeerroutes", - "section": "settings", - "order": 96 - }, { "id": "WmsLayersMenu", "label": "Map layers", @@ -1790,47 +1761,6 @@ "main": "DeelzaakDetail" } }, - { - "id": "Bezwaren", - "route": "/bezwaren", - "type": "index", - "title": "Bezwaren", - "config": { - "register": "dossiq", - "schema": "case", - "allowSavedViews": true, - "filter": { - "caseType": "b3c1a000-0000-4000-a000-00000000be2a" - }, - "showViewAction": false, - "actions": [ - { - "id": "view", - "label": "View", - "icon": "EyeOutline", - "handler": "navigate", - "route": "CaseDetail", - "type": "handler" - } - ], - "columns": [ - "identifier", - "title", - { - "key": "status", - "label": "Status", - "formatter": "statusTypeName" - }, - "assignee", - "deadline" - ], - "sidebar": { - "enabled": true, - "showMetadata": true - }, - "documentationUrl": "https://procest.conduction.nl" - } - }, { "id": "BezwaarDetail", "route": "/bezwaren/:id", @@ -2514,41 +2444,6 @@ "default": "VoorstelDetailView" } }, - { - "id": "Advice", - "route": "/advice", - "type": "index", - "title": "Advice requests", - "config": { - "register": "dossiq", - "schema": "adviesAanvraag", - "allowSavedViews": true, - "showViewAction": false, - "actions": [ - { - "id": "view", - "label": "View", - "icon": "EyeOutline", - "handler": "navigate", - "route": "AdviceDetail", - "type": "handler" - } - ], - "columns": [ - "onderwerp", - "case", - "adviseur", - "type", - "status", - "deadline" - ], - "sidebar": { - "enabled": true, - "showMetadata": true - }, - "documentationUrl": "https://procest.conduction.nl" - } - }, { "id": "AdviceDetail", "route": "/advice/:id", @@ -2901,46 +2796,6 @@ "documentationUrl": "https://procest.conduction.nl" } }, - { - "id": "Parafeerroutes", - "route": "/settings/parafeerroutes", - "type": "index", - "title": "Parafeerroutes", - "config": { - "register": "dossiq", - "schema": "parafeerroute", - "columns": [ - { - "key": "name" - }, - { - "key": "proposalType" - }, - { - "key": "caseType" - }, - { - "key": "isDefault" - } - ], - "showViewAction": false, - "actions": [ - { - "id": "view", - "label": "View", - "icon": "EyeOutline", - "handler": "navigate", - "route": "ParafeerrouteDetail", - "type": "handler" - } - ], - "sidebar": { - "enabled": true, - "showMetadata": true - }, - "documentationUrl": "https://procest.conduction.nl" - } - }, { "id": "WmsLayers", "route": "/settings/wms-layers", @@ -4271,47 +4126,6 @@ } } }, - { - "id": "Beroepen", - "route": "/beroepen", - "type": "index", - "title": "Beroepen", - "config": { - "register": "dossiq", - "schema": "case", - "allowSavedViews": true, - "filter": { - "caseType": "b3c1a000-0000-4000-a000-00000000be30" - }, - "columns": [ - "identifier", - "title", - { - "key": "status", - "label": "Status", - "formatter": "statusTypeName" - }, - "assignee", - "deadline" - ], - "showViewAction": false, - "actions": [ - { - "id": "view", - "label": "View", - "icon": "EyeOutline", - "handler": "navigate", - "route": "CaseDetail", - "type": "handler" - } - ], - "sidebar": { - "enabled": true, - "showMetadata": true - }, - "documentationUrl": "https://procest.conduction.nl" - } - }, { "id": "BeroepDetail", "route": "/beroepen/:id", diff --git a/src/menu-layout.json b/src/menu-layout.json index ac29d7ef0..813e1b621 100644 --- a/src/menu-layout.json +++ b/src/menu-layout.json @@ -3,17 +3,11 @@ "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 14 entries in `removals`, THIRTEEN are waived in `removalsReplacedBy` above. REMOVED 2026-09-02 — `Voorstellen` is no longer in this list. It needed no waiver only because `CaseDetail`'s `case-voorstellen` widget carried `viewAllRoute: /voorstellen`, and gate-53 followed that as its one real navigation edge. The case-detail consolidation dropped that widget, which left the route with no entry point at all — it was the ONLY removal here resting on a single widget rather than on a waiver, so it was the only one that could be orphaned by a layout change. The menu entry is restored rather than waived: naming a replacement surface would have asserted something untrue, since no other surface carries proposals. Parafering is moving onto flows and decidiq under `parafering-to-decidiq` / `approval-routes-are-flows`, and whichever change retires the proposals surface for real should re-remove this entry WITH a waiver that is true at the time. 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: }`, 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 `:` 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. ADDED 2026-09-01 — `BezwaarCommitteesMenu` -> `decidiq:GovernanceBodies`, a cross-app removal whose reduced guarantee gate-53 states plainly, so the review judgement is recorded here to be re-checkable. Measured against decidiq on the running instance: it declares page `GovernanceBodies` (route `/governance-bodies`, type index) and `GovernanceBodyDetail`, behind a live menu entry labelled `Organisation`, with members / evaluations / efficiency / template tabs. dossiq#1531 made dossiq SEND its committees there as GovernanceBody objects; this removal is the other half of that decision — a committee is designed and maintained in decidiq, and dossiq keeps only the seeding and the delegation. The `bezwaaradviescommissie` schema stays because the seed still writes it; what goes is the pretence that dossiq is where you edit one. The instance carries 0 committee rows. NOTE dossiq declares NO manifest dependency on decidiq (deliberately: decidiq is an optional peer and CommitteeDelegationService degrades when it is absent), so nothing in this repo corroborates the claim and gate-53 says so. Do not add a dependency to quieten that warning; it would change runtime semantics to flatter a gate. ADDED 2026-09-01 — `ParafeerroutesMenu` -> `Flows`, a SAME-app removal, so gate-53 verifies it itself. An approval route is a flow now: dossiq#1632 enabled the projection, so the route object is the thing a flow was generated FROM rather than the thing that drives parafering. Leaving the design screen in the menu would invite editing something whose edits do not reach the running flow unless somebody re-runs `occ dossiq:migrate-approval-routes-to-flows`, which would in turn overwrite whatever was authored on the canvas. The pages stay ROUTABLE so a reader can still open a legacy route and see what a flow came from, and so the audit context that names `parafeerrouteId` keeps resolving; what goes is the invitation to edit. Flows are authored at /flows and /flows/:id, on the shared canvas over the same engine. ADDED 2026-09-01 — `Analytics`, `TermijnDashboardMenu` and `ProcessMiningDashboardMenu` -> `Reports`, three SAME-app removals, so gate-53 verifies these itself rather than deferring to this note. They were relocated under an `AnalyticsGroup` foldout until now; ADR-112 makes reports one page of cards instead of a menu branch, on the grounds that a reader looking for a report should find a page listing the reports rather than a submenu they must open to discover what exists. `Reports` is an index of report cards carrying each retired entry as a card, so the destination is the same surface reached one click later, not an approximation." + "removalsCoverageNote": "Of the 8 entries in `removals`, ALL EIGHT are waived in `removalsReplacedBy` above. RESTORED 2026-09-02: `Voorstellen` left this list rather than being deleted. It needed no waiver only because `CaseDetail`'s `case-voorstellen` widget carried `viewAllRoute: /voorstellen`, and gate-53 followed that as its one real navigation edge. The case-detail consolidation dropped that widget, which left the route with no entry point at all. It was the ONLY removal here resting on a single widget rather than on a waiver, so it was the only one a layout change could orphan. The menu entry is restored rather than waived: naming a replacement surface would assert something untrue, because no other surface carries proposals. Parafering is moving onto flows and decidiq under `parafering-to-decidiq` and `approval-routes-are-flows`, and whichever change retires the proposals surface for real should re-remove this entry WITH a waiver that is true at the time. REWRITTEN 2026-09-02, when six entries left this list because their pages were DELETED rather than hidden. `Bezwaren`, `Beroepen`, `Advice` and `Parafeerroutes` no longer exist as pages, so there is no menu entry left to remove and no waiver left to make. `BezwaarBeroepGroup` went with them: its landing page `BezwaarBeroepOverview` was a card grid whose four cards pointed at `Bezwaren`, `Beroepen`, `BezwaarDecisions` and `BezwaarAdviceRequests`, and the last two had already been retired by `case-type-navigation`, so every card on it resolved to nothing. `BesluitvormingAgenda` was dropped as a stale entry: it matched no merged menu entry, which is what gate-53 had been reporting. WHAT THE DELETION PASS TAUGHT, because it decides what may follow. An entry whose page is `type: index` is genuinely replaceable: the page is a list over a register and a schema, so another list over the same register and schema with the same narrowing returns the same rows. `Bezwaren` and `Beroepen` were each `type: index` over register `dossiq` and schema `case` narrowed only by `filter: { caseType: }`, and `Cases` carries the same register, the same schema and the same field through `folderSidebar.filterField: caseType`. Both narrowed on case types that sit under `_caseTypes_disabled` in `lib/Settings/bezwaar_seed_data.json`, so they listed nothing at all, and `tests/e2e/workflows/complaints-bezwaar.spec.ts` had been `describe.fixme` on exactly that ground since procest#675. An entry whose page is `type: custom` is NOT replaceable by that reasoning, and the two survivors here are the proof. A page is custom precisely because the standard types cannot host what it does, so a waiver naming `Cases` covers where the user lands and not what they can do once there. `SubstitutionAdminMenu` waives to `Cases`, and `Cases` carries ONE of that page's five capabilities: `bulkActions` holds a `reassign` entry, while register-on-behalf, revoke, the substitution list and capacity-stamped action inspection have no home on a standard index. The page's own `_note` says as much: \"The standard list type cannot host the on-behalf-of register flow, the action-list inspection, or the bulk-reassign operation over the listed objects.\" `CaseMap` waives to `Cases` on the strength of `viewModes: [table, cards, map]` plus `mapConfig`, which covers the presentation, while the `case-map-overview` spec's rectangle, polygon and wijk/buurt selection scenarios have no counterpart there. So BOTH keep their pages routable, and their entry here hides the menu entry and means nothing more. Do not read a `removalsReplacedBy` target as permission to delete the page. `SubsidiesGroup` -> `Cases`: `case-type-navigation` (commit d6824aa20) replaced the standalone Subsidie nav with case-type children resolved dynamically onto the `Cases` page's `folderSidebar`, on the same index-over-the-same-schema reasoning as the objections pair. `Analytics`, `TermijnDashboardMenu` and `ProcessMiningDashboardMenu` -> `Reports`: three SAME-app removals, so gate-53 verifies these itself. ADR-112 makes reports one page of cards instead of a menu branch, on the grounds that a reader looking for a report should find a page listing the reports rather than a submenu they must open to discover what exists. `Reports` carries each retired entry as a card routing straight at its page, so these three pages ARE the destination of the replacement: deleting them would leave the Reports page with three dead cards. `TenantsMenu` -> `openregister:organisation` is CROSS-APP. 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 stay re-checkable. 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 and JoinOrganisation.vue. 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. `BezwaarCommitteesMenu` -> `decidiq:GovernanceBodies` is the second CROSS-APP one, with the same reduced guarantee, so its judgement is recorded here too. Measured against decidiq on the running instance: it declares page `GovernanceBodies` (route `/governance-bodies`, type index) and `GovernanceBodyDetail`, behind a live menu entry labelled `Organisation`, with members, evaluations, efficiency and template tabs. dossiq#1531 made dossiq SEND its committees there as GovernanceBody objects; this removal is the other half of that decision. A committee is designed and maintained in decidiq, and dossiq keeps only the seeding and the delegation. The `bezwaaradviescommissie` schema stays because the seed still writes it; what goes is the pretence that dossiq is where you edit one. The instance carries 0 committee rows. NOTE dossiq declares NO manifest dependency on decidiq (deliberately: decidiq is an optional peer and CommitteeDelegationService degrades when it is absent), so nothing in this repo corroborates the claim and gate-53 says so. Do not add a dependency to quieten that warning; it would change runtime semantics to flatter a gate." }, "removalsReplacedBy": { - "ParafeerroutesMenu": "Flows", - "BezwaarBeroepGroup": "Cases", - "Bezwaren": "Cases", - "Beroepen": "Cases", "SubsidiesGroup": "Cases", "CaseMap": "Cases", - "Advice": "CaseDetail", - "BesluitvormingAgenda": "decidesk:MeetingDetail", "Analytics": "Reports", "TermijnDashboardMenu": "Reports", "ProcessMiningDashboardMenu": "Reports", @@ -28,14 +22,8 @@ "WorkflowBoard": "WorkGroup" }, "removals": [ - "ParafeerroutesMenu", - "BezwaarBeroepGroup", - "Bezwaren", - "Beroepen", "SubsidiesGroup", "CaseMap", - "Advice", - "BesluitvormingAgenda", "Analytics", "TermijnDashboardMenu", "ProcessMiningDashboardMenu", diff --git a/src/registry.js b/src/registry.js index ff109254e..a57c5222a 100644 --- a/src/registry.js +++ b/src/registry.js @@ -25,7 +25,6 @@ // a pass-through. import BesluitPublicatiePanel from './components/besluitvorming/BesluitPublicatiePanel.vue' -import BezwaarBeroepOverview from './components/bezwaar/BezwaarBeroepOverview.vue' // Case-list CSV/Excel export via the OR export leaf — actions-slot component // on the Cases page (manifest `pages[].actionsComponent`). Builds the OR // export-leaf URL client-side; no dossiq-side serialization (ADR-022). @@ -143,14 +142,6 @@ import { leafTab } from './integrations/leafTabs.js' * @type {Record} */ const registry = { - // --- Bezwaar & Beroep cards-collapse landing page (bezwaar-beroep-cards-collapse). --- - // @spec openspec/changes/bezwaar-beroep-cards-collapse/specs/navigation/spec.md - BezwaarBeroepOverview: { - kind: 'page', - component: BezwaarBeroepOverview, - _note: 'Card-grid landing page replacing the BezwaarBeroepGroup four-leaf nav (ADR-044 cards-collapse). Four former leaves stay routable as deep links.', - }, - // --- Case-list CSV/Excel export via the OR export leaf. --- // @spec openspec/specs/case-list-export-via-or-export-leaf/spec.md CaseListExportAction: { diff --git a/tests/e2e/docs-screenshots.spec.ts b/tests/e2e/docs-screenshots.spec.ts index 19e39c899..d04f2ba0b 100644 --- a/tests/e2e/docs-screenshots.spec.ts +++ b/tests/e2e/docs-screenshots.spec.ts @@ -244,9 +244,10 @@ test.describe('docs: user track', () => { }) test('U5 record-decision', async ({ page }) => { - // docs/tutorials/user/05-record-decision.md — Advice / Decision - // objects don't exist yet; the standalone lists stand in. - await go(page, '/advice') + // docs/tutorials/user/05-record-decision.md — the standalone /advice + // index was retired on 2026-09-02: decision-making moved to decidesk and + // dossiq keeps the per-case view, so the case list stands in. + await go(page, '/cases') await shoot(page, 'user', '05-record-decision-01.png') const hadAdvice = await captureCreateDialog( page, @@ -277,11 +278,10 @@ test.describe('docs: user track', () => { test('U7 handle-objection', async ({ page }) => { // docs/tutorials/user/07-handle-objection.md — the standalone BAC - // (/bezwaar-advice-requests) and beslissing-op-bezwaar - // (/bezwaar-decisions) index pages were retired by - // case-type-navigation; objection handling now lives on the bezwaar - // index and the case's own tabs, so all captures target /bezwaren. - await go(page, '/bezwaren') + // (/bezwaar-advice-requests), beslissing-op-bezwaar (/bezwaar-decisions) + // and objections (/bezwaren) index pages are all retired now; objections + // are cases, so the captures target the case list and its own tabs. + await go(page, '/cases') await shoot(page, 'user', '07-handle-objection-01.png') await shoot(page, 'user', '07-handle-objection-02.png') }) diff --git a/tests/e2e/spec-coverage/bezwaar-family.spec.ts b/tests/e2e/spec-coverage/bezwaar-family.spec.ts index 136ca5c70..f4c97ba5d 100644 --- a/tests/e2e/spec-coverage/bezwaar-family.spec.ts +++ b/tests/e2e/spec-coverage/bezwaar-family.spec.ts @@ -21,32 +21,6 @@ import { expect, test } from '@playwright/test' import { navToRoute, trackDossiqErrors } from '../helpers/nav.ts' -test.describe('Beroepen (appeals) index page', () => { - // @e2e openspec/specs/bezwaar-lifecycle/spec.md#beroepen-index-page-renders-list-shell - test('beroepen index renders the appeals list shell with a create control', async ({ - page, - }) => { - const errors = trackDossiqErrors(page) - // The nav renders "Appeals", not "Beroepen" — navigate by route so this - // does not depend on the current translation of the menu string. - await navToRoute(page, '/beroepen') - // View switcher renders as buttons, not radios. - await expect(page.getByRole('button', { name: 'Cards' })).toBeVisible({ - timeout: 15000, - }) - await expect(page.getByRole('button', { name: 'Table' })).toBeVisible() - // Distinct create control for the appeals surface. - await expect( - page.getByRole('button', { name: /^Add Beroep|^Add Case/ }), - ).toBeVisible() - await expect( - page.getByRole('button', { name: 'Actions' }).first(), - ).toBeVisible() - await expect(page.locator('body')).not.toContainText('Internal Server Error') - expect(errors, errors.join('\n')).toEqual([]) - }) -}) - test.describe('Bezwaaradviescommissies (advisory committees) page', () => { // @e2e openspec/specs/bezwaar-lifecycle/spec.md#bezwaar-committees-settings-page-renders-list-shell test('bezwaar committees page renders its own create control', async ({ diff --git a/tests/e2e/spec-coverage/ui-pages.spec.ts b/tests/e2e/spec-coverage/ui-pages.spec.ts index 791879df9..f8dd9782b 100644 --- a/tests/e2e/spec-coverage/ui-pages.spec.ts +++ b/tests/e2e/spec-coverage/ui-pages.spec.ts @@ -133,32 +133,3 @@ test.describe('Doorlooptijd page render', () => { await expect(page.locator('body')).not.toContainText('Internal Server Error') }) }) - -test.describe('Bezwaren index page render', () => { - // @e2e openspec/specs/bezwaar-lifecycle/spec.md#bezwaren-index-page-renders-list-shell - test('bezwaren index renders list shell', async ({ page }) => { - // The nav renders "Objections", not "Bezwaren" — navigate by route. - await navToRoute(page, '/bezwaren') - await expect(page.getByRole('button', { name: 'Cards' })).toBeVisible({ - timeout: 15000, - }) - await expect(page.getByRole('button', { name: 'Table' })).toBeVisible() - await expect(page.getByRole('button', { name: /^Add / })).toBeVisible() - await expect(page.locator('body')).not.toContainText('Internal Server Error') - }) -}) - -test.describe('Advice index page render', () => { - // @e2e openspec/specs/advice-management/spec.md#advice-index-page-renders-list-shell - test('advice index renders list shell', async ({ page }) => { - // The Decision-making group's leaves are absent from this build's - // sidebar, so there is no "Advice" nav entry — navigate by route. - await navToRoute(page, '/advice') - await expect(page.getByRole('button', { name: 'Cards' })).toBeVisible({ - timeout: 15000, - }) - await expect(page.getByRole('button', { name: 'Table' })).toBeVisible() - await expect(page.getByRole('button', { name: /^Add / })).toBeVisible() - await expect(page.locator('body')).not.toContainText('Internal Server Error') - }) -}) diff --git a/tests/e2e/workflows/complaints-bezwaar.spec.ts b/tests/e2e/workflows/complaints-bezwaar.spec.ts index 4f65599a4..0f017c804 100644 --- a/tests/e2e/workflows/complaints-bezwaar.spec.ts +++ b/tests/e2e/workflows/complaints-bezwaar.spec.ts @@ -46,13 +46,17 @@ let caseTypeId: string let caseTypeSeeded = false let caseId: string -// BLOCKED on procest#675 — the Bezwaren index page filters cases by the retired -// bezwaar caseType (b3c1a000-…-be2a, now under `_caseTypes_disabled` in -// bezwaar_seed_data.json), while these specs seed `bezwaar`-schema objects that -// the case-based page never shows. The complaint model is mid-migration to the -// unified-case `citizen-complaint` caseType (ADR-044); until it settles, this -// describe cannot pass on any matched instance. Flip back to `test.describe` -// once the manifest filter + fixtures target the canonical caseType. +// BLOCKED on procest#675. These specs seed `objectionProceeding` objects while +// the list they assert against renders `case` objects, so the seeded row can +// never appear. The complaint model is mid-migration to the unified-case +// `citizen-complaint` caseType (ADR-044); until it settles, this describe cannot +// pass on any matched instance. Flip back to `test.describe` once the fixtures +// seed a case of the canonical caseType. +// +// The Bezwaren index page these specs used to drive was RETIRED on 2026-09-02, +// not hidden: it filtered `case` on the disabled bezwaar caseType +// (b3c1a000-…-be2a, under `_caseTypes_disabled` in bezwaar_seed_data.json) and +// so listed nothing at all. Objections are cases, so the list is Cases now. test.describe.fixme('Complaint-family workflow — bezwaren (objections)', () => { test.describe.configure({ mode: 'serial' }) @@ -90,17 +94,13 @@ test.describe.fixme('Complaint-family workflow — bezwaren (objections)', () => } /** - * Open the Bezwaren list via the sidebar and wait for its rows to load. + * Open the case list and wait for its rows to load. * @param page The page. */ async function openBezwaren(page: Page): Promise { - // The "Bezwaren" sidebar entry was retired in the nav-dedup pass - // (menu-layout.json `removals`), but its index page stays routable for - // deep-links and e2e. navTo(page,'Bezwaren') therefore matches no nav link - // and strands on the Dashboard — reach the list by a BARE deep-link instead - // (a /index.php-prefixed one resets the history-mode router to the - // Dashboard; the bare path resolves the /bezwaren route directly). - await page.goto('/index.php/apps/dossiq/bezwaren') + // Objections are cases, and the standalone /bezwaren index is retired, so + // the list to drive is Cases. + await page.goto('/index.php/apps/dossiq/cases') await dismissSupportDialog(page) await expect(page.locator('tbody tr').first()).toBeVisible({ timeout: 15000,