diff --git a/.specter-prompt.txt b/.specter-prompt.txt index 9e9c494d..985aaebe 100644 --- a/.specter-prompt.txt +++ b/.specter-prompt.txt @@ -4,8 +4,8 @@ You are running HEADLESS. Do NOT use AskUserQuestion, interactive prompts, or sk Write files directly using the Write tool. ## Inputs -- Change: p2-meeting-management-other-t1 (title: Meeting Management — Other T1) -- Context brief: openspec/changes/p2-meeting-management-other-t1/context-brief.md +- Change: p2-meeting-management-other-t2 (title: Meeting Management — Other T2) +- Context brief: openspec/changes/p2-meeting-management-other-t2/context-brief.md - Data model ADR: openspec/architecture/adr-000-data-model.md Governance Domains: @@ -29,13 +29,13 @@ Project guidelines: See ../project.md for workspace-wide standards **Spec type:** capability ## Step 1: Read context Read these files COMPLETELY before writing anything: -- openspec/changes/p2-meeting-management-other-t1/context-brief.md (features, stories, stakeholders, journeys) +- openspec/changes/p2-meeting-management-other-t2/context-brief.md (features, stories, stakeholders, journeys) - openspec/architecture/adr-000-data-model.md (entity definitions) - All files in openspec/architecture/ (app ADRs) - All files in .claude/openspec/architecture/ (company ADRs, if present) ## Step 2: Get artifact templates -Run: `openspec instructions proposal --change p2-meeting-management-other-t1 --json` +Run: `openspec instructions proposal --change p2-meeting-management-other-t2 --json` This returns the template and rules for the proposal artifact. Then do the same for: design, specs, tasks (in that order). @@ -54,8 +54,8 @@ For each artifact (proposal → design → specs → tasks): ## Step 4: Commit After all 4 artifacts are written: ```bash -git add openspec/changes/p2-meeting-management-other-t1/ -git commit -m 'feat: Add OpenSpec change p2-meeting-management-other-t1 from Specter' +git add openspec/changes/p2-meeting-management-other-t2/ +git commit -m 'feat: Add OpenSpec change p2-meeting-management-other-t2 from Specter' ``` Do NOT push — the caller handles pushing. Do NOT create branches — stay on the current branch. diff --git a/openspec/changes/p2-meeting-management-other-t2/.openspec.yaml b/openspec/changes/p2-meeting-management-other-t2/.openspec.yaml new file mode 100644 index 00000000..3a54a172 --- /dev/null +++ b/openspec/changes/p2-meeting-management-other-t2/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-04-16 diff --git a/openspec/changes/p2-meeting-management-other-t2/context-brief.md b/openspec/changes/p2-meeting-management-other-t2/context-brief.md new file mode 100644 index 00000000..9461ede9 --- /dev/null +++ b/openspec/changes/p2-meeting-management-other-t2/context-brief.md @@ -0,0 +1,2856 @@ +# Context Brief: Meeting Management — Other T2 + +**App:** Decidesk — Universal decision-making platform for governance bodies, associations, corporate boards, and operational meetings +**Spec:** p2-meeting-management-other-t2 +**Platform:** Nextcloud + OpenRegister + +**Depends on:** p2-meeting-management + +## Dependency Specs (content) + +These specs were already decided/implemented. Use them as context. + +### p2-meeting-management +# Context Brief: Meeting Management + +**App:** Decidesk — Universal decision-making platform for governance bodies, associations, corporate boards, and operational meetings +**Spec:** p2-meeting-management +**Platform:** Nextcloud + OpenRegister + +**Depends on:** p1-schemas-and-data-model, p1-dashboard-and-navigation, p1-crud-operations + +## Dependency Specs (content) + +These specs were already decided/implemented. Use them as context. + +### p1-schemas-and-data-model +# Context Brief: Schemas and Data Model + +**App:** Decidesk — Universal decision-making platform for governance bodies, associations, corporate boards, and operational meetings +**Spec:** p1-schemas-and-data-model +**Platform:** Nextcloud + OpenRegister + +## Features (6 total, sorted by market demand) + +### Resolution Register +**demand: 206** (66 tender mentions) | Category: core + +### Identity Governance Management +**demand: 91** (27 tender mentions) | Category: governance + +### Register to speak at committee meeting +**demand: 56** (18 tender mentions) | Category: core + +### Voter Register +**demand: 26** (6 tender mentions) | Category: other + +### Attendance Register +**demand: 26** (6 tender mentions) | Category: other + +### Link emails to specific decisions via OpenRegister _mail metadata +**demand: unknown** | Category: other + +## User Stories (6 linked) + +### Story 1: Configure SAML 2.0 identity provider +**Priority:** should +As an IAM administrator, I want to configure a SAML 2.0 identity provider using a metadata XML file, so that I can integrate with government identity federations that do not support OIDC. + +**Acceptance Criteria:** +GIVEN the IdP configuration screen WHEN I upload a SAML metadata XML file THEN the entity ID, SSO URL, and signing certificate are parsed and pre-filled +GIVEN a saved SAML configuration WHEN I download the OpenRegister service provider metadata THEN I receive a valid SAML metadata XML I can import into the identity provider + +### Story 2: View provenance and update metadata for a dataset +**Priority:** should +As a researcher, I want to view the provenance metadata of a register dataset including its source organisation, data steward, creation date, and last update timestamp, so that I can assess whether the dataset is authoritative and current enough for my research. + +**Acceptance Criteria:** +GIVEN a public register WHEN I open the dataset information page THEN I see the responsible organisation (OIN), data steward contact, creation date, last modified timestamp, and the update frequency commitment +GIVEN the dataset page THEN it links to the processing register entry and any applicable open data licence + +### Story 3: Link Nextcloud Mail emails to invoices +**Priority:** must-have +As a Nextcloud user, I want to link emails from Nextcloud Mail to invoice/expense records using OpenRegister _mail metadata, creating a native email-to-invoice connection. + +### Story 4: Link to Nextcloud Contacts +**Priority:** must-have +As a Nextcloud user, I want invoicing contacts to sync with Nextcloud Contacts via OpenRegister _contacts metadata, so I have one unified address book. + +### Story 5: Link emails to specific decisions via OpenRegister _mail metadata +**Priority:** must +As a decision maker, I want emails related to a decision to be automatically linked via the _mail metadata column so that all correspondence is part of the decision dossier and visible in the Mail app sidebar. + +**Acceptance Criteria:** +GIVEN an email mentioning a decision reference number WHEN the email is received THEN it appears linked to the decision object in OpenRegister AND is visible in the Nextcloud Mail sidebar + +### Story 6: Unsubscribe directly from email +**Priority:** must +As a subscriber, I want to unsubscribe from a mailing list by clicking a single link in the email footer, so that I stop receiving unwanted emails immediately. + +**Acceptance Criteria:** +Unsubscribe link visible in email footer; single click completes unsubscribe (no login required); confirmation page shown; no further emails sent from that list + +## Customer Journeys (15 linked) + +### AV & Webcast Infrastructure Management +Managing AV infrastructure in raadzaal and commissiekamers. Discussion systems, PTZ cameras, AV control, webcast/streaming, microphone management. +**Trigger:** Meeting scheduled requiring AV support; system maintenance/upgrade +**Desired outcome:** Reliable AV infrastructure supporting meetings with high-quality recording and streaming +**Current pain:** Complex multi-vendor systems; AV-RIS integration for indexing; maintenance windows; high costs; rapid tech evolution +**Frequency:** Every meeting (setup/support) + periodic maintenance + +### Handle Complex Multi-Domain Citizen Question +A citizen has a question spanning multiple domains (e.g., housing benefit, parking permit, and social assistance). The front desk officer creates linked zaken or a combined intake and routes each to the correct department. +**Trigger:** Citizen presents with multiple interconnected service needs in a sing +... (truncated) + +## Features (6 total, sorted by market demand) + +### School Attendance Zone Visualization +**demand: 1** | Category: other + +### speech recognition meetings +**demand: 1** | Category: other + +### Virtual-Only Meeting Support +**demand: 1** | Category: other + +### meeting-participant-list-limit +**demand: unknown** | Category: general +Discovered from GitHub issue in [competitor]/[competitor] + +### meeting-space-indicator +**demand: unknown** | Category: general +Discovered from GitHub issue in [competitor]/[competitor] + +### Track event attendance +**demand: unknown** | Category: other + +## User Stories (1 linked) + +### Story 1: Claim a task from the shared inbox +**Priority:** must +As a municipal employee, I want to claim a task from the shared inbox and assign it to myself, so that my colleagues know it is being handled and avoid duplicate work. + +**Acceptance Criteria:** +GIVEN an unclaimed task is in the shared inbox +WHEN I click 'Claim' +THEN the task is assigned to me and removed from the unclaimed inbox view + +GIVEN another employee has already claimed the task +WHEN I try to claim the same task +THEN the system prevents the double claim and shows who has claimed it + +## Customer Journeys (15 linked) + +### Water Board General Assembly Meeting +Water board general assembly meets at least 6x/year. Sets policy, approves budgets, oversees executive board. Chaired by dijkgraaf. Secretary-director maintains minutes. +**Trigger:** Scheduled general assembly meeting (minimum 6x/year) +**Desired outcome:** Policy decisions made, budgets approved, oversight exercised, complete minutes maintained +**Current pain:** Similar needs as municipalities but different governance; fewer commercial RIS options; unique stakeholder categories +**Frequency:** Minimum 6 times per year (general assembly); bi-weekly (executive board) + +### Collaborate on Work Package +Team members coordinate on a bounded work package, sharing progress, flagging blockers, and updating task statuses visible to the project manager. +**Trigger:** Work package assigned at start of sprint or project phase +**Desired outcome:** Work package completed on time with transparent progress visible to the project manager at all times +**Current pain:** Collaboration happens in chat tools with no link back to project plans, making progress invisible to managers +**Frequency:** daily + +### Open Data Publication (ORI) +Publishing council information as open data following the ORI standard. API access, linked data, integration with PLOOI. Over 100 Dutch municipalities participate. +**Trigger:** New meeting data or documents are published in the RIS +**Desired outcome:** Council data available as structured open data via standardized API, compliant with ORI and Woo +**Current pain:** Vendor-specific connectors required; inconsistent data quality; evolving standard; limited real-time capability +**Frequency:** Continuous (automated sync) + +### AV & Webcast Infrastructure Management +Managing AV infrastructure in raadzaal and commissiekamers. Discussion systems, PTZ cameras, AV control, webcast/streaming, microphone management. +**Trigger:** Meeting scheduled requiring AV support; system maintenance/upgrade +**Desired outcome:** Reliable AV infrastructure supporting meetings with high-quality recording and streaming +**Current pain:** Complex multi-vendor systems; AV-RIS integration for indexing; maintenance windows; high costs; rapid tech evolution +**Frequency:** Every meeting (setup/support) + periodic maintenance + +### RIS Platform Migration & Transition +Migrating from one RIS to another including data migration of historical records, user transition, integration reconfiguration, and training. +**Trigger:** Contract expiration, dissatisfaction with current RIS, or need for new features +**Desired outcome:** Successful migration with complete data transfer, minimal disruption, and satisfied users +**Current pain:** Complex data migration from proprietary formats; risk of data loss; user resistance; training needs; vendor lock-in +**Frequency:** Every 4-8 years (contract cycles) + +### Review Programme Risk Landscape +The program director reviews the aggregated risk picture across all projects in the programme to identify systemic risks and interdependencies that individual projects cannot resolve alone. +**Trigger:** Programme steering committee meeting or a cluster of related risks emerges +**Desired outcome:** Consolidated risk heatmap at programme level with clear ownership and mitigation responsibilities +**Current pain:** No automated aggregation exists; the programme risk view must be manually assembled from individual project risk logs +**Frequency:** monthly + +### Presidium Agenda Setting +The presidium (faction leaders + chair) meets to set the agenda. Decides which items go to which committee, hamerstuk vs bespreekstuk, and overall meeting planning. +**Trigger:** Scheduled presidium meeting at start of each meeting cycle +**Desired outcome:** Approved agenda with clear assignment of items to committees and plenary +**Current pain:** Manual compilation of agenda proposals; difficulty balancing workload across committees +**Frequency:** Every meeting cycle (approximately every 3-4 weeks) + +### Faction Position Coordination +Faction leader coordinates positions on upcoming agenda items through faction meetings. Distributes preparatory work, aligns voting positions, assigns spokespersons. +**Trigger:** Publication of agenda for upcoming council/committee meeting +**Desired outcome:** Aligned faction positions on all agenda items, assigned spokespersons, coordinated motion/amendment strategy +**Current pain:** Fragmented communication tools; no shared workspace; difficulty tracking faction-wide positions across multiple agenda items +**Frequency:** Weekly during active meeting periods + +### Press Coverage & Media Access +Journalists access council meetings, documents, and officials for reporting. Includes press pass registration, gallery access, post-meeting briefings, and RIS research. +**Trigger:** Newsworthy item on council agenda or need for background research +**Desired outcome:** Journalist can efficiently access all public council information, attend meetings, contact officials +**Current pain:** Complex registration; limited press facilities; restrictions on filming/quoting; delayed recordings; declining journalism resources +**Frequency:** Continuous (more intense around plenary meetings) + +### System Integration & Data Exchange +Managing integrations between RIS and other systems: zaaksysteem, DMS, AV/webcast, archiving, PLOOI platform. +**Trigger:** New system implementation, upgrade, or integration requirement +**Desired outcome:** Seamless data flow between RIS and connected systems with no manual re-entry +**Current pain:** Legacy APIs; proprietary interfaces; vendor lock-in; complex AV integration; multiple auth systems +**Frequency:** Ongoing (initial setup + continuous maintenance) + +### Meeting Recording Publication +Video and audio recordings processed, indexed (linked to agenda items), captioned, and published in RIS for on-demand viewing. +**Trigger:** Completion of a recorded meeting +**Desired outcome:** Indexed, accessible recordings published and linked to relevant agenda items in the RIS +**Current pain:** Long processing times; manual indexing; accessibility requirements (captions); large file storage +**Frequency:** After every recorded meeting + +### Live Meeting Following & Webcasting +Citizens and journalists follow meetings in real-time, physically or via live webcast/stream. Includes viewing agenda in real-time and tracking which item is being discussed. +**Trigger:** Council or committee meeting is in session +**Desired outcome:** Interested parties can follow the meeting in real-time with access to relevant documents +**Current pain:** Webcast quality varies; no real-time agenda tracking; difficult to find relevant document during live viewing; no live captions +**Frequency:** Every public meeting (3-6 per month) + +### Provincial States Meeting Cycle +Provincial States follow similar BOB model but larger scale. CdK chairs, griffier supports, factions coordinate through presidium. State proposals through statencommissies before statendag. +**Trigger:** Monthly meeting cycle of provincial states +**Desired outcome:** Provincial policy decisions made through structured committee and plenary process +**Current pain:** Similar to municipal pain points but larger scale; more formal procedures +**Frequency:** Monthly (statendag) plus committee meetings + +### Log Time and Availability +Team members record actual hours worked per project and flag upcoming unavailability so planners can keep capacity forecasts accurate. +**Trigger:** Weekly timesheet deadline or employee requests leave +**Desired outcome:** Accurate, up-to-date actuals feeding directly into capacity and cost forecasts without duplication +**Current pain:** Time is logged in a separate HR system and must be manually reconciled with project actuals in spreadsheets +**Frequency:** weekly + +### [competitor] External Supplier +The program director manages the onboarding of an external supplier into the project environment, granting scoped access to documents, tasks, and communication channels. +**Trigger:** Contract signed with an external party and work is about to commence +**Desired outcome:** External supplier operational in the project environment within 2 working days with correctly scoped access +**Current pain:** Onboarding involves multiple IT requests and manual coordination; suppliers often wait days before they can start +**Frequency:** ad-hoc + +## Stakeholders (48 linked) + +### CEO / Managing Director +Chief Executive Officer or managing director responsible for day-to-day management of the company. In Dutch two-tier model, member of the Raad van Bestuur (management board). +**Responsibilities:** Setting corporate strategy, executing board decisions, representing the company externally, reporting to supervisory board, preparing annual accounts, convening shareholder meetings +**Pain points:** Complex approval chains for strategic decisions, balancing stakeholder interests, ensuring compliance with Dutch Corporate Governance Code, managing conflict of interest declarations, coordinating between management board and supervisory board +**Goals:** Efficient decision-making processes, clear audit trails for all governance decisions, streamlined communication with supervisory board and shareholders, digital-first governance workflows + +### Board Secretary / Company Secretary +Corporate governance professional who manages all governance processes, board meetings, minutes, compliance, and stakeholder communication. Guardian of governance procedures and compliance. +**Responsibilities:** Preparing board packs and agendas, taking and distributing minutes, managing governance calendar, ensuring quorum, advising on governance procedures, maintaining corporate registers, coordinating AGM logistics, filing with KVK/AFM +**Pain points:** Manual board pack assembly, version control of sensitive documents, tracking action items across multiple boards and committees, ensuring timely distribution, managing multiple meeting calendars, paper-based minute signing processes +**Goals:** Digital board portal with secure document distribution, automated meeting scheduling and reminders, electronic minute approval workflows, integrated governance calendar, real-time action item tracking + +### Supervisory Board Chair +Chair of the supervisory board (Raad van Commissarissen) in Dutch two-tier governance model. Leads supervisory oversight, sets RvC agenda, and maintains relationship with management board. +**Responsibilities:** Chairing supervisory board meetings, setting RvC agenda, appointing committee chairs, leading board evaluations, maintaining dialogue with CEO and shareholders, ensuring proper governance, managing conflicts of interest within RvC +**Pain points:** Limited visibility into management decisions between meetings, difficulty coordinating dispersed supervisory board members, managing information asymmetry with management board, ensuring all members are adequately informed +**Goals:** Secure digital workspace for supervisory board, real-time access to management information, efficient virtual meeting capabilities, structured oversight and approval workflows + +### Supervisory Board Member +Individual member of the supervisory board. Provides oversight, advice, and approval on management decisions. May serve on audit, remuneration, or nomination committees. +**Responsibilities:** Attending supervisory board and committee meetings, reviewing management decisions, approving major transactions and appointments, monitoring risk management, evaluating management board performance +**Pain points:** Information overload from board packs, limited time for preparation, difficulty accessing documents on mobile devices, lack of annotation and collaboration tools, managing multiple board memberships +**Goals:** Mobile-friendly board portal with offline access, smart document summaries, annotation and note-taking tools, secure communication with fellow board members, clear voting and resolution tracking + +### Shareholder +Owner of shares in a BV or NV. Has voting rights at the Algemene Vergadering van Aandeelhouders (AVA/AGM). Dutch law provides specific rights for minority shareholders. +**Responsibilities:** Attending and voting at AVA/AGM, approving annual accounts, appointing/dismissing directors, approving statute amendments, exercising inquiry rights (enquêterecht) +**Pain points:** Complex proxy voting processes, lack of transparency in pre-meeting information, difficulty participating in hybrid/digital meetings, limited engagement between AGMs, unclear resolution outcomes +**Goals:** Easy digital proxy voting, transparent access to meeting agendas and documents, real-time participation in hybrid AGMs, clear dividend and resolution information, accessible corporate governance information + +### Works Council Representative +Representative of the works council (Ondernemingsraad), which has advisory and consent rights on major decisions in companies with 50+ employees. Has nomination rights for supervisory board under structure regime. +**Responsibilities:** Exercising advisory rights (adviesrecht) on strategic decisions, consent rights (instemmingsrecht) on HR policies, nominating supervisory board members (structure regime), attending shareholder meetings, reviewing major governance decisions +**Pain points:** Receiving governance information too late for meaningful input, limited access to decision-making timelines, difficulty tracking which decisions require works council involvement, inadequate digital tools for OR governance +**Goals:** Timely access to proposed decisions requiring OR advice/consent, digital workflow for adviesrecht and instemmingsrecht processes, transparent governance timeline visibility, secure communication with supervisory board + +### CEO / Director +Top executive responsible for overall organizational strategy, final decision authority on major matters, and accountability to the board of directors. +**Responsibilities:** ["Setting organizational strategy and vision", "Final authority on major investment and policy decisions", "Chairing management team meetings", "Reporting to board of directors / supervisory board", "Approving budgets above delegation thresholds", "Crisis decision-making and escalation endpoint"] +**Pain points:** ["Decisions bottleneck at the top due to unclear delegation", "Lack of visibility into decision status across layers", "Too many items escalated that should be handled lower", "Difficulty tracking whether MT decisions are actually implemented", "Information overload from multiple reporting channels"] +**Goals:** ["Clear delegation of authority matrix", "Real-time dashboard of organizational decision status", "Efficient MT meeting cycle with tracked outcomes", "Audit trail for governance and compliance"] + +### MT Member / Manager +Member of the management team responsible for a functional area (finance, operations, HR, IT, etc.). Participates in collective MT decision-making while managing own department. +**Responsibilities:** ["Participating in MT decision-making on strategic matters", "Translating MT decisions into departmental actions", "Preparing proposals and business cases for MT agenda", "Managing departmental budget and resources", "Escalating issues that exceed departmental authority", "Cross-functional coordination with other MT members"] +**Pain points:** ["Dual role tension: MT interest vs department interest", "Decisions revisited repeatedly without clear closure", "No single source of truth for what was decided", "Action items from meetings lost or not tracked", "Difficulty coordinating cross-departmental decisions"] +**Goals:** ["Structured agenda and decision log for MT meetings", "Clear action tracking with ownership and deadlines", "Efficient preparation workflow for meeting items", "Visibility into decisions affecting own department"] + +### Department Head +Leads a department within the organization. Translates management decisions into departmental plans, manages team leads, and handles operational decisions within delegated authority. +**Responsibilities:** ["Leading departmental meetings and decision-making", "Implementing MT decisions within the department", "Managing departmental budget within approved limits", "Approving procurement and hiring within delegation", "Escalating decisions beyond authority to MT member", "Coordinating with other departments on shared matters"] +**Pain points:** ["Unclear boundaries of decision authority", "Waiting for approvals from MT that delay operations", "No structured way to propose items to MT agenda", "Difficulty cascading decisions to teams consistently", "Cross-department dependencies causing bottlenecks"] +**Goals:** ["Clear delegation of authority documentation", "Streamlined approval workflows for routine decisions", "Efficient escalation path to management team", "Tool to cascade decisions to team leads and staff"] + +### Team Lead +Leads a team within a department. Makes day-to-day operational decisions, translates department directives into team actions, and escalates issues beyond team scope. +**Responsibilities:** ["Daily operational decision-making for the team", "Translating department decisions into team tasks", "First-line approval of leave, expenses, small purchases", "Identifying issues requiring escalation to department head", "Conducting team meetings and tracking team actions", "Reporting team progress and issues upward"] +**Pain points:** ["Decisions from above arrive without context or rationale", "No feedback loop to confirm decisions are understood", "Small decisions delayed by unnecessary approval chains", "Difficult to track which decisions affect the team", "Limited visibility into broader organizational decisions"] +**Goals:** ["Context-rich communication of cascaded decisions", "Autonomy for routine operational decisions", "Simple escalation mechanism for issues beyond scope", "Team action tracking linked to organizational decisions"] + +## Other App Entities (do NOT redefine) + +ActionItem, AgendaItem, Amendment, Area, ContactDetail, Decision, DigitalDocument, GovernanceBody, Meeting, Membership, Minutes, MonetaryAmount, Motion, Offer, Order, Participant, Person, Post, Product, Report, Speech, Vote, VotingRound + +## Company-Wide Architecture Rules (17 ADRs) + +These rules are MANDATORY for all Conduction apps. + +### ADR-001-data-layer +- 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 + +### ADR-002-api +- 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. + +### ADR-003-backend +- **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. + +### ADR-004-frontend +- **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 `