Pianeta Web · le 5 migliorative (handoff)

Raccolta delle migliorie "best-practice / tech più moderna" emerse chiudendo il design-pass del Pianeta Web. NON sono blocker del gate: sono qualità e debito sano. Sotto, prima un breve contesto, poi il PROMPT pronto da incollare in una sessione fresca.

Le 5 migliorative in breve

  1. Booking i18n — l'ultima stringa hardcoded IT ("Prenotazioni online in arrivo") + audit dell'intera famiglia Booking.
  2. Smooth-scroll sugli anchor (Lenis sugli hash) + cleanup dipendenze morte in sites-runtime.
  3. Consolidare la i18n del runtime in un meccanismo unico, tipizzato e moderno (oggi è sparsa in switch per-componente).
  4. Logo SVG ufficiale + watermark background-adaptive (oggi raster: su tenant scuro la sfera nera sparisce). Founder-gated (identità di marca).

PROMPT (incolla in una sessione fresca)

Sei un senior staff full-stack + design engineer (livello big-tech) che alza la qualità del Pianeta Web di MULTIVERBE. MULTIVERBE è il SaaS che dà a una PMI (CH/UE) tutta la presenza digitale (sito, prenotazioni, contenuti, CRM, vendite) coordinata da un'AI centrale. Il "BOS"/bos.multiverbe.com è lo strumento interno, NON il prodotto.

Standard di lavoro (Engineering Charter — memory operating_charter, non negoziabile)

Un task è "fatto" SOLO se: verificato dal vivo con metodo esplicito · piccolo e coeso (no refactor misti a feature) · zero hardcoded customer-facing (ogni stringa vale per QUALSIASI tenant; tutto via token --tenant-*) · sicuro multi-tenant (filtra workspace_id in query/cache/storage + RLS, valida ownership al data-layer) · advisor Supabase 0 errori · niente regressioni · fix alla radice (mai declassare warning) · merge SOLO a CI verde (squash + --admin è il pattern del repo). UI/copy in italiano; eccezione: il wordmark del watermark è inglese ("Powered by Multiverbe"), monolingua per tutti i tenant. Pseudonimizza PII prima di Anthropic. Mai DeepSeek/OpenRouter. 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, pricing/canon, sicurezza, hard-to-revert, e per scelte di identità di marca (logo). Cost-mode CI/infra: verifica in LOCALE prima di pushare (la PR nasce verde), batcha i commit, 1 PR per unità coerente, non ri-triggerare la CI a vuoto; i gate non si toccano. Per ogni scelta di stack/libreria valida sul web l'ultimo livello 2026 (versioni, best practice, deprecazioni) — non fidarti solo del training. Chiudi la sessione con un blocco 🔴 DA FARE in 3 categorie a tabella (🔄 Continuative · ⚡ Migliorative · 🗓️ Sessioni future) e persisti il pending in memoria/BOS (memory feedback_persist_pending_on_session_close).

Verità architetturale (tienila)

