diff --git a/eslint-suppressions.json b/eslint-suppressions.json index 5567f2ef7..b25f768c0 100644 --- a/eslint-suppressions.json +++ b/eslint-suppressions.json @@ -1,9 +1,4 @@ { - "src/App.vue": { - "jsdoc/require-param-type": { - "count": 1 - } - }, "src/components/InspectionChecklistEditor.vue": { "@nextcloud/l10n-enforce-ellipsis": { "count": 1 @@ -36,17 +31,11 @@ "src/components/map/AddressSearch.vue": { "@nextcloud/l10n-enforce-ellipsis": { "count": 2 - }, - "jsdoc/require-param-type": { - "count": 3 } }, "src/components/map/LocationPicker.vue": { "@nextcloud/no-deprecated-library-props": { "count": 3 - }, - "jsdoc/require-param-type": { - "count": 5 } }, "src/components/tabs/CaseDocumentsTab.vue": { @@ -81,17 +70,11 @@ "src/dialogs/AiClassifyDialog.vue": { "@nextcloud/no-deprecated-library-props": { "count": 2 - }, - "jsdoc/require-param-type": { - "count": 1 } }, "src/dialogs/AiExtractDialog.vue": { "@nextcloud/no-deprecated-library-props": { "count": 1 - }, - "jsdoc/require-param-type": { - "count": 3 } }, "src/dialogs/BerichtenboxComposeDialog.vue": { @@ -137,9 +120,6 @@ }, "@nextcloud/no-deprecated-library-props": { "count": 2 - }, - "jsdoc/require-param-type": { - "count": 1 } }, "src/dialogs/ConsultationResponseForm.vue": { @@ -148,9 +128,6 @@ }, "@nextcloud/no-deprecated-library-props": { "count": 3 - }, - "jsdoc/require-param-type": { - "count": 2 } }, "src/dialogs/CreateFederatedShareDialog.vue": { @@ -239,9 +216,6 @@ "src/dialogs/ZgwMappingDialog.vue": { "@nextcloud/no-deprecated-library-props": { "count": 2 - }, - "jsdoc/require-param-type": { - "count": 1 } }, "src/main.js": { @@ -255,15 +229,9 @@ }, "@typescript-eslint/no-unused-vars": { "count": 1 - }, - "jsdoc/require-param-type": { - "count": 1 } }, "src/modals/DeelzaakCreateModal.vue": { - "@nextcloud/no-deprecated-library-props": { - "count": 2 - }, "no-console": { "count": 3 } @@ -272,9 +240,6 @@ "@nextcloud/no-deprecated-library-props": { "count": 1 }, - "jsdoc/require-param-type": { - "count": 1 - }, "no-console": { "count": 1 } @@ -303,9 +268,6 @@ }, "@typescript-eslint/no-unused-vars": { "count": 1 - }, - "jsdoc/require-param-type": { - "count": 1 } }, "src/modals/TermijnDefinitieEditor.vue": { @@ -404,9 +366,6 @@ "@nextcloud/no-deprecated-library-props": { "count": 4 }, - "jsdoc/require-param-type": { - "count": 2 - }, "no-console": { "count": 3 } @@ -426,9 +385,6 @@ "@typescript-eslint/no-unused-vars": { "count": 1 }, - "jsdoc/require-param-type": { - "count": 1 - }, "no-console": { "count": 2 } @@ -436,9 +392,6 @@ "src/views/cases/components/AdviceRequestPanel.vue": { "@nextcloud/no-deprecated-library-props": { "count": 1 - }, - "jsdoc/require-param-type": { - "count": 4 } }, "src/views/cases/components/AdviesPanel.vue": { @@ -448,9 +401,6 @@ "@typescript-eslint/no-unused-vars": { "count": 1 }, - "jsdoc/require-param-type": { - "count": 11 - }, "no-console": { "count": 3 } @@ -500,20 +450,6 @@ "src/views/cases/components/EmailThread.vue": { "@nextcloud/no-deprecated-library-props": { "count": 1 - }, - "jsdoc/require-param-type": { - "count": 3 - } - }, - "src/views/cases/components/InspectionPanel.vue": { - "@nextcloud/l10n-enforce-ellipsis": { - "count": 1 - }, - "@nextcloud/no-deprecated-library-props": { - "count": 2 - }, - "jsdoc/require-param-type": { - "count": 6 } }, "src/views/cases/components/ShareTab.vue": { @@ -547,9 +483,6 @@ }, "@typescript-eslint/no-unused-vars": { "count": 1 - }, - "jsdoc/require-param-type": { - "count": 4 } }, "src/views/dashboard/WooDeadlinePanel.vue": { @@ -574,9 +507,6 @@ }, "@typescript-eslint/no-unused-vars": { "count": 2 - }, - "jsdoc/require-param-type": { - "count": 2 } }, "src/views/public/PublicAppointmentPage.vue": { @@ -585,9 +515,6 @@ }, "@typescript-eslint/no-unused-vars": { "count": 2 - }, - "jsdoc/require-param-type": { - "count": 2 } }, "src/views/public/PublicFederatedTransferPage.vue": { @@ -604,14 +531,6 @@ }, "@typescript-eslint/no-unused-vars": { "count": 1 - }, - "jsdoc/require-param-type": { - "count": 1 - } - }, - "src/views/settings/CaseTypeAdmin.vue": { - "jsdoc/require-param-type": { - "count": 2 } }, "src/views/settings/CaseTypeDetail.vue": { @@ -620,17 +539,11 @@ }, "@typescript-eslint/no-unused-vars": { "count": 1 - }, - "jsdoc/require-param-type": { - "count": 2 } }, "src/views/settings/CaseTypeList.vue": { "@nextcloud/no-deprecated-library-props": { "count": 3 - }, - "jsdoc/require-param-type": { - "count": 8 } }, "src/views/settings/EmailSettings.vue": { @@ -686,9 +599,6 @@ "@nextcloud/no-deprecated-library-props": { "count": 2 }, - "jsdoc/require-param-type": { - "count": 1 - }, "no-console": { "count": 2 } @@ -696,38 +606,21 @@ "src/views/settings/WorkflowEditor.vue": { "@typescript-eslint/no-unused-vars": { "count": 1 - }, - "jsdoc/require-param-type": { - "count": 25 } }, "src/views/settings/ZgwMappingSettings.vue": { "@nextcloud/no-deprecated-library-props": { "count": 2 - }, - "jsdoc/require-param-type": { - "count": 3 - } - }, - "src/views/settings/components/DurationPicker.vue": { - "jsdoc/require-param-type": { - "count": 2 } }, "src/views/settings/components/MandaatImportPanel.vue": { "@nextcloud/no-deprecated-library-props": { "count": 2 - }, - "jsdoc/require-param-type": { - "count": 1 } }, "src/views/settings/components/MandaatMatrixTable.vue": { "@nextcloud/no-deprecated-library-props": { "count": 2 - }, - "jsdoc/require-param-type": { - "count": 1 } }, "src/views/settings/components/MandaatToewijzingenTable.vue": { @@ -736,9 +629,6 @@ }, "@typescript-eslint/no-unused-vars": { "count": 2 - }, - "jsdoc/require-param-type": { - "count": 5 } }, "src/views/settings/components/OrganisatieRolManager.vue": { @@ -747,9 +637,6 @@ }, "@typescript-eslint/no-unused-vars": { "count": 2 - }, - "jsdoc/require-param-type": { - "count": 3 } }, "src/views/settings/components/RolNode.vue": { @@ -766,23 +653,14 @@ }, "eqeqeq": { "count": 1 - }, - "jsdoc/require-param-type": { - "count": 11 } }, "src/views/settings/components/TransitionConfigPanel.vue": { "@nextcloud/no-deprecated-library-props": { "count": 6 - }, - "jsdoc/require-param-type": { - "count": 6 } }, "src/views/settings/components/WorkflowNode.vue": { - "jsdoc/require-param-type": { - "count": 7 - }, "vue/custom-event-name-casing": { "count": 12 } @@ -791,9 +669,6 @@ "@nextcloud/no-deprecated-library-props": { "count": 1 }, - "jsdoc/require-param-type": { - "count": 2 - }, "vue/custom-event-name-casing": { "count": 2 } @@ -801,9 +676,6 @@ "src/views/settings/tabs/AiSettingsTab.vue": { "@typescript-eslint/no-unused-vars": { "count": 2 - }, - "jsdoc/require-param-type": { - "count": 2 } }, "src/views/settings/tabs/ChecklistsTab.vue": { @@ -841,14 +713,6 @@ "src/views/settings/tabs/DocumentTypesTab.vue": { "@nextcloud/no-deprecated-library-props": { "count": 3 - }, - "jsdoc/require-param-type": { - "count": 2 - } - }, - "src/views/settings/tabs/FinancialIntegrationTab.vue": { - "jsdoc/require-param-type": { - "count": 2 } }, "src/views/settings/tabs/GeneralTab.vue": { @@ -870,9 +734,6 @@ }, "@typescript-eslint/no-unused-vars": { "count": 4 - }, - "jsdoc/require-param-type": { - "count": 3 } }, "src/views/settings/tabs/PropertiesTab.vue": { @@ -883,25 +744,16 @@ "src/views/settings/tabs/ResultsTab.vue": { "@nextcloud/no-deprecated-library-props": { "count": 5 - }, - "jsdoc/require-param-type": { - "count": 3 } }, "src/views/settings/tabs/RolesTab.vue": { "@nextcloud/no-deprecated-library-props": { "count": 5 - }, - "jsdoc/require-param-type": { - "count": 3 } }, "src/views/settings/tabs/StatusesTab.vue": { "@nextcloud/no-deprecated-library-props": { "count": 5 - }, - "jsdoc/require-param-type": { - "count": 6 } }, "src/views/settings/tabs/SubCaseTypesTab.vue": { @@ -918,18 +770,12 @@ "src/views/settings/tabs/TermijnDefinitiesTab.vue": { "@nextcloud/no-deprecated-library-props": { "count": 1 - }, - "jsdoc/require-param-type": { - "count": 4 } }, "src/views/settings/tabs/WorkflowTab.vue": { "@nextcloud/no-deprecated-library-props": { "count": 7 }, - "jsdoc/require-param-type": { - "count": 1 - }, "no-console": { "count": 1 } diff --git a/lib/BackgroundJob/AdviceDeadlineJob.php b/lib/BackgroundJob/AdviceDeadlineJob.php index 9359cdcd6..bfbd44d28 100644 --- a/lib/BackgroundJob/AdviceDeadlineJob.php +++ b/lib/BackgroundJob/AdviceDeadlineJob.php @@ -39,6 +39,8 @@ /** * Daily timed job that processes advice request deadlines and reminders. + * + * @spec openspec/specs/advice-management/spec.md */ class AdviceDeadlineJob extends TimedJob { /** diff --git a/lib/BackgroundJob/AppointmentReminderJob.php b/lib/BackgroundJob/AppointmentReminderJob.php index 18af45eae..fd1602b90 100644 --- a/lib/BackgroundJob/AppointmentReminderJob.php +++ b/lib/BackgroundJob/AppointmentReminderJob.php @@ -34,6 +34,8 @@ /** * Daily timed job that sends appointment reminders for next-day appointments. + * + * @spec openspec/specs/appointment-booking/spec.md */ class AppointmentReminderJob extends TimedJob { /** diff --git a/lib/BackgroundJob/BerichtenboxReadStatusJob.php b/lib/BackgroundJob/BerichtenboxReadStatusJob.php index c7c939ed1..9f18d4ec4 100644 --- a/lib/BackgroundJob/BerichtenboxReadStatusJob.php +++ b/lib/BackgroundJob/BerichtenboxReadStatusJob.php @@ -33,6 +33,8 @@ /** * Daily timed job that polls Berichtenbox read status for sent messages. + * + * @spec openspec/specs/berichtenbox-integration/spec.md */ class BerichtenboxReadStatusJob extends TimedJob { /** diff --git a/lib/BackgroundJob/BottleneckDetectionJob.php b/lib/BackgroundJob/BottleneckDetectionJob.php index 84deff014..22a5b71ed 100644 --- a/lib/BackgroundJob/BottleneckDetectionJob.php +++ b/lib/BackgroundJob/BottleneckDetectionJob.php @@ -41,6 +41,8 @@ /** * Daily timed job that detects milestone bottlenecks and notifies case workers. + * + * @spec openspec/specs/milestone-tracking/spec.md */ class BottleneckDetectionJob extends TimedJob { /** diff --git a/lib/BackgroundJob/DeadlineNotificationDispatchJob.php b/lib/BackgroundJob/DeadlineNotificationDispatchJob.php index d958dcd92..41baa66d9 100644 --- a/lib/BackgroundJob/DeadlineNotificationDispatchJob.php +++ b/lib/BackgroundJob/DeadlineNotificationDispatchJob.php @@ -41,6 +41,8 @@ * Asynchronous queued notification dispatcher. * * @psalm-suppress UnusedClass + * + * @spec openspec/changes/termijnbewaking-dwangsom-engine-08-burger-notifications/tasks.md */ class DeadlineNotificationDispatchJob extends QueuedJob { /** diff --git a/lib/BackgroundJob/EmailPdfRetryJob.php b/lib/BackgroundJob/EmailPdfRetryJob.php index 51b1a7553..1a2370462 100644 --- a/lib/BackgroundJob/EmailPdfRetryJob.php +++ b/lib/BackgroundJob/EmailPdfRetryJob.php @@ -37,6 +37,8 @@ /** * Retries failed PDF archival attempts on a 15-minute cadence. + * + * @spec openspec/changes/case-email-integration/tasks.md#T09 */ class EmailPdfRetryJob extends TimedJob { /** diff --git a/lib/BackgroundJob/InboundEmailJob.php b/lib/BackgroundJob/InboundEmailJob.php index bdc15b4aa..d191d043d 100644 --- a/lib/BackgroundJob/InboundEmailJob.php +++ b/lib/BackgroundJob/InboundEmailJob.php @@ -42,6 +42,8 @@ /** * Pulls inbound email from the shared mailbox and auto-links to cases. + * + * @spec openspec/changes/case-email-integration/tasks.md#T08 */ class InboundEmailJob extends TimedJob { diff --git a/lib/BackgroundJob/ResetMonthlyQuotasJob.php b/lib/BackgroundJob/ResetMonthlyQuotasJob.php index 8a6150c3f..24f72fd29 100644 --- a/lib/BackgroundJob/ResetMonthlyQuotasJob.php +++ b/lib/BackgroundJob/ResetMonthlyQuotasJob.php @@ -36,6 +36,8 @@ /** * Resets monthly + hourly quotas after their window elapses. + * + * @spec openspec/changes/tenant-zaaksysteem-saas-09-quotas-enforcement/tasks.md */ class ResetMonthlyQuotasJob extends TimedJob { /** diff --git a/lib/BackgroundJob/ShareMaintenanceJob.php b/lib/BackgroundJob/ShareMaintenanceJob.php index 93c5bff0c..c3d917f49 100644 --- a/lib/BackgroundJob/ShareMaintenanceJob.php +++ b/lib/BackgroundJob/ShareMaintenanceJob.php @@ -39,6 +39,8 @@ * * Checks for shares expiring within 3 days and sends reminder * notifications to case workers. + * + * @spec openspec/specs/case-management/spec.md */ class ShareMaintenanceJob extends TimedJob { /** diff --git a/lib/BackgroundJob/StufRetryJob.php b/lib/BackgroundJob/StufRetryJob.php index 1e944a7f2..c36301964 100644 --- a/lib/BackgroundJob/StufRetryJob.php +++ b/lib/BackgroundJob/StufRetryJob.php @@ -36,6 +36,8 @@ /** * On-demand background job that retries a single StufMessage. + * + * @spec openspec/specs/stuf-zkn-outbound/spec.md#requirement-circuit-breaker-and-retry */ class StufRetryJob extends Job { /** diff --git a/lib/Command/BackfillLegalHoldsCommand.php b/lib/Command/BackfillLegalHoldsCommand.php index 667e60b4a..d3ef422a4 100644 --- a/lib/Command/BackfillLegalHoldsCommand.php +++ b/lib/Command/BackfillLegalHoldsCommand.php @@ -59,6 +59,8 @@ * Backfill the Awb legal holds the dead bezwaar listener never placed. * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) Remediation spans several OpenRegister collaborators. + * + * @spec openspec/specs/archief-edepot-handover/spec.md#requirement-legal-proceedings-must-suspend-archival-via-or-legal-holds */ class BackfillLegalHoldsCommand extends Command { diff --git a/lib/Command/SeedBezwaarBeroepCommand.php b/lib/Command/SeedBezwaarBeroepCommand.php index 953ebe88a..01885a972 100644 --- a/lib/Command/SeedBezwaarBeroepCommand.php +++ b/lib/Command/SeedBezwaarBeroepCommand.php @@ -40,6 +40,8 @@ /** * Seed the Bezwaar & Beroep case types, status types and role types. + * + * @spec openspec/specs/bezwaar-beroep-workflow/spec.md#requirement-req-bbw-001-bezwaar-casetype-seed-shall-be-installed-with-awb-compliant-process-configuration */ class SeedBezwaarBeroepCommand extends Command { /** diff --git a/lib/Controller/AdviceController.php b/lib/Controller/AdviceController.php index 2222ab304..aa7deefdd 100644 --- a/lib/Controller/AdviceController.php +++ b/lib/Controller/AdviceController.php @@ -43,6 +43,8 @@ /** * Controller for advice request workflow operations. + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ class AdviceController extends Controller { /** diff --git a/lib/Controller/AiAuditExportController.php b/lib/Controller/AiAuditExportController.php index 035ea693d..bf2abee4b 100644 --- a/lib/Controller/AiAuditExportController.php +++ b/lib/Controller/AiAuditExportController.php @@ -44,6 +44,8 @@ * Read-only action controller for the AI audit trail export. * * @psalm-suppress UnusedClass + * + * @spec openspec/changes/ai-oversight-log/tasks.md#2.1 */ class AiAuditExportController extends Controller { /** diff --git a/lib/Controller/AiController.php b/lib/Controller/AiController.php index bd27df387..7cfd9dbc1 100644 --- a/lib/Controller/AiController.php +++ b/lib/Controller/AiController.php @@ -48,6 +48,8 @@ * health endpoints live on {@see AiSettingsController}. * * @psalm-suppress UnusedClass + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ class AiController extends Controller { /** diff --git a/lib/Controller/AppointmentController.php b/lib/Controller/AppointmentController.php index 598011ff9..7624bf63b 100644 --- a/lib/Controller/AppointmentController.php +++ b/lib/Controller/AppointmentController.php @@ -36,6 +36,8 @@ /** * Controller exposing citizen appointment endpoints. + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ class AppointmentController extends Controller { /** diff --git a/lib/Controller/BerichtenboxController.php b/lib/Controller/BerichtenboxController.php index 3ff7c50a4..d967a4fe5 100644 --- a/lib/Controller/BerichtenboxController.php +++ b/lib/Controller/BerichtenboxController.php @@ -35,6 +35,8 @@ /** * Controller exposing Berichtenbox send/list/poll endpoints. + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ class BerichtenboxController extends Controller { /** diff --git a/lib/Controller/BesluitvormingController.php b/lib/Controller/BesluitvormingController.php index d3f0280ca..5e8c10866 100644 --- a/lib/Controller/BesluitvormingController.php +++ b/lib/Controller/BesluitvormingController.php @@ -42,6 +42,8 @@ * Controller exposing besluitvorming template-activation endpoints. * * @psalm-suppress UnusedClass + * + * @spec openspec/changes/besluitvorming-workflow/tasks.md#task-2 */ class BesluitvormingController extends Controller { /** diff --git a/lib/Controller/BrcController.php b/lib/Controller/BrcController.php index 79ef46691..915f16cd8 100644 --- a/lib/Controller/BrcController.php +++ b/lib/Controller/BrcController.php @@ -55,6 +55,8 @@ * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ class BrcController extends ZgwController { /** diff --git a/lib/Controller/ConsultationController.php b/lib/Controller/ConsultationController.php index c35cc361b..7a755264c 100644 --- a/lib/Controller/ConsultationController.php +++ b/lib/Controller/ConsultationController.php @@ -43,6 +43,8 @@ * * Every endpoint carries the NoAdminRequired annotation and applies the * ConsultationAccessGuard (OWASP A01:2021, ADR-005 Rule 3). + * + * @spec openspec/changes/consultation-management/tasks.md#TASK-CN-04 */ class ConsultationController extends Controller { /** diff --git a/lib/Controller/DashboardController.php b/lib/Controller/DashboardController.php index 9d78f0d45..4b0803b13 100644 --- a/lib/Controller/DashboardController.php +++ b/lib/Controller/DashboardController.php @@ -56,6 +56,8 @@ * Controller for the main Dossiq dashboard page plus the PWA assets. * * @psalm-suppress UnusedClass + * + * @spec openspec/changes/adopt-apphost/tasks.md#task-2.1 */ class DashboardController extends Controller { /** diff --git a/lib/Controller/DeelzaakController.php b/lib/Controller/DeelzaakController.php index 28832ccc2..a2c502532 100644 --- a/lib/Controller/DeelzaakController.php +++ b/lib/Controller/DeelzaakController.php @@ -38,6 +38,8 @@ /** * REST controller for sub-case operations. + * + * @spec openspec/specs/authz-bypass-fixes/spec.md */ class DeelzaakController extends Controller { /** diff --git a/lib/Controller/DoorlooptijdController.php b/lib/Controller/DoorlooptijdController.php index 85b8eff70..5e24a474b 100644 --- a/lib/Controller/DoorlooptijdController.php +++ b/lib/Controller/DoorlooptijdController.php @@ -37,6 +37,8 @@ /** * REST controller for the throughput-time dashboard. + * + * @spec openspec/changes/doorlooptijd-dashboard/tasks.md#T02 */ class DoorlooptijdController extends Controller { /** diff --git a/lib/Controller/DrcController.php b/lib/Controller/DrcController.php index 7735231e5..adc98c83a 100644 --- a/lib/Controller/DrcController.php +++ b/lib/Controller/DrcController.php @@ -53,6 +53,8 @@ * @SuppressWarnings(PHPMD.ExcessiveMethodLength) * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ class DrcController extends ZgwController { /** diff --git a/lib/Controller/EmailController.php b/lib/Controller/EmailController.php index 802519ef9..6f59005c0 100644 --- a/lib/Controller/EmailController.php +++ b/lib/Controller/EmailController.php @@ -35,6 +35,8 @@ /** * Controller for case email operations. + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ class EmailController extends Controller { /** diff --git a/lib/Controller/EmailTemplateController.php b/lib/Controller/EmailTemplateController.php index 58472869b..0900b4a8a 100644 --- a/lib/Controller/EmailTemplateController.php +++ b/lib/Controller/EmailTemplateController.php @@ -46,6 +46,8 @@ /** * REST controller for email-template templating + IMAP settings. + * + * @spec openspec/changes/case-email-integration/tasks.md#T06 */ class EmailTemplateController extends Controller { diff --git a/lib/Controller/Iv3TaakveldController.php b/lib/Controller/Iv3TaakveldController.php index c5d65dfe9..eca6eaca9 100644 --- a/lib/Controller/Iv3TaakveldController.php +++ b/lib/Controller/Iv3TaakveldController.php @@ -46,6 +46,8 @@ /** * Read-only access to the IV3/BBV taakveld reference list. + * + * @spec openspec/specs/iv3-taakveld-2023-refinement/spec.md */ class Iv3TaakveldController extends Controller { /** @@ -70,6 +72,8 @@ public function __construct( * is a public CBS classification, not report data). * * @return JSONResponse + * + * @spec openspec/specs/iv3-taakveld-2023-refinement/spec.md */ #[NoAdminRequired] public function taakvelden(): JSONResponse { diff --git a/lib/Controller/KccContactController.php b/lib/Controller/KccContactController.php index 0d88266cd..f5bd8de33 100644 --- a/lib/Controller/KccContactController.php +++ b/lib/Controller/KccContactController.php @@ -44,6 +44,8 @@ * Controller exposing KCC contact-moment and callback endpoints. * * @psalm-suppress UnusedClass + * + * @spec openspec/changes/kcc-klantcontact-integratie/tasks.md#TASK-KCC-16 */ class KccContactController extends Controller { /** @@ -73,6 +75,8 @@ public function __construct( * @NoAdminRequired * * @psalm-suppress PossiblyUnusedMethod + * + * @spec openspec/changes/kcc-klantcontact-integratie/tasks.md#TASK-KCC-16 */ public function index(): JSONResponse { $agentId = $this->requireAgentId(); @@ -107,6 +111,8 @@ public function index(): JSONResponse { * @NoAdminRequired * * @psalm-suppress PossiblyUnusedMethod + * + * @spec openspec/changes/kcc-klantcontact-integratie/tasks.md#TASK-KCC-16 */ public function create(): JSONResponse { $agentId = $this->requireAgentId(); @@ -133,6 +139,8 @@ public function create(): JSONResponse { * @NoAdminRequired * * @psalm-suppress PossiblyUnusedMethod + * + * @spec openspec/changes/kcc-klantcontact-integratie/tasks.md#TASK-KCC-16 */ public function show(string $id): JSONResponse { $agentId = $this->requireAgentId(); @@ -163,6 +171,8 @@ public function show(string $id): JSONResponse { * @NoAdminRequired * * @psalm-suppress PossiblyUnusedMethod + * + * @spec openspec/changes/kcc-klantcontact-integratie/tasks.md#TASK-KCC-16 */ public function update(string $id): JSONResponse { $agentId = $this->requireAgentId(); @@ -194,6 +204,8 @@ public function update(string $id): JSONResponse { * @NoAdminRequired * * @psalm-suppress PossiblyUnusedMethod + * + * @spec openspec/changes/kcc-klantcontact-integratie/tasks.md#TASK-KCC-16 */ public function related(string $id): JSONResponse { $agentId = $this->requireAgentId(); @@ -222,6 +234,8 @@ public function related(string $id): JSONResponse { * @NoAdminRequired * * @psalm-suppress PossiblyUnusedMethod + * + * @spec openspec/changes/kcc-klantcontact-integratie/tasks.md#TASK-KCC-16 */ public function scheduleCallback(): JSONResponse { $agentId = $this->requireAgentId(); @@ -246,6 +260,8 @@ public function scheduleCallback(): JSONResponse { * @NoAdminRequired * * @psalm-suppress PossiblyUnusedMethod + * + * @spec openspec/changes/kcc-klantcontact-integratie/tasks.md#TASK-KCC-16 */ public function indexCallbacks(): JSONResponse { $agentId = $this->requireAgentId(); @@ -278,6 +294,8 @@ public function indexCallbacks(): JSONResponse { * @NoAdminRequired * * @psalm-suppress PossiblyUnusedMethod + * + * @spec openspec/changes/kcc-klantcontact-integratie/tasks.md#TASK-KCC-16 */ public function cancelCallback(string $id): JSONResponse { $agentId = $this->requireAgentId(); diff --git a/lib/Controller/KccRoutingController.php b/lib/Controller/KccRoutingController.php index 1b5e3de64..faa4bf535 100644 --- a/lib/Controller/KccRoutingController.php +++ b/lib/Controller/KccRoutingController.php @@ -44,6 +44,8 @@ * Controller exposing KCC routing-rule and routing-evaluation endpoints. * * @psalm-suppress UnusedClass + * + * @spec openspec/changes/kcc-klantcontact-integratie/tasks.md#TASK-KCC-17 */ class KccRoutingController extends Controller { /** @@ -102,6 +104,8 @@ public function index(): JSONResponse { * @return JSONResponse * * @psalm-suppress PossiblyUnusedMethod + * + * @spec openspec/changes/kcc-klantcontact-integratie/tasks.md#TASK-KCC-17 */ #[AuthorizedAdminSetting(settings: AdminSettings::class)] public function create(): JSONResponse { @@ -130,6 +134,8 @@ public function create(): JSONResponse { * @return JSONResponse * * @psalm-suppress PossiblyUnusedMethod + * + * @spec openspec/changes/kcc-klantcontact-integratie/tasks.md#TASK-KCC-17 */ #[AuthorizedAdminSetting(settings: AdminSettings::class)] public function update(string $id): JSONResponse { diff --git a/lib/Controller/MilestoneController.php b/lib/Controller/MilestoneController.php index 746c213ae..aff2546b6 100644 --- a/lib/Controller/MilestoneController.php +++ b/lib/Controller/MilestoneController.php @@ -36,6 +36,8 @@ /** * Controller for milestone progress tracking. + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ class MilestoneController extends Controller { /** diff --git a/lib/Controller/NotesController.php b/lib/Controller/NotesController.php index 310bf9929..a8e784235 100644 --- a/lib/Controller/NotesController.php +++ b/lib/Controller/NotesController.php @@ -44,6 +44,8 @@ /** * Controller for note-mention notification side-effects. + * + * @spec openspec/specs/ncvue-w2-leaves-adoption/spec.md */ class NotesController extends Controller { /** diff --git a/lib/Controller/NoticeOfDefaultController.php b/lib/Controller/NoticeOfDefaultController.php index d3634ca03..b3d12cc53 100644 --- a/lib/Controller/NoticeOfDefaultController.php +++ b/lib/Controller/NoticeOfDefaultController.php @@ -40,6 +40,8 @@ * REST surface for ingebrekestelling registration. * * @psalm-suppress UnusedClass + * + * @spec openspec/changes/termijnbewaking-dwangsom-engine-10-bezwaar-rest-api/tasks.md */ class NoticeOfDefaultController extends Controller { diff --git a/lib/Controller/NrcController.php b/lib/Controller/NrcController.php index 26be9187f..eb11ab330 100644 --- a/lib/Controller/NrcController.php +++ b/lib/Controller/NrcController.php @@ -44,6 +44,8 @@ * @psalm-suppress UnusedClass * * @SuppressWarnings(PHPMD.TooManyPublicMethods) + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ class NrcController extends ZgwController { /** diff --git a/lib/Controller/PublicAppointmentController.php b/lib/Controller/PublicAppointmentController.php index 79a67d5db..3846af0fd 100644 --- a/lib/Controller/PublicAppointmentController.php +++ b/lib/Controller/PublicAppointmentController.php @@ -33,6 +33,8 @@ /** * Public (citizen-facing) endpoints for appointment view/cancel by token. + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ class PublicAppointmentController extends Controller { /** diff --git a/lib/Controller/PublicationController.php b/lib/Controller/PublicationController.php index ff873ba17..9762f0958 100644 --- a/lib/Controller/PublicationController.php +++ b/lib/Controller/PublicationController.php @@ -41,6 +41,8 @@ * Controller exposing besluitvorming publication endpoints. * * @psalm-suppress UnusedClass + * + * @spec openspec/changes/besluitvorming-workflow/tasks.md#task-7 */ class PublicationController extends Controller { /** diff --git a/lib/Controller/SetupController.php b/lib/Controller/SetupController.php index ca66035d8..551f8a04c 100644 --- a/lib/Controller/SetupController.php +++ b/lib/Controller/SetupController.php @@ -305,10 +305,11 @@ private function installDemoData(): DataResponse { [ 'success' => true, 'message' => sprintf( - 'Demo data installed: %d of %d objects stored, %d refused.', + 'Demo data installed: %d of %d objects stored, %d refused, %d already present.', $imported['objects'], $imported['requested'], - $imported['refused'] + $imported['refused'], + $imported['unchanged'] ), 'detail' => $imported, ] diff --git a/lib/Controller/StufController.php b/lib/Controller/StufController.php index 7e9bec5e1..5059b05de 100644 --- a/lib/Controller/StufController.php +++ b/lib/Controller/StufController.php @@ -65,6 +65,8 @@ * @psalm-suppress UnusedClass * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ class StufController extends Controller { /** diff --git a/lib/Controller/TemplateController.php b/lib/Controller/TemplateController.php index 8618932f6..b6ad9aed0 100644 --- a/lib/Controller/TemplateController.php +++ b/lib/Controller/TemplateController.php @@ -35,6 +35,8 @@ /** * Controller for zaaktype template management. + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ class TemplateController extends Controller { /** diff --git a/lib/Controller/TenantController.php b/lib/Controller/TenantController.php index 503703f64..d06cbef2b 100644 --- a/lib/Controller/TenantController.php +++ b/lib/Controller/TenantController.php @@ -49,6 +49,8 @@ * pages call the OpenRegister object endpoints directly. Only the three domain * methods below remain: they wrap provisioning workflow, resource-usage * aggregation, and current-tenant resolution. + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ class TenantController extends Controller { /** diff --git a/lib/Controller/TenantOnboardingController.php b/lib/Controller/TenantOnboardingController.php index 904cf69ca..0bf4b4923 100644 --- a/lib/Controller/TenantOnboardingController.php +++ b/lib/Controller/TenantOnboardingController.php @@ -35,6 +35,8 @@ /** * Onboarding REST controller. + * + * @spec openspec/changes/tenant-zaaksysteem-saas-07-onboarding-workflow/tasks.md */ class TenantOnboardingController extends Controller { /** @@ -58,6 +60,8 @@ public function __construct( * @param string $tenantId Tenant UUID. * * @return JSONResponse + * + * @spec openspec/changes/tenant-zaaksysteem-saas-07-onboarding-workflow/tasks.md */ #[AuthorizedAdminSetting(AdminSettings::class)] public function progress(string $tenantId): JSONResponse { @@ -76,6 +80,8 @@ public function progress(string $tenantId): JSONResponse { * @param string $step Step name. * * @return JSONResponse + * + * @spec openspec/changes/tenant-zaaksysteem-saas-07-onboarding-workflow/tasks.md */ #[AuthorizedAdminSetting(AdminSettings::class)] public function complete(string $tenantId, string $step): JSONResponse { @@ -107,6 +113,8 @@ public function complete(string $tenantId, string $step): JSONResponse { * @param string $tenantId Tenant UUID. * * @return JSONResponse + * + * @spec openspec/changes/tenant-zaaksysteem-saas-07-onboarding-workflow/tasks.md */ #[AuthorizedAdminSetting(AdminSettings::class)] public function activate(string $tenantId): JSONResponse { @@ -125,6 +133,8 @@ public function activate(string $tenantId): JSONResponse { * @param string $tenantId Tenant UUID. * * @return JSONResponse + * + * @spec openspec/changes/tenant-zaaksysteem-saas-07-onboarding-workflow/tasks.md */ #[AuthorizedAdminSetting(AdminSettings::class)] public function initialise(string $tenantId): JSONResponse { diff --git a/lib/Controller/TenantSaasController.php b/lib/Controller/TenantSaasController.php index f410e1845..0f926d570 100644 --- a/lib/Controller/TenantSaasController.php +++ b/lib/Controller/TenantSaasController.php @@ -51,6 +51,8 @@ * PATCH /api/saas/tenants/{tenantId} → update (display + optional status) * DELETE /api/saas/tenants/{tenantId} → destroy * POST /api/saas/tenants/{tenantId}/status → transition + * + * @spec openspec/changes/tenant-zaaksysteem-saas-02-tenant-crud-lifecycle/tasks.md */ class TenantSaasController extends Controller { /** diff --git a/lib/Controller/ZaakdossierController.php b/lib/Controller/ZaakdossierController.php index 5ed9a5622..46a5217a0 100644 --- a/lib/Controller/ZaakdossierController.php +++ b/lib/Controller/ZaakdossierController.php @@ -47,6 +47,8 @@ /** * Controller for the ZGW DRC zaakdossier. + * + * @spec openspec/changes/document-zaakdossier/tasks.md#T05 */ class ZaakdossierController extends Controller { /** diff --git a/lib/Controller/ZgwController.php b/lib/Controller/ZgwController.php index 47e66c318..e54357252 100644 --- a/lib/Controller/ZgwController.php +++ b/lib/Controller/ZgwController.php @@ -38,6 +38,8 @@ * controllers fall under ZGW JWT authentication and scope enforcement. * Any controller that handles a ZGW API endpoint must extend this class * so the middleware's guard is actually exercised. + * + * @spec openspec/specs/zgw-api-mapping/spec.md */ abstract class ZgwController extends Controller { use NormalisesObjectRows; diff --git a/lib/Controller/ZgwMappingController.php b/lib/Controller/ZgwMappingController.php index d53b4180e..c7c49f658 100644 --- a/lib/Controller/ZgwMappingController.php +++ b/lib/Controller/ZgwMappingController.php @@ -41,6 +41,8 @@ /** * Controller for managing ZGW API mapping configurations. + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ class ZgwMappingController extends Controller { /** diff --git a/lib/Controller/ZrcController.php b/lib/Controller/ZrcController.php index ad1e79ff1..2a55bbbf6 100644 --- a/lib/Controller/ZrcController.php +++ b/lib/Controller/ZrcController.php @@ -58,6 +58,8 @@ * @SuppressWarnings(PHPMD.NPathComplexity) * @SuppressWarnings(PHPMD.TooManyMethods) * @SuppressWarnings(PHPMD.TooManyPublicMethods) + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ class ZrcController extends ZgwController { /** diff --git a/lib/Controller/ZtcController.php b/lib/Controller/ZtcController.php index 6b49bab78..21c11557c 100644 --- a/lib/Controller/ZtcController.php +++ b/lib/Controller/ZtcController.php @@ -50,6 +50,8 @@ * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ class ZtcController extends ZgwController { /** diff --git a/lib/Dashboard/CasesOverviewWidget.php b/lib/Dashboard/CasesOverviewWidget.php index 3edb51aea..ccda3f3a7 100644 --- a/lib/Dashboard/CasesOverviewWidget.php +++ b/lib/Dashboard/CasesOverviewWidget.php @@ -36,6 +36,8 @@ /** * Dashboard widget showing an overview of recent cases. + * + * @spec openspec/specs/dashboard/spec.md */ class CasesOverviewWidget implements IWidget { /** @@ -55,6 +57,8 @@ public function __construct( * * @inheritDoc * @return string The widget identifier + * + * @spec openspec/specs/dashboard/spec.md */ public function getId(): string { // FROZEN at `procest_*` — deliberately NOT renamed with the app id. @@ -73,6 +77,8 @@ public function getId(): string { * * @inheritDoc * @return string The widget title + * + * @spec openspec/specs/dashboard/spec.md */ public function getTitle(): string { return $this->l10n->t('Cases overview'); @@ -83,6 +89,8 @@ public function getTitle(): string { * * @inheritDoc * @return int The widget order + * + * @spec openspec/specs/dashboard/spec.md */ public function getOrder(): int { return 10; @@ -93,6 +101,8 @@ public function getOrder(): int { * * @inheritDoc * @return string The icon CSS class + * + * @spec openspec/specs/dashboard/spec.md */ public function getIconClass(): string { return 'icon-dossiq-widget'; @@ -103,6 +113,8 @@ public function getIconClass(): string { * * @inheritDoc * @return string|null The widget URL or null + * + * @spec openspec/specs/dashboard/spec.md */ public function getUrl(): ?string { return $this->url->linkToRouteAbsolute(Application::APP_ID . '.dashboard.page'); @@ -115,6 +127,8 @@ public function getUrl(): ?string { * @return void * * @SuppressWarnings(PHPMD.StaticAccess) — Nextcloud Util API is static by design + * + * @spec openspec/specs/dashboard/spec.md */ public function load(): void { // Shared vendor chunks emitted by webpack splitChunks (see webpack.config.js). diff --git a/lib/Dashboard/DeadlineAlertsWidget.php b/lib/Dashboard/DeadlineAlertsWidget.php index 12caf930a..bb8d19d8e 100644 --- a/lib/Dashboard/DeadlineAlertsWidget.php +++ b/lib/Dashboard/DeadlineAlertsWidget.php @@ -38,6 +38,8 @@ /** * Dashboard widget showing deadline alerts for cases. + * + * @spec openspec/specs/signalering-widgets/spec.md */ class DeadlineAlertsWidget implements IWidget { /** @@ -57,6 +59,8 @@ public function __construct( * * @inheritDoc * @return string The widget identifier + * + * @spec openspec/specs/signalering-widgets/spec.md */ public function getId(): string { // FROZEN at the old app-id prefix — see CasesOverviewWidget::getId(). @@ -68,6 +72,8 @@ public function getId(): string { * * @inheritDoc * @return string The widget title + * + * @spec openspec/specs/signalering-widgets/spec.md */ public function getTitle(): string { return $this->l10n->t('Deadline Alerts'); @@ -78,6 +84,8 @@ public function getTitle(): string { * * @inheritDoc * @return int The widget order + * + * @spec openspec/specs/signalering-widgets/spec.md */ public function getOrder(): int { return 11; @@ -88,6 +96,8 @@ public function getOrder(): int { * * @inheritDoc * @return string The icon CSS class + * + * @spec openspec/specs/signalering-widgets/spec.md */ public function getIconClass(): string { return 'icon-dossiq-widget'; @@ -98,6 +108,8 @@ public function getIconClass(): string { * * @inheritDoc * @return string|null The widget URL or null + * + * @spec openspec/specs/signalering-widgets/spec.md */ public function getUrl(): ?string { return $this->url->linkToRouteAbsolute(Application::APP_ID . '.dashboard.page'); @@ -110,6 +122,8 @@ public function getUrl(): ?string { * @return void * * @SuppressWarnings(PHPMD.StaticAccess) — Nextcloud Util API is static by design + * + * @spec openspec/specs/signalering-widgets/spec.md */ public function load(): void { // Shared vendor chunks emitted by webpack splitChunks (see webpack.config.js). diff --git a/lib/Dashboard/MyTasksWidget.php b/lib/Dashboard/MyTasksWidget.php index a986c6198..b99470e9b 100644 --- a/lib/Dashboard/MyTasksWidget.php +++ b/lib/Dashboard/MyTasksWidget.php @@ -36,6 +36,8 @@ /** * Dashboard widget showing tasks assigned to the current user. + * + * @spec openspec/specs/dashboard/spec.md */ class MyTasksWidget implements IWidget { /** @@ -55,6 +57,8 @@ public function __construct( * * @inheritDoc * @return string The widget identifier + * + * @spec openspec/specs/dashboard/spec.md */ public function getId(): string { // FROZEN at the old app-id prefix — see CasesOverviewWidget::getId() @@ -70,6 +74,8 @@ public function getId(): string { * * @inheritDoc * @return string The widget title + * + * @spec openspec/specs/dashboard/spec.md */ public function getTitle(): string { return $this->l10n->t('My Tasks'); @@ -80,6 +86,8 @@ public function getTitle(): string { * * @inheritDoc * @return int The widget order + * + * @spec openspec/specs/dashboard/spec.md */ public function getOrder(): int { return 12; @@ -90,6 +98,8 @@ public function getOrder(): int { * * @inheritDoc * @return string The icon CSS class + * + * @spec openspec/specs/dashboard/spec.md */ public function getIconClass(): string { return 'icon-dossiq-widget'; @@ -100,6 +110,8 @@ public function getIconClass(): string { * * @inheritDoc * @return string|null The widget URL or null + * + * @spec openspec/specs/dashboard/spec.md */ public function getUrl(): ?string { return $this->url->linkToRouteAbsolute(Application::APP_ID . '.dashboard.page'); @@ -112,6 +124,8 @@ public function getUrl(): ?string { * @return void * * @SuppressWarnings(PHPMD.StaticAccess) — Nextcloud Util API is static by design + * + * @spec openspec/specs/dashboard/spec.md */ public function load(): void { // Shared vendor chunks emitted by webpack splitChunks (see webpack.config.js). diff --git a/lib/Dashboard/OverdueCasesWidget.php b/lib/Dashboard/OverdueCasesWidget.php index 825913df4..c0d167574 100644 --- a/lib/Dashboard/OverdueCasesWidget.php +++ b/lib/Dashboard/OverdueCasesWidget.php @@ -37,6 +37,8 @@ /** * Dashboard widget showing overdue cases with deadline info. + * + * @spec openspec/specs/signalering-widgets/spec.md */ class OverdueCasesWidget implements IWidget { /** @@ -56,6 +58,8 @@ public function __construct( * * @inheritDoc * @return string The widget identifier + * + * @spec openspec/specs/signalering-widgets/spec.md */ public function getId(): string { // FROZEN at the old app-id prefix — see CasesOverviewWidget::getId(). @@ -67,6 +71,8 @@ public function getId(): string { * * @inheritDoc * @return string The widget title + * + * @spec openspec/specs/signalering-widgets/spec.md */ public function getTitle(): string { return $this->l10n->t('Overdue Cases'); @@ -77,6 +83,8 @@ public function getTitle(): string { * * @inheritDoc * @return int The widget order + * + * @spec openspec/specs/signalering-widgets/spec.md */ public function getOrder(): int { return 11; @@ -87,6 +95,8 @@ public function getOrder(): int { * * @inheritDoc * @return string The icon CSS class + * + * @spec openspec/specs/signalering-widgets/spec.md */ public function getIconClass(): string { return 'icon-dossiq-widget'; @@ -97,6 +107,8 @@ public function getIconClass(): string { * * @inheritDoc * @return string|null The widget URL or null + * + * @spec openspec/specs/signalering-widgets/spec.md */ public function getUrl(): ?string { return $this->url->linkToRouteAbsolute(Application::APP_ID . '.dashboard.page'); @@ -109,6 +121,8 @@ public function getUrl(): ?string { * @return void * * @SuppressWarnings(PHPMD.StaticAccess) — Nextcloud Util API is static by design + * + * @spec openspec/specs/signalering-widgets/spec.md */ public function load(): void { // Shared vendor chunks emitted by webpack splitChunks (see webpack.config.js). diff --git a/lib/Dashboard/StalledCasesWidget.php b/lib/Dashboard/StalledCasesWidget.php index 411bbaaaf..0161b449c 100644 --- a/lib/Dashboard/StalledCasesWidget.php +++ b/lib/Dashboard/StalledCasesWidget.php @@ -38,6 +38,8 @@ /** * Dashboard widget showing stalled (inactive) cases. + * + * @spec openspec/specs/signalering-widgets/spec.md */ class StalledCasesWidget implements IWidget { /** @@ -57,6 +59,8 @@ public function __construct( * * @inheritDoc * @return string The widget identifier + * + * @spec openspec/specs/signalering-widgets/spec.md */ public function getId(): string { // FROZEN at the old app-id prefix — see CasesOverviewWidget::getId(). @@ -68,6 +72,8 @@ public function getId(): string { * * @inheritDoc * @return string The widget title + * + * @spec openspec/specs/signalering-widgets/spec.md */ public function getTitle(): string { return $this->l10n->t('Stalled Cases'); @@ -78,6 +84,8 @@ public function getTitle(): string { * * @inheritDoc * @return int The widget order + * + * @spec openspec/specs/signalering-widgets/spec.md */ public function getOrder(): int { return 13; @@ -88,6 +96,8 @@ public function getOrder(): int { * * @inheritDoc * @return string The icon CSS class + * + * @spec openspec/specs/signalering-widgets/spec.md */ public function getIconClass(): string { return 'icon-dossiq-widget'; @@ -98,6 +108,8 @@ public function getIconClass(): string { * * @inheritDoc * @return string|null The widget URL or null + * + * @spec openspec/specs/signalering-widgets/spec.md */ public function getUrl(): ?string { return $this->url->linkToRouteAbsolute(Application::APP_ID . '.dashboard.page'); @@ -110,6 +122,8 @@ public function getUrl(): ?string { * @return void * * @SuppressWarnings(PHPMD.StaticAccess) — Nextcloud Util API is static by design + * + * @spec openspec/specs/signalering-widgets/spec.md */ public function load(): void { // Shared vendor chunks emitted by webpack splitChunks (see webpack.config.js). diff --git a/lib/Dashboard/StartCaseWidget.php b/lib/Dashboard/StartCaseWidget.php index 0045f44fe..547c15882 100644 --- a/lib/Dashboard/StartCaseWidget.php +++ b/lib/Dashboard/StartCaseWidget.php @@ -36,6 +36,8 @@ /** * Dashboard widget showing available case types for quick case creation. + * + * @spec openspec/specs/dashboard/spec.md */ class StartCaseWidget implements IWidget { /** @@ -55,6 +57,8 @@ public function __construct( * * @inheritDoc * @return string The widget identifier + * + * @spec openspec/specs/dashboard/spec.md */ public function getId(): string { // FROZEN at the old app-id prefix — see CasesOverviewWidget::getId(). @@ -66,6 +70,8 @@ public function getId(): string { * * @inheritDoc * @return string The widget title + * + * @spec openspec/specs/dashboard/spec.md */ public function getTitle(): string { return $this->l10n->t('Start case'); @@ -76,6 +82,8 @@ public function getTitle(): string { * * @inheritDoc * @return int The widget order + * + * @spec openspec/specs/dashboard/spec.md */ public function getOrder(): int { return 15; @@ -86,6 +94,8 @@ public function getOrder(): int { * * @inheritDoc * @return string The icon CSS class + * + * @spec openspec/specs/dashboard/spec.md */ public function getIconClass(): string { return 'icon-dossiq-widget'; @@ -96,6 +106,8 @@ public function getIconClass(): string { * * @inheritDoc * @return string|null The widget URL or null + * + * @spec openspec/specs/dashboard/spec.md */ public function getUrl(): ?string { return $this->url->linkToRouteAbsolute(Application::APP_ID . '.dashboard.page'); @@ -108,6 +120,8 @@ public function getUrl(): ?string { * @return void * * @SuppressWarnings(PHPMD.StaticAccess) — Nextcloud Util API is static by design + * + * @spec openspec/specs/dashboard/spec.md */ public function load(): void { // Shared vendor chunks emitted by webpack splitChunks (see webpack.config.js). diff --git a/lib/Dashboard/TaskRemindersWidget.php b/lib/Dashboard/TaskRemindersWidget.php index 219d93a81..3989ec0af 100644 --- a/lib/Dashboard/TaskRemindersWidget.php +++ b/lib/Dashboard/TaskRemindersWidget.php @@ -38,6 +38,8 @@ /** * Dashboard widget showing task due reminders. + * + * @spec openspec/specs/signalering-widgets/spec.md */ class TaskRemindersWidget implements IWidget { /** @@ -57,6 +59,8 @@ public function __construct( * * @inheritDoc * @return string The widget identifier + * + * @spec openspec/specs/signalering-widgets/spec.md */ public function getId(): string { // FROZEN at the old app-id prefix — see CasesOverviewWidget::getId(). @@ -68,6 +72,8 @@ public function getId(): string { * * @inheritDoc * @return string The widget title + * + * @spec openspec/specs/signalering-widgets/spec.md */ public function getTitle(): string { return $this->l10n->t('Task Reminders'); @@ -78,6 +84,8 @@ public function getTitle(): string { * * @inheritDoc * @return int The widget order + * + * @spec openspec/specs/signalering-widgets/spec.md */ public function getOrder(): int { return 12; @@ -88,6 +96,8 @@ public function getOrder(): int { * * @inheritDoc * @return string The icon CSS class + * + * @spec openspec/specs/signalering-widgets/spec.md */ public function getIconClass(): string { return 'icon-dossiq-widget'; @@ -98,6 +108,8 @@ public function getIconClass(): string { * * @inheritDoc * @return string|null The widget URL or null + * + * @spec openspec/specs/signalering-widgets/spec.md */ public function getUrl(): ?string { return $this->url->linkToRouteAbsolute(Application::APP_ID . '.dashboard.page'); @@ -110,6 +122,8 @@ public function getUrl(): ?string { * @return void * * @SuppressWarnings(PHPMD.StaticAccess) — Nextcloud Util API is static by design + * + * @spec openspec/specs/signalering-widgets/spec.md */ public function load(): void { // Shared vendor chunks emitted by webpack splitChunks (see webpack.config.js). diff --git a/lib/Flow/DossiqFlowNodeBase.php b/lib/Flow/DossiqFlowNodeBase.php index e61a5440f..c6f7e6836 100644 --- a/lib/Flow/DossiqFlowNodeBase.php +++ b/lib/Flow/DossiqFlowNodeBase.php @@ -121,6 +121,8 @@ public function getId(): string { * The node icon. * * @return string The icon path. + * + * @spec openspec/changes/page-topology-cleanup/specs/automatic-actions-surface/spec.md */ public function getIcon(): string { return $this->urls->imagePath('dossiq', 'app-dark.svg'); @@ -217,6 +219,8 @@ public function execute(array $items, array $config, array $context): array { * @param integer $scope The Nextcloud workflow scope. * * @return boolean True when available in this scope. + * + * @spec openspec/changes/page-topology-cleanup/specs/automatic-actions-surface/spec.md */ public function isAvailableForScope(int $scope): bool { return in_array($scope, [IManager::SCOPE_ADMIN, IManager::SCOPE_USER], true); diff --git a/lib/Http/RangeStreamResponse.php b/lib/Http/RangeStreamResponse.php index 199ee2baa..b2f32b408 100644 --- a/lib/Http/RangeStreamResponse.php +++ b/lib/Http/RangeStreamResponse.php @@ -38,6 +38,8 @@ * @template-extends Response<200|206|404|416, array> * * @psalm-suppress InvalidTemplateParam + * + * @spec openspec/changes/document-zaakdossier/tasks.md#T05 */ class RangeStreamResponse extends Response { @@ -85,6 +87,8 @@ public function __construct(string $content, string $fileName, string $contentTy * Render the response body. * * @return string The (possibly sliced) content. + * + * @spec openspec/changes/document-zaakdossier/tasks.md#T05 */ public function render(): string { return $this->body; diff --git a/lib/Listener/BezwaarLifecycleListener.php b/lib/Listener/BezwaarLifecycleListener.php index 59330bc88..f793b5c66 100644 --- a/lib/Listener/BezwaarLifecycleListener.php +++ b/lib/Listener/BezwaarLifecycleListener.php @@ -49,6 +49,8 @@ * status-transition-engine without owning any transition logic itself. * * @template-implements IEventListener + * + * @spec openspec/specs/bezwaar-lifecycle/spec.md */ class BezwaarLifecycleListener implements IEventListener { diff --git a/lib/Listener/TermijnTimerFiredListener.php b/lib/Listener/TermijnTimerFiredListener.php index d5da79c27..f2eb69656 100644 --- a/lib/Listener/TermijnTimerFiredListener.php +++ b/lib/Listener/TermijnTimerFiredListener.php @@ -52,6 +52,8 @@ * Maps engine rung fires onto the AWB termijn domain actions. * * @template-implements IEventListener + * + * @spec openspec/changes/termijnbewaking-op-engine-timers/tasks.md */ class TermijnTimerFiredListener implements IEventListener { use SearchesObjects; diff --git a/lib/Mcp/DossiqToolProvider.php b/lib/Mcp/DossiqToolProvider.php index d75ce6afd..094e8c6ac 100644 --- a/lib/Mcp/DossiqToolProvider.php +++ b/lib/Mcp/DossiqToolProvider.php @@ -55,6 +55,8 @@ * the Nextcloud system admin group), mirroring StatusTransitionService. * - A non-admin caller may read a case only when they are its assignee * (primary handler) or hold a role record linking them to the case. + * + * @spec openspec/specs/mcp-integration/spec.md */ class DossiqToolProvider implements IMcpToolProvider { @@ -139,6 +141,8 @@ public function __construct( * Returns the app ID that namespaces every tool id. * * @return string "dossiq" + * + * @spec openspec/specs/mcp-integration/spec.md */ public function getAppId(): string { return 'dossiq'; @@ -151,6 +155,8 @@ public function getAppId(): string { * Per-object authorisation runs in invokeTool(). * * @return array> + * + * @spec openspec/specs/mcp-integration/spec.md */ public function getTools(): array { return self::TOOL_DESCRIPTORS; @@ -167,6 +173,8 @@ public function getTools(): array { * @param array $arguments Tool arguments from the LLM call * * @return array + * + * @spec openspec/specs/mcp-integration/spec.md */ public function invokeTool(string $toolId, array $arguments): array { switch ($toolId) { diff --git a/lib/Middleware/MandateDeniedException.php b/lib/Middleware/MandateDeniedException.php index 8e86e4370..90e04499f 100644 --- a/lib/Middleware/MandateDeniedException.php +++ b/lib/Middleware/MandateDeniedException.php @@ -26,6 +26,8 @@ /** * Mandate matrix denied this request. + * + * @spec openspec/changes/tenant-zaaksysteem-saas-06-mandate-validation/tasks.md */ class MandateDeniedException extends Exception { }//end class diff --git a/lib/Middleware/MandateValidationMiddleware.php b/lib/Middleware/MandateValidationMiddleware.php index 7faa055e1..a55227d26 100644 --- a/lib/Middleware/MandateValidationMiddleware.php +++ b/lib/Middleware/MandateValidationMiddleware.php @@ -35,6 +35,8 @@ /** * Mandate-matrix middleware. Audit-logs every decision (allow + deny). + * + * @spec openspec/changes/tenant-zaaksysteem-saas-06-mandate-validation/tasks.md */ class MandateValidationMiddleware extends Middleware { /** @@ -87,6 +89,8 @@ public function __construct( * @SuppressWarnings(PHPMD.UnusedFormalParameter) $controller and $methodName are * fixed by OCP\AppFramework\Middleware::beforeController(); this middleware * dispatches on the request URI instead. + * + * @spec openspec/changes/tenant-zaaksysteem-saas-06-mandate-validation/tasks.md */ public function beforeController($controller, $methodName): void { if ($this->context->isBound() === false) { @@ -137,6 +141,8 @@ public function beforeController($controller, $methodName): void { * @SuppressWarnings(PHPMD.UnusedFormalParameter) $controller and $methodName are * fixed by OCP\AppFramework\Middleware::afterException(); only $exception is * inspected. + * + * @spec openspec/changes/tenant-zaaksysteem-saas-06-mandate-validation/tasks.md */ public function afterException($controller, $methodName, \Exception $exception): \OCP\AppFramework\Http\Response { if ($exception instanceof MandateDeniedException) { @@ -156,6 +162,8 @@ public function afterException($controller, $methodName, \Exception $exception): * @param string $path Request URI. * * @return string|null Action or null when no mandate gate applies. + * + * @spec openspec/changes/tenant-zaaksysteem-saas-06-mandate-validation/tasks.md */ public function resolveAction(string $verb, string $path): ?string { foreach (self::STATUS_PATH_HINTS as $hint) { diff --git a/lib/Middleware/QuotaEnforcementMiddleware.php b/lib/Middleware/QuotaEnforcementMiddleware.php index 4760a9e92..87c446af7 100644 --- a/lib/Middleware/QuotaEnforcementMiddleware.php +++ b/lib/Middleware/QuotaEnforcementMiddleware.php @@ -33,6 +33,8 @@ /** * Pre-controller quota enforcement. + * + * @spec openspec/changes/tenant-zaaksysteem-saas-09-quotas-enforcement/tasks.md */ class QuotaEnforcementMiddleware extends Middleware { /** @@ -62,6 +64,8 @@ public function __construct( * @SuppressWarnings(PHPMD.UnusedFormalParameter) $controller and $methodName are * fixed by OCP\AppFramework\Middleware::beforeController(); this middleware * dispatches on the request URI instead. + * + * @spec openspec/changes/tenant-zaaksysteem-saas-09-quotas-enforcement/tasks.md */ public function beforeController($controller, $methodName): void { if ($this->context->isBound() === false) { @@ -115,6 +119,8 @@ public function beforeController($controller, $methodName): void { * @SuppressWarnings(PHPMD.UnusedFormalParameter) $controller and $methodName are * fixed by OCP\AppFramework\Middleware::afterException(); only $exception is * inspected. + * + * @spec openspec/changes/tenant-zaaksysteem-saas-09-quotas-enforcement/tasks.md */ public function afterException($controller, $methodName, \Exception $exception): \OCP\AppFramework\Http\Response { if ($exception instanceof QuotaExceededException) { @@ -134,6 +140,8 @@ public function afterException($controller, $methodName, \Exception $exception): * @param string $path URI. * * @return string|null + * + * @spec openspec/changes/tenant-zaaksysteem-saas-09-quotas-enforcement/tasks.md */ public function resolveQuotaType(string $verb, string $path): ?string { if ($verb === 'POST' && (str_contains($path, '/api/case') === true || str_contains($path, '/api/cases') === true)) { diff --git a/lib/Middleware/QuotaExceededException.php b/lib/Middleware/QuotaExceededException.php index 7da70cbd9..c1b78b6ac 100644 --- a/lib/Middleware/QuotaExceededException.php +++ b/lib/Middleware/QuotaExceededException.php @@ -26,6 +26,8 @@ /** * Tenant quota exceeded (429). + * + * @spec openspec/changes/tenant-zaaksysteem-saas-09-quotas-enforcement/tasks.md */ class QuotaExceededException extends Exception { }//end class diff --git a/lib/Middleware/TenantClaimMismatchException.php b/lib/Middleware/TenantClaimMismatchException.php index bd933c22b..b4e71f96e 100644 --- a/lib/Middleware/TenantClaimMismatchException.php +++ b/lib/Middleware/TenantClaimMismatchException.php @@ -29,6 +29,8 @@ /** * Tenant-claim mismatch exception (always 403). + * + * @spec openspec/changes/tenant-zaaksysteem-saas-05-auth-jwt-tenant-claim/tasks.md */ class TenantClaimMismatchException extends Exception { }//end class diff --git a/lib/Middleware/TenantClaimValidationMiddleware.php b/lib/Middleware/TenantClaimValidationMiddleware.php index eb0ecc015..9f9ea2f44 100644 --- a/lib/Middleware/TenantClaimValidationMiddleware.php +++ b/lib/Middleware/TenantClaimValidationMiddleware.php @@ -42,6 +42,8 @@ /** * Validate JWT tenant_id ↔ request-tenant match. Fail-closed. + * + * @spec openspec/changes/tenant-zaaksysteem-saas-05-auth-jwt-tenant-claim/tasks.md */ class TenantClaimValidationMiddleware extends Middleware { /** @@ -98,6 +100,8 @@ public function __construct( * @SuppressWarnings(PHPMD.UnusedFormalParameter) $controller and $methodName are * fixed by OCP\AppFramework\Middleware::beforeController(); this middleware * validates the bound tenant claim instead. + * + * @spec openspec/changes/tenant-zaaksysteem-saas-05-auth-jwt-tenant-claim/tasks.md */ public function beforeController($controller, $methodName): void { // No bearer header → not a JWT-authenticated request; let other auth layers handle. @@ -145,6 +149,8 @@ public function beforeController($controller, $methodName): void { * @SuppressWarnings(PHPMD.UnusedFormalParameter) $controller and $methodName are * fixed by OCP\AppFramework\Middleware::afterException(); only $exception is * inspected. + * + * @spec openspec/changes/tenant-zaaksysteem-saas-05-auth-jwt-tenant-claim/tasks.md */ public function afterException($controller, $methodName, \Exception $exception): \OCP\AppFramework\Http\Response { if ($exception instanceof TenantClaimMismatchException) { diff --git a/lib/Middleware/TenantContextMiddleware.php b/lib/Middleware/TenantContextMiddleware.php index f84b88a6e..15d415be2 100644 --- a/lib/Middleware/TenantContextMiddleware.php +++ b/lib/Middleware/TenantContextMiddleware.php @@ -51,6 +51,8 @@ /** * Middleware that resolves the tenant and binds it to the TenantContext. + * + * @spec openspec/changes/tenant-zaaksysteem-saas-04-tenant-context-isolation/tasks.md */ class TenantContextMiddleware extends Middleware { /** @@ -100,6 +102,8 @@ public function __construct( * @SuppressWarnings(PHPMD.UnusedFormalParameter) $methodName is fixed by * OCP\AppFramework\Middleware::beforeController(); tenant resolution keys off * the controller class and the request, not the action name. + * + * @spec openspec/changes/tenant-zaaksysteem-saas-04-tenant-context-isolation/tasks.md */ public function beforeController($controller, $methodName): void { if (in_array(get_class($controller), self::EXEMPT_CONTROLLERS, true) === true) { @@ -150,6 +154,8 @@ public function beforeController($controller, $methodName): void { * @SuppressWarnings(PHPMD.UnusedFormalParameter) $controller and $methodName are * fixed by OCP\AppFramework\Middleware::afterException(); this hook only * re-throws. + * + * @spec openspec/changes/tenant-zaaksysteem-saas-04-tenant-context-isolation/tasks.md */ public function afterException($controller, $methodName, \Exception $exception): \OCP\AppFramework\Http\Response { throw $exception; diff --git a/lib/Middleware/TenantIsolationMiddleware.php b/lib/Middleware/TenantIsolationMiddleware.php index 1c032a4a6..270c85e08 100644 --- a/lib/Middleware/TenantIsolationMiddleware.php +++ b/lib/Middleware/TenantIsolationMiddleware.php @@ -41,6 +41,8 @@ /** * Set the per-request Postgres search_path from the bound tenant schema. + * + * @spec openspec/changes/tenant-zaaksysteem-saas-04-tenant-context-isolation/tasks.md */ class TenantIsolationMiddleware extends Middleware { /** @@ -70,6 +72,8 @@ public function __construct( * @SuppressWarnings(PHPMD.UnusedFormalParameter) $controller and $methodName are * fixed by OCP\AppFramework\Middleware::beforeController(); the search_path is * derived from the bound tenant context. + * + * @spec openspec/changes/tenant-zaaksysteem-saas-04-tenant-context-isolation/tasks.md */ public function beforeController($controller, $methodName): void { if ($this->context->isBound() === false) { @@ -98,6 +102,8 @@ public function beforeController($controller, $methodName): void { * @SuppressWarnings(PHPMD.UnusedFormalParameter) $controller and $methodName are * fixed by OCP\AppFramework\Middleware::afterController(); the reset is * unconditional. + * + * @spec openspec/changes/tenant-zaaksysteem-saas-04-tenant-context-isolation/tasks.md */ public function afterController($controller, $methodName, \OCP\AppFramework\Http\Response $response): \OCP\AppFramework\Http\Response { $this->resetSearchPath(); @@ -118,6 +124,8 @@ public function afterController($controller, $methodName, \OCP\AppFramework\Http * @SuppressWarnings(PHPMD.UnusedFormalParameter) $controller and $methodName are * fixed by OCP\AppFramework\Middleware::afterException(); the reset is * unconditional. + * + * @spec openspec/changes/tenant-zaaksysteem-saas-04-tenant-context-isolation/tasks.md */ public function afterException($controller, $methodName, \Exception $exception): \OCP\AppFramework\Http\Response { $this->resetSearchPath(); @@ -130,6 +138,8 @@ public function afterException($controller, $methodName, \Exception $exception): * @param string $schemaName Schema name (validated). * * @return void + * + * @spec openspec/changes/tenant-zaaksysteem-saas-04-tenant-context-isolation/tasks.md */ public function applySearchPath(string $schemaName): void { try { @@ -158,6 +168,8 @@ public function applySearchPath(string $schemaName): void { * Reset the search_path to `public`. * * @return void + * + * @spec openspec/changes/tenant-zaaksysteem-saas-04-tenant-context-isolation/tasks.md */ public function resetSearchPath(): void { try { diff --git a/lib/Middleware/TenantMiddleware.php b/lib/Middleware/TenantMiddleware.php index d61e259d4..dbda172f8 100644 --- a/lib/Middleware/TenantMiddleware.php +++ b/lib/Middleware/TenantMiddleware.php @@ -37,6 +37,8 @@ * Ensures that users can only access data belonging to their tenant. * Platform admins can access any tenant via context switching. * Returns 404 (not 403) for cross-tenant access to prevent information leakage. + * + * @spec openspec/specs/tenant-isolation/spec.md */ class TenantMiddleware extends Middleware { /** @@ -79,6 +81,8 @@ public function __construct( * @SuppressWarnings(PHPMD.UnusedFormalParameter) $methodName is fixed by * OCP\AppFramework\Middleware::beforeController(); the tenant check keys off * the controller class and the request, not the action name. + * + * @spec openspec/specs/tenant-isolation/spec.md */ public function beforeController($controller, $methodName): void { // Skip for exempt controllers. @@ -157,6 +161,8 @@ public function beforeController($controller, $methodName): void { * @SuppressWarnings(PHPMD.UnusedFormalParameter) $controller and $methodName are * fixed by OCP\AppFramework\Middleware::afterException(); only $exception is * inspected. + * + * @spec openspec/specs/tenant-isolation/spec.md */ public function afterException($controller, $methodName, \Exception $exception): JSONResponse { if ($exception->getCode() === 404) { diff --git a/lib/Middleware/ZgwAuthException.php b/lib/Middleware/ZgwAuthException.php index 38eb09746..d5987ea5b 100644 --- a/lib/Middleware/ZgwAuthException.php +++ b/lib/Middleware/ZgwAuthException.php @@ -26,6 +26,8 @@ /** * Exception for ZGW authentication and authorization failures. + * + * @spec openspec/specs/zgw-autorisaties-api/spec.md */ class ZgwAuthException extends \Exception { @@ -51,6 +53,8 @@ public function __construct(string $message, int $statusCode = 403) { * Get the HTTP status code. * * @return int + * + * @spec openspec/specs/zgw-autorisaties-api/spec.md */ public function getStatusCode(): int { return $this->statusCode; diff --git a/lib/Middleware/ZgwAuthMiddleware.php b/lib/Middleware/ZgwAuthMiddleware.php index cdd8b23c3..1f4bf3203 100644 --- a/lib/Middleware/ZgwAuthMiddleware.php +++ b/lib/Middleware/ZgwAuthMiddleware.php @@ -42,6 +42,8 @@ * the authenticated applicatie has the required scope for the request. * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * + * @spec openspec/specs/zgw-api-mapping/spec.md */ class ZgwAuthMiddleware extends Middleware { /** @@ -167,6 +169,8 @@ private function loadOpenRegisterServices(): void { * @throws \OCA\Dossiq\Middleware\ZgwAuthException If authorization fails. * * @SuppressWarnings(PHPMD.UnusedFormalParameter) — $methodName required by Middleware interface + * + * @spec openspec/specs/zgw-api-mapping/spec.md */ public function beforeController($controller, $methodName): void { if (($controller instanceof ZgwController) === false) { @@ -240,6 +244,8 @@ public function beforeController($controller, $methodName): void { * @throws \Exception Re-throws any non-ZGW-auth exception for the next middleware. * * @SuppressWarnings(PHPMD.UnusedFormalParameter) — $controller/$methodName required by Middleware interface + * + * @spec openspec/specs/zgw-api-mapping/spec.md */ public function afterException($controller, $methodName, \Exception $exception): JSONResponse { if ($exception instanceof ZgwAuthException) { @@ -450,6 +456,8 @@ private function findConsumerByIssuer(string $issuer): ?object { * @param string $max The maximum allowed level * * @return bool True if actual is at or below max + * + * @spec openspec/specs/zgw-api-mapping/spec.md */ public function isConfidentialityAllowed(string $actual, string $max): bool { $actualIndex = array_search(needle: $actual, haystack: self::CONFIDENTIALITY_ORDER); diff --git a/lib/Notification/Notifier.php b/lib/Notification/Notifier.php index e385fa785..8e920540e 100644 --- a/lib/Notification/Notifier.php +++ b/lib/Notification/Notifier.php @@ -39,6 +39,8 @@ /** * Parses Dossiq notifications into localised, rendered form. + * + * @spec openspec/specs/ncvue-w2-leaves-adoption/spec.md */ class Notifier implements INotifier { @@ -67,6 +69,8 @@ public function __construct( * Identifier of the notifier, only use [a-z0-9_]. * * @return string + * + * @spec openspec/specs/ncvue-w2-leaves-adoption/spec.md */ public function getID(): string { return Application::APP_ID; @@ -76,6 +80,8 @@ public function getID(): string { * Human-readable name describing the notifier. * * @return string + * + * @spec openspec/specs/ncvue-w2-leaves-adoption/spec.md */ public function getName(): string { return 'Dossiq'; @@ -90,6 +96,8 @@ public function getName(): string { * @return INotification The prepared notification. * * @throws UnknownNotificationException When the notification is not a Dossiq one. + * + * @spec openspec/specs/ncvue-w2-leaves-adoption/spec.md */ public function prepare(INotification $notification, string $languageCode): INotification { if ($notification->getApp() !== Application::APP_ID) { diff --git a/lib/Repair/BackfillInformatieobjectMetadata.php b/lib/Repair/BackfillInformatieobjectMetadata.php index 0b01fce27..f2dd0a3f0 100644 --- a/lib/Repair/BackfillInformatieobjectMetadata.php +++ b/lib/Repair/BackfillInformatieobjectMetadata.php @@ -46,6 +46,8 @@ /** * Repair step that back-fills informatieobject metadata for existing files. + * + * @spec openspec/changes/document-zaakdossier/tasks.md#T09 */ class BackfillInformatieobjectMetadata implements IRepairStep { use RunsUnderSystemIdentity; @@ -74,6 +76,8 @@ public function __construct( * Get the repair-step display name. * * @return string + * + * @spec openspec/changes/document-zaakdossier/tasks.md#T09 */ public function getName(): string { return 'Back-fill ZGW informatieobject metadata for existing Dossiq dossier files'; diff --git a/lib/Repair/DbValueMigrationPort.php b/lib/Repair/DbValueMigrationPort.php index 9af6f17ba..70d32ca2c 100644 --- a/lib/Repair/DbValueMigrationPort.php +++ b/lib/Repair/DbValueMigrationPort.php @@ -35,6 +35,8 @@ /** * The real storage implementation behind ValueMigrationPort. + * + * @spec exclude Database adapter for the Dutch-to-English vocabulary migration. */ class DbValueMigrationPort implements ValueMigrationPort { /** diff --git a/lib/Repair/LinkInFlightContractDecisionsRepair.php b/lib/Repair/LinkInFlightContractDecisionsRepair.php index da3841acd..211fb7ff1 100644 --- a/lib/Repair/LinkInFlightContractDecisionsRepair.php +++ b/lib/Repair/LinkInFlightContractDecisionsRepair.php @@ -92,6 +92,8 @@ public function __construct( * Get the name of this repair step. * * @return string + * + * @spec openspec/specs/contract-decision-delegation/spec.md */ public function getName(): string { return 'Link in-flight Dossiq contract/besluitvorming cases to decidesk Decisions'; diff --git a/lib/Repair/LinkInFlightRemainingDecisionsRepair.php b/lib/Repair/LinkInFlightRemainingDecisionsRepair.php index 82d9d5b25..5f0a90e93 100644 --- a/lib/Repair/LinkInFlightRemainingDecisionsRepair.php +++ b/lib/Repair/LinkInFlightRemainingDecisionsRepair.php @@ -129,6 +129,8 @@ public function __construct( * Get the name of this repair step. * * @return string + * + * @spec openspec/specs/remaining-decision-delegation/spec.md#requirement-req-pdrd-006-in-flight-remaining-decision-cases-are-migrated-without-data-loss */ public function getName(): string { return 'Link in-flight Dossiq bezwaar/advies/consultatie objects to decidesk Decisions'; diff --git a/lib/Repair/MigrateWorkflowDefinitions.php b/lib/Repair/MigrateWorkflowDefinitions.php index e8387e7f3..944a44f15 100644 --- a/lib/Repair/MigrateWorkflowDefinitions.php +++ b/lib/Repair/MigrateWorkflowDefinitions.php @@ -39,6 +39,8 @@ /** * Backfill workflowTemplate objects from implicit statusType ordering. + * + * @spec openspec/specs/workflow-definition-model/spec.md */ class MigrateWorkflowDefinitions implements IRepairStep { @@ -69,6 +71,8 @@ public function __construct( * Get the name of this repair step. * * @return string + * + * @spec openspec/specs/workflow-definition-model/spec.md */ public function getName(): string { return 'Backfill workflowTemplate definitions for existing caseTypes'; diff --git a/lib/Repair/RenameDutchDirectionValues.php b/lib/Repair/RenameDutchDirectionValues.php index 7e84d0926..f346c8883 100644 --- a/lib/Repair/RenameDutchDirectionValues.php +++ b/lib/Repair/RenameDutchDirectionValues.php @@ -135,6 +135,8 @@ public function __construct( * Step name shown by `occ maintenance:repair`. * * @return string + * + * @spec openspec/specs/stuf-zkn-outbound/spec.md */ public function getName(): string { return 'Dossiq: rewrite Dutch direction values (inkomend/uitgaand/intern) to English'; diff --git a/lib/Repair/RenameDutchValueDecisions.php b/lib/Repair/RenameDutchValueDecisions.php index f57561e22..cc5aa9f1c 100644 --- a/lib/Repair/RenameDutchValueDecisions.php +++ b/lib/Repair/RenameDutchValueDecisions.php @@ -32,6 +32,8 @@ /** * Pure predicates for the Dutch-to-English value migration. + * + * @spec exclude Predicate of the Dutch-to-English vocabulary migration. */ class RenameDutchValueDecisions { diff --git a/lib/Repair/RenameDutchValues.php b/lib/Repair/RenameDutchValues.php index a73a11f76..c659148b8 100644 --- a/lib/Repair/RenameDutchValues.php +++ b/lib/Repair/RenameDutchValues.php @@ -35,6 +35,8 @@ /** * Rewrites stored Dutch enum values to their English replacements. + * + * @spec exclude Data migration for the Dutch-to-English vocabulary change. */ class RenameDutchValues implements IRepairStep { /** diff --git a/lib/Repair/SeedBezwaarBeroepData.php b/lib/Repair/SeedBezwaarBeroepData.php index cf9821e6b..acc590af9 100644 --- a/lib/Repair/SeedBezwaarBeroepData.php +++ b/lib/Repair/SeedBezwaarBeroepData.php @@ -35,6 +35,8 @@ /** * Repair step that seeds bezwaar and beroep case types into OpenRegister. + * + * @spec openspec/specs/bezwaar-lifecycle/spec.md */ class SeedBezwaarBeroepData implements IRepairStep { /** @@ -57,6 +59,8 @@ public function __construct( * Get the name of this repair step. * * @return string + * + * @spec openspec/specs/bezwaar-lifecycle/spec.md */ public function getName(): string { return 'Seed Bezwaar, Beroep and Subsidie case types for Dossiq'; diff --git a/lib/Repair/SeedBezwaarWorkflowDefinition.php b/lib/Repair/SeedBezwaarWorkflowDefinition.php index 439ba1be1..ee047a93d 100644 --- a/lib/Repair/SeedBezwaarWorkflowDefinition.php +++ b/lib/Repair/SeedBezwaarWorkflowDefinition.php @@ -43,6 +43,8 @@ /** * Seed the canonical bezwaar workflow definition (published, version 1). + * + * @spec openspec/specs/bezwaar-lifecycle/spec.md */ class SeedBezwaarWorkflowDefinition implements IRepairStep { @@ -78,6 +80,8 @@ public function __construct( * Get the name of this repair step. * * @return string + * + * @spec openspec/specs/bezwaar-lifecycle/spec.md */ public function getName(): string { return 'Seed canonical bezwaar workflow definition (AWB-compliant state machine)'; diff --git a/lib/Repair/SeedLhsMatrix.php b/lib/Repair/SeedLhsMatrix.php index e140ee9b6..5b6a84581 100644 --- a/lib/Repair/SeedLhsMatrix.php +++ b/lib/Repair/SeedLhsMatrix.php @@ -62,6 +62,8 @@ public function __construct( * Get the name of this repair step. * * @return string + * + * @spec openspec/changes/enforcement-lhs/tasks.md#T02 */ public function getName(): string { return 'Seed default LHS matrix (Landelijke Handhavingsstrategie 2024) for Dossiq'; diff --git a/lib/Sections/PersonalSection.php b/lib/Sections/PersonalSection.php index 74da183e5..195d94140 100644 --- a/lib/Sections/PersonalSection.php +++ b/lib/Sections/PersonalSection.php @@ -51,6 +51,8 @@ public function __construct( * Get the section id. * * @return string The section id. + * + * @spec openspec/changes/page-topology-cleanup/specs/personal-settings-surface/spec.md */ public function getID(): string { return 'dossiq'; @@ -60,6 +62,8 @@ public function getID(): string { * Get the section display name. * * @return string The translated section name. + * + * @spec openspec/changes/page-topology-cleanup/specs/personal-settings-surface/spec.md */ public function getName(): string { return $this->l->t('Dossiq'); @@ -69,6 +73,8 @@ public function getName(): string { * Get the ordering priority. * * @return int The priority. + * + * @spec openspec/changes/page-topology-cleanup/specs/personal-settings-surface/spec.md */ public function getPriority(): int { return 75; @@ -78,6 +84,8 @@ public function getPriority(): int { * Get the icon path for this section. * * @return string The icon path. + * + * @spec openspec/changes/page-topology-cleanup/specs/personal-settings-surface/spec.md */ public function getIcon(): string { // MUST be the live app id. imagePath() throws when the app does not diff --git a/lib/Sections/SettingsSection.php b/lib/Sections/SettingsSection.php index 528c5897a..0dd510b1f 100644 --- a/lib/Sections/SettingsSection.php +++ b/lib/Sections/SettingsSection.php @@ -30,6 +30,8 @@ /** * Defines the Dossiq section in the Nextcloud admin settings. + * + * @spec openspec/specs/admin-settings/spec.md */ class SettingsSection implements IIconSection { /** @@ -50,6 +52,8 @@ public function __construct( * Get the section identifier. * * @return string + * + * @spec openspec/specs/admin-settings/spec.md */ public function getID(): string { return 'dossiq'; @@ -59,6 +63,8 @@ public function getID(): string { * Get the display name of this section. * * @return string + * + * @spec openspec/specs/admin-settings/spec.md */ public function getName(): string { return $this->l->t('Dossiq'); @@ -68,6 +74,8 @@ public function getName(): string { * Get the priority for ordering this section. * * @return int + * + * @spec openspec/specs/admin-settings/spec.md */ public function getPriority(): int { return 75; @@ -77,6 +85,8 @@ public function getPriority(): int { * Get the icon path for this section. * * @return string + * + * @spec openspec/specs/admin-settings/spec.md */ public function getIcon(): string { return $this->urlGenerator->imagePath(appName: 'dossiq', file: 'app-dark.svg'); diff --git a/lib/Service/Actions/ActionResult.php b/lib/Service/Actions/ActionResult.php index f1734ae59..d73f1717f 100644 --- a/lib/Service/Actions/ActionResult.php +++ b/lib/Service/Actions/ActionResult.php @@ -36,6 +36,8 @@ * `webhook_timeout`, `unknown_action_ref`). Handlers MUST NEVER include * `$e->getMessage()` or raw exception text here — log the exception via * `LoggerInterface::error()` instead. + * + * @spec openspec/specs/automatic-actions/spec.md */ final class ActionResult { /** diff --git a/lib/Service/Actions/CallWebhookHandler.php b/lib/Service/Actions/CallWebhookHandler.php index 8242fa8b5..adf41df1f 100644 --- a/lib/Service/Actions/CallWebhookHandler.php +++ b/lib/Service/Actions/CallWebhookHandler.php @@ -35,6 +35,8 @@ /** * Handler for `callWebhook` automatic actions. + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ class CallWebhookHandler implements ActionHandlerInterface { use HandlesTemplates; diff --git a/lib/Service/Actions/CreateDocumentHandler.php b/lib/Service/Actions/CreateDocumentHandler.php index a7561e347..816c5f4ee 100644 --- a/lib/Service/Actions/CreateDocumentHandler.php +++ b/lib/Service/Actions/CreateDocumentHandler.php @@ -34,6 +34,8 @@ /** * Handler for `createDocument` automatic actions. + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ class CreateDocumentHandler implements ActionHandlerInterface { use HandlesTemplates; diff --git a/lib/Service/Actions/MergeTemplateHandler.php b/lib/Service/Actions/MergeTemplateHandler.php index 74ee812fa..4dca72333 100644 --- a/lib/Service/Actions/MergeTemplateHandler.php +++ b/lib/Service/Actions/MergeTemplateHandler.php @@ -36,6 +36,8 @@ /** * Handler for `mergeTemplate` automatic actions. + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ class MergeTemplateHandler implements ActionHandlerInterface { use HandlesTemplates; diff --git a/lib/Service/Actions/NotifyRoleHandler.php b/lib/Service/Actions/NotifyRoleHandler.php index c51a90b61..ea10291b9 100644 --- a/lib/Service/Actions/NotifyRoleHandler.php +++ b/lib/Service/Actions/NotifyRoleHandler.php @@ -34,6 +34,8 @@ /** * Handler for `notifyRole` automatic actions. + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ class NotifyRoleHandler implements ActionHandlerInterface { use HandlesTemplates; diff --git a/lib/Service/Actions/ScheduleReminderHandler.php b/lib/Service/Actions/ScheduleReminderHandler.php index 9b9d77d26..856df2ec8 100644 --- a/lib/Service/Actions/ScheduleReminderHandler.php +++ b/lib/Service/Actions/ScheduleReminderHandler.php @@ -38,6 +38,8 @@ /** * Handler for `scheduleReminder` automatic actions. + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ class ScheduleReminderHandler implements ActionHandlerInterface { use HandlesTemplates; diff --git a/lib/Service/Actions/SendEmailHandler.php b/lib/Service/Actions/SendEmailHandler.php index 1bfe9136e..0731f1265 100644 --- a/lib/Service/Actions/SendEmailHandler.php +++ b/lib/Service/Actions/SendEmailHandler.php @@ -34,6 +34,8 @@ /** * Handler for `sendEmail` automatic actions. + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ class SendEmailHandler implements ActionHandlerInterface { use HandlesTemplates; diff --git a/lib/Service/AdvisoryBodyService.php b/lib/Service/AdvisoryBodyService.php index e79fd6d4c..f33e41f74 100644 --- a/lib/Service/AdvisoryBodyService.php +++ b/lib/Service/AdvisoryBodyService.php @@ -38,6 +38,8 @@ * Advisory bodies are departments (internal) or organizations (external) that * can be consulted during case processing. This service exposes CRUD, weighted * specialization search, and secure-token issuance for external notification. + * + * @spec openspec/changes/consultation-management/tasks.md#TASK-CN-03 */ class AdvisoryBodyService { use SearchesObjects; diff --git a/lib/Service/AppointmentBackend/AppointmentBackendInterface.php b/lib/Service/AppointmentBackend/AppointmentBackendInterface.php index d91934a15..3a09a1dd0 100644 --- a/lib/Service/AppointmentBackend/AppointmentBackendInterface.php +++ b/lib/Service/AppointmentBackend/AppointmentBackendInterface.php @@ -38,6 +38,8 @@ interface AppointmentBackendInterface { * @param string $date The date (YYYY-MM-DD) * * @return array List of available timeslots [{time, duration, available}] + * + * @spec openspec/specs/appointment-booking/spec.md */ public function getTimeslots(string $productId, string $locationId, string $date): array; diff --git a/lib/Service/AppointmentBackend/JccBackend.php b/lib/Service/AppointmentBackend/JccBackend.php index f39a25a10..7e4f66cd7 100644 --- a/lib/Service/AppointmentBackend/JccBackend.php +++ b/lib/Service/AppointmentBackend/JccBackend.php @@ -32,6 +32,8 @@ * * Integrates with the JCC Afspraken REST API used by many Dutch municipalities * for balie appointment management. + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ class JccBackend implements AppointmentBackendInterface { /** diff --git a/lib/Service/AppointmentBackend/QmaticBackend.php b/lib/Service/AppointmentBackend/QmaticBackend.php index 7e0400fcf..a3318cf7c 100644 --- a/lib/Service/AppointmentBackend/QmaticBackend.php +++ b/lib/Service/AppointmentBackend/QmaticBackend.php @@ -28,6 +28,8 @@ /** * Qmatic Orchestra REST API backend for appointment scheduling. + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ class QmaticBackend implements AppointmentBackendInterface { /** diff --git a/lib/Service/AppointmentService.php b/lib/Service/AppointmentService.php index 1ca6b6591..59220d1e3 100644 --- a/lib/Service/AppointmentService.php +++ b/lib/Service/AppointmentService.php @@ -47,6 +47,8 @@ * Dispatches to the configured EXTERNAL backend (JCC or Qmatic) and stores * appointment records in OpenRegister. There is no local fallback — internal * scheduling lives in the OR calendar leaf. + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ class AppointmentService { /** @@ -77,6 +79,8 @@ public function __construct( * @param string $date The date (YYYY-MM-DD). * * @return array> List of available timeslots. + * + * @spec openspec/specs/appointment-booking/spec.md */ public function getTimeslots(string $productId, string $locationId, string $date): array { return $this->getBackend()->getTimeslots($productId, $locationId, $date); diff --git a/lib/Service/Auth/BrokerAssertionResult.php b/lib/Service/Auth/BrokerAssertionResult.php index 5747e67bb..d3d249721 100644 --- a/lib/Service/Auth/BrokerAssertionResult.php +++ b/lib/Service/Auth/BrokerAssertionResult.php @@ -37,6 +37,8 @@ /** * Decoded SAML-broker assertion result for dossiq auth flows. + * + * @spec openspec/specs/zaakportaal-mijngemeente/spec.md */ final class BrokerAssertionResult { /** @@ -81,6 +83,8 @@ private function __construct( * @param array $attributes Raw attributes. * * @return self + * + * @spec openspec/specs/zaakportaal-mijngemeente/spec.md */ public static function forEHerkenning( string $kvkNumber, @@ -114,6 +118,8 @@ public static function forEHerkenning( * @param array $attributes Raw attributes. * * @return self + * + * @spec openspec/specs/zaakportaal-mijngemeente/spec.md */ public static function forDigid( string $bsn, @@ -141,6 +147,8 @@ public static function forDigid( * Serialise to a JSON-safe array (audit logs, session bootstrap). * * @return array + * + * @spec openspec/specs/zaakportaal-mijngemeente/spec.md */ public function toArray(): array { return [ diff --git a/lib/Service/Auth/DigidSamlAdapterInterface.php b/lib/Service/Auth/DigidSamlAdapterInterface.php index 5c7b04a3e..21f9793bb 100644 --- a/lib/Service/Auth/DigidSamlAdapterInterface.php +++ b/lib/Service/Auth/DigidSamlAdapterInterface.php @@ -64,6 +64,8 @@ interface DigidSamlAdapterInterface { * @return BrokerAssertionResult Decoded assertion containing the citizen BSN. * * @throws RuntimeException When the broker is not configured, the signature is invalid, or no BSN claim is present. + * + * @spec openspec/specs/zaakportaal-mijngemeente/spec.md#requirement-digid-and-eherkenning-authentication-with-wdo-mandated-trust-levels */ public function decodeAssertion(string $samlResponse, string $relayState): BrokerAssertionResult; @@ -71,6 +73,8 @@ public function decodeAssertion(string $samlResponse, string $relayState): Broke * Whether the live DigiD broker is enabled by the operator. * * @return bool True when `digid.feature_flag` is `1`. + * + * @spec openspec/specs/zaakportaal-mijngemeente/spec.md#requirement-digid-and-eherkenning-authentication-with-wdo-mandated-trust-levels */ public function isActive(): bool; }//end interface diff --git a/lib/Service/Auth/EHerkenningSamlAdapterInterface.php b/lib/Service/Auth/EHerkenningSamlAdapterInterface.php index 24ad3cb84..17044f261 100644 --- a/lib/Service/Auth/EHerkenningSamlAdapterInterface.php +++ b/lib/Service/Auth/EHerkenningSamlAdapterInterface.php @@ -65,6 +65,8 @@ interface EHerkenningSamlAdapterInterface { * @return BrokerAssertionResult Decoded assertion containing the supplier KvK number. * * @throws RuntimeException When the broker is not configured, the signature is invalid, or no KvK claim is present. + * + * @spec openspec/changes/leverancier-zaakportaal-02-eherkenning-auth/tasks.md */ public function decodeAssertion(string $samlResponse, string $relayState): BrokerAssertionResult; @@ -72,6 +74,8 @@ public function decodeAssertion(string $samlResponse, string $relayState): Broke * Whether the live eHerkenning broker is enabled by the operator. * * @return bool True when `eherkenning.feature_flag` is `1`. + * + * @spec openspec/changes/leverancier-zaakportaal-02-eherkenning-auth/tasks.md */ public function isActive(): bool; }//end interface diff --git a/lib/Service/Auth/LogDigidSamlAdapter.php b/lib/Service/Auth/LogDigidSamlAdapter.php index 8481479e4..f303b895e 100644 --- a/lib/Service/Auth/LogDigidSamlAdapter.php +++ b/lib/Service/Auth/LogDigidSamlAdapter.php @@ -40,6 +40,8 @@ /** * Default DigiD adapter — logs + refuses. + * + * @spec openspec/specs/zaakportaal-mijngemeente/spec.md#requirement-digid-and-eherkenning-authentication-with-wdo-mandated-trust-levels */ final class LogDigidSamlAdapter implements DigidSamlAdapterInterface { /** @@ -100,6 +102,8 @@ public function decodeAssertion(string $samlResponse, string $relayState): Broke * Whether the live broker is enabled. * * @return bool + * + * @spec openspec/specs/zaakportaal-mijngemeente/spec.md#requirement-digid-and-eherkenning-authentication-with-wdo-mandated-trust-levels */ public function isActive(): bool { $raw = $this->config->getValueString(self::APP_ID, self::FLAG_KEY, '0'); diff --git a/lib/Service/Auth/LogEHerkenningSamlAdapter.php b/lib/Service/Auth/LogEHerkenningSamlAdapter.php index 8aadbe4e7..0c8dbcdd8 100644 --- a/lib/Service/Auth/LogEHerkenningSamlAdapter.php +++ b/lib/Service/Auth/LogEHerkenningSamlAdapter.php @@ -41,6 +41,8 @@ /** * Default eHerkenning adapter — logs + refuses. + * + * @spec openspec/changes/leverancier-zaakportaal-02-eherkenning-auth/tasks.md */ final class LogEHerkenningSamlAdapter implements EHerkenningSamlAdapterInterface { /** @@ -101,6 +103,8 @@ public function decodeAssertion(string $samlResponse, string $relayState): Broke * Whether the live broker is enabled. * * @return bool + * + * @spec openspec/specs/zaakportaal-mijngemeente/spec.md#requirement-digid-and-eherkenning-authentication-with-wdo-mandated-trust-levels */ public function isActive(): bool { $raw = $this->config->getValueString(self::APP_ID, self::FLAG_KEY, '0'); diff --git a/lib/Service/Auth/SimulatorDigidSamlAdapter.php b/lib/Service/Auth/SimulatorDigidSamlAdapter.php index d7905ffaf..d3efafad5 100644 --- a/lib/Service/Auth/SimulatorDigidSamlAdapter.php +++ b/lib/Service/Auth/SimulatorDigidSamlAdapter.php @@ -89,6 +89,8 @@ public function decodeAssertion(string $samlResponse, string $relayState): Broke * broker — callers surface the simulation label. * * @return bool + * + * @spec openspec/specs/external-integration-test-wiring/spec.md */ public function isActive(): bool { return true; diff --git a/lib/Service/Auth/SimulatorEHerkenningSamlAdapter.php b/lib/Service/Auth/SimulatorEHerkenningSamlAdapter.php index b0b9f8b5c..a35ee4d31 100644 --- a/lib/Service/Auth/SimulatorEHerkenningSamlAdapter.php +++ b/lib/Service/Auth/SimulatorEHerkenningSamlAdapter.php @@ -85,6 +85,8 @@ public function decodeAssertion(string $samlResponse, string $relayState): Broke * The simulator is an active (non-dormant) tier, but not a live broker. * * @return bool + * + * @spec openspec/specs/external-integration-test-wiring/spec.md */ public function isActive(): bool { return true; diff --git a/lib/Service/BerichtenboxAdapter/BerichtenboxAdapterInterface.php b/lib/Service/BerichtenboxAdapter/BerichtenboxAdapterInterface.php index 9347ae9a2..5c7b1c696 100644 --- a/lib/Service/BerichtenboxAdapter/BerichtenboxAdapterInterface.php +++ b/lib/Service/BerichtenboxAdapter/BerichtenboxAdapterInterface.php @@ -54,6 +54,8 @@ public function sendMessage( * @param string $messageId The external message ID * * @return array Status with read (bool), readAt (datetime|null) + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ public function getReadStatus(string $messageId): array; }//end interface diff --git a/lib/Service/BerichtenboxAdapter/MockAdapter.php b/lib/Service/BerichtenboxAdapter/MockAdapter.php index 85e0d80ce..bdcd502dd 100644 --- a/lib/Service/BerichtenboxAdapter/MockAdapter.php +++ b/lib/Service/BerichtenboxAdapter/MockAdapter.php @@ -31,6 +31,8 @@ * Mock Berichtenbox adapter for development and testing. * * Simulates message sending and read status without external API calls. + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ class MockAdapter implements BerichtenboxAdapterInterface { /** diff --git a/lib/Service/CaseDefinitionExportService.php b/lib/Service/CaseDefinitionExportService.php index 7338924ea..9302a94b3 100644 --- a/lib/Service/CaseDefinitionExportService.php +++ b/lib/Service/CaseDefinitionExportService.php @@ -44,6 +44,8 @@ * permission rules, document types, and workflow definitions for a case type. * * @psalm-suppress UnusedClass + * + * @spec openspec/changes/archive/retrofit-2026-05-24-annotate-procest/tasks.md#task-3 */ class CaseDefinitionExportService { /** diff --git a/lib/Service/CaseEmailService.php b/lib/Service/CaseEmailService.php index 497cf716e..6a0a59081 100644 --- a/lib/Service/CaseEmailService.php +++ b/lib/Service/CaseEmailService.php @@ -40,6 +40,8 @@ /** * Service for case-integrated email functionality. + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ class CaseEmailService { diff --git a/lib/Service/ConsultationService.php b/lib/Service/ConsultationService.php index 04a5fd3a2..142c28409 100644 --- a/lib/Service/ConsultationService.php +++ b/lib/Service/ConsultationService.php @@ -38,6 +38,8 @@ * Handles the full consultation lifecycle: creation with auto-generated numbers, * status transitions, advice responses, deadline extensions, and dependency * cycle detection per Awb 3:5-3:9. + * + * @spec openspec/changes/consultation-management/tasks.md#TASK-CN-02 */ class ConsultationService { /** diff --git a/lib/Service/DeadlineEscalationService.php b/lib/Service/DeadlineEscalationService.php index 5a3771480..fc95f0258 100644 --- a/lib/Service/DeadlineEscalationService.php +++ b/lib/Service/DeadlineEscalationService.php @@ -34,6 +34,8 @@ /** * Threshold-aware escalation dispatcher for the daily termijn scan. + * + * @spec openspec/changes/termijnbewaking-dwangsom-engine-04-daily-scan-escalation/tasks.md */ class DeadlineEscalationService { /** diff --git a/lib/Service/DeadlineExtensionService.php b/lib/Service/DeadlineExtensionService.php index a01becce1..07721ba79 100644 --- a/lib/Service/DeadlineExtensionService.php +++ b/lib/Service/DeadlineExtensionService.php @@ -36,6 +36,8 @@ /** * AWB 4:14 verlenging engine on a TermijnInstance. + * + * @spec openspec/changes/termijnbewaking-dwangsom-engine-03-pause-extension/tasks.md */ class DeadlineExtensionService { /** diff --git a/lib/Service/DeadlinePauseService.php b/lib/Service/DeadlinePauseService.php index 9fccf49b2..3c1764192 100644 --- a/lib/Service/DeadlinePauseService.php +++ b/lib/Service/DeadlinePauseService.php @@ -35,6 +35,8 @@ /** * AWB 4:5 / 4:15 pause + resume on a TermijnInstance. + * + * @spec openspec/changes/termijnbewaking-dwangsom-engine-03-pause-extension/tasks.md */ class DeadlinePauseService { /** diff --git a/lib/Service/DemoDataService.php b/lib/Service/DemoDataService.php index 94a3e6a30..1cfc2c18c 100644 --- a/lib/Service/DemoDataService.php +++ b/lib/Service/DemoDataService.php @@ -150,9 +150,11 @@ public function isAvailable(): bool { * the app already owns. A non-zero count here means the payload carried a * definitional block that {@see self::objectsOnly()} failed to strip. * - * @return array{objects: integer, requested: integer, refused: integer, registers: integer, schemas: integer} What was asked for and what landed. + * @return array{objects: integer, requested: integer, refused: integer, unchanged: integer, + * registers: integer, schemas: integer} What was asked for and what landed. * - * @throws RuntimeException When the descriptor is missing or unreadable, OpenRegister is absent, or the import stored nothing. + * @throws RuntimeException When the descriptor is missing or unreadable, OpenRegister is + * absent, or nothing was stored and nothing was already present. * * @spec openspec/changes/first-time-setup/specs/first-time-setup/spec.md */ @@ -189,11 +191,19 @@ public function install(): array { // The LANDING. An importer reply with no `objects` key has said nothing // about objects, and nothing is zero — never "as many as we asked for". - $skipped = (array)($result['skipped'] ?? []); - $imported = [ + $skipped = (array)($result['skipped'] ?? []); + $unchanged = (array)($result['unchanged'] ?? []); + $imported = [ 'objects' => count((array)($result['objects'] ?? [])), 'requested' => $requested, 'refused' => (int)($skipped['objects'] ?? 0), + // Already present at the same version, so correctly left alone. + // REPORTED BY THE IMPORTER, not inferred here: deriving it as + // `requested - stored - refused` looks equivalent and is not, because + // it silently reclassifies an object the importer dropped WITHOUT + // saying so as "already present", which is the exact failure this + // guard exists to catch. + 'unchanged' => (int)($unchanged['objects'] ?? 0), 'registers' => count((array)($result['registers'] ?? [])), 'schemas' => count((array)($result['schemas'] ?? [])), ]; @@ -204,16 +214,25 @@ public function install(): array { // recorded themselves as done. A descriptor that ships no objects at // all is a different condition and stays a success: registers and // schemas are a legitimate thing to ship on their own. - if ($requested > 0 && $imported['objects'] === 0) { + // STORING NOTHING IS NOT THE SAME AS FAILING. This read `objects === 0` + // alone, which refuses an import whose objects are already there, and + // that is the normal case on a second run. The step's own body promises + // it is "safe to run more than once", and an idempotent import + // necessarily stores zero the second time. Measured on CI, dossiq + // development, every run since 2026-09-03: 444 requested, 0 stored, + // reported as a hard failure on an install with nothing left to do. + // + // So the question is whether anything SURVIVED, not whether anything + // moved. + if ($requested > 0 && $imported['objects'] === 0 && $imported['unchanged'] === 0) { throw new RuntimeException( 'The demo import stored 0 of ' . $requested . ' object(s) (' - . $imported['refused'] . ' refused by OpenRegister). Nothing was written, so this is not ' - . 'an install. The demo set carries objects only and binds them to the register and schemas ' - . 'this app already owns, so check first that the register import has run: `occ ' - . 'maintenance:repair` provisions it. A schema slug that resolves to more than one row is ' - . 'refused as ambiguous, which is what an instance still carrying the old `dossiq.demo` ' - . 'schema fork looks like. Note also that an object whose version has not moved is left ' - . 'alone: re-importing an already-imported demo set lands nothing.' + . $imported['refused'] . ' refused by OpenRegister) and none was already present. ' + . 'Nothing was written, so this is not an install. The demo set carries objects only ' + . 'and binds them to the register and schemas this app already owns, so check first ' + . 'that the register import has run: `occ maintenance:repair` provisions it. A schema ' + . 'slug that resolves to more than one row is refused as ambiguous, which is what an ' + . 'instance still carrying the old `dossiq.demo` schema fork looks like.' ); } diff --git a/lib/Service/DoorlooptijdService.php b/lib/Service/DoorlooptijdService.php index 7d0edbd94..07c1eb61b 100644 --- a/lib/Service/DoorlooptijdService.php +++ b/lib/Service/DoorlooptijdService.php @@ -42,6 +42,8 @@ /** * Computes throughput-time metrics for the case dashboard. + * + * @spec openspec/changes/doorlooptijd-dashboard/tasks.md#T01 */ class DoorlooptijdService { diff --git a/lib/Service/DsoIntakeService.php b/lib/Service/DsoIntakeService.php index cd08cb57a..44d4929b8 100644 --- a/lib/Service/DsoIntakeService.php +++ b/lib/Service/DsoIntakeService.php @@ -36,6 +36,8 @@ * Creates permit cases from DSO vergunningaanvraag messages. * Supports multiple activities per application and calculates * deadlines based on procedure type (regulier: 8 weeks, uitgebreid: 26 weeks). + * + * @spec openspec/specs/dso-omgevingsloket-client/spec.md */ class DsoIntakeService { @@ -139,6 +141,8 @@ private function storeCaseProperties( * @param string $procedureType The procedure type (regulier or uitgebreid) * * @return string ISO 8601 duration + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ public function getDeadlineDuration(string $procedureType): string { return self::DEADLINE_DURATIONS[$procedureType] ?? self::DEADLINE_DURATIONS['regulier']; diff --git a/lib/Service/DwangsomBezwaarService.php b/lib/Service/DwangsomBezwaarService.php index 91e063fd7..ab78f630b 100644 --- a/lib/Service/DwangsomBezwaarService.php +++ b/lib/Service/DwangsomBezwaarService.php @@ -38,6 +38,8 @@ /** * Bezwaar lifecycle for a DwangsomBerekening. + * + * @spec openspec/changes/termijnbewaking-dwangsom-engine-10-bezwaar-rest-api/tasks.md */ class DwangsomBezwaarService { use SearchesObjects; diff --git a/lib/Service/DwangsomCalculationService.php b/lib/Service/DwangsomCalculationService.php index 80fe68205..f9f32c45e 100644 --- a/lib/Service/DwangsomCalculationService.php +++ b/lib/Service/DwangsomCalculationService.php @@ -42,6 +42,8 @@ /** * Daily-accruing dwangsom calculator. + * + * @spec openspec/changes/termijnbewaking-dwangsom-engine-06-dwangsom-calculation/tasks.md */ class DwangsomCalculationService { use SearchesObjects; diff --git a/lib/Service/DwangsomUitbetalingService.php b/lib/Service/DwangsomUitbetalingService.php index bb64b5915..7b513d5fa 100644 --- a/lib/Service/DwangsomUitbetalingService.php +++ b/lib/Service/DwangsomUitbetalingService.php @@ -38,6 +38,8 @@ /** * Payment-signal preparation + callback processing for dwangsom payouts. + * + * @spec openspec/changes/termijnbewaking-dwangsom-engine-07-financial-integration/tasks.md */ class DwangsomUitbetalingService { use SearchesObjects; diff --git a/lib/Service/EmailArchivalService.php b/lib/Service/EmailArchivalService.php index b50ac2743..8ddf15621 100644 --- a/lib/Service/EmailArchivalService.php +++ b/lib/Service/EmailArchivalService.php @@ -35,6 +35,8 @@ /** * Archival surface for emails linked to a case. + * + * @spec openspec/changes/case-email-integration/tasks.md#T05 */ class EmailArchivalService { diff --git a/lib/Service/EmailTemplateService.php b/lib/Service/EmailTemplateService.php index 49d411b95..86435f4d6 100644 --- a/lib/Service/EmailTemplateService.php +++ b/lib/Service/EmailTemplateService.php @@ -39,6 +39,8 @@ * OpenRegister access is delegated to EmailTemplateRepository; what stays here * is the template domain itself — versioning, seeding and placeholder * resolution. + * + * @spec openspec/changes/case-email-integration/tasks.md#T04 */ class EmailTemplateService { diff --git a/lib/Service/External/Brp/BrpHaalCentraalAdapterInterface.php b/lib/Service/External/Brp/BrpHaalCentraalAdapterInterface.php index 78a474454..3c2c946df 100644 --- a/lib/Service/External/Brp/BrpHaalCentraalAdapterInterface.php +++ b/lib/Service/External/Brp/BrpHaalCentraalAdapterInterface.php @@ -95,6 +95,8 @@ interface BrpHaalCentraalAdapterInterface { * * @return BrpLookupResult The lookup outcome (status + persoon * envelope minus BSN). + * + * @spec openspec/changes/brp-kvk-register-sets/proposal.md */ public function lookup(string $bsn, array $context = []): BrpLookupResult; @@ -103,6 +105,8 @@ public function lookup(string $bsn, array $context = []): BrpLookupResult; * Haal Centraal. * * @return bool TRUE when the adapter is a log-only stub. + * + * @spec openspec/changes/brp-kvk-register-sets/proposal.md */ public function isDormant(): bool; }//end interface diff --git a/lib/Service/External/Brp/HaalCentraalBrpAdapter.php b/lib/Service/External/Brp/HaalCentraalBrpAdapter.php index ec26bb63f..a6b305e56 100644 --- a/lib/Service/External/Brp/HaalCentraalBrpAdapter.php +++ b/lib/Service/External/Brp/HaalCentraalBrpAdapter.php @@ -151,6 +151,8 @@ public function lookup(string $bsn, array $context = []): BrpLookupResult { * A configured live adapter is not dormant. * * @return bool + * + * @spec openspec/specs/external-integration-test-wiring/spec.md */ public function isDormant(): bool { return false; diff --git a/lib/Service/External/Brp/LogBrpHaalCentraalAdapter.php b/lib/Service/External/Brp/LogBrpHaalCentraalAdapter.php index 1cf180f6a..a4d7297f8 100644 --- a/lib/Service/External/Brp/LogBrpHaalCentraalAdapter.php +++ b/lib/Service/External/Brp/LogBrpHaalCentraalAdapter.php @@ -96,6 +96,8 @@ public function lookup(string $bsn, array $context = []): BrpLookupResult { * @inheritDoc * * @return bool + * + * @spec openspec/specs/brp-register/spec.md#requirement-brp-person-register-schema-exists-in-openregister */ public function isDormant(): bool { return true; diff --git a/lib/Service/External/Kvk/KvkApiAdapter.php b/lib/Service/External/Kvk/KvkApiAdapter.php index 0466bc5d8..142fcc903 100644 --- a/lib/Service/External/Kvk/KvkApiAdapter.php +++ b/lib/Service/External/Kvk/KvkApiAdapter.php @@ -148,6 +148,8 @@ public function lookup(string $kvkNumber, array $context = []): KvkLookupResult * A configured live adapter is not dormant. * * @return bool + * + * @spec openspec/specs/external-integration-test-wiring/spec.md */ public function isDormant(): bool { return false; diff --git a/lib/Service/External/Kvk/KvkHandelsregisterAdapterInterface.php b/lib/Service/External/Kvk/KvkHandelsregisterAdapterInterface.php index c4135597f..b683838b4 100644 --- a/lib/Service/External/Kvk/KvkHandelsregisterAdapterInterface.php +++ b/lib/Service/External/Kvk/KvkHandelsregisterAdapterInterface.php @@ -84,6 +84,8 @@ interface KvkHandelsregisterAdapterInterface { * * @return KvkLookupResult The lookup outcome (status + entity * envelope + optional vestiging list). + * + * @spec openspec/changes/brp-kvk-register-sets/proposal.md */ public function lookup(string $kvkNumber, array $context = []): KvkLookupResult; @@ -92,6 +94,8 @@ public function lookup(string $kvkNumber, array $context = []): KvkLookupResult; * the KvK Handelsregister. * * @return bool TRUE when the adapter is a log-only stub. + * + * @spec openspec/changes/brp-kvk-register-sets/proposal.md */ public function isDormant(): bool; }//end interface diff --git a/lib/Service/External/Kvk/LogKvkHandelsregisterAdapter.php b/lib/Service/External/Kvk/LogKvkHandelsregisterAdapter.php index 5d624f01a..61509debb 100644 --- a/lib/Service/External/Kvk/LogKvkHandelsregisterAdapter.php +++ b/lib/Service/External/Kvk/LogKvkHandelsregisterAdapter.php @@ -94,6 +94,8 @@ public function lookup(string $kvkNumber, array $context = []): KvkLookupResult * @inheritDoc * * @return bool + * + * @spec openspec/specs/kvk-register/spec.md#requirement-kvk-company-register-schema-exists-in-openregister */ public function isDormant(): bool { return true; diff --git a/lib/Service/External/Zgw/LogZgwExternalAdapter.php b/lib/Service/External/Zgw/LogZgwExternalAdapter.php index b1f6277b1..eeffa311e 100644 --- a/lib/Service/External/Zgw/LogZgwExternalAdapter.php +++ b/lib/Service/External/Zgw/LogZgwExternalAdapter.php @@ -140,6 +140,8 @@ public function submitDocument(array $documentEnvelope, array $context = []): Zg * @inheritDoc * * @return bool + * + * @spec openspec/specs/zgw-api-mapping/spec.md#requirement-drc-documenten-api-resources-must-be-mappable */ public function isDormant(): bool { return true; diff --git a/lib/Service/External/Zgw/ZgwExternalAdapterInterface.php b/lib/Service/External/Zgw/ZgwExternalAdapterInterface.php index 50ff46ddb..f60adf1d4 100644 --- a/lib/Service/External/Zgw/ZgwExternalAdapterInterface.php +++ b/lib/Service/External/Zgw/ZgwExternalAdapterInterface.php @@ -93,6 +93,8 @@ interface ZgwExternalAdapterInterface { * * @return ZgwPushResult The dispatch outcome (status + * receiver-side zaak URL). + * + * @spec openspec/specs/zgw-api-mapping/spec.md */ public function submitZaak(array $caseEnvelope, array $context = []): ZgwPushResult; @@ -110,6 +112,8 @@ public function submitZaak(array $caseEnvelope, array $context = []): ZgwPushRes * * @return ZgwPushResult The dispatch outcome (status + * receiver-side document URL). + * + * @spec openspec/specs/zgw-api-mapping/spec.md */ public function submitDocument(array $documentEnvelope, array $context = []): ZgwPushResult; @@ -118,6 +122,8 @@ public function submitDocument(array $documentEnvelope, array $context = []): Zg * any external ZGW stack. * * @return bool TRUE when the adapter is a log-only stub. + * + * @spec openspec/specs/zgw-api-mapping/spec.md */ public function isDormant(): bool; }//end interface diff --git a/lib/Service/External/Ztc/LogZtcCatalogiAdapter.php b/lib/Service/External/Ztc/LogZtcCatalogiAdapter.php index 58c10f8b2..0974cca15 100644 --- a/lib/Service/External/Ztc/LogZtcCatalogiAdapter.php +++ b/lib/Service/External/Ztc/LogZtcCatalogiAdapter.php @@ -120,6 +120,8 @@ public function importZaakType(string $caseTypeUrl, array $context = []): ZtcRes * @inheritDoc * * @return bool + * + * @spec openspec/specs/zgw-api-mapping/spec.md#requirement-ztc-catalogi-api-resources-must-be-fully-mappable */ public function isDormant(): bool { return true; diff --git a/lib/Service/External/Ztc/ZtcCatalogiAdapterInterface.php b/lib/Service/External/Ztc/ZtcCatalogiAdapterInterface.php index 65a43de66..f0548ac14 100644 --- a/lib/Service/External/Ztc/ZtcCatalogiAdapterInterface.php +++ b/lib/Service/External/Ztc/ZtcCatalogiAdapterInterface.php @@ -87,6 +87,8 @@ interface ZtcCatalogiAdapterInterface { * correlationId. * * @return ZtcResult The lookup outcome (status + canonical URL). + * + * @spec openspec/specs/zgw-api-mapping/spec.md */ public function resolveZaakType(string $caseTypeId, string $receiverSourceSlug, array $context = []): ZtcResult; @@ -108,6 +110,8 @@ public function resolveZaakType(string $caseTypeId, string $receiverSourceSlug, * * @return ZtcResult The import outcome (status + * `localZaakTypeUrl`). + * + * @spec openspec/specs/zgw-api-mapping/spec.md */ public function importZaakType(string $caseTypeUrl, array $context = []): ZtcResult; @@ -116,6 +120,8 @@ public function importZaakType(string $caseTypeUrl, array $context = []): ZtcRes * an external Catalogi-API. * * @return bool TRUE when the adapter is a log-only stub. + * + * @spec openspec/specs/zgw-api-mapping/spec.md */ public function isDormant(): bool; }//end interface diff --git a/lib/Service/InformatieobjectAccessGuard.php b/lib/Service/InformatieobjectAccessGuard.php index 48872233f..73d1985f9 100644 --- a/lib/Service/InformatieobjectAccessGuard.php +++ b/lib/Service/InformatieobjectAccessGuard.php @@ -41,6 +41,8 @@ /** * Enforces vertrouwelijkheidaanduiding-based access control on informatieobjecten. + * + * @spec openspec/changes/document-zaakdossier/tasks.md#T03 */ class InformatieobjectAccessGuard { /** diff --git a/lib/Service/Kcc/BelplanRoutingService.php b/lib/Service/Kcc/BelplanRoutingService.php index 1a664ca4e..0cf9b8c6f 100644 --- a/lib/Service/Kcc/BelplanRoutingService.php +++ b/lib/Service/Kcc/BelplanRoutingService.php @@ -34,6 +34,8 @@ /** * Belplan-driven KCC call routing. + * + * @spec openspec/changes/kcc-werkplek-zaaksysteem-bridge/tasks.md#T06 */ class BelplanRoutingService { /** diff --git a/lib/Service/Kcc/CallbackService.php b/lib/Service/Kcc/CallbackService.php index ffe257df8..76e414fa5 100644 --- a/lib/Service/Kcc/CallbackService.php +++ b/lib/Service/Kcc/CallbackService.php @@ -41,6 +41,8 @@ * * @SuppressWarnings(PHPMD.BooleanArgumentFlag) — $isPrivileged is the standard * cross-agent/own-record scoping flag used across the app's controllers. + * + * @spec openspec/changes/kcc-klantcontact-integratie/tasks.md#TASK-KCC-05 */ class CallbackService { /** @@ -71,6 +73,8 @@ public function __construct( * @return array The callback payload. * * @throws OCSBadRequestException When validation fails. + * + * @spec openspec/changes/kcc-klantcontact-integratie/tasks.md#TASK-KCC-05 */ public function buildPayload(array $data, string $agentId): array { $phone = trim((string)($data['customerPhone'] ?? '')); @@ -144,6 +148,8 @@ public function schedule(array $data, string $agentId): array { * @return array The updated callback record. * * @SuppressWarnings(PHPMD.BooleanArgumentFlag) — $succeeded is the attempt outcome. + * + * @spec openspec/specs/kcc-klantcontact-integratie/spec.md#requirement-callback-scheduling-and-sla-tracking */ public function applyAttempt(array $callback, bool $succeeded, ?DateTimeImmutable $now = null): array { $now = ($now ?? new DateTimeImmutable()); @@ -181,6 +187,8 @@ public function applyAttempt(array $callback, bool $succeeded, ?DateTimeImmutabl * @return array The cancelled callback record. * * @throws OCSBadRequestException When not found or not owned. + * + * @spec openspec/specs/kcc-klantcontact-integratie/spec.md#requirement-callback-scheduling-and-sla-tracking */ public function cancel(string $id, string $agentId, bool $isPrivileged = false): array { [$objectService, $register, $schema] = $this->resolve(); @@ -208,6 +216,8 @@ public function cancel(string $id, string $agentId, bool $isPrivileged = false): * @param bool $isPrivileged Whether the caller may see all callbacks. * * @return array> The callback requests. + * + * @spec openspec/specs/kcc-klantcontact-integratie/spec.md#requirement-callback-scheduling-and-sla-tracking */ public function list(array $filters, string $agentId, bool $isPrivileged = false): array { [$objectService, $register, $schema] = $this->resolve(); @@ -232,6 +242,8 @@ public function list(array $filters, string $agentId, bool $isPrivileged = false * @param array $callback The callback record. * * @return array The saved record. + * + * @spec openspec/specs/kcc-klantcontact-integratie/spec.md#requirement-callback-scheduling-and-sla-tracking */ public function persist(string $id, array $callback): array { [$objectService, $register, $schema] = $this->resolve(); diff --git a/lib/Service/Kcc/ContactMomentService.php b/lib/Service/Kcc/ContactMomentService.php index 823b14c1a..5083b8c94 100644 --- a/lib/Service/Kcc/ContactMomentService.php +++ b/lib/Service/Kcc/ContactMomentService.php @@ -44,6 +44,8 @@ * validation, persistence and IDOR-scoped queries for one entity. * @SuppressWarnings(PHPMD.BooleanArgumentFlag) — $isPrivileged is the standard * cross-agent/own-record scoping flag used across the app's controllers. + * + * @spec openspec/changes/kcc-klantcontact-integratie/tasks.md#TASK-KCC-02 */ class ContactMomentService { /** @@ -84,6 +86,8 @@ public function __construct( * @return array The sanitised contact-moment payload. * * @throws OCSBadRequestException When validation fails. + * + * @spec openspec/changes/kcc-klantcontact-integratie/tasks.md#TASK-KCC-02 */ public function buildPayload(array $data, string $agentId): array { $channel = $this->validateEnum(value: (string)($data['channel'] ?? ''), allowed: self::CHANNELS, label: 'channel'); @@ -226,6 +230,8 @@ public function create(array $data, string $agentId): array { * @return array The updated contact moment. * * @throws OCSBadRequestException When not found or not owned. + * + * @spec openspec/specs/kcc-klantcontact-integratie/spec.md#requirement-contactmoment-records-capture-full-interaction-context */ public function update(string $id, array $data, string $agentId, bool $isPrivileged = false): array { [$objectService, $register, $schema] = $this->resolve(); @@ -297,6 +303,8 @@ private function mergeUpdate(array $existing, array $data): array { * @param bool $isPrivileged Whether the caller may see all moments. * * @return array> The contact moments. + * + * @spec openspec/changes/kcc-klantcontact-integratie/tasks.md#TASK-KCC-02 */ public function list(array $filters, string $agentId, bool $isPrivileged = false): array { [$objectService, $register, $schema] = $this->resolve(); @@ -328,6 +336,8 @@ public function list(array $filters, string $agentId, bool $isPrivileged = false * @return array The contact moment. * * @throws OCSBadRequestException When not found or not owned. + * + * @spec openspec/changes/kcc-klantcontact-integratie/tasks.md#TASK-KCC-02 */ public function get(string $id, string $agentId, bool $isPrivileged = false): array { [$objectService, $register, $schema] = $this->resolve(); @@ -349,6 +359,8 @@ public function get(string $id, string $agentId, bool $isPrivileged = false): ar * @param bool $isPrivileged Whether the caller may see any moment. * * @return array> Related contact moments. + * + * @spec openspec/changes/kcc-klantcontact-integratie/tasks.md#TASK-KCC-02 */ public function related(string $id, string $agentId, bool $isPrivileged = false): array { [$objectService, $register, $schema] = $this->resolve(); diff --git a/lib/Service/Kcc/RoutingEngine.php b/lib/Service/Kcc/RoutingEngine.php index 8f568f59f..53716ea6a 100644 --- a/lib/Service/Kcc/RoutingEngine.php +++ b/lib/Service/Kcc/RoutingEngine.php @@ -35,6 +35,8 @@ * Deterministic routing-rule evaluation and agent ranking for the KCC. * * @psalm-suppress UnusedClass + * + * @spec openspec/changes/kcc-klantcontact-integratie/tasks.md#TASK-KCC-03 */ class RoutingEngine { /** @@ -56,6 +58,8 @@ class RoutingEngine { * @param \DateTimeImmutable|null $now Reference time (for time-of-day rules). * * @return array|null The routing result, or null when unmatched. + * + * @spec openspec/changes/kcc-klantcontact-integratie/tasks.md#TASK-KCC-03 */ public function evaluate(array $rules, array $contactMoment, ?\DateTimeImmutable $now = null): ?array { $now = ($now ?? new DateTimeImmutable()); @@ -98,6 +102,8 @@ static function (array $first, array $second): int { * @param \DateTimeImmutable $now Reference time. * * @return bool True when all conditions match. + * + * @spec openspec/changes/kcc-klantcontact-integratie/tasks.md#TASK-KCC-03 */ public function ruleMatches(array $rule, array $contactMoment, \DateTimeImmutable $now): bool { $conditions = ($rule['matchConditions'] ?? []); @@ -219,6 +225,8 @@ private function timeOfDayMatches(string $value, \DateTimeImmutable $now): bool * @param int $limit Maximum results. * * @return array> Ranked agents with motivation. + * + * @spec openspec/changes/kcc-klantcontact-integratie/tasks.md#TASK-KCC-03 */ public function rankAgents(array $agents, string $team, array $contactMoment, int $limit = 3): array { $domain = strtolower((string)($contactMoment['assignedDomain'] ?? '')); diff --git a/lib/Service/Kcc/RoutingRuleService.php b/lib/Service/Kcc/RoutingRuleService.php index cbc6739ba..e1cb3a30c 100644 --- a/lib/Service/Kcc/RoutingRuleService.php +++ b/lib/Service/Kcc/RoutingRuleService.php @@ -38,6 +38,8 @@ * Persists routing rules / agents and drives the routing engine. * * @psalm-suppress UnusedClass + * + * @spec openspec/changes/kcc-klantcontact-integratie/tasks.md#TASK-KCC-17 */ class RoutingRuleService { /** @@ -61,6 +63,8 @@ public function __construct( * List all routing rules. * * @return array> The routing rules. + * + * @spec openspec/changes/kcc-klantcontact-integratie/tasks.md#TASK-KCC-17 */ public function listRules(): array { [$objectService, $register, $schema] = $this->resolve(schemaKey: 'routing_rule_schema'); @@ -76,6 +80,8 @@ public function listRules(): array { * @return array The saved rule. * * @throws OCSBadRequestException When validation fails. + * + * @spec openspec/changes/kcc-klantcontact-integratie/tasks.md#TASK-KCC-17 */ public function createRule(array $data): array { $payload = $this->validateRule(data: $data); @@ -92,6 +98,8 @@ public function createRule(array $data): array { * @return array The saved rule. * * @throws OCSBadRequestException When validation fails or not found. + * + * @spec openspec/changes/kcc-klantcontact-integratie/tasks.md#TASK-KCC-17 */ public function updateRule(string $id, array $data): array { $payload = $this->validateRule(data: $data); @@ -165,6 +173,8 @@ public function route(array $contactMoment, ?\DateTimeImmutable $now = null): ar * List all KCC agents. * * @return array> The agents. + * + * @spec openspec/changes/kcc-routing-onto-or-decision-tables/specs/kcc-routing/spec.md#requirement-routing-rules-evaluate-through-the-shared-decision-table-engine */ public function listAgents(): array { [$objectService, $register, $schema] = $this->resolve(schemaKey: 'kcc_agent_schema'); diff --git a/lib/Service/Kcc/SentimentService.php b/lib/Service/Kcc/SentimentService.php index 27f87a412..d21628354 100644 --- a/lib/Service/Kcc/SentimentService.php +++ b/lib/Service/Kcc/SentimentService.php @@ -34,6 +34,8 @@ /** * Deterministic Dutch sentiment analyser for KCC transcripts. + * + * @spec openspec/changes/kcc-werkplek-zaaksysteem-bridge/tasks.md#T09 */ class SentimentService { /** diff --git a/lib/Service/Kcc/SlaCalculator.php b/lib/Service/Kcc/SlaCalculator.php index 77da9db76..517939ed5 100644 --- a/lib/Service/Kcc/SlaCalculator.php +++ b/lib/Service/Kcc/SlaCalculator.php @@ -37,6 +37,8 @@ * Deterministic SLA / working-day calculator for the KCC integration. * * @psalm-suppress UnusedClass + * + * @spec openspec/changes/kcc-klantcontact-integratie/tasks.md#TASK-KCC-25 */ class SlaCalculator { /** @@ -74,6 +76,8 @@ class SlaCalculator { * @param DateTimeInterface $date The date to inspect. * * @return bool True for Saturday or Sunday. + * + * @spec openspec/changes/kcc-klantcontact-integratie/tasks.md#TASK-KCC-25 */ public function isWeekend(DateTimeInterface $date): bool { $dow = (int)$date->format('N'); @@ -90,6 +94,8 @@ public function isWeekend(DateTimeInterface $date): bool { * @param DateTimeInterface $date The date to inspect. * * @return bool True when the date is a recognised public holiday. + * + * @spec openspec/changes/kcc-klantcontact-integratie/tasks.md#TASK-KCC-25 */ public function isDutchHoliday(DateTimeInterface $date): bool { $year = (int)$date->format('Y'); @@ -104,6 +110,8 @@ public function isDutchHoliday(DateTimeInterface $date): bool { * @param DateTimeInterface $date The date to inspect. * * @return bool True for a working day. + * + * @spec openspec/changes/kcc-klantcontact-integratie/tasks.md#TASK-KCC-25 */ public function isWorkingDay(DateTimeInterface $date): bool { return ($this->isWeekend(date: $date) === false && $this->isDutchHoliday(date: $date) === false); @@ -118,6 +126,8 @@ public function isWorkingDay(DateTimeInterface $date): bool { * @param int $days Number of working days to add (>= 0). * * @return DateTimeImmutable The resulting date-time. + * + * @spec openspec/changes/kcc-klantcontact-integratie/tasks.md#TASK-KCC-25 */ public function addWorkingDays(DateTimeImmutable $start, int $days): DateTimeImmutable { $result = $start; @@ -140,6 +150,8 @@ public function addWorkingDays(DateTimeImmutable $start, int $days): DateTimeImm * @param DateTimeImmutable $end Range end (inclusive). * * @return int Number of working days in the range (0 when end < start). + * + * @spec openspec/changes/kcc-klantcontact-integratie/tasks.md#TASK-KCC-25 */ public function countWorkingDays(DateTimeImmutable $start, DateTimeImmutable $end): int { $startDay = $start->setTime(0, 0); @@ -172,6 +184,8 @@ public function countWorkingDays(DateTimeImmutable $start, DateTimeImmutable $en * @param DateTimeImmutable $start The contact start time. * * @return DateTimeImmutable The SLA deadline. + * + * @spec openspec/changes/kcc-klantcontact-integratie/tasks.md#TASK-KCC-25 */ public function deadlineFor(string $channel, DateTimeImmutable $start): DateTimeImmutable { if (isset(self::CHANNEL_SLA_WORKING_DAYS[$channel]) === true) { @@ -190,6 +204,8 @@ public function deadlineFor(string $channel, DateTimeImmutable $start): DateTime * @param DateTimeImmutable $now The reference (current) time. * * @return bool True when the deadline has passed. + * + * @spec openspec/changes/kcc-klantcontact-integratie/tasks.md#TASK-KCC-25 */ public function isBreached(string $channel, DateTimeImmutable $start, DateTimeImmutable $now): bool { return ($now > $this->deadlineFor(channel: $channel, start: $start)); @@ -204,6 +220,8 @@ public function isBreached(string $channel, DateTimeImmutable $start, DateTimeIm * @param int $attemptCount The number of attempts already made (>= 0). * * @return DateTimeImmutable The next attempt time. + * + * @spec openspec/changes/kcc-klantcontact-integratie/tasks.md#TASK-KCC-25 */ public function nextRetryAt(DateTimeImmutable $from, int $attemptCount): DateTimeImmutable { $baseMinutes = 15; diff --git a/lib/Service/MandaatEscalatieService.php b/lib/Service/MandaatEscalatieService.php index 2ddf8a563..25cb841eb 100644 --- a/lib/Service/MandaatEscalatieService.php +++ b/lib/Service/MandaatEscalatieService.php @@ -36,6 +36,8 @@ /** * Mandate escalation lifecycle. + * + * @spec openspec/changes/mandaat-matrix-03-escalation-engine/tasks.md */ class MandaatEscalatieService { use SearchesObjects; diff --git a/lib/Service/MandaatGebruikService.php b/lib/Service/MandaatGebruikService.php index 81e65e135..86cadc216 100644 --- a/lib/Service/MandaatGebruikService.php +++ b/lib/Service/MandaatGebruikService.php @@ -35,6 +35,8 @@ /** * Immutable audit log for mandate uses. + * + * @spec openspec/changes/mandaat-matrix-05-case-decision-integration/tasks.md */ class MandaatGebruikService { use SearchesObjects; diff --git a/lib/Service/MandaatImportService.php b/lib/Service/MandaatImportService.php index 157202fa9..a485970da 100644 --- a/lib/Service/MandaatImportService.php +++ b/lib/Service/MandaatImportService.php @@ -46,6 +46,8 @@ * The wire format is parsed by {@see MandaatCsvParser} and every register read * or write goes through {@see MandaatRepository}; what stays here is the import * decision — new vs changed vs removed — and the approval state machine. + * + * @spec openspec/changes/mandaat-matrix-04-decidesk-import/tasks.md */ class MandaatImportService { use SearchesObjects; diff --git a/lib/Service/MapTileService.php b/lib/Service/MapTileService.php index 0ee5ca478..cbd8acc90 100644 --- a/lib/Service/MapTileService.php +++ b/lib/Service/MapTileService.php @@ -37,6 +37,8 @@ /** * Stateless tile-list manifest builder for offline PWA pre-caching. + * + * @spec openspec/changes/mobiel-inspectie-offline/tasks.md#Task-6 */ class MapTileService { /** diff --git a/lib/Service/MentionNotificationService.php b/lib/Service/MentionNotificationService.php index 232e20865..049a8eed8 100644 --- a/lib/Service/MentionNotificationService.php +++ b/lib/Service/MentionNotificationService.php @@ -36,6 +36,8 @@ /** * Service for sending Nextcloud notifications for note `@mention`s. + * + * @spec openspec/specs/ncvue-w2-leaves-adoption/spec.md */ class MentionNotificationService { /** diff --git a/lib/Service/MilestoneService.php b/lib/Service/MilestoneService.php index 6708cc4aa..21939ac2d 100644 --- a/lib/Service/MilestoneService.php +++ b/lib/Service/MilestoneService.php @@ -40,6 +40,8 @@ * Reads go through {@see MilestoneRepository} and the stalled-case report is * owned by {@see StalledCaseDetector}; what stays here is milestone mutation * (mark/reverse) and per-case progress. + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ class MilestoneService { diff --git a/lib/Service/NoticeOfDefaultService.php b/lib/Service/NoticeOfDefaultService.php index fc54f9f7d..0ad554e9b 100644 --- a/lib/Service/NoticeOfDefaultService.php +++ b/lib/Service/NoticeOfDefaultService.php @@ -40,6 +40,8 @@ /** * AWB 4:17 ingebrekestelling registration + DwangsomBerekening creation. + * + * @spec openspec/changes/termijnbewaking-dwangsom-engine-05-ingebrekestelling/tasks.md */ class NoticeOfDefaultService { use SearchesObjects; diff --git a/lib/Service/NotificatieService.php b/lib/Service/NotificatieService.php index 3d3c499c2..97eee5418 100644 --- a/lib/Service/NotificatieService.php +++ b/lib/Service/NotificatieService.php @@ -34,6 +34,8 @@ * Service for publishing ZGW notifications to subscribers. * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * + * @spec openspec/specs/zgw-api-mapping/spec.md */ class NotificatieService { diff --git a/lib/Service/ObjectSchemaSlugResolver.php b/lib/Service/ObjectSchemaSlugResolver.php index 5e537618f..b67700bc7 100644 --- a/lib/Service/ObjectSchemaSlugResolver.php +++ b/lib/Service/ObjectSchemaSlugResolver.php @@ -46,6 +46,8 @@ /** * Turns the schema id an OpenRegister object payload carries into its slug. + * + * @spec openspec/specs/bezwaar-lifecycle/spec.md */ class ObjectSchemaSlugResolver { diff --git a/lib/Service/Pdok/PdokBagService.php b/lib/Service/Pdok/PdokBagService.php index 5f1aef893..4eb9c990c 100644 --- a/lib/Service/Pdok/PdokBagService.php +++ b/lib/Service/Pdok/PdokBagService.php @@ -45,6 +45,8 @@ /** * Single ingress for PDOK BAG WFS v2_0 lookups. + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ class PdokBagService { diff --git a/lib/Service/PdokService.php b/lib/Service/PdokService.php index cbd92fcfe..9b46ecc3b 100644 --- a/lib/Service/PdokService.php +++ b/lib/Service/PdokService.php @@ -61,6 +61,8 @@ /** * Backend-side PDOK shim consuming the openconnector PDOK source adapters. + * + * @spec openspec/specs/gis-integration/spec.md */ class PdokService { /** @@ -125,6 +127,8 @@ public function __construct( * @param int $rows Maximum suggestions to return. * * @return array> Normalised suggestion list. + * + * @spec openspec/changes/migrate-pdok-to-openconnector/tasks.md */ public function searchAddress(string $query, array $filters = [], int $rows = 10): array { $this->lastWarning = null; @@ -154,6 +158,8 @@ public function searchAddress(string $query, array $filters = [], int $rows = 10 * * @return array|null The normalised address envelope, * or null when not found / degraded. + * + * @spec openspec/changes/migrate-pdok-to-openconnector/tasks.md */ public function lookupAddress(string $id): ?array { $this->lastWarning = null; @@ -233,6 +239,8 @@ public function searchParcel(array $criteria): array { * featureFlagActive: bool, * lastWarning: array{messageKey:string,status:int}|null, * } + * + * @spec exclude phpstan dead-code cleanup only — dropped an always-false `$route === null` */ public function getServiceStatus(): array { return [ @@ -247,6 +255,8 @@ public function getServiceStatus(): array { * `messageKey` to the UI for an i18n-backed banner. * * @return array{messageKey:string,status:int}|null + * + * @spec exclude phpstan dead-code cleanup only — dropped an always-false `$route === null` */ public function lastWarning(): ?array { return $this->lastWarning; diff --git a/lib/Service/ProcessMiningService.php b/lib/Service/ProcessMiningService.php index 1f731ecf2..973883304 100644 --- a/lib/Service/ProcessMiningService.php +++ b/lib/Service/ProcessMiningService.php @@ -56,6 +56,8 @@ /** * Computes process-mining bottleneck metrics from recorded status history. + * + * @spec openspec/changes/process-mining-bottlenecks/tasks.md#T01 */ class ProcessMiningService { /** diff --git a/lib/Service/SelectionReassignmentService.php b/lib/Service/SelectionReassignmentService.php index ca32e771a..01ede95e0 100644 --- a/lib/Service/SelectionReassignmentService.php +++ b/lib/Service/SelectionReassignmentService.php @@ -35,6 +35,8 @@ * separate operations that happen to share a write, and putting both on one * class took it past the complexity threshold. The shared write lives in * {@see WritesReassignments}, so the audit entry cannot drift between them. + * + * @spec openspec/changes/reassignment-is-a-bulk-action/specs/reassignment-bulk-action/spec.md */ class SelectionReassignmentService { diff --git a/lib/Service/ShillinqIntegrationService.php b/lib/Service/ShillinqIntegrationService.php index 6ff824454..1f2f24e1f 100644 --- a/lib/Service/ShillinqIntegrationService.php +++ b/lib/Service/ShillinqIntegrationService.php @@ -30,6 +30,8 @@ /** * Shillinq HTTP integration with retry + backoff. + * + * @spec openspec/changes/tenant-zaaksysteem-saas-10-billing-shillinq/tasks.md */ class ShillinqIntegrationService { /** @@ -64,6 +66,8 @@ public function __construct( * @param array> $events Events. * * @return array>> Keyed by `:`. + * + * @spec openspec/changes/tenant-zaaksysteem-saas-10-billing-shillinq/tasks.md */ public function groupForInvoicing(array $events): array { $grouped = []; @@ -93,6 +97,8 @@ public function groupForInvoicing(array $events): array { * @param array> $events Events. * * @return array + * + * @spec openspec/changes/tenant-zaaksysteem-saas-10-billing-shillinq/tasks.md */ public function buildInvoicePayload(string $tenantId, string $month, array $events): array { $lineItems = []; diff --git a/lib/Service/Stuf/CircuitBreakerService.php b/lib/Service/Stuf/CircuitBreakerService.php index cea402d58..2acad0aa8 100644 --- a/lib/Service/Stuf/CircuitBreakerService.php +++ b/lib/Service/Stuf/CircuitBreakerService.php @@ -38,6 +38,8 @@ /** * Per-endpoint circuit breaker. + * + * @spec openspec/specs/stuf-zkn-outbound/spec.md#requirement-circuit-breaker-and-retry */ class CircuitBreakerService { public const THRESHOLD = 4; diff --git a/lib/Service/Stuf/CircuitOpenException.php b/lib/Service/Stuf/CircuitOpenException.php index 15388c0ad..4d5f2443e 100644 --- a/lib/Service/Stuf/CircuitOpenException.php +++ b/lib/Service/Stuf/CircuitOpenException.php @@ -29,6 +29,8 @@ /** * Short-circuited: circuit breaker is open for the endpoint. + * + * @spec openspec/specs/stuf-zkn-outbound/spec.md */ class CircuitOpenException extends StufException { }//end class diff --git a/lib/Service/Stuf/ContactBetrokkeneMapper.php b/lib/Service/Stuf/ContactBetrokkeneMapper.php index 3a157d5bd..5ea2c8d53 100644 --- a/lib/Service/Stuf/ContactBetrokkeneMapper.php +++ b/lib/Service/Stuf/ContactBetrokkeneMapper.php @@ -37,6 +37,8 @@ /** * Maps dossiq Contact entities to zaaksysteem betrokkenen. + * + * @spec openspec/specs/stuf-zkn-outbound/spec.md#requirement-bidirectional-mapping */ class ContactBetrokkeneMapper { /** diff --git a/lib/Service/Stuf/NeedsInputDispatcher.php b/lib/Service/Stuf/NeedsInputDispatcher.php index ca3097a85..fb1644684 100644 --- a/lib/Service/Stuf/NeedsInputDispatcher.php +++ b/lib/Service/Stuf/NeedsInputDispatcher.php @@ -49,6 +49,8 @@ /** * Dispatches needs-input events for the StUF adapter. + * + * @spec openspec/specs/stuf-zkn-outbound/spec.md#requirement-needs-input-escalation */ class NeedsInputDispatcher { /** diff --git a/lib/Service/Stuf/PayloadTooLargeException.php b/lib/Service/Stuf/PayloadTooLargeException.php index 1ce8ae50f..4c0f3bacc 100644 --- a/lib/Service/Stuf/PayloadTooLargeException.php +++ b/lib/Service/Stuf/PayloadTooLargeException.php @@ -29,6 +29,8 @@ /** * Pre-send domain error: payload too large for StUF envelope. + * + * @spec openspec/specs/stuf-zkn-outbound/spec.md */ class PayloadTooLargeException extends StufException { }//end class diff --git a/lib/Service/Stuf/StufException.php b/lib/Service/Stuf/StufException.php index fef98df1b..19b150305 100644 --- a/lib/Service/Stuf/StufException.php +++ b/lib/Service/Stuf/StufException.php @@ -28,6 +28,8 @@ /** * Base StUF adapter exception. + * + * @spec openspec/specs/stuf-zkn-outbound/spec.md */ class StufException extends RuntimeException { }//end class diff --git a/lib/Service/Stuf/StufHttpClient.php b/lib/Service/Stuf/StufHttpClient.php index 299e3d507..08ca23aa5 100644 --- a/lib/Service/Stuf/StufHttpClient.php +++ b/lib/Service/Stuf/StufHttpClient.php @@ -43,6 +43,8 @@ /** * Sends StUF SOAP envelopes over HTTPS with WSSE+mTLS auth. + * + * @spec openspec/specs/stuf-zkn-outbound/spec.md#requirement-secure-transport */ class StufHttpClient { public const DEFAULT_TIMEOUT_SECONDS = 30; diff --git a/lib/Service/Stuf/StufMessageHandler.php b/lib/Service/Stuf/StufMessageHandler.php index 35cb8f22b..c553339fc 100644 --- a/lib/Service/Stuf/StufMessageHandler.php +++ b/lib/Service/Stuf/StufMessageHandler.php @@ -33,6 +33,8 @@ /** * Persists and updates StufMessage audit rows. + * + * @spec openspec/specs/stuf-zkn-outbound/spec.md#requirement-outbound-audit-log */ class StufMessageHandler { diff --git a/lib/Service/Stuf/StufMessageParser.php b/lib/Service/Stuf/StufMessageParser.php index b480dd6ff..838aa9e76 100644 --- a/lib/Service/Stuf/StufMessageParser.php +++ b/lib/Service/Stuf/StufMessageParser.php @@ -37,6 +37,8 @@ /** * Parses StUF response envelopes. + * + * @spec openspec/specs/stuf-zkn-outbound/spec.md#requirement-response-parsing */ class StufMessageParser { public const NS_SOAPENV = StufMessageBuilder::NS_SOAPENV; diff --git a/lib/Service/Stuf/StufVaultService.php b/lib/Service/Stuf/StufVaultService.php index c3d4d2d10..193eda05c 100644 --- a/lib/Service/Stuf/StufVaultService.php +++ b/lib/Service/Stuf/StufVaultService.php @@ -37,6 +37,8 @@ /** * Resolves vault references to plaintext secrets at send time. + * + * @spec openspec/specs/stuf-zkn-outbound/spec.md#requirement-secure-credential-handling */ class StufVaultService { /** diff --git a/lib/Service/Stuf/TimeoutException.php b/lib/Service/Stuf/TimeoutException.php index 9c73b3af5..d17685308 100644 --- a/lib/Service/Stuf/TimeoutException.php +++ b/lib/Service/Stuf/TimeoutException.php @@ -29,6 +29,8 @@ /** * Synchronous vraag/antwoord exceeded the configured timeout. + * + * @spec openspec/specs/stuf-zkn-outbound/spec.md */ class TimeoutException extends StufException { }//end class diff --git a/lib/Service/Stuf/VrijBerichtNotRegisteredException.php b/lib/Service/Stuf/VrijBerichtNotRegisteredException.php index 1f2f12206..8b40a234b 100644 --- a/lib/Service/Stuf/VrijBerichtNotRegisteredException.php +++ b/lib/Service/Stuf/VrijBerichtNotRegisteredException.php @@ -29,6 +29,8 @@ /** * Pre-send domain error: vrijBericht template not registered. + * + * @spec openspec/specs/stuf-zkn-outbound/spec.md */ class VrijBerichtNotRegisteredException extends StufException { }//end class diff --git a/lib/Service/Stuf/ZaaktypeNotMappedException.php b/lib/Service/Stuf/ZaaktypeNotMappedException.php index 261f46fef..958af5d49 100644 --- a/lib/Service/Stuf/ZaaktypeNotMappedException.php +++ b/lib/Service/Stuf/ZaaktypeNotMappedException.php @@ -29,6 +29,8 @@ /** * Pre-send domain error: zaaktype not mapped. + * + * @spec openspec/specs/stuf-zkn-outbound/spec.md */ class ZaaktypeNotMappedException extends StufException { }//end class diff --git a/lib/Service/StufFieldMappingService.php b/lib/Service/StufFieldMappingService.php index d45b70dbd..4ebe7df47 100644 --- a/lib/Service/StufFieldMappingService.php +++ b/lib/Service/StufFieldMappingService.php @@ -36,6 +36,8 @@ * (YYYYMMDD <-> ISO 8601) and enum value transformation. * * @psalm-suppress UnusedClass + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ class StufFieldMappingService { /** diff --git a/lib/Service/StufMessageBuilder.php b/lib/Service/StufMessageBuilder.php index 9ebd7e85f..8d97e9ab7 100644 --- a/lib/Service/StufMessageBuilder.php +++ b/lib/Service/StufMessageBuilder.php @@ -54,6 +54,8 @@ * Service for constructing the outbound StUF-ZKN request envelopes. * * @psalm-suppress UnusedClass + * + * @spec openspec/specs/stuf-zkn-outbound/spec.md#requirement-outbound-envelope-construction */ class StufMessageBuilder { /** diff --git a/lib/Service/Subsidie/BeschikkingService.php b/lib/Service/Subsidie/BeschikkingService.php index aa6b0742e..fc742ef40 100644 --- a/lib/Service/Subsidie/BeschikkingService.php +++ b/lib/Service/Subsidie/BeschikkingService.php @@ -75,6 +75,8 @@ public function __construct( * @param DateTimeImmutable $publication The publication date. * * @return DateTimeImmutable The bezwaartermijn end. + * + * @spec openspec/changes/subsidieverlening-keten/specs.md */ public function computeBezwaartermijn(DateTimeImmutable $publication): DateTimeImmutable { return $publication->add(new DateInterval('P' . (self::BEZWAARTERMIJN_WEKEN * 7) . 'D')); @@ -88,6 +90,8 @@ public function computeBezwaartermijn(DateTimeImmutable $publication): DateTimeI * @return void * * @throws OCSBadRequestException When validation fails. + * + * @spec openspec/changes/subsidieverlening-keten/specs.md */ public function assertDraftValid(array $payload): void { $granted = (float)($payload['grantedAmount'] ?? 0); diff --git a/lib/Service/Subsidie/BewijsstukService.php b/lib/Service/Subsidie/BewijsstukService.php index 992c05986..cd45ec82e 100644 --- a/lib/Service/Subsidie/BewijsstukService.php +++ b/lib/Service/Subsidie/BewijsstukService.php @@ -91,6 +91,8 @@ public function __construct( * @param string $type The bewijsstuk type. * * @return bool True when the combination is on the whitelist. + * + * @spec openspec/changes/subsidieverlening-keten/specs.md */ public function isTypeAllowed(string $linkedIn, string $type): bool { $allowed = self::TYPE_WHITELIST[$linkedIn] ?? null; @@ -109,6 +111,8 @@ public function isTypeAllowed(string $linkedIn, string $type): bool { * @param int|null $override Regeling-configured retention, if any. * * @return int The retention years. + * + * @spec openspec/changes/subsidieverlening-keten/specs.md */ public function bewaartermijnJaren(string $linkedIn, ?int $override = null): int { if ($override !== null && $override > 0) { @@ -125,6 +129,8 @@ public function bewaartermijnJaren(string $linkedIn, ?int $override = null): int * @param int $jaren The retention years. * * @return DateTimeImmutable The retention end date. + * + * @spec openspec/changes/subsidieverlening-keten/specs.md */ public function bewaartermijnEinde(DateTimeImmutable $from, int $jaren): DateTimeImmutable { return $from->add(new DateInterval('P' . max(1, $jaren) . 'Y')); @@ -136,6 +142,8 @@ public function bewaartermijnEinde(DateTimeImmutable $from, int $jaren): DateTim * @param string $contents The raw file contents. * * @return string The lowercase hex digest. + * + * @spec openspec/changes/subsidieverlening-keten/specs.md */ public function computeHash(string $contents): string { return hash('sha256', $contents); @@ -148,6 +156,8 @@ public function computeHash(string $contents): string { * @param string $expectedHash The recorded digest. * * @return bool True when the hash matches (constant-time compare). + * + * @spec openspec/changes/subsidieverlening-keten/specs.md */ public function verifyHash(string $contents, string $expectedHash): bool { return hash_equals($expectedHash, $this->computeHash(contents: $contents)); @@ -208,6 +218,8 @@ public function create(array $payload, ?string $contents = null, ?int $regelingR * @return void * * @throws OCSBadRequestException When the document is immutable. + * + * @spec openspec/specs/subsidieverlening-keten/spec.md#requirement-req-sub-007-bewijsstukken-management-with-bewaartermijn */ public function assertMutable(array $bewijsstuk): void { if (($bewijsstuk['immutable'] ?? false) === true) { diff --git a/lib/Service/Subsidie/CofinancieringValidator.php b/lib/Service/Subsidie/CofinancieringValidator.php index 20daa92be..9cd1cc06f 100644 --- a/lib/Service/Subsidie/CofinancieringValidator.php +++ b/lib/Service/Subsidie/CofinancieringValidator.php @@ -50,6 +50,8 @@ class CofinancieringValidator { * @param array> $rows The contribution rows. * * @return float The total in EUR. + * + * @spec openspec/changes/subsidieverlening-keten/specs.md */ public function sumBedragen(array $rows): float { $sum = 0.0; @@ -69,6 +71,8 @@ public function sumBedragen(array $rows): float { * @param float $projectTotal The project total. * * @return bool True when the funding sources reconcile to the total. + * + * @spec openspec/changes/subsidieverlening-keten/specs.md */ public function reconciles(float $subsidyAmount, array $cofinanciering, float $projectTotal): bool { $total = ($subsidyAmount + $this->sumBedragen(rows: $cofinanciering)); @@ -81,6 +85,8 @@ public function reconciles(float $subsidyAmount, array $cofinanciering, float $p * @param array> $cofinanciering The co-financing rows. * * @return bool True when EU co-financing is present. + * + * @spec openspec/changes/subsidieverlening-keten/specs.md */ public function hasEuCofinanciering(array $cofinanciering): bool { foreach ($cofinanciering as $row) { @@ -104,6 +110,8 @@ public function hasEuCofinanciering(array $cofinanciering): bool { * @param float $projectTotal The project total. * * @return array{valid: bool, error: string|null, euCofinanciering: bool} + * + * @spec openspec/changes/subsidieverlening-keten/specs.md */ public function validate(float $subsidyAmount, array $cofinanciering, float $projectTotal): array { if ($projectTotal <= 0.0) { diff --git a/lib/Service/Subsidie/StaatssteunClassifier.php b/lib/Service/Subsidie/StaatssteunClassifier.php index 62e9c51eb..883243b36 100644 --- a/lib/Service/Subsidie/StaatssteunClassifier.php +++ b/lib/Service/Subsidie/StaatssteunClassifier.php @@ -64,6 +64,8 @@ class StaatssteunClassifier { * @param float $eerdereDeMinimis The cumulative prior de-minimis aid in the window. * * @return bool True when the cumulative total stays within the ceiling. + * + * @spec openspec/changes/subsidieverlening-keten/specs.md */ public function fitsDeMinimis(float $newAmount, float $eerdereDeMinimis): bool { return ($eerdereDeMinimis + $newAmount) <= self::DE_MINIMIS_PLAFOND; @@ -75,6 +77,8 @@ public function fitsDeMinimis(float $newAmount, float $eerdereDeMinimis): bool { * @param float $eerdereDeMinimis The cumulative prior de-minimis aid in the window. * * @return float The remaining headroom in EUR (never negative). + * + * @spec openspec/changes/subsidieverlening-keten/specs.md */ public function deMinimisHeadroom(float $eerdereDeMinimis): float { return max(0.0, (self::DE_MINIMIS_PLAFOND - $eerdereDeMinimis)); @@ -88,6 +92,8 @@ public function deMinimisHeadroom(float $eerdereDeMinimis): float { * @param float $eerdereDeMinimis The cumulative prior de-minimis aid. * * @return bool True when a state-aid ground must be recorded. + * + * @spec openspec/changes/subsidieverlening-keten/specs.md */ public function requiresStaatssteunGrondslag(float $amount, float $eerdereDeMinimis): bool { return $this->fitsDeMinimis(newAmount: $amount, eerdereDeMinimis: $eerdereDeMinimis) === false; @@ -99,6 +105,8 @@ public function requiresStaatssteunGrondslag(float $amount, float $eerdereDeMini * @param string $artikel The AGVV article token. * * @return bool True when supported. + * + * @spec openspec/changes/subsidieverlening-keten/specs.md */ public function isAgvvArtikel(string $artikel): bool { return in_array($artikel, self::AGVV_ARTIKELEN, true); @@ -116,6 +124,8 @@ public function isAgvvArtikel(string $artikel): bool { * * @SuppressWarnings(PHPMD.BooleanArgumentFlag) — $isDaeb is a classification * input (the activity either is or is not a DAEB), not a behaviour switch. + * + * @spec openspec/changes/subsidieverlening-keten/specs.md */ public function classify(float $amount, float $eerdereDeMinimis, ?string $agvvArtikel = null, bool $isDaeb = false): string { if ($isDaeb === true) { @@ -145,6 +155,8 @@ public function classify(float $amount, float $eerdereDeMinimis, ?string $agvvAr * @param float $amount The granted amount. * * @return array The melding payload for async transmission. + * + * @spec openspec/changes/subsidieverlening-keten/specs.md */ public function buildTamMelding(string $beschikkingnummer, string $agvvArtikel, float $amount): array { return [ diff --git a/lib/Service/Subsidie/SubsidieRegisterExporter.php b/lib/Service/Subsidie/SubsidieRegisterExporter.php index a14fa71dd..823445699 100644 --- a/lib/Service/Subsidie/SubsidieRegisterExporter.php +++ b/lib/Service/Subsidie/SubsidieRegisterExporter.php @@ -50,6 +50,8 @@ class SubsidieRegisterExporter { * @param array $request The application record. * * @return string The display name for the public register. + * + * @spec openspec/changes/subsidieverlening-keten/specs.md */ public function publicOntvanger(array $request): string { $kvk = (string)($request['applicantKvkRef'] ?? ''); @@ -69,6 +71,8 @@ public function publicOntvanger(array $request): string { * @param array $decision The (latest) decision record. * * @return array The feed entry. + * + * @spec openspec/changes/subsidieverlening-keten/specs.md */ public function toFeedEntry(array $request, array $regeling, array $decision): array { $determined = (string)($decision['beschikkingtype'] ?? '') === 'vaststellingsbeschikking'; @@ -100,6 +104,8 @@ public function toFeedEntry(array $request, array $regeling, array $decision): a * @param int $offset Page offset. * * @return array The feed document. + * + * @spec openspec/changes/subsidieverlening-keten/specs.md */ public function buildFeed(array $entries, int $limit = 100, int $offset = 0): array { $limit = max(1, $limit); diff --git a/lib/Service/Subsidie/SubsidieService.php b/lib/Service/Subsidie/SubsidieService.php index b378400a9..442090bf7 100644 --- a/lib/Service/Subsidie/SubsidieService.php +++ b/lib/Service/Subsidie/SubsidieService.php @@ -107,6 +107,8 @@ public function __construct( * @param string $to Target status. * * @return bool True when the transition is allowed. + * + * @spec openspec/changes/subsidieverlening-keten/specs.md */ public function isTransitionAllowed(string $from, string $to): bool { $allowed = self::TRANSITIONS[$from] ?? null; @@ -124,6 +126,8 @@ public function isTransitionAllowed(string $from, string $to): bool { * @param DateTimeImmutable|null $now Clock injection for tests. * * @return string The formatted beschikkingnummer. + * + * @spec openspec/changes/subsidieverlening-keten/specs.md */ public function generateBeschikkingnummer(int $sequence, ?DateTimeImmutable $now = null): string { $now = ($now ?? new DateTimeImmutable()); @@ -139,6 +143,8 @@ public function generateBeschikkingnummer(int $sequence, ?DateTimeImmutable $now * @param int $weken The regeling term in weeks. * * @return DateTimeImmutable The decision deadline. + * + * @spec openspec/changes/subsidieverlening-keten/specs.md */ public function computeBeslistermijn(DateTimeImmutable $registration, int $weken): DateTimeImmutable { $weken = max(1, $weken); @@ -153,6 +159,8 @@ public function computeBeslistermijn(DateTimeImmutable $registration, int $weken * @param float $grantedAmount The granted amount. * * @return bool True when the schedule reconciles to the granted amount. + * + * @spec openspec/changes/subsidieverlening-keten/specs.md */ public function voorschotSchemaReconciles(array $advanceSchema, float $grantedAmount): bool { $sum = 0.0; @@ -174,6 +182,8 @@ public function voorschotSchemaReconciles(array $advanceSchema, float $grantedAm * @param array $approvedReports Approved tussenrapportage ids. * * @return bool True when the voorschot is releasable. + * + * @spec openspec/changes/subsidieverlening-keten/specs.md */ public function isVoorschotReleasable(array $voorschot, array $approvedReports): bool { $voorwaarde = trim((string)($voorschot['voorwaarde'] ?? '')); @@ -197,6 +207,8 @@ public function isVoorschotReleasable(array $voorschot, array $approvedReports): * @param array> $verplichtingen Condition rows. * * @return array> The unmet conditions. + * + * @spec openspec/changes/subsidieverlening-keten/specs.md */ public function unmetVerplichtingen(array $verplichtingen): array { $unmet = []; @@ -302,6 +314,8 @@ public function transitionAanvraag(string $id, string $toStatus): array { * @return array> The aanvragen. * * @throws OCSBadRequestException When OpenRegister is unavailable/unconfigured. + * + * @spec openspec/specs/subsidieverlening-keten/spec.md#requirement-req-sub-002-awb-termijn-binding-for-each-phase */ public function listAanvragen(array $filters = []): array { [$objectService, $register, $schema] = $this->resolve(schemaConfigKey: 'subsidie_aanvraag_schema'); @@ -322,6 +336,8 @@ public function listAanvragen(array $filters = []): array { * @param string $bsn The raw BSN. * * @return string The masked reference. + * + * @spec openspec/specs/subsidieverlening-keten/spec.md#requirement-req-sub-002-awb-termijn-binding-for-each-phase */ public function maskBsn(string $bsn): string { $digits = preg_replace('/\D/', '', $bsn); diff --git a/lib/Service/Subsidie/TerugvorderingService.php b/lib/Service/Subsidie/TerugvorderingService.php index 0e9a310a5..e4fc48dda 100644 --- a/lib/Service/Subsidie/TerugvorderingService.php +++ b/lib/Service/Subsidie/TerugvorderingService.php @@ -81,6 +81,8 @@ public function __construct( * @param DateTimeImmutable $publication The publication date. * * @return DateTimeImmutable The bezwaartermijn end. + * + * @spec openspec/changes/subsidieverlening-keten/specs.md */ public function computeBezwaartermijn(DateTimeImmutable $publication): DateTimeImmutable { return $publication->add(new DateInterval('P' . (self::BEZWAARTERMIJN_WEKEN * 7) . 'D')); @@ -92,6 +94,8 @@ public function computeBezwaartermijn(DateTimeImmutable $publication): DateTimeI * @param DateTimeImmutable $publication The publication date. * * @return DateTimeImmutable The betaaltermijn end. + * + * @spec openspec/changes/subsidieverlening-keten/specs.md */ public function computeBetaaltermijn(DateTimeImmutable $publication): DateTimeImmutable { return $publication->add(new DateInterval('P' . (self::BETAALTERMIJN_WEKEN * 7) . 'D')); @@ -108,6 +112,8 @@ public function computeBetaaltermijn(DateTimeImmutable $publication): DateTimeIm * @param float|null $yearFaction Annual rate fraction; defaults to the wettelijke rente. * * @return float The accrued rente in EUR. + * + * @spec openspec/changes/subsidieverlening-keten/specs.md */ public function computeInvorderingsrente( float $openstaandBedrag, @@ -133,6 +139,8 @@ public function computeInvorderingsrente( * @param float $paid The cumulative amount paid. * * @return string The resulting status. + * + * @spec openspec/changes/subsidieverlening-keten/specs.md */ public function statusAfterPayment(float $amount, float $paid): string { if ($paid <= 0.0) { diff --git a/lib/Service/Subsidie/TussenrapportageService.php b/lib/Service/Subsidie/TussenrapportageService.php index 6525cb838..c2d83db4e 100644 --- a/lib/Service/Subsidie/TussenrapportageService.php +++ b/lib/Service/Subsidie/TussenrapportageService.php @@ -91,6 +91,8 @@ public function __construct( * @param int $termWeken The regeling assessment term. * * @return DateTimeImmutable The assessment deadline. + * + * @spec openspec/changes/subsidieverlening-keten/specs.md */ public function computeBeoordelingstermijn(DateTimeImmutable $periodEnd, int $termWeken): DateTimeImmutable { $termWeken = max(1, $termWeken); @@ -106,6 +108,8 @@ public function computeBeoordelingstermijn(DateTimeImmutable $periodEnd, int $te * @param int $year The calendar year. * * @return array The reporting periods. + * + * @spec openspec/changes/subsidieverlening-keten/specs.md */ public function periodsForFrequentie(string $frequency, int $year): array { if ($frequency === 'annually') { diff --git a/lib/Service/Support/SeedSummary.php b/lib/Service/Support/SeedSummary.php index dbaab03ba..45e15b1ca 100644 --- a/lib/Service/Support/SeedSummary.php +++ b/lib/Service/Support/SeedSummary.php @@ -61,6 +61,8 @@ class SeedSummary { * @param array $result The per-case-type counts. * * @return void + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ public function addCaseTypeResult(array $result): void { foreach (array_keys($this->created) as $kind) { @@ -72,6 +74,8 @@ public function addCaseTypeResult(array $result): void { * Record one refused write. * * @return void + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ public function recordFailure(): void { $this->failed++; @@ -81,6 +85,8 @@ public function recordFailure(): void { * Whether every write the run attempted landed. * * @return bool True when nothing was refused. + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ public function isClean(): bool { return $this->failed === 0; @@ -93,6 +99,8 @@ public function isClean(): bool { * `caseTypes: 0` as "nothing left to do". * * @return array The summary. + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ public function toArray(): array { $summary = ['success' => $this->isClean()] + $this->created + ['failed' => $this->failed]; diff --git a/lib/Service/TemplateLibraryService.php b/lib/Service/TemplateLibraryService.php index ab4bcdbc2..b8c393cf4 100644 --- a/lib/Service/TemplateLibraryService.php +++ b/lib/Service/TemplateLibraryService.php @@ -33,6 +33,8 @@ /** * Service for loading and activating zaaktype templates. + * + * @spec openspec/specs/template-library/spec.md */ class TemplateLibraryService { diff --git a/lib/Service/TenantAuditTrailService.php b/lib/Service/TenantAuditTrailService.php index 887a66a73..43467366f 100644 --- a/lib/Service/TenantAuditTrailService.php +++ b/lib/Service/TenantAuditTrailService.php @@ -47,6 +47,8 @@ /** * Tenant-stamped audit-trail emitter. + * + * @spec openspec/specs/tenant-compliance/spec.md */ class TenantAuditTrailService { /** @@ -225,6 +227,8 @@ private function resolveTenantEntity(string $tenantId): mixed { * @param array $bio Raw BIO context. * * @return array + * + * @spec openspec/specs/tenant-compliance/spec.md */ public function sanitiseBio(array $bio): array { $out = []; diff --git a/lib/Service/TenantAuthenticationService.php b/lib/Service/TenantAuthenticationService.php index 53ab67238..e7b3e4a26 100644 --- a/lib/Service/TenantAuthenticationService.php +++ b/lib/Service/TenantAuthenticationService.php @@ -36,6 +36,8 @@ /** * Mandate-matrix authorisation guard for tenant actions. + * + * @spec openspec/specs/multi-tenancy/spec.md#req-005-tenant-membership-and-status-helpers-for-middleware */ class TenantAuthenticationService { /** @@ -119,6 +121,8 @@ public function validateMandateMatrix(string $tenantId, string $userId, string $ * @param string $action Requested action. * * @return bool + * + * @spec openspec/specs/tenant-mandate/spec.md#requirement-mandate-matrix-validation-per-action-req-002-d-req-006-d */ public function isAllowed(array $matrix, string $role, string $action): bool { $roleEntry = ($matrix[$role] ?? null); @@ -152,6 +156,8 @@ public function isAllowed(array $matrix, string $role, string $action): bool { * @param string $tenantId Tenant UUID. * * @return array>|null Active matrix or null. + * + * @spec openspec/specs/tenant-mandate/spec.md#requirement-mandate-matrix-validation-per-action-req-002-d-req-006-d */ public function loadActiveMatrix(string $tenantId): ?array { $objectService = $this->getObjectService(); diff --git a/lib/Service/TenantBillingService.php b/lib/Service/TenantBillingService.php index 8c702a6a7..074edf67c 100644 --- a/lib/Service/TenantBillingService.php +++ b/lib/Service/TenantBillingService.php @@ -34,6 +34,8 @@ /** * Billing event service. + * + * @spec openspec/specs/tenant-billing/spec.md */ class TenantBillingService { /** @@ -215,6 +217,8 @@ public function emitEvent(string $tenantId, string $eventType, float $quantity = * @return array{eventCount:int, totalAmount:float, byType:array} * * @throws InvalidArgumentException When month is malformed. + * + * @spec openspec/specs/tenant-billing/spec.md#requirement-billing-event-emission-on-case-lifecycle-req-007-a */ public function getMonthBilling(string $tenantId, string $month): array { if (preg_match('/^[0-9]{4}-(0[1-9]|1[0-2])$/', $month) !== 1) { @@ -231,6 +235,8 @@ public function getMonthBilling(string $tenantId, string $month): array { * @param array> $events Event rows. * * @return array{eventCount:int, totalAmount:float, byType:array} + * + * @spec openspec/specs/tenant-billing/spec.md#requirement-billing-event-emission-on-case-lifecycle-req-007-a */ public function aggregate(array $events): array { $byType = []; @@ -306,6 +312,8 @@ public function markExported(array $events, string $invoiceRef): int { * @param string $month YYYY-MM. * * @return array> + * + * @spec openspec/specs/tenant-billing/spec.md#requirement-daily-billing-export-to-shillinq-req-007-b */ public function fetchEventsForMonth(string $tenantId, string $month): array { $objectService = $this->getObjectService(); diff --git a/lib/Service/TenantConfigurationService.php b/lib/Service/TenantConfigurationService.php index a88b8f93d..a87ec84d5 100644 --- a/lib/Service/TenantConfigurationService.php +++ b/lib/Service/TenantConfigurationService.php @@ -37,6 +37,8 @@ * Branding validation is owned by {@see TenantBrandingSanitiser}; this service * owns configuration storage — read, merge, persist — plus locale and feature * flags. + * + * @spec openspec/changes/tenant-zaaksysteem-saas-08-configuration-branding/tasks.md */ class TenantConfigurationService { /** @@ -103,6 +105,8 @@ public function __construct( * @param string $tenantId Tenant UUID. * * @return array|null + * + * @spec openspec/changes/tenant-zaaksysteem-saas-08-configuration-branding/tasks.md */ public function getConfig(string $tenantId): ?array { $objectService = $this->getObjectService(); @@ -161,6 +165,8 @@ public function getConfig(string $tenantId): ?array { * @param bool $enabled True to add, false to remove. * * @return array + * + * @spec openspec/changes/tenant-zaaksysteem-saas-08-configuration-branding/tasks.md */ public function setFeatureFlag(string $tenantId, string $flag, bool $enabled): array { $current = $this->getConfig(tenantId: $tenantId) ?? ['tenantRef' => $tenantId, 'features' => []]; @@ -228,6 +234,8 @@ public function sanitiseBranding(array $branding): array { * @param string $css Raw CSS. * * @return string Sanitised CSS. + * + * @spec openspec/specs/security-hardening/spec.md */ public function sanitiseCustomCss(string $css): string { return $this->sanitiser->sanitiseCustomCss(css: $css); @@ -242,6 +250,8 @@ public function sanitiseCustomCss(string $css): string { * @return void * * @throws InvalidArgumentException + * + * @spec openspec/specs/security-hardening/spec.md */ public function validateLogoUpload(string $mimeType, int $bytes): void { $this->sanitiser->validateLogoUpload(mimeType: $mimeType, bytes: $bytes); @@ -253,6 +263,8 @@ public function validateLogoUpload(string $mimeType, int $bytes): void { * @param string $val 6-digit hex (with leading #). * * @return bool + * + * @spec openspec/specs/security-hardening/spec.md */ public function isHexColor(string $val): bool { return $this->sanitiser->isHexColor(val: $val); diff --git a/lib/Service/TenantContext.php b/lib/Service/TenantContext.php index 3b3747f01..b70e6e9fe 100644 --- a/lib/Service/TenantContext.php +++ b/lib/Service/TenantContext.php @@ -35,6 +35,8 @@ * Implemented as a regular service whose lifetime is bound to the request * scope by the NC DI container (request-scoped via `IRequest` is sufficient * — every HTTP request gets a fresh container child). + * + * @spec openspec/changes/tenant-zaaksysteem-saas-04-tenant-context-isolation/tasks.md */ class TenantContext { @@ -73,6 +75,8 @@ class TenantContext { * @param string $schemaName Tenant schema name. * * @return void + * + * @spec openspec/changes/tenant-zaaksysteem-saas-04-tenant-context-isolation/tasks.md */ public function bind(array $tenant, string $schemaName): void { $this->tenant = $tenant; @@ -85,6 +89,8 @@ public function bind(array $tenant, string $schemaName): void { * Whether a tenant has been bound to the request. * * @return bool + * + * @spec openspec/changes/tenant-zaaksysteem-saas-04-tenant-context-isolation/tasks.md */ public function isBound(): bool { return $this->tenant !== null; @@ -96,6 +102,8 @@ public function isBound(): bool { * @return array * * @throws RuntimeException When no tenant is bound. + * + * @spec openspec/changes/tenant-zaaksysteem-saas-04-tenant-context-isolation/tasks.md */ public function getTenant(): array { $this->assertBound(); @@ -108,6 +116,8 @@ public function getTenant(): array { * @return string * * @throws RuntimeException When no tenant is bound. + * + * @spec openspec/changes/tenant-zaaksysteem-saas-04-tenant-context-isolation/tasks.md */ public function getTenantId(): string { $this->assertBound(); @@ -120,6 +130,8 @@ public function getTenantId(): string { * @return string * * @throws RuntimeException When no tenant is bound. + * + * @spec openspec/changes/tenant-zaaksysteem-saas-04-tenant-context-isolation/tasks.md */ public function getSlug(): string { $this->assertBound(); @@ -132,6 +144,8 @@ public function getSlug(): string { * @return string * * @throws RuntimeException When no tenant is bound. + * + * @spec openspec/changes/tenant-zaaksysteem-saas-04-tenant-context-isolation/tasks.md */ public function getSchemaName(): string { $this->assertBound(); @@ -142,6 +156,8 @@ public function getSchemaName(): string { * Reset the context. Used in tests + at the end of each request. * * @return void + * + * @spec openspec/changes/tenant-zaaksysteem-saas-04-tenant-context-isolation/tasks.md */ public function reset(): void { $this->tenant = null; diff --git a/lib/Service/TenantJwtService.php b/lib/Service/TenantJwtService.php index 5998ad914..9fb488a8f 100644 --- a/lib/Service/TenantJwtService.php +++ b/lib/Service/TenantJwtService.php @@ -37,6 +37,8 @@ /** * HMAC-based JWT validation with first-class tenant claim support. Minting * lives with the external broker that issues the tokens — see the note below. + * + * @spec openspec/changes/tenant-zaaksysteem-saas-05-auth-jwt-tenant-claim/tasks.md */ class TenantJwtService { /** @@ -98,6 +100,8 @@ public function __construct( * * @throws RuntimeException When the token is malformed, the signature * does not match, or the token is expired. + * + * @spec openspec/changes/tenant-zaaksysteem-saas-05-auth-jwt-tenant-claim/tasks.md */ public function validate(string $token): array { $parts = explode('.', $token); @@ -132,6 +136,8 @@ public function validate(string $token): array { * @return string * * @throws RuntimeException When the claim is missing. + * + * @spec openspec/changes/tenant-zaaksysteem-saas-05-auth-jwt-tenant-claim/tasks.md */ public function extractTenantId(array $claims): string { $tid = (string)($claims['tenant_id'] ?? ''); diff --git a/lib/Service/TenantLifecycleControlService.php b/lib/Service/TenantLifecycleControlService.php index b6d585185..27f3dddcc 100644 --- a/lib/Service/TenantLifecycleControlService.php +++ b/lib/Service/TenantLifecycleControlService.php @@ -31,6 +31,8 @@ /** * Suspension / reactivation / termination orchestration. + * + * @spec openspec/specs/tenant-lifecycle/spec.md#requirement-tenant-suspension-and-reactivation-req-008-a */ class TenantLifecycleControlService { /** @@ -139,6 +141,8 @@ public function terminate(string $tenantId, string $reason, int $retentionYears * @param string $tenantId Tenant UUID. * * @return int + * + * @spec openspec/specs/tenant-lifecycle/spec.md#requirement-tenant-termination-and-data-archival-req-008-b */ public function countUnsettledEvents(string $tenantId): int { $events = $this->billingService->fetchEventsForMonth( diff --git a/lib/Service/TenantOnboardingService.php b/lib/Service/TenantOnboardingService.php index e5f3a584c..f6373667d 100644 --- a/lib/Service/TenantOnboardingService.php +++ b/lib/Service/TenantOnboardingService.php @@ -34,6 +34,8 @@ /** * Onboarding workflow service. + * + * @spec openspec/specs/tenant-onboarding/spec.md#requirement-onboarding-checklist-and-progress-dashboard-req-003-a-req-003-d */ class TenantOnboardingService { /** @@ -244,6 +246,8 @@ public function markStepComplete(string $tenantId, string $step, string $complet * @param string $tenantId Tenant UUID. * * @return array{ready: bool, missing: array} + * + * @spec openspec/specs/tenant-onboarding/spec.md#requirement-onboarding-checklist-and-progress-dashboard-req-003-a-req-003-d */ public function validateGoLive(string $tenantId): array { $objectService = $this->getObjectService(); diff --git a/lib/Service/TenantProvisioningService.php b/lib/Service/TenantProvisioningService.php index 4cd259cc7..b29d14602 100644 --- a/lib/Service/TenantProvisioningService.php +++ b/lib/Service/TenantProvisioningService.php @@ -40,6 +40,8 @@ * * Returns the provisioning result (schemaName + steps performed) or throws * after rolling back any partial work. + * + * @spec openspec/specs/tenant-provisioning/spec.md#requirement-schema-per-tenant-provisioning-req-001-b */ class TenantProvisioningService { /** @@ -167,6 +169,8 @@ public function provision(string $tenantId): array { * @return string Schema name (≤63 chars, lowercase, identifier-safe). * * @throws InvalidArgumentException When uuid or slug is empty. + * + * @spec openspec/specs/tenant-provisioning/spec.md#requirement-schema-per-tenant-provisioning-req-001-b */ public function buildSchemaName(string $uuid, string $slug): string { if ($uuid === '' || $slug === '') { @@ -223,6 +227,8 @@ public function rollback(string $schemaName, array $steps): void { * Return the default roles seeded per tenant. * * @return array + * + * @spec openspec/specs/tenant-provisioning/spec.md#requirement-schema-per-tenant-provisioning-req-001-b */ public function getDefaultRoles(): array { return self::DEFAULT_ROLES; diff --git a/lib/Service/TenantQuotaService.php b/lib/Service/TenantQuotaService.php index 67601888e..9cf8c5a61 100644 --- a/lib/Service/TenantQuotaService.php +++ b/lib/Service/TenantQuotaService.php @@ -36,6 +36,8 @@ /** * Quota service. + * + * @spec openspec/changes/tenant-zaaksysteem-saas-09-quotas-enforcement/tasks.md */ class TenantQuotaService { /** @@ -143,6 +145,8 @@ public function initialize(string $tenantId, string $tier): array { * @param string $quotaType Type. * * @return array|null + * + * @spec openspec/specs/tenant-quotas/spec.md#requirement-tier-based-quota-initialisation-req-005-a-req-005-e */ public function getQuota(string $tenantId, string $quotaType): ?array { $objectService = $this->getObjectService(); @@ -185,6 +189,8 @@ public function getQuota(string $tenantId, string $quotaType): ?array { * @param int $increment Requested increment. * * @return array{decision:string, soft:bool, reason:string} + * + * @spec openspec/specs/tenant-quotas/spec.md#requirement-tier-based-quota-initialisation-req-005-a-req-005-e */ public function decide(array $quota, int $increment = 1): array { $limit = $quota['limit'] ?? null; @@ -231,6 +237,8 @@ public function decide(array $quota, int $increment = 1): array { * @param int $amount Amount to consume. * * @return array{decision:string, soft:bool, reason:string, currentUsage?:int} + * + * @spec openspec/specs/tenant-quotas/spec.md#requirement-tier-based-quota-initialisation-req-005-a-req-005-e */ public function consume(string $tenantId, string $quotaType, int $amount = 1): array { $quota = $this->getQuota(tenantId: $tenantId, quotaType: $quotaType); @@ -257,6 +265,8 @@ public function consume(string $tenantId, string $quotaType, int $amount = 1): a * @param int|null $limit New limit (null = unlimited). * * @return array|null Persisted row. + * + * @spec openspec/specs/tenant-quotas/spec.md#requirement-tier-based-quota-initialisation-req-005-a-req-005-e */ public function setLimit(string $tenantId, string $quotaType, ?int $limit): ?array { $quota = $this->getQuota(tenantId: $tenantId, quotaType: $quotaType); @@ -275,6 +285,8 @@ public function setLimit(string $tenantId, string $quotaType, ?int $limit): ?arr * @param array $quota Quota row. * * @return array Updated row. + * + * @spec openspec/specs/tenant-quotas/spec.md#requirement-tier-based-quota-initialisation-req-005-a-req-005-e */ public function resetIfDue(array $quota): array { $resetAt = strtotime((string)($quota['resetAt'] ?? '')); @@ -295,6 +307,8 @@ public function resetIfDue(array $quota): array { * @param string $quotaType Type. * * @return string ISO-8601 timestamp. + * + * @spec openspec/specs/tenant-quotas/spec.md#requirement-tier-based-quota-initialisation-req-005-a-req-005-e */ public function nextResetAt(string $quotaType): string { if ($quotaType === 'api_calls_per_hour') { diff --git a/lib/Service/TenantSaasService.php b/lib/Service/TenantSaasService.php index 2f008db57..adcbc236d 100644 --- a/lib/Service/TenantSaasService.php +++ b/lib/Service/TenantSaasService.php @@ -48,6 +48,8 @@ * All persistence goes through OpenRegister's ObjectService — no bespoke * Doctrine entity. The state machine validates that only the documented * transitions are written. + * + * @spec openspec/specs/tenant-crud-lifecycle/spec.md */ class TenantSaasService { use SearchesObjects; @@ -323,6 +325,8 @@ public function delete(string $tenantId): bool { * @param string $name Display name. * * @return string Slug. + * + * @spec openspec/specs/tenant-crud-lifecycle/spec.md#requirement-tenant-lifecycle-state-machine-req-001-a-lifecycle */ public function slugify(string $name): string { $lower = mb_strtolower(trim($name), 'UTF-8'); @@ -348,6 +352,8 @@ public function slugify(string $name): string { * @return void * * @throws InvalidArgumentException When the transition is illegal. + * + * @spec openspec/specs/tenant-crud-lifecycle/spec.md#requirement-tenant-lifecycle-state-machine-req-001-a-lifecycle */ public function assertLegalTransition(string $current, string $target): void { if (array_key_exists($current, self::LIFECYCLE_TRANSITIONS) === false) { @@ -369,6 +375,8 @@ public function assertLegalTransition(string $current, string $target): void { * Return the full lifecycle transition graph (for tests / introspection). * * @return array> + * + * @spec openspec/specs/tenant-crud-lifecycle/spec.md#requirement-tenant-lifecycle-state-machine-req-001-a-lifecycle */ public function getLifecycleGraph(): array { return self::LIFECYCLE_TRANSITIONS; diff --git a/lib/Service/TenantSchemaProvisioner.php b/lib/Service/TenantSchemaProvisioner.php index 2c630932d..c0ac0c7da 100644 --- a/lib/Service/TenantSchemaProvisioner.php +++ b/lib/Service/TenantSchemaProvisioner.php @@ -41,6 +41,8 @@ * those stay in `public`). Shared tables are the SaaS-control plane: * `tenant`, `tenantConfiguration`, `tenantQuota`, `tenantUser`, * `tenantMandate`, `tenantBillingEvent`, `tenantOnboardingTask`. + * + * @spec openspec/specs/tenant-provisioning/spec.md#requirement-schema-per-tenant-provisioning-req-001-b */ class TenantSchemaProvisioner { /** @@ -115,6 +117,8 @@ public function __construct( * * @throws InvalidArgumentException When the name is invalid. * @throws RuntimeException When the DDL fails. + * + * @spec openspec/changes/tenant-zaaksysteem-saas-03-schema-provisioning/tasks.md */ public function createSchema(string $name): void { $this->assertSafeIdentifier(name: $name); @@ -189,6 +193,8 @@ public function cloneApplicationTables(string $schemaName): array { * @return void * * @throws RuntimeException On DDL failure. + * + * @spec openspec/specs/tenant-provisioning/spec.md#requirement-schema-per-tenant-provisioning-req-001-b */ public function dropSchema(string $name): void { $this->assertSafeIdentifier(name: $name); @@ -235,6 +241,8 @@ public function schemaExists(string $name): bool { * @return void * * @throws InvalidArgumentException When invalid. + * + * @spec openspec/specs/tenant-provisioning/spec.md#requirement-schema-per-tenant-provisioning-req-001-b */ public function assertSafeIdentifier(string $name): void { if ($name === '' || strlen($name) > self::PG_IDENTIFIER_MAX_LENGTH) { diff --git a/lib/Service/TenantSeedService.php b/lib/Service/TenantSeedService.php index 4ef67a0ad..cc1b79816 100644 --- a/lib/Service/TenantSeedService.php +++ b/lib/Service/TenantSeedService.php @@ -36,6 +36,8 @@ /** * Seed standard templates (zaaktypen, mandaat-matrix, roles) into a tenant. + * + * @spec openspec/specs/tenant-schemas/spec.md#requirement-seed-tier-templates-and-default-tenant-onboarding-template-req-001-b-seed */ class TenantSeedService { /** diff --git a/lib/Service/TenantService.php b/lib/Service/TenantService.php index d810f66c6..1b7a3f3cd 100644 --- a/lib/Service/TenantService.php +++ b/lib/Service/TenantService.php @@ -48,6 +48,8 @@ * `Organisation.groups` array carries the NC group IDs used by dossiq for * tenant routing; `Organisation.status` carries the lifecycle state enforced * by `TenantMiddleware`. + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ class TenantService { /** @@ -234,6 +236,8 @@ public function getResourceUsage(string $tenantId): array { * @param string $userId The Nextcloud user ID. * * @return bool True when the user is in the NC admin group. + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ public function isPlatformAdmin(string $userId): bool { return $this->groupManager->isAdmin($userId); diff --git a/lib/Service/TenantSessionService.php b/lib/Service/TenantSessionService.php index 14f783a06..8f2f2f6fd 100644 --- a/lib/Service/TenantSessionService.php +++ b/lib/Service/TenantSessionService.php @@ -41,6 +41,8 @@ * * So the session decides, a switch is an explicit act, and membership is * verified at the moment of switching rather than trusted per request. + * + * @spec openspec/specs/multi-tenancy/spec.md#req-002-user-to-tenant-resolution-via-or-organisation-with-nc-group-fallback */ class TenantSessionService { /** diff --git a/lib/Service/TenantWelcomeMailer.php b/lib/Service/TenantWelcomeMailer.php index 698530afa..57ee8bb68 100644 --- a/lib/Service/TenantWelcomeMailer.php +++ b/lib/Service/TenantWelcomeMailer.php @@ -32,6 +32,8 @@ /** * Welcome-mail dispatch for newly provisioned tenants. + * + * @spec openspec/specs/tenant-onboarding/spec.md#requirement-onboarding-checklist-and-progress-dashboard-req-003-a-req-003-d */ class TenantWelcomeMailer { /** @@ -87,6 +89,8 @@ public function sendWelcomeEmail(array $tenant): bool { * @param array $tenant Tenant row. * * @return string|null + * + * @spec openspec/specs/tenant-onboarding/spec.md#requirement-onboarding-checklist-and-progress-dashboard-req-003-a-req-003-d */ public function resolveAdminEmail(array $tenant): ?string { $candidates = [ diff --git a/lib/Service/TermijnNotificationService.php b/lib/Service/TermijnNotificationService.php index 435ffe91f..81a9e59db 100644 --- a/lib/Service/TermijnNotificationService.php +++ b/lib/Service/TermijnNotificationService.php @@ -37,6 +37,8 @@ /** * Burger notification template renderer + dispatcher. + * + * @spec openspec/changes/termijnbewaking-dwangsom-engine-08-burger-notifications/tasks.md */ class TermijnNotificationService { public const TEMPLATES = [ diff --git a/lib/Service/TermijnTimerService.php b/lib/Service/TermijnTimerService.php index 99869dfd6..46efdeabd 100644 --- a/lib/Service/TermijnTimerService.php +++ b/lib/Service/TermijnTimerService.php @@ -41,6 +41,8 @@ /** * Arms, suspends, resumes, extends and cancels engine timers for AWB terms. + * + * @spec openspec/changes/termijnbewaking-op-engine-timers/tasks.md */ class TermijnTimerService { /** diff --git a/lib/Service/TranscriptionService.php b/lib/Service/TranscriptionService.php index dffb628b2..4cee53555 100644 --- a/lib/Service/TranscriptionService.php +++ b/lib/Service/TranscriptionService.php @@ -41,6 +41,8 @@ /** * Transcription orchestrator for voice-memo FieldEvidence records. + * + * @spec openspec/changes/mobiel-inspectie-offline/tasks.md#Task-9 */ class TranscriptionService { /** diff --git a/lib/Service/Transitions/ActionHandlerRegistry.php b/lib/Service/Transitions/ActionHandlerRegistry.php index 0cdf18441..126769486 100644 --- a/lib/Service/Transitions/ActionHandlerRegistry.php +++ b/lib/Service/Transitions/ActionHandlerRegistry.php @@ -96,6 +96,8 @@ public function registerHandler(string $type, ActionHandlerInterface $handler): * @param string $type Action type * * @return ActionHandlerInterface|null + * + * @spec openspec/specs/status-transition-engine/spec.md */ public function getHandler(string $type): ?ActionHandlerInterface { return ($this->handlers[$type] ?? null); @@ -105,6 +107,8 @@ public function getHandler(string $type): ?ActionHandlerInterface { * Get all registered action types. * * @return array + * + * @spec openspec/specs/status-transition-engine/spec.md */ public function getRegisteredTypes(): array { return array_keys($this->handlers); diff --git a/lib/Service/Transitions/GuardFailedException.php b/lib/Service/Transitions/GuardFailedException.php index 180e33476..06002783a 100644 --- a/lib/Service/Transitions/GuardFailedException.php +++ b/lib/Service/Transitions/GuardFailedException.php @@ -57,6 +57,8 @@ public function __construct(array $failedGuards, string $message = 'guard_failed * Get the failed guard snapshots. * * @return array> + * + * @spec openspec/changes/status-transition-engine/tasks.md#T10 */ public function getFailedGuards(): array { return $this->failedGuards; diff --git a/lib/Service/ZaakdossierService.php b/lib/Service/ZaakdossierService.php index 7a7dcf47c..066f34a8e 100644 --- a/lib/Service/ZaakdossierService.php +++ b/lib/Service/ZaakdossierService.php @@ -45,6 +45,8 @@ * The per-document status state machine is owned by * {@see InformatieobjectStatusLifecycle}; this service orchestrates the * dossier around it. + * + * @spec openspec/changes/document-zaakdossier/tasks.md#T02 */ class ZaakdossierService { use SearchesObjects; diff --git a/lib/Service/ZgwAuthValidationException.php b/lib/Service/ZgwAuthValidationException.php index 924c60adb..9b0d99c55 100644 --- a/lib/Service/ZgwAuthValidationException.php +++ b/lib/Service/ZgwAuthValidationException.php @@ -27,6 +27,8 @@ /** * Exception for ZGW JWT validation failures. + * + * @spec openspec/specs/zgw-autorisaties-api/spec.md */ class ZgwAuthValidationException extends \Exception { }//end class diff --git a/lib/Service/ZgwBrcRulesService.php b/lib/Service/ZgwBrcRulesService.php index 23136ad4d..c00f3d29b 100644 --- a/lib/Service/ZgwBrcRulesService.php +++ b/lib/Service/ZgwBrcRulesService.php @@ -73,6 +73,8 @@ * @psalm-suppress UnusedClass * * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ class ZgwBrcRulesService extends ZgwRulesBase { /** diff --git a/lib/Service/ZgwDrcRulesService.php b/lib/Service/ZgwDrcRulesService.php index 13e7607ea..e01809d22 100644 --- a/lib/Service/ZgwDrcRulesService.php +++ b/lib/Service/ZgwDrcRulesService.php @@ -70,6 +70,8 @@ * @psalm-suppress UnusedClass * * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ class ZgwDrcRulesService extends ZgwRulesBase { /** diff --git a/lib/Service/ZgwMappingService.php b/lib/Service/ZgwMappingService.php index 6cc41603a..ce2c71992 100644 --- a/lib/Service/ZgwMappingService.php +++ b/lib/Service/ZgwMappingService.php @@ -36,6 +36,8 @@ * `zgw_mapping_zaak`, `zgw_mapping_zaaktype`, etc. * * @SuppressWarnings(PHPMD.ExcessiveClassLength) + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ class ZgwMappingService { /** @@ -187,6 +189,8 @@ public function deleteMapping(string $resourceKey): void { * Get all known ZGW resource keys. * * @return string[] + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ public function getResourceKeys(): array { return self::RESOURCE_KEYS; @@ -198,6 +202,8 @@ public function getResourceKeys(): array { * @param string $resourceKey The ZGW resource key * * @return bool + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ public function hasMapping(string $resourceKey): bool { return $this->getMapping(resourceKey: $resourceKey) !== null; diff --git a/lib/Service/ZgwPaginationHelper.php b/lib/Service/ZgwPaginationHelper.php index a0edc4954..4af75509e 100644 --- a/lib/Service/ZgwPaginationHelper.php +++ b/lib/Service/ZgwPaginationHelper.php @@ -33,6 +33,8 @@ * @package OCA\Dossiq\Service * * @psalm-suppress UnusedClass + * + * @spec openspec/specs/zgw-api-mapping/spec.md */ class ZgwPaginationHelper { /** diff --git a/lib/Service/ZgwService.php b/lib/Service/ZgwService.php index 5890400b4..4a7048b4a 100644 --- a/lib/Service/ZgwService.php +++ b/lib/Service/ZgwService.php @@ -45,6 +45,8 @@ * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) * @SuppressWarnings(PHPMD.TooManyMethods) * @SuppressWarnings(PHPMD.TooManyPublicMethods) + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ class ZgwService { /** @@ -184,6 +186,8 @@ public function __construct( * Get the OpenRegister ObjectService. * * @return object|null + * + * @spec openspec/specs/zgw-api-mapping/spec.md */ public function getObjectService(): ?object { return $this->objectService; @@ -193,6 +197,8 @@ public function getObjectService(): ?object { * Get the OpenRegister ConsumerMapper. * * @return object|null + * + * @spec openspec/specs/zgw-api-mapping/spec.md */ public function getConsumerMapper(): ?object { return $this->consumerMapper; @@ -202,6 +208,8 @@ public function getConsumerMapper(): ?object { * Get the ZGW mapping service. * * @return ZgwMappingService + * + * @spec openspec/specs/zgw-api-mapping/spec.md */ public function getZgwMappingService(): ZgwMappingService { return $this->zgwMappingService; @@ -211,6 +219,8 @@ public function getZgwMappingService(): ZgwMappingService { * Get the pagination helper. * * @return ZgwPaginationHelper + * + * @spec openspec/specs/zgw-api-mapping/spec.md */ public function getPaginationHelper(): ZgwPaginationHelper { return $this->paginationHelper; @@ -220,6 +230,8 @@ public function getPaginationHelper(): ZgwPaginationHelper { * Get the document service. * * @return ZgwDocumentService + * + * @spec openspec/specs/zgw-api-mapping/spec.md */ public function getDocumentService(): ZgwDocumentService { return $this->documentService; @@ -229,6 +241,8 @@ public function getDocumentService(): ZgwDocumentService { * Get the business rules service. * * @return ZgwBusinessRulesService + * + * @spec openspec/specs/zgw-api-mapping/spec.md */ public function getBusinessRulesService(): ZgwBusinessRulesService { return $this->businessRulesService; @@ -238,6 +252,8 @@ public function getBusinessRulesService(): ZgwBusinessRulesService { * Get the logger. * * @return LoggerInterface + * + * @spec openspec/specs/zgw-api-mapping/spec.md */ public function getLogger(): LoggerInterface { return $this->logger; diff --git a/lib/Service/ZgwZrcRulesService.php b/lib/Service/ZgwZrcRulesService.php index 7bffa895d..4b70ab922 100644 --- a/lib/Service/ZgwZrcRulesService.php +++ b/lib/Service/ZgwZrcRulesService.php @@ -61,6 +61,8 @@ * * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) * @SuppressWarnings(PHPMD.ExcessiveClassLength) + * + * @spec openspec/specs/status-transition-engine/spec.md */ class ZgwZrcRulesService extends ZgwRulesBase { /** diff --git a/lib/Service/ZgwZtcRulesService.php b/lib/Service/ZgwZtcRulesService.php index b6c201322..997c0220e 100644 --- a/lib/Service/ZgwZtcRulesService.php +++ b/lib/Service/ZgwZtcRulesService.php @@ -61,6 +61,8 @@ * @psalm-suppress UnusedClass * * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) + * + * @spec openspec/changes/retrofit-2026-05-24-case-management/tasks.md */ class ZgwZtcRulesService extends ZgwRulesBase { /** diff --git a/lib/Service/ZipManifestBuilder.php b/lib/Service/ZipManifestBuilder.php index b6d47c30d..4def0e681 100644 --- a/lib/Service/ZipManifestBuilder.php +++ b/lib/Service/ZipManifestBuilder.php @@ -38,6 +38,8 @@ /** * Builds a manifest-bearing, type-foldered ZIP export of a dossier. + * + * @spec openspec/changes/document-zaakdossier/tasks.md#T04 */ class ZipManifestBuilder { /** diff --git a/lib/Settings/AdminSettings.php b/lib/Settings/AdminSettings.php index 94f6e80ab..35fb7c607 100644 --- a/lib/Settings/AdminSettings.php +++ b/lib/Settings/AdminSettings.php @@ -37,6 +37,8 @@ * Implements IDelegatedSettings so the form can be guarded by * #[AuthorizedAdminSetting(settings: AdminSettings::class)] on the * controllers that mutate Dossiq configuration. + * + * @spec openspec/specs/admin-settings/spec.md */ class AdminSettings implements IDelegatedSettings { /** @@ -64,6 +66,8 @@ public function __construct( * the same silent failure as procest#794's dead write routes. * * @return TemplateResponse + * + * @spec openspec/specs/admin-settings/spec.md */ public function getForm(): TemplateResponse { $version = $this->appManager->getAppVersion(appId: Application::APP_ID); @@ -142,6 +146,8 @@ private function mandateSettings(): array { * Get the section ID this settings page belongs to. * * @return string + * + * @spec openspec/specs/admin-settings/spec.md */ public function getSection(): string { return 'dossiq'; @@ -151,6 +157,8 @@ public function getSection(): string { * Get the priority for ordering within the section. * * @return int + * + * @spec openspec/specs/admin-settings/spec.md */ public function getPriority(): int { return 10; @@ -160,6 +168,8 @@ public function getPriority(): int { * Human-readable name of the delegated settings section. * * @return string|null The section name, or null to use the section default. + * + * @spec openspec/specs/admin-settings/spec.md */ public function getName(): ?string { return null; @@ -173,6 +183,8 @@ public function getName(): ?string { * the attribute still scopes the endpoint to full admins. * * @return array Map of appId to allowed config keys. + * + * @spec openspec/specs/admin-settings/spec.md */ public function getAuthorizedAppConfig(): array { return []; diff --git a/lib/Settings/EmailSettings.php b/lib/Settings/EmailSettings.php index 944ef8168..14e426b35 100644 --- a/lib/Settings/EmailSettings.php +++ b/lib/Settings/EmailSettings.php @@ -102,6 +102,8 @@ public function getForm(): TemplateResponse { * Get the section ID this settings page belongs to. * * @return string + * + * @spec openspec/specs/case-email-integration/spec.md */ public function getSection(): string { return 'dossiq'; @@ -114,6 +116,8 @@ public function getSection(): string { * this entry orders after it within the same section. * * @return int + * + * @spec openspec/specs/case-email-integration/spec.md */ public function getPriority(): int { return 60; @@ -123,6 +127,8 @@ public function getPriority(): int { * Human-readable name of the delegated settings entry. * * @return string|null + * + * @spec openspec/specs/case-email-integration/spec.md */ public function getName(): ?string { return 'Case email (shared mailbox)'; @@ -136,6 +142,8 @@ public function getName(): ?string { * flag and never surfaced as a readable delegated value. * * @return array Map of appId to allowed config keys. + * + * @spec openspec/specs/case-email-integration/spec.md */ public function getAuthorizedAppConfig(): array { return [Application::APP_ID => self::MANAGED_KEYS]; diff --git a/scripts/vue3-compile-sweep.cjs b/scripts/vue3-compile-sweep.cjs index e2249d26a..9c094c504 100644 --- a/scripts/vue3-compile-sweep.cjs +++ b/scripts/vue3-compile-sweep.cjs @@ -2,6 +2,7 @@ * Vue 3 compile-readiness sweep (ADR-066, openspec vue-3-migration). * * Compiles every SFC template + script under src/ with @vue/compiler-sfc in + * * @vue/compat MODE 2, and reports which components fail to COMPILE on Vue 3. * This is the fastest signal for the migration: compile failures are hard * blockers, and this needs no bundle/install of the runtime deps. @@ -31,9 +32,12 @@ const root = path.resolve(__dirname, '..', 'src') const compat = { compatConfig: { MODE: 2, COMPILER_FILTERS: true } } /** + * Collect every file path under a directory, recursively. + * + * @param {string} dir Directory to walk. + * @param {Array} out Accumulator the paths are appended to. * - * @param dir - * @param out + * @return {Array} The same accumulator, for convenience. */ function walk(dir, out = []) { for (const e of fs.readdirSync(dir, { withFileTypes: true })) { diff --git a/src/App.vue b/src/App.vue index b64544127..2f85677f4 100644 --- a/src/App.vue +++ b/src/App.vue @@ -175,9 +175,6 @@ export default { * * @param {string} key Translation key. * @return {string} Translated string (or the key on miss). - */ - /** - * @param key * @spec openspec/changes/retrofit-2026-05-25-procest-app-scaffold/tasks.md */ translateForApp(key) { diff --git a/src/components/besluitvorming/BesluitPublicatiePanel.vue b/src/components/besluitvorming/BesluitPublicatiePanel.vue index 831ad976d..063f498c9 100644 --- a/src/components/besluitvorming/BesluitPublicatiePanel.vue +++ b/src/components/besluitvorming/BesluitPublicatiePanel.vue @@ -68,6 +68,8 @@ export default { }, }, + emits: ['published'], + data() { return { state: this.initialState, diff --git a/src/components/initiator/InitiatorPicker.vue b/src/components/initiator/InitiatorPicker.vue index 494751152..9ac3697ed 100644 --- a/src/components/initiator/InitiatorPicker.vue +++ b/src/components/initiator/InitiatorPicker.vue @@ -107,6 +107,8 @@ export default { }, }, + emits: ['select'], + data() { return { activeTab: 'person', diff --git a/src/components/map/AddressSearch.vue b/src/components/map/AddressSearch.vue index 12f40ca66..b9c2ab920 100644 --- a/src/components/map/AddressSearch.vue +++ b/src/components/map/AddressSearch.vue @@ -66,7 +66,7 @@ export default { methods: { /** - * @param value + * @param {string|number|boolean|object} value The new value. * @spec openspec/changes/retrofit-2026-05-25-map-component/tasks.md */ async onInput(value) { @@ -99,7 +99,7 @@ export default { }, /** - * @param result + * @param {object} result The result. * @spec openspec/changes/retrofit-2026-05-25-map-component/tasks.md */ async selectResult(result) { @@ -136,7 +136,7 @@ export default { }, /** - * @param type + * @param {string} type The type. * @spec openspec/changes/retrofit-2026-05-25-map-component/tasks.md */ getTypeIcon(type) { diff --git a/src/components/map/LocationPicker.vue b/src/components/map/LocationPicker.vue index 257c18197..b4fcadff7 100644 --- a/src/components/map/LocationPicker.vue +++ b/src/components/map/LocationPicker.vue @@ -168,7 +168,7 @@ export default { }, /** - * @param mode + * @param {string} mode The drawing mode the picker is in. * @spec openspec/changes/retrofit-2026-05-25-map-component/tasks.md */ setMode(mode) { @@ -220,7 +220,7 @@ export default { }, /** - * @param latlng + * @param {object} latlng The latlng. * @spec openspec/changes/retrofit-2026-05-25-map-component/tasks.md */ placeMarker(latlng) { @@ -236,8 +236,8 @@ export default { }, /** - * @param root0 - * @param root0.coordinates + * @param {object} root0 The destructured argument object. + * @param {Array} root0.coordinates The [lon, lat] pair the picker selected. * @spec openspec/changes/retrofit-2026-05-25-map-component/tasks.md */ onAddressSelect({ coordinates }) { @@ -277,7 +277,7 @@ export default { }, /** - * @param sqm + * @param {number} sqm The sqm. * @spec openspec/changes/retrofit-2026-05-25-map-component/tasks.md */ formatArea(sqm) { diff --git a/src/dialogs/AiClassifyDialog.vue b/src/dialogs/AiClassifyDialog.vue index 0e9e122b1..4f4d4d452 100644 --- a/src/dialogs/AiClassifyDialog.vue +++ b/src/dialogs/AiClassifyDialog.vue @@ -101,7 +101,7 @@ export default { watch: { /** - * @param val + * @param {string|number|boolean|object} val The new value. * @spec openspec/changes/retrofit-2026-05-24-ai-assistance/tasks.md */ show(val) { diff --git a/src/dialogs/AiExtractDialog.vue b/src/dialogs/AiExtractDialog.vue index 641051f58..00a69a878 100644 --- a/src/dialogs/AiExtractDialog.vue +++ b/src/dialogs/AiExtractDialog.vue @@ -149,7 +149,7 @@ export default { watch: { /** - * @param val + * @param {string|number|boolean|object} val The new value. * @spec openspec/changes/retrofit-2026-05-24-ai-assistance/tasks.md */ show(val) { @@ -179,7 +179,7 @@ export default { }, /** - * @param checked + * @param {boolean} checked Whether the checked is set. * @spec openspec/changes/retrofit-2026-05-24-ai-assistance/tasks.md */ toggleAll(checked) { @@ -187,7 +187,7 @@ export default { }, /** - * @param name + * @param {string} name The name. * @spec openspec/changes/retrofit-2026-05-24-ai-assistance/tasks.md */ toggleField(name) { diff --git a/src/dialogs/ConsultationCreateDialog.vue b/src/dialogs/ConsultationCreateDialog.vue index c79905911..80dabc229 100644 --- a/src/dialogs/ConsultationCreateDialog.vue +++ b/src/dialogs/ConsultationCreateDialog.vue @@ -180,7 +180,7 @@ export default { watch: { /** - * @param value + * @param {string|number|boolean|object} value The new value. * @spec openspec/changes/consultation-management/tasks.md#TASK-CN-05 */ open(value) { diff --git a/src/dialogs/ConsultationResponseForm.vue b/src/dialogs/ConsultationResponseForm.vue index 37387f0b3..1c5d3aa1b 100644 --- a/src/dialogs/ConsultationResponseForm.vue +++ b/src/dialogs/ConsultationResponseForm.vue @@ -216,7 +216,7 @@ export default { watch: { /** - * @param value + * @param {string|number|boolean|object} value The new value. * @spec openspec/changes/consultation-management/tasks.md#TASK-CN-05 */ open(value) { @@ -240,7 +240,7 @@ export default { }, /** - * @param idx + * @param {number} idx The index. * @spec openspec/changes/consultation-management/tasks.md#TASK-CN-05 */ removeVoorwaarde(idx) { diff --git a/src/dialogs/EndAssignmentDialog.vue b/src/dialogs/EndAssignmentDialog.vue index f5c98ebb2..ddb874a36 100644 --- a/src/dialogs/EndAssignmentDialog.vue +++ b/src/dialogs/EndAssignmentDialog.vue @@ -55,6 +55,10 @@ export default { name: 'EndAssignmentDialog', components: { NcButton, NcDialog }, props: { + // MandaatToewijzingenTable passes `:assignment="ending"`. The dialog acts + // on it through its own emit rather than rendering it, and the declaration + // is what keeps it a prop instead of a fallthrough attribute. + // eslint-disable-next-line vue/no-unused-properties assignment: { type: Object, required: true }, }, diff --git a/src/dialogs/RedactionAssistDialog.vue b/src/dialogs/RedactionAssistDialog.vue index 9b6e1af44..4b89bf551 100644 --- a/src/dialogs/RedactionAssistDialog.vue +++ b/src/dialogs/RedactionAssistDialog.vue @@ -186,8 +186,12 @@ export default { }, props: { + // Defaults to true deliberately: nothing passes this, and the dialog is + // mounted to be shown. Flipping the default to satisfy the rule would + // change behaviour, not style, and the dialog would mount closed. open: { type: Boolean, + // eslint-disable-next-line vue/no-boolean-default default: true, }, diff --git a/src/dialogs/StufEnvelopeDialog.vue b/src/dialogs/StufEnvelopeDialog.vue index f5b259582..249f0621e 100644 --- a/src/dialogs/StufEnvelopeDialog.vue +++ b/src/dialogs/StufEnvelopeDialog.vue @@ -77,7 +77,7 @@ export default { /** * Pretty-print a value as indented JSON for display. * - * @param {*} value The value to render. + * @param {unknown} value The value to render. * @spec exclude presentational JSON formatter — no business logic */ pretty(value) { diff --git a/src/dialogs/ZgwMappingDialog.vue b/src/dialogs/ZgwMappingDialog.vue index 4d3c2a77d..5eec3254e 100644 --- a/src/dialogs/ZgwMappingDialog.vue +++ b/src/dialogs/ZgwMappingDialog.vue @@ -145,7 +145,7 @@ export default { open: { immediate: true, /** - * @param value + * @param {string|number|boolean|object} value The new value. * @spec openspec/changes/retrofit-2026-05-24-zgw-api-mapping/tasks.md */ handler(value) { diff --git a/src/modals/BulkReassignModal.vue b/src/modals/BulkReassignModal.vue index 82cc23545..5b6209288 100644 --- a/src/modals/BulkReassignModal.vue +++ b/src/modals/BulkReassignModal.vue @@ -302,7 +302,7 @@ export default { }, /** - * @param open + * @param {boolean} open Whether the open is set. * @spec openspec/specs/handler-vervanging-waarneming/spec.md */ onDialogClose(open) { diff --git a/src/modals/DeelzaakCreateModal.vue b/src/modals/DeelzaakCreateModal.vue index a4879ce95..ee2791efe 100644 --- a/src/modals/DeelzaakCreateModal.vue +++ b/src/modals/DeelzaakCreateModal.vue @@ -121,12 +121,12 @@