# Monsys.ai — Implementation Roadmap v1.1

*Gefaseerd actieplan op basis van de strategische analyse. Versie 1.1 — 19 mei 2026.*

**Wat is nieuw t.o.v. v1.0:**
- Fase 0.3 — MSP-pricing validatie als verplichte gate vóór fase 2
- Fase 1.2b — Externe CISO-review einde week 3 (was 1.6 in week 5-6)
- Drift Detection verplaatst van fase 4.3 → fase 1.4 (is Trust Score-input)
- Community Marketplace verplaatst van fase 3.5 → fase 5 (post-50-tenants)
- Trust Score formule gefixt: maintenance-aware, EAT-resolution i.p.v. -ack, tenant-age bootstrap
- Multi-party signing (3.2) dependency op 3.4 expliciet + SMS fallback
- AI Incident Summarisation (3.1) krijgt rate-limit voor cost-control
- Horizontale regel toegevoegd: elke migratie/worker moet backwards-compat zijn met oude agent-versies

**Hoe dit document te gebruiken:**
- Elk item heeft scope, acceptance criteria, dependencies en een Claude Code-trigger
- "Claude Code trigger" = de eerste prompt die je in een verse CC-sessie geeft
- Tijdsestimaten gaan ervan uit dat Claude Code de implementatie doet, niet jij handmatig
- ✅ Vink af als acceptance criteria gehaald zijn
- Verticale volgorde = aanbevolen volgorde; horizontale parallellisatie expliciet vermeld

---

## Horizontale invarianten (gelden voor élk item)

Deze regels gelden voor élk roadmap-item zonder ze elke keer te herhalen.

| Invariant | Wat het betekent |
|---|---|
| **tenant_id-WHERE-pattern** | Elke query op een domeintabel pinnt `WHERE tenant_id = $1::UUID`. RLS is backstop, niet primaire check. |
| **Backwards-compat met oude agents** | Elke nieuwe worker / handler die agent-data leest moet `gracefully degrade` bij agents op een oudere binary-versie. Geen panics, geen NULL-cascade. Standaard: `COALESCE(...) AS …`, of expliciete `agent_version >= 'X'` guard. |
| **i18n NL/FR/EN** | Elke nieuwe UI-string heeft alle drie de keys. Default = NL. Geen English-only ship. |
| **Ed25519 signing** | Alles wat "audit-grade" claimt is gesigneerd met `MONSYS_HUB_SIGNING_KEY_HEX` of `MONSYS_EMERGENCY_PRIVATE_KEY`. Verify-pad bestaat altijd. |
| **Pixel-grid branding** | Sharp 1px borders, dotted dividers, square status pixels, monospace voor data. Geen emoji's in dashboard (alleen op `/api/v1/ai/explain` AI-output, met de standaard regel). |
| **Audit-log voor mutaties** | Elke UserAuth mutation gaat door `middleware.Audit(pool)` middleware automatisch — handler hoeft niets toe te voegen behalve duidelijke `event_type`. |

Elke "Claude Code trigger" mag aannemen dat deze invarianten gelden. Geen herhaling nodig in elke prompt.

---

## Fase 0 — Voorbereiding (deze week)

### 0.1 Project context-document voor Claude Code uitbreiden
**Status:** ☐
**Tijd:** 1-2 uur
**Doel:** Eén `CLAUDE.md`-aanvulling in de hub-repo die per nieuwe feature de architecturale invariants en code-style afdwingt.

**Acceptance criteria:**
- [ ] `hub/CLAUDE.md` bevat sectie "Trust Score & Compliance — non-negotiables"
- [ ] Sectie kopieert de horizontale invarianten-tabel hierboven
- [ ] Migration-template gedocumenteerd (numbering, up/down, RLS policy verplicht, backwards-compat note)
- [ ] Handler-template met UserAuth + scope check + audit log
- [ ] Worker-template met `gracefulDegradeOnOldAgents()` helper

**Claude Code trigger:**
> "Open `/home/user/monsys/CLAUDE.md` en breid het uit met een sectie 'Trust Score & Compliance non-negotiables'. Kopieer de horizontale invarianten uit `MONSYS_IMPLEMENTATION_ROADMAP_V11.md` letterlijk. Voeg handler-template + migration-template + worker-template toe met expliciete backwards-compat behandeling. Houd het kort en imperatief geschreven."

---

### 0.2 Sales-pitch one-pager (geen code)
**Status:** ☐
**Tijd:** 1 uur (zelf, niet Claude Code)
**Doel:** Eén PDF/MD die de pivot van "sysadmin tool" naar "audit-deliverable platform" vastlegt voor jezelf en je co-founders.

**Acceptance criteria:**
- [ ] Eén pagina, gericht op CISO/compliance-lead van Belgische SME
- [ ] Headline-claim: *"Monsys turns NIS2-compliance into a monthly signed PDF."*
- [ ] NL-variant: *"Beheer je servers zonder ze ooit weg te geven."*
- [ ] Drie bullet-features: Trust Score, Evidence Packs, EAT-audit-trail
- [ ] Een mock-screenshot van Trust Score-dashboard (mag een schets zijn)

**Waarom hier:** Voorkomt dat je de pivot vergeet zodra je in de code duikt. Dit is je noord-ster voor de komende 6 maanden.

---

### 0.3 MSP-pricing validatie (NIEUW IN V1.1 — verplichte gate vóór fase 2)
**Status:** ☐
**Tijd:** 2 weken (verlopen tijd, geen werk-uren)
**Doel:** Voorkomen dat we 4-6 weken MSP-infra bouwen voor een markt die er niet om vraagt.

