diff --git a/docs/features/README.md b/docs/Features/README.md similarity index 93% rename from docs/features/README.md rename to docs/Features/README.md index 823e5dc0e..ea7091809 100644 --- a/docs/features/README.md +++ b/docs/Features/README.md @@ -1,6 +1,6 @@ -# Procest — Feature Overview +# Procest: Feature Overview -Procest is a Nextcloud case management app (zaaksysteem) for Dutch municipalities, covering general case handling (zaakgericht werken), VTH permits/supervision/enforcement, objection and appeal workflows, B&W decision-making, and workflow automation. All data is stored in OpenRegister — Procest owns no database tables. +Procest is a Nextcloud case management app (zaaksysteem) for Dutch municipalities, covering general case handling (zaakgericht werken), VTH permits/supervision/enforcement, objection and appeal workflows, B&W decision-making, and workflow automation. All data is stored in OpenRegister: Procest owns no database tables. ## Standards Compliance @@ -20,13 +20,13 @@ Procest is a Nextcloud case management app (zaaksysteem) for Dutch municipalitie | ZGW Besluiten API (BRC) | [zaakgerichtwerken.nl](https://zaakgerichtwerken.nl) | Implemented | | ZGW Autorisaties API (AC) | [zaakgerichtwerken.nl](https://zaakgerichtwerken.nl) | Implemented | | ZGW Notificaties API (NRC) | [zaakgerichtwerken.nl](https://zaakgerichtwerken.nl) | Implemented | -| TEC BPM RFP Template — Process Modeling | Sections 1.1–1.11 | Partial | -| TEC BPM RFP Template — Security Management | Sections 2.1–2.5 | Partial | -| TEC BPM RFP Template — Workflow Portal | Sections 5.1–5.6 | Partial | -| TEC BPM RFP Template — Monitoring & Management | Sections 6.1–6.6 | Partial | +| TEC BPM RFP Template: Process Modeling | Sections 1.1–1.11 | Partial | +| TEC BPM RFP Template: Security Management | Sections 2.1–2.5 | Partial | +| TEC BPM RFP Template: Workflow Portal | Sections 5.1–5.6 | Partial | +| TEC BPM RFP Template: Monitoring & Management | Sections 6.1–6.6 | Partial | | CMMN 1.1 (OMG) | Case Plan Model, HumanTask, Milestone | Partial | -| Forum Standaardisatie — REST-API Design Rules | [forumstandaardisatie.nl](https://forumstandaardisatie.nl/open-standaarden/rest-api-design-rules) | Implemented | -| Forum Standaardisatie — NL GOV CloudEvents | [forumstandaardisatie.nl](https://forumstandaardisatie.nl/open-standaarden/nl-gov-cloudevents) | Planned | +| Forum Standaardisatie: REST-API Design Rules | [forumstandaardisatie.nl](https://forumstandaardisatie.nl/open-standaarden/rest-api-design-rules) | Implemented | +| Forum Standaardisatie: NL GOV CloudEvents | [forumstandaardisatie.nl](https://forumstandaardisatie.nl/open-standaarden/nl-gov-cloudevents) | Planned | | Awb (Algemene wet bestuursrecht) | Processing deadlines, bezwaar/beroep | Implemented | | Woo (Wet open overheid) | 4-week response mandate, redaction | Planned | | DSO Omgevingsloket | VTH permit intake integration | Planned | @@ -47,7 +47,7 @@ Procest is a Nextcloud case management app (zaaksysteem) for Dutch municipalitie | Werkvoorraad | Team-level queue of unassigned cases available for claiming | TEC BPM 5.1, GEMMA Zaakafhandel | Planned | [werkvoorraad.md](werkvoorraad.md) | | Administration | Nextcloud admin panel for schema configuration, ZGW mapping, and seed data import | Nextcloud OCP | Implemented | [administration.md](administration.md) | | Admin Settings | Configuration page for register/schema UUID mappings and version information | Nextcloud OCP | Implemented | [admin-settings.md](admin-settings.md) | -| OpenRegister Integration | All data stored as OpenRegister objects — Procest owns no database tables | OpenRegister API | Implemented | [openregister-integration.md](openregister-integration.md) | +| OpenRegister Integration | All data stored as OpenRegister objects: Procest owns no database tables | OpenRegister API | Implemented | [openregister-integration.md](openregister-integration.md) | | Base Register Seed Data | Pre-configured case types (Bezwaar, Vergunning, Melding, VTH) imported on install | GEMMA | Implemented | [base-register-seed-data.md](base-register-seed-data.md) | | Workflow Engine | Zero-code visual workflow builder with status nodes, guards, and automatic actions | TEC BPM 1.1–1.6, BPMN 2.0 | Implemented | [workflow-engine-enhancement.md](workflow-engine-enhancement.md) | | VTH Module | Permits, supervision, and enforcement case types and domain schemas | GEMMA VTH, DSO Omgevingsloket | Partial | [vth-module.md](vth-module.md) | @@ -61,7 +61,7 @@ Procest is a Nextcloud case management app (zaaksysteem) for Dutch municipalitie | Case Dashboard View | Comprehensive case detail page with status timeline, panels, tasks, documents, and audit trail | CMMN, ZGW | Implemented | [case-dashboard-view.md](case-dashboard-view.md) | | GIS Integration | Map view for cases, location picker, PDOK/WMS/WFS overlay, and secure GIS proxy | BAG, BRK, PDOK | Implemented | [gis-integration.md](gis-integration.md) | | Milestone Tracking | Key progress checkpoints per case with target dates, overdue alerts, and visual timeline | CMMN Milestone, TEC BPM 6.3 | Planned | [milestone-tracking.md](milestone-tracking.md) | -| ZGW APIs | Full ZGW API suite: ZRC, ZTC, DRC, BRC, AC, NRC — VNG Newman test suite compliance | ZGW 1.x, VNG | Implemented | [zgw-apis.md](zgw-apis.md) | +| ZGW APIs | Full ZGW API suite: ZRC, ZTC, DRC, BRC, AC, NRC: VNG Newman test suite compliance | ZGW 1.x, VNG | Implemented | [zgw-apis.md](zgw-apis.md) | | Zaak Intake Flow | Structured intake form with case type selection, auto-numbering, and deadline calculation | ZGW ZRC, DSO | Planned | [zaak-intake-flow.md](zaak-intake-flow.md) | | Complaint Management | AWB-compliant klachtenprocedure with hearings, deadlines, and ombudsman escalation | Awb Hoofdstuk 9, GEMMA | Planned | [complaint-management.md](complaint-management.md) | | Consultation Management | Public participation (inspraak) with response collection and nota van beantwoording | Omgevingswet, Awb | Planned | [consultation-management.md](consultation-management.md) | diff --git a/docs/Features/_category_.json b/docs/Features/_category_.json new file mode 100644 index 000000000..53126e367 --- /dev/null +++ b/docs/Features/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Features", + "position": 3, + "collapsible": true, + "collapsed": true +} diff --git a/docs/features/admin-settings.md b/docs/Features/admin-settings.md similarity index 100% rename from docs/features/admin-settings.md rename to docs/Features/admin-settings.md diff --git a/docs/features/administration.md b/docs/Features/administration.md similarity index 81% rename from docs/features/administration.md rename to docs/Features/administration.md index 865626a4a..13ec0ce0a 100644 --- a/docs/features/administration.md +++ b/docs/Features/administration.md @@ -36,7 +36,7 @@ One case type can be marked as the default, pre-selected when creating new cases Transition a case type from draft to published state, making it available for case creation. Validates completeness before publishing. -### Planned (V1) — Admin Tabs +### Planned (V1): Admin Tabs Additional case type configuration tabs: @@ -47,23 +47,23 @@ Additional case type configuration tabs: ### OpenRegister Integration (MVP) -Procest owns no database tables — all data is stored as OpenRegister objects in the `procest` register with 12 schemas: +Procest owns no database tables: all data is stored as OpenRegister objects in the `procest` register with 12 schemas: **Configuration schemas (admin-managed):** -- `caseType` — Case behavior configuration -- `statusType` — Allowed statuses per case type -- `resultType` — Outcome types with archival rules -- `roleType` — Participant role definitions -- `propertyDefinition` — Custom field definitions -- `documentType` — Required document types -- `decisionType` — Decision type definitions +- `caseType`: Case behavior configuration +- `statusType`: Allowed statuses per case type +- `resultType`: Outcome types with archival rules +- `roleType`: Participant role definitions +- `propertyDefinition`: Custom field definitions +- `documentType`: Required document types +- `decisionType`: Decision type definitions **Instance schemas (user-created):** -- `case` — Case records -- `task` — Task work items -- `role` — Participant assignments -- `result` — Case outcomes -- `decision` — Formal decisions +- `case`: Case records +- `task`: Task work items +- `role`: Participant assignments +- `result`: Case outcomes +- `decision`: Formal decisions ### Auto-Configuration on Install (MVP) diff --git a/docs/features/ai-assisted-processing.md b/docs/Features/ai-assisted-processing.md similarity index 100% rename from docs/features/ai-assisted-processing.md rename to docs/Features/ai-assisted-processing.md diff --git a/docs/Features/app-scaffold.md b/docs/Features/app-scaffold.md new file mode 100644 index 000000000..ee68b1c9d --- /dev/null +++ b/docs/Features/app-scaffold.md @@ -0,0 +1,23 @@ +# App Scaffold + +Procest application foundation: Nextcloud PHP app boilerplate, Webpack/Vue 2 build system, OpenRegister integration wiring, and initial register configuration. + +## Overview + +The app scaffold establishes the technical foundation for the Procest Nextcloud app: + +- **PHP app skeleton**: AppInfo, Application class, DI container wiring +- **Vue 2 frontend**: Webpack build, Pinia state management, Vue Router +- **OpenRegister wiring**: `ConfigurationService::importFromApp()` repair step, `procest_register.json` with 12 initial schemas +- **Object store pattern**: Pinia stores per entity type, OpenRegister API calls from frontend +- **Nextcloud integration**: Admin panel settings, navigation, sidebar + +## Archive Changes + +This feature consolidates: +- `create-procest-app`: initial app registration and boilerplate +- `procest-app-scaffold`: build system, Webpack/Vue setup +- `procest-object-store`: Pinia store foundation per entity +- `procest-case-management`: core case CRUD scaffolding + +See [administration.md](administration.md) and [case-management.md](case-management.md) for functional details. diff --git a/docs/features/appointment-scheduling.md b/docs/Features/appointment-scheduling.md similarity index 100% rename from docs/features/appointment-scheduling.md rename to docs/Features/appointment-scheduling.md diff --git a/docs/features/base-register-seed-data.md b/docs/Features/base-register-seed-data.md similarity index 100% rename from docs/features/base-register-seed-data.md rename to docs/Features/base-register-seed-data.md diff --git a/docs/features/besluitvorming-workflow.md b/docs/Features/besluitvorming-workflow.md similarity index 68% rename from docs/features/besluitvorming-workflow.md rename to docs/Features/besluitvorming-workflow.md index 6dee64f0a..04dc4005f 100644 --- a/docs/features/besluitvorming-workflow.md +++ b/docs/Features/besluitvorming-workflow.md @@ -6,22 +6,22 @@ ## Overview -Implements the B&W (Board & Aldermen — College van Burgemeester en Wethouders) decision-making workflow for Dutch municipal case management. Provides a structured parafering (initialling/sign-off) chain for proposals (`voorstellen`) that require formal decision-making. +Implements the B&W (Board & Aldermen: College van Burgemeester en Wethouders) decision-making workflow for Dutch municipal case management. Provides a structured parafering (initialling/sign-off) chain for proposals (`voorstellen`) that require formal decision-making. ## Architecture ### Backend - **New schemas** in `lib/Settings/procest_register.json`: - - `voorstel` — the proposal document awaiting B&W decision - - `parafeerroute` — a named sign-off chain with ordered steps - - `parafeeractie` — an individual action taken by a paraferent + - `voorstel`: the proposal document awaiting B&W decision + - `parafeerroute`: a named sign-off chain with ordered steps + - `parafeeractie`: an individual action taken by a paraferent - **New service:** `lib/Service/ParaferingNotificationService.php` - Sends Nextcloud notifications for workflow events: - - `notifyStepActivated` — notify the actor when their step becomes active - - `notifyVoorstelReturned` — notify the steller when a proposal is returned - - `notifyParaferingReminder` — send overdue reminders + - `notifyStepActivated`: notify the actor when their step becomes active + - `notifyVoorstelReturned`: notify the steller when a proposal is returned + - `notifyParaferingReminder`: send overdue reminders - **Updated:** `lib/Service/SettingsService.php` - New config keys: `voorstel_schema`, `parafeerroute_schema`, `parafeeractie_schema` diff --git a/docs/features/bezwaar-beroep-workflow.md b/docs/Features/bezwaar-beroep-workflow.md similarity index 82% rename from docs/features/bezwaar-beroep-workflow.md rename to docs/Features/bezwaar-beroep-workflow.md index b5ac6a0c1..d5c495715 100644 --- a/docs/features/bezwaar-beroep-workflow.md +++ b/docs/Features/bezwaar-beroep-workflow.md @@ -22,7 +22,7 @@ Implements AWB-compliant (Algemene wet bestuursrecht) bezwaar (objection) and be - `IRepairStep` executed during app installation or upgrade - Delegates to `SeedDataService::seedBezwaarBeroepData()` - Skips if OpenRegister is not available (`SettingsService::isOpenRegisterAvailable`) -- Exceptions are caught and logged — never propagated +- Exceptions are caught and logged: never propagated **`lib/Settings/bezwaar_seed_data.json`** - Pre-defined case types: `bezwaar` and `beroep` @@ -47,5 +47,5 @@ Implements AWB-compliant (Algemene wet bestuursrecht) bezwaar (objection) and be ## Testing Unit tests are in: -- `tests/Unit/Service/SeedDataServiceTest.php` — ObjectService unavailable → failure, missing config → failure, happy path summary structure, idempotency (existing → skipped), seed data file integrity -- `tests/Unit/Repair/SeedBezwaarBeroepDataTest.php` — getName, skip when OpenRegister unavailable, call seed service, info output on success, exception handling +- `tests/Unit/Service/SeedDataServiceTest.php`: ObjectService unavailable → failure, missing config → failure, happy path summary structure, idempotency (existing → skipped), seed data file integrity +- `tests/Unit/Repair/SeedBezwaarBeroepDataTest.php`: getName, skip when OpenRegister unavailable, call seed service, info output on success, exception handling diff --git a/docs/features/bw-parafering.md b/docs/Features/bw-parafering.md similarity index 100% rename from docs/features/bw-parafering.md rename to docs/Features/bw-parafering.md diff --git a/docs/features/case-dashboard-view.md b/docs/Features/case-dashboard-view.md similarity index 100% rename from docs/features/case-dashboard-view.md rename to docs/Features/case-dashboard-view.md diff --git a/docs/features/case-definition-portability.md b/docs/Features/case-definition-portability.md similarity index 100% rename from docs/features/case-definition-portability.md rename to docs/Features/case-definition-portability.md diff --git a/docs/features/case-email-integration.md b/docs/Features/case-email-integration.md similarity index 100% rename from docs/features/case-email-integration.md rename to docs/Features/case-email-integration.md diff --git a/docs/features/case-management.md b/docs/Features/case-management.md similarity index 100% rename from docs/features/case-management.md rename to docs/Features/case-management.md diff --git a/docs/features/case-sharing-collaboration.md b/docs/Features/case-sharing-collaboration.md similarity index 100% rename from docs/features/case-sharing-collaboration.md rename to docs/Features/case-sharing-collaboration.md diff --git a/docs/features/case-types.md b/docs/Features/case-types.md similarity index 100% rename from docs/features/case-types.md rename to docs/Features/case-types.md diff --git a/docs/features/complaint-management.md b/docs/Features/complaint-management.md similarity index 100% rename from docs/features/complaint-management.md rename to docs/Features/complaint-management.md diff --git a/docs/features/consultation-management.md b/docs/Features/consultation-management.md similarity index 100% rename from docs/features/consultation-management.md rename to docs/Features/consultation-management.md diff --git a/docs/features/dashboard.md b/docs/Features/dashboard.md similarity index 100% rename from docs/features/dashboard.md rename to docs/Features/dashboard.md diff --git a/docs/features/deelzaak-support.md b/docs/Features/deelzaak-support.md similarity index 95% rename from docs/features/deelzaak-support.md rename to docs/Features/deelzaak-support.md index 6aa0c969e..87d541ad1 100644 --- a/docs/features/deelzaak-support.md +++ b/docs/Features/deelzaak-support.md @@ -5,7 +5,7 @@ ## Overview -Adds hierarchical case support (deelzaken) enabling a parent case to spawn child cases for parallel departmental processing. For example, an Omgevingsvergunning parent case can spawn separate sub-cases for building assessment, environmental impact, and fire safety — each with their own lifecycle, assignees, and deadlines. +Adds hierarchical case support (deelzaken) enabling a parent case to spawn child cases for parallel departmental processing. For example, an Omgevingsvergunning parent case can spawn separate sub-cases for building assessment, environmental impact, and fire safety: each with their own lifecycle, assignees, and deadlines. ## Capabilities diff --git a/docs/features/doorlooptijd-dashboard.md b/docs/Features/doorlooptijd-dashboard.md similarity index 54% rename from docs/features/doorlooptijd-dashboard.md rename to docs/Features/doorlooptijd-dashboard.md index cc2e7da7a..a2ec9d416 100644 --- a/docs/features/doorlooptijd-dashboard.md +++ b/docs/Features/doorlooptijd-dashboard.md @@ -9,16 +9,16 @@ Adds a dedicated Doorlooptijd (processing time) analytics view to the Procest da ## Features -- **SLA compliance rate widget** — Percentage of cases completed within their `processingDeadline`, broken down by case type -- **Processing time distribution chart** — Histogram of actual vs. allowed processing days per case type -- **Trend line chart** — Monthly SLA compliance rate over the last 12 months (ApexCharts) -- **At-risk cases panel** — Open cases where remaining time is less than 25% of the allowed processing deadline -- **Average processing time table** — Per-case-type performance table with SLA target comparison -- **Dashboard KPI card** — Summary SLA compliance card added to the main dashboard KPI row +- **SLA compliance rate widget**: Percentage of cases completed within their `processingDeadline`, broken down by case type +- **Processing time distribution chart**: Histogram of actual vs. allowed processing days per case type +- **Trend line chart**: Monthly SLA compliance rate over the last 12 months (ApexCharts) +- **At-risk cases panel**: Open cases where remaining time is less than 25% of the allowed processing deadline +- **Average processing time table**: Per-case-type performance table with SLA target comparison +- **Dashboard KPI card**: Summary SLA compliance card added to the main dashboard KPI row ## Data Sources -All data derived from existing case fields — no schema changes required: +All data derived from existing case fields: no schema changes required: - `case.startDate`, `case.endDate`, `case.deadline`, `case.plannedEndDate`, `case.status`, `case.caseType` - `caseType.processingDeadline` - `statusType.isFinal` diff --git a/docs/features/gis-integration.md b/docs/Features/gis-integration.md similarity index 78% rename from docs/features/gis-integration.md rename to docs/Features/gis-integration.md index 114b1ceb9..07606aed3 100644 --- a/docs/features/gis-integration.md +++ b/docs/Features/gis-integration.md @@ -23,11 +23,11 @@ Two new PHP classes handle secure GIS data proxying: - XML-to-JSON conversion via SimpleXML **`lib/Controller/GisProxyController`** -- `proxy()` endpoint — forwards WMS/WFS requests, returns `JSONResponse` -- `capabilities()` endpoint — fetches and parses GetCapabilities from a service URL +- `proxy()` endpoint: forwards WMS/WFS requests, returns `JSONResponse` +- `capabilities()` endpoint: fetches and parses GetCapabilities from a service URL - Error codes: 400 (missing URL), 403 (URL blocked), 429 (rate limited), 502 (upstream error) -**`lib/Service/SettingsService`** — new config keys: `map_layer_schema` +**`lib/Service/SettingsService`**: new config keys: `map_layer_schema` ### Frontend @@ -44,5 +44,5 @@ All external GIS requests are proxied through Nextcloud to avoid CORS issues and ## Testing Unit tests are in: -- `tests/Unit/Service/GisProxyServiceTest.php` — URL allowlist validation, cache hit returns, rate limiting -- `tests/Unit/Controller/GisProxyControllerTest.php` — HTTP status codes for success/403/429/502, missing URL → 400 +- `tests/Unit/Service/GisProxyServiceTest.php`: URL allowlist validation, cache hit returns, rate limiting +- `tests/Unit/Controller/GisProxyControllerTest.php`: HTTP status codes for success/403/429/502, missing URL → 400 diff --git a/docs/features/legesberekening.md b/docs/Features/legesberekening.md similarity index 100% rename from docs/features/legesberekening.md rename to docs/Features/legesberekening.md diff --git a/docs/features/mijn-overheid-integration.md b/docs/Features/mijn-overheid-integration.md similarity index 100% rename from docs/features/mijn-overheid-integration.md rename to docs/Features/mijn-overheid-integration.md diff --git a/docs/features/milestone-tracking.md b/docs/Features/milestone-tracking.md similarity index 100% rename from docs/features/milestone-tracking.md rename to docs/Features/milestone-tracking.md diff --git a/docs/features/mobiel-inspectie.md b/docs/Features/mobiel-inspectie.md similarity index 100% rename from docs/features/mobiel-inspectie.md rename to docs/Features/mobiel-inspectie.md diff --git a/docs/features/multi-tenant-saas.md b/docs/Features/multi-tenant-saas.md similarity index 100% rename from docs/features/multi-tenant-saas.md rename to docs/Features/multi-tenant-saas.md diff --git a/docs/features/my-work.md b/docs/Features/my-work.md similarity index 100% rename from docs/features/my-work.md rename to docs/Features/my-work.md diff --git a/docs/features/openregister-integration.md b/docs/Features/openregister-integration.md similarity index 100% rename from docs/features/openregister-integration.md rename to docs/Features/openregister-integration.md diff --git a/docs/features/prometheus-metrics.md b/docs/Features/prometheus-metrics.md similarity index 100% rename from docs/features/prometheus-metrics.md rename to docs/Features/prometheus-metrics.md diff --git a/docs/features/register-i18n.md b/docs/Features/register-i18n.md similarity index 100% rename from docs/features/register-i18n.md rename to docs/Features/register-i18n.md diff --git a/docs/features/roles-decisions.md b/docs/Features/roles-decisions.md similarity index 100% rename from docs/features/roles-decisions.md rename to docs/Features/roles-decisions.md diff --git a/docs/features/signalering-widgets.md b/docs/Features/signalering-widgets.md similarity index 100% rename from docs/features/signalering-widgets.md rename to docs/Features/signalering-widgets.md diff --git a/docs/features/start-case-widget.md b/docs/Features/start-case-widget.md similarity index 100% rename from docs/features/start-case-widget.md rename to docs/Features/start-case-widget.md diff --git a/docs/features/stuf-support.md b/docs/Features/stuf-support.md similarity index 100% rename from docs/features/stuf-support.md rename to docs/Features/stuf-support.md diff --git a/docs/features/task-management.md b/docs/Features/task-management.md similarity index 100% rename from docs/features/task-management.md rename to docs/Features/task-management.md diff --git a/docs/features/vth-module.md b/docs/Features/vth-module.md similarity index 100% rename from docs/features/vth-module.md rename to docs/Features/vth-module.md diff --git a/docs/features/vth-workflow-configuration.md b/docs/Features/vth-workflow-configuration.md similarity index 55% rename from docs/features/vth-workflow-configuration.md rename to docs/Features/vth-workflow-configuration.md index bdb2486fb..d76af76e3 100644 --- a/docs/features/vth-workflow-configuration.md +++ b/docs/Features/vth-workflow-configuration.md @@ -6,7 +6,7 @@ ## Overview -Configures the Procest workflow engine for VTH (Vergunningen, Toezicht, Handhaving — Permits, Supervision, Enforcement), adding domain-specific schemas, seed data, LHS matrix support, and UI panels for Dutch environmental compliance workflows. +Configures the Procest workflow engine for VTH (Vergunningen, Toezicht, Handhaving: Permits, Supervision, Enforcement), adding domain-specific schemas, seed data, LHS matrix support, and UI panels for Dutch environmental compliance workflows. ## Architecture @@ -21,15 +21,15 @@ Configures the Procest workflow engine for VTH (Vergunningen, Toezicht, Handhavi | `adviesAanvraag` | Advice request to internal/external advisors | **New config keys** in `SettingsService`: -- `inspectie_checklist_schema` — UUID of inspectieChecklist schema -- `inspectie_rapport_schema` — UUID of inspectieRapport schema -- `handhavingsactie_schema` — UUID of handhavingsactie schema -- `advies_aanvraag_schema` — UUID of adviesAanvraag schema -- `lhsMatrix` — JSON string of the 4×4 Landelijke Handhavingsstrategie matrix +- `inspectie_checklist_schema`: UUID of inspectieChecklist schema +- `inspectie_rapport_schema`: UUID of inspectieRapport schema +- `handhavingsactie_schema`: UUID of handhavingsactie schema +- `advies_aanvraag_schema`: UUID of adviesAanvraag schema +- `lhsMatrix`: JSON string of the 4×4 Landelijke Handhavingsstrategie matrix **Seed data:** -- `lib/Settings/vth_seed_data.json` — 6 VTH case types (Omgevingsvergunning Regulier/Uitgebreid, Sloopmelding, Toezichtzaak Bouw/Milieu, Handhavingszaak) -- `lib/Settings/vth-templates/` — 6 JSON template files, one per case type +- `lib/Settings/vth_seed_data.json`: 6 VTH case types (Omgevingsvergunning Regulier/Uitgebreid, Sloopmelding, Toezichtzaak Bouw/Milieu, Handhavingszaak) +- `lib/Settings/vth-templates/`: 6 JSON template files, one per case type ### LHS Matrix @@ -45,5 +45,5 @@ The Landelijke Handhavingsstrategie (LHS) provides a standard 4×4 enforcement r ## Testing Unit tests are in: -- `tests/Unit/Service/VthSettingsServiceTest.php` — VTH config keys in getSettings(), updateSettings() persists VTH keys, lhsMatrix readable, core keys not overridden -- `tests/Unit/Settings/VthSchemaTest.php` — all 4 VTH schemas registered, vth-templates dir exists, template files are valid JSON, expected files present, vth_seed_data.json valid +- `tests/Unit/Service/VthSettingsServiceTest.php`: VTH config keys in getSettings(), updateSettings() persists VTH keys, lhsMatrix readable, core keys not overridden +- `tests/Unit/Settings/VthSchemaTest.php`: all 4 VTH schemas registered, vth-templates dir exists, template files are valid JSON, expected files present, vth_seed_data.json valid diff --git a/docs/features/werkvoorraad.md b/docs/Features/werkvoorraad.md similarity index 100% rename from docs/features/werkvoorraad.md rename to docs/Features/werkvoorraad.md diff --git a/docs/features/woo-case-type.md b/docs/Features/woo-case-type.md similarity index 100% rename from docs/features/woo-case-type.md rename to docs/Features/woo-case-type.md diff --git a/docs/features/workflow-engine-enhancement.md b/docs/Features/workflow-engine-enhancement.md similarity index 90% rename from docs/features/workflow-engine-enhancement.md rename to docs/Features/workflow-engine-enhancement.md index b3eff40e4..1ebb64d08 100644 --- a/docs/features/workflow-engine-enhancement.md +++ b/docs/Features/workflow-engine-enhancement.md @@ -30,10 +30,10 @@ Adds a zero-code visual workflow builder that allows administrators to define pr - Pan/zoom via CSS transform - **Configuration Panels:** - - `StepConfigPanel.vue` — checklist editor, guard configuration - - `TransitionConfigPanel.vue` — action configuration per transition + - `StepConfigPanel.vue`: checklist editor, guard configuration + - `TransitionConfigPanel.vue`: action configuration per transition -- **Case Detail Integration:** `WorkflowTransitions.vue` — shows available transitions filtered by role/guards +- **Case Detail Integration:** `WorkflowTransitions.vue`: shows available transitions filtered by role/guards ## Guards diff --git a/docs/features/zaak-intake-flow.md b/docs/Features/zaak-intake-flow.md similarity index 100% rename from docs/features/zaak-intake-flow.md rename to docs/Features/zaak-intake-flow.md diff --git a/docs/features/zaaktype-configuratie.md b/docs/Features/zaaktype-configuratie.md similarity index 100% rename from docs/features/zaaktype-configuratie.md rename to docs/Features/zaaktype-configuratie.md diff --git a/docs/features/zgw-apis.md b/docs/Features/zgw-apis.md similarity index 90% rename from docs/features/zgw-apis.md rename to docs/Features/zgw-apis.md index 522f3198d..9fc8fc0d5 100644 --- a/docs/features/zgw-apis.md +++ b/docs/Features/zgw-apis.md @@ -24,7 +24,7 @@ Manages API client (applicatie) registration and authorization: ## Documenten API (DRC) Full document management with binary file I/O: -- `enkelvoudiginformatieobject` — document metadata + file content +- `enkelvoudiginformatieobject`: document metadata + file content - Binary upload via `inhoud` field (base64 or multipart) - File content stored in Nextcloud filesystem - Linked to cases via `zaakinformatieobject` resources @@ -55,14 +55,14 @@ VNG ZGW business rules compliance (tracked against the 353-assertion Newman test ## Newman Test Suite Automated ZGW compliance testing via VNG Postman collections: -- **ZGW OAS tests** — validates all 6 ZGW APIs against their OpenAPI specs -- **ZGW business rules** — validates business logic, edge cases, and authorization +- **ZGW OAS tests**: validates all 6 ZGW APIs against their OpenAPI specs +- **ZGW business rules**: validates business logic, edge cases, and authorization - Newman runs locally and in CI via `make test:zgw` - Test environment configuration in `data/newman-environment.json` ## Standards References -- [ZGW API standaard — zaakgrichtwerken.nl](https://zaakgerichtwerken.nl) +- [ZGW API standaard: zaakgrichtwerken.nl](https://zaakgerichtwerken.nl) - [VNG Realisatie ZGW GitHub](https://github.com/VNG-Realisatie/gemma-zaken) - [ZRC 1.x OAS](https://vng-realisatie.github.io/gemma-zaken/standaard/zaken/index) - [DRC 1.x OAS](https://vng-realisatie.github.io/gemma-zaken/standaard/documenten/index) diff --git a/docs/Integrations/_category_.json b/docs/Integrations/_category_.json new file mode 100644 index 000000000..73ff44d2a --- /dev/null +++ b/docs/Integrations/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Integrations", + "position": 5, + "collapsible": true, + "collapsed": true +} diff --git a/docs/Integrations/index.md b/docs/Integrations/index.md new file mode 100644 index 000000000..cfd193f59 --- /dev/null +++ b/docs/Integrations/index.md @@ -0,0 +1,9 @@ +--- +draft: true +title: Integrations +sidebar_position: 1 +--- + +# Integrations + +Integration guides for connecting Procest with external systems are being authored. Content authoring for this section is tracked in [issue #440](https://github.com/ConductionNL/procest/issues/440). diff --git a/docs/Technical/_category_.json b/docs/Technical/_category_.json new file mode 100644 index 000000000..1c027a4e1 --- /dev/null +++ b/docs/Technical/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Technical", + "position": 6, + "collapsible": true, + "collapsed": true +} diff --git a/docs/ARCHITECTURE.md b/docs/Technical/architecture.md similarity index 75% rename from docs/ARCHITECTURE.md rename to docs/Technical/architecture.md index 9143ef331..381a19623 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/Technical/architecture.md @@ -1,4 +1,4 @@ -# Procest — Architecture & Data Model +# Procest: Architecture & Data Model ## 1. Overview @@ -38,14 +38,14 @@ Procest owns **no database tables**. All data is stored as OpenRegister objects, | Standard | Type | Coverage | Maturity | Relevance | |----------|------|----------|----------|-----------| -| **CMMN 1.1** | International (OMG) | Case plans, tasks, milestones, sentries, case file items | Mature | **HIGH** — designed for case management | -| **BPMN 2.0** | International (OMG) | Processes, tasks, gateways, events | Very mature, widely adopted | **HIGH** — task/workflow modeling | -| **DMN 1.x** | International (OMG) | Decision tables, decision logic | Mature, growing | **MEDIUM** — decision modeling | -| **Schema.org** | International (W3C) | Action, Project, GovernmentService, Role | Very mature | **MEDIUM** — semantic vocabulary | -| **Dublin Core (ISO 15836)** | International | 15 metadata elements for documents | Very mature | **LOW** — document metadata | -| **ZGW APIs (VNG)** | Dutch gov | Zaak, Status, Resultaat, Besluit, Rol | Production, mandated NL | **HIGH** — Dutch API interoperability | -| **RGBZ** | Dutch gov | Information model behind ZGW | Stable (v1.0) | **HIGH** — field-level reference | -| **ZGW Catalogi API** | Dutch gov | ZaakType, StatusType, ResultaatType, RolType, etc. | Production (v1.3.x) | **HIGH** — case type system reference | +| **CMMN 1.1** | International (OMG) | Case plans, tasks, milestones, sentries, case file items | Mature | **HIGH**: designed for case management | +| **BPMN 2.0** | International (OMG) | Processes, tasks, gateways, events | Very mature, widely adopted | **HIGH**: task/workflow modeling | +| **DMN 1.x** | International (OMG) | Decision tables, decision logic | Mature, growing | **MEDIUM**: decision modeling | +| **Schema.org** | International (W3C) | Action, Project, GovernmentService, Role | Very mature | **MEDIUM**: semantic vocabulary | +| **Dublin Core (ISO 15836)** | International | 15 metadata elements for documents | Very mature | **LOW**: document metadata | +| **ZGW APIs (VNG)** | Dutch gov | Zaak, Status, Resultaat, Besluit, Rol | Production, mandated NL | **HIGH**: Dutch API interoperability | +| **RGBZ** | Dutch gov | Information model behind ZGW | Stable (v1.0) | **HIGH**: field-level reference | +| **ZGW Catalogi API** | Dutch gov | ZaakType, StatusType, ResultaatType, RolType, etc. | Production (v1.3.x) | **HIGH**: case type system reference | ### 2.2 Design Principle: International First @@ -66,7 +66,7 @@ This means: 4. **ZGW Catalogi API** defines `ZaakType` as a comprehensive case type system controlling: allowed statuses, result types with archival rules, role types, custom properties, required documents, processing deadlines, confidentiality defaults, and publication rules. This is the most complete case type reference available. -5. **Schema.org** provides `Action` (with `actionStatus`, `agent`, `result`), `Project`, and `Role` — useful as semantic annotations but not domain-specific enough for case management. +5. **Schema.org** provides `Action` (with `actionStatus`, `agent`, `result`), `Project`, and `Role`: useful as semantic annotations but not domain-specific enough for case management. 6. **Nextcloud** provides built-in Calendar (CalDAV), activity tracking, and file management that we reuse where possible. Deck was evaluated but is not suitable (no PHP API, model doesn't fit). @@ -91,7 +91,7 @@ A case type is a configurable definition that controls the behavior of cases: wh | Aspect | Decision | Rationale | |--------|----------|-----------| | **CMMN concept** | `CaseDefinition` / `CasePlanModel` template | CMMN separates case definition from case instance | -| **ZGW equivalent** | `ZaakType` (Catalogi API 1.3.x) | Full behavioral case type — our primary reference | +| **ZGW equivalent** | `ZaakType` (Catalogi API 1.3.x) | Full behavioral case type: our primary reference | | **Versioning** | Case types have validity periods and draft/published status | From ZGW: `concept`, `validFrom`, `validUntil` | **Core properties**: @@ -101,26 +101,26 @@ A case type is a configurable definition that controls the behavior of cases: wh | `title` | string | `schema:name` | `zaaktype_omschrijving` | Yes | | `description` | string | `schema:description` | `toelichting` | No | | `identifier` | string | `schema:identifier` | `identificatie` | Auto | -| `purpose` | string | — | `doel` | Yes | -| `trigger` | string | — | `aanleiding` | Yes | -| `subject` | string | — | `onderwerp` | Yes | -| `initiatorAction` | string | — | `handeling_initiator` | Yes | -| `handlerAction` | string | — | `handeling_behandelaar` | Yes | -| `origin` | enum: internal, external | — | `indicatie_intern_of_extern` | Yes | +| `purpose` | string |: | `doel` | Yes | +| `trigger` | string |: | `aanleiding` | Yes | +| `subject` | string |: | `onderwerp` | Yes | +| `initiatorAction` | string |: | `handeling_initiator` | Yes | +| `handlerAction` | string |: | `handeling_behandelaar` | Yes | +| `origin` | enum: internal, external |: | `indicatie_intern_of_extern` | Yes | | `processingDeadline` | duration (ISO 8601) | CMMN TimerEventListener | `doorlooptijd_behandeling` | Yes | -| `serviceTarget` | duration (ISO 8601) | — | `servicenorm_behandeling` | No | -| `suspensionAllowed` | boolean | — | `opschorting_en_aanhouding_mogelijk` | Yes | -| `extensionAllowed` | boolean | — | `verlenging_mogelijk` | Yes | -| `extensionPeriod` | duration (ISO 8601) | — | `verlengingstermijn` | Conditional | -| `confidentiality` | enum | — | `vertrouwelijkheidaanduiding` | Yes | -| `publicationRequired` | boolean | — | `publicatie_indicatie` | Yes | -| `publicationText` | string | — | `publicatietekst` | No | -| `responsibleUnit` | string | — | `verantwoordelijke` | Yes | -| `referenceProcess` | string | — | `referentieproces_naam` | No | -| `isDraft` | boolean | — | `concept` | No (default: true) | -| `validFrom` | date | — | `datum_begin_geldigheid` | Yes | -| `validUntil` | date | — | `datum_einde_geldigheid` | No | -| `keywords` | string[] | — | `trefwoorden` | No | +| `serviceTarget` | duration (ISO 8601) |: | `servicenorm_behandeling` | No | +| `suspensionAllowed` | boolean |: | `opschorting_en_aanhouding_mogelijk` | Yes | +| `extensionAllowed` | boolean |: | `verlenging_mogelijk` | Yes | +| `extensionPeriod` | duration (ISO 8601) |: | `verlengingstermijn` | Conditional | +| `confidentiality` | enum |: | `vertrouwelijkheidaanduiding` | Yes | +| `publicationRequired` | boolean |: | `publicatie_indicatie` | Yes | +| `publicationText` | string |: | `publicatietekst` | No | +| `responsibleUnit` | string |: | `verantwoordelijke` | Yes | +| `referenceProcess` | string |: | `referentieproces_naam` | No | +| `isDraft` | boolean |: | `concept` | No (default: true) | +| `validFrom` | date |: | `datum_begin_geldigheid` | Yes | +| `validUntil` | date |: | `datum_einde_geldigheid` | No | +| `keywords` | string[] |: | `trefwoorden` | No | | `subCaseTypes` | reference[] | CMMN CaseTask | `deelzaaktypen` | No | **Confidentiality levels** (from ZGW, internationally applicable): @@ -155,9 +155,9 @@ A configurable status definition linked to a case type. Controls which lifecycle | `caseType` | reference | Parent case type | `zaaktype` | Yes | | `order` | integer (1–9999) | CMMN Milestone sequence | `statustypevolgnummer` | Yes | | `isFinal` | boolean | CMMN terminal state | (last in order) | No (default: false) | -| `targetDuration` | duration | — | `doorlooptijd` | No | -| `notifyInitiator` | boolean | — | `informeren` | No (default: false) | -| `notificationText` | string | — | `statustekst` | No | +| `targetDuration` | duration |: | `doorlooptijd` | No | +| `notifyInitiator` | boolean |: | `informeren` | No (default: false) | +| `notificationText` | string |: | `statustekst` | No | #### Result Type @@ -175,9 +175,9 @@ A configurable result definition linked to a case type. Controls which outcomes | `name` | string | `schema:name` | `omschrijving` | Yes | | `description` | string | `schema:description` | `toelichting` | No | | `caseType` | reference | Parent case type | `zaaktype` | Yes | -| `archiveAction` | enum: retain, destroy | — | `archiefnominatie` | No | -| `retentionPeriod` | duration (ISO 8601) | — | `archiefactietermijn` | No | -| `retentionDateSource` | enum | — | `afleidingswijze` | No | +| `archiveAction` | enum: retain, destroy |: | `archiefnominatie` | No | +| `retentionPeriod` | duration (ISO 8601) |: | `archiefactietermijn` | No | +| `retentionDateSource` | enum |: | `afleidingswijze` | No | **Retention date source values** (from ZGW, internationally applicable): @@ -207,7 +207,7 @@ A configurable role definition linked to a case type. Controls which participant |----------|------|--------|-------------|----------| | `name` | string | `schema:roleName` | `omschrijving` | Yes | | `caseType` | reference | Parent case type | `zaaktype` | Yes | -| `genericRole` | enum | — | `omschrijvingGeneriek` | Yes | +| `genericRole` | enum |: | `omschrijvingGeneriek` | Yes | **Standard generic roles** (from ZGW, internationally applicable): @@ -238,9 +238,9 @@ A configurable custom field definition linked to a case type. Controls which add | `name` | string | `schema:name` | `eigenschapnaam` | Yes | | `definition` | string | `schema:description` | `definitie` | Yes | | `caseType` | reference | Parent case type | `zaaktype` | Yes | -| `format` | enum: text, number, date, datetime | — | `formaat` | Yes | -| `maxLength` | integer | — | `lengte` | No | -| `allowedValues` | string[] | — | `waardenverzameling` | No | +| `format` | enum: text, number, date, datetime |: | `formaat` | Yes | +| `maxLength` | integer |: | `lengte` | No | +| `allowedValues` | string[] |: | `waardenverzameling` | No | | `requiredAtStatus` | reference | Status at which this must be filled | `statustype` | No | #### Document Type @@ -257,11 +257,11 @@ A configurable document type definition linked to a case type. Controls which do | Property | Type | Source | ZGW Mapping | Required | |----------|------|--------|-------------|----------| | `name` | string | `schema:name` | `omschrijving` | Yes | -| `category` | string | — | `informatieobjectcategorie` | Yes | +| `category` | string |: | `informatieobjectcategorie` | Yes | | `caseType` | reference | Parent case type | `zaaktype` (via through table) | Yes | -| `direction` | enum: incoming, internal, outgoing | — | `richting` | Yes | -| `order` | integer | — | `volgnummer` | Yes | -| `confidentiality` | enum | — | `vertrouwelijkheidaanduiding` | No | +| `direction` | enum: incoming, internal, outgoing |: | `richting` | Yes | +| `order` | integer |: | `volgnummer` | Yes | +| `confidentiality` | enum |: | `vertrouwelijkheidaanduiding` | No | | `requiredAtStatus` | reference | Status requiring this document | `statustype` | No | #### Decision Type @@ -279,10 +279,10 @@ A configurable decision type definition linked to a case type. |----------|------|--------|-------------|----------| | `name` | string | `schema:name` | `omschrijving` | Yes | | `description` | string | `schema:description` | `toelichting` | No | -| `category` | string | — | `besluitcategorie` | No | -| `objectionPeriod` | duration (ISO 8601) | — | `reactietermijn` | No | -| `publicationRequired` | boolean | — | `publicatie_indicatie` | Yes | -| `publicationPeriod` | duration (ISO 8601) | — | `publicatietermijn` | No | +| `category` | string |: | `besluitcategorie` | No | +| `objectionPeriod` | duration (ISO 8601) |: | `reactietermijn` | No | +| `publicationRequired` | boolean |: | `publicatie_indicatie` | Yes | +| `publicationPeriod` | duration (ISO 8601) |: | `publicatietermijn` | No | #### Case (Zaak) @@ -290,7 +290,7 @@ A case is a coherent body of work with a defined lifecycle, initiation, and resu | Aspect | Decision | Rationale | |--------|----------|-----------| -| **CMMN concept** | `CasePlanModel` / Case instance | CMMN's core concept — a case with a plan | +| **CMMN concept** | `CasePlanModel` / Case instance | CMMN's core concept: a case with a plan | | **Schema.org type** | `schema:Project` | "An enterprise planned to achieve a particular aim" | | **ZGW mapping** | `Zaak` | Direct mapping for Dutch API compatibility | @@ -306,13 +306,13 @@ A case is a coherent body of work with a defined lifecycle, initiation, and resu | `result` | reference | CMMN case outcome | `resultaat` (URL ref) | No | | `startDate` | date | `schema:startDate` | `startdatum` | Yes | | `endDate` | date | `schema:endDate` | `einddatum` | No | -| `plannedEndDate` | date | — | `einddatumGepland` | No | -| `deadline` | date | — | `uiterlijkeEinddatumAfdoening` | Auto (from caseType) | -| `confidentiality` | enum | — | `vertrouwelijkheidaanduiding` | No (default from caseType) | -| `assignee` | string | CMMN HumanTask.assignee | — | No | -| `priority` | enum | `schema:priority` | — | No | +| `plannedEndDate` | date |: | `einddatumGepland` | No | +| `deadline` | date |: | `uiterlijkeEinddatumAfdoening` | Auto (from caseType) | +| `confidentiality` | enum |: | `vertrouwelijkheidaanduiding` | No (default from caseType) | +| `assignee` | string | CMMN HumanTask.assignee |: | No | +| `priority` | enum | `schema:priority` |: | No | | `parentCase` | reference | CMMN CaseTask (sub-case) | `hoofdzaak` | No | -| `relatedCases` | array | — | `relevanteAndereZaken` | No | +| `relatedCases` | array |: | `relevanteAndereZaken` | No | | `geometry` | GeoJSON | `schema:geo` | `zaakgeometrie` | No | **Case type behavioral controls on cases**: @@ -365,8 +365,8 @@ The relationship between a person/organization and a case. |----------|------|------------------|-------------|----------| | `name` | string | `schema:roleName` | `omschrijving` | Yes | | `description` | string | `schema:description` | `roltoelichting` | No | -| `roleType` | reference | — | `omschrijvingGeneriek` (via RoleType) | Yes | -| `case` | reference | — | `zaak` | Yes | +| `roleType` | reference |: | `omschrijvingGeneriek` (via RoleType) | Yes | +| `case` | reference |: | `zaak` | Yes | | `participant` | string (user UID or contact ref) | `schema:agent` | `betrokkene` | Yes | #### Result (Resultaat) @@ -390,11 +390,11 @@ A formal decision made on a case. | Property | Type | Schema.org Source | ZGW Mapping | Required | |----------|------|------------------|-------------|----------| -| `title` | string | `schema:name` | — | Yes | +| `title` | string | `schema:name` |: | Yes | | `description` | string | `schema:description` | `toelichting` | No | -| `case` | reference | — | `zaak` | No | -| `decisionType` | reference | — | `besluittype` | No | -| `decidedBy` | string | `schema:agent` | — | No | +| `case` | reference |: | `zaak` | No | +| `decisionType` | reference |: | `besluittype` | No | +| `decidedBy` | string | `schema:agent` |: | No | | `decidedAt` | datetime | `schema:endTime` | `datum` | No | | `effectiveDate` | date | `schema:startTime` | `ingangsdatum` | No | | `expiryDate` | date | `schema:endTime` | `vervaldatum` | No | @@ -405,13 +405,13 @@ The case type system forms a hierarchy where the CaseType is the central configu ``` CaseType -├── StatusType[] — Allowed lifecycle phases (ordered) -├── ResultType[] — Allowed outcomes (with archival rules) -├── RoleType[] — Allowed participant roles -├── PropertyDefinition[] — Required custom data fields -├── DocumentType[] — Required document types -├── DecisionType[] — Allowed decision types -└── subCaseTypes[] — Allowed sub-case types +├── StatusType[] : Allowed lifecycle phases (ordered) +├── ResultType[] : Allowed outcomes (with archival rules) +├── RoleType[] : Allowed participant roles +├── PropertyDefinition[]: Required custom data fields +├── DocumentType[] : Required document types +├── DecisionType[] : Allowed decision types +└── subCaseTypes[] : Allowed sub-case types ``` **Behavioral controls**: @@ -431,7 +431,7 @@ CaseType ### 3.4 My Work (Werkvoorraad) -A cross-entity workload view showing all items assigned to the current user. No new entity is needed — this is a frontend aggregation pattern. +A cross-entity workload view showing all items assigned to the current user. No new entity is needed: this is a frontend aggregation pattern. **How it works**: - Query cases with `assignee == currentUser` and non-final status @@ -445,7 +445,7 @@ A cross-entity workload view showing all items assigned to the current user. No |-------|------|------|--------------|-----------------| | `assignee` / `assignedTo` | Yes | Yes | Yes | Yes | | `priority` | Yes | Yes | Yes | Yes | -| `deadline` / `dueDate` | Yes | Yes | Yes | — | +| `deadline` / `dueDate` | Yes | Yes | Yes |: | | `status` | Yes | Yes | (via stage) | Yes | | Entity type label | "Case" | "Task" | "Lead" | "Request" | @@ -573,18 +573,18 @@ $conversation = $broker->createConversation('Case: ' . $caseTitle, $participantI Schemas MUST be defined in `lib/Settings/procest_register.json` using OpenAPI 3.0.0 format, following the pattern used by opencatalogi and softwarecatalog. **Schemas**: -- `caseType` — Case type definition (CMMN CaseDefinition) -- `statusType` — Status type per case type (CMMN Milestone) -- `resultType` — Result type per case type (with archival rules) -- `roleType` — Role type per case type (schema:Role) -- `propertyDefinition` — Custom field definition (schema:PropertyValueSpecification) -- `documentType` — Document type requirement (schema:DigitalDocument) -- `decisionType` — Decision type definition (schema:ChooseAction) -- `case` — Case instance (schema:Project) -- `task` — Task within a case (schema:Action) -- `role` — Role assignment on a case (schema:Role instance) -- `result` — Case outcome (schema:Action.result) -- `decision` — Formal decision (schema:ChooseAction instance) +- `caseType`: Case type definition (CMMN CaseDefinition) +- `statusType`: Status type per case type (CMMN Milestone) +- `resultType`: Result type per case type (with archival rules) +- `roleType`: Role type per case type (schema:Role) +- `propertyDefinition`: Custom field definition (schema:PropertyValueSpecification) +- `documentType`: Document type requirement (schema:DigitalDocument) +- `decisionType`: Decision type definition (schema:ChooseAction) +- `case`: Case instance (schema:Project) +- `task`: Task within a case (schema:Action) +- `role`: Role assignment on a case (schema:Role instance) +- `result`: Case outcome (schema:Action.result) +- `decision`: Formal decision (schema:ChooseAction instance) The configuration is imported via `ConfigurationService::importFromApp()` in the repair step. @@ -611,45 +611,45 @@ Field-level mappings are documented per entity in section 3.2 above. ## 6. Open Research Questions -1. ~~**Nextcloud Deck reuse**~~ — **RESOLVED**: Deck is not suitable. No PHP API, model doesn't fit case lifecycle. +1. ~~**Nextcloud Deck reuse**~~: **RESOLVED**: Deck is not suitable. No PHP API, model doesn't fit case lifecycle. -2. ~~**Case type system**~~ — **RESOLVED**: Case types are a core feature with full behavioral controls, modeled after ZGW ZaakType but using international terminology. +2. ~~**Case type system**~~: **RESOLVED**: Case types are a core feature with full behavioral controls, modeled after ZGW ZaakType but using international terminology. -3. **CMMN runtime** — Should Procest implement CMMN runtime semantics (sentries, entry/exit criteria) or keep the simpler status-based lifecycle? Current decision: start with ordered status progression, add CMMN features as needed. +3. **CMMN runtime**: Should Procest implement CMMN runtime semantics (sentries, entry/exit criteria) or keep the simpler status-based lifecycle? Current decision: start with ordered status progression, add CMMN features as needed. -4. **Archival** — ZGW has detailed archival rules. The case type system now includes result-based archival configuration (`archiveAction`, `retentionPeriod`, `retentionDateSource`). Runtime archival enforcement is deferred until compliance requirements emerge. +4. **Archival**: ZGW has detailed archival rules. The case type system now includes result-based archival configuration (`archiveAction`, `retentionPeriod`, `retentionDateSource`). Runtime archival enforcement is deferred until compliance requirements emerge. -5. **DMN for decisions** — Should Procest support DMN decision tables for automated decision logic? This is ambitious but aligns with the OMG "Triple Crown" (BPMN + CMMN + DMN). Deferred. +5. **DMN for decisions**: Should Procest support DMN decision tables for automated decision logic? This is ambitious but aligns with the OMG "Triple Crown" (BPMN + CMMN + DMN). Deferred. -6. **Case type versioning** — ZGW supports versioning of case types (new versions when modifications are made). Should Procest implement version chains? Current decision: `validFrom`/`validUntil` for validity windows, explicit versioning deferred. +6. **Case type versioning**: ZGW supports versioning of case types (new versions when modifications are made). Should Procest implement version chains? Current decision: `validFrom`/`validUntil` for validity windows, explicit versioning deferred. -7. **Cross-app My Work** — Should the My Work view in Procest also show Pipelinq leads/requests? Requires cross-app API calls or a shared dashboard widget. +7. **Cross-app My Work**: Should the My Work view in Procest also show Pipelinq leads/requests? Requires cross-app API calls or a shared dashboard widget. ## 7. References ### Primary Standards (International) -- [CMMN 1.1 (OMG)](https://www.omg.org/spec/CMMN/1.1/About-CMMN) — Case Management Model and Notation -- [BPMN 2.0 (OMG)](https://www.omg.org/spec/BPMN/2.0.2/) — Business Process Model and Notation -- [DMN (OMG)](https://www.omg.org/dmn/) — Decision Model and Notation -- [Schema.org](https://schema.org/) — Linked data vocabulary +- [CMMN 1.1 (OMG)](https://www.omg.org/spec/CMMN/1.1/About-CMMN): Case Management Model and Notation +- [BPMN 2.0 (OMG)](https://www.omg.org/spec/BPMN/2.0.2/): Business Process Model and Notation +- [DMN (OMG)](https://www.omg.org/dmn/): Decision Model and Notation +- [Schema.org](https://schema.org/): Linked data vocabulary ### Schema.org Types Used -- [schema:Project](https://schema.org/Project) — Case -- [schema:Action](https://schema.org/Action) — Task (with ActionStatusType) -- [schema:Role](https://schema.org/Role) — Case participant role -- [schema:ChooseAction](https://schema.org/ChooseAction) — Decision -- [schema:PropertyValueSpecification](https://schema.org/PropertyValueSpecification) — Custom field definition -- [schema:DigitalDocument](https://schema.org/DigitalDocument) — Document type -- [schema:identifier](https://schema.org/identifier) — Unique identifiers +- [schema:Project](https://schema.org/Project): Case +- [schema:Action](https://schema.org/Action): Task (with ActionStatusType) +- [schema:Role](https://schema.org/Role): Case participant role +- [schema:ChooseAction](https://schema.org/ChooseAction): Decision +- [schema:PropertyValueSpecification](https://schema.org/PropertyValueSpecification): Custom field definition +- [schema:DigitalDocument](https://schema.org/DigitalDocument): Document type +- [schema:identifier](https://schema.org/identifier): Unique identifiers ### Dutch Standards (API Mapping Layer) -- [ZGW API Standards](https://vng-realisatie.github.io/gemma-zaken/standaard/) — Zaken, Besluiten, Catalogi, Documenten APIs -- [ZGW Catalogi API](https://vng-realisatie.github.io/gemma-zaken/standaard/catalogi/index) — Case type definitions (ZaakType, StatusType, etc.) -- [RGBZ](https://vng-realisatie.github.io/RGBZ/) — Information model for ZGW -- [GEMMA Online](https://www.gemmaonline.nl/) — Dutch municipal architecture +- [ZGW API Standards](https://vng-realisatie.github.io/gemma-zaken/standaard/): Zaken, Besluiten, Catalogi, Documenten APIs +- [ZGW Catalogi API](https://vng-realisatie.github.io/gemma-zaken/standaard/catalogi/index): Case type definitions (ZaakType, StatusType, etc.) +- [RGBZ](https://vng-realisatie.github.io/RGBZ/): Information model for ZGW +- [GEMMA Online](https://www.gemmaonline.nl/): Dutch municipal architecture ### Industry References -- [OpenZaak](https://github.com/open-zaak/open-zaak) — ZGW reference implementation (ZaakType model source) -- [Valtimo](https://docs.valtimo.nl/) — Case management platform with ZGW integration -- [Flowable CMMN](https://www.flowable.com/open-source/docs/cmmn/ch06-cmmn) — CMMN engine reference -- [Camunda CMMN Patterns via BPMN](https://camunda.com/blog/2023/07/cmmn-patterns-bpmn/) — Pragmatic CMMN approach +- [OpenZaak](https://github.com/open-zaak/open-zaak): ZGW reference implementation (ZaakType model source) +- [Valtimo](https://docs.valtimo.nl/): Case management platform with ZGW integration +- [Flowable CMMN](https://www.flowable.com/open-source/docs/cmmn/ch06-cmmn): CMMN engine reference +- [Camunda CMMN Patterns via BPMN](https://camunda.com/blog/2023/07/cmmn-patterns-bpmn/): Pragmatic CMMN approach diff --git a/docs/DESIGN-REFERENCES.md b/docs/Technical/design-decisions.md similarity index 97% rename from docs/DESIGN-REFERENCES.md rename to docs/Technical/design-decisions.md index cced8b881..3989cbf36 100644 --- a/docs/DESIGN-REFERENCES.md +++ b/docs/Technical/design-decisions.md @@ -1,4 +1,4 @@ -# Procest — Design References & Dashboard Wireframes +# Procest: Design References & Dashboard Wireframes ## 1. Design Inspiration Sources @@ -22,7 +22,7 @@ ### Task Kanban / Board | Source | URL / Search | Key Patterns | |--------|-------------|--------------| -| Nextcloud Deck | apps.nextcloud.com/apps/deck | Board/Stack/Card — native Nextcloud kanban UX | +| Nextcloud Deck | apps.nextcloud.com/apps/deck | Board/Stack/Card: native Nextcloud kanban UX | | Trello | trello.com | Minimal cards, clear columns, smooth drag-and-drop | | Dribbble | Search "task board UI" | Task cards with assignee, due date, priority, case reference | | Asana | asana.com | Task boards with multiple views (list, board, timeline) | @@ -44,7 +44,7 @@ Features not currently in FEATURES.md but commonly present in case management da | Feature | Source Pattern | Justification | |---------|--------------|---------------| | Status timeline visualization on case detail | MijnOverheid, ServiceNow | Visual progress indicator showing which statuses have been passed | -| Case deadline countdown (days remaining) | All case management tools | At-a-glance urgency — "14 days remaining" or "3 days overdue" | +| Case deadline countdown (days remaining) | All case management tools | At-a-glance urgency: "14 days remaining" or "3 days overdue" | | Quick status change from list view | ServiceNow, Jira | Change case status without opening the detail page | ### V1 Additions @@ -116,7 +116,7 @@ Features not currently in FEATURES.md but commonly present in case management da │ │ │ │ │ ┌────────────────────────────────┐ │ • Decision recorded on │ │ │ │ My Work (Top 5) │ │ Case #036 "Vergunning │ │ -│ │ │ │ verleend" — Maria │ │ +│ │ │ │ verleend": Maria │ │ │ │ 🔴 Case #042 · Overdue 5d │ │ 1 hour ago │ │ │ │ Omgevingsvergunning │ │ │ │ │ │ │ │ • Task "Review docs" │ │ @@ -154,7 +154,7 @@ Features not currently in FEATURES.md but commonly present in case management da │ │ │ │ buurman │ │ │1 day │ ││ │ │ │ 2024-048 │ Subsidie │ Subsidie- │In behan.│Feb 28│ Jan ││ │ │ │ │ verduurz. │ aanvraag │ │3 days│ ││ -│ │ │ 2024-050 │ Bouwverg. │ Omgevings- │Ontvangen│Mar 15│ — ││ +│ │ │ 2024-050 │ Bouwverg. │ Omgevings- │Ontvangen│Mar 15│: ││ │ │ │ │ Prinsengr. │ vergunning │ │18 day│ ││ │ │ │ 2024-051 │ Melding │ Melding │Ontvangen│Mar 20│ Maria││ │ │ │ │ wegdek │ │ │23 day│ ││ @@ -239,7 +239,7 @@ Features not currently in FEATURES.md but commonly present in case management da │ │ │ │ │ │ Feb 25 · Task "Review docs" assigned to Jan de Vries │ │ │ │ │ │ -│ │ Feb 20 · ⚠ DEADLINE PASSED — case is now overdue │ │ +│ │ Feb 20 · ⚠ DEADLINE PASSED: case is now overdue │ │ │ │ │ │ │ │ Feb 1 · Status changed to "In behandeling" │ │ │ │ by Jan de Vries │ │ @@ -308,7 +308,7 @@ Features not currently in FEATURES.md but commonly present in case management da │ ││Check regs ││ ││Write report││ │ │ │ │ │ │ ││Case #051 ││ ││Case #048 ││ │ │ │ │ │ │ ││📅 Mar 10 ││ ││📅 Mar 1 ││ │ │ │ │ │ -│ ││👤 — ││ ││👤 Jan ││ │ │ │ │ │ +│ ││👤: ││ ││👤 Jan ││ │ │ │ │ │ │ │└────────────┘│ │└────────────┘│ │ │ │ │ │ │ │ │ │┌────────────┐│ │ │ │ │ │ │ │ │ ││Schedule ││ │ │ │ │ │ @@ -403,7 +403,7 @@ Features not currently in FEATURES.md but commonly present in case management da └─────────────────────────────────────────────────────────────────────┘ ``` -### 3.6 Admin Settings — Case Type Management +### 3.6 Admin Settings: Case Type Management ``` ┌─────────────────────────────────────────────────────────────────────┐ @@ -445,7 +445,7 @@ Features not currently in FEATURES.md but commonly present in case management da └─────────────────────────────────────────────────────────────────────┘ ``` -### 3.7 Admin Settings — Case Type Detail (Edit Mode) +### 3.7 Admin Settings: Case Type Detail (Edit Mode) ``` ┌─────────────────────────────────────────────────────────────────────┐ diff --git a/docs/development.md b/docs/Technical/development-guide.md similarity index 99% rename from docs/development.md rename to docs/Technical/development-guide.md index ceec28700..6449fc564 100644 --- a/docs/development.md +++ b/docs/Technical/development-guide.md @@ -1,4 +1,4 @@ -# Procest — Developer Guide +# Procest: Developer Guide ## Branching Strategy diff --git a/docs/GOVERNMENT-FEATURES.md b/docs/Technical/government-compliance.md similarity index 94% rename from docs/GOVERNMENT-FEATURES.md rename to docs/Technical/government-compliance.md index 2ecf553c8..e55f9b683 100644 --- a/docs/GOVERNMENT-FEATURES.md +++ b/docs/Technical/government-compliance.md @@ -1,4 +1,4 @@ -# Procest — Overheidsfunctionaliteiten +# Procest: Overheidsfunctionaliteiten > Functiepagina voor Nederlandse overheidsorganisaties. > Gebruik deze checklist om te toetsen aan uw Programma van Eisen. @@ -123,7 +123,7 @@ | P-02 | Recht op vergetelheid | Gepland (V1) | Zaak- en persoonsgegevens verwijdering | | P-03 | Recht op rectificatie | Via platform | Object wijzigen via OpenRegister | | P-04 | Bewaartermijnen | Gepland (Enterprise) | Automatische vernietiging | -| P-05 | Data minimalisatie | Beschikbaar | Schema-gebaseerd — alleen gedefinieerde velden | +| P-05 | Data minimalisatie | Beschikbaar | Schema-gebaseerd: alleen gedefinieerde velden | --- @@ -202,10 +202,10 @@ | Kenmerk | Toelichting | |---------|-------------| -| **Nextcloud-native** | Geen apart systeem — case management in uw bestaande samenwerkingsplatform | -| **Lichtgewicht** | Geen Java/Spring stack — draait als Nextcloud-app | +| **Nextcloud-native** | Geen apart systeem: case management in uw bestaande samenwerkingsplatform | +| **Lichtgewicht** | Geen Java/Spring stack: draait als Nextcloud-app | | **CRM + Zaak in één** | Pipelinq (CRM) → Procest (zaak) is een unieke geïntegreerde workflow | | **NL Design System** | Overheidshuisstijl via design tokens | | **Data-hergebruik** | Zaakdata op OpenRegister is herbruikbaar door andere apps | | **Gefedereerd** | Cross-organisatie zaakafhandeling via Nextcloud federatie | -| **~50% infrastructuur gratis** | Taken, bestanden, notificaties, chat — al ingebouwd | +| **~50% infrastructuur gratis** | Taken, bestanden, notificaties, chat: al ingebouwd | diff --git a/docs/FEATURES.md b/docs/Technical/market-analysis.md similarity index 92% rename from docs/FEATURES.md rename to docs/Technical/market-analysis.md index 665b213d9..6e8d666f4 100644 --- a/docs/FEATURES.md +++ b/docs/Technical/market-analysis.md @@ -1,10 +1,10 @@ -# Procest — Feature Analysis & Product Strategy +# Procest: Feature Analysis & Product Strategy ## Executive Summary There is **no lightweight, self-hosted case management system that integrates with a collaboration platform**. The market has enterprise BPM suites that are heavyweight and expensive (Camunda, Flowable), Dutch government implementations that are API-only without user-facing UI (OpenZaak), and SaaS platforms with data sovereignty issues (ServiceNow, Monday.com). Procest fills all three gaps by being lightweight, Nextcloud-native, and government-ready. -**Key insight**: Case management is fundamentally about coordination — tracking work, assigning tasks, meeting deadlines, managing documents, and making decisions. Nextcloud already provides task management (Calendar/VTODO), file management, real-time chat, and activity feeds. A Nextcloud-native case manager orchestrates these capabilities rather than rebuilding them. +**Key insight**: Case management is fundamentally about coordination: tracking work, assigning tasks, meeting deadlines, managing documents, and making decisions. Nextcloud already provides task management (Calendar/VTODO), file management, real-time chat, and activity feeds. A Nextcloud-native case manager orchestrates these capabilities rather than rebuilding them. ## 1. Competitive Landscape @@ -12,9 +12,9 @@ There is **no lightweight, self-hosted case management system that integrates wi | Name | Status | Approach | |------|--------|----------| -| **Nextcloud Deck** | Bundled, active | Kanban board for tasks — not case management | -| **Nextcloud Tasks** | Available | CalDAV VTODO client — individual task tracking | -| **Nextcloud Forms** | Available | Form builder — intake only, no workflow | +| **Nextcloud Deck** | Bundled, active | Kanban board for tasks: not case management | +| **Nextcloud Tasks** | Available | CalDAV VTODO client: individual task tracking | +| **Nextcloud Forms** | Available | Form builder: intake only, no workflow | **Finding**: No case management solution exists in Nextcloud. Deck and Tasks handle individual work items but lack case lifecycle, roles, decisions, and compliance features. @@ -22,7 +22,7 @@ There is **no lightweight, self-hosted case management system that integrates wi | Name | Positioning | Strengths | Weaknesses | |------|------------|-----------|------------| -| **OpenZaak** | ZGW API reference implementation | Full ZGW compliance, production-proven (40+ municipalities) | API-only — no end-user UI, requires frontend | +| **OpenZaak** | ZGW API reference implementation | Full ZGW compliance, production-proven (40+ municipalities) | API-only: no end-user UI, requires frontend | | **Valtimo/GZAC** | Commercial case platform + ZGW | BPMN/DMN engine, document handling, ZGW connector | Proprietary core (Ritense), Java/Spring stack, heavy | | **ZAC (Dimpact)** | Municipal frontend on OpenZaak | Full zaakgericht werken workflow | Tightly coupled to OpenZaak, limited outside NL | | **Camunda ZGW** | BPMN engine + ZGW connectors | Powerful process automation | Complex setup, Java, enterprise pricing | @@ -278,21 +278,21 @@ There is **no lightweight, self-hosted case management system that integrates wi | Air-gapped deployment | Enterprise platforms cannot function without internet | | Talk rooms per case | Built-in real-time chat; no BPM engine has this | | Calendar-native deadlines | Case deadlines appear in user's calendar without sync | -| ~40-50% infrastructure free | Tasks, files, notifications, activity, comments — already built | +| ~40-50% infrastructure free | Tasks, files, notifications, activity, comments: already built | ## 4. Strategic Positioning ### Positioning Statement -**Procest is case management that lives where your team already works.** Built natively into Nextcloud, it turns your existing collaboration platform into a case management system — with files, calendar, chat, and activity already connected. +**Procest is case management that lives where your team already works.** Built natively into Nextcloud, it turns your existing collaboration platform into a case management system: with files, calendar, chat, and activity already connected. ### Differentiation Strategy Three pillars: -1. **Platform leverage** — Every Nextcloud feature (AI, workflows, federation, files) automatically benefits Procest -2. **Government-first** — ZGW standard alignment, NL Design System, GDPR-by-architecture, archival-ready -3. **Lightweight simplicity** — No Java stack, no separate deployment; runs inside existing Nextcloud with zero additional infrastructure +1. **Platform leverage**: Every Nextcloud feature (AI, workflows, federation, files) automatically benefits Procest +2. **Government-first**: ZGW standard alignment, NL Design System, GDPR-by-architecture, archival-ready +3. **Lightweight simplicity**: No Java stack, no separate deployment; runs inside existing Nextcloud with zero additional infrastructure ### Target Segments diff --git a/docs/zgw-implementation.md b/docs/Technical/zgw-spec.md similarity index 81% rename from docs/zgw-implementation.md rename to docs/Technical/zgw-spec.md index ef19b0df0..ee89bb916 100644 --- a/docs/zgw-implementation.md +++ b/docs/Technical/zgw-spec.md @@ -21,50 +21,50 @@ Shared knowledge file for sub-agents working on Procest's ZGW API implementation All controllers depend on `ZgwService` (`lib/Service/ZgwService.php`). Key methods: **CRUD orchestration** (handles auth, mapping, validation, save, notification): -- `handleIndex(IRequest, zgwApi, resource)` — paginated list -- `handleCreate(IRequest, zgwApi, resource, ?zaakClosed, hasForceer)` — create with business rules -- `handleShow(IRequest, zgwApi, resource, uuid)` — get single -- `handleUpdate(IRequest, zgwApi, resource, uuid, partial, ?parentZtDraft, ?zaakClosed, hasForceer)` — PUT/PATCH -- `handleDestroy(IRequest, zgwApi, resource, uuid, ?parentZtDraft, ?zaakClosed, hasForceer)` — DELETE +- `handleIndex(IRequest, zgwApi, resource)`: paginated list +- `handleCreate(IRequest, zgwApi, resource, ?zaakClosed, hasForceer)`: create with business rules +- `handleShow(IRequest, zgwApi, resource, uuid)`: get single +- `handleUpdate(IRequest, zgwApi, resource, uuid, partial, ?parentZtDraft, ?zaakClosed, hasForceer)`: PUT/PATCH +- `handleDestroy(IRequest, zgwApi, resource, uuid, ?parentZtDraft, ?zaakClosed, hasForceer)`: DELETE **Utility methods:** -- `validateJwtAuth(IRequest)` — returns JSONResponse on failure, null on success -- `loadMappingConfig(zgwApi, resource)` — loads Twig mapping from IAppConfig -- `getRequestBody(IRequest)` — parses JSON body (with malformed JSON fallback) -- `buildBaseUrl(IRequest, zgwApi, resource)` — constructs ZGW-style URL -- `createOutboundMapping/createInboundMapping(mappingConfig)` — builds Mapping objects -- `applyOutboundMapping/applyInboundMapping(...)` — executes Twig-based field translation -- `translateQueryParams(params, mappingConfig)` — ZGW query params to OpenRegister filters -- `consumerHasScope(IRequest, component, scope)` — checks JWT consumer scopes -- `publishNotification(zgwApi, resource, resourceUrl, actie)` — sends to NRC subscribers -- `buildValidationError(ruleResult)` — formats validation error response -- `unavailableResponse()` / `mappingNotFoundResponse(zgwApi, resource)` — standard error responses +- `validateJwtAuth(IRequest)`: returns JSONResponse on failure, null on success +- `loadMappingConfig(zgwApi, resource)`: loads Twig mapping from IAppConfig +- `getRequestBody(IRequest)`: parses JSON body (with malformed JSON fallback) +- `buildBaseUrl(IRequest, zgwApi, resource)`: constructs ZGW-style URL +- `createOutboundMapping/createInboundMapping(mappingConfig)`: builds Mapping objects +- `applyOutboundMapping/applyInboundMapping(...)`: executes Twig-based field translation +- `translateQueryParams(params, mappingConfig)`: ZGW query params to OpenRegister filters +- `consumerHasScope(IRequest, component, scope)`: checks JWT consumer scopes +- `publishNotification(zgwApi, resource, resourceUrl, actie)`: sends to NRC subscribers +- `buildValidationError(ruleResult)`: formats validation error response +- `unavailableResponse()` / `mappingNotFoundResponse(zgwApi, resource)`: standard error responses **OpenRegister access:** -- `getObjectService()` — OpenRegister ObjectService (find, saveObject, deleteObject, buildSearchQuery, searchObjectsPaginated) -- `getConsumerMapper()` — OpenRegister ConsumerMapper (for AC) -- `getZgwMappingService()` — Procest's ZgwMappingService (IAppConfig storage) -- `getBusinessRulesService()` — ZgwBusinessRulesService -- `getDocumentService()` — ZgwDocumentService (file storage) -- `getLogger()` — PSR LoggerInterface +- `getObjectService()`: OpenRegister ObjectService (find, saveObject, deleteObject, buildSearchQuery, searchObjectsPaginated) +- `getConsumerMapper()`: OpenRegister ConsumerMapper (for AC) +- `getZgwMappingService()`: Procest's ZgwMappingService (IAppConfig storage) +- `getBusinessRulesService()`: ZgwBusinessRulesService +- `getDocumentService()`: ZgwDocumentService (file storage) +- `getLogger()`: PSR LoggerInterface **Cross-register resolvers:** -- `resolveZaakClosed(resource, existingData)` — checks if zaak has einddatum (for zrc-007) -- `resolveZaakClosedFromBody(resource, body)` — same but from request body (sub-resource creation) -- `resolveParentZaaktypeDraft(resource, existingData)` — checks if parent zaaktype is concept (for ztc-010) +- `resolveZaakClosed(resource, existingData)`: checks if zaak has einddatum (for zrc-007) +- `resolveZaakClosedFromBody(resource, body)`: same but from request body (sub-resource creation) +- `resolveParentZaaktypeDraft(resource, existingData)`: checks if parent zaaktype is concept (for ztc-010) ### Other Services -- `ZgwBusinessRulesService` — validates VNG business rules before save. Call via `zgwService->getBusinessRulesService()->validate(...)` -- `ZgwMappingService` — stores/retrieves Twig mapping configs from IAppConfig -- `ZgwPaginationHelper` — wraps results in ZGW HAL-style `{count, next, previous, results}` -- `ZgwDocumentService` — stores binary files in Nextcloud filesystem at `/admin/files/procest/documenten/{uuid}/{filename}` -- `NotificatieService` — delivers notifications to NRC subscribers via HTTP POST +- `ZgwBusinessRulesService`: validates VNG business rules before save. Call via `zgwService->getBusinessRulesService()->validate(...)` +- `ZgwMappingService`: stores/retrieves Twig mapping configs from IAppConfig +- `ZgwPaginationHelper`: wraps results in ZGW HAL-style `{count, next, previous, results}` +- `ZgwDocumentService`: stores binary files in Nextcloud filesystem at `/admin/files/procest/documenten/{uuid}/{filename}` +- `NotificatieService`: delivers notifications to NRC subscribers via HTTP POST ## Business Rules by Register ### ZRC (Zaken) -- **zrc-007**: Closed zaak protection — zaak sub-resources cannot be modified when the parent zaak has an `einddatum`, unless the consumer has `zaken.geforceerd-bijwerken` scope +- **zrc-007**: Closed zaak protection: zaak sub-resources cannot be modified when the parent zaak has an `einddatum`, unless the consumer has `zaken.geforceerd-bijwerken` scope - **zrc-007a**: When creating a status whose statustype has `isEindstatus=true`, automatically set the parent zaak's `einddatum` to the `datumStatusGezet` date - Zaakeigenschappen are nested sub-resources (`/zaken/{zaakUuid}/zaakeigenschappen`) - `_zoek` endpoint delegates to index and returns HTTP 201 (not 200) @@ -79,28 +79,28 @@ All controllers depend on `ZgwService` (`lib/Service/ZgwService.php`). Key metho ### DRC (Documenten) - **drc-009**: Document must be locked before updates. Lock ID must be provided and must match. - Binary content (`inhoud`) is stored as base64 in the request, decoded and saved to filesystem -- `inhoud` is NOT stored in OpenRegister — only as a Nextcloud file +- `inhoud` is NOT stored in OpenRegister: only as a Nextcloud file - Lock/unlock uses `locked` (bool) and `lockId` (string) fields on the OpenRegister object - On destroy, stored files must be cleaned up via `documentService->deleteFiles(uuid)` ### BRC (Besluiten) - **brc-001**: Standard besluit CRUD (create, update, patch) with besluittype validation - **brc-002**: Identificatie uniqueness under verantwoordelijke_organisatie; immutable on update -- **brc-003a**: BIO informatieobject URL validation — must resolve to a valid EIO -- **brc-004a/b**: BesluitInformatieObject is immutable — PUT/PATCH returns 405 -- **brc-005a**: Cross-register OIO sync — creating a BIO also creates an OIO in DRC with objectType=besluit +- **brc-003a**: BIO informatieobject URL validation: must resolve to a valid EIO +- **brc-004a/b**: BesluitInformatieObject is immutable: PUT/PATCH returns 405 +- **brc-005a**: Cross-register OIO sync: creating a BIO also creates an OIO in DRC with objectType=besluit - **brc-005b**: Deleting a BIO also deletes the corresponding OIO in DRC -- **brc-006a**: Zaak-besluit relation — checks both directions (BT.caseTypes -> ZT UUID, and ZT.decisionTypes -> BT omschrijving/UUID) +- **brc-006a**: Zaak-besluit relation: checks both directions (BT.caseTypes -> ZT UUID, and ZT.decisionTypes -> BT omschrijving/UUID) - **brc-007**: BesluitInformatieObject validates that informatieobjecttype is in besluittype.informatieobjecttypen - **brc-008a**: BIO create validates IOT is in BT.informatieobjecttypen -- **brc-009**: Cascade delete — deleting a besluit also deletes related BIOs and their OIOs in DRC; audit trail returns 404 for deleted besluiten +- **brc-009**: Cascade delete: deleting a besluit also deletes related BIOs and their OIOs in DRC; audit trail returns 404 for deleted besluiten ### NRC (Notificaties) - `notificatieCreate` endpoint just echoes the body back with HTTP 201 - Standard CRUD for kanaal and abonnement resources ### AC (Autorisaties) -- Completely custom — maps OpenRegister Consumers to ZGW Applicatie format +- Completely custom: maps OpenRegister Consumers to ZGW Applicatie format - Does NOT use the standard CRUD flow (no Twig mapping, no ObjectService) - `show('consumer')` with `?clientId=...` is a special lookup pattern @@ -133,11 +133,11 @@ preg_match('/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/i', ``` ### OpenRegister ObjectService API -- `find($uuid, register: $reg, schema: $schema)` — may return object or array -- `saveObject(register: $reg, schema: $schema, object: $data, uuid: $uuid)` — uuid optional for create -- `deleteObject(uuid: $uuid)` — delete by UUID -- `buildSearchQuery(requestParams: [...], register: $reg, schema: $schema)` — build query -- `searchObjectsPaginated(query: $query)` — returns `['results' => [...], 'total' => N]` +- `find($uuid, register: $reg, schema: $schema)`: may return object or array +- `saveObject(register: $reg, schema: $schema, object: $data, uuid: $uuid)`: uuid optional for create +- `deleteObject(uuid: $uuid)`: delete by UUID +- `buildSearchQuery(requestParams: [...], register: $reg, schema: $schema)`: build query +- `searchObjectsPaginated(query: $query)`: returns `['results' => [...], 'total' => N]` - Always handle both array and object returns: `is_array($obj) ? $obj : $obj->jsonSerialize()` ## Testing @@ -158,7 +158,7 @@ bash procest/tests/zgw/run-zgw-tests.sh --business-only --folder ztc # Business ### After making changes 1. Clear OPcache: `docker exec nextcloud apache2ctl graceful` 2. Run the relevant register's tests -3. Compare failures against baseline — new failures = regression +3. Compare failures against baseline: new failures = regression ### Known pre-existing test failures (baseline 2026-03-08) These failures exist before the controller split and are NOT regressions: @@ -175,7 +175,7 @@ These failures exist before the controller split and are NOT regressions: _Sub-agents: append new discoveries below this line. Include the date, register, and what you learned._ -### 2026-03-08 — DRC: drc-009 lock enforcement response format +### 2026-03-08: DRC: drc-009 lock enforcement response format The VNG business rules tests for drc-009 expect error responses in a specific `invalidParams` format: ```json @@ -195,7 +195,7 @@ Key distinctions: The PUT vs PATCH distinction matters: PUT treats `lock` as a required field, PATCH treats it as a missing lock enforcement error. -### 2026-03-08 — DRC: Force unlock scope check +### 2026-03-08: DRC: Force unlock scope check Force unlock (drc-009k) requires checking `documenten.geforceerd-bijwerken` scope via `consumerHasScope()`. When the lock ID doesn't match or is missing, the unlock endpoint checks if the consumer has this scope. If yes, force unlock succeeds (204). If no, returns 400. @@ -205,17 +205,17 @@ The `consumerHasScope()` method returns `true` (bypass) when: - Consumer not found in database - Consumer has `superuser: true` -### 2026-03-08 — DRC: OAS test lock status code +### 2026-03-08: DRC: OAS test lock status code The OAS test collection expects lock to return HTTP 201, while the business rules test (drc-009c) expects HTTP 200. The ZGW standard specifies 200 for lock. The lock endpoint returns 200. The OAS unlock test expects 201, but the ZGW standard and business rules (drc-009k) expect 204. The unlock endpoint returns 204. -### 2026-03-08 — DRC: Boolean normalization for locked field +### 2026-03-08: DRC: Boolean normalization for locked field OpenRegister may store boolean fields as strings (`"true"`, `"1"`) or integers (`1`, `0`). The lock/unlock/checkDocumentLock methods must normalize the `locked` field value before comparison. -### 2026-03-08 — ZRC business rules implementation +### 2026-03-08: ZRC business rules implementation **zrc-002a**: Unique identificatie enforcement. Added `checkIdentificatieUnique()` in `ZgwBusinessRulesService` that searches OpenRegister for existing zaken with the same `identifier` (and `sourceOrganisation`). Returns 400 with `identificatie-niet-uniek` error code. @@ -229,9 +229,9 @@ OpenRegister may store boolean fields as strings (`"true"`, `"1"`) or integers ( **zrc-007**: Closed zaak protection. The validation error now includes a top-level `code: "permission_denied"` field in the response, matching the VNG test expectation (`pm.response.json().code`). This required changes to both `ZgwBusinessRulesService` (adding `'code' => 'permission_denied'` to the rule result) and `ZgwService::buildValidationError()` (propagating the `code` field to the response data). -**Key finding**: The `VERTROUWELIJKHEID_LEVELS` ordering for authorization filtering is: openbaar(1) < beperkt_openbaar(2) < intern(3) < zaakvertrouwelijk(4) < vertrouwelijk(5) < confidentieel(6) < geheim(7) < zeer_geheim(8). Consumer's `maxVertrouwelijkheidaanduiding` sets the ceiling — zaken with a higher level are filtered out. +**Key finding**: The `VERTROUWELIJKHEID_LEVELS` ordering for authorization filtering is: openbaar(1) < beperkt_openbaar(2) < intern(3) < zaakvertrouwelijk(4) < vertrouwelijk(5) < confidentieel(6) < geheim(7) < zeer_geheim(8). Consumer's `maxVertrouwelijkheidaanduiding` sets the ceiling: zaken with a higher level are filtered out. -### 2026-03-08 — AC business rules implementation +### 2026-03-08: AC business rules implementation **ac-001**: ClientId uniqueness. `validateClientIdUniqueness()` iterates all existing consumers and checks both the primary `name` field and any extra clientIds stored in `authorizationConfiguration.clientIds`. Returns 400 with `clientId-exists` error code. @@ -277,7 +277,7 @@ ZTC types (zaaktypen, besluittypen) contain cross-reference arrays (informatieob VNG tests may send ZIOT `informatieobjecttype` as an omschrijving string that happens to be UUID-shaped. `rulesZaaktypeinformatieobjecttypenCreate` handles this by: (1) if it's a URL, keep as-is; (2) if it's a bare UUID, verify it exists in OR -- if not, fall back to name-based lookup; (3) if not a UUID, resolve by name. This prevents storing non-existent UUIDs when the value is actually an omschrijving that looks like a UUID. -### 2026-03-08 — BRC business rules implementation +### 2026-03-08: BRC business rules implementation **brc-003a fix**: The `validateInformatieobjectUrl()` in `ZgwRulesBase` had a bug where `extractUuid()` returning null caused the validation to silently pass (the `if ($ioUuid !== null && $this->objectService !== null)` condition was skipped). Fixed by adding an explicit null check that returns 400 when UUID extraction fails. @@ -293,7 +293,7 @@ VNG tests may send ZIOT `informatieobjecttype` as an omschrijving string that ha **Audit trail for deleted resources**: `BrcController::audittrailIndex()` checks if the parent resource exists before returning audit trail data. If the resource was soft-deleted, `find()` throws `DoesNotExistException`, and the controller returns 404. This satisfies brc-009d. -### 2026-03-08 — OpenRegister Magic Mapper soft delete gotcha +### 2026-03-08: OpenRegister Magic Mapper soft delete gotcha **CRITICAL**: OpenRegister's `ObjectService::deleteObject()` performs soft delete by calling `ObjectEntityMapper::update()`. But `update()` checks `shouldUseMagicMapperForRegisterSchema()` which reads `Register::isMagicMappingEnabledForSchema()`. If the register's `configuration` column is NULL or doesn't have the schema listed with `magicMapping: true`, the update falls through to the blob table `parent::update()` call, which operates on `oc_openregister_objects` (the blob table). Since the object only exists in the magic table (`oc_openregister_table_{register}_{schema}`), the soft delete appears to succeed (returns true) but the magic table row is NOT updated. diff --git a/docs/UseCases/_category_.json b/docs/UseCases/_category_.json new file mode 100644 index 000000000..6babf4f75 --- /dev/null +++ b/docs/UseCases/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Use Cases", + "position": 4, + "collapsible": true, + "collapsed": true +} diff --git a/docs/UseCases/index.md b/docs/UseCases/index.md new file mode 100644 index 000000000..4aff85ed2 --- /dev/null +++ b/docs/UseCases/index.md @@ -0,0 +1,9 @@ +--- +draft: true +title: Use Cases +sidebar_position: 1 +--- + +# Use Cases + +Real-world use case walkthroughs for Procest are being authored. Content authoring for this section is tracked in [issue #440](https://github.com/ConductionNL/procest/issues/440). diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index 15242d2ed..a275da4be 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -27,18 +27,12 @@ const config = createConfig({ organizationName: 'ConductionNL', projectName: 'procest', - /* English-only until the docs actually ship translated markdown. - Per ADR-030: a `locales` array carrying `nl` without a populated - `docs/i18n/nl/docusaurus-plugin-content-docs/current/` directory - of translated markdown triggers SSR rendering errors ("Cannot read - properties of undefined (reading 'id')") on tutorial pages when the - docs source moves faster than the locale's `current.json`. Trim to - `['en']`; re-add `nl` once the translation backfill lands. */ i18n: { defaultLocale: 'en', - locales: ['en'], + locales: ['en', 'nl'], localeConfigs: { en: { label: 'English' }, + nl: { label: 'Nederlands' }, }, }, @@ -71,6 +65,17 @@ const config = createConfig({ }, }, ], + [ + 'redocusaurus', + { + specs: [ + { + spec: 'static/oas/procest.json', + route: '/api/', + }, + ], + }, + ], ], themes: [BRAND_THEME, '@docusaurus/theme-mermaid'], @@ -87,6 +92,11 @@ const config = createConfig({ position: 'left', label: 'Documentation', }, + { + to: '/api/', + label: 'API Documentation', + position: 'left', + }, { href: 'https://github.com/ConductionNL/procest', label: 'GitHub', diff --git a/docs/features/app-scaffold.md b/docs/features/app-scaffold.md deleted file mode 100644 index 830b51ee0..000000000 --- a/docs/features/app-scaffold.md +++ /dev/null @@ -1,23 +0,0 @@ -# App Scaffold - -Procest application foundation — Nextcloud PHP app boilerplate, Webpack/Vue 2 build system, OpenRegister integration wiring, and initial register configuration. - -## Overview - -The app scaffold establishes the technical foundation for the Procest Nextcloud app: - -- **PHP app skeleton** — AppInfo, Application class, DI container wiring -- **Vue 2 frontend** — Webpack build, Pinia state management, Vue Router -- **OpenRegister wiring** — `ConfigurationService::importFromApp()` repair step, `procest_register.json` with 12 initial schemas -- **Object store pattern** — Pinia stores per entity type, OpenRegister API calls from frontend -- **Nextcloud integration** — Admin panel settings, navigation, sidebar - -## Archive Changes - -This feature consolidates: -- `create-procest-app` — initial app registration and boilerplate -- `procest-app-scaffold` — build system, Webpack/Vue setup -- `procest-object-store` — Pinia store foundation per entity -- `procest-case-management` — core case CRUD scaffolding - -See [administration.md](administration.md) and [case-management.md](case-management.md) for functional details. diff --git a/docs/README.md b/docs/index.md similarity index 61% rename from docs/README.md rename to docs/index.md index c782f9364..2b129a12c 100644 --- a/docs/README.md +++ b/docs/index.md @@ -1,3 +1,9 @@ +--- +id: intro +title: Introduction +sidebar_position: 1 +--- + # Procest Documentation Procest is a case management (zaakgericht werken) application for Nextcloud, designed for Dutch government organizations. It provides a complete case management solution built on top of OpenRegister. @@ -20,57 +26,57 @@ Procest is a case management (zaakgericht werken) application for Nextcloud, des | Feature | Description | Status | |---------|-------------|--------| -| [Dashboard](features/dashboard.md) | Overview with case statistics, status chart, and personal work queue | Implemented | -| [Case Management](features/case-management.md) | List, filter, and manage cases in table or card view | Implemented | -| [Case Dashboard View](features/case-dashboard-view.md) | Individual case detail page with status, tasks, and documents | In development | -| [My Work](features/my-work.md) | Personal work queue showing assigned cases and tasks | Implemented | -| [Task Management](features/task-management.md) | List, create, and manage tasks associated with cases | Implemented | -| [Case Types](features/case-types.md) | Configure case type definitions with ZGW-compliant properties | Implemented | -| [Admin Settings](features/admin-settings.md) | Application configuration, schema mapping, and version info | Implemented | -| [Zaaktype Configuratie](features/zaaktype-configuratie.md) | ZGW API field mapping between OpenRegister and Dutch ZGW standard | Implemented | +| [Dashboard](Features/dashboard.md) | Overview with case statistics, status chart, and personal work queue | Implemented | +| [Case Management](Features/case-management.md) | List, filter, and manage cases in table or card view | Implemented | +| [Case Dashboard View](Features/case-dashboard-view.md) | Individual case detail page with status, tasks, and documents | In development | +| [My Work](Features/my-work.md) | Personal work queue showing assigned cases and tasks | Implemented | +| [Task Management](Features/task-management.md) | List, create, and manage tasks associated with cases | Implemented | +| [Case Types](Features/case-types.md) | Configure case type definitions with ZGW-compliant properties | Implemented | +| [Admin Settings](Features/admin-settings.md) | Application configuration, schema mapping, and version info | Implemented | +| [Zaaktype Configuratie](Features/zaaktype-configuratie.md) | ZGW API field mapping between OpenRegister and Dutch ZGW standard | Implemented | ### Case Processing Features (text-only) | Feature | Description | Status | |---------|-------------|--------| -| [Werkvoorraad](features/werkvoorraad.md) | Team work queue for unassigned cases | Planned | -| [Roles and Decisions](features/roles-decisions.md) | Role assignment and formal decision recording | Partial | -| [Zaak Intake Flow](features/zaak-intake-flow.md) | Case registration and intake process | Planned | -| [Complaint Management](features/complaint-management.md) | Citizen complaint handling (klachtafhandeling) | Planned | -| [Consultation Management](features/consultation-management.md) | Public participation and consultation processes | Planned | -| [Milestone Tracking](features/milestone-tracking.md) | Case lifecycle checkpoint monitoring | Planned | -| [Case Email Integration](features/case-email-integration.md) | Email-to-case and case correspondence | Planned | -| [WOO Case Type](features/woo-case-type.md) | Open Government Act disclosure requests | Planned | -| [VTH Module](features/vth-module.md) | Permits, supervision, and enforcement | Planned | -| [Case Sharing](features/case-sharing-collaboration.md) | Multi-user and cross-org case collaboration | In development | -| [AI-Assisted Processing](features/ai-assisted-processing.md) | LLM-powered case analysis and document processing | In development | +| [Werkvoorraad](Features/werkvoorraad.md) | Team work queue for unassigned cases | Planned | +| [Roles and Decisions](Features/roles-decisions.md) | Role assignment and formal decision recording | Partial | +| [Zaak Intake Flow](Features/zaak-intake-flow.md) | Case registration and intake process | Planned | +| [Complaint Management](Features/complaint-management.md) | Citizen complaint handling (klachtafhandeling) | Planned | +| [Consultation Management](Features/consultation-management.md) | Public participation and consultation processes | Planned | +| [Milestone Tracking](Features/milestone-tracking.md) | Case lifecycle checkpoint monitoring | Planned | +| [Case Email Integration](Features/case-email-integration.md) | Email-to-case and case correspondence | Planned | +| [WOO Case Type](Features/woo-case-type.md) | Open Government Act disclosure requests | Planned | +| [VTH Module](Features/vth-module.md) | Permits, supervision, and enforcement | Planned | +| [Case Sharing](Features/case-sharing-collaboration.md) | Multi-user and cross-org case collaboration | In development | +| [AI-Assisted Processing](Features/ai-assisted-processing.md) | LLM-powered case analysis and document processing | In development | ### Administrative Features (text-only) | Feature | Description | Status | |---------|-------------|--------| -| [Appointment Scheduling](features/appointment-scheduling.md) | Meeting and hearing scheduling | Planned | -| [B&W Parafering](features/bw-parafering.md) | Executive approval workflow | Planned | -| [Legesberekening](features/legesberekening.md) | Municipal fee calculation | Planned | -| [Mobiel Inspectie](features/mobiel-inspectie.md) | Mobile field inspection interface | Planned | +| [Appointment Scheduling](Features/appointment-scheduling.md) | Meeting and hearing scheduling | Planned | +| [B&W Parafering](Features/bw-parafering.md) | Executive approval workflow | Planned | +| [Legesberekening](Features/legesberekening.md) | Municipal fee calculation | Planned | +| [Mobiel Inspectie](Features/mobiel-inspectie.md) | Mobile field inspection interface | Planned | ### Integration Features (text-only) | Feature | Description | Status | |---------|-------------|--------| -| [OpenRegister Integration](features/openregister-integration.md) | Core data layer via OpenRegister | Implemented | -| [MijnOverheid Integration](features/mijn-overheid-integration.md) | National citizen portal integration | Planned | -| [StUF Support](features/stuf-support.md) | Legacy Dutch government data exchange | Planned | +| [OpenRegister Integration](Features/openregister-integration.md) | Core data layer via OpenRegister | Implemented | +| [MijnOverheid Integration](Features/mijn-overheid-integration.md) | National citizen portal integration | Planned | +| [StUF Support](Features/stuf-support.md) | Legacy Dutch government data exchange | Planned | ### Platform Features (text-only) | Feature | Description | Status | |---------|-------------|--------| -| [Prometheus Metrics](features/prometheus-metrics.md) | Production monitoring and alerting | Planned | -| [Register i18n](features/register-i18n.md) | Multilingual support (nl/en) | Partial | -| [Base Register Seed Data](features/base-register-seed-data.md) | Pre-configured case types and definitions | Implemented | -| [Multi-Tenant SaaS](features/multi-tenant-saas.md) | Multi-organization support | Planned | -| [Case Definition Portability](features/case-definition-portability.md) | Export/import case type configurations | Planned | +| [Prometheus Metrics](Features/prometheus-metrics.md) | Production monitoring and alerting | Planned | +| [Register i18n](Features/register-i18n.md) | Multilingual support (nl/en) | Partial | +| [Base Register Seed Data](Features/base-register-seed-data.md) | Pre-configured case types and definitions | Implemented | +| [Multi-Tenant SaaS](Features/multi-tenant-saas.md) | Multi-organization support | Planned | +| [Case Definition Portability](Features/case-definition-portability.md) | Export/import case type configurations | Planned | ## Architecture diff --git a/docs/installation.md b/docs/installation.md new file mode 100644 index 000000000..9019a8429 --- /dev/null +++ b/docs/installation.md @@ -0,0 +1,98 @@ +--- +sidebar_position: 2 +title: Installation +--- + +# Installation + +This guide covers installing and configuring Procest in a Nextcloud environment. + +## Prerequisites + +- **Nextcloud 28 or higher**: Procest requires Nextcloud 28+ for full compatibility. +- **OpenRegister app**: Procest stores all case data (cases, tasks, decisions, case types) in OpenRegister. Install and enable OpenRegister before installing Procest. +- **PHP 8.1+**: Required by Nextcloud 28. +- **Database**: Any Nextcloud-supported database (PostgreSQL recommended for production). + +## Installation from the App Store + +1. Log in to Nextcloud as an administrator. +2. Open **Apps** from the top-right menu (or navigate to `/index.php/settings/apps`). +3. Search for **Procest** in the Apps catalog. +4. Click **Download and enable**. +5. Nextcloud installs the app and runs the initial repair step automatically. This repair step creates the `procest` register and imports the 12 base schemas (case, task, caseType, statusType, resultType, roleType, etc.) into OpenRegister. + +## Post-Install Configuration + +### Verify the Procest Register + +After installation, confirm the register was created: + +1. Navigate to **OpenRegister** in the left sidebar. +2. Under **Registers**, verify a register named `procest` exists with 12 schemas. +3. If the register is missing, re-run the repair step: go to **Admin settings** > **Procest** > click **Re-import configuration**. + +### Case Type Configuration + +Procest ships with seed data containing example case types. To configure your own: + +1. Open **Procest** from the left sidebar. +2. In the left navigation, click **Case Types**. +3. Click **Add case type** to create a new type. Set: + - **Name** and **Description** + - **Processing deadline** (in days, auto-calculates the case due date) + - **Allowed statuses** (ordered list of status types) + - **Allowed roles** (initiator, handler, advisor) +4. Set the status for the type to **Published** when ready for use. + +### ZGW API Endpoint Mapping + +If your organization uses ZGW-compliant systems (OpenZaak, Rx.Mission, etc.): + +1. Go to **Admin settings** > **Basic settings** > **Procest**. +2. Under **ZGW Configuration**, enter: + - **Zaken API URL**, e.g. `https://api.example.nl/zaken/api/v1` + - **Catalogi API URL**, e.g. `https://api.example.nl/catalogi/api/v1` + - **Besluiten API URL**, e.g. `https://api.example.nl/besluiten/api/v1` + - **API token / client credentials** as required by your ZGW provider. +3. Click **Save** and verify the connection using the **Test connection** button. + +## Troubleshooting + +### Register not found after installation + +**Symptom**: Procest opens but lists show "No items found" and the admin settings report a missing register. + +**Fix**: Re-run the repair step manually: + +```bash +php occ maintenance:repair --include-expensive +``` + +Or from the admin UI: **Admin settings** > **Procest** > **Re-import configuration**. + +### ZGW 400 / 422 errors + +**Symptom**: Case creation or status updates fail with ZGW API errors. + +**Causes and fixes**: +- **400 Bad Request**: Verify that the Catalogi API URL contains the `zaaktype` UUID you configured in the case type. The UUID must exist in the remote ZGW Catalogi. +- **422 Unprocessable Entity**: A required ZGW field (e.g., `bronorganisatie`, `verantwoordelijkeOrganisatie`) is missing. Check the ZGW field mapping in **Admin settings** > **Procest** > **ZGW mapping**. + +### Missing case types after import + +**Symptom**: The Case Types list is empty after installation. + +**Fix**: The seed data import is triggered by the repair step. Run: + +```bash +php occ maintenance:repair +``` + +If case types still do not appear, check OpenRegister logs at **OpenRegister** > **Logs** for import errors. + +### App not visible in navigation + +**Symptom**: Procest does not appear in the Nextcloud left sidebar. + +**Fix**: Confirm the app is enabled for your account. An administrator can check this at **Admin settings** > **Apps** > **Procest**. If the app is restricted to a group, ensure your account is a member of that group. diff --git a/docs/package-lock.json b/docs/package-lock.json index 0a58e1587..424b6990c 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -16,7 +16,8 @@ "clsx": "^1.2.1", "prism-react-renderer": "^1.3.5", "react": "^18.3.1", - "react-dom": "^18.3.1" + "react-dom": "^18.3.1", + "redocusaurus": "^2.0.0" }, "devDependencies": { "@docusaurus/module-type-aliases": "^3.7.0" @@ -4206,6 +4207,27 @@ "node": ">=20.0" } }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.4.0.tgz", + "integrity": "sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.9.0" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", + "license": "MIT" + }, + "node_modules/@exodus/schemasafe": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@exodus/schemasafe/-/schemasafe-1.3.0.tgz", + "integrity": "sha512-5Aap/GaRupgNx/feGBwLLTVv8OQFfv3pq2lPRzPg9R+IOBnDgghTGW7l7EuVXOvg5cc/xSAlRW8rBrjIC3Nvqw==", + "license": "MIT" + }, "node_modules/@hapi/hoek": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", @@ -4812,6 +4834,18 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/@nodable/entities": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-nyT7T3nbMyBI/lvr6L5TyWbFJAI9FTgVRakNoBqCD+PmID8DzFrrNdLLtHMwMszOtqZa8PAOV24ZqDnQrhQINA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/nodable" + } + ], + "license": "MIT" + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -5042,6 +5076,78 @@ "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", "license": "MIT" }, + "node_modules/@redocly/ajv": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/@redocly/ajv/-/ajv-8.18.3.tgz", + "integrity": "sha512-l42u0of3hY98sN2A+M4qTX1O/KrpgGH32Hu9kP2GtHyD5Dfqq86PKFLe5dwaD8DEnNmlOlll2BAmeEtf0DaySg==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@redocly/config": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@redocly/config/-/config-0.6.3.tgz", + "integrity": "sha512-hGWJgCsXRw0Ow4rplqRlUQifZvoSwZipkYnt11e3SeH1Eb23VUIDBcRuaQOUqy1wn0eevXkU2GzzQ8fbKdQ7Mg==", + "license": "MIT" + }, + "node_modules/@redocly/openapi-core": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-1.16.0.tgz", + "integrity": "sha512-z06h+svyqbUcdAaePq8LPSwTPlm6Ig7j2VlL8skPBYnJvyaQ2IN7x/JkOvRL4ta+wcOCBdAex5JWnZbKaNktJg==", + "license": "MIT", + "dependencies": { + "@redocly/ajv": "^8.11.0", + "@redocly/config": "^0.6.0", + "colorette": "^1.2.0", + "https-proxy-agent": "^7.0.4", + "js-levenshtein": "^1.1.6", + "js-yaml": "^4.1.0", + "lodash.isequal": "^4.5.0", + "minimatch": "^5.0.1", + "node-fetch": "^2.6.1", + "pluralize": "^8.0.0", + "yaml-ast-parser": "0.0.43" + }, + "engines": { + "node": ">=14.19.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@redocly/openapi-core/node_modules/brace-expansion": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@redocly/openapi-core/node_modules/colorette": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", + "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", + "license": "MIT" + }, + "node_modules/@redocly/openapi-core/node_modules/minimatch": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@sideway/address": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", @@ -6269,6 +6375,15 @@ "node": ">= 10.0.0" } }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, "node_modules/aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", @@ -6950,6 +7065,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/call-me-maybe": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz", + "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==", + "license": "MIT" + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -6981,6 +7102,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/camelize": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz", + "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/caniuse-api": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", @@ -7200,6 +7330,12 @@ "node": ">=8" } }, + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", + "license": "MIT" + }, "node_modules/clean-css": { "version": "5.3.3", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", @@ -7277,6 +7413,57 @@ "node": ">=8" } }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/clone-deep": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", @@ -7763,6 +7950,15 @@ "node": ">=4" } }, + "node_modules/css-color-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", + "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==", + "license": "ISC", + "engines": { + "node": ">=4" + } + }, "node_modules/css-declaration-sorter": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-7.3.1.tgz", @@ -7932,6 +8128,17 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/css-to-react-native": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz", + "integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==", + "license": "MIT", + "dependencies": { + "camelize": "^1.0.0", + "css-color-keywords": "^1.0.0", + "postcss-value-parser": "^4.0.2" + } + }, "node_modules/css-tree": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", @@ -8658,6 +8865,11 @@ } } }, + "node_modules/decko": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decko/-/decko-1.2.0.tgz", + "integrity": "sha512-m8FnyHXV1QX+S1cl+KPFDIl6NMkxtKsy6+U/aYyjrOqWMuwAwYWu7ePqrsUHtDR5Y8Yk2pi/KIDSgF+vT4cPOQ==" + }, "node_modules/decode-named-character-reference": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", @@ -8893,6 +9105,45 @@ "node": ">=6" } }, + "node_modules/docusaurus-plugin-redoc": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/docusaurus-plugin-redoc/-/docusaurus-plugin-redoc-2.5.0.tgz", + "integrity": "sha512-44sDhuXvItHnUuPdKswF3cRhiN5UW3YZxmMBsQLSfCYKcYr9tgWF2qvDfQoZO9i1DwpaYbIZ/RKMrSgny/iWYA==", + "license": "MIT", + "dependencies": { + "@redocly/openapi-core": "1.16.0", + "redoc": "2.4.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@docusaurus/utils": "^3.6.0" + } + }, + "node_modules/docusaurus-theme-redoc": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/docusaurus-theme-redoc/-/docusaurus-theme-redoc-2.5.0.tgz", + "integrity": "sha512-ykLmnnvE20Im3eABlIpUnXnT2gSHVAjgyy2fU2G8yecu7zqIE+G/SiBpBg/hrWMUycL31a8VSG7Ehkf3pg1u+A==", + "license": "MIT", + "dependencies": { + "@redocly/openapi-core": "1.16.0", + "clsx": "^1.2.1", + "lodash": "^4.17.21", + "mobx": "^6.12.4", + "postcss": "^8.4.45", + "postcss-prefix-selector": "^1.16.1", + "redoc": "2.4.0", + "styled-components": "^6.1.11" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@docusaurus/theme-common": "^3.6.0", + "webpack": "^5.0.0" + } + }, "node_modules/dom-converter": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", @@ -9148,6 +9399,12 @@ "node": ">= 0.4" } }, + "node_modules/es6-promise": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", + "integrity": "sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==", + "license": "MIT" + }, "node_modules/esast-util-from-estree": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/esast-util-from-estree/-/esast-util-from-estree-2.0.0.tgz", @@ -9592,6 +9849,12 @@ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "license": "MIT" }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "license": "MIT" + }, "node_modules/fast-uri": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", @@ -9608,6 +9871,44 @@ ], "license": "BSD-3-Clause" }, + "node_modules/fast-xml-builder": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.2.0.tgz", + "integrity": "sha512-00aAWieqff+ZJhsXA4g1g7M8k+7AYoMUUHF+/zFb5U6Uv/P0Vl4QZo84/IcufzYalLuEj9928bXN9PbbFzMF0Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "path-expression-matcher": "^1.5.0", + "xml-naming": "^0.1.0" + } + }, + "node_modules/fast-xml-parser": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.8.0.tgz", + "integrity": "sha512-6bIM7fsJxeo3uXv7OncQYsBAMPJ7V16Slahl/6M98C/i2q+vB1+4a0MtrvYwDFEUrwDSbAmeLDRXsOBwrL7yAg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "@nodable/entities": "^2.1.0", + "fast-xml-builder": "^1.2.0", + "path-expression-matcher": "^1.5.0", + "strnum": "^2.3.0", + "xml-naming": "^0.1.0" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, "node_modules/fastq": { "version": "1.20.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", @@ -9853,6 +10154,12 @@ } } }, + "node_modules/foreach": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.6.tgz", + "integrity": "sha512-k6GAGDyqLe9JaebCsFCoudPPWfihKu8pylYXRlqP1J7ms39iPoTtk2fviNglIeQEwdh0bQeKJ01ZPyuyQvKzwg==", + "license": "MIT" + }, "node_modules/form-data-encoder": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", @@ -9947,6 +10254,15 @@ "node": ">=6.9.0" } }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, "node_modules/get-intrinsic": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", @@ -10722,6 +11038,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/http2-client": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/http2-client/-/http2-client-1.3.5.tgz", + "integrity": "sha512-EC2utToWl4RKfs5zd36Mxq7nzHHBuomZboI0yYL6Y0RmBgT7Sgkq4rQ0ezFTYoIsSs7Tm9SJe+o2FcAg6GBhGA==", + "license": "MIT" + }, "node_modules/http2-wrapper": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", @@ -10735,6 +11057,19 @@ "node": ">=10.19.0" } }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", @@ -11303,6 +11638,15 @@ "@sideway/pinpoint": "^2.0.0" } }, + "node_modules/js-levenshtein": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", + "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -11345,6 +11689,15 @@ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "license": "MIT" }, + "node_modules/json-pointer": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/json-pointer/-/json-pointer-0.6.2.tgz", + "integrity": "sha512-vLWcKbOaXlO+jvRy4qNd+TI1QUPZzfJj1tpJ3vAXDych5XJf93ftpUKe5pKCrzyIIwgBJcOcCVRUfqQP25afBw==", + "license": "MIT", + "dependencies": { + "foreach": "^2.0.4" + } + }, "node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", @@ -11567,6 +11920,13 @@ "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", "license": "MIT" }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", + "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.", + "license": "MIT" + }, "node_modules/lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -11631,6 +11991,18 @@ "yallist": "^3.0.2" } }, + "node_modules/lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", + "license": "MIT" + }, + "node_modules/mark.js": { + "version": "8.11.1", + "resolved": "https://registry.npmjs.org/mark.js/-/mark.js-8.11.1.tgz", + "integrity": "sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==", + "license": "MIT" + }, "node_modules/markdown-extensions": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-2.0.0.tgz", @@ -14091,6 +14463,66 @@ "ufo": "^1.6.1" } }, + "node_modules/mobx": { + "version": "6.15.3", + "resolved": "https://registry.npmjs.org/mobx/-/mobx-6.15.3.tgz", + "integrity": "sha512-6+ZSYDs5zgH5CdGfEU2q2Lsa5PztVryL1ys7kAImTU25n2A9LAMj/yneVsQpd03MfwMLDQF+7kakJR9Z+cQxSw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mobx" + } + }, + "node_modules/mobx-react": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/mobx-react/-/mobx-react-9.2.1.tgz", + "integrity": "sha512-WJNNm0FB2n0Z0u+jS1QHmmWyV8l2WiAj8V8I/96kbUEN2YbYCoKW+hbbqKKRUBqElu0llxM7nWKehvRIkhBVJw==", + "license": "MIT", + "dependencies": { + "mobx-react-lite": "^4.1.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mobx" + }, + "peerDependencies": { + "mobx": "^6.9.0", + "react": "^16.8.0 || ^17 || ^18 || ^19" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/mobx-react-lite": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/mobx-react-lite/-/mobx-react-lite-4.1.1.tgz", + "integrity": "sha512-iUxiMpsvNraCKXU+yPotsOncNNmyeS2B5DKL+TL6Tar/xm+wwNJAubJmtRSeAoYawdZqwv8Z/+5nPRHeQxTiXg==", + "license": "MIT", + "dependencies": { + "use-sync-external-store": "^1.4.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mobx" + }, + "peerDependencies": { + "mobx": "^6.9.0", + "react": "^16.8.0 || ^17 || ^18 || ^19" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, "node_modules/mrmime": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", @@ -14177,10 +14609,51 @@ "node": ">=18" } }, - "node_modules/node-releases": { - "version": "2.0.27", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", - "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch-h2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/node-fetch-h2/-/node-fetch-h2-2.3.0.tgz", + "integrity": "sha512-ofRW94Ab0T4AOh5Fk8t0h8OBWrmjb0SSB20xh1H8YnPV9EJ+f5AMoYSUQ2zgJ4Iq2HAK0I2l5/Nequ8YzFS3Hg==", + "license": "MIT", + "dependencies": { + "http2-client": "^1.2.5" + }, + "engines": { + "node": "4.x || >=6.0.0" + } + }, + "node_modules/node-readfiles": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/node-readfiles/-/node-readfiles-0.2.0.tgz", + "integrity": "sha512-SU00ZarexNlE4Rjdm83vglt5Y9yiQ+XI1XpflWlb7q7UTN1JUItm69xMeiQCTxtTfnzt+83T8Cx+vI2ED++VDA==", + "license": "MIT", + "dependencies": { + "es6-promise": "^3.2.1" + } + }, + "node_modules/node-releases": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", "license": "MIT" }, "node_modules/normalize-path": { @@ -14303,6 +14776,76 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/oas-kit-common": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/oas-kit-common/-/oas-kit-common-1.0.8.tgz", + "integrity": "sha512-pJTS2+T0oGIwgjGpw7sIRU8RQMcUoKCDWFLdBqKB2BNmGpbBMH2sdqAaOXUg8OzonZHU0L7vfJu1mJFEiYDWOQ==", + "license": "BSD-3-Clause", + "dependencies": { + "fast-safe-stringify": "^2.0.7" + } + }, + "node_modules/oas-linter": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/oas-linter/-/oas-linter-3.2.2.tgz", + "integrity": "sha512-KEGjPDVoU5K6swgo9hJVA/qYGlwfbFx+Kg2QB/kd7rzV5N8N5Mg6PlsoCMohVnQmo+pzJap/F610qTodKzecGQ==", + "license": "BSD-3-Clause", + "dependencies": { + "@exodus/schemasafe": "^1.0.0-rc.2", + "should": "^13.2.1", + "yaml": "^1.10.0" + }, + "funding": { + "url": "https://github.com/Mermade/oas-kit?sponsor=1" + } + }, + "node_modules/oas-resolver": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/oas-resolver/-/oas-resolver-2.5.6.tgz", + "integrity": "sha512-Yx5PWQNZomfEhPPOphFbZKi9W93CocQj18NlD2Pa4GWZzdZpSJvYwoiuurRI7m3SpcChrnO08hkuQDL3FGsVFQ==", + "license": "BSD-3-Clause", + "dependencies": { + "node-fetch-h2": "^2.3.0", + "oas-kit-common": "^1.0.8", + "reftools": "^1.1.9", + "yaml": "^1.10.0", + "yargs": "^17.0.1" + }, + "bin": { + "resolve": "resolve.js" + }, + "funding": { + "url": "https://github.com/Mermade/oas-kit?sponsor=1" + } + }, + "node_modules/oas-schema-walker": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/oas-schema-walker/-/oas-schema-walker-1.1.5.tgz", + "integrity": "sha512-2yucenq1a9YPmeNExoUa9Qwrt9RFkjqaMAA1X+U7sbb0AqBeTIdMHky9SQQ6iN94bO5NW0W4TRYXerG+BdAvAQ==", + "license": "BSD-3-Clause", + "funding": { + "url": "https://github.com/Mermade/oas-kit?sponsor=1" + } + }, + "node_modules/oas-validator": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/oas-validator/-/oas-validator-5.0.8.tgz", + "integrity": "sha512-cu20/HE5N5HKqVygs3dt94eYJfBi0TsZvPVXDhbXQHiEityDN+RROTleefoKRKKJ9dFAF2JBkDHgvWj0sjKGmw==", + "license": "BSD-3-Clause", + "dependencies": { + "call-me-maybe": "^1.0.1", + "oas-kit-common": "^1.0.8", + "oas-linter": "^3.2.2", + "oas-resolver": "^2.5.6", + "oas-schema-walker": "^1.1.5", + "reftools": "^1.1.9", + "should": "^13.2.1", + "yaml": "^1.10.0" + }, + "funding": { + "url": "https://github.com/Mermade/oas-kit?sponsor=1" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -14412,6 +14955,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/openapi-sampler": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/openapi-sampler/-/openapi-sampler-1.7.3.tgz", + "integrity": "sha512-Qgy2+Z7xR3l7kXurtzi1PCtzAINkFKhBADBe/8cidC2fQrLUQTudLiJjQDnqJXoisWAR6zaHhC0hP6Hn5vja+g==", + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.7", + "fast-xml-parser": "^5.5.1", + "json-pointer": "0.6.2" + } + }, "node_modules/opener": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", @@ -14680,6 +15234,12 @@ "tslib": "^2.0.3" } }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "license": "MIT" + }, "node_modules/path-data-parser": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/path-data-parser/-/path-data-parser-0.1.0.tgz", @@ -14695,6 +15255,21 @@ "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, + "node_modules/path-expression-matcher": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.5.0.tgz", + "integrity": "sha512-cbrerZV+6rvdQrrD+iGMcZFEiiSrbv9Tfdkvnusy6y0x0GKBXREFg/Y65GhIfm0tnLntThhzCnfKwp1WRjeCyQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/path-is-inside": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", @@ -14740,6 +15315,12 @@ "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", "license": "MIT" }, + "node_modules/perfect-scrollbar": { + "version": "1.5.6", + "resolved": "https://registry.npmjs.org/perfect-scrollbar/-/perfect-scrollbar-1.5.6.tgz", + "integrity": "sha512-rixgxw3SxyJbCaSpo1n35A/fwI1r2rdwMKOTCg/AcG+xOEyZcE8UHVjpZMFCVImzsFoCZeJTT+M/rdEIQYO2nw==", + "license": "MIT" + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -14801,6 +15382,15 @@ "node": ">=16.0.0" } }, + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/points-on-curve": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/points-on-curve/-/points-on-curve-0.2.0.tgz", @@ -14817,6 +15407,18 @@ "points-on-curve": "0.2.0" } }, + "node_modules/polished": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/polished/-/polished-4.3.1.tgz", + "integrity": "sha512-OBatVyC/N7SCW/FaDHrSd+vn0o5cS855TOmYi4OkdWUMSJCET/xip//ch8xGUvtr3i44X9LVyWwQlRMTN3pwSA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.17.8" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/postcss": { "version": "8.5.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", @@ -15933,6 +16535,15 @@ "postcss": "^8.4" } }, + "node_modules/postcss-prefix-selector": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/postcss-prefix-selector/-/postcss-prefix-selector-1.16.1.tgz", + "integrity": "sha512-Umxu+FvKMwlY6TyDzGFoSUnzW+NOfMBLyC1tAkIjgX+Z/qGspJeRjVC903D7mx7TuBpJlwti2ibXtWuA7fKMeQ==", + "license": "MIT", + "peerDependencies": { + "postcss": ">4 <9" + } + }, "node_modules/postcss-preset-env": { "version": "10.6.1", "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-10.6.1.tgz", @@ -16661,6 +17272,28 @@ "react": ">=15" } }, + "node_modules/react-tabs": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/react-tabs/-/react-tabs-6.1.1.tgz", + "integrity": "sha512-CPiuKoMFf89B7QlbFfdBD9XmUWiE3qudQputMVZB8GQvPJZRX/gqjDaDWOPDwGinEfpJKEuBCkGt83Tt4efeyA==", + "license": "MIT", + "dependencies": { + "clsx": "^2.0.0", + "prop-types": "^15.5.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/react-tabs/node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", @@ -16754,12 +17387,96 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/redoc": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/redoc/-/redoc-2.4.0.tgz", + "integrity": "sha512-rFlfzFVWS9XJ6aYAs/bHnLhHP5FQEhwAHDBVgwb9L2FqDQ8Hu8rQ1G84iwaWXxZfPP9UWn7JdWkxI6MXr2ZDjw==", + "license": "MIT", + "dependencies": { + "@redocly/openapi-core": "^1.4.0", + "classnames": "^2.3.2", + "decko": "^1.2.0", + "dompurify": "^3.0.6", + "eventemitter3": "^5.0.1", + "json-pointer": "^0.6.2", + "lunr": "^2.3.9", + "mark.js": "^8.11.1", + "marked": "^4.3.0", + "mobx-react": "^9.1.1", + "openapi-sampler": "^1.5.0", + "path-browserify": "^1.0.1", + "perfect-scrollbar": "^1.5.5", + "polished": "^4.2.2", + "prismjs": "^1.29.0", + "prop-types": "^15.8.1", + "react-tabs": "^6.0.2", + "slugify": "~1.4.7", + "stickyfill": "^1.1.1", + "swagger2openapi": "^7.0.8", + "url-template": "^2.0.8" + }, + "engines": { + "node": ">=6.9", + "npm": ">=3.0.0" + }, + "peerDependencies": { + "core-js": "^3.1.4", + "mobx": "^6.0.4", + "react": "^16.8.4 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.4 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "styled-components": "^4.1.1 || ^5.1.1 || ^6.0.5" + } + }, + "node_modules/redoc/node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "license": "MIT" + }, + "node_modules/redoc/node_modules/marked": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/redocusaurus": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/redocusaurus/-/redocusaurus-2.5.0.tgz", + "integrity": "sha512-QWJX2hgnEfSDb7fZzS4iZe6aqdAvm/XLCsNv6RkgDw6Pl/lsTZKipP2n1r5QS1CC5hY8eAwsjVXeF7B03vkz2g==", + "license": "MIT", + "dependencies": { + "docusaurus-plugin-redoc": "2.5.0", + "docusaurus-theme-redoc": "2.5.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@docusaurus/theme-common": "^3.6.0", + "@docusaurus/utils": "^3.6.0" + } + }, "node_modules/reflect-metadata": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", "license": "Apache-2.0" }, + "node_modules/reftools": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/reftools/-/reftools-1.1.9.tgz", + "integrity": "sha512-OVede/NQE13xBQ+ob5CKd5KyeJYU2YInb1bmV4nRoOfquZPkAkxuOXicSe1PvqIuZZ4kD13sPKBbR7UFDmli6w==", + "license": "BSD-3-Clause", + "funding": { + "url": "https://github.com/Mermade/oas-kit?sponsor=1" + } + }, "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -17116,6 +17833,15 @@ "node": ">=0.10" } }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", @@ -17678,6 +18404,60 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/should": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/should/-/should-13.2.3.tgz", + "integrity": "sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ==", + "license": "MIT", + "dependencies": { + "should-equal": "^2.0.0", + "should-format": "^3.0.3", + "should-type": "^1.4.0", + "should-type-adaptors": "^1.0.1", + "should-util": "^1.0.0" + } + }, + "node_modules/should-equal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-2.0.0.tgz", + "integrity": "sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==", + "license": "MIT", + "dependencies": { + "should-type": "^1.4.0" + } + }, + "node_modules/should-format": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz", + "integrity": "sha512-hZ58adtulAk0gKtua7QxevgUaXTTXxIi8t41L3zo9AHvjXO1/7sdLECuHeIN2SRtYXpNkmhoUP2pdeWgricQ+Q==", + "license": "MIT", + "dependencies": { + "should-type": "^1.3.0", + "should-type-adaptors": "^1.0.1" + } + }, + "node_modules/should-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz", + "integrity": "sha512-MdAsTu3n25yDbIe1NeN69G4n6mUnJGtSJHygX3+oN0ZbO3DTiATnf7XnYJdGT42JCXurTb1JI0qOBR65shvhPQ==", + "license": "MIT" + }, + "node_modules/should-type-adaptors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.1.0.tgz", + "integrity": "sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA==", + "license": "MIT", + "dependencies": { + "should-type": "^1.3.0", + "should-util": "^1.0.0" + } + }, + "node_modules/should-util": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.1.tgz", + "integrity": "sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g==", + "license": "MIT" + }, "node_modules/side-channel": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", @@ -17822,6 +18602,15 @@ "node": ">=8" } }, + "node_modules/slugify": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.4.7.tgz", + "integrity": "sha512-tf+h5W1IrjNm/9rKKj0JU2MDMruiopx0jjVA5zCdBtcGjfp0+c5rHw/zADLC3IeKlGHtVbHtpfzvYA0OYT+HKg==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/snake-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", @@ -17971,6 +18760,11 @@ "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", "license": "MIT" }, + "node_modules/stickyfill": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stickyfill/-/stickyfill-1.1.1.tgz", + "integrity": "sha512-GCp7vHAfpao+Qh/3Flh9DXEJ/qSi0KJwJw6zYlZOtRYXWUIpMM6mC2rIep/dK8RQqwW0KxGJIllmjPIBOGN8AA==" + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -18094,6 +18888,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/strnum": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.3.0.tgz", + "integrity": "sha512-ums3KNd42PGyx5xaoVTO1mjU1bH3NpY4vsrVlnv9PNGqQj8wd7rJ6nEypLrJ7z5vxK5RP0yMLo6J/Gsm62DI5Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, "node_modules/style-to-js": { "version": "1.1.21", "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.21.tgz", @@ -18112,6 +18918,42 @@ "inline-style-parser": "0.2.7" } }, + "node_modules/styled-components": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.4.1.tgz", + "integrity": "sha512-ADu2dF53esUzzM4I0ewxhxFtsDd6v4V6dNkg3vG0iFKhnt06sJneTZnRvujAosZwW0XD58IKgGMQoqri4wHRqg==", + "license": "MIT", + "dependencies": { + "@emotion/is-prop-valid": "1.4.0", + "css-to-react-native": "3.2.0", + "csstype": "3.2.3", + "stylis": "4.3.6" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/styled-components" + }, + "peerDependencies": { + "css-to-react-native": ">= 3.2.0", + "react": ">= 16.8.0", + "react-dom": ">= 16.8.0", + "react-native": ">= 0.68.0" + }, + "peerDependenciesMeta": { + "css-to-react-native": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, "node_modules/stylehacks": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-6.1.1.tgz", @@ -18198,6 +19040,33 @@ "node": ">= 10" } }, + "node_modules/swagger2openapi": { + "version": "7.0.8", + "resolved": "https://registry.npmjs.org/swagger2openapi/-/swagger2openapi-7.0.8.tgz", + "integrity": "sha512-upi/0ZGkYgEcLeGieoz8gT74oWHA0E7JivX7aN9mAf+Tc7BQoRBvnIGHoPDw+f9TXTW4s6kGYCZJtauP6OYp7g==", + "license": "BSD-3-Clause", + "dependencies": { + "call-me-maybe": "^1.0.1", + "node-fetch": "^2.6.1", + "node-fetch-h2": "^2.3.0", + "node-readfiles": "^0.2.0", + "oas-kit-common": "^1.0.8", + "oas-resolver": "^2.5.6", + "oas-schema-walker": "^1.1.5", + "oas-validator": "^5.0.8", + "reftools": "^1.1.9", + "yaml": "^1.10.0", + "yargs": "^17.0.1" + }, + "bin": { + "boast": "boast.js", + "oas-validate": "oas-validate.js", + "swagger2openapi": "swagger2openapi.js" + }, + "funding": { + "url": "https://github.com/Mermade/oas-kit?sponsor=1" + } + }, "node_modules/tapable": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", @@ -18380,6 +19249,12 @@ "node": ">=6" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, "node_modules/tree-dump": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.1.0.tgz", @@ -18908,6 +19783,21 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/url-template": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", + "integrity": "sha512-XdVKMF4SJ0nP/O7XIPB0JwAEuT9lDIYnNsK8yGVe43y0AWoKeJNdv3ZNWh7ksJ6KqQFjOO6ox/VEitLnaVNufw==", + "license": "BSD" + }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -19089,6 +19979,12 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, "node_modules/webpack": { "version": "5.105.3", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.3.tgz", @@ -19482,6 +20378,16 @@ "node": ">=0.8.0" } }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -19661,12 +20567,98 @@ "xml-js": "bin/cli.js" } }, + "node_modules/xml-naming": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/xml-naming/-/xml-naming-0.1.0.tgz", + "integrity": "sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "license": "ISC" }, + "node_modules/yaml": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", + "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/yaml-ast-parser": { + "version": "0.0.43", + "resolved": "https://registry.npmjs.org/yaml-ast-parser/-/yaml-ast-parser-0.0.43.tgz", + "integrity": "sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==", + "license": "Apache-2.0" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/yocto-queue": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz", diff --git a/docs/package.json b/docs/package.json index 4635a9503..b5b9da0f3 100644 --- a/docs/package.json +++ b/docs/package.json @@ -23,7 +23,8 @@ "clsx": "^1.2.1", "prism-react-renderer": "^1.3.5", "react": "^18.3.1", - "react-dom": "^18.3.1" + "react-dom": "^18.3.1", + "redocusaurus": "^2.0.0" }, "devDependencies": { "@docusaurus/module-type-aliases": "^3.7.0" diff --git a/docs/static/oas/procest.json b/docs/static/oas/procest.json new file mode 100644 index 000000000..a94155e83 --- /dev/null +++ b/docs/static/oas/procest.json @@ -0,0 +1 @@ +{"openapi":"3.0.0","info":{"title":"Procest","version":"0.0.0"},"paths":{}} diff --git a/docs/tutorials/_category_.json b/docs/user-guide/_category_.json similarity index 83% rename from docs/tutorials/_category_.json rename to docs/user-guide/_category_.json index 5c460a648..0585889bb 100644 --- a/docs/tutorials/_category_.json +++ b/docs/user-guide/_category_.json @@ -1,11 +1,11 @@ { - "label": "Tutorials", + "label": "User Guide", "position": 2, "collapsible": true, "collapsed": false, "link": { "type": "generated-index", - "title": "Tutorials", + "title": "User Guide", "description": "Step-by-step walkthroughs for everyday tasks. The user track covers individual workflows; the admin track covers org-wide configuration." } } diff --git a/docs/tutorials/admin/01-configure-case-types.md b/docs/user-guide/admin/01-configure-case-types.md similarity index 77% rename from docs/tutorials/admin/01-configure-case-types.md rename to docs/user-guide/admin/01-configure-case-types.md index 826273d92..c1be0c0e7 100644 --- a/docs/tutorials/admin/01-configure-case-types.md +++ b/docs/user-guide/admin/01-configure-case-types.md @@ -6,7 +6,7 @@ description: Create a case type, define allowed statuses and transitions, attach # Configure case types and workflows -A case type is the template for every case of one kind — its statuses, allowed transitions, per-status deadlines, required documents, and default participants. This tutorial creates one from scratch. +A case type is the template for every case of one kind: its statuses, allowed transitions, per-status deadlines, required documents, and default participants. This tutorial creates one from scratch. ## Goal @@ -24,11 +24,11 @@ By the end you will have created a new case type, defined its status lifecycle, ![Case Types list](/screenshots/tutorials/admin/01-configure-case-types-01.png) -2. Click **Add Item**. The case-type dialog opens. Fill the basics — *Name* (e.g. *Vergunningaanvraag*), *Identification* (slug), *Description*, *Default confidentiality*, *Maximum lead time* (in days). +2. Click **Add Item**. The case-type dialog opens. Fill the basics: *Name* (e.g. *Vergunningaanvraag*), *Identification* (slug), *Description*, *Default confidentiality*, *Maximum lead time* (in days). ![New case type dialog](/screenshots/tutorials/admin/01-configure-case-types-02.png) -3. Open the **Statuses** tab on the dialog. Add the statuses your workflow needs (*Open*, *In behandeling*, *Wachten op aanvrager*, *Beslissen*, *Afgerond*). For each status set the *Allowed next statuses* — only those will appear in the transition dialog on a case. +3. Open the **Statuses** tab on the dialog. Add the statuses your workflow needs (*Open*, *In behandeling*, *Wachten op aanvrager*, *Beslissen*, *Afgerond*). For each status set the *Allowed next statuses*: only those will appear in the transition dialog on a case. ![Statuses and transitions](/screenshots/tutorials/admin/01-configure-case-types-03.png) @@ -36,7 +36,7 @@ By the end you will have created a new case type, defined its status lifecycle, ![Per-status deadlines](/screenshots/tutorials/admin/01-configure-case-types-04.png) -5. Open the **Documents** tab. Add the document types that must be present at each status — these power the document checklist on the case detail. Save the whole case type with **Save**. +5. Open the **Documents** tab. Add the document types that must be present at each status: these power the document checklist on the case detail. Save the whole case type with **Save**. ![Document checklist](/screenshots/tutorials/admin/01-configure-case-types-05.png) @@ -48,12 +48,12 @@ You have configured the case type correctly when: it appears in the **Case Types | Symptom | Fix | |---|---| -| **Add Item** opens a dialog with no form fields | The Case-type schema is not mapped — re-import configuration via [Manage Procest settings](./03-admin-settings.md). | +| **Add Item** opens a dialog with no form fields | The Case-type schema is not mapped: re-import configuration via [Manage Procest settings](./03-admin-settings.md). | | Status transitions on a new case do not match what you configured | The status mapping on the case-type may have been saved before the status schema was created; reopen and save again. | | Deadline never warns | The warning threshold is larger than the duration, or the case-type field is not mapped to the Case schema. | | Document checklist on the case is always empty | Document types live in a separate register; confirm the *informatieobjecttype* mapping under **ZGW API Mapping** is configured. | ## Reference -- [Case management](../../features/case-management.md) — model that case types drive. -- [Automatic actions](./02-automatic-actions.md) — task generation tied to case-type transitions. +- [Case management](../../Features/case-management.md): model that case types drive. +- [Automatic actions](./02-automatic-actions.md): task generation tied to case-type transitions. diff --git a/docs/tutorials/admin/02-automatic-actions.md b/docs/user-guide/admin/02-automatic-actions.md similarity index 81% rename from docs/tutorials/admin/02-automatic-actions.md rename to docs/user-guide/admin/02-automatic-actions.md index 005b14e05..b0c13f21e 100644 --- a/docs/tutorials/admin/02-automatic-actions.md +++ b/docs/user-guide/admin/02-automatic-actions.md @@ -1,7 +1,7 @@ --- sidebar_position: 2 title: Set up automatic actions -description: Create rules that fire on case events — create tasks, send notifications, transition status, kick off integrations. +description: "Create rules that fire on case events: create tasks, send notifications, transition status, kick off integrations." --- # Set up automatic actions @@ -24,7 +24,7 @@ By the end you will have created an automatic action that fires on a specific st ![Automatic actions list](/screenshots/tutorials/admin/02-automatic-actions-01.png) -2. Click **Add Item**. The rule dialog opens with four sections — *Algemeen* (name, description, active toggle), *Trigger*, *Condition*, *Action*. +2. Click **Add Item**. The rule dialog opens with four sections: *Algemeen* (name, description, active toggle), *Trigger*, *Condition*, *Action*. ![New automatic action dialog](/screenshots/tutorials/admin/02-automatic-actions-02.png) @@ -36,7 +36,7 @@ By the end you will have created an automatic action that fires on a specific st ![Conditions](/screenshots/tutorials/admin/02-automatic-actions-04.png) -5. Set the **Action**. Pick *Create task*, fill the task title, description, assignee role, and due-date offset. Save the rule with **Save**. Confirm the rule is *Active* in the list — only active rules fire. +5. Set the **Action**. Pick *Create task*, fill the task title, description, assignee role, and due-date offset. Save the rule with **Save**. Confirm the rule is *Active* in the list: only active rules fire. ![Action and save](/screenshots/tutorials/admin/02-automatic-actions-05.png) @@ -50,10 +50,10 @@ You have set up the action correctly when: triggering the configured status tran |---|---| | Rule is configured but never fires | The rule's *Active* toggle is off, or the trigger case-type does not match the case-type you tested on. | | Task is created but unassigned | The configured assignee role is not present on the case; add it to the case's Participants or update the rule to use a role that exists. | -| Action runs but no notification arrives | The notification action uses Nextcloud's mail; SMTP must be configured at the server level (the dev environment intentionally disables outgoing mail — see [PROJECT MEMORY notes on mail](../../#mail-notifications)). | -| Condition does not match what you expect | Open the rule's *Last run* details — the recorded field values clarify why the condition skipped. | +| Action runs but no notification arrives | The notification action uses Nextcloud's mail; SMTP must be configured at the server level (the dev environment intentionally disables outgoing mail: see [PROJECT MEMORY notes on mail](../../#mail-notifications)). | +| Condition does not match what you expect | Open the rule's *Last run* details: the recorded field values clarify why the condition skipped. | ## Reference -- [Configure case types and workflows](./01-configure-case-types.md) — defines the triggers (statuses, deadlines). -- [Case management](../../features/case-management.md) — the underlying event stream rules listen to. +- [Configure case types and workflows](./01-configure-case-types.md): defines the triggers (statuses, deadlines). +- [Case management](../../Features/case-management.md): the underlying event stream rules listen to. diff --git a/docs/tutorials/admin/03-admin-settings.md b/docs/user-guide/admin/03-admin-settings.md similarity index 66% rename from docs/tutorials/admin/03-admin-settings.md rename to docs/user-guide/admin/03-admin-settings.md index 79a572922..b26c6c6a0 100644 --- a/docs/tutorials/admin/03-admin-settings.md +++ b/docs/user-guide/admin/03-admin-settings.md @@ -1,12 +1,12 @@ --- sidebar_position: 3 title: Manage Procest settings -description: Walk the Administration → Procest settings page — version, register configuration, ZGW mapping, map layers, AI features. +description: "Walk the Administration > Procest settings page: version, register configuration, ZGW mapping, map layers, AI features." --- # Manage Procest settings -The **Administration settings → Procest** page is the single pane for everything you configure once and then forget — the version banner, the OpenRegister mapping, the ZGW API mapping, GIS map layers, and the AI-assisted processing toggles. +The **Administration settings → Procest** page is the single pane for everything you configure once and then forget: the version banner, the OpenRegister mapping, the ZGW API mapping, GIS map layers, and the AI-assisted processing toggles. ## Goal @@ -19,15 +19,15 @@ By the end you will have opened the Administration settings page, re-imported th ## Steps -1. Open **Administration settings → Procest** (left navigation under *Administration*). The header reads *Administration settings: Procest* and the body has five sections — *Version Information*, *Configuration*, *Case Type Management*, *Map Layers*, *ZGW API Mapping*, *AI-Assisted Processing*. +1. Open **Administration settings → Procest** (left navigation under *Administration*). The header reads *Administration settings: Procest* and the body has five sections: *Version Information*, *Configuration*, *Case Type Management*, *Map Layers*, *ZGW API Mapping*, *AI-Assisted Processing*. ![Admin settings landing](/screenshots/tutorials/admin/03-admin-settings-01.png) -2. The **Version Information** card shows the installed version (e.g. *Procest 0.2.0*) and an **Up to date** badge. Click **Re-import configuration** to (re-)run the OpenRegister import — needed on first install and whenever a Procest release bumps the schemas. Confirm the success toast. +2. The **Version Information** card shows the installed version (e.g. *Procest 0.2.0*) and an **Up to date** badge. Click **Re-import configuration** to (re-)run the OpenRegister import: needed on first install and whenever a Procest release bumps the schemas. Confirm the success toast. ![Re-import configuration](/screenshots/tutorials/admin/03-admin-settings-02.png) -3. Scroll to **Configuration**. Pick the *Register* (e.g. *Procest*) from the first dropdown — the rest of the fields (*Case schema*, *Task schema*, *Status schema*, *Role schema*, *Result schema*, *Decision schema*, *Case type schema*, *Status type schema*) auto-fill from the register. Click **Save** to persist. +3. Scroll to **Configuration**. Pick the *Register* (e.g. *Procest*) from the first dropdown: the rest of the fields (*Case schema*, *Task schema*, *Status schema*, *Role schema*, *Result schema*, *Decision schema*, *Case type schema*, *Status type schema*) auto-fill from the register. Click **Save** to persist. ![Register and schema mapping](/screenshots/tutorials/admin/03-admin-settings-03.png) @@ -47,14 +47,14 @@ You have configured Procest correctly when: *Version Information* shows *Up to d | Symptom | Fix | |---|---| -| **Re-import configuration** errors out | Open Nextcloud → Settings → Logs and read the OpenRegister `ImportHandler` errors; usually a schema with an invalid type — fix the configuration JSON and re-run. | -| Schema dropdowns are empty | The register is not imported yet — click **Re-import configuration** first, then refresh. | +| **Re-import configuration** errors out | Open Nextcloud → Settings → Logs and read the OpenRegister `ImportHandler` errors; usually a schema with an invalid type: fix the configuration JSON and re-run. | +| Schema dropdowns are empty | The register is not imported yet: click **Re-import configuration** first, then refresh. | | ZGW mapping table shows only *Not configured* | Map each row by hand or via the **Reset** button to re-populate defaults. The *zaak* row is the minimum needed for the ZGW API. | | Map layers section "No map layers configured" warning | Click **PDOK presets** to add the standard Dutch PDOK layers in one click. | -| AI features show but never respond | The AI endpoint is not configured at the server level — check the Nextcloud Assistant / LLM settings. | +| AI features show but never respond | The AI endpoint is not configured at the server level: check the Nextcloud Assistant / LLM settings. | ## Reference -- [Administration](../../features/administration.md) — the page this tutorial documents. -- [Admin settings](../../features/admin-settings.md) — field reference. -- [Configure case types and workflows](./01-configure-case-types.md) — the next thing to configure once settings are in place. +- [Administration](../../Features/administration.md): the page this tutorial documents. +- [Admin settings](../../Features/admin-settings.md): field reference. +- [Configure case types and workflows](./01-configure-case-types.md): the next thing to configure once settings are in place. diff --git a/docs/tutorials/admin/_category_.json b/docs/user-guide/admin/_category_.json similarity index 100% rename from docs/tutorials/admin/_category_.json rename to docs/user-guide/admin/_category_.json diff --git a/docs/tutorials/user/01-first-launch.md b/docs/user-guide/user/01-first-launch.md similarity index 53% rename from docs/tutorials/user/01-first-launch.md rename to docs/user-guide/user/01-first-launch.md index 2b66c46a1..9c4d74de2 100644 --- a/docs/tutorials/user/01-first-launch.md +++ b/docs/user-guide/user/01-first-launch.md @@ -6,7 +6,7 @@ description: Open Procest, walk the navigation, and confirm the OpenRegister bac # Open Procest for the first time -A first look at Procest — where the app lives, what the navigation gives you, and how to tell it is connected to OpenRegister. +A first look at Procest: where the app lives, what the navigation gives you, and how to tell it is connected to OpenRegister. ## Goal @@ -15,7 +15,7 @@ By the end you will have opened the Procest app, found your way around the dashb ## Prerequisites - A Nextcloud account on an instance where the **Procest** app is installed and enabled. -- The **OpenRegister** app installed and enabled — Procest stores cases, tasks, decisions and case types in OpenRegister, so it is a hard dependency. +- The **OpenRegister** app installed and enabled: Procest stores cases, tasks, decisions and case types in OpenRegister, so it is a hard dependency. - The Procest register and its schemas imported. An admin runs this once from **Administration settings → Procest → Re-import configuration** (see [Manage Procest settings](../admin/03-admin-settings.md)). ## Steps @@ -24,32 +24,32 @@ By the end you will have opened the Procest app, found your way around the dashb ![Procest dashboard](/screenshots/tutorials/user/01-first-launch-01.png) -2. Read the dashboard widgets — *Cases by Status*, *Cases by Type*, *My Work*, *Deadline Alerts*, *Task Due Reminders*, *Stalled Cases*, *Case Map*. On a fresh install they read *Widget not available* until cases are created and the register is fully configured. +2. Read the dashboard widgets: *Cases by Status*, *Cases by Type*, *My Work*, *Deadline Alerts*, *Task Due Reminders*, *Stalled Cases*, *Case Map*. On a fresh install they read *Widget not available* until cases are created and the register is fully configured. ![Dashboard widgets](/screenshots/tutorials/user/01-first-launch-02.png) -3. Open the left-hand navigation. The top group is your day-to-day work — **Dashboard**, **My Work**, **Work Queue**, **Cases**, **Bezwaren**, **Beroepen**, **Beslissingen op bezwaar**, **Tasks**, **Map**, **Voorstellen**, **Advice**, **BAC-adviezen**, **Transfers**. Below the divider sits the configuration group — **Case Types**, **Legesverordeningen**, **Parafeerroutes**, **Automatische acties**, **Handhavingsstrategie**, and the rest of the admin entries — ending in **Settings**. +3. Open the left-hand navigation. The top group is your day-to-day work: **Dashboard**, **My Work**, **Work Queue**, **Cases**, **Bezwaren**, **Beroepen**, **Beslissingen op bezwaar**, **Tasks**, **Map**, **Voorstellen**, **Advice**, **BAC-adviezen**, **Transfers**. Below the divider sits the configuration group: **Case Types**, **Legesverordeningen**, **Parafeerroutes**, **Automatische acties**, **Handhavingsstrategie**, and the rest of the admin entries: ending in **Settings**. ![Procest navigation](/screenshots/tutorials/user/01-first-launch-03.png) -4. Click **Cases**. The list view opens with a *Cards / Table* toggle, an **Add Item** button, and a search/actions row. An empty install shows *No items found* — expected until someone creates the first case. +4. Click **Cases**. The list view opens with a *Cards / Table* toggle, an **Add Item** button, and a search/actions row. An empty install shows *No items found*: expected until someone creates the first case. ![Cases list, empty state](/screenshots/tutorials/user/01-first-launch-04.png) ## Verification -You are set up correctly when: the Procest dashboard renders without an error banner, the left navigation lists the entries above, and clicking **Cases** (or any other list) shows either rows or a clean *No items found* state — not a load error. +You are set up correctly when: the Procest dashboard renders without an error banner, the left navigation lists the entries above, and clicking **Cases** (or any other list) shows either rows or a clean *No items found* state: not a load error. ## Common issues | Symptom | Fix | |---|---| | "OpenRegister is not installed or enabled" banner | Install and enable the OpenRegister app, then reload Procest. | -| Lists load but **Add Item** opens a dialog with no form fields | The Procest register import is incomplete — an admin re-runs **Administration settings → Procest → Re-import configuration**. | -| Procest is missing from the app menu | The app is not enabled for your account — ask an administrator to enable it (and check it is not restricted to a group you are not in). | -| Dashboard widgets all read *Widget not available* | The register is not connected — see [Manage Procest settings](../admin/03-admin-settings.md). | +| Lists load but **Add Item** opens a dialog with no form fields | The Procest register import is incomplete: an admin re-runs **Administration settings → Procest → Re-import configuration**. | +| Procest is missing from the app menu | The app is not enabled for your account: ask an administrator to enable it (and check it is not restricted to a group you are not in). | +| Dashboard widgets all read *Widget not available* | The register is not connected: see [Manage Procest settings](../admin/03-admin-settings.md). | ## Reference -- [Case management](../../features/case-management.md) — the data model and lifecycle behind every list. -- [Manage Procest settings](../admin/03-admin-settings.md) — register import, schema mapping, ZGW configuration. +- [Case management](../../Features/case-management.md): the data model and lifecycle behind every list. +- [Manage Procest settings](../admin/03-admin-settings.md): register import, schema mapping, ZGW configuration. diff --git a/docs/tutorials/user/02-my-work.md b/docs/user-guide/user/02-my-work.md similarity index 66% rename from docs/tutorials/user/02-my-work.md rename to docs/user-guide/user/02-my-work.md index e3acc47f8..34ece1273 100644 --- a/docs/tutorials/user/02-my-work.md +++ b/docs/user-guide/user/02-my-work.md @@ -6,7 +6,7 @@ description: Use the My Work page to see everything assigned to you across cases # Find your work in My Work -The My Work page is the personal queue every case-handler starts the day on — every case and task assigned to you, in one list, with tabs for filtering and a "Ter parafering" panel for items waiting on your initial. +The My Work page is the personal queue every case-handler starts the day on: every case and task assigned to you, in one list, with tabs for filtering and a "Ter parafering" panel for items waiting on your initial. ## Goal @@ -15,7 +15,7 @@ By the end you will have opened My Work, used the tabs to switch between cases a ## Prerequisites - Completed [Open Procest for the first time](./01-first-launch.md). -- At least one case or task assigned to your user — otherwise the list is legitimately empty. +- At least one case or task assigned to your user: otherwise the list is legitimately empty. ## Steps @@ -23,7 +23,7 @@ By the end you will have opened My Work, used the tabs to switch between cases a ![My Work landing](/screenshots/tutorials/user/02-my-work-01.png) -2. The top row holds three tabs — **All**, **Cases**, **Tasks** — each with its own count. Click **Cases** to limit the list to cases; click **Tasks** for tasks only. +2. The top row holds three tabs: **All**, **Cases**, **Tasks**: each with its own count. Click **Cases** to limit the list to cases; click **Tasks** for tasks only. ![My Work tabs](/screenshots/tutorials/user/02-my-work-02.png) @@ -31,7 +31,7 @@ By the end you will have opened My Work, used the tabs to switch between cases a ![Show completed toggle](/screenshots/tutorials/user/02-my-work-03.png) -4. Scroll to the **Ter parafering** panel at the bottom — proposals waiting on your initial as part of the paraferingsroute (see [BW Parafering](../../features/bw-parafering.md)). Empty means there is nothing waiting on you. +4. Scroll to the **Ter parafering** panel at the bottom: proposals waiting on your initial as part of the paraferingsroute (see [BW Parafering](../../Features/bw-parafering.md)). Empty means there is nothing waiting on you. ![Ter parafering panel](/screenshots/tutorials/user/02-my-work-04.png) @@ -43,11 +43,11 @@ You are set up correctly when: the My Work page shows counts on each tab, the *S | Symptom | Fix | |---|---| -| All tabs read `(0)` even though cases exist | The case is not assigned to your user — open the case and add yourself to a role from **Participants**. | +| All tabs read `(0)` even though cases exist | The case is not assigned to your user: open the case and add yourself to a role from **Participants**. | | *Ter parafering* shows "Geen voorstellen ter parafering" but you expect items | The paraferingsroute step has not been triggered, or your user is not on the step's role; ask an admin to check the route under **Parafeerroutes**. | | Tabs render but never load | Hard-reload the page; if the issue persists check the browser console for OpenRegister fetch errors. | ## Reference -- [Case management](../../features/case-management.md) — the data model behind My Work entries. -- [BW Parafering](../../features/bw-parafering.md) — how items end up in *Ter parafering*. +- [Case management](../../Features/case-management.md): the data model behind My Work entries. +- [BW Parafering](../../Features/bw-parafering.md): how items end up in *Ter parafering*. diff --git a/docs/tutorials/user/03-view-case.md b/docs/user-guide/user/03-view-case.md similarity index 72% rename from docs/tutorials/user/03-view-case.md rename to docs/user-guide/user/03-view-case.md index a29d53147..a0eca4c27 100644 --- a/docs/tutorials/user/03-view-case.md +++ b/docs/user-guide/user/03-view-case.md @@ -6,7 +6,7 @@ description: Open a case from the list, read its detail view, and walk the sideb # Open and read a case -How to find a case, open it, and recognise the parts of the detail view — the header, the status timeline, and the sidebar tabs (Tasks, Documents, Participants, History, …). +How to find a case, open it, and recognise the parts of the detail view: the header, the status timeline, and the sidebar tabs (Tasks, Documents, Participants, History, …). ## Goal @@ -15,7 +15,7 @@ By the end you will have opened the Cases list, located a case by search or filt ## Prerequisites - Completed [Open Procest for the first time](./01-first-launch.md). -- At least one case in the register — otherwise the list shows *No items found*. +- At least one case in the register: otherwise the list shows *No items found*. ## Steps @@ -23,11 +23,11 @@ By the end you will have opened the Cases list, located a case by search or filt ![Cases list view](/screenshots/tutorials/user/03-view-case-01.png) -2. Switch between **Cards** and **Table** with the radio toggle. Cards show the rich preview (status pill, deadline, handler avatar). Table is denser — better for scanning a long list. Use the search row at the right to filter by title, identifier, or status. +2. Switch between **Cards** and **Table** with the radio toggle. Cards show the rich preview (status pill, deadline, handler avatar). Table is denser: better for scanning a long list. Use the search row at the right to filter by title, identifier, or status. ![Cards vs Table toggle](/screenshots/tutorials/user/03-view-case-02.png) -3. Click a row (or a card) to open the case. The detail view loads with a header band — case title, identifier, status pill, deadline countdown, confidentiality badge — and a sidebar on the right. +3. Click a row (or a card) to open the case. The detail view loads with a header band: case title, identifier, status pill, deadline countdown, confidentiality badge: and a sidebar on the right. ![Case detail header](/screenshots/tutorials/user/03-view-case-03.png) @@ -43,11 +43,11 @@ You are reading the case correctly when: the header shows a non-empty status pil | Symptom | Fix | |---|---| -| Detail view opens but body is empty | The case schema fields are not mapped — see [Manage Procest settings](../admin/03-admin-settings.md) and re-import the configuration. | +| Detail view opens but body is empty | The case schema fields are not mapped: see [Manage Procest settings](../admin/03-admin-settings.md) and re-import the configuration. | | Status pill is blank | The case has no current status; open the **History** tab to confirm a starting status was set, or transition it via [Move a case through its workflow](./04-advance-case.md). | | Search field returns nothing | Search is case-sensitive by default; clear filters with the *X* in the search row. | ## Reference -- [Case dashboard view](../../features/case-dashboard-view.md) — the layout convention used by the case detail page. -- [Case management](../../features/case-management.md) — the model behind cases and their statuses. +- [Case dashboard view](../../Features/case-dashboard-view.md): the layout convention used by the case detail page. +- [Case management](../../Features/case-management.md): the model behind cases and their statuses. diff --git a/docs/tutorials/user/04-advance-case.md b/docs/user-guide/user/04-advance-case.md similarity index 70% rename from docs/tutorials/user/04-advance-case.md rename to docs/user-guide/user/04-advance-case.md index d2c34e440..223f3e145 100644 --- a/docs/tutorials/user/04-advance-case.md +++ b/docs/user-guide/user/04-advance-case.md @@ -6,7 +6,7 @@ description: Transition a case to the next status, complete required tasks, and # Move a case through its workflow -Cases in Procest follow a configurable workflow — each case-type defines its allowed statuses and the transitions between them. This tutorial walks one case from intake to closure. +Cases in Procest follow a configurable workflow: each case-type defines its allowed statuses and the transitions between them. This tutorial walks one case from intake to closure. ## Goal @@ -20,11 +20,11 @@ By the end you will have opened a case, transitioned it through at least one sta ## Steps -1. Open the case detail view. The header shows the current status pill — for a fresh case usually *Open* or *In behandeling*. +1. Open the case detail view. The header shows the current status pill: for a fresh case usually *Open* or *In behandeling*. ![Case header, current status](/screenshots/tutorials/user/04-advance-case-01.png) -2. Click the status pill (or the **Change status** button on the header bar). A dialog opens with the allowed next statuses for this case-type — only valid transitions appear. +2. Click the status pill (or the **Change status** button on the header bar). A dialog opens with the allowed next statuses for this case-type: only valid transitions appear. ![Status transition dialog](/screenshots/tutorials/user/04-advance-case-02.png) @@ -32,11 +32,11 @@ By the end you will have opened a case, transitioned it through at least one sta ![Confirm status change](/screenshots/tutorials/user/04-advance-case-03.png) -4. Open the **Tasks** tab in the sidebar — automatic actions for the new status may have created fresh tasks (e.g. "Review by manager", "Send confirmation"). Required tasks must be completed before the next transition is offered. +4. Open the **Tasks** tab in the sidebar: automatic actions for the new status may have created fresh tasks (e.g. "Review by manager", "Send confirmation"). Required tasks must be completed before the next transition is offered. ![Tasks created by transition](/screenshots/tutorials/user/04-advance-case-04.png) -5. Open the **History** tab — the transition is logged with who, when, from-status, to-status, and the reason. This timeline is the audit trail. +5. Open the **History** tab: the transition is logged with who, when, from-status, to-status, and the reason. This timeline is the audit trail. ![History timeline](/screenshots/tutorials/user/04-advance-case-05.png) @@ -49,12 +49,12 @@ You have transitioned correctly when: the header status pill matches the target, | Symptom | Fix | |---|---| | Status pill is greyed out / not clickable | You do not hold a role that may transition this case; ask an admin to add you as a handler. | -| Dialog shows "No transitions available" | The case is at a terminal status, or the case-type has no outgoing transitions defined — see [Configure case types and workflows](../admin/01-configure-case-types.md). | +| Dialog shows "No transitions available" | The case is at a terminal status, or the case-type has no outgoing transitions defined: see [Configure case types and workflows](../admin/01-configure-case-types.md). | | Required tasks block the next transition | Complete the open Tasks listed in the sidebar, or have a colleague complete tasks assigned to them. | | Deadline does not re-base | The case-type has no per-status deadline configured; this is configuration not a bug. | ## Reference -- [Case management](../../features/case-management.md) — model and lifecycle. -- [Configure case types and workflows](../admin/01-configure-case-types.md) — defining the allowed transitions. -- [Automatic actions](../admin/02-automatic-actions.md) — task generation rules. +- [Case management](../../Features/case-management.md): model and lifecycle. +- [Configure case types and workflows](../admin/01-configure-case-types.md): defining the allowed transitions. +- [Automatic actions](../admin/02-automatic-actions.md): task generation rules. diff --git a/docs/tutorials/user/05-record-decision.md b/docs/user-guide/user/05-record-decision.md similarity index 78% rename from docs/tutorials/user/05-record-decision.md rename to docs/user-guide/user/05-record-decision.md index 2e1ea4053..52443d746 100644 --- a/docs/tutorials/user/05-record-decision.md +++ b/docs/user-guide/user/05-record-decision.md @@ -6,7 +6,7 @@ description: Capture an advisory (advies) or a formal decision (besluit) on a ca # Record advice or a decision on a case -A decision is the formal outcome of a case — granted, refused, partially granted, withdrawn. Advice is the non-binding recommendation that often precedes it. Both are first-class objects in Procest and live in their own lists. +A decision is the formal outcome of a case: granted, refused, partially granted, withdrawn. Advice is the non-binding recommendation that often precedes it. Both are first-class objects in Procest and live in their own lists. ## Goal @@ -32,7 +32,7 @@ By the end you will have added a piece of advice to a case, recorded a formal de ![Decision dialog](/screenshots/tutorials/user/05-record-decision-03.png) -4. Pick the outcome — typically one of *Granted*, *Refused*, *Partially granted*, *Withdrawn*. The decision-maker role is filled from the case's participants; override it if needed. Click **Save**. +4. Pick the outcome: typically one of *Granted*, *Refused*, *Partially granted*, *Withdrawn*. The decision-maker role is filled from the case's participants; override it if needed. Click **Save**. ![Decision outcome](/screenshots/tutorials/user/05-record-decision-04.png) @@ -49,10 +49,10 @@ You have recorded the decision correctly when: the case header shows the new out | Symptom | Fix | |---|---| | **Add advice** / **Record decision** is missing from the Actions menu | The current status does not permit it; transition the case to an "advisory" or "decision-ready" status first (see [Move a case through its workflow](./04-advance-case.md)). | -| Dialog opens but fields are empty / unmapped | The Advice or Decision schema is not mapped — re-import the register configuration (see [Manage Procest settings](../admin/03-admin-settings.md)). | +| Dialog opens but fields are empty / unmapped | The Advice or Decision schema is not mapped: re-import the register configuration (see [Manage Procest settings](../admin/03-admin-settings.md)). | | Outcome dropdown is empty | The Result schema has no seed values; an admin populates them via the **Result** schema in OpenRegister. | ## Reference -- [Besluitvorming workflow](../../features/besluitvorming-workflow.md) — the advisory-to-decision pattern. -- [Configure case types and workflows](../admin/01-configure-case-types.md) — controlling when advice / decisions are permitted. +- [Besluitvorming workflow](../../Features/besluitvorming-workflow.md): the advisory-to-decision pattern. +- [Configure case types and workflows](../admin/01-configure-case-types.md): controlling when advice / decisions are permitted. diff --git a/docs/tutorials/user/06-track-deadlines.md b/docs/user-guide/user/06-track-deadlines.md similarity index 72% rename from docs/tutorials/user/06-track-deadlines.md rename to docs/user-guide/user/06-track-deadlines.md index f4edb26a9..4a915be5b 100644 --- a/docs/tutorials/user/06-track-deadlines.md +++ b/docs/user-guide/user/06-track-deadlines.md @@ -1,7 +1,7 @@ --- sidebar_position: 6 title: Track deadlines and lead times on the dashboard -description: Use the dashboard widgets — Deadline Alerts, Task Due Reminders, Stalled Cases — to surface what needs attention this week. +description: "Use the dashboard widgets (Deadline Alerts, Task Due Reminders, Stalled Cases) to surface what needs attention this week." --- # Track deadlines and lead times on the dashboard @@ -19,11 +19,11 @@ By the end you will have read the three deadline widgets on the dashboard, jumpe ## Steps -1. Open the Procest dashboard. The widget shelf renders along the page — *Cases by Status*, *Cases by Type*, *My Work*, *Deadline Alerts*, *Task Due Reminders*, *Stalled Cases*, *Case Map*. +1. Open the Procest dashboard. The widget shelf renders along the page: *Cases by Status*, *Cases by Type*, *My Work*, *Deadline Alerts*, *Task Due Reminders*, *Stalled Cases*, *Case Map*. ![Dashboard widget shelf](/screenshots/tutorials/user/06-track-deadlines-01.png) -2. Find **Deadline Alerts**. Each row is a case approaching or past its statutory deadline, colour-coded — green is comfortably ahead, amber is within the warning window, red is overdue. +2. Find **Deadline Alerts**. Each row is a case approaching or past its statutory deadline, colour-coded: green is comfortably ahead, amber is within the warning window, red is overdue. ![Deadline Alerts widget](/screenshots/tutorials/user/06-track-deadlines-02.png) @@ -37,17 +37,17 @@ By the end you will have read the three deadline widgets on the dashboard, jumpe ## Verification -You have the dashboard set up correctly when: at least one of the three deadline widgets shows rows (or a clean *No items* state — not a load error), the colour coding matches the deadline windows, and clicking a row navigates to the case. +You have the dashboard set up correctly when: at least one of the three deadline widgets shows rows (or a clean *No items* state: not a load error), the colour coding matches the deadline windows, and clicking a row navigates to the case. ## Common issues | Symptom | Fix | |---|---| -| All three widgets read *Widget not available* | The register is not connected — see [Manage Procest settings](../admin/03-admin-settings.md). | -| Deadlines never go amber or red | The case-type has no deadline configured, or the warning thresholds are too short — adjust under **Case Types**. | +| All three widgets read *Widget not available* | The register is not connected: see [Manage Procest settings](../admin/03-admin-settings.md). | +| Deadlines never go amber or red | The case-type has no deadline configured, or the warning thresholds are too short: adjust under **Case Types**. | | A case is overdue but missing from *Deadline Alerts* | The case-type's deadline field is not mapped to the Case schema; an admin checks the schema mapping. | ## Reference -- [Case management](../../features/case-management.md) — deadlines on the case model. -- [Configure case types and workflows](../admin/01-configure-case-types.md) — setting per-status durations. +- [Case management](../../Features/case-management.md): deadlines on the case model. +- [Configure case types and workflows](../admin/01-configure-case-types.md): setting per-status durations. diff --git a/docs/tutorials/user/07-handle-objection.md b/docs/user-guide/user/07-handle-objection.md similarity index 78% rename from docs/tutorials/user/07-handle-objection.md rename to docs/user-guide/user/07-handle-objection.md index 0b798d30a..c7b91f2e7 100644 --- a/docs/tutorials/user/07-handle-objection.md +++ b/docs/user-guide/user/07-handle-objection.md @@ -16,7 +16,7 @@ By the end you will have opened a bezwaar from the Bezwaren list, walked it to t - Completed [Move a case through its workflow](./04-advance-case.md). - A bezwaar in the register (you can register one from the Bezwaren list with **Add Item**, or one was filed against an existing decision). -- A *bezwaaradviescommissie* configured under **Bezwaaradviescommissies** (see [Bezwaar-beroep workflow](../../features/bezwaar-beroep-workflow.md)). +- A *bezwaaradviescommissie* configured under **Bezwaaradviescommissies** (see [Bezwaar-beroep workflow](../../Features/bezwaar-beroep-workflow.md)). ## Steps @@ -28,11 +28,11 @@ By the end you will have opened a bezwaar from the Bezwaren list, walked it to t ![Routing to BAC](/screenshots/tutorials/user/07-handle-objection-02.png) -3. From the navigation, click **BAC-adviezen**. The new request shows up as *Open*. Click it to record the committee's advisory — *Outcome*, *Motivation*, *Hearing date*. Save. +3. From the navigation, click **BAC-adviezen**. The new request shows up as *Open*. Click it to record the committee's advisory: *Outcome*, *Motivation*, *Hearing date*. Save. ![BAC advice form](/screenshots/tutorials/user/07-handle-objection-03.png) -4. Back on the bezwaar, click **Record beslissing op bezwaar**. A dialog opens — pre-filled with the BAC advisory outcome as a default. Adjust if the authority departs from the advisory, add a motivation, and save. +4. Back on the bezwaar, click **Record beslissing op bezwaar**. A dialog opens: pre-filled with the BAC advisory outcome as a default. Adjust if the authority departs from the advisory, add a motivation, and save. ![Beslissing op bezwaar dialog](/screenshots/tutorials/user/07-handle-objection-04.png) @@ -48,11 +48,11 @@ You have handled the bezwaar correctly when: a row exists in **BAC-adviezen** re | Symptom | Fix | |---|---| -| **Route to BAC** is missing | The current status of the bezwaar does not permit it — transition to a status that has *Naar BAC* as an allowed next step. | -| BAC-advies form fields are empty | The Advice schema is not mapped to the bezwaar register — see [Manage Procest settings](../admin/03-admin-settings.md). | +| **Route to BAC** is missing | The current status of the bezwaar does not permit it: transition to a status that has *Naar BAC* as an allowed next step. | +| BAC-advies form fields are empty | The Advice schema is not mapped to the bezwaar register: see [Manage Procest settings](../admin/03-admin-settings.md). | | Beslissing op bezwaar opens but does not pre-fill from BAC advice | The BAC advisory has not been saved as *Afgerond*; reopen it and finalise before recording the decision. | ## Reference -- [Bezwaar-beroep workflow](../../features/bezwaar-beroep-workflow.md) — the full objection / appeal flow. -- [Besluitvorming workflow](../../features/besluitvorming-workflow.md) — the underlying advisory-to-decision pattern. +- [Bezwaar-beroep workflow](../../Features/bezwaar-beroep-workflow.md): the full objection / appeal flow. +- [Besluitvorming workflow](../../Features/besluitvorming-workflow.md): the underlying advisory-to-decision pattern. diff --git a/docs/tutorials/user/08-inspection-checklist.md b/docs/user-guide/user/08-inspection-checklist.md similarity index 72% rename from docs/tutorials/user/08-inspection-checklist.md rename to docs/user-guide/user/08-inspection-checklist.md index f3fec6bb4..2abcdbf67 100644 --- a/docs/tutorials/user/08-inspection-checklist.md +++ b/docs/user-guide/user/08-inspection-checklist.md @@ -1,7 +1,7 @@ --- sidebar_position: 8 title: Run an inspection checklist -description: Use the Handhavingsstrategie matrix on a case — record observations, get a recommended sanction, override if needed. +description: "Use the Handhavingsstrategie matrix on a case: record observations, get a recommended sanction, override if needed." --- # Run an inspection checklist @@ -15,24 +15,24 @@ By the end you will have opened a case that requires inspection, run through the ## Prerequisites - Completed [Open and read a case](./03-view-case.md). -- An LHS matrix configured under **Handhavingsstrategie** (an admin sets this up — see [Bezwaar-beroep workflow](../../features/bezwaar-beroep-workflow.md) and the LHS feature page). +- An LHS matrix configured under **Handhavingsstrategie** (an admin sets this up: see [Bezwaar-beroep workflow](../../Features/bezwaar-beroep-workflow.md) and the LHS feature page). - A case-type that triggers the LHS workflow (typically *Toezicht* or *Handhaving*). ## Steps -1. Open the case from **Cases** or **My Work**. On the sidebar, pick the **Inspection** tab (or click **Start checklist** from the Actions menu). The checklist renders the matrix's axes — typically *Gedrag van de overtreder* on one axis and *Gevolgen van de overtreding* on the other. +1. Open the case from **Cases** or **My Work**. On the sidebar, pick the **Inspection** tab (or click **Start checklist** from the Actions menu). The checklist renders the matrix's axes: typically *Gedrag van de overtreder* on one axis and *Gevolgen van de overtreding* on the other. ![Inspection checklist start](/screenshots/tutorials/user/08-inspection-checklist-01.png) -2. Record an observation on each axis. The matrix is a 4×4 grid; the inspector picks one cell per axis. Add notes per cell — these become part of the case audit trail. +2. Record an observation on each axis. The matrix is a 4×4 grid; the inspector picks one cell per axis. Add notes per cell: these become part of the case audit trail. ![Recording observations](/screenshots/tutorials/user/08-inspection-checklist-02.png) -3. Click **Get recommendation**. Procest looks up the recommended sanction from the configured matrix — usually one of *Waarschuwing*, *Bestuurlijke boete*, *Last onder dwangsom*, *Bestuursdwang*. The recommendation is shown with its reasoning. +3. Click **Get recommendation**. Procest looks up the recommended sanction from the configured matrix: usually one of *Waarschuwing*, *Bestuurlijke boete*, *Last onder dwangsom*, *Bestuursdwang*. The recommendation is shown with its reasoning. ![Sanction recommendation](/screenshots/tutorials/user/08-inspection-checklist-03.png) -4. If you accept the recommendation, click **Accept**. The case transitions to the matching sanction status. If you depart, click **Override**, pick the alternative sanction, and add a motivation — required, because overrides need to be defended on appeal. +4. If you accept the recommendation, click **Accept**. The case transitions to the matching sanction status. If you depart, click **Override**, pick the alternative sanction, and add a motivation: required, because overrides need to be defended on appeal. ![Override with motivation](/screenshots/tutorials/user/08-inspection-checklist-04.png) @@ -49,10 +49,10 @@ You have run the inspection correctly when: the case History tab shows an *Inspe | Symptom | Fix | |---|---| | **Start checklist** is missing on the Actions menu | The case-type does not trigger the LHS workflow; an admin checks the case-type configuration. | -| Matrix axes are empty | The LHS matrix is not configured — see **Handhavingsstrategie** in the navigation. | +| Matrix axes are empty | The LHS matrix is not configured: see **Handhavingsstrategie** in the navigation. | | **Get recommendation** errors out | The matrix has gaps for some axis combinations; an admin completes the matrix or you record the observation outside it with **Override**. | ## Reference -- [Case management](../../features/case-management.md) — how the inspection slots into the case lifecycle. -- [Configure case types and workflows](../admin/01-configure-case-types.md) — enabling the LHS trigger per case-type. +- [Case management](../../Features/case-management.md): how the inspection slots into the case lifecycle. +- [Configure case types and workflows](../admin/01-configure-case-types.md): enabling the LHS trigger per case-type. diff --git a/docs/tutorials/user/_category_.json b/docs/user-guide/user/_category_.json similarity index 100% rename from docs/tutorials/user/_category_.json rename to docs/user-guide/user/_category_.json diff --git a/openspec/changes/docs-product-pages-conformance/.openspec.yaml b/openspec/changes/docs-product-pages-conformance/.openspec.yaml new file mode 100644 index 000000000..93831bd26 --- /dev/null +++ b/openspec/changes/docs-product-pages-conformance/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-05-13 diff --git a/openspec/changes/docs-product-pages-conformance/design.md b/openspec/changes/docs-product-pages-conformance/design.md new file mode 100644 index 000000000..7446d9874 --- /dev/null +++ b/openspec/changes/docs-product-pages-conformance/design.md @@ -0,0 +1,67 @@ +## Context + +Procest's documentation site (`docs/`) is built on `@conduction/docusaurus-preset`. The 2026-05-13 fleet audit identified structural non-conformance against the canonical product-pages spec: wrong-case folder names (`features/` vs `Features/`, `tutorials/` vs `user-guide/`), six legacy root-level MDs that belong in a `Technical/` subfolder, no `installation.md`, no Redocusaurus API mount, and em-dash violations across 12 files. + +The migration is entirely mechanical: git renames, file moves, new stub files, config edits, and find-and-replace em-dash fixes. There are no PHP, Vue, or backend code changes. + +**Upstream already applied:** +- Preset bump `^1.5.1` → `^2.6.1` (PR #433) +- Tutorial content fills and screenshots (PR #437) + +## Goals / Non-Goals + +**Goals:** +- Rename `features/` → `Features/` and `tutorials/` → `user-guide/` using `git mv` (preserves history) +- Move 6 legacy root MDs into `Technical/` using `git mv` +- Rename `README.md` → `index.md` with Docusaurus frontmatter +- Create `installation.md` with real install + config steps for procest +- Scaffold `UseCases/` and `Integrations/` stub folders (draft: true) +- Add `redocusaurus@^2.0.0` + configure `/api` route + `static/oas/procest.json` placeholder +- Add "API Documentation" navbar item +- Re-enable `nl` locale (with SSR-failure escape hatch per ADR-030) +- Fix all em-dashes in the docs scope (gate: `git grep -E '—' docs/` = 0) + +**Non-Goals:** +- Writing actual NL translated markdown (issue #441) +- Writing real content for `UseCases/` or `Integrations/` (issue #440) +- Writing the real OpenAPI spec (issue #442) +- Any PHP, Vue, or backend code changes +- Changing landing page (`src/pages/index.js`) — already brand-compliant + +## Decisions + +### D1: Use `git mv` for all renames and moves + +`git mv` preserves file history, which matters for the 44 feature files and 11 tutorial files. The alternative (delete + add) would orphan history. + +### D2: `FEATURES.md` → `Technical/market-analysis.md` (not `Features/`) + +`FEATURES.md` is 360-line strategic/competitive analyst content (market analysis, competitor tables, feature demand matrix). It is NOT a curated end-user feature page. Moving it to `Technical/` separates internal analyst material from the public-facing feature catalogue. The 44 curated feature pages in `features/` are the canonical product docs. + +### D3: `README.md` → `index.md` with frontmatter, not deletion + +`README.md` has real content (feature table, architecture overview, screenshots). Renaming to `index.md` and adding `sidebar_position: 1` frontmatter makes it the site's landing document in the Docusaurus autogenerated sidebar. Deleting would remove useful navigation content. + +### D4: OAS placeholder shim in `static/oas/procest.json` + +Redocusaurus requires the OAS file to exist at build time or the build 404s. Shipping a minimal valid OAS `{"openapi":"3.0.0","info":{"title":"Procest","version":"0.0.0"},"paths":{}}` lets Redocusaurus render without failing. The real spec is tracked in issue #442. + +### D5: `nl` locale re-enable with escape hatch + +ADR-030 documents SSR failures when `i18n/nl/` contains stale metadata without translated markdown. The config will add `'nl'` to `locales` with a comment explaining the escape hatch: if the `npm run build` fails on nl, revert `locales` to `['en']` and cite issue #441. The build verification step in the apply task handles this automatically. + +### D6: Em-dash replacement strategy + +Em-dashes in the Technical/ files (especially `market-analysis.md`) are prose em-dashes that separate clauses. Replacement: `' — '` (space-em-dash-space) → `', '` (comma-space) or `': '` (colon-space) depending on context. Em-dashes in feature files are mostly in technical bullet lists (e.g., `` `endpoint()` — description ``): replace with `: ` or ` - ` for code-reference bullets. Em-dashes in HTML comments (tutorials) are purely in the `{{TODO: ... — see /journeydoc-add-story}}` template: replace `—` with `-`. + +Use Edit tool with targeted replacements per file. Never use sed/awk/python. + +## Risks / Trade-offs + +- **Sidebar order disruption** → Docusaurus autogenerated sidebar uses alphabetical order by default; folder renames (lower→upper case) may shift the sidebar position of Features/ relative to other top-level items. Mitigation: add `_category_.json` with explicit `position` to each canonical folder to pin the order. + +- **nl SSR failure** → Known ADR-030 issue. Mitigation: build verification step tries `npm run build`; if nl SSR breaks, the apply task reverts `locales` to `['en']` with a comment. + +- **Internal cross-link breakage** → Files moved to `Technical/` may have relative links pointing to other root-level MDs. Mitigation: scan moved files for relative MD links and update paths as part of the move task. + +- **Screenshots in tutorials/** → The PR #437 added screenshots to `tutorials/user/` and `tutorials/admin/`. The `git mv docs/tutorials docs/user-guide` will move the entire subtree including PNG files. Verify screenshot count before and after. diff --git a/openspec/changes/docs-product-pages-conformance/proposal.md b/openspec/changes/docs-product-pages-conformance/proposal.md new file mode 100644 index 000000000..c6df75076 --- /dev/null +++ b/openspec/changes/docs-product-pages-conformance/proposal.md @@ -0,0 +1,47 @@ +## Why + +Procest's documentation site does not conform to the canonical product-pages structure defined by `@conduction/docusaurus-preset` and the design-system preview (commit `411db7e`). The audit of 2026-05-13 identified missing canonical folders, misnamed folders, legacy root-level markdown files that belong in a `Technical/` subfolder, missing `installation.md`, missing Redocusaurus API route, and em-dash violations across 12 files. Without structural conformance, the site fails the fleet-wide product-pages standard and cannot serve as a reference for government procurement audiences. + +## What Changes + +- **Rename** `docs/features/` → `docs/Features/` (44 feature pages + README.md, preserving content) +- **Rename** `docs/tutorials/` → `docs/user-guide/` (11 tutorial pages in admin/ + user/ subdirs, preserving content and screenshots) +- **Create** `docs/Technical/` folder and move 6 legacy root MDs into it: + - `ARCHITECTURE.md` → `Technical/architecture.md` + - `DESIGN-REFERENCES.md` → `Technical/design-decisions.md` + - `development.md` → `Technical/development-guide.md` + - `zgw-implementation.md` → `Technical/zgw-spec.md` + - `GOVERNMENT-FEATURES.md` → `Technical/government-compliance.md` + - `FEATURES.md` → `Technical/market-analysis.md` (strategic analyst content, not a curated feature page) +- **Rename** `docs/README.md` → `docs/index.md` with proper Docusaurus frontmatter +- **Create** `docs/installation.md` with real Nextcloud App Store install steps, prerequisites, post-install config (register + case-type setup + ZGW API endpoint mapping), and troubleshooting +- **Create** `docs/UseCases/` and `docs/Integrations/` stub folders (draft: true, citing issue #440) +- **Add** `redocusaurus@^2.0.0` to `docs/package.json` and configure the `/api` route in `docs/docusaurus.config.js` fed by `docs/static/oas/procest.json` +- **Add** "API Documentation" navbar item +- **Re-enable** `nl` locale in `docs/docusaurus.config.js` (revert to `['en']` with comment if SSR fails, cite #441) +- **Create** `docs/static/oas/procest.json` placeholder OAS shim (real spec via issue #442) +- **Fix** all em-dash violations across 12 docs files to pass the `git grep -E '—' docs/` = 0 gate +- **Update** internal cross-links in moved files + +Note: Preset bump `^1.5.1` → `^2.6.1` was already completed upstream in PR #433. Tutorial content fills were done in PR #437. Both are out of scope. + +## Capabilities + +### New Capabilities + +- `docs-product-pages`: Canonical product-pages folder structure, installation guide, Redocusaurus API mount, UseCases/Integrations stubs, nl locale, em-dash-clean prose + +### Modified Capabilities + +- (none — no existing spec-level requirements change; this is a docs-structure migration) + +## Impact + +- `docs/` folder structure: ~60 files renamed or moved (git mv preserves history) +- `docs/docusaurus.config.js`: redocusaurus plugin + navbar item + nl locale re-enabled +- `docs/package.json`: add `redocusaurus@^2.0.0` +- `docs/static/oas/procest.json`: new placeholder file +- All internal links in moved Technical/ files: updated to relative paths +- No PHP, Vue, or backend code changes +- No OpenRegister schema changes +- Downstream: CI docs-deploy workflow will pick up the changes on merge to `development` diff --git a/openspec/changes/docs-product-pages-conformance/specs/docs-product-pages/spec.md b/openspec/changes/docs-product-pages-conformance/specs/docs-product-pages/spec.md new file mode 100644 index 000000000..b8d21c7b8 --- /dev/null +++ b/openspec/changes/docs-product-pages-conformance/specs/docs-product-pages/spec.md @@ -0,0 +1,104 @@ +## ADDED Requirements + +### Requirement: Canonical folder taxonomy + +The documentation site SHALL use the following canonical top-level folder structure under `docs/`: +- `Features/` (capital F) — curated product feature pages +- `user-guide/` — step-by-step tutorials with `admin/` and `user/` subdirs +- `Technical/` — architecture, design decisions, implementation guides +- `UseCases/` — use-case narratives (may be stubs with `draft: true`) +- `Integrations/` — integration guides (may be stubs with `draft: true`) + +#### Scenario: Features folder is capital-F + +- **WHEN** a user browses the documentation sidebar +- **THEN** the Features section appears as `Features/` (not `features/`) + +#### Scenario: Tutorials renamed to user-guide + +- **WHEN** a user navigates to a tutorial +- **THEN** the URL contains `/user-guide/` (not `/tutorials/`) + +#### Scenario: Legacy root MDs are in Technical/ + +- **WHEN** a developer searches for ARCHITECTURE.md +- **THEN** the file is found at `Technical/architecture.md`, not at the docs root + +#### Scenario: UseCases and Integrations stubs exist + +- **WHEN** Docusaurus builds the sidebar +- **THEN** `UseCases/` and `Integrations/` appear as sections (with draft index stubs) + +--- + +### Requirement: Root index document + +The documentation site SHALL have a `docs/index.md` (not `README.md`) with Docusaurus frontmatter (`id: intro`, `title: Introduction`, `sidebar_position: 1`) as the entry point for the sidebar. + +#### Scenario: index.md renders as site introduction + +- **WHEN** a user opens the Documentation section +- **THEN** the first page shown is the Introduction page (from `index.md`) + +--- + +### Requirement: Installation guide + +The documentation site SHALL provide a `docs/installation.md` covering: +1. Prerequisites (Nextcloud 28+, OpenRegister app enabled) +2. App Store installation steps +3. Post-install configuration: register setup, case-type configuration, ZGW API endpoint mapping +4. Basic troubleshooting (common errors and resolutions) + +#### Scenario: Installation guide is accessible from sidebar + +- **WHEN** a user navigates the Documentation sidebar +- **THEN** an "Installation" entry is visible at the top level + +#### Scenario: Installation guide covers ZGW endpoint config + +- **WHEN** a user follows the installation guide +- **THEN** they find instructions for configuring the ZGW API endpoint mapping in admin settings + +--- + +### Requirement: Redocusaurus API documentation route + +The documentation site SHALL mount `redocusaurus@^2.0.0` at route `/api`, fed by `static/oas/procest.json`. The navbar SHALL include an "API Documentation" link pointing to `/api`. + +#### Scenario: API Documentation navbar item exists + +- **WHEN** a user views the documentation navbar +- **THEN** an "API Documentation" link is present + +#### Scenario: /api route resolves without build error + +- **WHEN** `npm run build` is executed +- **THEN** the build exits 0 and the `/api` route is generated (using the placeholder OAS shim until the real spec lands via issue #442) + +--- + +### Requirement: Dutch locale re-enabled + +The documentation site SHALL declare `locales: ['en', 'nl']` in `docusaurus.config.js`. If SSR rendering errors occur during `npm run build`, the locale SHALL be reverted to `['en']` with a comment citing issue #441. + +#### Scenario: nl locale declared in config + +- **WHEN** a developer reads `docusaurus.config.js` +- **THEN** the `locales` array contains both `'en'` and `'nl'` + +#### Scenario: Build passes with nl locale declared + +- **WHEN** `npm run build` runs +- **THEN** the build exits 0 (or, if SSR fails, the locale is reverted to ['en'] and build exits 0) + +--- + +### Requirement: Em-dash-free documentation prose + +All markdown files under `docs/` SHALL contain zero em-dash characters (`—`). The gate `git grep -E '—' docs/` MUST return empty output. + +#### Scenario: Em-dash gate passes + +- **WHEN** `git grep -E '—' docs/` is run after implementation +- **THEN** the command returns no output (exit code 1, zero matches) diff --git a/openspec/changes/docs-product-pages-conformance/tasks.md b/openspec/changes/docs-product-pages-conformance/tasks.md new file mode 100644 index 000000000..8ad321ce6 --- /dev/null +++ b/openspec/changes/docs-product-pages-conformance/tasks.md @@ -0,0 +1,85 @@ +## 1. Folder renames (git mv — preserves history) + +- [ ] 1.1 `git mv docs/features docs/Features` — rename features folder to canonical casing (44 feature files + README.md) +- [ ] 1.2 `git mv docs/tutorials docs/user-guide` — rename tutorials folder to canonical name (11 MD files in admin/ + user/ subdirs, plus all screenshots) +- [ ] 1.3 Verify screenshot count in `docs/user-guide/` matches original `docs/tutorials/` (PNG files must all be present after mv) + +## 2. Create Technical/ folder and move legacy root MDs + +- [ ] 2.1 Create `docs/Technical/` folder with `_category_.json` (label: "Technical", position: 6) +- [ ] 2.2 `git mv docs/ARCHITECTURE.md docs/Technical/architecture.md` +- [ ] 2.3 `git mv docs/DESIGN-REFERENCES.md docs/Technical/design-decisions.md` +- [ ] 2.4 `git mv docs/development.md docs/Technical/development-guide.md` +- [ ] 2.5 `git mv docs/zgw-implementation.md docs/Technical/zgw-spec.md` +- [ ] 2.6 `git mv docs/GOVERNMENT-FEATURES.md docs/Technical/government-compliance.md` +- [ ] 2.7 `git mv docs/FEATURES.md docs/Technical/market-analysis.md` + +## 3. Root README rename and index.md creation + +- [ ] 3.1 `git mv docs/README.md docs/index.md` +- [ ] 3.2 Add Docusaurus frontmatter to `docs/index.md`: `id: intro`, `title: Introduction`, `sidebar_position: 1` + +## 4. Create installation.md + +- [ ] 4.1 Create `docs/installation.md` with: + - `sidebar_position: 2` frontmatter + - Prerequisites section (Nextcloud 28+, OpenRegister app) + - App Store installation steps (install from Nextcloud App Store, enable app) + - Post-install configuration section: register setup (procest register created automatically via repair step), case-type configuration, ZGW API endpoint mapping in Admin Settings + - Troubleshooting section (register not found: re-run repair step; ZGW 400 errors: verify endpoint URLs) + +## 5. Create UseCases/ and Integrations/ stub folders + +- [ ] 5.1 Create `docs/UseCases/_category_.json` (label: "Use Cases", position: 4) +- [ ] 5.2 Create `docs/UseCases/index.md` stub (frontmatter: `draft: true`, title: "Use Cases", note: content authoring tracked in issue #440) +- [ ] 5.3 Create `docs/Integrations/_category_.json` (label: "Integrations", position: 5) +- [ ] 5.4 Create `docs/Integrations/index.md` stub (frontmatter: `draft: true`, title: "Integrations", note: content authoring tracked in issue #440) + +## 6. _category_.json files for canonical folders + +- [ ] 6.1 Create `docs/Features/_category_.json` (label: "Features", position: 3) +- [ ] 6.2 Create `docs/user-guide/_category_.json` (label: "User Guide", position: 2) — only if one does not already exist +- [ ] 6.3 Create `docs/Technical/_category_.json` if not already done in task 2.1 + +## 7. Add Redocusaurus and API Documentation route + +- [ ] 7.1 Add `"redocusaurus": "^2.0.0"` to `docs/package.json` under `dependencies` +- [ ] 7.2 Create `docs/static/oas/` directory and write `docs/static/oas/procest.json` with minimal valid OAS shim: `{"openapi":"3.0.0","info":{"title":"Procest","version":"0.0.0"},"paths":{}}` +- [ ] 7.3 Add Redocusaurus plugin config to `docs/docusaurus.config.js`: plugin `redocusaurus` with `specs: [{spec: 'static/oas/procest.json', route: '/api/'}]` +- [ ] 7.4 Add "API Documentation" navbar item to `docs/docusaurus.config.js`: `{to: '/api/', label: 'API Documentation', position: 'left'}` + +## 8. Re-enable nl locale + +- [ ] 8.1 In `docs/docusaurus.config.js`, update `i18n.locales` from `['en']` to `['en', 'nl']` +- [ ] 8.2 Add `nl: { label: 'Nederlands' }` to `i18n.localeConfigs` +- [ ] 8.3 Run `npm run build` in `docs/`; if SSR fails with nl locale, revert `locales` to `['en']` and add comment: `/* nl reverted: SSR error with empty i18n/nl/ — re-enable once translation backfill lands (issue #441) */` + +## 9. Em-dash sweep (gate: git grep -E '—' docs/ returns 0) + +- [ ] 9.1 Fix em-dashes in `docs/Technical/market-analysis.md` (11 hits from FEATURES.md): replace ` — ` with `, ` or `: ` per context; title `# Procest — Feature Analysis` → `# Procest: Feature Analysis` +- [ ] 9.2 Fix em-dashes in `docs/Features/README.md` (table cells and prose): replace ` — ` with `, ` or `: ` +- [ ] 9.3 Fix em-dashes in `docs/Features/administration.md` (bullet list items with ` — `): replace ` — ` with `: ` +- [ ] 9.4 Fix em-dashes in `docs/Features/zgw-apis.md`: replace ` — ` with `: ` in code-reference bullets +- [ ] 9.5 Fix em-dashes in `docs/Features/bezwaar-beroep-workflow.md`: replace ` — ` with `: ` +- [ ] 9.6 Fix em-dashes in `docs/Features/workflow-engine-enhancement.md`: replace ` — ` with `: ` +- [ ] 9.7 Fix em-dashes in `docs/Features/vth-workflow-configuration.md`: replace ` — ` with `: ` +- [ ] 9.8 Fix em-dashes in `docs/Features/besluitvorming-workflow.md`: replace ` — ` with `: ` +- [ ] 9.9 Fix em-dashes in `docs/Features/doorlooptijd-dashboard.md`: replace ` — ` with `: ` +- [ ] 9.10 Fix em-dashes in `docs/Features/deelzaak-support.md`: replace ` — ` with `: ` +- [ ] 9.11 Fix em-dashes in `docs/Features/app-scaffold.md`: replace ` — ` with `: ` +- [ ] 9.12 Fix em-dashes in `docs/Features/gis-integration.md`: replace ` — ` with `: ` +- [ ] 9.13 Fix em-dashes in `docs/user-guide/` HTML comments (tutorials): in ``, replace `—` with `-` +- [ ] 9.14 Verify em-dash gate: run `git grep -E '—' docs/` (excluding node_modules) — must return 0 matches + +## 10. Internal link updates in moved files + +- [ ] 10.1 Scan all files moved to `docs/Technical/` for relative links pointing to sibling root MDs (e.g., `../ARCHITECTURE.md`) and update to the new paths +- [ ] 10.2 Scan `docs/Features/` files for any cross-links to root MDs and update accordingly +- [ ] 10.3 Verify `docs/index.md` links to `features/` are updated to `Features/` (if any) + +## 11. Build verification + +- [ ] 11.1 Run `cd docs && npm install --legacy-peer-deps` +- [ ] 11.2 Run `npm run build` (with 10-minute timeout) — must exit 0 +- [ ] 11.3 If build fails due to nl SSR error, execute escape hatch from task 8.3 and re-run build +- [ ] 11.4 Confirm build output includes `Features/`, `user-guide/`, `Technical/`, `api/` routes diff --git a/openspec/specs/docs-product-pages/spec.md b/openspec/specs/docs-product-pages/spec.md new file mode 100644 index 000000000..7fcbe91f6 --- /dev/null +++ b/openspec/specs/docs-product-pages/spec.md @@ -0,0 +1,93 @@ +**Capability**: docs-product-pages +**Status**: in-progress +**OpenSpec changes**: docs-product-pages-conformance (2026-05-13) + +## Summary + +Canonical product-pages documentation structure for the Procest documentation site, conforming to the `@conduction/docusaurus-preset` fleet standard. + +## Requirements + +### Requirement: Canonical folder taxonomy + +The documentation site SHALL use the following canonical top-level folder structure under `docs/`: +- `Features/` (capital F) — curated product feature pages +- `user-guide/` — step-by-step tutorials with `admin/` and `user/` subdirs +- `Technical/` — architecture, design decisions, implementation guides +- `UseCases/` — use-case narratives (may be stubs with `draft: true`) +- `Integrations/` — integration guides (may be stubs with `draft: true`) + +#### Scenario: Features folder is capital-F + +- **WHEN** a user browses the documentation sidebar +- **THEN** the Features section appears as `Features/` (not `features/`) + +#### Scenario: Tutorials renamed to user-guide + +- **WHEN** a user navigates to a tutorial +- **THEN** the URL contains `/user-guide/` (not `/tutorials/`) + +#### Scenario: Legacy root MDs are in Technical/ + +- **WHEN** a developer searches for ARCHITECTURE.md +- **THEN** the file is found at `Technical/architecture.md`, not at the docs root + +#### Scenario: UseCases and Integrations stubs exist + +- **WHEN** Docusaurus builds the sidebar +- **THEN** `UseCases/` and `Integrations/` appear as sections + +--- + +### Requirement: Root index document + +The documentation site SHALL have a `docs/index.md` with Docusaurus frontmatter (`id: intro`, `title: Introduction`, `sidebar_position: 1`) as the entry point for the sidebar. + +#### Scenario: index.md renders as site introduction + +- **WHEN** a user opens the Documentation section +- **THEN** the first page shown is the Introduction page + +--- + +### Requirement: Installation guide + +The documentation site SHALL provide a `docs/installation.md` covering prerequisites, App Store installation, post-install configuration, and troubleshooting. + +#### Scenario: Installation guide is accessible from sidebar + +- **WHEN** a user navigates the Documentation sidebar +- **THEN** an "Installation" entry is visible + +--- + +### Requirement: Redocusaurus API documentation route + +The documentation site SHALL mount `redocusaurus@^2.0.0` at route `/api` with an "API Documentation" navbar link. + +#### Scenario: API Documentation navbar item exists + +- **WHEN** a user views the documentation navbar +- **THEN** an "API Documentation" link is present + +--- + +### Requirement: Dutch locale declared + +The documentation site SHALL declare `locales: ['en', 'nl']` (with SSR-failure escape hatch per ADR-030). + +#### Scenario: nl locale declared in config + +- **WHEN** a developer reads `docusaurus.config.js` +- **THEN** the `locales` array contains both `'en'` and `'nl'` + +--- + +### Requirement: Em-dash-free documentation prose + +All markdown files under `docs/` SHALL contain zero em-dash characters (`—`). + +#### Scenario: Em-dash gate passes + +- **WHEN** `git grep -E '—' docs/` is run +- **THEN** the command returns no output