App Readiness · Lockdown Lift Plan · 2026-05-18
Audit READ-ONLY condotto da Claude (sessione P-launch-readiness) il 2026-05-18 Hard gate 10 Giu 2026 · 22 giorni rimanenti · soft gate 31 Mag (13 giorni)
Scopo: identificare ogni gate tecnico + operativo tra l'app oggi (founder-gated lockdown,
VITE_FOUNDER_EMAILS3 email) e il primo paying customer reale che firma un checkout Stripe e riceve valore dal SaaS in autonomia.Premessa metodologica: questo report è prodotto da Claude in lettura sola del repo codice (
D:\Desktop\Multiverbe) + database Supabase live (yqhixdqipojvgzfadufo) + checklist business (Multiverbe-Business/ops/first-paying-customer-checklist.md). Nessuna modifica al codice, niente migration, niente deploy.
0 · Executive summary (per founder · 60 secondi)
Verdict launch-readiness 18 Mag 2026: READY-WITH-2-BLOCKERS.
L'app è funzionalmente pronta per il primo paying customer. Il 78% delle 35 task della
checklist first-paying-customer-checklist.md è done; i 2 unici BLOCKING reali sono
azioni founder (10 + 20 minuti), non codice da scrivere:
- BLOCKING-A3: verify domain Brevo (TXT su DNS
multiverbe.com) → senza, le mail transazionali (signup confirm, welcome paying, invoice receipt) NON partono. - BLOCKING-C2: wildcard CNAME
*.sites.multiverbe.comsu DNS → senza, i siti generati dal Site Builder NON sono raggiungibili dal pubblico.
Tutto il resto è polish o stato fisiologico di un MVP pre-lancio.
Counts
| Categoria | Findings |
|---|---|
| BLOCKING (pre-payment) | 6 |
| NICE-TO-HAVE (post-1st) | 9 |
| Risk register top | 10 |
Top 3 founder action items immediate (oggi · 18 Mag)
- Verify domain Brevo (10 min) — Dashboard Brevo > Senders > Domains >
multiverbe.com→ copia 3 record DNS (1 TXT DKIM + 1 TXT SPF + 1 TXT verification) → incolla in provider DNS landingmultiverbe.com. Sblocca BLOCKING-A3 (email confirmation, welcome, invoice receipts). - DNS wildcard
*.sites.multiverbe.com(20 min) — Cloudflare/Register.it CNAME →cname.vercel-dns.com+ verifica nel projectmultiverbe-sitesdi Vercel. Sblocca BLOCKING-C2 + abilita SSL Let's Encrypt auto-issued post-propagazione DNS (~5 min). - Switch Stripe live mode + fund test card $5 — Dashboard Stripe > Activate account
(founder data + bank account CH/IT). Poi rotate test → live le 9 price IDs su Vercel
env
STRIPE_PRICE_*. Sblocca BLOCKING-F0 (oggi le price sonosk_test_*).
Il primo paying customer non può oggi firmare un checkout reale finché item #3 non è fatto, anche se la
BillingPageeuseCheckoutsono già code-complete.
1 · Stato lockdown attuale (defense-in-depth a 4 layer)
L'app è protetta da 4 layer indipendenti — togliere SOLO il layer 1 (client) lascia comunque chiuso il signup; togliere SOLO il layer 2 (signup_enabled) lascia comunque i nuovi utenti banned dal trigger DB. Per APRIRE bisogna toccare tutti i layer in ordine specifico (vedi §5 checklist).
1.1 · Layer 1 · Client gate · FounderGate.tsx
File: frontend\multiverbe-app\src\components\auth\FounderGate.tsx (131 righe)
Wired in: frontend\multiverbe-app\src\App.tsx:343-344 (post-auth, pre-dashboard)
Trigger: !isFounderEmail(email) → mostra schermata "Stiamo costruendo" + auto-signOut
in 6 secondi (setTimeout in FounderGate.tsx:20-26).
isFounderEmail() è definito in frontend\multiverbe-app\src\lib\founder.ts:15-25:
const FOUNDER_EMAILS = (
import.meta.env.VITE_FOUNDER_EMAILS ?? 'metaverbe@gmail.com'
).split(',').map(e => e.trim().toLowerCase())
Build-time env: VITE_FOUNDER_EMAILS su Vercel project multiverbe-app Production
scope. Valori attesi (per BOS audit + DB allowlist):
metaverbe@gmail.com(founder Gregorio)loris.beraud17.7@icloud.com(Loris)gregoriociurleo@gmail.com(founder personal, aggiunto 2026-05-17)
Nota: la variabile è
VITE_*(esposta al client a build-time). Cambiarla richiede redeploy. La fonte di verità è la tabellapublic.founder_emails(allowlist server).
1.2 · Layer 2 · Signup UI flag · VITE_SIGNUP_ENABLED
File: frontend\multiverbe-app\src\components\auth\SignupPage.tsx:17 (default false)
Comportamento: la pagina /?auth=signup mostra <SignupClosedPage /> (righe 19-89)
con testo "Le registrazioni sono chiuse." e CTA Torna al login. Solo se
VITE_SIGNUP_ENABLED === 'true' viene renderato <SignupOriginal /> (signup form vero).
Link "Primo accesso?" nella
LoginPage.tsxè stato rimosso (commento riga 375-377:Build phase (2026-05-17 founder): registrazioni chiuse al pubblico). Mostra solo la stringa "Multiverbe è in fase di build. Le registrazioni apriranno presto." (riga 389).
1.3 · Layer 3 · Supabase Auth signup OFF (Dashboard founder)
Stato pending verifica: dalla migration founder_gate_build_phase_2026_05_17 (commento
inline righe 7-8) il toggle "Allow new users to sign up" è stato spento manualmente in
Supabase Dashboard > Authentication > Settings. Anche se il front-end manda
supabase.auth.signUp(), l'API risponde 422 Signups disabled.
Non verificabile via MCP
mcp__supabase__*perché non c'è un'API per leggere il flagdisable_signup. Va guardato manualmente in Dashboard (founder action).
1.4 · Layer 4 · Trigger DB auto_ban_non_founder_users_trigger
Migration: 20260517183128_founder_gate_build_phase_2026_05_17 (applicata su prod
Supabase 2026-05-17 18:31 UTC).
Crea 3 oggetti server-side:
- Tabella
public.founder_emails— allowlist primary keyemailtext (lowercase). Seed 2 founder + 1 manuale post-deploy (gregoriociurleo@gmail.com). RLS ON, policyfounder_emails_self_readpermette SELECT solo seemail = lower(auth.jwt() ->> 'email'). - Function
is_founder()—SECURITY DEFINER STABLE SQL, ritornabool. Usata per future RLS policy. Già un advisor warnauthenticated_security_definer_function_executableraccomanda di rivalutare quando si apre signup. - Trigger
auto_ban_non_founder_users_triggersuauth.users AFTER INSERT FOR EACH ROW. Se la nuova email non è infounder_emails, esegueUPDATE auth.users SET banned_until = 'infinity'.SECURITY DEFINERindispensabile (la tabellaauth.usersè di proprietà disupabase_auth_admin).
Verifica live (eseguita oggi via MCP):
total_users : 5
banned_users : 2 ← non-founder + 1 unconfirmed
founder_emails : 3
workspaces : 5
subscriptions : 0
sectors : 21
users_confirmed : 4
users_unconfirmed : 1
sites : 0
bookings : 0
webhook_events : 2
smtp_configs : 0 ← VUOTO (founder mailbox SMTP non ancora configurato in DB)
email_accounts : 0 ← VUOTO
tier_caps : 15 (3 tier × 5 metric)
1.5 · Riassunto · cosa cambiare per togliere il gate
| # | Layer | File / Risorsa | Cambio |
|---|---|---|---|
| 1 | Vercel env | VITE_SIGNUP_ENABLED (project multiverbe-app) |
false → true + redeploy |
| 2 | Vercel env | VITE_FOUNDER_EMAILS |
RIMUOVERE (oppure lasciare come admin allowlist · vedi §5 decisione) |
| 3 | Supabase | Dashboard > Auth > Settings > Allow new users sign up | OFF → ON (1 click founder) |
| 4 | Supabase DB | Trigger auto_ban_non_founder_users_trigger |
DROP TRIGGER auto_ban_non_founder_users_trigger ON auth.users |
| 5 | App code | frontend\multiverbe-app\src\App.tsx:343-345 |
Rimuovere il blocco if (!isFounderEmail(email)) return <FounderGate/> |
| 6 | App code | frontend\multiverbe-app\src\components\auth\LoginPage.tsx:375-390 |
Ripristinare link "Primo accesso? → /?auth=signup" |
Steps 4-6 sono opzionali con dipendenza (vedi §5): se vuoi mantenere founder_emails
come admin allowlist (es. per accesso a ?__dev=* harness) puoi tenere step 5 e DROP
solo il trigger. Decisione founder consigliata: tenere founder_emails come admin
ACL, rimuovere il banneraggio automatico, rimuovere FounderGate (il signup pubblico
diventa la porta normale, gli harness __dev restano founder-only).
2 · Onboarding readiness · landing → primo pagamento (10 step)
Audit step-by-step del happy path. Per ogni step: status (✅ works · ⚠️ partial · ❌ broken) con file/riga e gap concreti.
Step 1 · Landing multiverbe.com → CTA "Inizia ora"
Stato: ⚠️ partial — source non in questo repo
- Repo locale
D:\Desktop\Multiverbe\NON contiene il source della landing (cfr. MEMORY indexproject_landing_no_local_source.md). - La landing è hostata su Vercel project
multiverbe-landing(rinominato 2026-05-11), lockdown via Dashboard, non confonderla conD:\Desktop\Metaverbe\metaverbe.com\che è il sito agenzia. - Il founder ha confermato A1 done in checklist (riga 20: "live su Vercel multiverbe-landing").
- GAP da verificare manualmente con founder: il CTA "Inizia ora" punta a
https://app.multiverbe.app/?auth=signup? Se sì OK. Se ancoraapp.multiverbe.com, funziona via redirect 308 infrontend\multiverbe-app\vercel.json:6-19(entrambiapp.multiverbe.comeapp.multiverbe.appredirectano amultiverbe.app).
Azione: founder verifica CTA destination + test mobile.
Step 2 · Signup app.multiverbe.app/?auth=signup
File entry: src\components\auth\SignupPage.tsx → <SignupOriginal /> solo se
VITE_SIGNUP_ENABLED=true.
Stato: ✅ code-complete, gated da env flag
- Form email + password + checkbox terms (righe 245-310).
- Validation:
required+minLength={6}(riga 269). - Submit →
useAuth().register(email, password)→AuthContext.tsx:95-115→supabase.auth.signUp({ email, password }). - Risposta: se
data.user && !data.sessionmostraneedsConfirmationscreen "Apri la mail" (righe 129-200). Se session presente, login automatico. - Link OAuth Google/Apple presenti nella LoginPage (
LoginPage.tsx:298-371), MA OAuth provider va abilitato in Supabase Dashboard > Auth > Providers (founder action).
GAP / decisioni:
- OAuth Google/Apple richiede setup separato (Google Cloud OAuth client + Apple
Developer team ID). Vedi
Multiverbe-Business/ops/google-api-setup-kit-2026-05-18.md. Non bloccante: passwordless signup funziona da solo. - Quando si toglie il lockdown, ricordare di ripristinare il link "Primo accesso?" in
LoginPage.tsx:378-390(oggi mostra solo testo "Multiverbe è in fase di build").
Step 3 · Email confirmation (Brevo SMTP)
Stato: ❌ BLOCKING — Brevo domain verify pending
- Supabase di default invia l'email di conferma tramite il proprio SMTP fallback
(
noreply@mail.app.supabase.io). Quello funziona per testing, NON è production-grade (alta delivery rate solo se cliente in whitelist). - L'integrazione Brevo c'è già lato Vercel functions (
api\_lib\brevo.ts108 righeapi\booking\_lib\brevo.ts), MA la funzionesendBrevoEmailparte solo seprocess.env.BREVO_API_KEYè settato + il sender domain è verified su Brevo.
- Lo stato
smtp_configsin DB live = 0 righe (verificato via SQL). I template Brevo per signup confirm NON sono ancora collegati a Supabase Auth (servirebbe configurare Supabase Auth Email Templates con SMTP custom Brevo). - Checklist riga 22 (
A3): "Email confirmation Brevo SMTP attiva (bloccante: verify domain Brevo TXT)".
GAP concreti:
- Brevo domain verify
multiverbe.comcon TXT DKIM + SPF + verification → founder DNS task. - Supabase Auth SMTP custom (Dashboard > Authentication > Email > SMTP Settings) →
host
smtp-relay.brevo.com:587+ Brevo SMTP user + password. - Email template "Confirm signup" in Supabase → personalizzare HTML allineato a
wrapMultiverbeEmail()(api\_lib\brevo.ts:94-107) per consistenza brand.
Step 4 · Login post-confirm + creazione workspace
Stato: ✅ works (trigger handle_new_user attivo)
- Function
handle_new_user()è ON inauth.users AFTER INSERT(verificato viainformation_schema.triggers). - Crea: 1 row
workspaces(default settings) + 1 rowteam_members(role=owner). - La logica è in canon (
Multiverbe-Business/canon/05-stack.mdriga "Trigger automatici") + verificata in checklistA5done. - Live: 5 workspace per 5 users → 1:1 corrispondenza confermata.
Step 5 · Onboarding wizard SetupWizardV2
Stato: ✅ code-complete
- Wired in
App.tsx:347-369con feature flagUSE_ONBOARDING_V2 = import.meta.env.VITE_ONBOARDING_V2 === 'true'. - Default OFF (legacy
SetupWizardattivo). Founder action pre-launch: settareVITE_ONBOARDING_V2=truesu Vercel. - 4 step orchestrator (
SetupWizardV2.tsx310 righe):- Step 1 Macro (5 cards · 15 sec)
- Step 2 Sector (3-5 cards per macro · 10-30 sec)
- Step 2.5 AI Chat fallback (Sonnet 4.6 · max 4 turni ·
Step2AIChat.tsx) - Step 3 Workspace (5 sotto-domande · 60 sec)
- Step 4 Tour (60 sec preview)
- Salvataggio finale:
workspaces UPDATEconsector_id,sector_macro_id,business_type,active_modules,onboarding_completed=true(righe 142-159). - Fallback graceful pre-migration B: drop campi V2 e salva tutto in
default_settings.onboarding_v2jsonb (righe 162-176).
21 settori live in DB (verificato via SQL): 4 hospitality (ristorante, bar, hotel, bnb) · 4 salute (parrucchiere, estetica, gym, studio-medico) · 4 servizi-pro (legale, commercialista, tecnico, consulente) · 4 vendita (ecommerce, boutique, concept-store, wholesale) · 5 eventi (wedding, fotografo, video, comunicazione, web-agency).
Settori top-7 pre-MVP (cfr. memory project_sectors_top_7_pre_mvp.md):
ristorante, hotel, parrucchiere, gym, studio-medico, immobiliari (MISSING — non
in DB · canon 11-sectors-deep.md riga 47 marker TODO), studi professionali
(studio-legale + studio-commercialista + studio-tecnico ok).
GAP: il settore immobiliari previsto in canon NON è nel DB seed. È in top-7 pre-MVP. Decisione founder: ship MVP senza (il fallback AI chat copre il gap) OR
seed inline pre-deploy.
Step 6 · Dashboard primo accesso
File entry: App.tsx:377-440 → <PlanetScene /> (v2-3d 2026-05-17 root experience).
Stato: ✅ works
PlanetScene.tsx(171 righe iniziali read) = NucleoSphere 3D fullbleed + glass nav- PlanetPanel side overlay quando un pianeta è selezionato + SatelliteCard carousel.
- Layout legacy MAIND (KPI/Crescita/Finanza/Opera) rimosso dal route principale (decisione founder 2026-05-17, righe commento 17-29).
- KPI "—" placeholder è ok per primo accesso (workspace vuoto, nessun deal/booking/contatto).
GAP NICE-TO-HAVE:
- D6 Mobile responsive pixel-level audit (checklist riga 63) scheduled w4 26 Mag-1 Giu.
- Empty state copywriting su pianeti vuoti — verifica founder.
KPISection/OperaSectioncomponenti legacy esistono ancora come dead-code (cfr. memoryproject_repo_rename_2026_05_11- CLAUDE.md riga 119-126).
Step 7 · Site Builder flow
Entry: click "Pianeta Web" in DesktopSidebar.tsx:70-75 → setShowSiteBuilder(true) →
App.tsx:415-423 renderizza <SiteBuilderWizard />.
Stato: ✅ code-complete (B1+B2 done in checklist), ⚠️ smoke pending API keys
- 7 step wizard:
Step1SectorConfirm.tsxStep2TemplateChoice.tsxStep3BrandIntake.tsxStep4PhotoUpload.tsxStep5ContentSeeds.tsxStep6GeneratePreview.tsx(background job + polling)Step7Publish.tsx
- Pipeline AI 6-stage funzionante: Opus 4.7 + Kimi K2.6 + Replicate Flux + Sonnet polish.
- Persistence:
localStorage(draft) + DB upsert susites.brand_dna._intake(SiteBuilderWizard.tsx:55-62). - Tier caps via
useSiteBuilderCap(Starter 1 sito / Pro 3 / Business 10).
GAP / dipendenze:
MOONSHOT_API_KEY(Kimi K2.6 per Stage 3 Copywriter) — fallback Sonnet se mancante.REPLICATE_API_TOKEN(Flux dev/pro per Stage 4 Visual) — bloccante: no fallback, Stage 4 fallisce silenziosamente.QSTASH_TOKEN+ signing keys (Upstash) — per scheduling worker pipeline.- Verifica founder: env presenti su Vercel project
multiverbe-appProduction.
Step 8 · Booking widget setup
Entry: pianeta CRM/Booking → BookingDashboard.tsx + BookingSettings.tsx in
features\booking\dashboard\.
Stato: ✅ code-complete (E1+E2+E3+E4 100% in checklist riga 101)
- 8 API endpoint:
api\booking\{cancel,confirm,create,prepay,services,slots-available,update,widget-create}.ts. - Widget pubblico embeddable:
features\booking\widget\BookingWidget.tsx(route/widget/booking/:sluginApp.tsx:294-306, NO auth). - 4 settori coperti: ristorante (tavoli) · parrucchiere (slot) · gym (lezioni) · studio professionale (appuntamenti) · hotel (camere) — checklist riga 67.
- Email confirmation cliente via
api\booking\_lib\brevo.ts(helper dedicato) — dipende da Brevo verify (vedi BLOCKING-A3).
GAP: notification ristoratore via push PWA pending service worker (checklist riga 69 "E3 · push PWA pending service worker"). Per MVP basta email.
Step 9 · Stripe Checkout (BillingPage + useCheckout)
Stato: ⚠️ code-complete, ma Stripe in TEST MODE oggi
useCheckout.ts(72 righe) →POST /api/stripe/create-checkout-session.api\stripe\create-checkout-session.ts(194 righe):- Body:
{ tier, billingPeriod, includeSetupFee, workspaceId }. - Auth: Supabase JWT in header
X-Supabase-Auth(riga 88-102). - Workspace ownership check via
team_members(RLS-safe · righe 109-125). - Recurring + optional setup fee line items (righe 148-153).
success_url: ${appBaseUrl}/billing?session_id={CHECKOUT_SESSION_ID}&status=success.- TRIAL OFF di default (riga 161-164 commento):
// subscription_data: { trial_period_days: 10 }. Canon dice "NO trial v1" → corretto.
- Body:
BLOCKING-F0: il founder oggi ha Stripe in test mode (cfr. memory
project_stripe_mcp_live_mode_default.md). I 9 STRIPE_PRICE_* env su Vercel sono
price_test_*. Per accettare €/CHF reali serve:
- Stripe Dashboard > Activate account (founder info + bank IBAN CH/IT).
- Re-seed 9 price live mode con
scripts/seed-stripe-prices.ts+sk_live_*. - Update Vercel env
STRIPE_PRICE_{STARTER,PRO,BUSINESS}_{MONTHLY,ANNUAL}+ 3 setup fees. - Update
STRIPE_SECRET_KEYdask_test_*ask_live_*(Production scope). - Update
STRIPE_WEBHOOK_SECRET(Stripe live mode dashboard webhook).
Step 10 · Stripe webhook → subscriptions table + tier_caps
File: api\stripe\webhook.ts (440 righe · audit completo)
Stato: ✅ code-complete
- Idempotency table
webhook_events(stripe_event_idPK, righe 103-128). - Signature verification obbligatoria (righe 88-101) — return 400 se manca/invalida.
- 9 event handlers:
checkout.session.completed(righe 203-247) — updateworkspaces.stripe_customer_id+ setsubscriptions.setup_fee_paid=true+ welcome email Brevo.customer.subscription.{created,updated}(upsertSubscriptionrighe 249-300).customer.subscription.deleted(onSubscriptionDeletedrighe 302-331) — status=canceled+ cancellation email.customer.subscription.trial_will_end(righe 333-353) — pre-renewal email.invoice.payment_succeeded(righe 355-391) —status=active+ invoice receipt email.invoice.payment_failed(righe 393-423) —status=past_due+ dunning email.customer.{created,updated}(righe 425-439).
- DLQ implicito via
webhook_events.errortext (riga 142-146 update on catch).
GAP critici:
- Tier caps NON enforced dal webhook checkout.session.completed (checklist riga
77 dice F4 done "schema applicato" ma il webhook non scrive in
usage_countersné triggeracheck_tier_cap). Il tier viene salvato insubscriptions.plan_tier, ma l'enforcement runtime dipende dall'app stessa chiamarecheck_tier_cap(). - Email Brevo gracefully skip se BREVO_API_KEY missing (
api\_lib\brevo.ts:43-45). Significa che oggi (key non in Vercel) il cliente paga MA non riceve welcome email → percezione "checkout silenzioso" → support ticket.
3 · Pre-launch BLOCKING vs NICE-TO-HAVE
3.1 · BLOCKING (deve essere fixato per accettare 1° pagamento)
| ID | Item | File / Risorsa | Stima | Owner |
|---|---|---|---|---|
| B1 | Brevo domain verify TXT su DNS multiverbe.com | DNS provider (Register.it/Cloudflare) + Brevo Dashboard | 10m | Founder |
| B2 | DNS wildcard *.sites.multiverbe.com |
DNS provider + Vercel project multiverbe-sites (canon: *.multiverbe.app) |
20m | Founder |
| B3 | Stripe live mode + 9 price IDs | Stripe Dashboard + scripts/seed-stripe-prices.ts + Vercel env |
1h | Founder |
| B4 | Stripe webhook live endpoint registrato | Stripe Dashboard > Webhooks > Add app.multiverbe.app/api/stripe/webhook + 9 event subscribe + reveal STRIPE_WEBHOOK_SECRET → Vercel env |
15m | Founder |
| B5 | Supabase Auth SMTP custom Brevo | Supabase Dashboard > Auth > Email > SMTP | 10m | Founder |
| B6 | Replicate API key in Vercel (Site Builder) | Founder signup + REPLICATE_API_TOKEN Vercel env |
15m | Founder |
Nota: tutti BLOCKING sono founder actions, zero codice da scrivere. Il code path è già completo. Eccezione: B4 richiede 1 redeploy post-env update.
3.2 · NICE-TO-HAVE (non bloccano il primo pagamento)
| ID | Item | Note | Stima |
|---|---|---|---|
| N1 | Settore immobiliari seed in DB |
top-7 pre-MVP · AI fallback chat copre gap | 30m |
| N2 | VITE_ONBOARDING_V2=true Vercel env |
Senza, default è legacy SetupWizard (uno solo wizard step) |
5m |
| N3 | OAuth Google + Apple provider in Supabase Auth | Passwordless email funziona da solo | 1h |
| N4 | D6 mobile responsive pixel-level audit | Checklist scheduled w4 | 4-6h |
| N5 | Empty state copy su pianeti vuoti (KPI/CRM/Sales) primo accesso | Polish UX | 2h |
| N6 | Push notification PWA service worker (notify ristoratore booking) | Email fallback ok per MVP | 4h |
| N7 | Tier caps enforcement runtime (chiamare check_tier_cap da app) |
Limit AI gen / cold email / contacts | 6h |
| N8 | Klaro cookie banner verify su app subdomain | Già wired sites-runtime · verify app.multiverbe.app | 30m |
| N9 | Sentry alert rules per webhook_events.error IS NOT NULL |
Cfr. §7 monitoring | 1h |
4 · 7-day execution plan (Mar 19 Mag → Lun 25 Mag 2026)
Convenzione: F = founder action · C = Claude code/audit · J = joint (founder+Claude in stessa sessione · smoke test, monitoring).
Giorno 1 · Martedì 19 Mag (focus DNS + Brevo)
| Time | Owner | Task | Output verificabile |
|---|---|---|---|
| 09:00 | F | DNS Brevo verify TXT (DKIM + SPF + verification) su multiverbe.com |
Brevo Dashboard > Senders > Domains: status verde |
| 09:30 | F | DNS wildcard CNAME *.sites.multiverbe.com → vercel-dns.com |
dig *.sites.multiverbe.com answer entry |
| 10:00 | F | Supabase Dashboard > Auth > Email > SMTP custom (Brevo) | Test "Send confirmation email" da Supabase |
| 11:00 | C | Audit Brevo templates HTML vs wrapMultiverbeEmail() consistency |
Diff report inline (no commit) |
| 14:00 | F | Stripe Dashboard > Activate account (founder info + IBAN) | Account status: active |
| 15:00 | J | Test signup founder-non-allowlist mail (Mailosaur o personale) | Confirmation email Brevo arriva entro 5 sec |
| 17:00 | C | Update Multiverbe-Business/ops/first-paying-customer-checklist.md A3+B2 done |
Progress 78% → 86% |
Goal fine-giornata: confirmation email Brevo funziona + DNS sites-runtime up.
Giorno 2 · Mercoledì 20 Mag (focus Stripe live mode)
| Time | Owner | Task | Output verificabile |
|---|---|---|---|
| 09:00 | F | Stripe live mode webhook endpoint + reveal STRIPE_WEBHOOK_SECRET |
Vercel env updated · redeploy ok |
| 09:30 | C | Re-seed 9 prices live via scripts/seed-stripe-prices.ts (sk_live_*) |
9 price_live_* IDs |
| 10:30 | F | Update 9 Vercel env STRIPE_PRICE_* + STRIPE_SECRET_KEY=sk_live_* |
Vercel env diff |
| 11:00 | F | Redeploy production | Deploy ok |
| 14:00 | J | E2E smoke test: signup foo@example.com → onboard → checkout Starter monthly carta 4242 4242 4242 4242 |
subscriptions row insert + welcome email arriva |
| 16:00 | C | Verify webhook_events table: 4 eventi (checkout + customer + sub.created + invoice.paid) tutti processed_at NOT NULL |
DB query screenshot |
| 17:00 | C | Update checklist F0 (stripe live) + F1-F5 verified | Progress 86% → 92% |
Goal fine-giornata: 1 pagamento di test reale (carta Stripe real money 1 CHF, refund subito). Welcome email + invoice receipt arrivano.
Giorno 3 · Giovedì 21 Mag (focus polish onboarding + Replicate)
| Time | Owner | Task | Output verificabile |
|---|---|---|---|
| 09:00 | F | Replicate signup + $20 credit + API token su Vercel REPLICATE_API_TOKEN |
Vercel env |
| 09:30 | F | Vercel env VITE_ONBOARDING_V2=true + redeploy |
Deploy ok |
| 10:00 | J | Site Builder smoke test: ristorante demo cliente → 6-stage pipeline → publish | Sito nomeristorante.sites.multiverbe.com live |
| 12:00 | C | Seed settore immobiliari in DB (migration inline read-only audit + propose) |
Migration draft (NO apply, founder sign-off) |
| 14:00 | C | Audit kpi_defaults per pianeti vuoti — empty state copywriting |
Diff proposal (no commit) |
| 16:00 | F | Founder approva migration immobiliari + Claude applica via MCP | Settore visibile in onboarding wizard |
| 17:00 | C | Stress test webhook idempotency (replay 1 evento Stripe da Dashboard) | Log "already processed, skipping" |
Goal fine-giornata: pipeline Site Builder funzionante E2E con Replicate + 22 settori in onboarding.
Giorno 4 · Venerdì 22 Mag (focus mobile audit + UAT pre-friend)
| Time | Owner | Task | Output verificabile |
|---|---|---|---|
| 09:00 | C | D6 mobile responsive pixel-level audit · iPhone 15 + Pixel 8 Chrome DevTools | Audit report coverage/d6-mobile-audit-2026-05-22.md |
| 11:00 | C | Fix critical mobile bugs (tap target 44px · safe area · canvas fullbleed) | PR draft no merge |
| 14:00 | F | UAT con 1 amico ristoratore Lugano (founder accompagna in persona) | UAT note + 5 bug minori identificati |
| 16:00 | C | Triage UAT bug → fix immediate vs post-launch | Priority list |
| 17:00 | J | Daily standup status: progress %, blockers, decisione "open pubblico domenica?" | Decision log entry |
Goal fine-giornata: 1 utente reale ha completato signup→checkout→site publish→booking widget visible.
Giorno 5 · Sabato 23 Mag (buffer + content + waitlist)
| Time | Owner | Task | Output verificabile |
|---|---|---|---|
| 10:00 | F | Loris cold outreach 30 min — pre-launch teaser "domani apriamo" | 30 touch |
| 11:00 | C | Final UI polish (loading states, error messages, toast copy) | Diff inline |
| 14:00 | C | Sentry config (DSN già setup) — alert rules: | 3 alert rules attive |
- webhook_events.error IS NOT NULL (Slack) |
|||
- auth.users insert rate >10/min (anomaly) |
|||
- API /api/stripe/* 5xx rate >1% |
|||
| 16:00 | F | Cookie banner (Klaro) verify su app.multiverbe.app |
Klaro corner pill visible · accept/reject ok |
Giorno 6 · Domenica 24 Mag (final smoke + lockdown lift go/no-go decision)
| Time | Owner | Task | Output verificabile |
|---|---|---|---|
| 09:00 | J | Full E2E rehearsal: signup nuovo account (gmail) → onboarding 4-step → site builder publish → booking widget embed → Stripe checkout Starter annual 4242 → portal cancellation |
Tutti i passi ok in <30 min |
| 11:00 | J | Decision meeting: GO / NO-GO lockdown lift | Decision log + ticket |
| 14:00 | F | (if GO) Vercel env updates + Supabase Dashboard toggle (vedi §5 checklist) | Lockdown lift checklist done |
| 16:00 | J | Lockdown LIFT in produzione · smoke test 1° utente esterno | Status: "LIVE" |
Giorno 7 · Lunedì 25 Mag (post-lift monitoring + Loris activation)
| Time | Owner | Task | Output verificabile |
|---|---|---|---|
| 09:00 | J | /security-weekly check |
Audit log clean |
| 10:00 | F | Loris activation: campaign "Multiverbe è aperto" 60 touch · LinkedIn + DM IG | 60 touch first 24h |
| 11:00 | C | Monitor Sentry + Vercel runtime logs · cluster errors top 10 | Triage report |
| 14:00 | C | First paying customer playbook: founder-led onboarding call template | Multiverbe-Business/ops/first-cust-onboard-call.md |
| 17:00 | J | Daily retrospective: cosa funziona, cosa rompiamo, priority W22 (25-31 Mag) | Decisions log |
Goal fine-settimana 25 Mag: lockdown lifted da 24 ore, prime 3-5 signup pubblici tracked, almeno 1 customer in trial (no carta) o paying confermato.
5 · Lockdown lift checklist (ordered per dependency)
Prerequisiti (devono essere TUTTI ✅ prima del lift):
- [ ] B1 Brevo domain verify done
- [ ] B2 DNS wildcard sites-runtime done
- [ ] B3 Stripe live + 9 prices live mode + env updated + redeploy ok
- [ ] B4 Stripe webhook live endpoint + secret in Vercel
- [ ] B5 Supabase Auth SMTP custom Brevo
- [ ] B6 Replicate token in Vercel
- [ ] E2E smoke test pagamento real money 1 CHF ok (con refund subito)
- [ ] Founder GO decision logged in
Multiverbe-Business/execution/decisions-log.md
Click-by-click sequence (founder lift) · ~10 minuti
-
Vercel (project
multiverbe-app) > Settings > Environment Variables > Production:- Set
VITE_SIGNUP_ENABLED=true - Set
VITE_ONBOARDING_V2=true - Tenere
VITE_FOUNDER_EMAILScome admin ACL (per harness?__dev=*accessibili in prod solo founder). NON svuotare la var.
- Set
-
Supabase Dashboard (project
yqhixdqipojvgzfadufo) > Authentication > Settings:- Toggle "Allow new users to sign up" → ON
-
Supabase Dashboard > SQL Editor:
-- Remove the auto-ban trigger (founder_emails table + is_founder() restano per future ACL) DROP TRIGGER IF EXISTS auto_ban_non_founder_users_trigger ON auth.users; -- Optional: unban any test users created during lockdown UPDATE auth.users SET banned_until = NULL WHERE banned_until = 'infinity'::timestamptz; -
Vercel > Deployments > Redeploy production (no cache) → ~2 min build.
-
Code edit + commit (Claude task, founder approve):
frontend\multiverbe-app\src\App.tsx:343-345— rimuovere bloccoif (!isFounderEmail(email)) return <FounderGate email={email}/>+ import cleanup.frontend\multiverbe-app\src\components\auth\LoginPage.tsx:378-390— ripristinare link "Primo accesso? → /?auth=signup" come da commento "Quando lanciamo".
-
Smoke test post-lift (5 min):
- Open incognito →
app.multiverbe.app→ mostra LoginPage senza "Multiverbe è in fase di build" - Click "Primo accesso?" → SignupPage con form vero (non SignupClosedPage)
- Signup email reale (Mailosaur o domain proprio) → conferma email arriva
- Login → SetupWizardV2 step 1 macro
- Complete onboarding → PlanetScene 3D · NO FounderGate
- Click Pianeta Web → SiteBuilderWizard apre
- Click Billing → PricingTable mostra 3 tier · click "Inizia" → redirect Stripe Checkout reale
- Open incognito →
6 · Risk register · top 10 prime 24h post-lift
Format: Impact (H/M/L) · Likelihood (H/M/L) · Score = I×L.
| # | Rischio | I | L | Score | Mitigation |
|---|---|---|---|---|---|
| 1 | Brevo email dropped (SPF/DKIM misconfig) → user non riceve confirmation | H | M | 6 | Smoke test post-DNS, monitorare Brevo Dashboard > Statistics > Bounce rate <2% |
| 2 | Stripe webhook signature fail in live mode (different secret) | H | M | 6 | Verify STRIPE_WEBHOOK_SECRET matches Dashboard live mode, replay 1 evento test |
| 3 | RLS leak cross-tenant (auth.uid() not wrapped in policy) | H | L | 3 | Audit pg_policies via skill multiverbe-supabase-rls-patterns · query <50ms |
| 4 | Replicate budget burn ($20 credit) — Stage 4 senza fallback | M | M | 4 | Cap budget Replicate Dashboard a $20 hard · alert email |
| 5 | auto_ban_non_founder_users_trigger rimosso ma founder_emails tab visibile via RPC is_founder() → enumeration |
L | L | 1 | REVOKE EXECUTE già fatto in migration _lockdown_function_permissions |
| 6 | Bot signup spam su /auth=signup (no captcha) |
M | H | 6 | Supabase Auth rate limiting native + cap users insert/IP/hour |
| 7 | DNS wildcard sites-runtime propaga in 24h ma SSL Let's Encrypt fail | H | L | 3 | Vercel handle auto-retry · monitor vercel inspect <domain> |
| 8 | Sentry off → errori invisibili primo customer | M | M | 4 | Daily check Sentry 9:00 (founder) + alert Slack su 5xx >1% |
| 9 | Settore "immobiliari" mancante → cliente Lugano agente real estate quita onboarding | M | M | 4 | AI fallback chat copre · seed immobiliari Giorno 3 |
| 10 | Workspace creazione fallisce silenziosamente (trigger handle_new_user race con RLS) |
H | L | 3 | Già hardened in migration _team_members_rls_fix_2026_05_13a · monitor logs |
7 · Linea critica giornaliera (calendario cron 7 gg)
Daily 9:00 (10 min) · Founder check-in
- Vercel > Deployments > status (last 24h)
- Vercel > Runtime Logs > grep "ERROR" last 24h
- Supabase > Logs Explorer > severity=error last 24h
- Sentry > Issues > unresolved sorted by Last Seen
- Stripe Dashboard > Payments > last 24h (anomaly check)
- Brevo > Statistics > Bounce rate · Spam complaint rate
Daily 18:00 (5 min) · Deploy production verifica
- Vercel > Deployments > Production: last commit deployed?
- app.multiverbe.app → manual visit, login founder, dashboard load <3 sec?
- /api/stripe/webhook OPTIONS 405 (livelock test)
Sentry alert rules raccomandati
# Critical (PagerDuty)
- name: "Stripe webhook 5xx > 1%"
filter: "transaction:/api/stripe/* AND http.status:5xx"
threshold: ">1% of events in 5min window"
- name: "Webhook events error backlog"
filter: "metric:webhook_events.error_count > 5 in 15min"
# Warning (Slack #multiverbe-alerts)
- name: "Signup rate spike"
filter: "transaction:auth.signUp count > 20/min"
reason: "bot signup attack"
- name: "Auth.users insert without team_members"
filter: "metric:orphan_users > 0"
reason: "handle_new_user trigger failed"
# Info (digest email daily)
- name: "Replicate cost burn"
filter: "metric:replicate_cost_eur > 5/day"
- name: "AI generation jobs > 100/day"
filter: "metric:ai_generation_jobs.count > 100"
Status.json bump finale (Mother orchestrator pattern)
Post lockdown lift, bump Multiverbe-Business/source/_meta/status.json:
{
"phase": "live",
"lockdown": "lifted",
"lockdown_lifted_at": "2026-05-24T16:00:00Z",
"first_paying_target": "2026-06-10",
"current_paying_customers": 0,
"trial_active": 0,
"next_review": "2026-05-25T09:00:00Z"
}
8 · Verifica cross-check vs first-paying-customer-checklist.md
Riconciliazione delle 35 task della checklist business vs questo audit tecnico:
| Cat. | Done in checklist | Verificato da questo audit | Note differenza |
|---|---|---|---|
| A | 4/5 | 4/5 (A3 blocking confermato) | Allineato |
| B | 2/5 | 2/5 (B3+B4+B5 deferred ok) | Allineato |
| C | 4/6 | 4/6 (C2+C4 blocking confermato) | Allineato |
| D | 5/6 | 5/6 (D6 mobile audit w4) | Allineato |
| E | 4/4 | 4/4 | Allineato (E3 push PWA = nice-to-have) |
| F | 5/5 | 4/5 (manca F0 live mode!) | DRIFT: checklist non considera F0 test→live switch |
| G | 4/4 | 4/4 | Allineato |
| TOT | 28/35 = 80% | 27/35 = 77% | F0 live mode aggiunto come blocking nuovo (vedi B3-B4) |
Raccomandazione: aggiungere riga F0 "Stripe live mode + 9 prices live" alla checklist business. Oggi è implicita ("Stripe Checkout funzionante" F1 done) ma il founder potrebbe non realizzare che
sk_test_*non accetta carte reali.
9 · Closing notes
- Il codice è 78% production-ready. Le 6 BLOCKING sono al 100% founder action (DNS · Dashboard toggle · API keys signup · Stripe activate). Zero codice da scrivere per togliere il lockdown.
- Il design system (Osservatorio v1.1 · PR #46-#49) + auth-v2-awwwards (PR #50) + sphere-logo
3D (PR #51) sono già "bar incredibile" per il primo customer (cfr. memory
project_stream_c_v2_orbi_logos.md+feedback_design_streams_mother_pattern.md). - Il founder può lift il lockdown Domenica 24 Mag, prendendo 17 giorni di margin prima del hard gate 10 Giu (vs scenario "lift il 9 Giu" che lascerebbe 1 giorno per qualunque drift).
- Il rate "+11.5%/giorno medio ultimi 5 giorni" (checklist riga 117) è già 15× sopra il pace richiesto (+0.77%/giorno). Margin di sicurezza enorme — può essere usato per Loris cold outreach W21-W23 con app già LIVE = conversion rate atteso ↑↑↑.
Owner audit: Claude (session P-launch-readiness · D:\Desktop\Multiverbe)
Founder review: Gregorio · richiesta entro 18 Mag sera
Next refresh: Mercoledì 20 Mag post Giorno 2 (Stripe live mode test)
Skill chain usata: multiverbe-stripe-checkout-edges · multiverbe-supabase-rls-patterns · multiverbe-security-ch · multiverbe-ch-compliance