**Scope:**
Drie expliciete pitch-gesprekken met Belgische MSPs over de €1.50/server wholesale tier. Vóór week 6 (start fase 2) moeten minimaal 2 van 3 mondeling commitment hebben tot pilot.

**Target MSPs (warm via BeHosted-netwerk):**
- Easi (Antwerpen, Vlaamse SME-markt)
- Combell-aangrenzende spelers (Combell zelf is te groot)
- Eén of twee Brusselse/Waalse MSPs van 20-100 medewerkers
- *Niet* Cegeka of Proximus — te groot, te traag in beslissing

**Pitch-script in 5 minuten:**
1. NIS2/CRA deadline 2026: je klanten gaan ernaar vragen, je hebt geen team om dit zelf op te bouwen
2. Monsys levert per klant een ondertekende maandelijkse audit-PDF
3. €3 retail, €1.50 wholesale = €1.50 marge per server per maand
4. Pilot: 5 klanten, 3 maanden, gratis monsys-side
5. "Welke 5 klanten zou je deze week pilot-aan-zetten als ik je vandaag toegang gaf?"

**Acceptance criteria:**
- [ ] 3 gesprekken gevoerd, datums vastgelegd in agenda
- [ ] Notities per gesprek: prijsgevoeligheid, deal-blockers, gevraagde features
- [ ] Minimaal 2 van 3 mondelinge commitment tot 3-maand-pilot
- [ ] **Bij minder dan 2 commitments: fase 2 wordt uitgesteld en fase 1 wordt verbreed** (extra dashboard polish, betere onboarding, lager priced standaard tier i.p.v. MSP-spel)

**Waarom belangrijk:** Geen enkele andere fase mag starten op aannames. Dit is het cheapste experiment dat €30k aan dev-werk kan besparen als de markt-aanname fout is.

---

## Fase 1 — Trust Score & Audit Pack (4-6 weken)

Dit is je sales-deliverable. Alles in deze fase werkt naar één PDF die een auditor begrijpt.

### 1.1 Trust Score 1.0 — backend (formule GEWIJZIGD IN V1.1)
**Status:** ☐
**Tijd:** 1-2 weken
**Dependencies:** geen — migratie 056 staat al; vereist 1.4 (drift) voor 100% accurate score, draait tot dan met component-blanking
**Parallel met:** 1.2 (frontend kan vooruitgaan met mock-data), 1.4 (drift detection)

**Scope:**
- Berekening per agent: 0-100 score met 6 componenten
- Berekening per tenant: gewogen gemiddelde over alle agents
- Rolling 12-maanden history (één snapshot per dag per agent)
- Componenten breakdown is altijd zichtbaar (geen black box)
- **Tenant-age bootstrap** (NIEUW): tenants < 90 dagen oud krijgen evidence_continuity-weight = 0%, herverdeeld over andere componenten
- **Maintenance-window aware** (NIEUW): agents binnen actieve maintenance_window worden niet gepenaliseerd voor heartbeat-gaten

**Formule v1.1 (gefixt vs v1.0):**

| Component | Gewicht | Datasource | Notes |
|---|---|---|---|
| Patch hygiene | 30% | `inventory_dependency_cves` + `cve_matches`, KEV/EPSS-weighted, age sinds `fix_available_at` | onveranderd |
| Agent health | 20% | `agents.last_seen_at` + version-currency, **excluding agents in active `maintenance_windows`** | maintenance-aware ✨ |
| Secrets exposure | 15% | `inventory_security_findings` open vs resolved | onveranderd |
| Configuration drift | 15% | `process_dna` divergence + `integrity_anomalies` + **nieuwe `config_file_baselines` uit 1.4** | wordt pas accuraat na 1.4 ✨ |
| EAT resolution discipline | 10% | `emergency_tokens`: % met `exit_code = 0` vs % met `exit_code IN (65,66,67,70)` of `executed_at IS NULL > 7d` | **was: acked vs unack — nu: resoluut succes/falen** ✨ |
| Evidence continuity | 10% (0% voor tenants < 90d) | `ai_evidence_packs` + maandelijkse audit-pack coverage | bootstrap-modus ✨ |

**Tenant-age bootstrap formule:**
- Tenant < 30d oud: evidence_continuity = 0%, herverdeeld 50/50 over Patch hygiene + Agent health → 40% + 30% + 15% + 15% + 10% + 0%
- Tenant 30-90d: evidence_continuity = 5%, herverdeeld evenredig
- Tenant >= 90d: volle 10%

**Acceptance criteria:**
- [ ] Migratie 084 `trust_score_snapshots` (agent_id, tenant_id, captured_at TIMESTAMPTZ, total_score, components JSONB, tenant_age_days INT, RLS policy)
- [ ] Hypertable op `captured_at` met 30-day chunks
- [ ] Worker `TrustScoreWorker` in `handlers/workers/trust_score.go`, draait dagelijks om 03:00 tenant-tijd
- [ ] Helper `gracefulDegradeOnOldAgents(agentVersion)` returnt 0 voor componenten waar oude agent-data ontbreekt — score loopt door, banner in UI: *"upgrade agent voor volledige Trust Score"*
- [ ] API `GET /api/v1/trust-score/agents/:id?range=30d|90d|365d` — viewer mag lezen
- [ ] API `GET /api/v1/trust-score/tenant?range=30d|90d|365d` — aggregate
- [ ] Handler returnt `{current: {score, components, tenant_age_days, in_bootstrap_mode}, history: [...], breakdown: {component_name: {score, weight, evidence_count, blanking_reason?}}}`
- [ ] Unit tests met 7 scenario's: perfect (95+), KEV-doomed (<40), offline-met-maintenance (geen penalty), nieuwe tenant (bootstrap mode actief), agent-acked-EATs (boost), agent-failed-EATs (penalty), oude-agent-version (graceful degrade banner)

