📐 ADR templates · 3 seedati
Planet Module System foundation · 2026-05-16
ADR (Architecture Decision Records) seedati da Mother fase-0 · Child finalizzano con esempi reali a fine sessione. Target path:
D:\Desktop\Multiverbe\docs\adr/Format: MADR 3.0 (Markdown Architectural Decision Record) lightweight.
ADR-001 · Planet Module System (PMS)
# ADR-001 · Planet Module System (PMS)
- Status: accepted
- Date: 2026-05-16
- Deciders: Gregorio Ciurleo (founder), Claude (Opus 4.7 advisor)
- Tags: architecture, scaling, monorepo, plug-in
## Context
Multiverbe è un Business OS per PMI svizzere. 6 pianeti canonici user-facing:
- Web 🌐 (Site Builder) · Booking 📅 · Content Studio 🎬 · CRM 🎯 · Sales 💼 · Marketing 📣
- HR Q3 2026 · Finanza Q4 2027 (futuri)
Stato iniziale 2026-05-16: Web ~70%, Booking ~30%, Marketing in BOS app, CRM/Sales/Content 0-15%, HR 0%.
Vecchio pattern di crescita: aggiungere un pianeta = 5-7gg lavoro (feature folder ad-hoc, integrazione manuale con sidebar, RLS scoped a mano, telemetria copy-paste, feature flag duplicati).
Hard gate 10 Giugno 2026 (24gg da oggi) richiede MVP completo + 5 paganti CHF. 4 pianeti da chiudere = 28gg al vecchio pattern → **fail**.
UX/UI unificata (obiettivo founder) richiede `PlanetSlot` shared layout — impossibile retrofit ex-post quando ogni pianeta ha shape diversa.
## Decision
Costruire un **Planet Module System (PMS)**: contratto stabile `PlanetModule<TState>` che ogni pianeta esporta, registry centralizzato in `@multiverbe/planet-core` che gestisce lifecycle (init/mount/unmount), event bus typed cross-planet, telemetria OTel uniforme, feature flag reader, state schema migration.
Struttura monorepo (pnpm workspaces):
- `packages/contracts/` — ports (TS interface + Zod runtime + branded types)
- `packages/planet-core/` — orchestratore
- `packages/sector-adapters/` — Sole AI cross-planet adapters
- `packages/planet-{kind}/` — bounded context per pianeta
- `packages/planet-testkit/` — 18 contract test shared
Scaffold script `pnpm run scaffold:planet <kind>` → nuovo pianeta in <60s.
## Alternative considered
### A. Module Federation (Webpack 5)
- ✅ Pro: indipendenza deploy per pianeta · veri micro-frontend
- ❌ Con: complessità runtime · debug penoso · TypeScript safety persa al boundary · stack non vede Vite/Vercel · setup ore vs giorni
- ❌ Esclusa: overkill per team 1.5 persone (Gregorio + Claude)
### B. Nx monorepo
- ✅ Pro: caching potente · scaffold integrato
- ❌ Con: lock-in Nx · learning curve · oggi usiamo pnpm workspaces che basta
- ❌ Esclusa: incremental value < incremental cost
### C. Plain feature folders (status quo)
- ✅ Pro: zero abstraction · veloce per primo pianeta
- ❌ Con: copy-paste per ogni nuovo pianeta · UX/UI drift · RLS divergente · telemetria inconsistente
- ❌ Esclusa: confermata insostenibile dal Wow Audit 2026-05-14 (3 gap aperti)
### D. PMS custom plug-in pattern (scelta)
- ✅ Pro: TS safety end-to-end · DX scaffold <60s · UX/UI unificabile · ADR-driven · zero lock-in vendor
- ✅ Pro: paga tech debt via Strangler retrofit (ADR-003) invece di accumularlo
- ⚠️ Con: 6-8h investimento iniziale · richiede disciplina contracts
- ✅ Scelta: ROI 1:5 in 24gg (4 pianeti × 1-2gg vs 5-7gg)
## Consequences
### Positive
- Aggiungere pianeta = 1-2gg invece di 5-7gg
- UX/UI unificata via `PlanetSlot` + manifest condivisi (sidebar auto-generata)
- W-002 (keyframes morti) + W-010 (sezioni null) + W-011 (screenshot stub) risolti come side-effect del retrofit Web
- Onboarding nuova Claude session/developer: contratti espliciti + 18 contract test forniscono safety net automatica
- RLS workspace_id isolation testato gratuitamente in planet-testkit
- Bundle size budget enforced per pianeta (≤80KB gz)
- Telemetria OTel uniforme · debugging cross-planet via event bus DevTools hook
### Negative
- Disciplina contracts richiesta · ogni nuovo planet capability → update `@multiverbe/contracts` prima
- Indirection level aggiunto per chi legge il codice la prima volta
- Mutation testing Stryker (`packages/planet-core/`) costa ~3-5min CI per merge
### Neutral
- Decisione reversibile: se PMS si rivela sbagliato, `defineModule()` può essere bypassato e codice scritto inline · costo refactor < benefit attesi
## Verification
Success metrics post-merge:
- [ ] `pnpm run scaffold:planet crm` <60s exit 0 + test green
- [ ] Web e Booking retrofit zero breaking change end-user (Playwright smoke pre+post)
- [ ] Bundle size respected per package
- [ ] Coverage ≥80% line / ≥70% branch su planet-core
- [ ] Mutation score ≥60% planet-core
3-month review (2026-08-16):
- N pianeti shippati post-PMS
- Tempo medio onboarding nuovo pianeta
- Bug rate cross-planet (event bus, RLS leaks)
- Feedback Gregorio + future contributors
## References
- BOS `canon/02-product.md` § 6 pianeti
- BOS `canon/05-stack.md` § Stack Architettura
- BOS `execution/decisions-log.md` 2026-05-16 entry
- BOS `ops/sessions/2026-05-16-pms-foundation/` session kit
- Wow Audit 2026-05-14 (`execution/quality-reports/2026-05-14T2345-wow-audit-one-time.md`)
ADR-002 · Hexagonal architecture + DDD bounded contexts
# ADR-002 · Hexagonal architecture + DDD bounded contexts per pianeta
- Status: accepted
- Date: 2026-05-16
- Deciders: Gregorio Ciurleo (founder), Claude (Opus 4.7 advisor)
- Tags: architecture, ddd, hexagonal, boundary
## Context
Decisione tecnica conseguente ad ADR-001 (PMS). Dato che ogni pianeta è un modulo plug-in con contratto stabile, serve un pattern interno per:
- Decoupling business logic da infrastruttura (Supabase, Anthropic, Stripe, ecc.)
- Boundary chiara fra pianeti (no cross-coupling)
- Test isolato del business logic senza mock pesanti
- Sostituzione adapter (es. Anthropic → Mistral) senza toccare business logic
## Decision
Adottare **Hexagonal architecture** (Ports & Adapters, Alistair Cockburn) per ogni pianeta + **DDD bounded contexts** (Eric Evans) come boundary semantica.
Layering interno per `packages/planet-{kind}/`:
packages/planet-{kind}/ ├─ src/ │ ├─ domain/ # entities · value objects · domain events · pure logic │ │ ├─ entities.ts │ │ ├─ value-objects.ts │ │ └─ events.ts │ ├─ application/ # use cases · orchestration · NON depends on infra │ │ └─ use-cases/ │ ├─ ports/ # interfaces verso infra (output ports) │ │ ├─ persistence.port.ts │ │ ├─ ai.port.ts │ │ └─ email.port.ts │ ├─ adapters/ # implementations dei ports │ │ ├─ supabase.adapter.ts │ │ ├─ anthropic.adapter.ts │ │ └─ brevo.adapter.ts │ └─ ui/ # React components · mount points │ └─ {Kind}Dashboard.tsx └─ tests/ ├─ unit/ # domain + application (no infra · pure) ├─ integration/ # ports + adapters └─ e2e/
Cross-planet communication SOLO via `EventBus` (typed) o `SoleAdapter` (cross-sector). MAI import diretto fra `planet-{kind}/` (enforced via ESLint `no-restricted-imports` + boundary check script).
## Alternative considered
### A. Clean Architecture (Bob Martin) — molto simile a Hexagonal
- ✅ Pro: documentazione abbondante
- ❌ Con: 4-layer (entities/usecases/interface adapters/frameworks) eccesso per nostra scala
- Scelta: Hexagonal 3-layer più snello
### B. Onion Architecture
- Praticamente identica · scelta arbitraria
### C. Layered architecture tradizionale (Controller→Service→Repository)
- ❌ Con: dipendenze pesanti su infra · test mock-heavy
- Esclusa: scelte già fatte di sostituire AI provider in passato (Anthropic primario) richiedono port
### D. CQRS + Event Sourcing
- ✅ Pro: audit log nativo · time-travel debugging
- ❌ Con: complessità eccessiva per MVP · differiamo a v2 se serve
## Consequences
### Positive
- Test unitari pure-domain veloci (<10ms per test)
- Sostituzione adapter senza rompere business logic (es. Mistral al posto di Anthropic per email outreach)
- Boundary contexts chiari · documentazione self-evident dal codice
- Onboarding rapido: leggi `domain/` per capire il pianeta in 5min
### Negative
- 3 layer = qualche file in più
- Domain anemico se non si presta attenzione (rischio leak business logic in adapter)
- Mitigation: code review focus su "dove vive questa logica?" + ADR pattern review trimestrale
### Neutral
- Pattern reversibile: se peso > benefit, collassare in 2 layer (domain+infra)
## Verification
- ESLint boundary rule + `scripts/check-boundaries.sh` in CI
- Code review checklist: "questa funzione tocca infra? va in `adapters/`"
- Test coverage `domain/` ≥90% (logica pura · facile)
## References
- "Hexagonal Architecture" — Alistair Cockburn (2005)
- "Domain-Driven Design" — Eric Evans (2003)
- "Implementing Domain-Driven Design" — Vaughn Vernon (2013)
- ADR-001 (PMS) parent decision
ADR-003 · Strangler retrofit strategy
# ADR-003 · Strangler retrofit strategy per Web + Booking
- Status: accepted
- Date: 2026-05-16
- Deciders: Gregorio Ciurleo (founder), Claude (Opus 4.7 advisor)
- Tags: architecture, refactoring, retrofit, strangler
## Context
ADR-001 introduce PMS. Web (70%) e Booking (30%) esistono già con shape divergenti dal contratto `PlanetModule<TState>`. Due strade:
- **Big bang rewrite**: riscrivere Web + Booking from scratch sotto PMS · 3-5gg per pianeta · alto rischio breaking change · time-budget oggi 8h totali
- **Strangler retrofit**: avvolgere codice esistente progressivamente in `PlanetModule<TState>` · zero big-bang · CI verde a ogni commit intermedio · feature flag rollback 5sec
Hard gate 10 Giu in 24gg + demo Loris W4 = non possiamo rompere Web/Booking nemmeno per 30min.
## Decision
Adottare **Strangler Fig pattern** (Martin Fowler 2004) per retrofit Web + Booking:
1. **Mantieni codice esistente intoccato** in `frontend/multiverbe-app/src/{web,booking}/` (vecchia location)
2. **Crea wrapper** in `packages/planet-{kind}/src/` che importa il vecchio codice e lo espone via `PlanetModule<TState>` conforme
3. **Feature flag `pms.enabled`** default `true` in dev/preview, `true` in prod post-validation · flip a `false` = rollback istantaneo al vecchio routing
4. **Migrare progressivamente** componenti dal vecchio path al nuovo `packages/planet-{kind}/src/` quando si tocca quel componente per altri motivi (next 4-8 settimane)
5. **Side-effect fix Wow Audit gaps** (W-002/010/011) come parte del retrofit Web (manifest forza dichiarazione esplicita · gap chiusi naturalmente)
## Alternative considered
### A. Big bang rewrite
- ✅ Pro: codice finale pulito subito
- ❌ Con: 6-10gg rischiosi · breaking change garantito intermedio · founder NO
- Esclusa: time + risk inaccettabili
### B. Parallel run (vecchia + nuova UI live insieme)
- ✅ Pro: A/B testing
- ❌ Con: 2x manutenzione · confusion utente · duplicate analytics
- Esclusa: overkill per refactor interno
### C. Strangler (scelta)
- ✅ Pro: zero breaking change · feature flag rollback · graduale · cost-effective
- ⚠️ Con: dual location temporanea (`frontend/multiverbe-app/src/web/` + `packages/planet-web/src/`) per qualche settimana
- ✅ Mitigation: ADR aggiorna stato "migration progress" mensile · target full migration Q3 2026
## Consequences
### Positive
- Zero breaking change end-user oggi
- CI verde a ogni commit intermedio (no big-bang merge)
- Feature flag rollback 5sec se issue prod
- Wow Audit gaps chiusi come side-effect
### Negative
- Code lives in 2 places temporaneamente (`frontend/multiverbe-app/src/web` + `packages/planet-web/`)
- Mental overhead per nuovi contributor: "dove vive `X`? vecchio o nuovo?"
- Mitigation: comment `// MIGRATED TO @multiverbe/planet-web` in vecchi file + grep-friendly TODO
### Neutral
- Quando migration completa (target Q3 2026), `frontend/multiverbe-app/src/{web,booking}/` deletable
## Verification
- Playwright smoke `signup → /web → create site` zero error pre AND post retrofit
- Feature flag `pms.enabled=false` → demo Loris segue path vecchio funzionante (regression test)
- Coverage del wrapper ≥70%
- Migration progress tracker in `D:\Desktop\Multiverbe-Business\status.json` (key `pms_migration_progress`)
## References
- "StranglerFigApplication" — Martin Fowler (martinfowler.com/bliki/StranglerFigApplication.html)
- ADR-001 (PMS) · ADR-002 (Hexagonal)
- Wow Audit 2026-05-14 W-002/W-010/W-011 gaps
- BOS action_item `web-quality-gap-closure-2026-05-15`
ADR-004 · Section Registry restricted menu (W-010 fix · seedato per Child-1)
# ADR-004 · Section Registry restricted menu per AI section selection
- Status: proposed (Child-1 finalizza dopo founder pick)
- Date: 2026-05-16
- Deciders: Gregorio (founder picka final menù), Claude Child-1
- Tags: ai, section-registry, wow-audit-W010
## Context
Wow Audit 2026-05-14 identifica gap W-010: `SectionRenderer` in `components/sections/index.tsx` ritorna null silenziosamente per sezioni AI-selectable che non sono implementate (`menu-story-driven`, `hero-food-bento`, `hero-video-loop`, `gallery-scroll-parallax` + famiglie social-proof/about-story/private-events).
Risultato: AI Art Director può "scegliere" sezione che non rende → bug silenzioso shipabile, screenshot stub passa Stage-6 review.
## Decision
Restringere il menù dell'AI section selection a **solo sezioni esistenti in `SectionRegistry` typed**.
```typescript
// Before
type SectionKind = string; // any string from AI
// After
const SectionRegistry = {
'hero-classic': HeroClassic,
'hero-image-bg': HeroImageBg,
'menu-grid': MenuGrid,
'gallery-grid': GalleryGrid,
'booking-cta': BookingCta,
'about-text': AboutText,
'contact-form': ContactForm,
'footer-classic': FooterClassic,
// ... solo sezioni che esistono davvero
} as const;
type SectionKind = keyof typeof SectionRegistry;
AI Art Director prompt vincola output a SectionKind enum.
Sezioni mancanti (menu-story-driven, hero-food-bento, hero-video-loop, gallery-scroll-parallax, famiglie social-proof/about-story/private-events):
- Deferred a Fase 4 Wow Backlog
- Documentate in
execution/wow-backlog.mdcome W-{N} - Action_item BOS per implementation Q3 2026
Alternative considered
A. Implementare le sezioni mancanti subito
- ❌ Con: 6-10h aggiuntive · scope creep · time-budget oggi 6h Child-1
- Esclusa
B. Restringere menù (scelta)
- ✅ Pro: bug chiuso oggi · scope respected · safer default
- ⚠️ Con: AI Art Director ha meno opzioni creative
- ✅ Mitigation: implementare le 7+ sezioni in W4-W5 quando tempo permette
Consequences
- Zero
nullrenders silenziosi <UnknownSectionWarning />explicit fallback se AI sbaglia (improbabile post-vincolo)- Type safety end-to-end · compile-time guard
- Sezioni differred chiare nel backlog
Verification
- Test: AI mock returns invalid kind → expect
<UnknownSectionWarning />rendered (NOT null) - Test: AI mock returns valid kind → expect component rendered
- Lint rule:
SectionRegistrynon può essere indexed con string raw · soloSectionKind
References
- Wow Audit 2026-05-14 W-010
- ADR-003 (Strangler retrofit · W-010 side-effect)
---
## ADR-005 · Studi-medici adapter GDPR Art 9 (seedato per Child-2)
```markdown
# ADR-005 · Studi-medici adapter · GDPR Art 9 audit log + pseudonimizzazione
- Status: proposed (Child-2 finalizza)
- Date: 2026-05-16
- Deciders: Gregorio (founder · legal liability), Claude Child-2
- Tags: privacy, gdpr, art9, sanitario, security
## Context
L'adapter `studi-medici` tratta dati sanitari di pazienti = **categoria speciale art. 9 GDPR**. Obblighi legali:
- Consenso esplicito (art. 9.2.a) o necessità medica (art. 9.2.h)
- Misure di sicurezza tecniche e organizzative adeguate (art. 32)
- Audit log obbligatorio (CHI ha visto COSA QUANDO PERCHÉ)
- Pseudonimizzazione raccomandata (art. 32.1.a)
Multiverbe è basata in Lugano (TI, CH) · clienti CH+IT+EU5. Founder personal liability **CHF 250k** sotto revFADP CH se breach (memoria `feedback_marketing_capture_proattiva` + skill `multiverbe-incident-response`).
## Decision
L'adapter `studi-medici` implementa:
1. **Pseudonimizzazione deterministic** del Codice Fiscale paziente:
```typescript
patient_pseudonym_id = HMAC-SHA256(workspace_secret, patient_codice_fiscale)
Mapping pseudonym ↔ CF storato in tabella patient_pseudo_map RLS workspace_id scoped + role clinic_admin only.
-
Audit log obbligatorio in tabella
audit_log_gdpr_art9:event_type,workspace_id,actor_user_id,patient_pseudonym_id,prestazione_code,purpose,legal_basis(art 9.2.x),timestamp,ip_hash,session_id- Append-only (no UPDATE/DELETE policy)
- Retention 10 anni (max EU)
- Encrypted at rest (Supabase default · revisit se serve TDE custom)
-
Email confirmation contiene solo
patient_pseudonym_id· NEVER CF. -
Telemetria + log strip PII pre-export ·
metadata.pii_fields: ['patient_codice_fiscale', 'patient_name']enforced. -
Tier gating: adapter disponibile SOLO workspace tier ≥ Pro (Starter return
Result.err({ code: 'TIER_REQUIRED', message: 'Adapter medici richiede piano Pro' })). -
Feature flag
booking.adapter.medicidefault OFF · activation richiede:- Tier check
- Workspace ha accepted DPA Multiverbe → studio medico
- Consenso art 9 firmato dal paziente (workspace responsibility)
Alternative considered
A. No adapter medici prima del 10 Giu
- ✅ Pro: zero rischio art 9 prima del launch
- ❌ Con: studi medici target sector confermato (canon/11-sectors-deep.md)
- Mitigation alternativa: skeleton + flag OFF · attivazione post-launch con DPA firmata
B. Adapter implementato ma flag default OFF (scelta)
- ✅ Pro: codice ready · activation gated per cliente
- ✅ Pro: testing infrastruttura privacy oggi · niente fretta in prod
- ⚠️ Con: complessità extra subito
- Scelta: aderente a privacy-by-design (art 25)
C. Adapter live default ON
- ❌ Con: rischio breach senza DPA firmata · founder liability CHF 250k
- Esclusa categoricamente
Consequences
Positive
- Privacy-by-design (art 25) compliant
- Founder liability mitigated · "due diligence" demonstrable
- Studi medici sector unlock post-DPA flow
- Audit log review monthly check schedule (security calendar)
Negative
- 2 tabelle DB nuove:
patient_pseudo_map+audit_log_gdpr_art9(Child-2 deve escalare Mother per migration · DB write gated) - Cost: secret
workspace_secretper HMAC · stored in Supabase Vault o env per-workspace - Sub-processor list update: nessun nuovo (rimaniamo su Anthropic+Mistral+Supabase ma adapter medici NON manda PII ad AI · solo seed astratti)
Neutral
- Pattern riutilizzabile per altri adapter sensibili (es. immobiliari trattano CF acquirente)
Verification
- Test: pseudonimizzazione roundtrip deterministic
- Test: audit log INSERT obbligatorio · skip mock = fail
- Test: RLS isolation (workspace A audit log NON visibile da workspace B)
- Test: CF NON appare in log strutturati (regex scanner)
- Test: tier Starter denied
- Pen test simulato: query
audit_log_gdpr_art9da role anon expect deny
References
- GDPR Reg. (UE) 2016/679 art 9 (categorie particolari) + art 25 (privacy by design) + art 32 (security)
- revFADP (CH) art 5 lit g (dati personali degni di particolare protezione) + art 22 (sicurezza)
- BOS skill
multiverbe-ch-compliance+multiverbe-security-ch - canon/11-sectors-deep.md § Studi medici
- Memoria
feedback_supabase_rls_patterns_multi_tenant
---
## Mother fase-0 commit-template per ADR
docs(adr): seed 001-PMS, 002-hexagonal, 003-strangler, 004-section-registry, 005-medici-gdpr
ADR seedati per Planet Module System foundation session 2026-05-16. Child-1 finalizza 001+003+004 con esempi reali. Child-2 finalizza 002+005 con implementation details.
Refs: BOS#planet-module-system-foundation-2026-05-16