HANDOFF — Multiverbe · E2E verde + Igiene DB + Cleanup deprecati + No-show simplify
Preparato 2026-06-06 (sessione
reverent-hermann-66aa02, contesto pieno). Esegui in sessione fresca, repo codiceD:\Desktop\Multiverbe. Ordine e DoD sotto. Qualità BigTech, gate-ready.
0 · CHI SEI / MISSIONE
Sei una sessione Claude Code autonoma sul prodotto MULTIVERBE (BOS per PMI svizzere). Repo D:\Desktop\Multiverbe (lavora in un worktree dedicato). Supabase yqhixdqipojvgzfadufo (eu-central-1). Deploy Vercel su merge in master. Gate vicino (10 Giu / sprint 15 Giu): chiudi buchi e igiene con qualità estrema, NON costruire feature nuove. Procedi in autonomia: branch → PR → CI verde → squash-merge → verifica live. Parla al founder solo per vere decisioni (schema prod rischioso, pricing/canon, sicurezza, hard-to-revert).
Il founder ha scelto in questa sessione: fare 2+3+4 (E2E verde + Igiene DB + Cleanup deprecati) + No-show #287 = "nascondi/semplifica di più", tutto in ordine e in estrema qualità.
1 · OPERATING CHARTER (sintesi — vale sempre)
Leggi le memorie operating_charter, feedback_no_hardcoding_quality, project_ci_vercel_cost_2026_06_06, feedback_notification_architecture_hub_crm, project_supabase_advisor_hardening_2026_06_03 (metodo dry-run RLS), feedback_do_not_touch_3d_planets.
DoD (un task è "fatto" SOLO se): funzionante + verificato dal vivo (test o passi manuali dichiarati) + testato dove ha senso (test/doc nello stesso commit) + piccolo/coeso (no refactor mescolati, YAGNI) + zero hardcoded interno customer-facing + sicuro multi-tenant (filtra workspace_id in ogni query/cache/storage, ownership al data-layer, RLS non basta da sola) + scalabile/osservabile + niente regressioni + fix alla radice (no declassamenti) + merge solo a CI verde + advisor 0 nuovi finding.
Processo: plan-first per lavori non banali; proponi la scelta migliore con trade-off; verifica lo stato reale (DB/prod/CI) prima di agire; chiedi prima solo per schema prod rischioso / pricing-canon / sicurezza / hard-to-revert.
2 · COST-MODE CI/INFRA (attivo, additivo ai gate)
Pre-revenue: ogni minuto CI e ogni build Vercel costa. Verifica in LOCALE prima di pushare (la PR nasce verde, niente catene di fix-commit). Batch in pochi commit coesi, 1 PR per unità, squash-merge. No commit usa-e-getta. Niente nuovi cron. I gate NON si toccano (typecheck+build+lint+test+security restano). GitHub budget Actions $40+stop (NON rimetterlo a $0 = blocca tutta la CI). Vercel skip-deployments ON + cap $25.
3 · METODO DI VERIFICA (questo repo)
api/NON è typecheckato da tsc (tsconfig include solosrc/). Per i fileapi/:node <root>/node_modules/.bin/esbuild <file> --bundle --platform=node --format=esm --packages=external(sintassi) + vitest col binario root e config usa-e-gettacss.postcss:{plugins:[]}(test puri, vedi memoriareference_local_vitest_worktree_technique) +node scripts/check-api-esm-imports.mjs(import relativiapi/DEVONO avere.js).- Lint è il gate vero per
api/:eslint src/ api/ --max-warnings=560(cap ASSOLUTO, ~554 oggi). Evitasecurity/detect-object-injection(nienteobj[varKey]: usaswitchoMap.getda Record viaObject.entries). Nienteeslint-disablemorti. - Frontend:
pnpm --filter multiverbe-dashboard build=tsc && vite build(è ciò che builda Vercel; usalo come typecheck affidabile anche se Actions è giù). - Schema: dry-run DO-block +
RAISE 'DRYRUN_OK'(forza rollback, testa su ruoli/dati reali) →apply_migrationMCP → advisor 0 nuovi WARN → se cambia lo schema-dati rigenerasrc/types/supabase.ts(hand-edit minimale multi-line; l'output MCP è single-line). Indici/policy non cambiano i types. - Frontend dietro auth = QA founder (no Playwright). Tu verifichi backend + smoke endpoint (es.
POSTsenza token →401). - Web: per stack di ultimo livello (Playwright 2026, Supabase RLS, Vercel) valida sul web le best practice correnti prima di decidere.
4 · STATO GIÀ VERIFICATO 2026-06-06 (NON rifare)
- CI master VERDE:
frontend-ci.ymlsuccess su HEAD. I merge--admin#278/#287/#292 (durante il blocco billing) non hanno lasciato regressioni. - Login fresco in PROD è SANO (verificato con Playwright su
https://multiverbe.app): cookie→email→password→bottone "Apri Multiverbe" cliccabile in <500ms, form stabile (iduseIdinvariato, bbox ferme), zero overlay che intercetta, networkidle <1s. Il form èMAIN.mv-auth-form-colcontextbox "Email"+input[type=password]+ button "Apri Multiverbe". - Advisor SECURITY: 0 ERROR, 0 WARN, 2 INFO
rls_enabled_no_policy(external_api_usage,idempotency_keys) = fail-closed accettati (RLS ON + 0 policy → deny-by-default; tabelle di servizio). Eventuale micro-hardening: revocare i grant ridondantianon,authenticatedsu quelle 2 tabelle (non bloccante). - Advisor PERFORMANCE: 0 ERROR, 13 WARN (dettagli in TASK 1), 145 INFO (109 unused_index + 35 unindexed_FK = normale pre-traffico, non toccare in massa).
I 4 TASK — in ordine
▶ TASK 1 — Igiene DB pre-scala (advisor performance → 0 WARN) · PR "chore(db): advisor hygiene"
Perché: porta l'advisor a 0 WARN, RLS più pulita/scalabile. Verificabile end-to-end dal vivo. Tocca RLS → procedi col metodo dry-run + verifica accessi prima/dopo (rischio cross-tenant se sbagli la semantica).
1a · duplicate_index (2) — quick win, ma VERIFICA prima di droppare
public.entity_interactions:{idx_entity_interactions_ws, idx_entity_interactions_ws_created}segnalati identici.public.tier_caps:{tier_caps_tier_metric_key, uq_tier_caps_tier_metric}segnalati identici. ⚠️ Verifica le definizioni reali (select indexdef from pg_indexes where indexname in (...)) PRIMA: i nomi suggeriscono colonne diverse (_wsvs_ws_created). Se NON sono davvero identici, NON droppare (l'advisor confronta le colonne ma controlla). Pertier_caps: uno è probabilmente un UNIQUE constraint (uq_…) e uno un index — droppa l'index, mai il constraint (servirebbedrop index, non toccare il constraint che garantisce l'unicità). Migration additiva/reversibile.
1b · multiple_permissive_policies (11) — consolidamento RLS
Due gruppi, due pattern di fix:
- 6 tabelle
site_*(site_assets,site_block_translations,site_blocks,site_pages,site_subdomains,sites) — roleanon, action SELECT, policy{*_public_read_published, *_select}. Il*_select(owner/authenticated) si applica anche ad anon → ridondanza. Fix: restringere*_selectaTO authenticated(gli owner loggati), lasciando*_public_read_publishedcome unica policyanon. Verifica: anon legge SOLO i sitipublished, NON i draft/non-pubblicati; l'owner loggato continua a leggere i propri. - 5 tabelle Sales/team (
deals,sales_commissions_rules,sales_quotas,sales_territories,team_member_planet_access) — roleauthenticated, action SELECT, policy{*_modify, *_select}. La*_modifyè probabilmenteFOR ALL→ include SELECT, si sovrappone a*_select. Fix: cambiare*_modifydaFOR ALLaFOR INSERT/UPDATE/DELETE(o split), lasciando*_selectper la lettura. Verifica: un utente legge solo i record del proprioworkspace_id; le scritture restano protette. Metodo (memoriaproject_supabase_advisor_hardening_2026_06_03): per ogni tabella ispeziona le policy reali (pg_policies), scrivi la migration, dry-run in DO-block con verificaset role anon/authenticated+request.jwt.claimssimulati su dati reali (un sito published vs draft; un deal di workspace A vs B), poiapply_migration. Usa(SELECT auth.uid())wrap per initplan caching (skillmultiverbe-supabase-rls-patterns). DoD TASK 1: advisor performance recheck → quei 13 WARN spariti, 0 nuovi finding security/perf; accessi anon/authenticated invariati nella semantica (verificati prima/dopo); migration nel repodatabase/migrations/; nessun cambio ai types. CI verde.
▶ TASK 2 — No-show #287 "nascondi/semplifica di più" (decisione founder) · PR "feat(booking): de-emphasize no-show fee UI"
File: UI in frontend/multiverbe-app/src/features/booking/dashboard/BookingDashboard.tsx (bottone "Applica penale CHF X"); endpoint api/booking/no-show-fee.ts (NON toccare la logica/idempotenza). Helper i18n in api/booking/_lib/i18n.ts.
Cosa fare: rendere il no-show meno prominente nella dashboard. Oggi compare se il titolare ha no_show_fee_chf>0 (già gated). "Semplifica di più" = es. spostarlo dietro un dettaglio/menu "azioni avanzate" della prenotazione no_show, o ridurlo a voce discreta non in primo piano; togliere enfasi visiva. Non rimuovere endpoint/colonne (bookings.no_show_fee_applied_chf/at) — solo UI. Verifica con il founder il livello di "nascondere" (QA visiva sua).
DoD: tsc && vite build verde; endpoint intatto (smoke POST /api/booking/no-show-fee senza token → 401); UI verificata dal founder; copy eventuale via skill multiverbe-copy (it + de/fr/en se tocchi stringhe utente). Aggiorna memoria feedback_notification_architecture_hub_crm (no-show ora "semplificata" non solo gated).
▶ TASK 3 — Cleanup deprecati: edge ai-copilot-* (parte SICURA) · PR "chore: remove deprecated ai-copilot edge functions"
Contesto: 8 edge supabase/functions/ai-copilot-* (-chat,-scan,-pulse,-goals,-weekly,-monthly,-yearly,-competitors) + _shared/{sovereign,sole-identity,ai-client}.ts. NON sono deployate (list_edge_functions MCP = vuoto) → sostituite dal routing sovrano in api/_lib/sovereign. Sono codice morto in repo.
⚠️ Cautele prima di rimuovere:
- Verifica che NESSUN cron/webhook/Inngest attivo le invochi (grep
ai-copilotinapi/,.github/workflows,vercel.json, supabase cron). Il hook frontendsrc/hooks/useAIChat.tsè ATTIVO e usa il routing nuovo → NON è questo, non toccarlo. scripts/check-sole-identity-parity.mjsconfronta l'identità Soleapi/_lib↔ edge_shared/sole-identity.ts. Se rimuovi le edge, aggiorna o rimuovi quello script + il suo step in CI (frontend-ci/planet-ci) per non lasciarlo rotto._shared/*usati SOLO dalle edge → rimuovibili con esse; se referenziati altrove, tieni.docs/plans/2026-02-*ai-copilot*+maind-brain-*= doc storici pre-canon → archivia/rimuovi (basso rischio). DoD: build verde, nessun import rotto, parity-script e CI coerenti (verde), zero riferimenti orfani. Additivo/reversibile (git).
▶ TASK 4 — E2E smoke verde affidabile · PR "test(e2e): robust login flow" — richiede input founder per validare
Diagnosi già fatta (NON rifare): il login in prod è SANO. I 4 e2e (tests/e2e/{login-smoke,crm-add-contact,booking-create,stripe-checkout}.spec.ts) falliscono solo in ambiente CI (runner headless lento), non in prodotto. Sintomi: fill/click vanno in "Test timeout 30000ms" (budget globale del test, non l'actionTimeout) → qualcosa prima consuma i 30s. Causa probabile: page.goto('/') usa il default waitUntil:'load' che aspetta TUTTI gli asset (scena 3D pesante) → su runner CI lento mangia il test-timeout; l'ultima azione (password fill in crm, click in login-smoke) sfora. Dal vivo (rete veloce) non si riproduce.
Fix raccomandato (best-practice Playwright 2026 — valida sul web):
page.goto('/', { waitUntil: 'domcontentloaded' })(non 'load') + web-first wait sul form login prima di interagire.test.setTimeout(60_000)(otimeoutin config) per assorbire la lentezza CI.- Cookie banner robusto: è un
<div role=dialog>non-modale, ancorato in fondo (NON copre il form). Il checkisVisible()immediato è race-y. Meglio: dismissalo deterministicamente (click su "Va bene così" conwaitForbreve, oppure pre-seedlocalStoragedel consenso prima del goto). - Verifica che
playwright.config.tsnavigationTimeout/actionTimeoutsiano coerenti col nuovo waitUntil. VINCOLO: per riprodurre/validare servonoCLAUDE_DEMO_EMAIL/CLAUDE_DEMO_PASSWORD(GH secrets, non in chiaro). Chiedi al founder: (a) le credenziali demo per girarepnpm --filter multiverbe-dashboard test:e2ein locale headless contro prod, OPPURE (b) l'ok a pushare il fix + lanciare UNworkflow_dispatchdie2e-smoke.ymlper validare (1 run, cost-mode ok). Non pushare fix speculativi a raffica. DoD: i 4 e2e verdi in CI (workflow_dispatch su prod), login+nav confermati; nessun falso-rosso residuo.
⏸ (OPZIONALE, RISCHIOSO — NON nel giro "sicuro") — rename opera legacy
8 file usano il naming MAIND opera: src/types/planets.ts, src/store/index.ts, src/lib/cloudflare-api.ts, src/components/layout/{SectionTabBar,PlanetSidebar,PlanetScene,DesktopSidebar}.tsx, src/components/dashboard/InsightsFeed.tsx. ⚠️ PlanetScene.tsx = scena 3D = territorio founder (memoria feedback_do_not_touch_3d_planets, chiedi prima). entity_interactions.planet CHECK rifiuta opera (accetta crm|booking|…) → c'è una mappatura; il refactor è classificato post-MVP in CLAUDE.md. Raccomandazione: NON farlo in questo giro (o solo con ok esplicito founder e SENZA toccare geometria/animazione 3D). Mappare opera→crm/booking con cura, zero regressioni UI.
5 · PRIMO PASSO CONCRETO
- Conferma CI master verde (
gh run list --branch master --workflow frontend-ci.yml --limit 1). - Apri TASK 1 (Igiene DB): introspeziona
pg_indexes+pg_policiesper le 13 tabelle/indici elencati, costruisci la migration, dry-run con verifica accessi anon/authenticated su dati reali, applica, advisor recheck → 0 WARN. Una PR coesa. - Procedi TASK 2 → 3, ognuno PR coesa verificata in locale → CI verde → squash-merge → verifica live.
- TASK 4 (E2E): chiedi subito al founder le credenziali demo o l'ok al workflow_dispatch, così non resti bloccato a fine.
- Chiudi con blocco 🔴 DA FARE + aggiorna BOS (
status.json: action_items, decisione no-show "semplificata") + memorie + push BOS.
6 · DoD GLOBALE
Ogni PR: verificata in locale (esbuild/vitest/check-esm/eslint≤560 per api/; tsc && vite build per frontend) → nasce verde → CI verde → squash-merge → verifica live (smoke endpoint/advisor) → niente regressioni → advisor 0 nuovi. Non perdere nulla: commit a fine + 🔴 DA FARE + BOS aggiornato e pushato.