**Claude Code trigger:**
> "Implementeer Trust Score 1.0 zoals beschreven in `MONSYS_IMPLEMENTATION_ROADMAP_V11.md §1.1`. Belangrijk: dit is v1.1 dus gebruik EAT-resolution (niet -ack), tenant-age bootstrap, en maintenance-window awareness. Lees `migrations/056_trust_score_scaffolding.up.sql` voor het bestaande schema. Maak migratie 084, de worker, twee API endpoints, en run de 7 unit-test-scenario's tot allemaal slagen."

---

### 1.2 Trust Score 1.0 — dashboard
**Status:** ☐
**Tijd:** 3-5 dagen
**Dependencies:** 1.1 (kan parallel starten met mock-data)

**Scope:**
- Route `/trust-score` wordt productioneel
- Top-card: huidige score met 12-maand sparkline
- Component breakdown: 6 rijen, elk met bar en evidence-link
- "Bootstrap mode"-banner als tenant < 90d (geen verwarring)
- "Component blanked"-tooltip als oude-agent-versie data mist
- Per-agent uitsplitsing: tabel gesorteerd op laagste score eerst
- Export-knop: PDF met current state + 12-maand grafiek + alle component details

**Acceptance criteria:**
- [ ] `/[locale]/trust-score/page.tsx` toont tenant-aggregate
- [ ] `/[locale]/trust-score/agents/[id]/page.tsx` toont per-agent
- [ ] Bootstrap-banner verschijnt voor tenants < 90d: *"score wordt pas volledig vanaf dag 90 — evidence-continuity component activeert dan"*
- [ ] NL/FR/EN translation keys aanwezig
- [ ] Component-bars klikbaar → diepe link naar onderliggende evidence
- [ ] PDF-export via headless puppeteer, Ed25519-signed in metadata
- [ ] Pixel-grid branding consequent
- [ ] SWR refresh 5 min (heavy query)

**Claude Code trigger:**
> "Bouw de Trust Score dashboard view in Next.js v1.1. Lees `dashboard/src/components/AppShell.tsx` voor branding. Bouw twee pagina's (tenant + per-agent), bind aan `/api/v1/trust-score/*` endpoints, en zorg voor de bootstrap-banner + component-blanking tooltip. Export-knop produceert gesigneerde PDF via puppeteer."

---

### 1.2b Externe CISO-review (NIEUW IN V1.1 — verplichte gate vóór 1.3)
**Status:** ☐
**Tijd:** 4 uur (zelf, niet Claude Code)
**Dependencies:** 1.1 en 1.2 in werkende staat met fake data
**Wanneer:** einde week 3, niet later

**Scope:**
30-minuut sessie met één echte Belgische SME-CISO. Demonstreer:
1. Trust Score view voor één van je eigen agents (5 min)
2. Drill-down naar één component (3 min)
3. "Zou je dit aan je auditor laten zien?" — open-ended (15 min)
4. "Wat mis je hier nog?" — note-taking (5 min)

**Doel:** ontdekken welke 30% van het ontwerp fout is *voordat* de PDF-renderer in 1.3 wordt vastgelegd.

**Acceptance criteria:**
- [ ] CISO-gesprek gevoerd, notities op papier
- [ ] Minimaal 3 concrete feedback-items genoteerd
- [ ] Beslissingsblok: welke feedback wordt geadresseerd in 1.3, welke wordt uitgesteld
- [ ] Trust Score formule eventueel bijgesteld (kleine weightverschuivingen ok zonder migratie — config-file)

**Target CISO-profielen:** Belgische SME 50-500 medewerkers, NIS2-onderworpen sector (zorg, financiën, productie, of overheid). Geen vrienden van vrienden van vrienden — directe CISO-contacten.

---

### 1.3 Monthly Audit Pack — bundeling (UITGEBREID IN V1.1)
**Status:** ☐
**Tijd:** 1 week
**Dependencies:** 1.1, 1.2b (CISO-feedback geïntegreerd)

**Scope:**
Twee output-formaten, beide ondertekend:
- **JSONL.gz + manifest** — voor offline auditor-verificatie via CLI (machine-readable)
- **PDF** — voor de auditor's inbox (human-readable, branded)

**JSONL.gz bundle-inhoud:**
- Trust Score history (12 maanden)
- Alle EAT-executies (nonce, action, exit_code, acked_by) uit `emergency_tokens`
- Alle console sessies (begin/eind, operator, reden, session_hash) uit `console_sessions`
- Alle CVE-fixes geleverd in de maand uit `inventory_dependency_cves` met fix_available_at
- Alle alerts >= warning met resolution-time uit `alerts`
- SBOM per agent (zie 1.5) — referenced by hash
- Compliance findings + status uit `compliance_scan_results`
- AI evidence packs metadata — referenced
- Manifest: counts, byte sizes, hash chain root, Ed25519 signature, public-key-id

**PDF inhoud** (uitvoeriger sectie-indeling):
1. Executive summary: Trust Score, top 3 risicoposten, key changes deze maand
2. Compliance coverage matrix (NIS2 + CRA + ISO27001)
3. CVE-history: KEV first, fix-times p50/p95, watching-CVEs
4. EAT-log per signing operator + per agent
5. SLA-rapport per kritisch service
6. Evidence-pack manifest (hashes + sig references)
7. Cryptografische appendix met verify-instructies

