From 2f28664768883b035e226a771411a99e68e77ba7 Mon Sep 17 00:00:00 2001 From: Specter Intelligence Date: Fri, 22 May 2026 05:25:49 +0000 Subject: [PATCH 1/4] feat: Add OpenSpec change commissievergaderingen from Specter --- .../commissievergaderingen/.openspec.yaml | 2 + .../commissievergaderingen/context-brief.md | 195 ++++++++++++ .../changes/commissievergaderingen/design.md | 280 ++++++++++++++++++ .../commissievergaderingen/proposal.md | 103 +++++++ .../changes/commissievergaderingen/specs.md | 142 +++++++++ .../changes/commissievergaderingen/tasks.md | 183 ++++++++++++ 6 files changed, 905 insertions(+) create mode 100644 openspec/changes/commissievergaderingen/.openspec.yaml create mode 100644 openspec/changes/commissievergaderingen/context-brief.md create mode 100644 openspec/changes/commissievergaderingen/design.md create mode 100644 openspec/changes/commissievergaderingen/proposal.md create mode 100644 openspec/changes/commissievergaderingen/specs.md create mode 100644 openspec/changes/commissievergaderingen/tasks.md diff --git a/openspec/changes/commissievergaderingen/.openspec.yaml b/openspec/changes/commissievergaderingen/.openspec.yaml new file mode 100644 index 00000000..4a1c6774 --- /dev/null +++ b/openspec/changes/commissievergaderingen/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-05-22 diff --git a/openspec/changes/commissievergaderingen/context-brief.md b/openspec/changes/commissievergaderingen/context-brief.md new file mode 100644 index 00000000..8a01cc9c --- /dev/null +++ b/openspec/changes/commissievergaderingen/context-brief.md @@ -0,0 +1,195 @@ +--- +status: draft +app: decidesk +spec: commissievergaderingen +target_users: raadsleden, commissieleden, voorzitters, griffie, ambtelijke ondersteuning, college +depends_on: + - decidesk-base +references: + - Gemeentewet artikel 82-84 (raadscommissies) + - https://www.raadsleden.nl/onderwerpen/raadscommissies + - https://lokaleregelgeving.overheid.nl/ (verordening op raadscommissies) + - https://standaarden.overheid.nl/owms + - Reglement van Orde gemeenteraad (per gemeente) +--- + +# Commissievergaderingen + +## Purpose + +Vrijwel elke Nederlandse gemeenteraad werkt met raadscommissies als voorbereidende organen op de plenaire raadsvergadering. Veelvoorkomende commissies zijn de audit-commissie (financiën en rekenkamer), commissie ruimte (ruimtelijke ordening, wonen, mobiliteit), commissie sociaal (zorg, jeugd, participatie), en commissie bestuur (algemeen bestuur, veiligheid, dienstverlening). De commissies hebben geen besluitvormende bevoegdheid maar geven advies aan de raad over voorliggende voorstellen, voeren technische beraadslagingen, en horen burgers en organisaties via inspraak. Een gemeente kent typisch 3 tot 6 commissies die elk maandelijks vergaderen — voor de griffie een aanzienlijke planningslast, en voor commissieleden een complex puzzelstuk van agenda's, dossiers en belangenverstrengelings-meldingen. Daarnaast worden in toenemende mate raadsbrede thema-bijeenkomsten en informele beeldvormende sessies onder de commissie-vlag georganiseerd, wat aparte planning-, presentie- en publicatie-regels vraagt. + +Deze spec breidt decidesk uit met een eersteklas commissie-model dat sub-vergaderingen voor commissies beheert, vaste samenstelling per commissie (leden, plaatsvervangers, voorzitter, griffier) bijhoudt, het adviestraject naar de raadsvergadering automatiseert, en belangenverstrengelings-declaraties per agendapunt verplicht stelt conform artikel 28 Gemeentewet. Daarnaast ondersteunt de spec besloten zittingen met aparte toegangsregels, openbare verslaglegging met audio/videoregistratie waar gemeenten dat al doen, en inspraak-aanmelding voor burgers via een publiek portaal. Het sluit aan op de bredere besluitvormings-workflow en garandeert dat commissieadvies traceerbaar terechtkomt bij het agendapunt in de plenaire raadsvergadering. + +De ontwerpkeuzes adresseren expliciet drie pijnpunten die uit interviews met griffies naar voren komen. Ten eerste de hoge handmatige last bij wisseling van plaatsvervangers: een fractie-voorzitter die op het laatste moment iemand vervangt voor commissie-deelname moet nu vaak per e-mail aan de griffier doorgeven wie er komt, waarna de griffier handmatig de stemrecht-status omklapt. In deze spec verloopt dit via een fractie-portaal-actie die direct presentie, agenda-toegang en stemrecht synchroniseert. Ten tweede de zwakke link tussen commissieadvies en plenaire besluitvorming: in legacy-systemen verdwijnt het commissieadvies vaak in een PDF-bijlage waar de raadsleden niet doorklikken. De spec maakt het advies een eersteklas annotatie op het plenaire agendapunt met fractie-standpunten als gestructureerde data, niet als losse tekst. Ten derde de privacy-paradox bij inspraak: burgers willen inspreken maar niet altijd hun adres en telefoonnummer publiek hebben — de InspraakAanmelding scheidt contactgegevens (intern) van inspraak-onderwerp en spreker-naam (publiek) automatisch. Voor besloten zittingen zoals personeels-aangelegenheden en grond-aankopen wordt een aparte audit-track gevoerd die alleen via dual-control geopend kan worden, zodat de Woo-toets achteraf altijd reproduceerbaar is. + +Een bewuste keuze in deze spec is om verschillende commissie-typen via één Commissie-schema te modelleren in plaats van aparte schemas voor elk type (audit, ruimte, sociaal, etc.). Dit volgt het principe dat elke gemeente eigen commissie-samenstelling kiest binnen de wettelijke kaders en dat de portefeuille-scope een attribute is, geen schema-eigenschap. Daarmee is de spec direct geschikt voor gemeenten met klassieke vakcommissies, gemeenten met thema-commissies, en gemeenten die werken met een enkele oordeelsvormende commissie waar alle voorstellen langs gaan. Tegelijk faciliteert de spec experimenten met nieuwere vormen zoals burger-jury's (tijdelijke commissies waar gelote burgers naast raadsleden zitting hebben) door het type-veld uit te breiden zonder het schema te wijzigen. De koppeling met de Verordening op de raadscommissies (REQ-013) garandeert dat elke wijziging in de configuratie van een commissie traceerbaar is naar een formeel raadsbesluit, wat juridische bezwaren tegen commissie-besluiten ondervangt en bestuursrechters in beroep-procedures de nodige feitelijke onderbouwing biedt. + +## Data Model + +**Commissie** is een schema met velden: naam, type (`vast`, `tijdelijk`, `ad-hoc`), portefeuille-scope (TOOI-categorieën), voorzitter (raadslid-koppeling), plaatsvervangend-voorzitter, griffier (medewerker-koppeling), vergader-frequentie (`maandelijks`, `tweewekelijks`, `op-afroep`), vaste-vergaderdag, vergader-tijdstip, vergader-locatie, instellings-datum, instellings-besluit (raadsbesluit-koppeling), opheffings-datum, openbaarheids-default (`openbaar`, `besloten`). + +**CommissieLidmaatschap** is een schema met velden: commissie-koppeling, raadslid-koppeling, fractie (gesnapshot), rol (`lid`, `plaatsvervanger`, `voorzitter`, `griffier`, `adviseur`), begin-datum, eind-datum, beëindigings-reden. + +**CommissieVergadering** is een schema met velden: commissie-koppeling, vergader-datum, vergader-tijd-start, vergader-tijd-eind, locatie, openbaar (`ja`, `besloten`, `gedeeltelijk`), status (`gepland`, `agenda-vastgesteld`, `actief`, `geschorst`, `gesloten`, `geannuleerd`), audio-opname-url, video-opname-url, conceptverslag (rich text), definitief-verslag, presentielijst. + +**CommissieAgendapunt** is een schema met velden: commissie-vergadering-koppeling, volgnummer, titel, type (`mededeling`, `bespreekstuk`, `hamerstuk`, `advies-aan-raad`, `inspraak`, `besloten-onderdeel`), beoogd-raadsvoorstel (koppeling naar raadsvoorstel dat naar plenaire raad gaat), portefeuillehouder, behandel-duur-geschat, bijlagen. + +**CommissieAdvies** is een schema met velden: agendapunt-koppeling, advies-strekking (`positief`, `negatief`, `verdeeld`, `geen-advies`, `verzoek-tot-aanpassing`), advies-tekst (rich text), stemverhouding-samenvatting, fractie-standpunten (lijst van fractie + standpunt), inspraak-samenvatting. + +**BelangenverstrengelingDeclaratie** is een schema met velden: commissielid-koppeling, agendapunt-koppeling, soort (`financieel-belang`, `aandeelhouderschap`, `bestuursfunctie`, `familierelatie`, `eerder-betrokken`, `geen`), beschrijving, gevolg (`onthoudt-zich-van-stemming`, `verlaat-vergadering`, `meldt-maar-blijft`), declaratie-datum. + +**InspraakAanmelding** is een schema met velden: commissie-vergadering-koppeling, agendapunt-koppeling, naam-spreker, organisatie, contactgegevens (intern), onderwerp (publiek), spreektijd-aanvraag, status (`aangemeld`, `goedgekeurd`, `afgewezen`, `gesproken`, `niet-verschenen`), bijdrage-tekst (optionele schriftelijke variant), woon-of-werk-plaats (verplicht bij representativiteit-toets). + +**Presentielijst** is een schema met velden: commissie-vergadering-koppeling, lid-koppeling, aanwezig (`aanwezig`, `afwezig-met-bericht`, `afwezig-zonder-bericht`, `plaatsvervangen-door`), aankomst-tijd, vertrek-tijd, presentievergoeding-uitbetaald (boolean). + +## Requirements + +### REQ-001: Commissie instellen op basis van raadsbesluit + +**GIVEN** de raad heeft een commissie ingesteld via een formeel raadsbesluit +**WHEN** de griffier de commissie aanmaakt +**THEN** wordt de commissie gekoppeld aan het instellings-besluit en is niet wijzigbaar zonder verwijzing naar een wijzigingsbesluit +**AND** verschijnt de commissie in het publieke register van bestuurlijke organen + +### REQ-002: Samenstelling beheren met fractie-evenredigheid + +**GIVEN** een commissie heeft vaste samenstelling en een fractie wijzigt qua omvang +**WHEN** de griffier het aantal commissiezetels herziet +**THEN** wordt de evenredige verdeling per fractie berekend (D'Hondt-systeem of restzetels-methode per Reglement van Orde) +**AND** kan elke fractie haar eigen commissieleden aanwijzen +**AND** wordt een gewijzigde-samenstelling-melding vastgelegd met ingangsdatum + +### REQ-003: Plaatsvervanging bij afwezigheid + +**GIVEN** een commissielid kan niet aanwezig zijn bij een vergadering +**WHEN** het lid zich afmeldt en een plaatsvervanger aanwijst +**THEN** ontvangt de plaatsvervanger automatisch agenda en dossier +**AND** wordt op de presentielijst de plaatsvervanger zichtbaar +**AND** kan de plaatsvervanger meestemmen in adviesvorming + +### REQ-004: Belangenverstrengelings-declaratie per agendapunt + +**GIVEN** een commissielid is geagendeerd om over een onderwerp te beraadslagen +**WHEN** het lid niet eerder een declaratie heeft afgegeven en het agendapunt wordt geopend +**THEN** wordt het lid verplicht een BelangenverstrengelingDeclaratie in te vullen (ook als die `geen` is) +**AND** wordt bij `aandeelhouderschap` of `familierelatie` automatisch de griffier en voorzitter geattendeerd +**AND** kan het lid zich onthouden van beraadslaging zonder verlies van presentievergoeding + +### REQ-005: Besloten zitting met aparte toegangscontrole + +**GIVEN** een agendapunt is gemarkeerd als besloten (bv personeels-aangelegenheid, grond-aankoop met onderhandelingspositie) +**WHEN** de vergadering bij dit punt aanvangt +**THEN** wordt het publieke portaal en de video-livestream onderbroken +**AND** krijgen alleen commissieleden, voorzitter, griffier en expliciet uitgenodigde adviseurs toegang tot stukken +**AND** wordt een aparte besloten-zittings-notulen-track aangemaakt die niet via reguliere publicatie-flow gaat + +### REQ-006: Adviesvorming met fractie-standpunten + +**GIVEN** een commissie heeft een bespreekstuk behandeld en gaat advies geven +**WHEN** de voorzitter de adviesvorming afsluit +**THEN** worden per fractie de standpunten genoteerd (`voor`, `tegen`, `verdeeld`, `geen-mening`) +**AND** wordt een CommissieAdvies opgesteld dat automatisch wordt gekoppeld aan het beoogd-raadsvoorstel +**AND** verschijnt het advies in de plenaire raadsagenda bij het agendapunt + +### REQ-007: Inspraak-aanmelding via publiek portaal + +**GIVEN** een commissievergadering staat gepland en een burger wil inspreken +**WHEN** de burger zich via het publieke portaal aanmeldt voor inspraak op een specifiek agendapunt +**THEN** ontvangt de griffier een aanvraag met contactgegevens en onderwerp +**AND** kan de griffier de aanvraag goedkeuren, afwijzen (met reden), of doorverwijzen +**AND** ontvangt de burger bevestiging met spreektijd-toewijzing +**AND** sluit aanmelding 24 uur voor vergadering automatisch (configurabel per commissie) + +### REQ-008: Verslag publicatie naar griffieportaal + +**GIVEN** een commissievergadering is afgesloten en het conceptverslag is goedgekeurd in de volgende vergadering +**WHEN** de griffier het verslag als definitief markeert +**THEN** wordt het verslag gepubliceerd op het griffieportaal met agenda, presentielijst, adviezen, inspraak-overzicht +**AND** wordt audio/video-opname gekoppeld met tijdcodes per agendapunt (deeplink) +**AND** wordt OWMS-metadata gegenereerd voor zoekmachine-indexering + +### REQ-009: Conflict-of-interest rapportage per periode + +**GIVEN** de rekenkamer of een journalist wil zicht op gemelde belangen +**WHEN** de gebruiker de rapportage `belangen-overzicht` opvraagt voor een periode +**THEN** wordt een overzicht gegenereerd van alle declaraties per commissielid, gesorteerd op type belang +**AND** worden alleen openbare delen getoond (besloten-zittings-declaraties blijven afgeschermd) + +### REQ-010: Commissie-naar-raad doorgeleiding + +**GIVEN** een agendapunt is in commissie voorbespreken en het commissieadvies is opgesteld +**WHEN** het agendapunt op de plenaire raadsagenda wordt geplaatst +**THEN** verschijnt automatisch een verwijzing naar het commissieadvies, de stemverhouding-samenvatting, en eventuele inspraak-bijdragen +**AND** kunnen raadsleden uit de commissie hun voorbereidings-notities meenemen naar de plenaire vergadering + +### REQ-011: Thema-bijeenkomst zonder advies-vorming + +**GIVEN** de griffie organiseert een raadsbrede beeldvormende sessie over een toekomst-thema +**WHEN** de bijeenkomst als CommissieVergadering met type `thema-bijeenkomst` wordt gemarkeerd +**THEN** vervalt de verplichte adviesvorming-stap +**AND** kunnen alle raadsleden (niet alleen commissieleden) zich aanmelden +**AND** wordt een lichtgewicht verslag opgesteld zonder formele stemverhoudingen + +### REQ-012: Audit-trail voor besloten zittings-stukken + +**GIVEN** een besloten-zittings-document wordt openbaar gemaakt na verloop van geheimhoudings-termijn (Woo-toets) +**WHEN** een ambtenaar of journalist het document opvraagt +**THEN** wordt de complete toegang-historie tijdens de geheimhoudings-periode getoond (wie heeft wanneer ingezien) +**AND** wordt de dual-control-handeling voor opheffing van geheimhouding aantoonbaar vastgelegd + +### REQ-013: Commissie-verordening synchronisatie + +**GIVEN** de raad wijzigt de Verordening op de raadscommissies (bv aantal commissies, samenstelling, spreektijd) +**WHEN** de griffier de gewijzigde verordening importeert +**THEN** wordt het Commissie-record gekoppeld aan de nieuwe verordening-versie via een onveranderlijke verwijzing +**AND** worden eerdere vergaderingen onder oude verordening getoond met de op-dat-moment-geldende regels +**AND** wordt elke gemeente-specifieke afwijking (configurabele parameters) gevalideerd tegen de verordening-tekst + +## Standards + +- **Gemeentewet** artikelen 82, 83, 84 (instelling en samenstelling raadscommissies), artikel 28 (verbod schijn van belangenverstrengeling), artikel 86 (geheimhouding) +- **Reglement van Orde** van de individuele gemeenteraad +- **Verordening op raadscommissies** (gemeentelijke verordening, verplicht door Gemeentewet artikel 82 lid 1) +- **Wet openbaarheid van bestuur** opvolger **Wet open overheid** (Woo) categorie 6 (vergaderstukken bestuursorganen) +- **Wet hergebruik overheidsinformatie (Who)** voor open data publicatie +- **OWMS** versie 4 voor publicatie van vergaderstukken en verslagen +- **TOOI** voor onderwerp-classificatie en bestuursorgaan-aanduiding +- **WCAG 2.1 AA** voor publiek portaal, conform Tijdelijk besluit digitale toegankelijkheid +- **AVG** voor verwerking persoonsgegevens van insprekers en commissieleden +- **Archiefwet 1995** — bewaartermijn besluitvormingsdossiers conform selectielijst gemeenten 2020 +- **Wet bescherming persoonsgegevens** (vervangen door AVG, maar relevant voor historische dossiers) +- **NEN-ISO 16175** voor digitaal records management +- **NORA** principes voor inter-bestuurlijke samenwerking +- **OPRL** referentie-architectuur Raadsinformatie van VNG + +## Cross-app + +- **decidesk base**: levert basismodel vergadering, agendapunt, raadslid, fractie, presentielijst +- **decidesk motie-amendement-administratie**: amendementen kunnen voortkomen uit commissieadvies; commissieadvies bepaalt vaak indieningsstrategie van moties +- **decidesk fractievoorzitter-fractie-koppeling**: levert evenredigheidsberekening bij commissie-samenstelling en plaatsvervangers-management via fractie-portaal +- **decidesk besluitvorming-workflow**: commissieadvies wordt onderdeel van besluitvormings-flow en zichtbaar bij plenaire agendapunten +- **docudesk**: vergaderstukken en verslagen worden PDF-gerendeerd, eIDAS-handtekening op definitieve verslagen, geheimhouding-watermark op besloten stukken +- **opentalk**: livestream van openbare commissievergaderingen, met tijdcode-koppeling per agendapunt voor deeplinks; automatische onderbreking bij besloten zitting +- **opencatalogi**: publicatie van publieke commissie-stukken als openbare catalogus met TOOI-metadata +- **openconnector**: synchronisatie naar iBabs of Notubiz voor gemeenten in transitie; ook synchronisatie met agenda-systemen (Outlook, Google Calendar) +- **openregister**: alle entiteiten leven op openregister schemas; audit-trail voor toegang besloten stukken +- **mydash**: dashboards voor griffie met commissie-activiteit per periode, attendance-trends, advies-naar-raad ratio +- **openklant**: insprekers kunnen via openklant zich aanmelden en hun contactgegevens beheren met privacy-controle +- **docudesk eIDAS**: handtekeningen op vastgestelde commissie-verslagen voor formele juridische status + +## Target Users + +- **Commissieleden** raadplegen agenda, dossier, geven advies, registreren belangenverstrengeling, bereiden plenaire raadsvergadering voor +- **Commissievoorzitter** leidt vergadering, sluit beraadslaging, formuleert advies, bewaakt spreektijd en orde +- **Griffier en griffie-medewerkers** plannen vergaderingen, stellen agenda op, registreren presentie, publiceren verslag, bewaken termijnen +- **Raadsleden niet in commissie** raadplegen commissieadvies ter voorbereiding plenaire raadsvergadering en kunnen agendapunten als toehoorder volgen +- **Burgers en organisaties** melden inspraak aan en volgen openbare vergaderingen via livestream en archief +- **Ambtelijke ondersteuning portefeuillehouder** bereidt technische antwoorden voor commissievragen voor en stelt bestuursrapportages op +- **Collegeleden** beantwoorden vragen tijdens commissievergaderingen, presenteren collegevoorstellen +- **Externe adviseurs** (juridisch, financieel, technisch) kunnen geagendeerd worden voor toelichting onder NDA +- **Rekenkamer** raadpleegt commissie-archief voor onderzoek naar kwaliteit van besluitvorming +- **Journalisten en publiek** volgen openbare zittingen via livestream en gepubliceerde verslagen +- **Plaatsvervangers** ontvangen tijdig agenda en dossier wanneer zij worden ingezet +- **Bestuursrechter** raadpleegt commissie-advies bij beroep tegen besluiten die door de commissie zijn voorbesproken +- **Provincie** in toezichthoudende rol bij signalen over kwaliteit raadsbesluitvorming diff --git a/openspec/changes/commissievergaderingen/design.md b/openspec/changes/commissievergaderingen/design.md new file mode 100644 index 00000000..4eaa8cd9 --- /dev/null +++ b/openspec/changes/commissievergaderingen/design.md @@ -0,0 +1,280 @@ +# Design — Commissievergaderingen + +## Context + +Decidesk base levert basismodel Meeting (plenaire raadsvergaderingen), AgendaItem, Participant, Membership. Commissievergaderingen zijn sub-type van Meeting met aanvullende velden: commissie-koppeling, commissie-specifieke agendapunt-types, adviesvorming per agendapunt, belangenverstrengeling-registratie, inspraak-aanmelding, en besloten-zittings-afhandeling. + +**Huidige decidesk-staat:** +- Meeting, AgendaItem, Participant, Membership, GovernanceBody zijn gedefinieerd in p1-schemas-en-data-model en p3-governance-bodies +- Geen commissie-specifieke logica bestaat nog +- Griffie-workflows (plaatsvervanging, adviesvorming, belangenverstrengeling) zijn handmatig en error-prone + +**Stakeholders:** +- Griffiepoort: Commissie-voorzitter, griffier, griffie-medewerkers (planning, verslaglegging) +- Commissie-leden: Inzien agenda, geven advies, declareren belangenconflicten +- Fractie-voorzitters: Commissieleden aanwijzen, plaatsvervangers regelen +- Burgers: Inspreken via publiek portaal, openbare vergaderingen volgen +- Raadsleden niet-in-commissie: Commissieadvies ter voorbereiding plenaire raad inzien +- Collegeleden: Presenteren voorstellen in commissie, beantwoorden vragen + +## Goals / Non-Goals + +**Goals:** +- Definieer 8 OpenRegister schemas voor commissie-entiteiten met correcte field-types, enum-waarden, en schema.org-annotaties +- Implementeer business logic voor commissie-samenstelling (fractie-evenredigheid), plaatsvervanger-management, adviesvorming met fractie-standpunten +- Zorg voor belangenverstrengeling-registratie (artikel 28 Gemeentewet) en gevolg-afhandeling (onthoudt-zich, verlaat, meldt-maar-blijft) +- Publiceer commissieadvies automatisch op plenaire agendapunt als gestructureerde data (fractie-standpunten) +- Ondersteun inspraak-aanmelding via publiek portaal met privacy-scheiding (contactgegevens ↔ publieke inspraak) +- Zorg voor audit-trail van toegang tot besloten-zittings-stukken voor Woo-toets +- Documenteer commissions API-patronen zodat andere gemeenten kunnen overnemen + +**Non-Goals:** +- Frontend UI (REST API only; UI in p3 sprint) +- Audio/video-opname en -livestream (opentalk-integratie volgt) +- PDF-rendering van verslagen (docudesk-integratie volgt) +- Automatische kalender-sync (openconnector volgt) +- Dashboard-rendering (mydash volgt) +- Multi-tenant commissie-sharing (common pattern later) + +## Decisions + +### D1: Acht schemas in één commissievergaderingen-register + +Alle commissie-entiteiten (Commissie, CommissieLidmaatschap, CommissieVergadering, CommissieAgendapunt, CommissieAdvies, BelangenverstrengelingDeclaratie, InspraakAanmelding, Presentielijst) leven in één register. + +**Alternatieven:** één register per commissie-type (audit, ruimte, sociaal, bestuur) — afgewezen omdat gemeente-specifieke commissie-samenstelling het logischer maakt om commissie-type als enum-attribute te modeleren, niet als schema-scheiding. + +**Waarom dit:** Eenvoudige cross-entity-relaties; één register = één import-stap; schema-type enum biedt latere flexibiliteit (bv burger-jury's als tijdelijk type). + +### D2: CommissieVergadering erft van Meeting, voegt commissie-velden toe + +CommissieVergadering is sub-type van Meeting (relation, niet inheritance). Het heeft alle Meeting-velden (title, scheduledDate, meetingType, lifecycle) plus commissie-speci fieke velden (commissie-ref, openbaar ja/nee, status van presentielijst). + +**Alternatieven:** volledig aparte Meeting-subklasse in OpenRegister; shared-type-pattern via polymorphism. **Waarom dit:** Meeting-lifecycle (scheduled, opened, paused, adjourned, closed) past commissie-vergaderingen; commissie-velden zijn additioneel, niet conflicterend. + +### D3: CommissieAdvies als linked annotation op plenaire AgendaItem + +CommissieAdvies heeft relatie naar CommissieAgendapunt (waar het ontstond) EN relation naar het beoogd-raadsvoorstel (plenaire AgendaItem). Fractie-standpunten zijn array-veld op CommissieAdvies (niet separate entities). + +**Alternatieven:** CommissieAdvies als complete duplicate van plenaire AgendaItem-advies; losse PDF-bijlage. **Waarom dit:** Gestructureerde data voor LLM-verwerking (MCP-tools kunnen fractie-standpunten analyseren); traceerbare link plenair ↔ commissie; single source of truth. + +### D4: BelangenverstrengelingDeclaratie verplicht per agendapunt, lazily-triggered + +Wanneer CommissieAgendapunt wordt geopend voor beraadslaging, wordt per CommissielIdmaatschap een declaratie-record gemaakt met default-waarde `soort: 'geen'` (of `vraag-uit-formulier` als konfigurabel). Lid kan deze wijzigen. Declaratie met `soort !== 'geen'` triggert automatische alert naar voorzitter + griffier. + +**Alternatieven:** pre-session-declaration (vroegtijdig invullen); optioneel (lid kan overslaan). **Waarom dit:** Naleving artikel 28 Gemeentewet; laziness voorkomt papierwerk als geen conflicten; alert leidt tot live-afhandeling (onthoudt-zich, verlaat, meldt-maar-blijft). + +### D5: InspraakAanmelding scheidt contactgegevens (intern) van inspraak-onderwerp (publiek) + +InspraakAanmelding heeft twee veldsets: `contactgegevens` (naam, email, telefoon, adres — intern) en `onderwerp` (spreker-naam, organisatie, spreektijd-aanvraag — publiek). Griffie ziet beide; publieke verslaglegging toont alleen onderwerp. + +**Alternatieven:** één 'inspraak-bijdrager'-veld met alles gemengd. **Waarom dit:** Privacy (burgers willen niet dat hun adres publiek is); AVG-naleving (intern contact gescheiden van publieke registratie); technische scheiding enforces privacy. + +### D6: Presentielijst is aparte schema, niet geëmbedded in CommissieVergadering + +Presentielijst is één record per CommissieVergadering met array van Presentielijst-items (one-to-many). Elk item koppelt aan CommissieLid (via Membership) met status, aankomst/vertrek-tijd. + +**Alternatieven:** presentiestatus direct op CommissieLidmaatschap; array-veld op CommissieVergadering. **Waarom dit:** Multiple vergaderingen per lid → historisch per-vergadering spoor nodig; OpenRegister relaties maken one-to-many clear. + +### D7: Fracties-snapshot in CommissieLidmaatschap + +CommissieLidmaatschap heeft `fractie`-veld dat de huidige fractie van het CommissieLid (via Raadslid/Membership) op dat moment vastlegt. Bij fractie-wisseling van een raadslid blijft bestaande CommissieLidmaatschap ongewijzigd; volgende commissie-aanwijzing maakt nieuw lid maatschap met nieuwe fractie. + +**Alternatieven:** fractie via live-relation naar Membership. **Waarom dit:** Commissie-samenstelling moet reproduceerbaar zijn (wat waren fractie-verhoudingen op datum X); snapshot voorkomt later-wijzigen van historische commissie-samenstelling. + +### D8: Commissie-type via enum, geen aparte schemas + +Commissie heeft `type`-enum (vast, tijdelijk, ad-hoc) en `portefeuille-scope` (array van TOOI-categorieën). Geen aparte AuditCommissie-, RuimteCommissie-schemas. + +**Alternatieven:** per-type-schema (AuditCommissie, RuimteCommissie, etc.). **Waarom dit:** Gemeente-specifieke configuratie; enum is uitbreidbaar (bv burger-jury's toevoegen zonder schema-change); TOOI-scope hanteert gemeente-specifieke prioriteiten. + +## Reuse Analysis + +| Code-pad | Bron | Hergebruik-strategie | +|---|---|---| +| Meeting-lifecycle (scheduled, opened, closed, etc.) | decidesk p2-meeting-management | CommissieVergadering uses relation naar Meeting; lifecycle-transitions via bestaande StateEngine | +| Participant/Membership model | decidesk p3-governance-bodies | CommissieLidmaatschap erft relatie-patronen van Membership; voegt commissie-specifieke velden toe | +| AgendaItem | decidesk p2-agenda-management | CommissieAgendapunt is separate schema; koppelt via relation naar CommissieVergadering | +| Speech/Vote/VotingRound | decidesk p2-motion-voting | CommissieAdvies is lighter-weight (geen formal voting, alleen stemmingsverhouding-samenvatting + fractie-standpunten) | +| OpenRegister ConfigurationService | openregister core | `importFromApp('commissievergaderingen')` voor register-import | +| Relation management | openregister core | Alle cross-entity-relaties via x-openregister-relaties in schema JSON (geen foreign keys) | +| ObjectService CRUD | openregister core | Reused voor alle schema-operations (list, get, create, update) | +| REST API | openregister core + decidesk controllers | Decidesk-controllers voor griffie-workflows (samenstelling, plaatsvervanging, adviesvorming); inheritance uit decidesk patterns | + +**Geen nieuwe business-logic in provider** — services leveren alleen orchestration van existing CRUD + validatie. + +## Seed Data + +### Commissie (3 objecten — Nederlandse gemeenten) + +```json +[ + { + "@self": { "register": "commissievergaderingen", "schema": "Commissie", "slug": "commissie-ruimte-westerkwartier" }, + "naam": "Commissie Ruimte", + "type": "vast", + "portefeuille-scope": ["ruimtelijke-ordening", "wonen", "mobiliteit"], + "voorzitter": { "register": "decidesk", "schema": "Raadslid", "id": "rd-001" }, + "griffier": { "register": "decidesk", "schema": "Medewerker", "id": "mw-001" }, + "vergader-frequentie": "maandelijks", + "vaste-vergaderdag": "donderdag", + "vergader-tijdstip": "19:30", + "vergader-locatie": "Raadzaal Westerkwartier", + "instellings-datum": "2022-06-15", + "instellings-besluit": { "register": "decidesk", "schema": "RaadsBesluit", "id": "rb-001" }, + "openbaarheids-default": "openbaar" + }, + { + "@self": { "register": "commissievergaderingen", "schema": "Commissie", "slug": "commissie-sociaal-westerkwartier" }, + "naam": "Commissie Sociaal", + "type": "vast", + "portefeuille-scope": ["zorg", "jeugd", "participatie"], + "voorzitter": { "register": "decidesk", "schema": "Raadslid", "id": "rd-002" }, + "griffier": { "register": "decidesk", "schema": "Medewerker", "id": "mw-001" }, + "vergader-frequentie": "maandelijks", + "vaste-vergaderdag": "dinsdag", + "vergader-tijdstip": "19:00", + "vergader-locatie": "Raadzaal Westerkwartier", + "instellings-datum": "2022-06-15", + "instellings-besluit": { "register": "decidesk", "schema": "RaadsBesluit", "id": "rb-001" }, + "openbaarheids-default": "openbaar" + }, + { + "@self": { "register": "commissievergaderingen", "schema": "Commissie", "slug": "commissie-audit-westerkwartier" }, + "naam": "Commissie Audit", + "type": "vast", + "portefeuille-scope": ["financiën", "rekenkamer"], + "voorzitter": { "register": "decidesk", "schema": "Raadslid", "id": "rd-003" }, + "griffier": { "register": "decidesk", "schema": "Medewerker", "id": "mw-002" }, + "vergader-frequentie": "tweewekelijks", + "vaste-vergaderdag": "vrijdag", + "vergader-tijdstip": "13:30", + "vergader-locatie": "Kantoor Griffie", + "instellings-datum": "2022-06-15", + "instellings-besluit": { "register": "decidesk", "schema": "RaadsBesluit", "id": "rb-001" }, + "openbaarheids-default": "openbaar" + } +] +``` + +### CommissieLidmaatschap (5 objecten) + +```json +[ + { + "@self": { "register": "commissievergaderingen", "schema": "CommissieLidmaatschap", "slug": "lid-commissie-ruimte-001" }, + "commissie": { "register": "commissievergaderingen", "schema": "Commissie", "id": "commissie-ruimte-westerkwartier" }, + "raadslid": { "register": "decidesk", "schema": "Raadslid", "id": "rd-004" }, + "fractie": "Lokaal Belang", + "rol": "lid", + "begin-datum": "2022-06-15", + "eind-datum": null + }, + { + "@self": { "register": "commissievergaderingen", "schema": "CommissieLidmaatschap", "slug": "lid-commissie-ruimte-002" }, + "commissie": { "register": "commissievergaderingen", "schema": "Commissie", "id": "commissie-ruimte-westerkwartier" }, + "raadslid": { "register": "decidesk", "schema": "Raadslid", "id": "rd-005" }, + "fractie": "GroenLinks", + "rol": "lid", + "begin-datum": "2022-06-15", + "eind-datum": null + }, + { + "@self": { "register": "commissievergaderingen", "schema": "CommissieLidmaatschap", "slug": "lid-commissie-ruimte-plaatsvervanger" }, + "commissie": { "register": "commissievergaderingen", "schema": "Commissie", "id": "commissie-ruimte-westerkwartier" }, + "raadslid": { "register": "decidesk", "schema": "Raadslid", "id": "rd-006" }, + "fractie": "GroenLinks", + "rol": "plaatsvervanger", + "begin-datum": "2022-06-15", + "eind-datum": null + }, + { + "@self": { "register": "commissievergaderingen", "schema": "CommissieLidmaatschap", "slug": "lid-commissie-sociaal-001" }, + "commissie": { "register": "commissievergaderingen", "schema": "Commissie", "id": "commissie-sociaal-westerkwartier" }, + "raadslid": { "register": "decidesk", "schema": "Raadslid", "id": "rd-007" }, + "fractie": "VVD", + "rol": "lid", + "begin-datum": "2022-06-15", + "eind-datum": null + }, + { + "@self": { "register": "commissievergaderingen", "schema": "CommissieLidmaatschap", "slug": "lid-commissie-audit-001" }, + "commissie": { "register": "commissievergaderingen", "schema": "Commissie", "id": "commissie-audit-westerkwartier" }, + "raadslid": { "register": "decidesk", "schema": "Raadslid", "id": "rd-008" }, + "fractie": "CDA", + "rol": "lid", + "begin-datum": "2022-06-15", + "eind-datum": null + } +] +``` + +### CommissieVergadering (3 objecten) + +```json +[ + { + "@self": { "register": "commissievergaderingen", "schema": "CommissieVergadering", "slug": "vergadering-ruimte-2026-05-22" }, + "commissie": { "register": "commissievergaderingen", "schema": "Commissie", "id": "commissie-ruimte-westerkwartier" }, + "vergader-datum": "2026-05-22", + "vergader-tijd-start": "19:30", + "vergader-tijd-eind": "21:00", + "locatie": "Raadzaal Westerkwartier", + "openbaar": "ja", + "status": "gepland", + "conceptverslag": null, + "definitief-verslag": null + }, + { + "@self": { "register": "commissievergaderingen", "schema": "CommissieVergadering", "slug": "vergadering-sociaal-2026-05-20" }, + "commissie": { "register": "commissievergaderingen", "schema": "Commissie", "id": "commissie-sociaal-westerkwartier" }, + "vergader-datum": "2026-05-20", + "vergader-tijd-start": "19:00", + "vergader-tijd-eind": "20:30", + "locatie": "Raadzaal Westerkwartier", + "openbaar": "ja", + "status": "agenda-vastgesteld", + "conceptverslag": null, + "definitief-verslag": null + }, + { + "@self": { "register": "commissievergaderingen", "schema": "CommissieVergadering", "slug": "vergadering-audit-2026-05-15" }, + "commissie": { "register": "commissievergaderingen", "schema": "Commissie", "id": "commissie-audit-westerkwartier" }, + "vergader-datum": "2026-05-15", + "vergader-tijd-start": "13:30", + "vergader-tijd-eind": "14:45", + "locatie": "Kantoor Griffie", + "openbaar": "ja", + "status": "gesloten", + "conceptverslag": "Vergadering ging over audit van begrotingsvoorstel 2025.", + "definitief-verslag": "Vergadering ging over audit van begrotingsvoorstel 2025. Commissie adviseerde tot aanname." + } +] +``` + +## Risks / Trade-offs + +| Risico | Mitigatie | +|---|---| +| **R1 — Commissie-samenstelling wijzigt door fractie-wisseling; historische audit breekt.** CommissieLidmaatschap-records kunnen niet muteren; wijziging = eindigen bestaand + starten nieuw. | Fractie-snapshot enforces immutability; history audit-trail toont timings. | +| **R2 — Belangenverstrengeling-declaratie kan worden genegeerd of verkeerd ingevuld.** Lid kan per ongeluk `geen` zeggen terwijl belang bestaat. | Griffier en voorzitter krijgen alert bij `soort !== 'geen'`; live-checklist op vergadering. | +| **R3 — Inspraak-contactgegevens-leak via publieke verslaglegging.** Griffie publiceert per ongeluk contactgegevens in commissie-verslag. | Technische scheiding (twee veldsets) + schema-validatie + testen. | +| **R4 — CommissieAdvies niet gekoppeld aan plenaire raad door technische fout.** Griffie vergeet advies-link in plenaire voorbereiding. | Automatische link via API-trigger; plenaire agendapunt-veld `commissieAdviesRef` is verplicht als commissie-agendapunt bestaat. | +| **R5 — Presentielijst-management is handmatig en error-prone.** Griffier typt plaatsvervanging verkeerd. | API voor plaatsvervanging triggert presentielijst-update automatisch. | +| **R6 — Besloten-zittings-audit-trail leakt via Woo-request.** Systeem-logs tonen toegang tot vertrouwelijke stukken. | Audit-trail gescheiden van app-logs; dual-control voor openbaarmaking; Woo-handler valideert beschermingsgrond. | + +## Migration Plan + +1. **Add register template:** `lib/Settings/commissievergaderingen_register.json` met 8 schemas en seed data +2. **Add migration:** `lib/Migration/CommissionRegistration.php` implementeert `IRepairStep` die `ConfigurationService::importFromApp('commissievergaderingen')` aanroept +3. **Update Application.php:** Registreer CommissionRegistration in repair-steps +4. **Add services:** `CommissionService` + `CommissionMeetingService` met CRUD + business logic +5. **Add controllers:** `CommissionController`, `CommissionMeetingController`, `CommissionAdviceController` met REST API +6. **Add tests:** Unit tests per service, integration tests end-to-end +7. **Add docs:** `docs/features/commissievergaderingen.md` voor operators + +**No data migration.** No modifications to existing Meeting, Participant, Membership schemas. + +**Rollback:** Verwijder register via OpenRegister admin UI; geen SQL rollback nodig. + +**Compatibility:** Opt-in via commissie-beheer in griffie-portaal. diff --git a/openspec/changes/commissievergaderingen/proposal.md b/openspec/changes/commissievergaderingen/proposal.md new file mode 100644 index 00000000..8ab1d825 --- /dev/null +++ b/openspec/changes/commissievergaderingen/proposal.md @@ -0,0 +1,103 @@ +--- +kind: feature +depends_on: [decidesk-base] +--- + +# Commissievergaderingen + +## Why + +Vrijwel elke Nederlandse gemeenteraad werkt met raadscommissies als voorbereidende organen op de plenaire raadsvergadering. De griffie moet commissievergaderingen plannen, samenstelling beheren, belangenconflicten registreren, en commissieadviezen traceerbaar koppelen aan plenaire besluiten. Commissieleden en burgers hebben grote handmatige lasten: fractie-voorzitters moeten per e-mail plaatsvervangers doorgeven, commissieadviezen verdwijnen in PDF-bijlagen, en insprekers moeten hun persoonlijke gegevens publiek maken. + +Deze spec breidt Decidesk uit met een eersteklas commissie-model dat: +- Sub-vergaderingen voor commissies beheert (planning, agendavoorbereiding, verslaglegging) +- Vaste samenstelling per commissie (leden, plaatsvervangers, voorzitter, griffier) bijhoudt +- Belangenverstrengelings-declaraties per agendapunt verplicht stelt (artikel 28 Gemeentewet) +- Commissieadvies automatiseert naar de plenaire raadsagenda (met fractie-standpunten als gestructureerde data) +- Inspraak-aanmelding biedt via publiek portaal met privacy-scheiding (contactgegevens intern, onderwerp publiek) +- Besloten zittingen ondersteunt met aparte toegangscontrole en audit-trail voor Woo-openbaarmaking + +De spec adresseert drie pijnpunten uit griffies-interviews: +1. **Plaatsvervanging**: Fractie-voorzitter geeft plaatsvervanger door via fractie-portaal; presentie en stemrecht synchroniseren automatisch +2. **Advies-tracering**: Commissieadvies wordt eersteklas annotatie op plenaire agendapunt met fractie-standpunten, niet losse PDF +3. **Privacy bij inspraak**: Burgers melden inspraak aan, contactgegevens blijven intern, inspraak-onderwerp en spreker-naam worden publiek + +## What Changes + +- **NEW** 8 schemas: `Commissie`, `CommissieLidmaatschap`, `CommissieVergadering`, `CommissieAgendapunt`, `CommissieAdvies`, `BelangenverstrengelingDeclaratie`, `InspraakAanmelding`, `Presentielijst` +- **NEW** `lib/Settings/commissievergaderingen_register.json` met schema-definities en seed data (3-5 Nederlandse commissies met leden en vergaderingen) +- **NEW** `lib/Migration/CommissionRegistration.php` die de register via `ConfigurationService::importFromApp()` importeert +- **MODIFIED** `lib/AppInfo/Application.php` – registratie van CommissionRegistration +- **NEW** `lib/Service/CommissionService.php` – business logic voor commissie-beheer (samenstelling, plaatsvervanging) +- **NEW** `lib/Service/CommissionMeetingService.php` – commissievergadering-lifecycle en adviesvorming +- **NEW** `lib/Controller/CommissionController.php` – REST API voor commissies en leden +- **NEW** `lib/Controller/CommissionMeetingController.php` – REST API voor commissievergaderingen +- **NEW** `lib/Controller/CommissionAdviceController.php` – adviesvorming en publicatie naar plenaire raad +- **NEW** frontend views voor griffie en commissieleden (Vue.js met Nextcloud Vue) +- **NEW** `tests/Unit/Service/CommissionServiceTest.php` en bijbehorende integration tests +- **NEW** `docs/features/commissievergaderingen.md` – operator docs en gebruikers-handleiding + +## Capabilities + +### New Capabilities + +- `commissie-management`: Commissies instellen op basis van raadsbesluit, samenstelling beheren per fractie, plaatsvervangers aanwijzen +- `commissie-vergaderingen`: Vergaderingen plannen, agenda opstellen, agendapunten typen (mededeling, bespreekstuk, advies-aan-raad, inspraak, besloten), verslaglegging +- `adviesvorming`: Commissieadvies per agendapunt (strekking, tekst, fractie-standpunten), automatische doorgeleiding naar plenaire raad +- `belangenverstrengeling`: Declaratie per commissielid per agendapunt (financieel-belang, aandeelhouderschap, bestuursfunctie, familierelatie, eerder-betrokken, geen), gevolg (onthoudt-zich, verlaat, meldt-maar-blijft) +- `inspraak-aanmelding`: Burgers en organisaties kunnen zich aanmelden voor inspraak via publiek portaal; griffie goedkeurt/wijst af; contactgegevens gescheiden van publieke onderwerp +- `besloten-zittingen`: Agendapunten kunnen als besloten gemarkeerd worden; publieke livestream en portaal onderbr oken; aparte audit-trail voor Woo-openbaarmaking +- `presentielijst-met-plaatsvervanging`: Dynamische presentielijst met aanwezigheid-status, plaatsvervanger-indicatie, aankomst- en vertrektijd +- `commissie-verordening-synchronisatie`: Commissie gekoppeld aan verordening-versie; wijzigingen traceerbaar vastgelegd + +### Modified Capabilities + +- `p2-meeting-management`: CommissieVergadering is sub-type van Meeting; vererft meeting-lifecycle maar voegt commissie-specifieke velden toe +- `p2-decision-flow`: CommissieAdvies wordt linked annotation op plenaire agendapunt; fractie-standpunten als gestructureerde data +- `p3-governance-bodies`: GovernanceBody krijgt commissie-relaties; Commissie heeft raadslid-koppelingen via CommissieLidmaatschap + +## Impact + +**Backend:** +- `lib/Settings/commissievergaderingen_register.json` (new) +- `lib/Migration/CommissionRegistration.php` (new) +- `lib/Service/CommissionService.php` (new) +- `lib/Service/CommissionMeetingService.php` (new) +- `lib/Controller/CommissionController.php` (new) +- `lib/Controller/CommissionMeetingController.php` (new) +- `lib/Controller/CommissionAdviceController.php` (new) +- `lib/AppInfo/Application.php` (modified – migration registration) + +**Frontend:** +- `src/views/CommissionList.vue` (new) +- `src/views/CommissionDetail.vue` (new) +- `src/views/CommissionMeetingAgenda.vue` (new) +- `src/components/CommissionAdvicePanel.vue` (new) +- `src/components/ConflictDeclaration.vue` (new) +- `src/components/InspraakPanel.vue` (new) + +**Data:** +- 8 new OpenRegister schemas; no existing data affected + +**Dependencies:** +- Decidesk base (decidesk-base) +- OpenRegister app (runtime autoloader) +- Nextcloud Vue for frontend components + +**Other apps:** +- `docudesk`: PDF-rendering van commissie-verslagen met eIDAS-handtekening +- `opentalk`: Livestream van openbare commissievergaderingen met tijdcode-koppeling +- `opencatalogi`: Publicatie van publieke commissie-stukken als TOOI-catalogus +- `openconnector`: Synchronisatie naar iBabs/Notubiz; agenda-sync naar Outlook/Google +- `mydash`: Dashboards voor griffie (commissie-activiteit, attendance-trends, advies-ratio) +- `openklant`: Inspraak-aanmeldingen via openklant contactgegevens-beheer + +## Out of Scope + +- Frontend UI in v1 (REST API only; UI follows in p3 sprint) +- Audio/video-recording integration (opentalk-koppeling volgt in p3) +- Livestream-onderbreking bij besloten zitting (opentalk-specifiek, volgt in p3) +- PDF-watermarking voor besloten stukken (docudesk-integratie volgt in p3) +- Automatische kalender-sync (openconnector volgt in p3) +- Dashboard-rendering (mydash volgt in p3) +- Per-role tool visibility voor MCP tools (v2) diff --git a/openspec/changes/commissievergaderingen/specs.md b/openspec/changes/commissievergaderingen/specs.md new file mode 100644 index 00000000..911c9ede --- /dev/null +++ b/openspec/changes/commissievergaderingen/specs.md @@ -0,0 +1,142 @@ +# Specs — Commissievergaderingen + +## REQ-CVG-001: Commissie instellen op basis van raadsbesluit + +**GIVEN** de raad heeft een commissie ingesteld via een formeel raadsbesluit +**WHEN** de griffier via de API een Commissie-record aanmaakt met `instellings-besluit`-referentie +**THEN** wordt de Commissie gekoppeld aan het instellings-besluit via `instellings_besluit_id` +**AND** is de Commissie nadien onwijzigbaar zonder verwijzing naar een wijzigings-raadsbesluit +**AND** verschijnt de Commissie in het publieke register van bestuurlijke organen (TOOI-export) + +## REQ-CVG-002: Samenstelling beheren met fractie-evenredigheid + +**GIVEN** een Commissie heeft vaste samenstelling en fractie-verdeling wijzigt in de raad +**WHEN** de griffier de Commissie-samenstelling herziet via `PUT /commissions/{id}/composition` +**THEN** wordt per fractie het aantal commissiezetels berekend volgens het Reglement van Orde van de gemeente +**AND** kan elke fractie-voorzitter via fractie-portaal haar commissieleden aanwijzen +**AND** wordt de gewijzigde-samenstelling-melding vastgelegd met ingangsdatum en vorig-besluit-referentie + +## REQ-CVG-003: Plaatsvervanging bij afwezigheid + +**GIVEN** een CommissieLid kan niet aanwezig zijn bij een CommissieVergadering +**WHEN** het lid zich afmeldt via `/meetings/{meeting_id}/absences` en een plaatsvervanger uit zijn fractie-groep aanwijst +**THEN** ontvangt de plaatsvervanger automatisch agenda en dossier via e-mail-notificatie +**AND** wordt de Presentielijst bijgewerkt: `plaatsvervanger_door`-veld toont plaatsvervanger plaats van afgemeld lid +**AND** kan de plaatsvervanger meestemmen in adviesvorming en gaat zijn stemming naar fractie-count (niet dubbel) + +## REQ-CVG-004: Belangenverstrengelingsdeclaratie per agendapunt + +**GIVEN** een CommissieVergadering start en een CommissieAgendapunt wordt geopend +**WHEN** voor elk CommissieLid (rol = lid, plaatsvervanger, voorzitter) nog geen BelangenverstrengelingDeclaratie voor dit agendapunt bestaat +**THEN** wordt per lid een declaratie-record aangemaakt met `soort: 'nog-in-te-vullen'` +**AND** wordt lid via notificatie gevraagd declaratie in te vullen (JSON POST naar `/declarations/{id}`) +**AND** kan lid waarde wijzigen naar financieel-belang, aandeelhouderschap, bestuursfunctie, familierelatie, eerder-betrokken, of geen +**AND** bij `soort !== 'geen'` krijgen voorzitter + griffier automatisch alert met lid + soort + gevolg + +## REQ-CVG-005: Gevolg van belangenverstrengeling (onthoudt-zich, verlaat, meldt-maar-blijft) + +**GIVEN** een CommissieLid heeft BelangenverstrengelingDeclaratie met `soort !== 'geen'` ingediend +**WHEN** de voorzitter de gevolg-optie kiest (onthoudt-zich-van-stemming, verlaat-vergadering, meldt-maar-blijft) +**THEN** wordt gevolg opgeslagen op declaratie-record +**AND** bij `onthoudt-zich`: lid blijft op presentielijst maar krijgt geen stemrecht op dit agendapunt +**AND** bij `verlaat`: lid wordt van presentielijst afgehaald (vertrek-time geregistreerd) +**AND** bij `meldt-maar-blijft`: notatie wordt in verslag opgenomen, lid behoudt stemrecht + +## REQ-CVG-006: Adviesvorming met fractie-standpunten + +**GIVEN** een CommissieVergadering behandelt een CommissieAgendapunt van type `advies-aan-raad` +**WHEN** de voorzitter de beraadslaging afsluit via `POST /agenda-items/{id}/finalize-advice` +**THEN** wordt voor elke fractie met leden in commissie gevraagd hun standpunt (voor, tegen, verdeeld, geen-mening) +**AND** wordt CommissieAdvies aangemaakt met: + - `advies-strekking`: samengestelde aanbeveling (positief, negatief, verdeeld, geen-advies, verzoek-tot-aanpassing) + - `fractie-standpunten`: array van {fractie-naam, standpunt} + - `advies-tekst`: rich-text samenvatting van beraadslaging + - `stemverhouding-samenvatting`: bijv "3 voor, 1 tegen, 1 verdeeld" +**AND** wordt CommissieAdvies automatisch gekoppeld aan het beoogd-raadsvoorstel (plenaire AgendaItem) via relatie + +## REQ-CVG-007: Commissieadvies op plenaire agendapunt + +**GIVEN** een plenaire raadsvergadering bereidt een agendapunt voor dat eerder in commissie is voorbesproken +**WHEN** griffier of raadslid het CommissieAdvies opvraagt via `/agenda-items/{id}/commission-advice` +**THEN** verschijnt het CommissieAdvies in volledige vorm: + - Titel vorige agendapunt (commissie) + - Advies-strekking + - Fractie-standpunten gegroepeerd per fractie + - Advies-tekst + - Link naar commissie-verslag +**AND** kan raadslid dit advies gebruiken ter voorbereiding plenaire beraadslaging + +## REQ-CVG-008: Thema-bijeenkomst zonder advies-vorming + +**GIVEN** de griffie organiseert een raadsbrede beeldvormende sessie (geen advies) +**WHEN** CommissieVergadering wordt gemarkeerd met `type: 'thema-bijeenkomst'` +**THEN** vervalt de verplichte adviesvorming-stap +**AND** kunnen alle raadsleden (niet alleen commissieleden) zich aanmelden via `/public-api/registration` +**AND** wordt presentielijst en lichtgewicht verslag opgesteld (geen stemverhoudingen) + +## REQ-CVG-009: Inspraak-aanmelding via publiek portaal + +**GIVEN** een CommissieVergadering staat gepland en burger wil inspreken op specifiek agendapunt +**WHEN** burger zich aanmeldt via publiek portaal `POST /public-api/commissions/{id}/inspraak` +**THEN** wordt InspraakAanmelding aangemaakt met twee veldgroepen: + - `contactgegevens` (naam, email, telefoon, adres — alleen voor griffie zichtbaar) + - `onderwerp` (spreker-naam (kan pseudoniem), organisatie, spreektijd-aanvraag — publiek) +**AND** griffier ziet aanvraag in griffie-portaal en kan goedkeuren, afwijzen (met reden), of doorverwijzen +**AND** burger ontvangt bevestiging met spreektijd-toewijzing +**AND** sluit aanmelding automatisch 24 uur voor vergadering (konfigurabel per commissie via `inspraak-deadline-uren`) + +## REQ-CVG-010: Besloten zitting met aparte toegangscontrole + +**GIVEN** een CommissieAgendapunt is gemarkeerd als type `besloten-onderdeel` (personeels-aangelegenheid, grond-aankoop) +**WHEN** CommissieVergadering bij dit punt aanvangt +**THEN** wordt het publieke portaal en eventuele livestream onderbroken +**AND** krijgen alleen Commissieleden, voorzitter, griffier en expliciet uitgenodigde adviseurs (via lijst) toegang tot agendapunt-stukken +**AND** wordt een aparte besloten-zittings-notulen-track aangemaakt in CommissieVergadering (veld `besloten_verslag`) +**AND** audittrace worden geregistreerd: wie heeft wanneer besloten-stukken ingezien + +## REQ-CVG-011: Verslag publicatie naar griffieportaal + +**GIVEN** een CommissieVergadering is afgesloten en conceptverslag is goedgekeurd in volgende vergadering +**WHEN** griffier het verslag via API als definitief markeert (`PUT /meetings/{id}/minutes` met `status: 'approved'`) +**THEN** wordt verslag gepubliceerd op griffieportaal met: + - Volledige agendalist + - Presentielijst (met afwezigen-reden waar getoond) + - CommissieAdviezen (per agendapunt waar advies gegeven) + - InspraakAanmeldingen (publieke delen: spreker-naam, organisatie, onderwerp) + - Definitief verslag (rich text) +**AND** wordt OWMS-metadata gegenereerd voor zoekmachine-indexering en opendata-export (Via Who/Woo) + +## REQ-CVG-012: Conflict-of-interest rapportage per periode + +**GIVEN** de rekenkamer, journalist, of raadslid wil zicht op gemelde belangen +**WHEN** gebruiker via griffie-portaal rapportage `belangen-overzicht` opvraagt voor periode (bv "januari-maart 2026") +**THEN** wordt overzicht gegenereerd van alle BelangenverstrengelingDeclaraties per CommissieLid in die periode, gegroepeerd op soort (financieel-belang, aandeelhouderschap, etc.) +**AND** worden alleen openbare delen getoond (besloten-zittings-declaraties worden afgeschermd) +**AND** is rapport exporteerbaar als CSV/PDF voor archief/audit + +## REQ-CVG-013: Commissie-verordening synchronisatie + +**GIVEN** raad wijzigt Verordening op de Raadscommissies (bv aantal commissies, samenstelling, spreektijd-limits) +**WHEN** griffier de gewijzigde verordening importeert via import-wizard +**THEN** wordt Commissie-record gekoppeld aan verordening-versie via immutable-referentie +**AND** worden Commissie-wijzigingen (samenstelling, type, frequentie) gevalideerd tegen verordening-tekst (logische checks via rules-engine) +**AND** eerdere CommissieVergaderingen tonen met op-dat-moment-geldende verordening-regels (bv "spreektijd destijds 3min, nu 5min") +**AND** wordt elke gemeente-specifieke afwijking gemarkeerd in audit-trail + +--- + +## Implementation Notes + +- REQ-CVG-004 en REQ-CVG-005 implementeren artikel 28 Gemeentewet (verhindering belangenverstrengeling) +- REQ-CVG-009 implementeert privacy (contactgegevens ↔ publieke inspraak) conform AVG +- REQ-CVG-010 implementeert artikel 86 Gemeentewet (geheimhouding besloten zitting) + audit-trail voor Woo-toetsing +- REQ-CVG-011 en REQ-CVG-012 implementeren Woo-transparantie + Archiefwet-naleving (bewaartermijn) +- REQ-CVG-013 implementeert traceerbaarheid naar juridisch-bindend raadsbesluit (verdedigingsstrategie tegen bestuursrechter-bezwaar) + +## Data Integrity Constraints + +- `CommissieLidmaatschap.fractie` is immutable snapshot; wijziging vereist eindigen-date + nieuw record +- `BelangenverstrengelingDeclaratie` per lid-agendapunt combinatie is uniek; create-if-not-exists pattern +- `CommissieAdvies` kan alleen ontstaan na beraadslaging (CommissieAgendapunt.status: 'behandeld') +- `Presentielijst` één per CommissieVergadering; wijzigingen via transactie-pattern (versioning) +- `InspraakAanmelding` onveranderlijk na `status: 'goedgekeurd'`; geen edit-after-approval diff --git a/openspec/changes/commissievergaderingen/tasks.md b/openspec/changes/commissievergaderingen/tasks.md new file mode 100644 index 00000000..f3c330c4 --- /dev/null +++ b/openspec/changes/commissievergaderingen/tasks.md @@ -0,0 +1,183 @@ +# Tasks — Commissievergaderingen + +## 1. Register Definition + +- [ ] 1.1 Create `lib/Settings/commissievergaderingen_register.json` as OpenAPI 3.0.0 document with `x-openregister` extensions +- [ ] 1.2 Define `Commissie` schema with all properties: naam, type, portefeuille-scope, voorzitter, griffier, vergader-frequentie, vaste-vergaderdag, vergader-tijdstip, vergader-locatie, instellings-datum, instellings-besluit, opheffings-datum, openbaarheids-default +- [ ] 1.3 Define `CommissieLidmaatschap` schema with properties: commissie-ref, raadslid-ref, fractie (snapshot), rol, begin-datum, eind-datum, beëindigings-reden +- [ ] 1.4 Define `CommissieVergadering` schema with relation to Commissie, plus velden: vergader-datum, vergader-tijd-start, vergader-tijd-eind, locatie, openbaar (ja/besloten/gedeeltelijk), status, audio-opname-url, video-opname-url, conceptverslag, definitief-verslag +- [ ] 1.5 Define `CommissieAgendapunt` schema with relation to CommissieVergadering, plus: volgnummer, titel, type (mededeling, bespreekstuk, hamerstuk, advies-aan-raad, inspraak, besloten-onderdeel), beoogd-raadsvoorstel-ref, portefeuillehouder, behandel-duur-geschat, bijlagen +- [ ] 1.6 Define `CommissieAdvies` schema with relation to CommissieAgendapunt + plenaire AgendaItem, plus: advies-strekking (positief, negatief, verdeeld, geen-advies, verzoek-tot-aanpassing), advies-tekst (rich text), stemverhouding-samenvatting, fractie-standpunten (array), inspraak-samenvatting +- [ ] 1.7 Define `BelangenverstrengelingDeclaratie` schema with relation to CommissieLid + CommissieAgendapunt, plus: soort (financieel-belang, aandeelhouderschap, bestuursfunctie, familierelatie, eerder-betrokken, geen), beschrijving, gevolg (onthoudt-zich-van-stemming, verlaat-vergadering, meldt-maar-blijft), declaratie-datum +- [ ] 1.8 Define `InspraakAanmelding` schema with relation to CommissieVergadering + CommissieAgendapunt, plus: twee veld-secties (contactgegevens: naam, email, telefoon, adres; publiek-deel: spreker-naam, organisatie, spreektijd-aanvraag), onderwerp (publiek), status (aangemeld, goedgekeurd, afgewezen, gesproken, niet-verschenen), bijdrage-tekst, woon-of-werk-plaats +- [ ] 1.9 Define `Presentielijst` schema with relation to CommissieVergadering + CommissieLid, plus: aanwezig (aanwezig, afwezig-met-bericht, afwezig-zonder-bericht, plaatsvervangen-door), aankomst-tijd, vertrek-tijd, presentievergoeding-uitbetaald +- [ ] 1.10 Add Commissie seed data: 3 Nederlandse commissies (Commissie Ruimte, Commissie Sociaal, Commissie Audit) met TOOI-portefeuille-scope +- [ ] 1.11 Add CommissieLidmaatschap seed data: 5+ leden per fractie-mix over commissies +- [ ] 1.12 Add CommissieVergadering seed data: 3+ vergaderingen met verschillende statussen (gepland, agenda-vastgesteld, gesloten) +- [ ] 1.13 Add CommissieAgendapunt seed data: 8+ agendapunten per vergadering-mix (mededeling, bespreekstuk, advies-aan-raad, inspraak, besloten) +- [ ] 1.14 Verify schema.org type annotations present (commissie → custom:CommissionBody, CommissieLid → foaf:Person, etc.) + +## 2. Backend Services + +- [ ] 2.1 Create `lib/Service/CommissionService.php` with methods: + - `getCommission(uuid): Commission` + - `listCommissions(filters, pagination): array` + - `createCommission(array $data): Commission` + - `updateCommission(uuid, array $data): Commission` + - `deleteCommission(uuid): void` +- [ ] 2.2 Add `CommissionService::updateComposition(uuid, array $newMembership)` to handle fractie-evenredigheid berekening +- [ ] 2.3 Add validation in `updateComposition` against Reglement-van-Orde rules (bijv max commissieleden per fractie) +- [ ] 2.4 Create `lib/Service/CommissionMeetingService.php` with methods: + - `getMeeting(uuid): CommissieVergadering` + - `listMeetings(commissie-uuid, filters): array` + - `createMeeting(commissie-uuid, array $data): CommissieVergadering` + - `transitionMeeting(uuid, new-status): CommissieVergadering` + - `publishMinutes(uuid, minutes-text): CommissieVergadering` +- [ ] 2.5 Add `CommissionMeetingService::finalizeAdvice(agenda-item-uuid, fractie-standpunten)` to create CommissieAdvies with gestructureerde fractie-data +- [ ] 2.6 Create `lib/Service/CommissionAdviceService.php` with: + - `getAdvice(uuid): CommissieAdvies` + - `linkAdviceToPlenaryItem(advice-uuid, plenaire-agenda-item-uuid): void` (automatische koppeling) + - `getAdviceForPlenaryItem(agenda-item-uuid): CommissieAdvies` +- [ ] 2.7 Create `lib/Service/ConflictDeclarationService.php` with: + - `createDeclaration(lid-uuid, agendapunt-uuid): BelangenverstrengelingDeclaratie` + - `updateDeclaration(declaratie-uuid, soort, beschrijving, gevolg): void` + - `getDeclarationsForMeeting(meeting-uuid): array` + - `alertChairAndSecretary(declaratie-uuid)` (notification-service integratie) +- [ ] 2.8 Create `lib/Service/InspraakService.php` with: + - `submitInspraakRequest(commissie-uuid, agendapunt-uuid, contactgegevens, onderwerp): InspraakAanmelding` + - `approveInspraak(aanmelding-uuid): void` + - `rejectInspraak(aanmelding-uuid, reden): void` + - `getPublicInspraakForMeeting(meeting-uuid): array` (contactgegevens gefilterd) + - `checkInspraakDeadline(meeting-uuid): bool` +- [ ] 2.9 Create `lib/Service/PresenceListService.php` with: + - `initializePresenceList(meeting-uuid, commissie-uuid): Presentielijst` + - `recordPresence(presentielijst-uuid, lid-uuid, status, aankomst-tijd): void` + - `recordSubstitution(presentielijst-uuid, afwezig-lid-uuid, plaatsvervanger-uuid): void` + - `finalizPresenceList(presentielijst-uuid): void` +- [ ] 2.10 All services inject `ObjectService` (OpenRegister CRUD) + `Audit Logservice` +- [ ] 2.11 All services implement error-handling: invalid UUIDs → HTTP 400, not-found → 404, forbidden → 403 + +## 3. REST Controllers + +- [ ] 3.1 Create `lib/Controller/CommissionController.php` with routes: + - `GET /apps/decidesk/api/commissions` → list all (with filters: type, governance-body) + - `GET /apps/decidesk/api/commissions/{uuid}` → get single + - `POST /apps/decidesk/api/commissions` → create (griffier+ required) + - `PUT /apps/decidesk/api/commissions/{uuid}` → update (griffier+ required) + - `PUT /apps/decidesk/api/commissions/{uuid}/composition` → update samenstelling (griffier+ required) + - `DELETE /apps/decidesk/api/commissions/{uuid}` → delete (griffier+ required) +- [ ] 3.2 Create `lib/Controller/CommissionMembershipController.php` with routes: + - `GET /apps/decidesk/api/commissions/{uuid}/members` → list leden per commissie + - `POST /apps/decidesk/api/commissions/{uuid}/members` → add lid (fractie-voorzitter or griffier+) + - `DELETE /apps/decidesk/api/commissions/{uuid}/members/{lid-uuid}` → remove lid +- [ ] 3.3 Create `lib/Controller/CommissionMeetingController.php` with routes: + - `GET /apps/decidesk/api/commissions/{uuid}/meetings` → list vergaderingen + - `GET /apps/decidesk/api/commissions/{uuid}/meetings/{meeting-uuid}` → get vergadering + - `POST /apps/decidesk/api/commissions/{uuid}/meetings` → schedule vergadering (griffier+) + - `PUT /apps/decidesk/api/commissions/{uuid}/meetings/{meeting-uuid}` → update vergadering + - `PUT /apps/decidesk/api/commissions/{uuid}/meetings/{meeting-uuid}/transition` → change status (griffier+) + - `PUT /apps/decidesk/api/commissions/{uuid}/meetings/{meeting-uuid}/minutes` → approve minutes (griffier+) +- [ ] 3.4 Create `lib/Controller/CommissionAgendaController.php` with routes: + - `GET /apps/decidesk/api/meetings/{meeting-uuid}/agenda` → list agendapunten + - `POST /apps/decidesk/api/meetings/{meeting-uuid}/agenda` → add agendapunt (griffier+) + - `PUT /apps/decidesk/api/meetings/{meeting-uuid}/agenda/{item-uuid}` → update agendapunt + - `POST /apps/decidesk/api/meetings/{meeting-uuid}/agenda/{item-uuid}/finalize-advice` → sluit adviesvorming af (voorzitter+) +- [ ] 3.5 Create `lib/Controller/CommissionAdviceController.php` with routes: + - `GET /apps/decidesk/api/advice/{uuid}` → get CommissieAdvies + - `GET /apps/decidesk/api/agenda-items/{item-uuid}/commission-advice` → get advies voor plenair (REQ-CVG-007) + - `POST /apps/decidesk/api/advice/{uuid}/link-to-plenary` → link naar plenaire item (griffier+) +- [ ] 3.6 Create `lib/Controller/ConflictDeclarationController.php` with routes: + - `GET /apps/decidesk/api/declarations` → list voor huidi ge lid + - `GET /apps/decidesk/api/declarations/{meeting-uuid}` → list per vergadering (griffier+) + - `POST /apps/decidesk/api/declarations/{uuid}` → submit/update declaratie (lid) + - `PUT /apps/decidesk/api/declarations/{uuid}/consequence` → set gevolg (voorzitter+) + - `GET /apps/decidesk/api/conflict-reports` → generate rapportage (griffier+, rekenkamer+) +- [ ] 3.7 Create `lib/Controller/PresenceListController.php` with routes: + - `GET /apps/decidesk/api/meetings/{meeting-uuid}/presence` → get presentielijst + - `POST /apps/decidesk/api/meetings/{meeting-uuid}/presence/{lid-uuid}` → record presence (griffier+) + - `POST /apps/decidesk/api/meetings/{meeting-uuid}/absences/{lid-uuid}/substitute` → record plaatsvervanging (lid + griffier+) +- [ ] 3.8 Create `lib/Controller/InspraakPublicController.php` with routes (NO auth required for submission): + - `POST /apps/decidesk/api/public/commissions/{uuid}/inspraak` → submit request (public) + - `GET /apps/decidesk/api/public/commissions/{uuid}/meetings/{meeting-uuid}/inspraak` → list publieke inspraak (public) +- [ ] 3.9 Create `lib/Controller/InspraakController.php` with routes (griffier+): + - `GET /apps/decidesk/api/commissions/{uuid}/inspraak` → list alle aanmeldingen + - `PUT /apps/decidesk/api/inspraak/{uuid}/approve` → goedkeuren + - `PUT /apps/decidesk/api/inspraak/{uuid}/reject` → afwijzen +- [ ] 3.10 Add authorization middleware to all controllers: `requireCommissionMember()`, `requireChairOrSecretary()`, `requireGriffier()` checks +- [ ] 3.11 Add input validation to all POST/PUT routes (JSON Schema validation per OpenAPI spec) + +## 4. Data Migrations + +- [ ] 4.1 Create `lib/Migration/CommissionRegistration.php` implementing `IRepairStep` that: + - Loads `commissievergaderingen_register.json` + - Calls `ConfigurationService::importFromApp('commissievergaderingen')` + - Logs success/failure + object counts + - Implements `getDescription()` with fix description +- [ ] 4.2 Register repair step in `appinfo/info.xml` under `` +- [ ] 4.3 Test idempotency: run repair step twice, verify no duplicate seed-data created +- [ ] 4.4 Add rollback documentation: "Delete register via OpenRegister admin UI" + +## 5. Tests + +- [ ] 5.1 Create `tests/Unit/Service/CommissionServiceTest.php`: + - Test create, update, delete commission + - Test updateComposition with fractie-calculation + - Test validation against Reglement rules +- [ ] 5.2 Create `tests/Unit/Service/CommissionMeetingServiceTest.php`: + - Test meeting lifecycle transitions + - Test finalizeAdvice with fractie-standpunten +- [ ] 5.3 Create `tests/Unit/Service/ConflictDeclarationServiceTest.php`: + - Test lazy-creation per agendapunt + - Test alert on soort !== 'geen' + - Test consequences: onthoudt-zich, verlaat, meldt-maar-blijft +- [ ] 5.4 Create `tests/Unit/Service/InspraakServiceTest.php`: + - Test contactgegevens/onderwerp separation + - Test deadline checking + - Test public endpoint (no auth) +- [ ] 5.5 Create `tests/Integration/CommissionApiTest.php`: + - Test full workflow: create commission → schedule meeting → add agenda → finalize advice + - Test authorization: griffier can edit, lid cannot + - Test advice-linking to plenary item +- [ ] 5.6 Create `tests/Integration/PresenceAndSubstitutionTest.php`: + - Test presentielijst-creation + - Test substitution workflow: lid absence → substitute gets access + - Test voting-rights: substitute counts, not original +- [ ] 5.7 Create `tests/Integration/ConflictDeclarationTest.php`: + - Test alert generation on conflict declaration + - Test consequences affect voting +- [ ] 5.8 Create `tests/Integration/InspraakPublicTest.php`: + - Test public submission (no auth) + - Test griffier approval/rejection + - Test public view filters contactgegevens +- [ ] 5.9 Ensure all tests use real OpenRegister ObjectService (not mocks) +- [ ] 5.10 Run `composer check:strict` — ensure all PHP is typed + +## 6. Documentation + +- [ ] 6.1 Create `docs/features/commissievergaderingen.md` with: + - Feature overview (3-5 paragraphs) + - Architecture diagram (relations between schemas) + - User journeys: griffier planning, lid declaring conflict, burger inspraak + - API reference (routes, required auth, example payloads) + - Configuration options (inspraak-deadline-uren, Reglement-van-Orde file location) + - Troubleshooting: common errors, logs to check +- [ ] 6.2 Add ADR note in docs explaining commission-type enum vs separate schemas decision +- [ ] 6.3 Document privacy-model for inspraak (contactgegevens vs onderwerp) +- [ ] 6.4 Document audit-trail strategy for besloten zittingen (Woo-compliance) +- [ ] 6.5 Create migration guide for legacy systems (iBabs, Notubiz) → commissievergaderingen format + +## 7. Integration with Other Apps + +- [ ] 7.1 Define API contract with decidesk-base (Meeting, AgendaItem, Participant relations) +- [ ] 7.2 Define hooks for docudesk: "commission-minutes-ready" → trigger PDF rendering +- [ ] 7.3 Define hooks for opentalk: "meeting-status-changed" → livestream pause/resume for besloten zitting +- [ ] 7.4 Define hooks for opencatalogi: "minutes-published" → TOOI-export with OWMS-metadata +- [ ] 7.5 Document MCP tool extension points (future p3: AI chat companion querying commission advice) + +## 8. Deployment & Rollout + +- [ ] 8.1 Create migration documentation for griffies (how to set up first commissies) +- [ ] 8.2 Create data-validation checklist (all commissies linked to raadsbesluiten?) +- [ ] 8.3 Create backup strategy: register-export before first production use +- [ ] 8.4 Set up monitoring: track failed inspraak-submissions, conflict-declaration alert latency +- [ ] 8.5 Create runbook for common issues (duplicate members, deadline-enforcement, audit-trail gaps) From 36b34061116388150be258799d7cb4b6a07bb463 Mon Sep 17 00:00:00 2001 From: Specter Intelligence Date: Fri, 22 May 2026 07:43:24 +0200 Subject: [PATCH 2/4] feat: Add OpenSpec change commissievergaderingen from Specter --- .specter-prompt.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.specter-prompt.txt b/.specter-prompt.txt index afd81d0f..4ca69320 100644 --- a/.specter-prompt.txt +++ b/.specter-prompt.txt @@ -4,19 +4,19 @@ You are running HEADLESS. Do NOT use AskUserQuestion, interactive prompts, or sk Write files directly using the Write tool. ## Inputs -- Change: mcp-tools (title: mcp-tools Specification) -- Context brief: openspec/changes/mcp-tools/context-brief.md +- Change: commissievergaderingen (title: Commissievergaderingen) +- Context brief: openspec/changes/commissievergaderingen/context-brief.md - Data model ADR: openspec/architecture/adr-000-data-model.md ## Step 1: Read context Read these files COMPLETELY before writing anything: -- openspec/changes/mcp-tools/context-brief.md (features, stories, stakeholders, journeys) +- openspec/changes/commissievergaderingen/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 mcp-tools --json` +Run: `openspec instructions proposal --change commissievergaderingen --json` This returns the template and rules for the proposal artifact. Then do the same for: design, specs, tasks (in that order). @@ -35,8 +35,8 @@ For each artifact (proposal → design → specs → tasks): ## Step 4: Commit After all 4 artifacts are written: ```bash -git add openspec/changes/mcp-tools/ -git commit -m 'feat: Add OpenSpec change mcp-tools from Specter' +git add openspec/changes/commissievergaderingen/ +git commit -m 'feat: Add OpenSpec change commissievergaderingen from Specter' ``` Do NOT push — the caller handles pushing. Do NOT create branches — stay on the current branch. From bd5b082e1061a3a07ad834d23c9b9b664434a4bb Mon Sep 17 00:00:00 2001 From: Specter Intelligence Date: Fri, 22 May 2026 07:43:24 +0200 Subject: [PATCH 3/4] chore: add hydra.json for commissievergaderingen --- openspec/changes/commissievergaderingen/hydra.json | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 openspec/changes/commissievergaderingen/hydra.json diff --git a/openspec/changes/commissievergaderingen/hydra.json b/openspec/changes/commissievergaderingen/hydra.json new file mode 100644 index 00000000..8c017946 --- /dev/null +++ b/openspec/changes/commissievergaderingen/hydra.json @@ -0,0 +1,8 @@ +{ + "spec_slug": "commissievergaderingen", + "title": "Commissievergaderingen", + "app": "decidesk", + "repo": "https://github.com/ConductionNL/decidesk", + "depends_on": [], + "issue": null +} \ No newline at end of file From a550a58b48d9ce601fc527901181ca4d06c48e38 Mon Sep 17 00:00:00 2001 From: Ruben van der Linde Date: Fri, 22 May 2026 15:00:41 +0200 Subject: [PATCH 4/4] docs(brief): inject Placement & IA section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Automated update — captures Information Architecture placement for builders. --- .../changes/commissievergaderingen/context-brief.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/openspec/changes/commissievergaderingen/context-brief.md b/openspec/changes/commissievergaderingen/context-brief.md index 8a01cc9c..6b364625 100644 --- a/openspec/changes/commissievergaderingen/context-brief.md +++ b/openspec/changes/commissievergaderingen/context-brief.md @@ -15,6 +15,17 @@ references: # Commissievergaderingen +## Placement & Information Architecture + +**Placement type:** `SUB_PAGE` — Sub-page beneath a top-level menu entry. Renders as a page inside the parent surface (usually reachable via a router child route or a tab on the parent index page). + +**Lives at:** Vergaderingen filter "Commissie" + Fracties & Organen > Commissies / split + +**Rationale:** A meeting type + an organ definition +_Source: /tmp/ia-doc-dec-cat-conn.md_ + +> **Implementation note for builders:** Respect the placement above. Do not promote this spec to a top-level menu item, sub-page, or new route unless the placement type explicitly says so. If the placement is `DETAIL_TAB`, `WIDGET`, `ACTION`, `SETTING`, or `INFRA`, the feature must NOT introduce a new entry in the app sidebar. When in doubt, ask before creating a new top-level surface. + ## Purpose Vrijwel elke Nederlandse gemeenteraad werkt met raadscommissies als voorbereidende organen op de plenaire raadsvergadering. Veelvoorkomende commissies zijn de audit-commissie (financiën en rekenkamer), commissie ruimte (ruimtelijke ordening, wonen, mobiliteit), commissie sociaal (zorg, jeugd, participatie), en commissie bestuur (algemeen bestuur, veiligheid, dienstverlening). De commissies hebben geen besluitvormende bevoegdheid maar geven advies aan de raad over voorliggende voorstellen, voeren technische beraadslagingen, en horen burgers en organisaties via inspraak. Een gemeente kent typisch 3 tot 6 commissies die elk maandelijks vergaderen — voor de griffie een aanzienlijke planningslast, en voor commissieleden een complex puzzelstuk van agenda's, dossiers en belangenverstrengelings-meldingen. Daarnaast worden in toenemende mate raadsbrede thema-bijeenkomsten en informele beeldvormende sessies onder de commissie-vlag georganiseerd, wat aparte planning-, presentie- en publicatie-regels vraagt.