From 80233a7f77d92c2d328225a81a166462616776ee Mon Sep 17 00:00:00 2001 From: Specter Intelligence Date: Thu, 16 Apr 2026 10:35:25 +0200 Subject: [PATCH 1/2] feat: Add OpenSpec change workflow-import-export from Specter --- .../architecture/adr-001-data-layer.md | 221 +++++++ .claude/openspec/architecture/adr-002-api.md | 6 + .../openspec/architecture/adr-003-backend.md | 14 + .../openspec/architecture/adr-004-frontend.md | 129 ++++ .../openspec/architecture/adr-005-security.md | 9 + .../openspec/architecture/adr-006-metrics.md | 3 + .claude/openspec/architecture/adr-007-i18n.md | 40 ++ .../openspec/architecture/adr-008-testing.md | 24 + .claude/openspec/architecture/adr-009-docs.md | 2 + .../architecture/adr-010-nl-design.md | 8 + .../architecture/adr-011-schema-standards.md | 8 + .../architecture/adr-012-deduplication.md | 7 + .../architecture/adr-013-container-pool.md | 133 ++++ .../architecture/adr-014-licensing.md | 7 + .../architecture/adr-015-common-patterns.md | 98 +++ .../adr-017-component-composition.md | 86 +++ .../adr-018-widget-header-actions.md | 105 +++ .claude/skills/clean-env/SKILL.md | 48 ++ .claude/skills/clean-env/evals/evals.json | 1 + .claude/skills/create-pr/SKILL.md | 446 +++++++++++++ .claude/skills/create-pr/evals/evals.json | 1 + .claude/skills/create-pr/learnings.md | 11 + .../references/branch-protection-guide.md | 95 +++ .../references/check-tool-verification.md | 71 ++ .../ci-step-categorisation-guide.md | 128 ++++ .claude/skills/feature-counsel/SKILL.md | 288 ++++++++ .../skills/feature-counsel/evals/evals.json | 1 + .claude/skills/feature-counsel/learnings.md | 16 + .claude/skills/openspec-apply-change/SKILL.md | 156 +++++ .../skills/openspec-archive-change/SKILL.md | 114 ++++ .claude/skills/openspec-explore/SKILL.md | 288 ++++++++ .claude/skills/openspec-propose/SKILL.md | 110 ++++ .claude/skills/opsx-apply-loop/SKILL.md | 470 +++++++++++++ .../assets/apply-loop-check.sh | 88 +++ .../assets/apply-loop.Dockerfile | 38 ++ .../skills/opsx-apply-loop/evals/evals.json | 1 + .claude/skills/opsx-apply-loop/learnings.md | 11 + .../references/apply-verify-loop-protocol.md | 139 ++++ .../references/container-auth-check.md | 41 ++ .../references/container-limitations.md | 39 ++ .../references/container-setup-guide.md | 287 ++++++++ .../references/host-test-loop-protocol.md | 122 ++++ .claude/skills/opsx-apply/SKILL.md | 329 ++++++++++ .claude/skills/opsx-apply/evals/evals.json | 1 + .claude/skills/opsx-apply/learnings.md | 16 + .claude/skills/opsx-archive/SKILL.md | 332 ++++++++++ .claude/skills/opsx-archive/evals/evals.json | 1 + .../opsx-archive/examples/output-templates.md | 70 ++ .claude/skills/opsx-archive/learnings.md | 11 + .../templates/test-scenario-template.md | 45 ++ .claude/skills/opsx-bulk-archive/SKILL.md | 300 +++++++++ .../skills/opsx-bulk-archive/evals/evals.json | 1 + .claude/skills/opsx-continue/SKILL.md | 152 +++++ .claude/skills/opsx-continue/evals/evals.json | 1 + .claude/skills/opsx-explore/SKILL.md | 221 +++++++ .claude/skills/opsx-ff/SKILL.md | 183 ++++++ .claude/skills/opsx-ff/evals/evals.json | 1 + .claude/skills/opsx-ff/learnings.md | 16 + .claude/skills/opsx-new/SKILL.md | 95 +++ .claude/skills/opsx-onboard/SKILL.md | 430 ++++++++++++ .claude/skills/opsx-onboard/evals/evals.json | 1 + .../opsx-onboard/examples/design-template.md | 29 + .../examples/proposal-template.md | 32 + .../opsx-onboard/examples/specs-template.md | 23 + .../opsx-onboard/examples/tasks-template.md | 20 + .claude/skills/opsx-pipeline/SKILL.md | 486 ++++++++++++++ .claude/skills/opsx-pipeline/evals/evals.json | 1 + .claude/skills/opsx-pipeline/learnings.md | 16 + .claude/skills/opsx-plan-to-issues/SKILL.md | 224 +++++++ .../opsx-plan-to-issues/evals/evals.json | 1 + .../skills/opsx-plan-to-issues/learnings.md | 11 + .claude/skills/opsx-sync/SKILL.md | 139 ++++ .claude/skills/opsx-sync/evals/evals.json | 1 + .claude/skills/opsx-verify/SKILL.md | 375 +++++++++++ .claude/skills/opsx-verify/evals/evals.json | 1 + .claude/skills/opsx-verify/learnings.md | 16 + .claude/skills/skill-level-overview.html | 620 ++++++++++++++++++ .claude/skills/sync-docs/SKILL.md | 473 +++++++++++++ .claude/skills/sync-docs/evals/evals.json | 1 + .claude/skills/sync-docs/learnings.md | 11 + .../sync-docs/references/preflight-checks.md | 65 ++ .claude/skills/team-architect/SKILL.md | 325 +++++++++ .../skills/team-architect/evals/evals.json | 1 + .claude/skills/team-architect/learnings.md | 11 + .../references/bio2-security-checklist.md | 70 ++ .../dutch-gov-architecture-standards.md | 153 +++++ .../references/nlgov-api-design-rules.md | 88 +++ .claude/skills/team-backend/SKILL.md | 345 ++++++++++ .claude/skills/team-backend/evals/evals.json | 1 + .claude/skills/team-backend/learnings.md | 11 + .../references/dutch-gov-backend-standards.md | 102 +++ .claude/skills/team-frontend/SKILL.md | 436 ++++++++++++ .claude/skills/team-frontend/evals/evals.json | 1 + .claude/skills/team-frontend/learnings.md | 11 + .../dutch-gov-frontend-standards.md | 132 ++++ .../references/nextcloud-layout-patterns.md | 84 +++ .claude/skills/team-po/SKILL.md | 168 +++++ .claude/skills/team-po/evals/evals.json | 1 + .claude/skills/team-qa/SKILL.md | 219 +++++++ .claude/skills/team-qa/evals/evals.json | 1 + .claude/skills/team-qa/learnings.md | 11 + .../references/dutch-gov-compliance.md | 120 ++++ .../team-qa/templates/qa-report-template.md | 58 ++ .claude/skills/team-reviewer/SKILL.md | 296 +++++++++ .claude/skills/team-reviewer/evals/evals.json | 1 + .claude/skills/team-sm/SKILL.md | 224 +++++++ .claude/skills/team-sm/evals/evals.json | 1 + .claude/skills/test-accessibility/SKILL.md | 229 +++++++ .../test-accessibility/evals/evals.json | 1 + .claude/skills/test-api/SKILL.md | 272 ++++++++ .claude/skills/test-api/evals/evals.json | 1 + .claude/skills/test-app/SKILL.md | 213 ++++++ .claude/skills/test-app/evals/evals.json | 1 + .claude/skills/test-app/learnings.md | 16 + .../templates/agent-prompt-template.md | 159 +++++ .../templates/perspective-instructions.md | 104 +++ .../templates/summary-report-template.md | 74 +++ .claude/skills/test-counsel/SKILL.md | 469 +++++++++++++ .claude/skills/test-counsel/evals/evals.json | 1 + .claude/skills/test-counsel/learnings.md | 16 + .claude/skills/test-functional/SKILL.md | 176 +++++ .../skills/test-functional/evals/evals.json | 1 + .claude/skills/test-functional/learnings.md | 16 + .claude/skills/test-performance/SKILL.md | 227 +++++++ .../skills/test-performance/evals/evals.json | 1 + .../skills/test-persona-annemarie/SKILL.md | 214 ++++++ .../test-persona-annemarie/evals/evals.json | 1 + .claude/skills/test-persona-fatima/SKILL.md | 165 +++++ .../test-persona-fatima/evals/evals.json | 1 + .claude/skills/test-persona-henk/SKILL.md | 172 +++++ .../skills/test-persona-henk/evals/evals.json | 1 + .../skills/test-persona-janwillem/SKILL.md | 176 +++++ .../test-persona-janwillem/evals/evals.json | 1 + .claude/skills/test-persona-mark/SKILL.md | 175 +++++ .../skills/test-persona-mark/evals/evals.json | 1 + .claude/skills/test-persona-noor/SKILL.md | 194 ++++++ .../skills/test-persona-noor/evals/evals.json | 1 + .claude/skills/test-persona-priya/SKILL.md | 202 ++++++ .../test-persona-priya/evals/evals.json | 1 + .claude/skills/test-persona-sem/SKILL.md | 175 +++++ .../skills/test-persona-sem/evals/evals.json | 1 + .claude/skills/test-regression/SKILL.md | 224 +++++++ .../skills/test-regression/evals/evals.json | 1 + .claude/skills/test-scenario-create/SKILL.md | 323 +++++++++ .../test-scenario-create/evals/evals.json | 1 + .claude/skills/test-scenario-edit/SKILL.md | 229 +++++++ .../test-scenario-edit/evals/evals.json | 1 + .claude/skills/test-scenario-run/SKILL.md | 252 +++++++ .../skills/test-scenario-run/evals/evals.json | 1 + .claude/skills/test-security/SKILL.md | 271 ++++++++ .claude/skills/test-security/evals/evals.json | 1 + .claude/skills/update-skill-overview.sh | 314 +++++++++ .../verify-global-settings-version/SKILL.md | 121 ++++ .../evals/evals.json | 1 + .specter-prompt.txt | 49 ++ .../workflow-import-export/.openspec.yaml | 2 + .../workflow-import-export/context-brief.md | 47 ++ 157 files changed, 16828 insertions(+) create mode 100644 .claude/openspec/architecture/adr-001-data-layer.md create mode 100644 .claude/openspec/architecture/adr-002-api.md create mode 100644 .claude/openspec/architecture/adr-003-backend.md create mode 100644 .claude/openspec/architecture/adr-004-frontend.md create mode 100644 .claude/openspec/architecture/adr-005-security.md create mode 100644 .claude/openspec/architecture/adr-006-metrics.md create mode 100644 .claude/openspec/architecture/adr-007-i18n.md create mode 100644 .claude/openspec/architecture/adr-008-testing.md create mode 100644 .claude/openspec/architecture/adr-009-docs.md create mode 100644 .claude/openspec/architecture/adr-010-nl-design.md create mode 100644 .claude/openspec/architecture/adr-011-schema-standards.md create mode 100644 .claude/openspec/architecture/adr-012-deduplication.md create mode 100644 .claude/openspec/architecture/adr-013-container-pool.md create mode 100644 .claude/openspec/architecture/adr-014-licensing.md create mode 100644 .claude/openspec/architecture/adr-015-common-patterns.md create mode 100644 .claude/openspec/architecture/adr-017-component-composition.md create mode 100644 .claude/openspec/architecture/adr-018-widget-header-actions.md create mode 100644 .claude/skills/clean-env/SKILL.md create mode 100644 .claude/skills/clean-env/evals/evals.json create mode 100644 .claude/skills/create-pr/SKILL.md create mode 100644 .claude/skills/create-pr/evals/evals.json create mode 100644 .claude/skills/create-pr/learnings.md create mode 100644 .claude/skills/create-pr/references/branch-protection-guide.md create mode 100644 .claude/skills/create-pr/references/check-tool-verification.md create mode 100644 .claude/skills/create-pr/references/ci-step-categorisation-guide.md create mode 100644 .claude/skills/feature-counsel/SKILL.md create mode 100644 .claude/skills/feature-counsel/evals/evals.json create mode 100644 .claude/skills/feature-counsel/learnings.md create mode 100644 .claude/skills/openspec-apply-change/SKILL.md create mode 100644 .claude/skills/openspec-archive-change/SKILL.md create mode 100644 .claude/skills/openspec-explore/SKILL.md create mode 100644 .claude/skills/openspec-propose/SKILL.md create mode 100644 .claude/skills/opsx-apply-loop/SKILL.md create mode 100644 .claude/skills/opsx-apply-loop/assets/apply-loop-check.sh create mode 100644 .claude/skills/opsx-apply-loop/assets/apply-loop.Dockerfile create mode 100644 .claude/skills/opsx-apply-loop/evals/evals.json create mode 100644 .claude/skills/opsx-apply-loop/learnings.md create mode 100644 .claude/skills/opsx-apply-loop/references/apply-verify-loop-protocol.md create mode 100644 .claude/skills/opsx-apply-loop/references/container-auth-check.md create mode 100644 .claude/skills/opsx-apply-loop/references/container-limitations.md create mode 100644 .claude/skills/opsx-apply-loop/references/container-setup-guide.md create mode 100644 .claude/skills/opsx-apply-loop/references/host-test-loop-protocol.md create mode 100644 .claude/skills/opsx-apply/SKILL.md create mode 100644 .claude/skills/opsx-apply/evals/evals.json create mode 100644 .claude/skills/opsx-apply/learnings.md create mode 100644 .claude/skills/opsx-archive/SKILL.md create mode 100644 .claude/skills/opsx-archive/evals/evals.json create mode 100644 .claude/skills/opsx-archive/examples/output-templates.md create mode 100644 .claude/skills/opsx-archive/learnings.md create mode 100644 .claude/skills/opsx-archive/templates/test-scenario-template.md create mode 100644 .claude/skills/opsx-bulk-archive/SKILL.md create mode 100644 .claude/skills/opsx-bulk-archive/evals/evals.json create mode 100644 .claude/skills/opsx-continue/SKILL.md create mode 100644 .claude/skills/opsx-continue/evals/evals.json create mode 100644 .claude/skills/opsx-explore/SKILL.md create mode 100644 .claude/skills/opsx-ff/SKILL.md create mode 100644 .claude/skills/opsx-ff/evals/evals.json create mode 100644 .claude/skills/opsx-ff/learnings.md create mode 100644 .claude/skills/opsx-new/SKILL.md create mode 100644 .claude/skills/opsx-onboard/SKILL.md create mode 100644 .claude/skills/opsx-onboard/evals/evals.json create mode 100644 .claude/skills/opsx-onboard/examples/design-template.md create mode 100644 .claude/skills/opsx-onboard/examples/proposal-template.md create mode 100644 .claude/skills/opsx-onboard/examples/specs-template.md create mode 100644 .claude/skills/opsx-onboard/examples/tasks-template.md create mode 100644 .claude/skills/opsx-pipeline/SKILL.md create mode 100644 .claude/skills/opsx-pipeline/evals/evals.json create mode 100644 .claude/skills/opsx-pipeline/learnings.md create mode 100644 .claude/skills/opsx-plan-to-issues/SKILL.md create mode 100644 .claude/skills/opsx-plan-to-issues/evals/evals.json create mode 100644 .claude/skills/opsx-plan-to-issues/learnings.md create mode 100644 .claude/skills/opsx-sync/SKILL.md create mode 100644 .claude/skills/opsx-sync/evals/evals.json create mode 100644 .claude/skills/opsx-verify/SKILL.md create mode 100644 .claude/skills/opsx-verify/evals/evals.json create mode 100644 .claude/skills/opsx-verify/learnings.md create mode 100644 .claude/skills/skill-level-overview.html create mode 100644 .claude/skills/sync-docs/SKILL.md create mode 100644 .claude/skills/sync-docs/evals/evals.json create mode 100644 .claude/skills/sync-docs/learnings.md create mode 100644 .claude/skills/sync-docs/references/preflight-checks.md create mode 100644 .claude/skills/team-architect/SKILL.md create mode 100644 .claude/skills/team-architect/evals/evals.json create mode 100644 .claude/skills/team-architect/learnings.md create mode 100644 .claude/skills/team-architect/references/bio2-security-checklist.md create mode 100644 .claude/skills/team-architect/references/dutch-gov-architecture-standards.md create mode 100644 .claude/skills/team-architect/references/nlgov-api-design-rules.md create mode 100644 .claude/skills/team-backend/SKILL.md create mode 100644 .claude/skills/team-backend/evals/evals.json create mode 100644 .claude/skills/team-backend/learnings.md create mode 100644 .claude/skills/team-backend/references/dutch-gov-backend-standards.md create mode 100644 .claude/skills/team-frontend/SKILL.md create mode 100644 .claude/skills/team-frontend/evals/evals.json create mode 100644 .claude/skills/team-frontend/learnings.md create mode 100644 .claude/skills/team-frontend/references/dutch-gov-frontend-standards.md create mode 100644 .claude/skills/team-frontend/references/nextcloud-layout-patterns.md create mode 100644 .claude/skills/team-po/SKILL.md create mode 100644 .claude/skills/team-po/evals/evals.json create mode 100644 .claude/skills/team-qa/SKILL.md create mode 100644 .claude/skills/team-qa/evals/evals.json create mode 100644 .claude/skills/team-qa/learnings.md create mode 100644 .claude/skills/team-qa/references/dutch-gov-compliance.md create mode 100644 .claude/skills/team-qa/templates/qa-report-template.md create mode 100644 .claude/skills/team-reviewer/SKILL.md create mode 100644 .claude/skills/team-reviewer/evals/evals.json create mode 100644 .claude/skills/team-sm/SKILL.md create mode 100644 .claude/skills/team-sm/evals/evals.json create mode 100644 .claude/skills/test-accessibility/SKILL.md create mode 100644 .claude/skills/test-accessibility/evals/evals.json create mode 100644 .claude/skills/test-api/SKILL.md create mode 100644 .claude/skills/test-api/evals/evals.json create mode 100644 .claude/skills/test-app/SKILL.md create mode 100644 .claude/skills/test-app/evals/evals.json create mode 100644 .claude/skills/test-app/learnings.md create mode 100644 .claude/skills/test-app/templates/agent-prompt-template.md create mode 100644 .claude/skills/test-app/templates/perspective-instructions.md create mode 100644 .claude/skills/test-app/templates/summary-report-template.md create mode 100644 .claude/skills/test-counsel/SKILL.md create mode 100644 .claude/skills/test-counsel/evals/evals.json create mode 100644 .claude/skills/test-counsel/learnings.md create mode 100644 .claude/skills/test-functional/SKILL.md create mode 100644 .claude/skills/test-functional/evals/evals.json create mode 100644 .claude/skills/test-functional/learnings.md create mode 100644 .claude/skills/test-performance/SKILL.md create mode 100644 .claude/skills/test-performance/evals/evals.json create mode 100644 .claude/skills/test-persona-annemarie/SKILL.md create mode 100644 .claude/skills/test-persona-annemarie/evals/evals.json create mode 100644 .claude/skills/test-persona-fatima/SKILL.md create mode 100644 .claude/skills/test-persona-fatima/evals/evals.json create mode 100644 .claude/skills/test-persona-henk/SKILL.md create mode 100644 .claude/skills/test-persona-henk/evals/evals.json create mode 100644 .claude/skills/test-persona-janwillem/SKILL.md create mode 100644 .claude/skills/test-persona-janwillem/evals/evals.json create mode 100644 .claude/skills/test-persona-mark/SKILL.md create mode 100644 .claude/skills/test-persona-mark/evals/evals.json create mode 100644 .claude/skills/test-persona-noor/SKILL.md create mode 100644 .claude/skills/test-persona-noor/evals/evals.json create mode 100644 .claude/skills/test-persona-priya/SKILL.md create mode 100644 .claude/skills/test-persona-priya/evals/evals.json create mode 100644 .claude/skills/test-persona-sem/SKILL.md create mode 100644 .claude/skills/test-persona-sem/evals/evals.json create mode 100644 .claude/skills/test-regression/SKILL.md create mode 100644 .claude/skills/test-regression/evals/evals.json create mode 100644 .claude/skills/test-scenario-create/SKILL.md create mode 100644 .claude/skills/test-scenario-create/evals/evals.json create mode 100644 .claude/skills/test-scenario-edit/SKILL.md create mode 100644 .claude/skills/test-scenario-edit/evals/evals.json create mode 100644 .claude/skills/test-scenario-run/SKILL.md create mode 100644 .claude/skills/test-scenario-run/evals/evals.json create mode 100644 .claude/skills/test-security/SKILL.md create mode 100644 .claude/skills/test-security/evals/evals.json create mode 100644 .claude/skills/update-skill-overview.sh create mode 100644 .claude/skills/verify-global-settings-version/SKILL.md create mode 100644 .claude/skills/verify-global-settings-version/evals/evals.json create mode 100644 .specter-prompt.txt create mode 100644 openspec/changes/workflow-import-export/.openspec.yaml create mode 100644 openspec/changes/workflow-import-export/context-brief.md diff --git a/.claude/openspec/architecture/adr-001-data-layer.md b/.claude/openspec/architecture/adr-001-data-layer.md new file mode 100644 index 00000000..6b52c806 --- /dev/null +++ b/.claude/openspec/architecture/adr-001-data-layer.md @@ -0,0 +1,221 @@ +- ALL domain data → OpenRegister objects. NO custom Entity/Mapper for domain data. +- App config → `IAppConfig`. NOT OpenRegister. +- Cross-entity references: OpenRegister relations (register+schema+objectId). NO foreign keys. + MUST NOT store foreign keys or embed full objects. + +### Schema standards + +- Schemas: PascalCase, schema.org vocabulary, explicit types + required flags + description field. +- MUST NOT invent custom property names when a schema.org equivalent exists. +- Contact schemas MUST align with vCard properties (fn, email, tel, adr). +- Dutch government fields SHOULD use a mapping layer translating between international standards + and Dutch specs — do not hardcode Dutch field names as primary. +- Schema changes that remove or rename properties are BREAKING. Adding optional properties is non-breaking. + +### Register templates + +- Location: `lib/Settings/{app}_register.json` (OpenAPI 3.0 + `x-openregister` extensions). +- Three template categories: + - **App configuration** — define data models (schemas/registers/views/mappings). + Mark with `x-openregister.type: "application"`. + - **Mock data** — fictional but realistic seed data for dev/test. + Mark with `x-openregister.type: "mock"`. + - **Government standards** — aligned to Dutch API specs (BAG, BRP, KVK, DSO). +- Import mechanism: `ConfigurationService::importFromApp(appId, data, version, force)` → + `ImportHandler::importFromApp()`. Called from repair step or `SettingsLoadService`. +- Idempotency: re-importing with `force: false` MUST NOT create duplicates. Match by slug + using `ObjectService::searchObjects` with `_rbac: false` and `_multitenancy: false`. + Use `version_compare` for skip logic. + +### Seed data + +Apps that store data in OpenRegister are empty on first install. An empty app cannot be +meaningfully tested — there are no objects to view, search, filter, or interact with. +This blocks both automated browser testing and manual QA. The Loadable Register Template +pattern (see Register templates above) already supports seed data via `components.objects[]` +with the `@self` envelope. + +**Requirements:** + +- Every app using OpenRegister MUST include 3-5 realistic objects per schema in + `lib/Settings/{app}_register.json`. +- Use `@self` envelope: `{ "@self": { "register": ..., "schema": ..., "slug": ... }, ...properties }`. + Register/schema MUST match keys; slug is unique human-readable identifier for matching. +- Use general organisation data (municipality, consultancy, travel agency, non-profit) — + NOT context-specific. Varied, realistic field values. +- Mock data quality: real Dutch street names, valid postcodes (`[1-9][0-9]{3}[A-Z]{2}`), + correct municipality/KVK codes, BSNs that pass 11-proef. Fictional but distinguishable from real. +- Cross-register consistency: BRP→BAG, KVK→BAG, DSO→BAG references must be valid. +- Loaded on install alongside schemas via same `importFromApp()` pipeline. +- MUST be idempotent — re-importing skips existing objects matched by slug. + +**In OpenSpec artifacts:** + +- **In design.md**: MUST include a Seed Data section when change introduces/modifies schemas — + define seed objects per schema with concrete field values and related items (files, notes, tasks, contacts). +- **In tasks.md**: MUST include a seed data generation task when change introduces/modifies schemas. + +**Exceptions** (no seed data required): + +- **nldesign** — has no OpenRegister schemas. +- **ExApp sidecar wrappers** (openklant, opentalk, openzaak, valtimo, n8n-nextcloud) — proxy + external services and do not use OpenRegister. +- **nextcloud-vue** — shared library, no seed data applicable. +- Changes that only modify frontend components or non-schema backend logic (e.g., settings, + permissions) do not require seed data. + +**Limitations:** OpenRegister's `ImportHandler` currently supports only flat seed objects. +Related items (files, notes, tasks, contacts) linked through the relation system are tracked +on the product roadmap. Until then, seed data is limited to object properties defined in schemas. + +### Deduplication check + +- Before proposing new capability: search `openspec/specs/` and `openregister/lib/Service/` for overlap + with ObjectService, RegisterService, SchemaService, ConfigurationService, and shared Vue components. +- If similar capability exists: MUST reference it and explain why new code is needed rather than extending. +- Proposals duplicating existing functionality without justification MUST be rejected. +- **In design.md**: MUST include a "Reuse Analysis" section listing existing OpenRegister services leveraged. +- **In tasks.md**: MUST include a "Deduplication Check" task verifying no overlap — document findings + even if "no overlap found". + +### Schema migrations + +- Breaking schema changes → new migration in repair step. NEVER modify existing migrations. + +### OpenRegister + @conduction/nextcloud-vue — DO NOT REBUILD + +The platform provides 258+ backend methods and 69+ frontend components. Apps ONLY build +custom logic for domain-specific business rules. Everything below is provided for FREE. + +**CRUD & Data Management** (use ObjectService + CnIndexPage + CnDetailPage): +- Single & bulk create, read, update, delete — `ObjectService.saveObject()`, `deleteObject()` +- List with pagination, sorting, filtering — `ObjectService.findAll()` + `CnDataTable` +- Schema-driven forms — `CnFormDialog` (auto-generates from schema) or `CnAdvancedFormDialog` +- Detail views — `CnDetailPage` with `CnDetailGrid`, `CnDetailCard` sections +- Record merging/deduplication — `ObjectService.mergeObjects()` +- Object locking — `ObjectService.lockObject()` / `unlockObject()` + +**Import & Export** (use ImportService/ExportService + CnMassImportDialog/CnMassExportDialog): +- CSV, Excel, JSON import with intelligent field mapping — `ImportService` +- CSV, Excel, JSON export with column selection — `ExportService` +- Bulk import with validation and progress — `CnMassImportDialog` +- Filtered export with format picker — `CnMassExportDialog` +- NO custom import dialogs, parsers, upload handlers, or export controllers + +**Search & Discovery** (use IndexService + CnFilterBar + CnFacetSidebar): +- Full-text search with field weighting — `IndexService` +- Faceted navigation with counts — `FacetBuilder` + `CnFacetSidebar` +- Semantic search with embeddings — `VectorizationService` +- Hybrid search (keyword + semantic) — automatic +- Search analytics — `SearchTrailService` (popular terms, activity) +- NO custom search endpoints, query builders, or search pages + +**File Management** (use FileService + CnObjectSidebar): +- Upload (single/multipart), download, share links — `FileService` +- File tagging, public/private toggle — `FileService` +- Bulk download as ZIP — `createObjectFilesZip()` +- Text extraction from PDFs/Office docs — `TextExtractionService` +- File tab in object sidebar — `CnObjectSidebar` → `CnFilesTab` +- NO custom file upload components, file controllers, or download handlers + +**Audit & Compliance** (use AuditTrailService + CnObjectSidebar): +- Full change tracking with before/after snapshots — automatic +- Audit trail tab — `CnObjectSidebar` → `CnAuditTrailTab` +- GDPR data subject access requests — `inzageverzoek()`, `verwerkingsregister()` +- Audit export and analytics — `AuditTrailController` +- NO custom audit logging, change tracking, or compliance controllers + +**Dashboard & Analytics** (use CnDashboardPage + CnChartWidget + CnStatsBlock): +- Drag-drop widget dashboard — `CnDashboardPage` with GridStack +- KPI cards — `CnKpiGrid`, `CnStatsBlock`, `CnStatsPanel` +- Charts (line/bar/pie/donut) — `CnChartWidget` (ApexCharts) +- Data tables as widgets — `CnTableWidget` +- Editable data grids — `CnObjectDataWidget` +- NO custom dashboard layouts, chart components, or KPI cards + +**Forms & Dialogs** (use CnFormDialog + schema-driven generation): +- Auto-generated create/edit forms — `CnFormDialog` reads schema → generates fields +- JSON/metadata editing — `CnAdvancedFormDialog` with Properties/Data/Metadata tabs +- Schema editor — `CnSchemaFormDialog` +- Delete/Copy/Mass operations — `CnDeleteDialog`, `CnCopyDialog`, `CnMassDeleteDialog` +- NO custom form components, validation logic, or dialog wrappers + +**Navigation & Pagination** (use CnPagination + CnActionsBar + useListView): +- Pagination control with size selector — `CnPagination` +- Action bar (add, search, toggle views) — `CnActionsBar` +- List state management — `useListView` composable (handles search, filter, sort, page) +- Detail state management — `useDetailView` composable +- NO custom pagination logic, debounced search, or list state management + +**Authorization & RBAC** (use AuthorizationService + PropertyRbacHandler): +- Role-based access control — `AuthorizationService` +- Field-level permissions — `PropertyRbacHandler` +- Object-level restrictions — `PermissionHandler` +- Authorization audit — `AuthorizationAuditService` +- NO custom permission checks, role systems, or access control middleware + +**Webhooks & Events** (use WebhookService): +- Create, test, retry webhooks — `WebhookService` +- CloudEvents format — automatic +- Event subscriptions — selective per schema/action +- NO custom webhook controllers or event dispatchers + +**Notifications & Activity** (use NotificationService + ActivityService): +- Nextcloud notifications — `NotificationService` +- Activity feed — `ActivityService` +- Calendar events — `CalendarEventService` +- Deck/Kanban cards — `DeckCardService` + +**Store & State** (use createObjectStore + plugins): +- Object stores — `createObjectStore(name)` generates Pinia CRUD store +- Store plugins: `auditTrails`, `files`, `lifecycle`, `relations`, `search`, `selection` +- Column/field/filter generation from schema — `columnsFromSchema()`, `fieldsFromSchema()` +- NO custom Pinia stores for CRUD, Vuex, or manual API call management + +**Chat & AI** (use ChatService): +- Multi-turn conversation — `ChatService` +- RAG-based knowledge retrieval — `ContextRetrievalHandler` +- LLM response generation — `ResponseGenerationHandler` + +**Data Retention & Archival** (use ArchivalService): +- Legal hold — `LegalHoldService` +- Destruction schedules — `DestructionService` +- Retention policies — `RetentionService` + +**Semantic & Hybrid Search** (use SolrController + SettingsController): +- Semantic search via vector embeddings — `SettingsController.semanticSearch()` +- Hybrid search (keyword + semantic combined) — `SolrController.hybridSearch()` +- Vector embedding generation — `VectorizationService` +- NO custom search algorithms — configure via OpenRegister settings + +**GraphQL API** (use GraphQLController): +- Query objects across schemas via GraphQL — `GraphQLController.execute()` +- Alternative to REST for complex cross-entity queries + +**Organization / Multi-Tenancy** (use OrganisationController): +- Organization CRUD — `OrganisationController` +- Tenant-scoped data isolation — automatic via `TenantLifecycleService` +- NO custom multi-tenancy logic + +**Task & Workflow Management** (use TasksController + WorkflowEngineController): +- Task creation and tracking — `TasksController` +- Workflow orchestration — `WorkflowEngineRegistry` +- Scheduled workflows — `ScheduledWorkflowController` +- NO custom task/workflow systems + +**Text Extraction** (use FileTextController): +- Extract text from PDFs and Office docs — `TextExtractionService` +- Entity recognition (PII detection) — `EntityRecognitionHandler` +- Content anonymization — automatic + +**Timeline & Stages** (use CnTimelineStages): +- Workflow progression visualization — `CnTimelineStages` component +- Stage tracking with status colors + +### What apps SHOULD build (custom business logic only): +- External API integrations (SAP, Peppol, TenderNed, etc.) +- PDF/document generation with business-specific templates +- Workflow triggers and business rules specific to the domain +- Notification dispatch with app-specific event types +- Custom settings pages with app-specific configuration +- Background jobs for domain-specific processing diff --git a/.claude/openspec/architecture/adr-002-api.md b/.claude/openspec/architecture/adr-002-api.md new file mode 100644 index 00000000..4f956593 --- /dev/null +++ b/.claude/openspec/architecture/adr-002-api.md @@ -0,0 +1,6 @@ +- URL pattern: `/index.php/apps/{app}/api/{resource}` — lowercase plural, hyphens. +- Methods: GET=read, POST=create, PUT=update, DELETE=remove. No custom methods. +- Pagination: support `_page` + `_limit`. Response includes `total`, `page`, `pages`. +- Errors: appropriate HTTP status + `message` field. NO stack traces in responses. +- Auth: Nextcloud built-in only. NO custom login/session/token flows. +- Public endpoints: annotate `#[PublicPage]` + `#[NoCSRFRequired]`. Register CORS OPTIONS route. diff --git a/.claude/openspec/architecture/adr-003-backend.md b/.claude/openspec/architecture/adr-003-backend.md new file mode 100644 index 00000000..82abe764 --- /dev/null +++ b/.claude/openspec/architecture/adr-003-backend.md @@ -0,0 +1,14 @@ +- **Controller → Service → Mapper** (strict 3-layer). Controllers NEVER call mappers directly. +- Controllers: thin (<10 lines/method). Routing + validation + response only. +- Services: ALL business logic. Stateless — no instance state between requests. +- Mappers: DB CRUD only. No business logic. +- DI: constructor injection with `private readonly`. NO `\OC::$server` or static locators. +- Entity setters: POSITIONAL args only. `$e->setName('val')` — NEVER `$e->setName(name: 'val')`. + (`__call` passes `['name' => val]` but `setter()` uses `$args[0]`.) +- Routes: `appinfo/routes.php`. Specific routes BEFORE wildcard `{slug}` routes. +- Config: `IAppConfig` with sensitive flag for secrets. NEVER read DB directly. +- Lifecycle: schema init via repair steps (`IRepairStep`), background via job queue, events via dispatcher. +- **Spec traceability**: every class and public method MUST have `@spec` PHPDoc tag(s) linking to + the OpenSpec change that caused it: `@spec openspec/changes/{name}/tasks.md#task-N`. + Multiple `@spec` tags allowed (code touched by multiple changes). File-level `@spec` in header docblock. + This enables: code → docblock → spec traceability alongside code → git blame → commit → issue → spec. diff --git a/.claude/openspec/architecture/adr-004-frontend.md b/.claude/openspec/architecture/adr-004-frontend.md new file mode 100644 index 00000000..2484aa21 --- /dev/null +++ b/.claude/openspec/architecture/adr-004-frontend.md @@ -0,0 +1,129 @@ +- **Vue 2 + Pinia + @nextcloud/vue + @conduction/nextcloud-vue**. NO Vuex. Options API only. +- State: Pinia stores in `src/store/modules/`. Use `createObjectStore` for OpenRegister CRUD. +- API calls: `axios` from `@nextcloud/axios` — auto-attaches CSRF token. NEVER raw `fetch()` for mutations. + Loading state with `try/finally`. +- Translations: ALL user-visible strings via `t(appName, 'text')`. NO hardcoded strings. + Translation keys MUST be English — Dutch translations go in `l10n/nl.json`. +- CSS: ONLY Nextcloud CSS variables (`var(--color-primary-element)`, etc.). NO hardcoded colors. + NEVER reference `--nldesign-*` directly — nldesign app handles theming. +- Router: history mode, base `generateUrl('/apps/{app}/')`. Requires matching PHP routes in `routes.php`. + Deep link URL templates MUST match the router mode — use path format (`/apps/{app}/entities/{uuid}`), + NOT hash format (`/apps/{app}/#/entities/{uuid}`). +- OpenRegister dependency: settings returns `openRegisters` (bool) + `isAdmin`. + Show empty state if OR missing. NEVER use `OC.isAdmin` — get from backend. +- NEVER `window.confirm()` or `window.alert()` — use `NcDialog` or `CnFormDialog` (WCAG, theming). +- NEVER read app state from DOM (`document.getElementById`, `dataset`) — use backend API or store. +- EVERY `await store.action()` call MUST be wrapped in `try/catch` with user-facing error feedback. +- NEVER import from `@nextcloud/vue` directly — use `@conduction/nextcloud-vue` which re-exports all + NC components plus Conduction components. This ensures consistent theming and component versions. +- EVERY component used in `