**Acceptance criteria:**
- [ ] Migratie 085 `audit_packs` (tenant_id, month_start DATE, jsonl_path, pdf_path, signature, public_key_id, signed_at, RLS)
- [ ] Worker `AuditPackWorker` 1e van de maand om 02:00 voor elke tenant met `>= 1 agent`
- [ ] Output: `/var/lib/monsys/audit-packs/<tenant_id>/<YYYY-MM>.jsonl.gz` + `.pdf` + `.sig`
- [ ] Endpoint `GET /api/v1/audit-packs?year&month` — auditor + admin role
- [ ] Endpoint `GET /api/v1/audit-packs/:id/download?format=jsonl|pdf` — streamed download
- [ ] Endpoint `GET /api/v1/audit-packs/:id/verify` — re-rekent hash chain + signature
- [ ] CLI tool `cmd/monsys-verify-pack/main.go` — offline verify met `--pubkey`
- [ ] README in bundle uitleggend hoe te verifiëren

**Claude Code trigger:**
> "Bouw het Monthly Audit Pack systeem zoals in `MONSYS_IMPLEMENTATION_ROADMAP_V11.md §1.3`. Twee output-formaten: JSONL.gz (voor CLI-verify) én PDF (voor auditor-inbox). Migratie 085 + worker + drie endpoints + verify-CLI. Hergebruik Ed25519-signing pattern uit `handlers/ai/evidence_packs.go`. CISO-feedback uit 1.2b moet in PDF-layout verwerkt zijn."

---

### 1.4 Drift Detection (VERPLAATST UIT V1.0 §4.3 NAAR FASE 1)
**Status:** ☐
**Tijd:** 2 weken
**Dependencies:** geen
**Parallel met:** 1.1, 1.2, 1.3, 1.5

**Waarom verplaatst:** Trust Score (1.1) gebruikt drift als 15% component. In v1.0 zat drift in fase 4 wat een 6/6 score van blanco component zou geven tot maand 3+. Slechte sales-positie. Promoveren.

**Scope:**
Bij elke inventory-cycle: detecteer config-files die gewijzigd zijn buiten een EAT om.

**Acceptance criteria:**
- [ ] Migratie 086 `config_file_baselines` (agent_id, path, sha256, last_changed_at, change_authorized_by_eat_nonce NULL)
- [ ] Default watched paths (config-driven): `/etc/nginx/`, `/etc/postgresql/`, `/etc/ssh/sshd_config`, `/etc/sudoers`, `/etc/systemd/system/*.service`
- [ ] Agent uitbreiding: hash deze paden bij elke 6h-inventory-cycle, ship in `InventorySnapshot.config_hashes`
- [ ] Hub-side detector: hash-mismatch zonder EAT in laatste 5 min → `drift` alert, append `integrity_anomaly` row
- [ ] Drift gevoegd aan Trust Score worker als component
- [ ] Dashboard: drift-events in agent-detail "Integrity" tab, met diff-view (sha256 only, content niet — privacy)
- [ ] Per-tenant configureerbaar welke paden gewatched worden (`tenant_settings.drift_watched_paths`)
- [ ] **Backwards-compat**: oude agents sturen geen config_hashes; in dat geval drift-component blanked + UI-tooltip *"upgrade agent v1330+ voor drift-detection"*

**Claude Code trigger:**
> "Implementeer drift detection volgens `MONSYS_IMPLEMENTATION_ROADMAP_V11.md §1.4`. Migratie 086 + agent-inventory uitbreiding (`agent/src/inventory/config_hashes.rs`) + hub detector + Trust Score integration. Belangrijk: backwards-compat met agents die geen config_hashes sturen. Test met canvoseu-dev als pilot host."

---

### 1.5 SBOM-export per agent
**Status:** ☐
**Tijd:** 3-5 dagen
**Dependencies:** geen
**Parallel met:** 1.1, 1.2, 1.3, 1.4

**Scope:**
Genereer SPDX 2.3 of CycloneDX 1.5 SBOM uit bestaande `inventory_dependencies` + OS-packages. Vereist door CRA per september 2026.

**Acceptance criteria:**
- [ ] Endpoint `GET /api/v1/agents/:id/sbom?format=spdx-json|cyclonedx-json` — viewer-role
- [ ] SPDX: SPDXID, name, versionInfo, supplier, downloadLocation (NOASSERTION ok), checksum waar bekend, license uit `061_dependency_licenses`
- [ ] CycloneDX: bom-ref, type=library, group, name, version, purl
- [ ] Output Ed25519-signed in sidecar `.sig` file
- [ ] Automatisch geïncludeerd in Monthly Audit Pack (1.3)
- [ ] Voorbeeld-output in CLAUDE.md's "audit deliverables" sectie

**Claude Code trigger:**
> "Implementeer SBOM-export volgens v1.1 §1.5. Lees `migrations/035_dependencies.up.sql` en `061_dependency_licenses.up.sql`. Twee renderers (SPDX 2.3, CycloneDX 1.5) in `handlers/sbom/`, één endpoint, en hook in de Monthly Audit Pack worker."

---

### 1.6 NIS2 + CRA Compliance Coverage View
**Status:** ☐
**Tijd:** 1-2 weken
**Dependencies:** 1.1 (Trust Score-componenten worden gehergebruikt)

**Scope:**
Eén pagina per framework die laat zien: welke controls dekt monsys automatisch, welke gedeeltelijk, welke niet. Geen vage claims; elk gemapt control wijst naar een concrete signaalbron via een runbare SQL-query.

