PMS Sessione D · Strangler retrofit reale · Scoping doc
Status: READ-ONLY scoping · NO execution Owner execution: Joint (Claude code + founder UAT) Stima: 8-12h distribuite in 2-3 sessioni Pre-requisite: founder disponibile per UAT 30-45 min tra fasi Rollback: feature flag
?ff=pms.web.enabled:off(5 sec) Action item BOS:pms-strangler-real-retrofit-web-booking-2026-05-31
Contesto · cosa è già fatto (Sessioni A/B/C)
Le 3 sessioni precedenti del PMS retrofit sono mergiate a master via PR:
| Sessione | PR | Cosa fatto |
|---|---|---|
| A · npm→pnpm conversion | PR #57 | frontend/multiverbe-app ora workspace member pnpm-workspace.yaml |
| B · planet-core + testkit | PR #56 | @multiverbe/planet-core registry/loader/event-bus/feature-flags · @multiverbe/planet-testkit 18 contract test |
| C · sector-adapters + GDPR Art 9 | PR #60 | @multiverbe/sector-adapters 7 settori · DB migration audit_log_gdpr_art9 + patient_pseudo_map (medici) |
6 packages esistono come scaffold:
@multiverbe/contractsv0.1.0 — defineModule, PlanetContext, PlanetManifest, EventMap@multiverbe/planet-corev0.1.0 — registry + loader + event-bus + feature-flags + telemetry + healthcheck@multiverbe/planet-testkitv0.1.0 — contract suite vitest runner@multiverbe/planet-webv0.1.0 — scaffold conforme (NON wirato)@multiverbe/planet-bookingv0.1.0 — scaffold conforme (NON wirato)@multiverbe/sector-adaptersv0.1.0 — 7 settori · 4 adapter completi (ristorazione/parrucchieri/studi-medici/hotel) + 3 skeleton
Stato reale: i 2 scaffold planet-web + planet-booking esistono ma il dashboard frontend NON li monta. Il routing avviene tutto via PlanetScene + PlanetPanel con state Zustand (selectedPlanet + activeSatellite). Nessun bridge tra l'app esistente e i package PMS.
Scope reale Sessione D
Cosa serve fare (in ordine logica esecuzione)
Fase 1 · Bootstrap registry nel frontend (1.5h)
File: frontend/multiverbe-app/src/main.tsx
Oggi: monta solo React + AuthProvider + App.
Da fare:
- Import
createRegistry,registerAdapterda@multiverbe/planet-core - Lazy-import
moduleda@multiverbe/planet-web+@multiverbe/planet-booking - Crea istanza PlanetContext con:
workspaceIdda Zustand store (useWorkspace hook)supabaseclient esistentefeatureFlags.isOn(key)reading URL?ff=key:on/off+ localStorage fallbacktelemetryno-op stub (Sentry wrapper next phase)loggerconsole wrappereventBuslocalmente Map-based (cross-planet broadcast)
- Register entrambi i moduli + init()
- Espone registry via React Context (
PMSContext) sotto AuthProvider
Output verificabile: console.log in dev mode mostra "planet-web ok · planet-booking ok · contract tests pass".
Fase 2 · Feature flag URL handler (30 min)
File: nuovo frontend/multiverbe-app/src/lib/pms/feature-flags.ts
Implementa:
parseFFFromURL()→?ff=pms.web.enabled:off,pms.booking.enabled:on→Map<string, boolean>isFFOn(key)→ URL > localStorage > manifest defaultsetFF(key, value)→ localStorage write + emit event
Wire in main.tsx bootstrap.
Fase 3 · Bridge Web planet (3h)
File: frontend/multiverbe-app/src/components/layout/PlanetPanel.tsx
Oggi: switch case routing web.site → SiteBuilderLauncher, web.analytics → AnalyticsPage, ecc.
Da fare nel SatelliteContent (function inside PlanetPanel):
if (destination === 'web') {
const webModule = useRegistryModule('planet-web');
if (webModule && featureFlags.isOn('pms.web.enabled')) {
// PMS-managed mount
const Mount = webModule.mount({ slot: { name: satelliteId || 'default' } });
return <Mount />;
}
// FALLBACK: existing component chain (current code path)
switch (satelliteId) {
case 'site': return <SiteBuilderLauncher />;
case 'analytics': return <AnalyticsPage />;
// ... resto invariato ...
}
}
Pattern: PMS-first con fallback istantaneo a legacy. Quando il mount() PMS è incompleto, ritorna null → fallback automatico al switch case esistente.
Per ora il mount() PMS è un placeholder div (WebPlaceholderComponent in planet-web/src/index.ts:109). Sessione D NON sostituisce il mount() con il vero codice — quello è Sessione E future.
Sessione D fa solo il bridge: feature flag → either PMS path or legacy.
Fase 4 · Bridge Booking planet (1.5h)
Stesso pattern di Fase 3 ma per destination === 'booking'.
Fase 5 · Contract test integration (1h)
File: frontend/multiverbe-app/src/test/pms-bootstrap.test.ts (nuovo)
Test integration che verifica:
- Registry bootstrap senza errori
- module.init() ritorna Result.ok
- Feature flag URL parsing
- Healthcheck pass per entrambi i planet
Run: pnpm --filter @multiverbe/dashboard test
Fase 6 · UAT + smoke E2E (1-2h founder)
Joint session:
- Founder login app · navigate planet Web → satellite Site → verifica mount placeholder
- URL
?ff=pms.web.enabled:off· refresh → verifica fallback a SiteBuilderLauncher legacy - Stesso pattern pianeta Booking
- Run contract tests pass
Fase 7 · Commit + push (30 min)
Commit message structurato. Push a feature branch feat/pms-sessione-d-bridge. UAT founder. Merge.
Rischi identificati · mitigation
R1 · Collision con design system attivo (HIGH risk)
Issue: founder sta attivamente modificando App.tsx, PlanetPanel.tsx, sta aggiungendo GlassSheetOverlay.tsx (v4.6). Touchare gli stessi file = merge conflict garantito.
Mitigation:
- ESEGUI Sessione D SOLO quando founder PAUSA il design work
- Joint scheduled session 4h continuative
- Lavora su branch dedicato
feat/pms-sessione-d-bridge(no master) - Bridge logic concentrato in 1-2 file (main.tsx + PlanetPanel.tsx 2 location switch case)
R2 · React Context overhead bootstrap (MID risk)
Issue: aggiungere PMSContext + registry init in main.tsx ritarda il first paint.
Mitigation:
- Lazy-init: registry created at first useRegistryModule() call, NOT at bootstrap
- defer planet module imports via dynamic import()
- Measure bundle: planet-core + 2 manifests = ~5KB gzipped budget
R3 · Feature flag URL ?ff= conflict con altri URL params (LOW)
Issue: parse del query string ?ff= potrebbe collidere con altri params usati (?auth=, ?__dev=, ?siteId=, ?t=).
Mitigation: namespace dedicato ?ff= · multi-value separato da , · case-insensitive · validation in parseFFFromURL().
R4 · Contract tests fail al primo runtime (MID)
Issue: i contract test pre-esistenti su planet-web/planet-booking testano in isolation con fake context. Quando integrati nel main.tsx con context reale (Supabase + workspace), potrebbero fallire per ragioni di env (anon key, RLS, ecc.).
Mitigation:
- Eseguire contract test in
pms-bootstrap.test.tscon mock Supabase - Init test isolato dal context reale
- Fail-safe: se
module.init()fail, log warning ma NON crash bootstrap (app continua con fallback)
R5 · Vercel build fail per workspace dependencies (LOW)
Issue: frontend/multiverbe-app/package.json deve dichiarare @multiverbe/planet-web come workspace:* dep. Se manca, Vercel build fail dipende dalla pnpm-lock.
Mitigation: aggiungere in dependencies:
"@multiverbe/planet-web": "workspace:*",
"@multiverbe/planet-booking": "workspace:*",
"@multiverbe/planet-core": "workspace:*",
"@multiverbe/contracts": "workspace:*"
Run pnpm install per rigen lockfile · commit lockfile.
Out-of-scope Sessione D (post-MVP)
NON facciamo in Sessione D:
- ❌ Implementare il vero
mount()di planet-web con sites-runtime real wiring (Sessione E) - ❌ Migrare event-bus a Sentry/PostHog telemetry (Sessione F)
- ❌ State migrations runtime su switch versione manifest (Sessione G)
- ❌ Cross-planet event subscription (es.
web:site:published→crm:contact:created) (Sessione H) - ❌ Server-side PMS (edge function executor) (Sessione I post-launch)
Sessione D è ESCLUSIVAMENTE bridge + feature flag. Tutto il vero codice business resta in frontend/multiverbe-app/src/components/* + src/features/booking/* come oggi.
Acceptance criteria
Sessione D considerata "done" quando:
- [ ]
pnpm installda root passa zero errori (workspace + lockfile coerenti) - [ ]
pnpm --filter @multiverbe/dashboard test pms-bootstrap.test.tspass - [ ]
pnpm --filter @multiverbe/planet-web test(contract suite) pass - [ ]
pnpm --filter @multiverbe/planet-booking testpass - [ ] App login + navigate planet Web (default
?ff=pms.web.enabled:on) → mostra placeholder PMS div - [ ] App login + navigate planet Web con
?ff=pms.web.enabled:off→ mostra SiteBuilderLauncher legacy (fallback) - [ ] Idem pianeta Booking
- [ ] Vercel build production pass post-merge
- [ ] Browser console: zero errors related to PMS bootstrap
Decision needed dal founder · quando eseguire
Sessione D è pronta da eseguire MA collide con il tuo lavoro design attivo (v4.5/v4.6 glass redesign). Opzioni:
- Defer post-lift launch (24 Mag+) — più sicuro, no merge conflict. Dopo primo paying.
- Window dedicato 4h continuative pre-launch — solo se design v4.x è stabile e tu sei disponibile UAT.
- Mai — accettare che planet-web + planet-booking scaffold restino bridged solo via tests, mai mount runtime. Costo: il PMS resta architettura "future" non "today" → quando vorrai aggiungere planet HR (Q3) o Finanza (2027), dovrai fare bridge allora.
Raccomandazione: opzione 1 (defer post-lift). Il PMS retrofit non sblocca primo paying, e il design v4.x è ancora in active iteration.
Last update: 2026-05-18 · scoping post-N1 immobiliari seed Owner: Gregorio (decisione timing) · Claude (execution quando autorizzato)