Skip to main content

Features

StableBetaComing soon
account-self-serviceProvides the signed-in user's self-service account page, letting users change their own password, request account deactivation, and manage their personal API tokens and avatar. Password changes and deactivation requests surface inline section feedback and leave the current session active until an administrator acts on the request.action-registry@e2e exclude backend service/entity — covered by PHPUnit TBD - created by archiving change action-registry. Update Purpose after archive.Actions@e2e exclude backend service/entity — covered by PHPUnitActivity Provider@e2e exclude Nextcloud activity provider — backend-only, covered by PHPUnitadmin-list-viewsProvides consistent interaction behaviour across the OpenRegister admin index views (agents, applications, configurations, entities, sources, templates, webhooks). Gives each list a select-all bulk-selection action, an optional detail-sidebar toggle, and a soft refresh of its data on mount so views render instantly from already-loaded store state.admin-settingsThe OpenRegister admin settings surface renders in the Nextcloud admin panel and exposes operational status sections — including the realtime push-notifications (notify_push) status probe — without instantiating runtime queue services during render. Backed by `lib/Settings/OpenRegisterAdmin.php` and the admin settings Vue component.aggregation-apiProvides a runtime, client-controlled aggregation primitive over REST and GraphQL that buckets the rows of a register-schema collection by a named field, with optional time-bucketing and count/sum/avg/min/max metrics. Enforces row-level RBAC and multi-tenant filtering before aggregating, generates native SQL per database engine (with a PHP fallback), and caches results for up to 60 seconds with event-driven invalidation.aggregations-backend-native@e2e exclude backend aggregation service — covered by PHPUnit TBD - created by archiving change retrofit-2026-05-25-bw-svc-mid3. Update Purpose after archive.apphost-observabilityServes health and Prometheus-format metrics endpoints for any Nextcloud app by executing declarative descriptors from the app's manifest, so apps get monitoring without writing endpoint code. Supports five health-check types and five metric source kinds with caching, a provider escape hatch for imperative metrics, and descriptor validation that falls back to safe defaults. Enforces the engine-owned auth posture — public health, admin-only metrics — and powers OpenRegister's own observability endpoints from its manifest.apphost-store-planeGives any AppHost-hosted app a read-only client for a remote "store" — another OpenRegister instance that exposes installable items over its objects API — so openbuild's application-template store, openconnector's connector store and hermiq's agent-template store share one engine-owned implementation instead of three app-local copies. The plane covers DISCOVERY only (configure / search / resolve); INSTALL stays in each consuming app, because cloning an application template, enabling a connector adapter and instantiating an agent template are different operations with different authorization. Everything that differs between apps is carried in a `StoreDescriptor` value object; everything else — SSRF guarding, redirect refusal, Bearer-token handling, outcome mapping and card normalisation — lives once in `GenericStoreService`. Implements ADR-080.Approval Workflow@e2e exclude REST API CRUD — covered by Newman; no dedicated OR UI surfacearchival-annotation-vocabularyGives schemas a retention and archival vocabulary via the `x-openregister-archival` annotation, enforcing data-retention policy on object rows. Schemas declare a default retention plus condition-based rules; an hourly cron sweeps and deletes expired rows, object reads surface a computed `_retention` block, and user-driven deletes on archival schemas are blocked with HTTP 403. Validates retention declarations at save time and recognises the annotation through the import path so it round-trips without being dropped.Archival Destruction Workflow@e2e exclude backend workflow/archival — covered by PHPUnitarchivering-vernietiging@e2e exclude backend archival/MDTO — covered by PHPUnit Implement archiving and destruction lifecycle management for register objects, conforming to MDTO (Metagegevens Duurzaam Toegankelijke Overheidsinformatie), NEN 2082 records management, and e-Depot export standards. Objects MUST support retention schedules, automated destruction workflows, and transfer to digital archival systems.audit-trail-immutable@e2e exclude backend audit trail — covered by PHPUnit Implement an immutable audit trail with cryptographic hash chaining for all register operations. Every create, read (of sensitive data), update, and delete MUST be recorded in a tamper-evident log with minimum 10-year retention. The audit trail MUST be independently verifiable and exportable for compliance auditing.Calendar Integration@e2e exclude CalDAV provider — backend-only, covered by PHPUnitCalendar Provider@e2e exclude CalDAV ICalendarProvider backend — covered by PHPUnitChat AI@e2e exclude REST API + LLPhant adapter backend — covered by PHPUnitcleanup-linked-entity-type-mapRemoves the hardcoded `LinkedEntityService::TYPE_COLUMN_MAP` and `Schema::VALID_LINKED_TYPES` constants so integration discovery and linked-type validation are driven entirely by `IntegrationRegistry`. Existing schemas continue to validate through `IntegrationRegistry::listIds()`, and an organisation-wide grep sweep migrates any external callers before the constants are deleted.contacts-actions@e2e exclude Nextcloud Contacts IContactsMenuProvider backend — covered by PHPUnit TBD - created by archiving change contacts-actions. Update Purpose after archive.Content Versioning@e2e exclude backend version tracking — covered by PHPUnit Content versioning provides a complete lifecycle for register objects, enabling users to track every change as a numbered version, create named draft versions for work-in-progress edits, compare any two versions with field-level diffs, and roll back to any previous state. This capability is essential for government compliance (WOO, Archiefwet), editorial workflows where changes require review before publication, and multi-user collaboration where concurrent edits must be managed safely.Context Chat Provider@e2e exclude backend Nextcloud Context Chat integration — covered by PHPUnitDashboard Sidebar Default StateDefines the initial open/closed state of the OpenRegister dashboard's right-hand app sidebar. The dashboard sidebar renders collapsed on initial load so the dashboard's primary content is unobstructed, while remaining fully functional via the standard Nextcloud sidebar toggle. The default applies to the dashboard view only and does not change any other view's sidebar default.Data Import and ExportDocument and extend OpenRegister's existing import/export infrastructure. The core pipeline is already implemented: ImportService with SaveObjects' internal chunked processing for bulk ingest, ExportService/ExportHandler for CSV/JSON/XML output, and Configuration/ImportHandler for register template loading. This spec validates the existing implementation and defines extensions for additional formats, progress tracking, and schema validation. The existing pipeline already handles CSV and Excel import via PhpSpreadsheet, CSV and Excel export with RBAC-aware header generation and relation name resolution, configuration import/export in OpenAPI 3.0.0 format, bulk operations via SaveObjects with BulkRelationHandler and BulkValidationHandler, deduplication efficiency reporting, multi-sheet Excel import, two-pass UUID-to-name resolution, and property-level RBAC enforcement on export columns. This spec extends that foundation with JSON/XML/ODS format support, interactive column mapping, progress tracking UI, downloadable error reports, import templates, streaming for large datasets, scheduled imports, and i18n for headers and templates.data-sync-harvesting@e2e exclude backend sync/harvesting service — covered by PHPUnitdbal-virtual-registersExpose external relational databases as read-only **virtual registers** over Doctrine DBAL: the database becomes a Register, its tables and views become Schemas, and objects are served live through the existing object-source-provider seam (`x-openregister-object-source`, ADR-049 mechanism) — no copy or sync. SQL structure is introspected into JSON Schema so virtual schemas follow the same validation rules and relations as the underlying tables (columns → properties, NOT NULL → required, foreign keys → `$ref` relations resolvable via `_extend`). Credentials are custodied per ADR-004; reads enforce RBAC parity and 502/503 failure semantics.Deep Link Registry@e2e exclude backend deep-link registration service — covered by PHPUnitDeletion Audit Trail@e2e exclude backend audit/lifecycle service — covered by PHPUnitDSAR Deadline EscalationThe temporal re-evaluation sweep that makes the DSAR register's already-declared deadline reminder/escalation/breach notifications dispatch without an object write (dsar-escalation-and-dpia), plus the write-once `breachedAt` breach stamp and privacy-officer breach visibility. A `now`-dependent materialised calculation (the `escalationTier`) goes stale on untouched cases; the hourly `TemporalCalculationSweepJob` re-materialises it through the normal write path so the declared `calculatedChange` rules fire boundary-guarded. Generic clockwork any future `now`-dependent schema inherits.DSAR DPIA Pattern DetectionGDPR art-35 DPIA pattern detection over DSAR cases (dsar-escalation-and-dpia): the daily `DsarDpiaDetectionJob` groups cases received inside a rolling window by pack-configured characteristics (default type + normalised scope) and sets `dpiaRequired = true` on every case of a group reaching the pack threshold, through an audited write, notifying the privacy officer via the declared `dpiaFlagged` rule. Threshold, window, grouping, and officer group are policy-pack data (config as data); no pack / no `dpiaDetection` block is a fail-safe no-op.e-Depot BagIt Output FormatRFC 8493 (BagIt 1.0) SIP serialization as a per-connection output option in `SipPackageBuilder` (archival-transfer-hardening): a connection whose `edepot_package_format` is `bagit` produces a bag with `bagit.txt`, `bag-info.txt` (payload oxum, bagging date, source-organization), a complete `manifest-sha256.txt` + `tagmanifest-sha256.txt`, and SIP content under `data/`; the plain-zip layout stays the byte-for-byte default so existing connections are unchanged, and the same content serializes losslessly in either format.e-Depot Durable Transfer RetryJob-based durable retry for e-Depot transfers (archival-transfer-hardening): `transfer#create` verifies an `approved` list and dispatches `TransferExecutionJob` rather than transporting synchronously; the in-flow `sleep()` chain is replaced by cross-request retries where each attempt is recorded append-only and a failure reschedules via the background-job system with exponential backoff (~1 min → 8 h cap, ±10 % jitter) — the worker never blocks on a backoff window. After a configurable attempt cap the transfer fails and escalates to archivists through the existing notification path, and retries only cover objects not already confirmed (no double ingest).e-Depot Proof of TransferDurable transfer records and immutable proof-of-transfer per object (archival-transfer-hardening): transfer lists persist as objects in a system register (status, references, exclusions, approval metadata, attempt history, result) through the audited write path, and `transfer#index`/`show` serve the persisted records instead of placeholder responses. Every confirmed object gets a write-once `edepotTransferProof` (ingest reference + transport receipt, package identity + manifest hash, per-file SHA-256, transport, timestamp) that lives in the `edepot-transfers` register so it survives destruction of the source (Archiefwet accountability outlives the data); failed/unconfirmed objects get no proof.e-Depot Transfer@e2e exclude backend OAIS/SFTP transfer service — covered by PHPUnit Define how OpenRegister exports objects to a Dutch e-Depot for permanent archival storage. The capability MUST package selected objects as OAIS-compliant SIP archives with MDTO-compliant XML metadata, deliver them via SFTP, REST, or OpenConnector, track per-object transfer status, and enforce read-only state on transferred objects so the e-Depot remains the authoritative copy. This satisfies Archiefwet 1995 obligations for transferring permanent records to the receiving archival institution.Entity Management ModalsDescribes the user-facing modal dialog components that mediate create / read / update / delete and bulk operations on first-class register entities (registers, schemas, objects, applications, organisations, configurations, endpoints, sources, views, webhooks, soft-deleted records, audit-trail entries, files). Every register entity in the OpenRegister UI is mutated through a small family of modal Vue components (`Edit{Entity}.vue`, `Delete{Entity}.vue`, `View{Entity}.vue`, plus per-entity bulk variants) that share a consistent open / load / submit / close / error-handling lifecycle driven by the `navigationStore` dialog state and the corresponding entity store.entity-relation-grondslagenLets operators annotate detected entity-relations with legal-basis (`bases`) UUIDs and a `skipAnonymization` flag through an audited `PATCH /api/entity-relations/{id}` endpoint, and add manual entities to a file via chunk-aware exact-string matching. The anonymisation flow honours `skipAnonymization` so flagged relations are never redacted, substitutes entities with stable `[<TYPE>: <id>]` placeholders for byte-identical re-runs, and records every decision write in OpenRegister's audit trail while keeping operator-supplied values out of HTTP logs and error bodies.Environment OTAP@e2e exclude backend Organisation entity field — covered by PHPUnit Define environment type tagging (Ontwikkeling/Test/Acceptatie/Productie) for Organisation entities, enabling environment-aware configuration, behavior differentiation, and configuration promotion between environments. This supports the standard Dutch government OTAP deployment model where changes flow from development through test and acceptance to production.Faceting Configuration@e2e exclude backend facet config parser — covered by PHPUnit Provides a comprehensive, backend-agnostic faceting system for OpenRegister that enables per-property facet definition on schema properties, supports multiple facet types (terms, date histogram, range), and delivers configurable facet metadata (title, description, order, aggregation control) through the REST and GraphQL APIs. The system is designed to solve the fundamental conflict between pagination and facet computation by calculating facets on the full filtered dataset independently of pagination, while maintaining backward compatibility with the legacy boolean `facetable` flag and offering intelligent caching at multiple layers (in-memory, APCu/distributed, and database-persistent) to ensure sub-200ms facet response times even on large datasets.features-roadmap-menuAdds a Features & Roadmap surface to an app — a dedicated route with a Features tab listing capabilities from a generated `docs/features.json` manifest and a Roadmap tab showing live GitHub issues sorted by reaction count, plus a "Suggest feature" modal that submits new requests. Markdown is rendered with strict DOMPurify sanitization, pipeline labels are filtered out, widgets and pages can declare a `specRef` to pre-fill and filter by capability, and admins can disable the whole feature via an app-config flag. The same manifest powers a public Docusaurus `/features` page, with a CI check keeping it in sync with the specs.federationThe canonical home for what OpenRegister's federated-share serving surface (`FederationController`, `/api/federation/{shareToken}/...`) is allowed to hand to a remote instance.file-risk-classification@e2e exclude backend PII/risk classifier — covered by PHPUnit TBD - created by archiving change retrofit-2026-05-25-bw2-svc-flat-3. Update Purpose after archive.Filter Sidebar TabsProvide a consistent filter-sidebar UX across OpenRegister's main list views (Entities, Webhooks, Dashboard, Deleted). Each filter sidebar is a Vue single-file component that owns a small set of filter controls (search input, register/schema pickers, status pickers, date ranges) and communicates its state either through `update:*` events to a parent list view (Entities, Webhooks) or through the global Pinia register/schema/deleted stores plus the router query string (Dashboard, Deleted).frontend-app-bootstrap@e2e exclude Vue app bootstrap/JS unit patterns — covered by unit tests, not Playwright TBD - created by archiving change retrofit-2026-05-25-fe-misc. Update Purpose after archive.frontend-store-client-state@e2e exclude Pinia store unit patterns — covered by unit tests, not Playwright TBD - created by archiving change retrofit-2026-05-25-fe-store-1. Update Purpose after archive.generic-integrations@e2e exclude Nextcloud shares provider backend — covered by PHPUnit TBD - created by archiving change integration-shares. Update Purpose after archive.geo-metadata-kaart@e2e exclude feature not yet implemented — no UI surface exists Add geospatial metadata support and map visualization to register objects. Objects MUST support storing coordinates (point), polygons, and references to BAG/BGT base registrations. A map widget using Leaflet MUST visualize object locations, support clustering, and enable spatial queries for filtering objects by geographic area.github-issue-proxyProvides a server-side proxy at `GET`/`POST /api/github/issues` that lets authenticated Nextcloud users read a configured repository's issues and submit new ones without exposing GitHub tokens to the browser. Reads merge OR-semantics label filters and are cached; submissions fall back to an app-level PAT with a sanitized attribution prefix, attach an optional `specRef` label, and are rate-limited and audit-logged. Enforces a single-repo allowlist, least-privilege PAT scopes, and guarantees the token never leaks into responses, logs, caches, or errors.i18n-api-language-negotiationNegotiates the language of API responses from a `?_lang=`/`?language=` query parameter, the `Accept-Language` header, the register default, then a hardcoded `nl` fallback, applying the same precedence to single-object and bulk-listing reads. Invalid BCP-47 tags fall through with a warning rather than failing the request. On writes, an `X-Translation-Target-Language` header directs scalar body values into a specific translation language independently of the response language, with a 400 conflict when it clashes with a full language-keyed body.i18n-source-of-truthTracks which language is the canonical source for each translatable property so derived translations can be flagged when the source changes. Schemas and individual objects declare a `sourceLanguage`, every projected translation row records it, and editing a source value automatically flips approved derived translations to `outdated`. Exposes source-language and out-of-date query filters, an opt-in `_translationMeta` render envelope, and an `X-Source-Language` response header for at-a-glance "is this the original?" detection.integration-activitySurfaces Nextcloud Activity events alongside OpenRegister cross-integration events as a blended, scope-filtered feed on an object, with event-type filter chips that persist the user's selection. Registers an Activity integration provider using a query-time storage strategy — listing is read directly from NC Activity, mutations return HTTP 501 — and renders the standard widget surfaces plus a single-event reference chip. Per-user visibility defers entirely to NC Activity's own filtering.integration-analyticsLinks Nextcloud Analytics reports to OpenRegister objects and embeds their charts, rendering through the shared apexcharts dependency from the Analytics chart config rather than re-implementing chart logic. Dashboard surfaces auto-refresh every five minutes while detail-page and single-entity surfaces refresh only on user action, and the single-entity surface and `referenceType: 'analytics'` properties add a sparkline. Access control defers to Analytics' own ACLs.integration-bookmarksLinks Nextcloud Bookmarks to OpenRegister objects, delegating URL title/favicon scraping to the NC Bookmarks create endpoint instead of re-implementing it. Displays linked bookmarks with their Bookmarks-side tags as filter chips, renders the standard four widget surfaces, and shows a favicon chip for `referenceType: 'bookmarks'` properties. Access control defers to Bookmarks' own ACLs.integration-calendarLinks Nextcloud Calendar meetings to OpenRegister objects, surfacing them in a "Meetings" sidebar tab, dashboard widget, and inline detail-grid chips. Users can create VEVENTs in their own calendar directly from an object and unlink them without deleting the underlying event. The provider appears only when the Calendar app is installed, and access inherits from object RBAC plus NC Calendar's own controls.integration-collectivesLinks existing Nextcloud Collectives pages to OpenRegister objects and renders their markdown content inline, both in a sidebar tab and on the detail-page surface. Page creation stays in Collectives; the integration only links and previews. Access defers entirely to Collectives' own ACLs.integration-contactsLinks Nextcloud Contacts to OpenRegister objects with per-link roles, grouping linked contacts by role in the sidebar tab and offering reverse lookup of every object a contact is linked to. It provides the canonical person chip (avatar, name, hover details) used to render person-reference properties across Conduction apps. Access inherits from object RBAC plus Contacts address-book permissions.integration-cospendLinks Cospend projects and bills to OpenRegister objects, each link typed as either a project or a bill, and renders amount chips and totals across the standard surfaces. Totals aggregate only within a single currency, with mixed-currency sets shown as per-currency totals side by side. Access inherits from object RBAC plus Cospend's own ACLs.integration-deckLinks Nextcloud Deck cards to OpenRegister objects, letting users create new cards (with sticky per-schema default board and stack) or link existing ones from a sidebar tab. The detail-page surface renders a compact mini-kanban that highlights the linked card in its current stack, and unlinking leaves the Deck card untouched. Access inherits from object RBAC plus Deck's per-board ACLs.integration-emailLinks existing Nextcloud Mail messages to OpenRegister objects, listing them by date in a sidebar tab and caching subject, sender, and date at link time so dashboards render without live Mail API calls. The integration links and unlinks only — it never composes, sends, or modifies the underlying message. Access inherits from object RBAC plus the user's own Mail account access.integration-flowLinks Nextcloud Flow (workflowengine) rules to OpenRegister objects, defaulting to schema scope so all objects of a schema trigger the linked rule. The sidebar tab separates NC Flow rules from OR workflow rules and shows recent fire events within a configurable window (default 7 days). Because Flow is admin-gated, the tab and its endpoints are visible only to admins.integration-formsLinks Nextcloud Forms responses to OpenRegister objects, supporting both linking individual responses and form-mappings that auto-link future submissions via an object selector. Linked responses render read-only across the standard surfaces, with editing delegated to NC Forms. Access inherits from object RBAC plus Forms app access.integration-leaf-foundationProvides the OpenRegister backend foundation that leaf apps build on: minting, resolving, and revoking opaque public case-token links to objects, and registering and fetching page-level analytics chart series. Public token resolution and analytics fetches run the canonical OR read path with RBAC enforced and fail closed with uniform 404s so they cannot act as enumeration oracles. OpenRegister owns persistence and the render contract; the consuming leaf owns the maths and UI flows.integration-mapsLinks Nextcloud Maps locations to OpenRegister objects, caching latitude, longitude, and address so rendering never calls geocoding. Users add a location either by entering an address (geocoded) or by clicking the embedded map, and the single-entity surface renders an address chip that expands to a map popover on click. Access inherits from object RBAC plus Maps' own ACLs.integration-maps-overviewLets an authenticated user register page-level map overview widgets scoped to a register and schema, then query an RBAC-scoped marker point set drawn from each object's geometry. A default Dutch PDOK WMTS base layer is applied as declarative metadata unless one is supplied, and the register/schema scope is caller-immutable so it cannot be spoofed through filters. Point queries run the canonical OR read path with RBAC enforced for non-admins, returning a uniform point list that never acts as an enumeration oracle.integration-openprojectLinks OpenProject work packages to OpenRegister objects, routing all CRUD through the ExternalIntegrationRouter to an OpenConnector `openproject` OAuth2 source rather than a local link table. The provider appears only when that source exists, surfaces an explicit "Reconnect" banner when the token expires, and exposes its auth status through OCS capabilities. Per-work-package visibility is governed transitively by OpenProject's own ACLs.integration-photosSurfaces an object's linked image files as a dedicated Photos integration that shares the Files link table and filters by MIME type. Extracts and caches EXIF metadata lazily on first view, optionally strips GPS coordinates at link time (opt-in, leaving the original file untouched), and renders thumbnail chips for `photos` reference properties. File permissions govern visibility.integration-pollsLinks Nextcloud Polls to OpenRegister objects, showing each poll's status (draft/open/closed), vote tally, and the current user's own highlighted vote. Renders a polls card across all widget surfaces (with a mini bar-chart tally on the detail page) and for `polls` reference properties. The Polls app's own ACLs govern visibility.integration-registryProvides a pluggable integration registry that lets OpenRegister link external and Nextcloud services to objects through a common `IntegrationProvider` contract, auto-registered via DI tags and resolvable through the `IntegrationRegistry` service. Ships the eight built-in NC integrations (files, notes, tasks, calendar, mail, contacts, deck, talk) while preserving their legacy linking behavior, validates schema `linkedTypes` against the registry, routes external providers through OpenConnector, advertises enabled integrations via OCS capabilities, and supplies a CI parity gate, a scaffold script, and an OCC listing command.integration-registry-reference-provider-convergenceDocuments a spike that evaluates whether the OpenRegister integration registry surface should converge onto Nextcloud's `IReferenceProvider`. Delivers a responsibilities matrix separating pure read/render duties from genuine value-adds, a single go/no-go recommendation with phased follow-up plan and risks, and an enumerated migration blast radius — all as documentation and spec artifacts only, with no production registry or frontend code modified.integration-shares@e2e exclude redirect/duplicate of generic-integrations — backend-only TBD - created by archiving change integration-shares. Update Purpose after archive.integration-talkLinks Nextcloud Talk conversations to OpenRegister objects through a single chat-and-rooms provider, present only when Spreed is installed. The tab opens chat-first to the most recent conversation with a compose box, dashboard surfaces show the unread-message count as the headline metric, and `talk` reference properties render a conversation card with an unread indicator. Talk's own room ACLs govern visibility.integration-time-trackerLinks time-tracking entries to OpenRegister objects via a configurable Nextcloud backend app (default `timemanager`), storing a denormalized per-object hour total that dashboards read in a single row instead of aggregating entries at render time. Renders across the standard widget surfaces (with a per-user/week breakdown on the detail page) and an hours chip for `time-tracker` reference properties, with an `occ openregister:time:reconcile` command to recalculate totals from source entries. The backend app's ACLs govern visibility.integration-xwikiLinks external XWiki pages to OpenRegister objects, routing all CRUD through an OpenConnector `xwiki` source (Basic or OAuth2). The link form accepts a full URL or a space.page path and stores a canonical reference, tab rows show the full wiki/space/page breadcrumb, the detail page renders a macro-stripped text-only preview, and an auth-expiry banner offers a reconnect link. Renders on all four widget surfaces and as a page chip for `xwiki` reference properties; XWiki's own ACLs govern access transitively.json-ld-outputProvide read-side JSON-LD (JSON-LD 1.1) serialization of register objects, backing the App Store / README "JSON-LD and Linked Data" promise. Objects are retrievable as `application/ld+json` via content negotiation on the existing object read endpoints, with `@id` set to the canonical object URI, `@context` derived from schema definitions, optional schema-level mapping of properties to external vocabulary terms (e.g. Schema.org), and dereferenceable register/schema `@context` document endpoints. Scope is read-side output only — JSON-LD ingest is explicitly excluded.Linked Entity Types@e2e exclude backend schema property type extension — covered by PHPUnitMail Sidebar@e2e exclude Nextcloud Mail IMailProvider backend — covered by PHPUnitMail Smart Picker@e2e exclude Nextcloud Smart Picker IReference backend — covered by PHPUnitMariaDB Support & Dual-Database CI Matrix@e2e exclude CI infrastructure spec — no UI surfaceMock Registers@e2e exclude seed-data/configuration backend — covered by PHPUnitnextcloud-api-compat@e2e exclude NC34 API compat backend — covered by PHPUnit TBD - created by archiving change fix-nc34-server-accessor-removals. Update Purpose after archive.nextcloud-entity-relations@e2e exclude backend entity relation mapper — covered by PHPUnit TBD - created by archiving change nextcloud-entity-relations. Update Purpose after archive.OAS Generation@e2e exclude backend OAS generation service — covered by PHPUnitOAS Validation@e2e exclude backend OAS validation — covered by PHPUnit Ensure that `OasService::createOas()` produces valid OpenAPI 3.1.0 JSON that passes Redocly CLI lint without errors. The current output may contain invalid property structures, broken `$ref` references, or non-compliant schema compositions that cause tools like Redocly, Swagger UI, and Swagger Editor to fail.Object Interactions@e2e exclude REST API convenience layer — covered by NewmanObject Lifecycle@e2e exclude internal object pipeline backend — covered by PHPUnitoffice-document-sanitizationSanitises DOCX and ODT documents during anonymisation by removing hidden and identifying content without mutating the original file. Strips comments and tracked changes (accepting inserts, dropping deletions), custom-XML data bindings, person-identity field codes, and hyperlink URLs, and replaces metadata fields with a `DocuDesk Anonymisation` sentinel while preserving timestamps and visible text. Produces a PII-free `SanitizationReport` persisted on the anonymisation log, guarantees the output opens cleanly in Word and LibreOffice, and raises a typed `SanitizationException` for encrypted or unsupported inputs.OpenAPI Generation@e2e exclude backend OpenAPI generation — covered by PHPUnit Auto-generate OpenAPI 3.1.0 specifications from register and schema definitions stored in OpenRegister, producing complete API documentation that covers every CRUD endpoint, query parameter, authentication scheme, and response model. The generated spec MUST be downloadable in JSON and YAML formats, serveable via an interactive Swagger UI, and MUST regenerate automatically when schemas change so that documentation never drifts from the live API surface. The generation pipeline MUST also support NL API Design Rules compliance markers for Dutch government API interoperability.OpenRegister app-manifest capabilityDefine OpenRegister's adoption of the JSON-driven app-manifest pattern published by `@conduction/nextcloud-vue` (ADR-024). OR ships a single `src/manifest.json` that declares its full shell — menu items, route → page mapping, and per-page configuration — and mounts that manifest through `CnAppRoot` + `CnPageRenderer` so the runtime renders the entire app from data instead of from bespoke `App.vue`/`router/index.js` boilerplate.Orphan Auth RemediationHydra gate 6 (`orphan-auth`) flags public authorization/validation methods (`is*/requires?*/validate*/authorize*/check*/ensure*/verify*/assert*`) that are DEFINED but have zero callers on any live path. A defined-but-uncalled auth method is identical to having no check at all (OWASP A01:2021) OR is dead code that falsely signals a second guard. This capability records how OpenRegister resolves such findings: a duplicate of a proven live check is removed; a non-authorization value-object predicate or a deliberately-deferred opt-in validator is left in place and documented — never force-wired or force-deleted.pdf-anonymisationAnonymises PDF documents by rewriting their content streams in place rather than corrupting bytes via naive string replacement. Decodes the text-relevant PDF 1.7 filter set, resolves font encodings (including Identity-H composite fonts via ToUnicode CMaps), flattens kerning arrays, and replaces every variant of a detected entity with an identifiable `[<TYPE>: <id>]` placeholder while preserving table and layout structure and scrubbing metadata to a sentinel. A post-replacement validation gate re-extracts the output and discards it if any entity text survives; image-only PDFs defer to OCR and encrypted PDFs are rejected. The capability extends the existing anonymise endpoint with no new routes and no changes to the DOCX/ODT/text branches.pdf-anonymisation-odt-fallbackAdds an opt-in fallback (Path B) that retries PDF anonymisation by converting the document through ODT via NC Office when the primary path's strict-mode validation gate fails. It is gated per-tenant by a feature flag (default off) and bridge availability, so the v1 fail-closed behaviour is preserved by default, and it never triggers for encrypted-PDF or text-layer-missing reasons. On failure it raises a PII-free `validation_failed_after_fallback` exception whose diagnostic identifies only the failed stage and exception class.Platform Administration ModalsDescribes the administrator-facing modal dialogs that configure OpenRegister's platform-level infrastructure (SOLR search backend, LLM provider wiring, configuration sets, collection assignments, vectorization, faceting, file management) and that drive long-running operational tasks (cache clear, index warmup, mass validation, index inspection, SOLR setup). Unlike the entity-management modals — which mutate user data via per-entity stores — these modals read and write platform settings via `/api/settings/*` REST endpoints and dispatch background operational jobs.Profile Actions@e2e exclude REST API endpoint contracts — covered by Newmanrbac-zaaktype@e2e exclude backend RBAC enforcement — covered by PHPUnit Implement role-based access control (RBAC) at the zaaktype (case type) and objecttype level. Users and groups MUST only access records belonging to types they are authorized for. This covers read, write, and delete permissions scoped to specific register schema combinations, enabling fine-grained data compartmentalization across departments.Realtime Updates@e2e exclude SSE/server-push backend — covered by PHPUnit and Newman Provide live data synchronization to connected clients so that register object mutations (create, update, delete) are pushed immediately without manual page refresh. The system MUST offer Server-Sent Events (SSE) as the primary transport, with Nextcloud's notify_push integration as a complementary channel, and graceful fallback to polling. All realtime channels MUST be authorization-aware, meaning users only receive events for objects their RBAC permissions allow them to see, and MUST support topic-based subscriptions at the register, schema, and individual object level.reference-existence-validation@e2e exclude backend schema property validation — covered by PHPUnit TBD - created by archiving change reference-existence-validation. Update Purpose after archive.Referential Integrity@e2e exclude backend referential integrity enforcer — covered by PHPUnit Enforce referential integrity between register objects connected via `$ref` schema properties so that modifications or deletions of referenced objects propagate correctly according to configurable integrity actions (CASCADE, SET_NULL, SET_DEFAULT, RESTRICT, NO_ACTION). The system MUST maintain data consistency across schemas, detect circular reference chains, support cross-register references, and provide auditable, transactional enforcement that prevents orphaned references while respecting performance constraints on deep reference graphs.Register InternationalizationImplement multi-language content management for register objects so that translatable properties store per-language variants, APIs negotiate content language via Accept-Language headers, and the UI provides language-aware editing with completeness tracking. The system MUST support at minimum Dutch (NL, required) and English (EN, optional) to comply with Single Digital Gateway (SDG) Regulation (EU) 2018/1724 for cross-border EU service access, while the architecture MUST allow registers to configure any number of BCP 47 languages including RTL scripts. This spec covers data-level i18n for register object content -- it is distinct from the app UI string translations governed by `i18n-infrastructure`, `i18n-string-extraction`, `i18n-backend-messages`, and `i18n-dutch-translations` specs, which handle Nextcloud `IL10N` / `t()` / `$l->t()` for interface labels.register-resolver-serviceProvide a single, DI-resolvable PHP service in OpenRegister that consumer apps use to resolve `<context>_register` / `<context>_schema` `IAppConfig` keys into either bare slug/UUID strings or hydrated `Register` / `Schema` entities, with consistent error semantics, request-scoped caching, and multi-tenant scoping. Replaces the duplicated `getValueString(...)` + manual mapper-lookup pattern observed in 13 call sites across opencatalogi (5 controllers), pipelinq (8 services / jobs), and docudesk (`OpenRegisterResolver`).register-service-extensionsExposes serialized `RegisterService` query methods (`findAllSerialized` and `findSerialized`) that apply `_extend` transformations so DI callers get the same payload as the `RegistersController::index()` endpoint. Supports expanding schema IDs into full schema objects and attaching per-schema `@self.stats` object counts, while retaining orphan schema IDs in place on hydration failure, ignoring unknown `_extend` keys silently, and keeping the `Register` entity's serialization ID-only. The expansion logic moves out of the controller into a dedicated `RegisterSerializer` under the `OCA\OpenRegister\Service\Serializer` namespace.Retention Management@e2e exclude backend MDTO retention lifecycle — covered by PHPUnit Implement retention lifecycle management for register objects: MDTO-compliant archival metadata, selectielijsten, archiefactiedatum calculation, destruction scheduling with approval workflows, legal holds, and notifications per Archiefwet 1995.Row and Field Level Security@e2e exclude backend RLS/FLS enforcement — covered by PHPUnit Implement dynamic per-record access rules based on field values (row-level security / RLS) and per-field visibility and editability rules based on user roles (field-level security / FLS). Beyond schema-level RBAC that controls access to entire object types, the system MUST support row-level security where access to individual objects depends on the object's own properties (e.g., department, classification level, owner), and field-level security where different users see different fields of the same object. Both security layers MUST be enforced consistently across REST, GraphQL, search, export, and MCP access methods, evaluated at the database query level where possible for performance, and composable with schema-level RBAC and multi-tenancy isolation.runtime-schema-apiProvides runtime CRUD on registers and schemas so that creating, updating, or deleting a schema or register immediately invalidates the relevant cache and re-binds the affected declarative engines (lifecycle, aggregations, calculations, notifications) without a restart. Deletions are guarded by object counts and refuse with HTTP 409 unless forced, and slug-pairs are resolved to numeric IDs at the slug-aware layer for object search and application-config imports.saas-multi-tenantManages per-tenant HMAC signing keys for multi-tenant deployments, guaranteeing each tenant has exactly one active key that is stored encrypted via Nextcloud's crypto service and bootstrapped or rotated through a single write path. The service is DI-registered for server-side use only — used by audit-trail and evidence signers — and never exposes plaintext key material over REST, in logs, or in audit output.Schema-Driven Read Coercion@e2e exclude backend type coercion service — covered by PHPUnit Defines how OpenRegister coerces database column values to JSON-Schema-typed PHP values when reconstructing an `ObjectEntity` from a magic-table row. Establishes a single canonical converter (`SchemaTypeConverter`) that all read paths delegate to, eliminating the class of bugs where the schema declares one type but the API returns another — `boolean` properties arriving as `int 0`/`1` from MariaDB, or `string` properties whose values look like JSON literals being silently decoded back into the original primitive.Schema Hooks@e2e exclude backend webhook/hook delivery — covered by PHPUnit and Newman Schema hooks enable per-schema configuration of workflow callbacks that fire on object lifecycle events, allowing external systems to validate, enrich, transform, or reject data before or after persistence. Hooks use CloudEvents 1.0 structured content mode for payloads, support synchronous (request-response) and asynchronous (fire-and-forget) delivery modes, and provide configurable failure behavior (reject, allow, flag, queue) so administrators can balance data integrity against availability. The hook system is engine-agnostic through the `WorkflowEngineInterface` abstraction, currently supporting n8n and Windmill adapters, and integrates deeply with Nextcloud's PSR-14 event dispatcher via `StoppableEventInterface` for pre-mutation rejection.schema-importImports register schemas from external vocabulary standards — Schema.org types and GGM (Gemeentelijk Gegevensmodel) objecttypes — out of bundled versioned snapshots or uploaded export files, mapping each standard's datatypes, descriptions, and reference lists into JSON Schema and pre-filling JSON-LD term mappings. Importable types are discoverable by search, schema uploads are dialect-aware and reject unidentifiable input, and every imported schema records its provenance so it can be re-imported with a guarded diff preview that preserves local additions and flags conflicts.schema-migrationManages schema versioning and object migration by classifying every schema definition change as compatible or breaking, recording a typed changelog with the matching version bump, and stamping objects with the schema version they validated against. Provides non-mutating revalidation runs for impact analysis, declarative migration plans that transform an object population through the standard save pipeline with rollback via content versioning, and a gate that refuses breaking changes without explicit acknowledgement across every update path.schema-property-exploration@e2e exclude backend schema introspection service — covered by PHPUnit TBD - created by archiving change retrofit-2026-05-25-bw2-svc-flat-3. Update Purpose after archive.Schema-Scoped Reference Providers@e2e exclude backend Smart Picker / unified-search provider base classes — covered by PHPUnitSearch Index@e2e exclude backend Solr/search index service — covered by PHPUnitSearch Trail RecordingOpenRegister records a *search trail* — the term searched, the result and total counts, the response time, and the execution backend — for paginated searches so that the dashboard's "Popular Search Terms" widget and "Searches" KPI have data to display. The read side (`SearchTrailService`, `SearchTrailMapper`, popular-terms and statistics aggregations) already existed; this capability supplies the write path that feeds it.self-folder-access-controlEnforces a default-deny access check on every numeric `@self.folder` bind so an object is only attached to a Nextcloud folder when the acting user can actually read it. Any unreadable, non-existent, file, or trashed target — or any inability to confirm readability — aborts the save with a `FolderAccessDeniedException` mapped to HTTP 403 and an audit-trail entry, while empty or legacy non-numeric folder values preserve the existing auto-create behaviour for cron and seed paths.Semantic Object Handoff (Engine)The OR-owned semantic-object-handoff engine (ADR-051): cross-app workflows hand objects over via canonical semantic kinds, declared on the source schema through the `x-openregister-handoff` dialect, bound on the implementing schema through `handoffContract`, executed by `HandoffService` on top of `SemanticTypeResolver` with RBAC, provenance relations, immutable audit, ADR-041 events, and hide/queue degradation. Mirrors the hydra contract spec `hydra/openspec/changes/semantic-object-handoff/specs/semantic-object-handoff/spec.md` 1:1 so the OR main spec and the cross-app contract cannot drift.settings-managementManages OpenRegister configuration across all domains (LLM, File, Object, Retention, Archival, SOLR, search backend, RBAC, Multitenancy, Organisation, n8n, Publishing) through a sliced typed get/update pattern that persists each domain as a JSON blob in IAppConfig with defaults backfill and PATCH-merge semantics. A thin SettingsService facade delegates each domain to a dedicated handler and additionally orchestrates cache statistics and clearing, mass object validation in serial or parallel batch jobs, environment introspection, and configuration rebase.shared-ui-componentsProvides reusable OpenRegister frontend components with well-defined contracts: a pagination component that clamps page-change requests to the valid range, a ConfigurationCard that detects already-imported discovered configurations via a backend lookup on mount, a collapsible settings card that emits its toggle state, and a settings section that escapes HTML in detailed descriptions to prevent XSS.skos-concept-registers@e2e exclude backend vocabulary registers + import + resolution API — covered by PHPUnit (leaf-side consumption UIs ship their own e2e in the leaf repos).tables-virtual-registerExpose Nextcloud Tables tables as read-only **virtual registers**: each Tables table (or Tables View) becomes an auto-seeded Schema under a `tables` Register, and rows are served live through the existing object-source-provider seam (`x-openregister-object-source`, ADR-049 mechanism) — no copy or sync. Tables column types are mapped to JSON Schema (text/number/datetime/selection/usergroup; relation columns resolve to the referenced virtual object's deterministic UUIDv5), RBAC is delegated to Tables via the acting user (denied == absent, anti-oracle parity), the provider fails closed when the Tables app is missing/disabled, and writes are rejected as a read-only projection.Tenant Isolation Audit@e2e exclude backend audit/isolation verification — covered by PHPUnit Define cross-tenant access audit logging, isolation verification, and automated isolation testing to ensure that tenant boundaries are never breached in a SaaS deployment. This provides the evidence trail required for BIO/ISO 27001 compliance and builds confidence that the shared-database multi-tenancy model provides adequate isolation.Tenant Lifecycle@e2e exclude backend Organisation state machine — covered by PHPUnit Define the provisioning, suspension, and deprovisioning workflow for tenant organisations in a SaaS multi-tenant OpenRegister deployment. Each tenant maps to an Organisation entity with a lifecycle state machine that governs API access, data retention, and administrative operations.Tenant Quotas@e2e exclude backend quota enforcement service — covered by PHPUnit Define enforcement of per-organisation resource quotas (storage, bandwidth, API requests) to prevent any single tenant from monopolizing shared resources in a SaaS deployment. The Organisation entity already has `storageQuota`, `bandwidthQuota`, and `requestQuota` fields; this spec defines their enforcement, tracking, and overage handling.text-extraction@e2e exclude backend text extraction service — covered by PHPUnit TBD - created by archiving change retrofit-2026-05-25-bw-svc-mid2. Update Purpose after archive.text-extraction-emlExtracts text from `message/rfc822` (EML) email files, producing both a flat plain-text output — ordered headers, body, and recursively-extracted attachment text — and a structured `EmlStructure` value object exposing parsed headers, plain/HTML bodies, and per-attachment metadata. Nested EML is recursed to depth 3, RFC 2047 encoded-words are decoded, non-UTF-8 bodies are transcoded best-effort, and the extraction never logs PII while failing gracefully on malformed input.text-extraction-wordExtracts complete text from Word-family documents (DOCX, legacy DOC, ODT) by recursively walking every element — including table cells and nested tables, section headers and footers, and footnotes and endnotes — and selecting the correct PhpWord reader from the input MIME or extension. The recursive walker is depth-guarded against pathological nesting, reader or load failures return null gracefully rather than aborting, and failure logs never contain document content.tmlo-auto-populate@e2e exclude backend TMLO auto-populate handler — covered by PHPUnit TBD - created by archiving change tmlo-metadata. Update Purpose after archive.tmlo-export@e2e exclude backend MDTO/XML export service — covered by PHPUnit TBD - created by archiving change tmlo-metadata. Update Purpose after archive.tmlo-metadata@e2e exclude backend TMLO metadata foundation — covered by PHPUnittmlo-metadata-schema@e2e exclude backend TMLO schema fields — covered by PHPUnit TBD - created by archiving change tmlo-metadata. Update Purpose after archive.tmlo-query-api@e2e exclude backend TMLO query/summary API — covered by Newman Provides query and summary API endpoints for filtering and aggregating objects by their TMLO archival metadata. Recovered from the archived tmlo-metadata change on 2026-05-02 — the archive operation created the spec directory but never moved the canonical spec.md across. Sibling specs (tmlo-export, tmlo-auto-populate, tmlo-metadata-schema) landed cleanly; this one was orphaned.tmlo-register-toggleControls whether objects in a register carry TMLO archival metadata via a `tmloEnabled` flag in the register's configuration. When enabled, new and updated objects receive TMLO metadata fields seeded from the schema's configured `tmloDefaults` (classification, archival nomination, retention period, destruction category), with `archiefstatus` defaulting to `actief`.tmlo-validationValidates TMLO archival metadata on objects, enforcing the allowed archival-status transition path (actief → semi_statisch → overgebracht or vernietigd) with the required fields and `archiefnominatie` value for each step. It also validates individual TMLO field values against their allowed enums and formats (archiefnominatie, archiefstatus, ISO-8601 retention durations and action dates), rejecting violations with a 422 error.URN Resource Addressing@e2e exclude backend URN/URL resolver — covered by PHPUnitverwerkingsregister-api@e2e exclude GDPR verwerkingsregister REST API — covered by Newman GDPR Art 30 processing register API for querying processing activities, generating data subject access reports (inzageverzoek), and exporting the verwerkingsregister. Enables compliance auditing for Dutch government organisations.Webhook Payload Mapping@e2e exclude backend webhook delivery/mapping — covered by PHPUnit Extend OpenRegister's existing CloudEvent-based event and webhook infrastructure with configurable payload mapping. The core webhook delivery (WebhookService, WebhookDeliveryJob, CloudEventFormatter) is already implemented. This spec focuses on the Mapping entity integration for payload transformation, advanced filtering, and delivery management. It documents the complete webhook lifecycle as already implemented: registration with URL/events/secret, payload format selection (standard, CloudEvents, Twig-mapped), delivery retry with exponential backoff, delivery logging, HMAC authentication, event filtering by register/schema/conditions, webhook management API, testing/dry-run, async delivery via background jobs, health monitoring through statistics, multi-tenant webhook isolation via organisation scoping, and request interception for pre-event webhooks. The Mapping entity reference allows any subscriber to receive events in whatever format they require (ZGW notifications, FHIR events, CloudEvents, VNG Notificaties API, custom formats) without any hardcoded format knowledge in OpenRegister.Workflow Engine Abstraction@e2e exclude backend workflow engine adapter — covered by PHPUnitWorkflow in Import@e2e exclude backend import/workflow deploy pipeline — covered by PHPUnitWorkflow Integration@e2e exclude backend n8n/workflow trigger service — covered by PHPUnit Integrate BPMN-style workflow automation with register operations via n8n (primary) and other pluggable workflow engines (Windmill, future). Register events (create, update, delete, status change) MUST trigger configurable workflows for process automation, enrichment, validation, escalation, approval chains, and scheduled tasks. The integration MUST support zero-coding workflow configuration for functional administrators and provide full observability into workflow executions via logging, status tracking, and audit trails.workflow-operations@e2e exclude backend workflow execution history — covered by PHPUnit TBD - created by archiving change workflow-operations. Update Purpose after archive.