**NIS2 Annex II — 10 maatregelen, map naar:**

| Maatregel | monsys-signaal |
|---|---|
| 1. Risk analysis policies | Trust Score + per-agent breakdown |
| 2. Incident handling | `alerts` + EAT history |
| 3. Business continuity / backup | `backups.rs` inventory + age check |
| 4. Supply chain security | `inventory_dependencies` + maintainer-rotation blocks |
| 5. Network/info system security | Topology + firewall + secrets findings |
| 6. Security policies & procedures | `compliance_scan_results` + `audit_log` |
| 7. Basic cyber hygiene | Heartbeat + version-currency + patch hygiene |
| 8. Cryptography | Certificate inventory + DNS hygiene |
| 9. HR security / access management | `console_sessions` + RBAC scope-checks |
| 10. MFA / authentication | TOTP enforcement op destructive actions |

**CRA Annex I** — 13 essentiële eisen, analoog mapped (vereist legal-review-pass).

**Acceptance criteria:**
- [ ] Migratie 087 `compliance_framework_controls` (framework, control_id, description NL/FR/EN, monsys_evidence_query TEXT, coverage_level enum 'automatic'|'partial'|'manual')
- [ ] Seed: NIS2 (10 rows) + CRA (13 rows) + ISO 27001:2022 top 30 controls
- [ ] **Legal review pass**: voordat seed in productie gaat, NIS2 + CRA mapping reviewed door legal counsel (jij hebt contacten). Niet-juridisch correcte claims kan compliance-aansprakelijkheid creëren.
- [ ] Endpoint `GET /api/v1/compliance/coverage?framework=NIS2|CRA|ISO27001`
- [ ] Pagina `/compliance/[framework]` matrix view
- [ ] Klik control → modal met "evidence preview" (laatste 5 signaal-rows)
- [ ] PDF-export — geïncludeerd in Monthly Audit Pack
- [ ] Coverage-metrics gevoegd in Trust Score dashboard als secundaire KPI

**Claude Code trigger:**
> "Bouw Compliance Coverage view voor NIS2, CRA, ISO27001:2022 zoals in v1.1 §1.6. Migratie 087 + seed data + endpoint + matrix view. Voor elk control: maak `monsys_evidence_query` een echte runbare SQL — geen placeholder. Markeer in `seed_review_needed` flag op rows die nog legal-pass nodig hebben. PDF-export hookt in Monthly Audit Pack."

---

### 1.7 Fase 1 — Demo-script schrijven en oefenen
**Status:** ☐
**Tijd:** 4 uur (zelf)
**Dependencies:** 1.1 t/m 1.6 klaar
**Was 1.6 in v1.0 — nu 1.7 omdat 1.6 = Compliance**

**Scope:**
12-minuten verkoopscript dat een Belgische SME-CISO door deze flow leidt:
1. Login op demo-tenant (1 min)
2. Trust Score: *"we zijn 74/100, vorig kwartaal 81, dit zijn de redenen"* (3 min)
3. Compliance Coverage NIS2: *"7 van 10 maatregelen automatisch gedekt"* (3 min)
4. Audit Pack: *"hier is mei 2026, één bestand voor je auditor"* (2 min)
5. EAT-actie live: *"ik kill een process, ondertekend, geverifieerd, geaudit"* (3 min)

**Acceptance:** je hebt dit één keer voor een willekeurige collega gedemo'd zonder vast te lopen.

---

## Fase 2 — MSP-multiplier (4-6 weken)

**Verplichte gate: 0.3 minimaal 2 van 3 commitments behaald. Anders skip fase 2.**

### 2.1 MSP Wholesale tier — billing
**Status:** ☐
**Tijd:** 1 week
**Dependencies:** 0.3 gepasseerd, Fase 1.1 (Trust Score)

**Scope:**
- Stripe-plan `msp_wholesale`: €1.50/server/maand vanaf server 6
- MSP-tenant heeft `is_msp = true`
- MSP kan child-tenants maken
- Billing aggregeert naar MSP, niet child

**Acceptance criteria:**
- [ ] Migratie 088 `tenant_relationships` (parent_tenant_id, child_tenant_id, relationship_type enum, created_at, RLS)
- [ ] `tenants` krijgt `is_msp BOOLEAN DEFAULT FALSE`, `parent_tenant_id UUID NULL`
- [ ] Stripe-product `monsys_msp_wholesale` met tiered pricing
- [ ] `POST /api/v1/msp/customers` — `msp_operator` role, maakt child-tenant + initial enrolment token
- [ ] `GET /api/v1/msp/customers` — lijst met agent count + Trust Score
- [ ] Billing-aggregator telt agents over alle child-tenants

**Claude Code trigger:**
> "Implementeer MSP wholesale billing volgens v1.1 §2.1. Migratie 088, tenant.is_msp + parent_tenant_id, MSP-customer endpoints, billing-aggregator op MSP-niveau."

---

### 2.2 MSP Cockpit — multi-tenant overzicht
**Status:** ☐
**Tijd:** 1-2 weken
**Dependencies:** 2.1

**Scope:** `/msp/cockpit` productioneel maken.

**Acceptance criteria:**
- [ ] Tabel: één rij per child-tenant met `name`, `agent_count`, `trust_score`, `critical_alerts_open`, `kev_cves_open`, `last_audit_pack_signed_at`
- [ ] Sorteerbaar; default laagste trust_score eerst
- [ ] Filter: "alleen klanten met open KEV", "alleen klanten met heartbeat-stille agents"
- [ ] Bulk-actie: "stuur monthly audit pack naar alle klanten" (genereert + mailt PDF)
- [ ] Drill-down via klik op rij
- [ ] Per-klant "impersonate read-only" na TOTP — 15min TTL auditor-sessie token

