Skip to content
This repository was archived by the owner on May 29, 2026. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
136 commits
Select commit Hold shift + click to select a range
1f2420f
refactor: Tighten BooleanArgumentFlag suppressions to method-level
rubenvdlinde Mar 19, 2026
521a34a
test: Update test results — 85 issues tested, 11 bugs fixed
rubenvdlinde Mar 19, 2026
2463af0
docs: Add method-decomposition OpenSpec for complexity suppressions
rubenvdlinde Mar 19, 2026
6918db3
fix: update editUrl to reference docs/ instead of docusaurus/
rubenvdlinde Mar 19, 2026
6ac2551
chore: add missing package-lock.json for docs build
rubenvdlinde Mar 19, 2026
956887d
fix: exclude node_modules from Docusaurus docs path
rubenvdlinde Mar 19, 2026
8fe0a90
feat: add Dutch (nl) locale support for documentation
rubenvdlinde Mar 19, 2026
332c7c6
feat: Enrich method-decomposition spec with deep research
rubenvdlinde Mar 20, 2026
dc40773
chore: Add ADR enforcement rules to openspec config
rubenvdlinde Mar 21, 2026
31c8cca
docs: add docs/features/README.md with full feature index
rubenvdlinde Mar 23, 2026
ad34c16
chore: add missing test/build artifact entries to .gitignore
rubenvdlinde Apr 9, 2026
d29a3a9
chore: add docs/node_modules and docs/.docusaurus to .gitignore
rubenvdlinde Apr 9, 2026
09e5f3e
fix(headers): @author email typo dev@conductio.nl -> info@conduction.nl
rubenvdlinde Apr 20, 2026
d863e4e
feat: adopt x-openregister-lifecycle on 5 softwarecatalogus schemas
rubenvdlinde Apr 29, 2026
e800d69
feat(openspec): softwarecatalog-adopt-or-abstractions — manifest + re…
rubenvdlinde May 3, 2026
dc51033
chore: bump @conduction/nextcloud-vue to ^0.1.0-beta.17 (#213)
rubenvdlinde May 3, 2026
b7a8e89
feat(openspec): softwarecatalog-legacy-quality-cleanup tracking chang…
rubenvdlinde May 3, 2026
655dc2f
feat: activate ConceptOrganisaties dashboard widget with shared chunks
rubenvdlinde May 5, 2026
2a9760d
Merge pull request #215 from ConductionNL/feat/activate-dashboard-widget
rubenvdlinde May 5, 2026
de03d17
feat(docs): adopt @conduction/docusaurus-preset + move to softwarecat…
rubenvdlinde May 7, 2026
0d0dbfa
Merge pull request #216 from ConductionNL/feature/conduction-nl-migra…
rubenvdlinde May 7, 2026
116bfc6
feat(docs): cobalt hero on landing (preset 1.5.1)
rubenvdlinde May 7, 2026
6820e38
Merge pull request #217 from ConductionNL/feature/cobalt-hero
rubenvdlinde May 7, 2026
9ec4646
spec(softwarecatalog-manifest-v1): adopt JSON manifest renderer (Tier 4)
rubenvdlinde May 9, 2026
0e56c5d
feat(softwarecatalog): add manifest.json + customComponents + router …
rubenvdlinde May 9, 2026
7046129
feat(softwarecatalog): adopt CnAppRoot Tier-4 shell (main.js + App.vu…
rubenvdlinde May 9, 2026
e93dc5b
refactor(softwarecatalog): delete obsolete shell views replaced by ma…
rubenvdlinde May 9, 2026
8c0638f
Merge pull request #218 from ConductionNL/feature/softwarecatalog-man…
rubenvdlinde May 10, 2026
25909fa
docs(openspec): add softwarecatalog-store-migration change
rubenvdlinde May 10, 2026
f7ecaf6
chore(store): clear jsdoc/no-defaults warnings in softwarecatalogPlugin
rubenvdlinde May 10, 2026
705402b
Merge pull request #219 from ConductionNL/feature/softwarecatalog-sto…
rubenvdlinde May 10, 2026
5b6b26b
chore: bump @conduction/nextcloud-vue to 1.0.0-beta.30 (#220)
rubenvdlinde May 10, 2026
c9308af
fix(#221): provision @resolve: keys via IInitialState (#222)
rubenvdlinde May 10, 2026
2b9809e
chore: add missing @nextcloud/eslint-config peer deps + fix PHPCS sni…
rubenvdlinde May 10, 2026
6d57448
chore(stylelint): add missing @nextcloud/stylelint-config peer deps (…
rubenvdlinde May 11, 2026
4f26f90
chore(deps): bump @conduction/nextcloud-vue to ^1.0.0-beta.40
rubenvdlinde May 12, 2026
ac9cc59
Merge pull request #226 from ConductionNL/feature/manifest-tier4
rubenvdlinde May 12, 2026
2969403
Merge branch 'feature/declarative-annotation-pilot' into development
rubenvdlinde May 12, 2026
8097f99
chore(docs): bump @conduction/docusaurus-preset to 1.5.1 in lockfile …
rubenvdlinde May 12, 2026
b235a73
chore(docs): bump @conduction/docusaurus-preset to 2.6.1; deploy from…
rubenvdlinde May 12, 2026
8b5a516
test: stub OCA\OpenRegister\Db\ObjectEntity (real one has __call-magi…
rubenvdlinde May 13, 2026
e66b5ea
Merge origin/development
rubenvdlinde May 13, 2026
2605ae1
feat(manifest): render status/category columns as badges (widget:"bad…
rubenvdlinde May 13, 2026
ee6cab6
Merge pull request #231 from ConductionNL/feat/index-status-badges
rubenvdlinde May 13, 2026
31f8f0c
feat(manifest): render date columns via the built-in `date` formatter
rubenvdlinde May 13, 2026
7c49525
Merge pull request #233 from ConductionNL/feat/date-formatters-and-be…
rubenvdlinde May 13, 2026
9030b61
ci(docs): revert deploy source to documentation branch (docs CI separ…
rubenvdlinde May 13, 2026
5f6bdbf
chore(security): require 24h cooldown on npm packages (#238)
rubenvdlinde May 17, 2026
0d7743e
feat(docs): wire AI-crawler baseline (preset 3.4.0 + validator + llms…
rubenvdlinde May 18, 2026
1c3d294
feat(docs): per-app OG card + accurate llms.txt links (#240)
rubenvdlinde May 18, 2026
4385722
chore(docs): use validator bin from preset 3.5.0 (#241)
rubenvdlinde May 18, 2026
27df1da
chore(docs): bump preset to ^3.6.0 + sync lockfile (#242)
rubenvdlinde May 18, 2026
544b55c
chore(deps): upgrade preset lockfile to 3.6.1 (unbreaks deploy) (#244)
rubenvdlinde May 18, 2026
4cc5014
chore(deps): preset lockfile 3.6.1 -> 3.6.2 (validator patch) (#246)
rubenvdlinde May 18, 2026
d98c3d3
chore(deps): preset lockfile 3.6.2 -> 3.7.0 (sitemap lastmod auto-app…
rubenvdlinde May 19, 2026
ea0dccc
fix(tests): unblock PHPUnit CI — load stub before NC bootstrap + skip…
rubenvdlinde May 19, 2026
7d89761
chore(brand): shrink app-icon glyph for better hex breathing room (#237)
rubenvdlinde May 19, 2026
1ca2d36
chore: harmonize .gitignore with shared template (closes #204) (#205)
rubenvdlinde May 19, 2026
693f1df
chore: Final OpenSpec structure cleanup (#202)
rubenvdlinde May 19, 2026
f8215fd
chore(deps): preset lockfile 3.7.1 -> 3.8.0 (BreadcrumbList + TechArt…
rubenvdlinde May 19, 2026
7775508
chore(brand): align app-store hex to canonical cobalt #21468B (#236)
rubenvdlinde May 19, 2026
cea48ba
fix(brand): revert app-store.svg cobalt to canonical #4376FC (#256)
rubenvdlinde May 19, 2026
b3c9406
fix(brand): re-apply #21468B cobalt (reverting my earlier revert — #2…
rubenvdlinde May 19, 2026
5b3529b
chore(deps): preset lockfile 3.8.0 -> 3.9.0 (TechArticle gate) (#260)
rubenvdlinde May 19, 2026
23ada40
fix(docs): descriptive homepage title (closes ConductionNL/.github#80)
rubenvdlinde May 19, 2026
5ba59e2
Merge pull request #262 from ConductionNL/seo/title-fix-80
rubenvdlinde May 19, 2026
25fef37
fix(docs): hand-written meta descriptions on homepage + intro (#81)
rubenvdlinde May 19, 2026
8ad10c2
Merge pull request #264 from ConductionNL/seo/meta-descriptions-81
rubenvdlinde May 19, 2026
341dd0e
chore(docs): bump @conduction/docusaurus-preset to 3.10.0 (#79)
rubenvdlinde May 19, 2026
a725315
Merge pull request #266 from ConductionNL/chore/preset-3.10.0
rubenvdlinde May 19, 2026
c88e205
feat(manifest-v2): migrate to universal widget manifest (#268)
rubenvdlinde May 19, 2026
4704951
fix(quality): wire registryProp to App render so no-unused-vars passe…
rubenvdlinde May 19, 2026
3207038
fix(webpack): inject appName + appVersion via DefinePlugin (#270)
rubenvdlinde May 19, 2026
443d6ef
feat(manifest-v2): convert Dashboard to type:dashboard (refs #271) (#…
rubenvdlinde May 20, 2026
6ba425e
feat: Add OpenSpec change method-decomposition from Specter
May 20, 2026
9710919
feat: Add OpenSpec change method-decomposition from Specter
May 20, 2026
9322e94
chore: add hydra.json for method-decomposition
May 20, 2026
4b21bfe
chore: link issue to hydra.json for method-decomposition
May 20, 2026
2d477db
feat(manifest-v2): flip Organisaties to type:"index", drop wrapper vi…
rubenvdlinde May 20, 2026
daa14fc
chore(deps): bump @conduction/nextcloud-vue to ^1.0.0-beta.66 (#277)
rubenvdlinde May 21, 2026
936d8be
chore: remove dead .php-cs-fixer.dist.php (#278)
rubenvdlinde May 21, 2026
a3719e0
chore: sync canonical root configs + mechanical phpmd cleanup (#280)
rubenvdlinde May 21, 2026
6a73d30
chore(deps): bump PHP requirement to ^8.3 (#282)
rubenvdlinde May 22, 2026
90f3826
chore(deps): bump composer config.platform.php to 8.3 (#283)
rubenvdlinde May 23, 2026
254c383
chore(info.xml): canonicalize PHP min, NC version range, licence spel…
rubenvdlinde May 23, 2026
6b9dc1f
feat(openspec): adopt org-archimate-export spec + 3 GEMMA changes fro…
rubenvdlinde May 24, 2026
d413b15
retrofit: annotate softwarecatalog Bucket 1 (46 methods / 27 files) (…
rubenvdlinde May 24, 2026
30a507a
retrofit: draft progress-tracking spec + annotate 9 methods (#288)
rubenvdlinde May 25, 2026
ce54c58
retrofit: draft aanbod-listings spec + annotate 4 methods (#289)
rubenvdlinde May 25, 2026
9831509
retrofit: draft concept-organizations-widget spec + annotate load() (…
rubenvdlinde May 25, 2026
8a84d7e
retrofit: draft gebruik-services spec + annotate 3 methods (#291)
rubenvdlinde May 25, 2026
d3e2d28
retrofit: draft organisatie-service spec + annotate 8 methods (#292)
rubenvdlinde May 25, 2026
0b472dc
retrofit: extend method-decomposition with SettingsController public …
rubenvdlinde May 25, 2026
11d08aa
chore(nav): adopt three-section nav model + bump nc-vue to beta.97 (#…
rubenvdlinde May 25, 2026
2922a10
feat(nav): add Features & roadmap item + page, bump nc-vue beta.101 (…
rubenvdlinde May 25, 2026
57039c3
feat(preferences): generic per-user preferences endpoint (#299)
rubenvdlinde May 25, 2026
9ced404
fix(ui): bump @nextcloud/vue to ^8.39.0 to fix nav corner sliver on N…
rubenvdlinde May 25, 2026
57f2c55
retrofit(coverage): spec-coverage to zero uncovered methods (#301)
rubenvdlinde May 25, 2026
5d4f911
[change request] softwarecatalog notifications (#302)
rubenvdlinde May 25, 2026
a00eccf
chore(composer): bump lock platform-overrides to PHP 8.3 to match con…
rubenvdlinde May 25, 2026
d368a90
chore(composer): bump dev deps twig/twig + symfony/yaml to patched ve…
rubenvdlinde May 26, 2026
3b7cd81
chore: remove stale generated test-results
rubenvdlinde May 26, 2026
eb9ab07
fix: resolve hydra mechanical gates (spdx, initial-state, nc-input-la…
rubenvdlinde May 26, 2026
fd66f23
fix(security+nc34): bump vulnerable symfony mailer/mime, replace remo…
rubenvdlinde May 26, 2026
066f9f5
Merge remote-tracking branch 'origin/development' into chore/remove-s…
rubenvdlinde May 26, 2026
3df8377
fix: resolve all CI quality gate failures on PR #306
rubenvdlinde May 26, 2026
7a9a382
ci: trigger fresh quality run
rubenvdlinde May 26, 2026
02fbba4
chore: remove stale generated test-results
rubenvdlinde May 26, 2026
be56814
fix(security): clear Bucket-B gates 5/6/7/9/14 (ADR-023 + auth/routin…
rubenvdlinde May 26, 2026
adea5f9
chore(spec): annotate extracted BulkSyncDialog methods (gate-16) (#319)
rubenvdlinde May 26, 2026
dc9e05e
chore: add publiccode.yml (Standard for Public Code compliance) (#320)
rubenvdlinde May 26, 2026
c6ce322
fix: resolve gate-3 stub-scan — remove dead CronjobContextTrait and a…
rubenvdlinde May 26, 2026
d30d115
test(e2e): gate-19 e2e-coverage for org-archimate-export spec
rubenvdlinde May 27, 2026
f772da1
Merge pull request #323 from ConductionNL/test/e2e-coverage-gate19
rubenvdlinde May 27, 2026
6b95f78
fix(spa): load webpack runtime chunk in templates to fix SPA white-sc…
rubenvdlinde May 27, 2026
467cd7e
Merge pull request #324 from ConductionNL/fix/spa-runtime-chunk-322
rubenvdlinde May 27, 2026
2489bc7
fix: patch CVE-2026-46644 and OrganizationContactSyncJob missing cons…
rubenvdlinde May 27, 2026
47b1501
Merge pull request #325 from ConductionNL/fix/cve-46644-and-orgsyncjo…
rubenvdlinde May 27, 2026
2025873
fix: gate auth-critical endpoints + remove dormant plaintext-password…
rubenvdlinde May 27, 2026
b50e267
fix(auth): drop @PublicPage from mutating endpoints and fix isUserInG…
rubenvdlinde May 27, 2026
b686396
fix(sync): H6 in_array precedence, H7 Postgres SQL, H8 organisatie st…
rubenvdlinde May 27, 2026
e420d2b
fix(nc34): replace all OC::$server->get() with ContainerInterface inj…
rubenvdlinde May 27, 2026
c982b58
fix(medium-low): M1 empty HTTP status, M3 credential redaction, M4 ra…
rubenvdlinde May 27, 2026
51ab544
fix(email): prevent SMTP-cred round-trip, XSS in templates, DSN encod…
rubenvdlinde May 28, 2026
5fa5a9a
fix(state): correct inverted boolean conversion and empty-if status-c…
rubenvdlinde May 28, 2026
2d47177
fix(sync): correct processContactPerson username resolution and error…
rubenvdlinde May 28, 2026
775e014
fix(archimate): fill all empty-if bodies in export/import/service (#362)
rubenvdlinde May 28, 2026
ec8b86f
fix(auth): add missing admin gates and remove debug/deprecated endpoi…
rubenvdlinde May 28, 2026
af19d4f
fix(deps): bump twig/twig to ^3.27.0 to fix 5 CVEs
rubenvdlinde May 28, 2026
9d4213b
Merge pull request #363 from ConductionNL/fix/twig-cve-3-27
rubenvdlinde May 28, 2026
91bf0e4
fix(security): wave-3 critical fixes — empty-if fallthroughs and priv…
rubenvdlinde May 28, 2026
478e8dc
fix: resolve all composer check:strict failures — PHPStan bugs, PHPCS…
rubenvdlinde May 28, 2026
3ae709f
Merge pull request #366 from ConductionNL/fix/strict-real-bugs-and-gates
rubenvdlinde May 28, 2026
8704587
fix(contactpersoon): make e-mailadres field nullable to prevent HTTP 500
rubenvdlinde May 28, 2026
1ef87ec
Merge pull request #367 from ConductionNL/fix/contactpersoon-email-nu…
rubenvdlinde May 28, 2026
9a398a6
fix(security): wave-7 critical C1-C3 (cross-tenant user-info + empty-…
rubenvdlinde May 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
223 changes: 223 additions & 0 deletions .claude/openspec/architecture/adr-001-data-layer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
- 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
in OpenRegister's pending `seed-related-items` openspec change (see
`openregister/openspec/changes/seed-related-items/`). Until that lands, 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
6 changes: 6 additions & 0 deletions .claude/openspec/architecture/adr-002-api.md
Original file line number Diff line number Diff line change
@@ -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.
14 changes: 14 additions & 0 deletions .claude/openspec/architecture/adr-003-backend.md
Original file line number Diff line number Diff line change
@@ -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.
Loading