Non esiste codice per-sito. UNA runtime condivisa (sites-runtime, Next.js 16 + React 19, Vercel project multiverbe-sites) serve tutti i *.multiverbe.app via routing per subdomain (sites-runtime/proxy.ts) + ISR. Il sito = DATI in Supabase (sites/site_subdomains/site_pages/site_blocks/site_block_translations/site_assets/site_constitutions). Modificare i dati = UPDATE righe + /api/revalidate (REVALIDATE_SECRET) → live, no deploy. Progetto Supabase yqhixdqipojvgzfadufo (eu-central-1). Unico sito pubblicato = trattoria-bellinzona-demo (tier business, tema CHIARO: bg #FAF5EC, testo #241C17; locale it/de/fr/en presenti). Le route [subdomain]/... sono dinamiche (ƒ), con data-cache via unstable_cache + revalidate.

Base già fatta e verificata live (NON rifarla)

  • #307 — watermark "Powered by Multiverbe": logo brand + wordmark EN monolingua + micro-press stile Apple (active:scale(.96), reduced-motion safe) + UTM, gating per-tier (Starter/Pro lo mostrano, Business no). Asset = sites-runtime/public/brand/multiverbe-mark.png (raster 128px right-sized dalla sfera-occhio).
  • #311 — la CTA sticky mobile dell'hero si ritrae quando il footer entra in vista.
  • #321 — footer/cookie/legali page-locale-aware (il middleware inoltra x-multiverbe-locale come request headerapp/[subdomain]/layout.tsx lo legge via headers(), narrowing a SiteLocale) + cornice sezioni localizzata via sites-runtime/lib/sections/i18n.ts (it/de/fr/en) con locale threadato da SectionRenderer (components/sections/index.tsx) a Events + Menu (3 varianti + primitive). Verificato SSR su prod: /deCookie-Einstellungen/Sitzplätze/Allergene:, zero IT residuo.

Missione: le 5 migliorative, in quest'ordine

⚡ M1 — Chiudi la i18n: "Prenotazioni online in arrivo" + audit Booking (quick win, mecc.)

Unica stringa di cornice ancora hardcoded IT: sites-runtime/components/sections/Booking/_BookingForm.tsx (~riga 169, fallback CTA quando il booking online è disattivo). La famiglia Booking NON riceve ancora locale: in components/sections/index.tsx il case 'booking' rende <Booking content=... /> senza locale. Cosa fare: passa locale da SectionRenderer → Booking/index.tsx (dispatcher) → varianti (InlineForm/SlideOver/StickyMobile) → _BookingForm.tsx; aggiungi la chiave a lib/sections/i18n.ts (4 lingue). Prima, fai un audit completo: grep su components/sections/** per ogni stringa IT hardcoded rimasta (Contact, SocialProof, About, ServicesPricing, Faq, Gallery, Booking — label fisse, aria-label, empty-state) e localizzale tutte nello stesso giro. Done: zero stringhe IT hardcoded nelle sezioni; verifica SSR su /de del demo.

⚡ M2 — Smooth-scroll anchor (Lenis) + cleanup dipendenze morte

(a) I CTA puntano a #prenota/#menu ma lo scroll è il jump nativo: Lenis (sites-runtime/components/effects/SmoothScroll.tsx) non è agganciato agli hash. Aggancia i click su link a[href^="#"] allo scroll smooth di Lenis (rispetta prefers-reduced-motion → niente smooth; mantieni il fallback no-JS; aggiorna l'hash + focus del target per a11y). (b) sites-runtime/package.json dichiara @react-three/fiber, @react-three/drei, three ora inutilizzati (l'hero WebGL è stato rimosso). Prima npx depcheck (verifica anche gsap/mapbox-gl/framer-motion/lenis reali usi: es. il Contact usa una mappa?); rimuovi solo ciò che è davvero morto. ⚠️ NON editare pnpm-lock.yaml a mano: usa pnpm remove e rigenera il lock dove pnpm funziona (la junction node_modules nei worktree è solo per build/typecheck, non per mutare il lock). Done: smooth-scroll verificato (con e senza reduced-motion), next build verde, lockfile coerente, bundle più snello.

⚡ M3 — Consolida la i18n del runtime (architetturale · plan-first)

Oggi la i18n del runtime è sparsa: lib/sections/i18n.ts (nuova), lo switch cookieLabel in components/layout/SiteFooter.tsx, le stringhe in components/Compliance/CookieBanner.tsx, le locale in proxy.ts, e (citato in memoria) booking/_lib/i18n.ts lato app. Obiettivo: un meccanismo unico, tipizzato, moderno. Valida sul web (2026) next-intl per App Router vs un piccolo dizionario tipizzato in-house. ⚠️ Vincolo: il runtime ha già il proprio routing locale (subdomain + [locale] + x-multiverbe-locale) → se usi next-intl, usane il core (getTranslations/useTranslations) senza il suo middleware di routing (evita conflitti con proxy.ts). Confine corretto: le label di cornice/UI stanno nel codice (i18n tipizzata); il contenuto del tenant resta data-driven in site_block_translations (già così — non spostarlo nel codice né viceversa). Plan-first: presenta la scelta (libreria vs in-house) con trade-off + raccomandazione, poi consolida le isole sopra in lib/i18n/ con chiavi tipizzate. M1 può confluire qui. Done: una sola fonte di verità i18n per il runtime, tipizzata, tsc verde, render SSR identico nelle 4 lingue.

🎨 M4 — Logo SVG ufficiale + watermark background-adaptive (FOUNDER-GATED)

Il watermark usa un raster (sfera nera + occhio ciano): su un tenant a tema scuro la sfera si fonde con lo sfondo. Il canon (canon/12-design-system-orbi-logos.md §"Logo di Multiverbe") conferma che non esiste un SVG pulito; colori canon #0EA5E9 base · #22D3EE luci ciano · #4ADE80 verde acceso; servono master SVG + 3 varianti (completo/monogramma/ritaglio) + light/dark + export. Task aperto: execution/logo-ufficiale-task-2026-06-06.md. ⚠️ Il logo è identità di marca = territorio founder (come i pianeti 3D, memory feedback_do_not_touch_3d_planets): non ridisegnare unilateralmente. Cosa fare: (1) proponi 2-3 opzioni di mark monocromo inline SVG currentColor (riproduzione fedele della sfera-occhio esistente, NON un redesign) che legga su QUALSIASI sfondo — riferimento di partenza l'SVG in frontend/multiverbe-app/src/components/auth/SolarSystemPattern.tsx; (2) ottieni l'OK del founder sul mark; (3) wiralo in sites-runtime/components/layout/SiteFooter.tsx (inline SVG che eredita currentColor al posto dell'<img> raster), mantenendo press Apple + gating + UTM + il raster come fallback. Verifica leggibilità su CHIARO e SCURO: il demo è chiaro → per il test scuro, flippa temporaneamente i design_tokens del demo a un set scuro in DB (poi ripristina) oppure monta il footer in una pagina di prova locale con sfondo scuro. Done: il watermark resta nitido e leggibile su un tenant chiaro E uno scuro, verificato a vivo; founder ha approvato il mark.

Metodo di verifica LOCALE (sites-runtime) — memory reference_live_verify_behind_auth_chrome_mcp §sites-runtime

I siti sono pubblici → verificabili in locale a quality-bar. Setup: pnpm è rotto nei worktree → crea una junction sites-runtime/node_modules verso il checkout main (cmd /c mklink /J) + copia next-env.d.ts; così girano tsc --noEmit, node scripts/check-cwv-budget.mjs, next build. Per renderizzare un tenant: il proxy supporta *.localtest.mehttp://<slug>.localtest.me:3001/ legge i dati reali di prod (build con la anon key VERA via Supabase MCP get_publishable_keys, è inlinata a build-time). L'idratazione NON parte in next dev sotto localtest.me → usa build di produzione + next start; ma output:'standalone' impedisce al middleware di girare sotto next startcommenta temporaneamente output:'standalone' in next.config.mjs, builda, testa, RIPRISTINA (verifica git diff). Verifica gli stati: SSR via curl + grep (le stringhe i18n sono SSR → ground truth: es. /de deve contenere Cookie-Einstellungen, / Preferenze cookie) oppure Playwright per l'interattività; misura via getComputedStyle/ARIA dopo il settle delle transizioni. Feature tier-gated (watermark): dopo il merge, flippa il tier del demo in DB su prod → poll ISR (~16-60s) → ripristina. Pulizia: rimuovi la junction con cmd /c rmdir (toglie solo il link); MAI Remove-Item *.png alla radice (lì vive Closed-Sphere-NoBackground.png tracciato).

CI / merge (cost-mode)

Sul PR (solo sites-runtime/**) girano security-audit (Semgrep + Trivy/secret/CVE) + Vercel multiverbe-sites (= npm run build: CWV prebuild + next build + typecheck) = il gate type/build. frontend-ci/planet-system-ci/e2e-smoke NON triggerano su sites-runtime. Merge: gh pr merge <n> --squash --admin a check verdi (mergeStateStatus BLOCKED = branch protection, si supera con --admin). Messaggi multi-riga: git commit -F <file> e gh pr ... --body-file <file> (l'inline PowerShell con " si rompe). Chiudi il commit con Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> e il body PR con la riga Claude Code.

Primo passo concreto

Inizia da M1 (chiusura i18n Booking + audit): è veloce, mecc., e chiude al 100% la classe "stringhe hardcoded". Apri components/sections/index.tsx (case 'booking'), components/sections/Booking/_BookingForm.tsx, lib/sections/i18n.ts; fai prima il grep di audit su tutte le sezioni. Done dell'unità = differenza verificata a vivo (SSR /de) + CI verde + PR squash-merged, senza regressioni né hardcoded. Poi M2 → M3 (plan-first) → M4 (founder-gated). Una slice coesa per PR.

Leggi prima le memory operating_charter, reference_live_verify_behind_auth_chrome_mcp, project_pianeta_web_trattoria_impeccabile_2026_06_06, project_pianeta_web_program_2026_06_06, e questo doc. Poi dichiara il piano del giorno (3 categorie) e procedi a qualità massima.