**Claude Code trigger:**
> "Bouw MSP Cockpit volgens v1.1 §2.2. Lees `migrations/074_groups_sla_rbac_failover.up.sql` + `064_auditor_msp.up.sql`. `/msp/cockpit` pagina + impersonate-read-only handler met TOTP-gating."

---

### 2.3 White-label branding pipeline
**Status:** ☐
**Tijd:** 4-5 dagen
**Dependencies:** 2.1

**Scope:** Migratie `031_branding` uitbreiden voor echte MSP-rebranding.

**Acceptance criteria:**
- [ ] Per-tenant custom domain (`monitoring.mspklant.be` → CNAME naar `monsys.ai`)
- [ ] Caddy on-demand TLS
- [ ] Per-tenant `tenant_settings.smtp_from`
- [ ] Per-tenant favicon
- [ ] PDF-exports gebruiken tenant-logo i.p.v. monsys-logo
- [ ] MSP-klanten zien "monsys.ai" nergens behalve footer (1 regel, opt-out tegen meerprijs)

**Claude Code trigger:**
> "Full white-labeling voor MSP-tenants volgens v1.1 §2.3. Migratie 031 uitbreiden, Caddy on-demand TLS, PDF-renderers branding-aware, `/settings/branding` voor MSP-operators."

---

### 2.4 Per-tenant SMTP — geïntegreerd in 2.3
Niet separate, zit in 2.3 acceptance criteria.

---

### 2.5 MSP-revenue dashboard
**Status:** ☐
**Tijd:** 3 dagen
**Dependencies:** 2.1, 2.2

**Acceptance criteria:**
- [ ] MSP-operator kan per child-tenant `customer_retail_price` invullen
- [ ] Dashboard: monthly wholesale_cost, monthly retail_revenue, monthly_margin
- [ ] Aggregate over alle child-tenants
- [ ] CSV-export voor boekhouding

---

## Fase 3 — Differentiator features (8-12 weken)

Fase 1+2 zijn pure verkoopaccelerators. Fase 3 maakt monsys *moeilijk te kopiëren*.

### 3.1 AI Incident Summarisation (RATE-LIMIT TOEGEVOEGD IN V1.1)
**Status:** ☐
**Tijd:** 1-2 weken
**Dependencies:** geen

**Scope:** Bij elke kritieke alert: 2-zin samenvatting + voorgestelde EAT.

**Pipeline:**
1. Critical alert → `IncidentSummariserWorker` async
2. pgvector cosine similarity → top-3 historische alerts
3. AGE blast-radius traversal → downstream services
4. Ollama-prompt → 2-zin summary + 1 voorgestelde EAT (suggestion, geen auto-execute)
5. Schrijft naar `alerts.ai_summary` + `alerts.suggested_eat_payload`

**Acceptance criteria:**
- [ ] Migratie 089: `ai_summary TEXT`, `suggested_eat_payload JSONB`, `ai_summarised_at TIMESTAMPTZ` op `alerts`
- [ ] `IncidentSummariserWorker` per critical alert binnen 30s
- [ ] Embedding-pipeline: alert-descriptions krijgen pgvector embedding bij INSERT (Ollama `nomic-embed-text`)
- [ ] **Rate-limit (NIEUW v1.1)**: `tenant_settings.ai_summarisation_max_per_hour` default 50. Bij overschrijding: graceful fallback, banner *"AI insight tijdelijk niet beschikbaar — handmatig onderzoek"*. Voorkomt Ollama-overload bij MSP-klanten met 1000 critical alerts/dag.
- [ ] **Cost telemetry**: log per call duration + tokens-in/out + model voor toekomstige cost-attribution per tenant
- [ ] Dashboard: green "AI Insight"-banner met disclaimer *"suggestie — niet automatisch uitgevoerd"*
- [ ] "Apply suggested EAT" knop opent EAT-builder met payload pre-filled; TOTP + scope-check verplicht. **Nooit auto-execute.**
- [ ] Graceful fallback bij geen historische cases (eerste maand van tenant)

**Claude Code trigger:**
> "Implementeer AI Incident Summarisation volgens v1.1 §3.1. Belangrijk: rate-limit per tenant (default 50/uur), cost telemetry, en geen auto-execute. Lees `migrations/013_embeddings.up.sql` en `063_anomaly_correlations.up.sql`. Bouw embedding-pipeline + worker + dashboard-banner. De suggested EAT moet altijd door TOTP."

---

### 3.2 Multi-party EAT signing voor Level 3 (DEPENDENCY OP 3.4 EXPLICIET v1.1)
**Status:** ☐
**Tijd:** 1-2 weken voor backend; **+1 week voor SMS fallback OF wacht op 3.4**
**Dependencies:** 3.4 (mobile PWA) OF SMS-fallback voor approver-notifications

**Waarom dependency:** Operator A initieert EAT, push notificatie naar Operator B. Zonder mobile PWA (3.4) of SMS-fallback krijgt B de notificatie alleen via desktop browser — onbruikbaar tijdens crisis als B niet ingelogd is.

**Twee paden:**
- **Pad A**: bouw 3.2 + 3.4 als gekoppeld pakket (~3 weken samen) → push notification via PWA
- **Pad B**: bouw 3.2 alleen met SMS-fallback via Twilio (~2 weken) → notificatie via SMS, mobile PWA later

