📐 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.md come 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 null renders 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: SectionRegistry non può essere indexed con string raw · solo SectionKind

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.

  1. 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)
  2. Email confirmation contiene solo patient_pseudonym_id · NEVER CF.

  3. Telemetria + log strip PII pre-export · metadata.pii_fields: ['patient_codice_fiscale', 'patient_name'] enforced.

  4. Tier gating: adapter disponibile SOLO workspace tier ≥ Pro (Starter return Result.err({ code: 'TIER_REQUIRED', message: 'Adapter medici richiede piano Pro' })).

  5. Feature flag booking.adapter.medici default 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_secret per 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_art9 da 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