name: pianeta-web-golive-verify description: GO-LIVE del generatore Pianeta Web + verifica end-to-end + estensione section library. Cosa è fatto, cosa è verificato, l'unica azione env rimasta, e la roadmap del restante. last_update: 2026-06-05 owner: gregorio + claude status: GO-LIVE eseguito · verifica DB/RLS/REST verde · render live bloccato su 1 env var founder · P1 section library iniziata (2/5 merged) correlati: pianeta-web-moat-extension-2026-06-05.md · pianeta-web-handoff-2026-06-05.md
Pianeta Web · GO-LIVE + verifica end-to-end (2026-06-05)
0. TL;DR
Il generatore Pianeta Web è passato da "0 siti producibili" a vivo sul lato dati + codice, verificato a ogni strato (DB, RLS, REST-anon, middleware, routing, render). I siti pubblicati non renderizzano ancora live per UNA sola ragione: il deploy Vercel multiverbe-sites non ha la chiave Supabase che legge i dati. Azione founder (1 minuto): settare NEXT_PUBLIC_SUPABASE_ANON_KEY nel progetto Vercel multiverbe-sites (= anon key del progetto yqhixdqipojvgzfadufo) e ridistribuire. Dopo, ogni sito pubblicato renderizza.
1. GO-LIVE — costituzione restaurant attiva in prod
- Applicata la migration
database/migrations/2026-05-15g_seed_restaurant_constitution.sql(66 KB, UPSERT idempotente) via Supabase SQL Editor (browser). - Verifica:
site_constitutionsid=restaurant→active=true,jsonb_typeof=object,pg_column_size34 KB compressi (66 KB raw), 29 chiavi top-level,display_name='Ristorante',schema_org_type='Restaurant'. (Prima: placeholder 46 byte, active=false.) - Reversibile:
active=false(nessuna generazione parte da sola — app founder-gated).
2. Sito demo ristorante — verifica end-to-end
- Seedato un sito demo reale (
database/seeds/2026-06-05_demo_restaurant_site.sql, idempotente, teardown =DELETE FROM sites WHERE id='dddddddd-…0010'):- 1 sito (
trattoria-bellinzona-demo, published, tier business), workspaceDEMO · Trattoria Bellinzona. - 1 pagina home, 8 blocchi (tutte le 8 famiglie: hero · social-proof · about · menu · gallery · private-events · booking · contact), 32 traduzioni (8 × it/de/fr/en).
- Palette warm
--tenant-*(AA-verificata), nessuna immagine (graceful degradation by design: hero gradiente, gallery placeholder eleganti, about editoriale centrato).
- 1 sito (
- Verifica DB sotto ruolo
anon(dopo il fix RLS): 1 site / 1 subdomain / 1 page / 32 translations visibili · 0 contenuti non-published (isolamento intatto). - Verifica REST API con anon key:
GET /rest/v1/site_subdomains+/sites→ HTTP 200 + righe (esattamente il path che usa la runtime).
3. Blocco di prodotto trovato (e risolto lato DB): RLS non esponeva i siti pubblicati
Root cause (verificato in prod): le policy RLS su sites/site_subdomains/site_pages/site_blocks/site_block_translations/site_assets esponevano i dati SOLO ai membri del workspace (workspace_id IN team_members WHERE auth.uid()). Nessuna policy di lettura pubblica per status='published'. La sites-runtime serve il web pubblico come ruolo anon → ogni sito generato rispondeva 404 (fetchSiteBySubdomain → null → notFound). È il motivo per cui "la strada del wildcard non era mai stata testata": nessun sito reale era mai stato pubblicato + renderizzato.
Fix applicato (approvato dal founder, migration 2026-06-05a_sites_public_read_published.sql):
- 6 policy
SELECTpermissive per ruoloanon, solostatus='published'. Additiva (le policy membri-workspace restano), reversibile (6DROP POLICY), isolamento draft/preview intatto, usa indici esistenti. fetch-page.ts: usaNEXT_PUBLIC_SUPABASE_ANON_KEY(RLS-scoped) invece della service_role key in un'app pubblica → toglie la service-role key dal blast-radius (risolve il vecchioTODO(D5.B)). Fallback service key solo per retro-compat.- Merged in master: PR #240.
Diagnosi del 404 residuo: con RLS corretto, la REST API anon legge i dati (HTTP 200), ma il deploy multiverbe-sites continua a dare 404 con x-vercel-cache: MISS (render fresco) → la sua query torna null. Causa: la chiave Supabase nell'env del deploy non legge questo progetto come anon. .env.example documenta solo SUPABASE_SERVICE_ROLE_KEY (verosimilmente errata/placeholder nel deploy) e nessun NEXT_PUBLIC_SUPABASE_ANON_KEY.
→ AZIONE FOUNDER (unica rimasta per il render live)
Settare NEXT_PUBLIC_SUPABASE_ANON_KEY nel progetto Vercel multiverbe-sites (= anon key di yqhixdqipojvgzfadufo, è pubblica per natura) + redeploy. Dopo, ogni sito pubblicato renderizza. Tutto il resto è verificato.
4. Matrice di verifica
| Strato | Stato |
|---|---|
| Costituzione restaurant attiva | ✅ verde (prod) |
| Sito demo seedato (8 famiglie, 4 lingue, published) | ✅ verde (prod) |
| RLS public-read published (anon) | ✅ verde (applicato + testato anon) |
| Isolamento draft/preview (anon non vede non-published) | ✅ verde |
| REST API anon (path della runtime) | ✅ verde (HTTP 200 + righe) |
| Middleware host→subdomain + routing | ✅ verde (header x-multiverbe-subdomain + x-matched-path=/[subdomain]/[locale]) |
| Render code (8 renderer, content shapes, schema.org) | ✅ verde (review + Vercel build) |
| Render live end-to-end | ⏳ bloccato su env NEXT_PUBLIC_SUPABASE_ANON_KEY |
| a11y AA / mobile 390 / 4 lingue / LCP-CLS / get_advisors | ⏳ da fare sul sito live (dopo l'env) |
5. Section library sector-neutral (P1) — il vero codice del moat
Pattern del vertical-slice consolidato (10 punti di registrazione mappati): Zod schema + prompt builder + SCHEMA_REGISTRY + dispatch + AnyVariantId + SECONDARY_SECTION_TYPES (generatore) · tipo mirror + componente + case renderer (runtime) · CANONICAL_TO_FAMILY già pre-mappato.
| Tipo | Stato | PR |
|---|---|---|
services-pricing (cards / list-grouped / tiers · prezzi CHF de-CH) |
✅ MERGED | #244 |
faq (accordion <details> / two-column · alimenta schema.org FAQPage) |
🟢 PR aperta CI-verde | #248 |
testimonials |
⏳ next (pattern pronto) | — |
team |
⏳ next (con avatar-iniziali graceful) | — |
booking adattivo (tavolo / appuntamento / corso-trial) |
⏳ next (adatta booking) | — |
Ogni componente: solo token --tenant-*, a11y AA (heading order, list/dl semantics, tabular-nums), prefers-reduced-motion, graceful degradation. Modellati sui renderer P0-PR2 (SocialProof/About/Events).
6. Igiene CI — schema-drift risolto alla radice
Il check schema-drift.yml (types/supabase.ts ↔ prod schema) era ROSSO pre-esistente: mancava la colonna workspaces.subscription_tier (string) nei types committati. Allineato byte-exact (Row/Insert/Update) in PR #240 → check verde. Da ora le PR che toccano database/migrations/** passano senza --admin.
7. Roadmap del restante (pattern pronto)
- P1:
testimonials,team,booking adattivo(vertical slice, 1 PR ciascuno, pattern di #244/#248). - P2 — Costituzioni (dati, su gold-standard
restaurant.ts):hair-salon→gym→studio-professionale. Meccanismo: scriviconstitutions/<id>.ts(SectorConstitutionEnriched) →scripts/seed-<id>-constitution.tsgenera la migration → applica +active=true. Workspace demo già esistenti:DEMO · Salone Lugano,DEMO · Studio Legale Locarno. - P3 — Onboarding scoping: instradare solo ai settori con costituzione viva (stato onesto "in arrivo"), niente 404 né ristorante-forzato. Mappa i 28 settori (skill
multiverbe-sector-onboarding). - Hardening finale (post-env): giro adversariale a11y/mobile/i18n/schema.org/perf su un sito reale per settore +
get_advisors0 errori.
8. PR
- #240 MERGED — anon key + RLS public-read (
2026-06-05a) + sito demo fixture + fix schema-driftworkspaces.subscription_tier. - #244 MERGED — section library
services-pricing. - #248 MERGED — section library
faq.
Nota: tutte le verifiche sono su prod reale (query DB + REST + CI), non stime.
9. RISOLTO — il render live era DOWN per env sul PROGETTO SBAGLIATO (2026-06-05 sera)
Sintomo: ogni URL *.multiverbe.app rispondeva 404 ("This page could not be found"), anche col sito demo published e tutte le RLS public-read a posto.
Falsa pista iniziale: si pensava bastasse settare NEXT_PUBLIC_SUPABASE_ANON_KEY. Settata + redeploy → ancora 404.
Vera radice: il progetto Vercel multiverbe-sites aveva gli env NEXT_PUBLIC_SUPABASE_URL e la anon key puntati a un progetto Supabase diverso — iouqemthcpccyyfhcrno invece di yqhixdqipojvgzfadufo (quello vero, dove vivono costituzione + sito demo + dati). Configurati così il 13 maggio alla creazione del progetto. Ogni query del runtime colpiva un DB senza i dati → fetchPage ritorna null → notFound() → 404 silenzioso (nessun errore nei log: fetch-page degrada a null senza loggare). Aver settato solo la anon key di yqhix lasciando l'URL su iouqem = mismatch chiave/progetto → 401 → 404 (ecco perché il primo fix non bastava).
Metodo di diagnosi (tutto su prod, zero stima):
- Provato che dato+RLS+anon-key+query-esatta funzionano contro yqhix via REST anonima dal browser (subdomain→site→page→blocks→translations: 200 con dati).
- Tracciato il routing reale:
proxy.ts(Next 16 ha rinominatomiddleware.ts→proxy.ts) estrae bene subdomain + redirect locale;fetch-page.tsusa la anon key e filtraenabled=true+status=published+localized_paths @> {locale:path}— tutto verificato corrispondente al seed. - Rivelato nella dashboard Vercel il valore dell'URL Dev (non-sensitive):
https://iouqemthcpccyyfhcrno.supabase.co. Smoking gun.
Fix (browser, env pubblici non segreti):
NEXT_PUBLIC_SUPABASE_URL(scope Production) →https://yqhixdqipojvgzfadufo.supabase.co(input-verificato len 40 prima del save).NEXT_PUBLIC_SUPABASE_ANON_KEY(Production+Preview) → anon key di yqhix (JWT decodato:ref=yqhixdqipojvgzfadufo, role=anon, len 208).- Redeploy NO-CACHE (build cache unchecked): Next inietta i
NEXT_PUBLIC_*a BUILD time, anche nel codice server → serve un build pulito perché il nuovo valore venga ri-inlined.
Verificato LIVE su https://trattoria-bellinzona-demo.multiverbe.app/it (browser reale del founder): titolo "Trattoria Bellinzona · Cucina ticinese di territorio", cookie banner nDSG/GDPR in IT, e tutte e 8 le famiglie renderizzano con contenuto italiano umanizzato e settore-perfetto (hero "Il territorio, nel piatto" · social-proof "312 recensioni 4,8" · about "Tre generazioni" · menu Antipasti/Primi/Secondi CHF+allergeni · gallery 6 slot categorizzati · eventi sala privata SEDUTI 40 · booking "nessuna commissione" Persone 1-12+ · contatti Via Codeborgo 12 + orari settimana con "VenerdìOGGI"). Zero return null. get_advisors security = 0 errori (solo 1 INFO noto idempotency_keys). Subdomain diagnostico demo2 ripulito.
🔴 Residui env (igiene, non bloccanti per prod)
NEXT_PUBLIC_SUPABASE_URLscope Development è ancoraiouqem...→ correggere a yqhix (impatta solovercel devlocale).SUPABASE_SERVICE_ROLE_KEY(Production+Preview, May 13) è quasi certamente la service key diiouqem...→ oggi NON usata (fetch-page preferisce la anon key), ma è una mina: riallineare a yqhix o rimuovere. AncheJWT_SECRET/REVALIDATE_SECRET(May 13) da ri-verificare.- Osservazione perf: gli screenshot CDP del render andavano in timeout mentre
get_page_textrispondeva subito → probabile loop rAF costoso dell'accento R3F hero (HeroR3FAccent, solo tier Business). Da verificare la fluidità su device reale (non bloccante). - Lezione: alla creazione di un progetto Vercel verificare SEMPRE che gli env Supabase puntino al
refcorretto (yqhixdqipojvgzfadufo). Ilrefè già hardcoded come ground-truth insites-runtime/next.config.mjs(imageremotePatterns+ CSPconnect-src).