**Aanbeveling:** Pad A is duurder maar levert het hele mobile-on-call verhaal. Pad B is sneller maar laat een gat waar je tijdens demo's "twilio" moet uitleggen.

**Scope:** Level 3 EATs (Reboot, DeleteAgent, InstallPackage system) vereisen 2 operators binnen 30 min.

**Acceptance criteria:**
- [ ] Migratie 090 `emergency_token_approvals` (token_id, approver_user_id, approved_at, totp_verified_at, notification_method TEXT)
- [ ] `emergency_tokens.required_approvals INT`, `state TEXT` ('pending_approval', 'issued', 'expired', 'rejected')
- [ ] `tenant_settings.level3_required_approvers` default 2
- [ ] `POST /api/v1/emergency/:nonce/approve` met TOTP
- [ ] Approval flow: operator A drukt knop → state='pending_approval' → notificatie naar andere admin-role users (via PWA push of SMS-fallback) → operator B opent dashboard → approve met TOTP → EAT naar agent
- [ ] **Split-control**: eerste operator kan niet zelf approver zijn
- [ ] 30-min TTL op pending; auto-rejected daarna
- [ ] Audit-log toont beide signers expliciet

**Claude Code trigger:**
> "Implementeer multi-party signing voor Level 3 EATs volgens v1.1 §3.2. Belangrijk: split-control (initiator ≠ approver). Migratie 090 + endpoint + flow. Beslis vooraf: SMS-fallback (Twilio integratie) OF wacht tot 3.4 mobile PWA klaar is. Push notificaties naar admins gaan via NotifyWorker."

---

### 3.3 One-click incident response playbooks
**Status:** ☐
**Tijd:** 1 week
**Dependencies:** 3.1 (suggested EAT) — niet strikt, mooi samen

**Default playbooks:**

| Alert type | One-click action |
|---|---|
| Honeypot canary | IsolateNetwork (hub-only allowlist) |
| Heartbeat silence > 5min | WoL if known, escalate to on-call |
| Critical CVE met fix | UpdatePackages EAT met dry-run flag |
| Disk full | Cleanup EAT voor `/tmp` + `/var/log/*.gz` |
| Process DNA divergence | KillProcess + restart service |

**Acceptance criteria:**
- [ ] Migratie 091 `incident_response_templates` (name, alert_category, eat_template JSONB, required_role, tenant_id NULL voor system-defaults)
- [ ] Seed met 5 default playbooks
- [ ] Tenant kan eigen playbooks toevoegen
- [ ] Alert-detail toont "Quick Response" sectie
- [ ] Klik → EAT-builder met payload pre-filled → TOTP → dispatch

---

### 3.4 Mobile-first on-call PWA
**Status:** ☐
**Tijd:** 2-3 weken
**Dependencies:** 3.3 (één-klik playbooks)
**KRITIEK**: als 3.2 met pad A (gekoppeld) wordt gedaan, dan 3.4 vóór 3.2

**Schermen (4, niet meer):**
1. Inkomende alerts — gesorteerd op severity + age
2. Alert-detail — title, description, AI-summary, "Acknowledge" + "Apply Playbook" + (v1.1) "Approve EAT" buttons
3. Console session viewen (alleen view, niet starten)
4. Trust Score quick-glance

**Acceptance criteria:**
- [ ] PWA manifest met install-prompt
- [ ] Service worker voor offline alert-cache (laatste 50)
- [ ] Push notifications via ntfy direct (subscribe op `monsys-user-<short>`)
- [ ] TOTP via WebAuthn waar device-support, anders 6-digit
- [ ] **(v1.1) EAT-approval scherm**: ontvangt push wanneer initiator een Level 3 EAT heeft gestart, toont action + reden + initiator naam + "Approve with TOTP" knop
- [ ] Werkt op 360px-tot-430px
- [ ] Geen zware tabellen

**Claude Code trigger:**
> "Bouw mobile-first PWA volgens v1.1 §3.4. Vier schermen, ntfy-push direct, TOTP via WebAuthn + fallback. KRITIEK: scherm 4 inclusief EAT-approval flow voor multi-party signing (3.2 dependency). Werk in `dashboard/src/app/[locale]/mobile/` met aparte layout."

---

## Fase 4 — Strategische defensives (12+ weken, post-Fase 3)

### 4.1 Client-side EAT verificatie via transparency log
**Status:** ☐
**Tijd:** 3-4 weken
**Dependencies:** Fase 1-3 stabiel

**Scope:** Browser-extensie + CLI voor onafhankelijke EAT-key verify via publiek transparency log (Sigstore/Rekor-stijl, of eigen Merkle tree).

**Acceptance criteria:**
- [ ] Eigen append-only transparency log
- [ ] Hub-key rotation pushes nieuwe pubkey met timestamp
- [ ] Browser-extensie (Chrome + Firefox) toont groen vinkje per EAT: *"key in transparency log sinds X"*
- [ ] CLI `monsys-verify-eat <eat.json> --log https://transparency.monsys.ai`
- [ ] Documentatie voor klanten over mirror-log draaien (paranoid mode)

**Waarom:** Defensie- en overheidsklanten met clearance vragen hier expliciet naar.

---

### 4.2 Hub HA (active-passive)
**Status:** ☐
**Tijd:** 4-6 weken
**Dependencies:** alles stabiel

**Scope:** Vermijdt SPOF zonder lokale escape hatch.

**Acceptance criteria:**
- [ ] Standby hub ontvangt WAL-stream van active
- [ ] DNS-failover via Hetzner/CloudFlare met 60s TTL
- [ ] Agent config ondersteunt `hub_urls = [...]` lijst
- [ ] EAT-signing key veilig gerepliceerd (HSM of K8s-secret, niet plain DB)
- [ ] Failover-drill draaibaar als chaos-test

---

### 4.3 Pre-issued playbook EATs (hub-offline failsafe)
**Status:** ☐
**Tijd:** 2 weken
**Dependencies:** 3.3, 4.2

**Was 4.4 in v1.0 — nu 4.3 omdat 4.3 drift is verplaatst naar 1.4**

**Scope:** Hub stuurt bij elke heartbeat vooraf goedgekeurde kort-geldige EATs voor lokaal-actiebare incidents.

**Acceptance criteria:**
- [ ] EAT-formaat uitgebreid met `local_trigger_condition JSONB`
- [ ] Heartbeat-response bevat 0-5 pre-issued EATs per agent
- [ ] Agent evalueert lokale conditie elke 30s
- [ ] Match + hub-onbereikbaar > 5 min → execute, buffer resultaat voor latere upload
- [ ] Hub-bereikbaar → upload + audit-log met `executed_offline = true`
- [ ] TTL strikt: pre-issued EAT verloopt 1u na heartbeat-uitgifte

---

## Fase 5 — Community & marketplace (post-50-tenants)

### 5.1 Community Playbook & App Template Marketplace
**Status:** ☐
**Tijd:** 2-3 weken
**Dependencies:** **minimaal 50 paying tenants** + voorgeseede content
**Was 3.5 in v1.0 — verplaatst naar fase 5 wegens "lege marketplace = slechte indruk"**

**Pre-seed regel (NIEUW v1.1):** vóór publieke launch moet de marketplace ≥ 40 playbooks bevatten die je zelf hebt geschreven of laten schrijven. Anders ziet eerste bezoeker leegte.

**Acceptance criteria:**
- [ ] GitHub org `monsys-community` met README, contribution guide, code of conduct
- [ ] Schema voor playbook YAML/JSON gedocumenteerd
- [ ] Top 20 Belgische SME-apps gescaffold (Odoo, Nextcloud, Mailcow, OwnCloud, Synology DSM, etc.)
- [ ] **Pre-seed van 40+ playbooks** vóór publieke launch
- [ ] Endpoint `GET /api/v1/marketplace/playbooks?ecosystem=apps|incident-response` — GitHub raw met caching
- [ ] Dashboard `/marketplace` — browse + install
- [ ] Hash van remote content opgeslagen voor integrity-check
- [ ] CI valideert elke PR tegen schema + dry-run EAT-simulator

---

## Niet-doen-lijst (expliciet) — UITGEBREID IN V1.1

| Item | Reden |
|---|---|
| OpenTelemetry-compatible AI ingest | Verbreekt byte-stabiele evidence packs |
| Kubernetes als first-class deployment | Ondergraaft "draait op één VPS"-MSP-argument |
| Auto-executing LLM-EATs | Eén verkeerde call = bedrijf failliet |
| Offline lokale EAT-injectie (ChatGPT's voorstel) | Breekt cryptografisch dreigingsmodel |
| NL-translation als optional | Belgische SME-verkoop hangt op NL/FR-default |
| Generic "monitoring" framing | Iedereen monitort; verkoop audit-deliverables |
| **(v1.1) Marketplace vóór 50 tenants** | Lege marketplace = eerste-indruk-schade |
| **(v1.1) Trust Score zonder bootstrap** | Maakt nieuwe tenants artificieel laag |
| **(v1.1) AI summarisation zonder rate-limit** | Ollama-overload bij MSP-klanten met veel alerts |
| **(v1.1) Multi-party signing zonder mobile-of-SMS** | Approver krijgt notificatie nooit op tijd |
| **(v1.1) MSP-infra bouwen zonder 0.3 pricing-validatie** | Risico op 6 weken werk voor markt-die-er-niet-is |

---

## Bijhouden van progress

**Suggestie:** GitHub Project of Notion-tabel met deze items als rows. Update wekelijks. Houd **1.7 Fase 1 demo-script** als noord-ster — als je daar over 6 weken niet kunt staan, is fase 1 niet af.

**Tijdsestimaten samengevat (v1.1):**

| Fase | Tijd | Kritiek pad? | Gates |
|---|---|---|---|
| Fase 0 | 1-3 weken (incl. 0.3 = 2w) | Ja | 0.3 ≥ 2/3 commitments |
| Fase 1 | 4-6 weken | Ja | 1.2b CISO-review verplicht |
| Fase 2 | 4-6 weken | Alleen als 0.3 ✓ | — |
| Fase 3 | 8-12 weken | — | 3.4 vóór 3.2 of SMS-fallback |
| Fase 4 | 12+ weken | — | Fase 1-3 stabiel |
| Fase 5 | post-50-tenants | — | Pre-seed ≥ 40 playbooks |

**Realistische totaal-doorlooptijd tot "verkoopbare productie-stand v2":** 4-5 maanden bij volledige focus, 6-8 maanden bij parallel NormNest-werk.

---

## Wijzigingslogboek

| Versie | Datum | Wat |
|---|---|---|
| v1.0 | 2026-05-19 | Initiële versie op basis van Claude's strategische analyse |
| v1.1 | 2026-05-19 | 6 bug-fixes + 2 toevoegingen: Trust Score formule, drift-promotie, marketplace-verplaatsing, MSP-validatie-gate, CISO-review-gate, multi-party-3.4-dependency, AI rate-limit, backwards-compat invariant |

---

*Einde roadmap v1.1. Update maandelijks naarmate realisaties en nieuwe inzichten binnenkomen.*
