Un tutorial pratico: costruisci una directory di aeroporti internazionalizzata su Profound CMS — un'unica route parametrica che renderizza una pagina per ogni aeroporto, in 35 lingue.
Crea una vera directory di aeroporti internazionalizzata su Profound CMS: un solo pattern di URL che renderizza una pagina per ogni aeroporto, in 35 lingue. Tu scrivi il codice Next.js e costruisci a mano la struttura del CMS; Claude Code (tramite il Profound MCP) si occupa di tre attività — generare i dati degli aeroporti, collegare un design system e generare i quattro componenti React. Tre parti: Setup, Build, Production.
Guarda il video tutorial completo.
/{language}/{airport_code}.cms-renderer.curl -fsSL https://bun.sh/install | bashgh) con accesso effettuato e un account Vercel collegato a GitHub.language) sono preinstallati.cms-renderer con una chiave API di livello lettura.Stato finale: ~50 aeroporti nel CMS, l'app collegata per leggerli e il design system configurato.
Registrati su Profound (autenticazione WorkOS) e crea un sito chiamato airports. Copia due elementi: l'ID del sito web (la UUID nell'URL dell'admin) e una chiave API di livello lettura da Deployments → Create API key. L'app esegue solo lettura, quindi è sufficiente una chiave di read.
bunx create-profound-next airports
cd airports
Aggiungi le tue credenziali a .env.local:
PROFOUND_API_KEY=<your read key>
NEXT_PUBLIC_PROFOUND_WEBSITE_ID=<your website id>
NEXT_PUBLIC_CMS_API_URL=https://cms.dev.tryprofound.com
NEXT_PUBLIC_BUNNY_CDN_URL=https://cms-profound.b-cdn.net
Esegui bun dev e apri localhost:3000 per verificare la connessione.
airportNell'admin vai su Components → Create new component e chiamalo airport. Aggiungi sei campi: code, name, city, country (Text) e latitude, longitude (Number). Imposta code come campo Route Slug e imposta lo stato su Active. Lascia tutti i campi facoltativi; non aggiungere tag UI Element.
Il componente airport — sei campi, con code impostato come Route Slug.
bun run generate-schemas
Questo comando scrive airportSchema (Zod) e Airport (type) in generated/cms-schemas.ts e conferma che le credenziali funzionano.
Collega l'MCP e autentica:
claude mcp add --transport http Profound http://107.21.107.99:8081/mcp
Il server autentica tramite OAuth (WorkOS). In Claude Code, esegui /mcp, scegli Profound e completa l'accesso nel browser — Claude Code ti chiede automaticamente la prima volta che viene chiamato uno strumento Profound. Quando /mcp mostra Profound come connected, chiedi a Claude:
Genera cinquanta aeroporti reali — codici IATA corretti, nomi, città, paesi e coordinate. Salvali come JSON in una cartella
data, validali rispetto al nostro componente airport, quindi crea ciascuno come documento pubblicato tramite il Profound MCP, in parallelo.
Apri airport → Variants per confermare ~50 aeroporti pubblicati. L'app legge con la chiave API; l'MCP scrive con la propria sessione WorkOS.
Circa 50 aeroporti, inseriti come Varianti pubblicate.
Lo scaffold viene fornito senza stile. Inserisci un file DESIGN.md (un blocco @theme di Tailwind v4 più i token) nella root del progetto — puoi crearne uno tuo oppure scaricarne uno da refero.design. Quindi chiedi a Claude:
Leggi DESIGN.md. Configura Tailwind v4 e integra il tema e i font. Usa
next/fontper i font, non un import runtime da Google. Solo styling — niente pagine o componenti per ora.
Verifica che src/app/globals.css contenga @import "tailwindcss"; più il blocco @theme, e che localhost:3000 mostri i token.
Costruisci il livello di render: gli elementi UI, i componenti React, la route, i binding CEL e la traduzione.
Nell'admin, fai Create new component quattro volte (senza Route Slug). Per ciascuno, aggiungi i campi come Text salvo indicazione diversa, imposta lo stato su Active e aggiungi il tag UI Element in Settings → Tags:
nav → brandheadline → title, subtitlebody → code, city, country, latitude (Number), longitude (Number)footer → textbody.latitude e body.longitude devono essere Number per corrispondere al componente airport.
Ogni elemento UI è un componente a sé — qui body, attivo con il tag UI Element.
Tutti e quattro gli elementi UI accanto al componente airport personalizzato.
bun run generate-schemas
Chiedi a Claude:
Crea quattro componenti React — nav, headline, body, footer — in
components/. Ognuno accetta una singola propcontenttipizzata comeBlockComponentProps<T>dacms-renderer/lib/types, doveTè il tipo generato dell'elemento, e legge i campi dacontent. Registra tutti e quattro nel registro della route catch-all con il nome del componente. Stile secondo il nostro design system, ma come componenti originali — niente copia del layout del sito sorgente. Nav: brand a sinistra. Headline: nome dell'aeroporto con un sottotitolocode · city, country. Body: pannello dettagli con codice, città, paese e coordinate. Footer: una riga statica. Solo layout e stile.
Claude crea i quattro componenti e popola il registro in src/app/[...slug]/page.tsx:
const registry = { nav: Nav, headline: Headline, body: Body, footer: Footer };
Due regole: ogni componente legge i campi da content (non come prop separate) e le chiavi del registro devono corrispondere esattamente ai nomi dei componenti nel CMS — un disallineamento produce un render vuoto.
Nell'admin vai su Pages → Create page e imposta il pattern /{airport_code}. In Dynamic Segment Mappings, collega airport_code → componente airport, campo slug code. Salva — arriverai al Page Builder. Verifica che /JFK si risolva.
Aggiunta di un elemento UI alla pagina dalla scheda Custom.
I quattro UI Element aggiunti al binding di JFK nel Page Builder.
Seleziona il binding JFK → Add UI Element → scheda Custom → aggiungi nav, headline, body, footer in quest'ordine. Profound propaga il set a ogni binding aeroportuale.
Compila ciascun campo. Valori statici (nav brand, testo del footer): inseriscili direttamente. Valori dinamici: passa alla modalità dinamica e scrivi CEL. La funzione di lookup condivisa è documents.get("airport", meta.params.airport_code).
| Campo | Valore CEL |
|---|---|
headline.title | documents.get("airport", meta.params.airport_code).name |
headline.subtitle | documents.get("airport", meta.params.airport_code).code + " · " + documents.get("airport", meta.params.airport_code).city + ", " + documents.get("airport", meta.params.airport_code).country |
body.code / body.city / body.country | documents.get("airport", meta.params.airport_code).<field> |
body.latitude / body.longitude | documents.get("airport", meta.params.airport_code).latitude (e .longitude) |
nav.brand, footer.text | stringhe statiche |
Pubblica la pagina (in alto a destra).
Apri localhost:3000/JFK, poi /SFO, /LAX — stesso template, aeroporto diverso.
La pagina finale che mostra i dati di JFK, in inglese.
Traduci prima i componenti. Nell'admin, apri ciascun componente (qualsiasi componente — non dev'essere un elemento UI) e fai clic su Translate → Submit. Profound traduce il contenuto in tutte e 35 le lingue in un colpo solo, inclusi i valori statici dei campi. Fallo prima di modificare la route o toccare il CEL.
Translate → Submit invia un componente a tutte e 35 le lingue contemporaneamente.
Aggiungi la dimensione lingua. In Pages, modifica il pattern in /{language}/{airport_code}. Aggiungi un Dynamic Segment Mapping per language → componente di sistema language, campo slug code. Salva e verifica che /en/JFK si risolva.
Aggiunta del segmento {language} alla route.
Collega ogni campo traducibile al fetch tradotto. Internazionalizzare la pagina significa sostituire ogni campo dipendente dalla lingua — non solo l'headline — da documents.get(...) a documents.translated("airport", meta.params.airport_code, meta.params.language):
| Campo | CEL tradotto |
|---|---|
headline.title | documents.translated("airport", meta.params.airport_code, meta.params.language).name |
headline.subtitle | documents.get("airport", meta.params.airport_code).code + " · " + documents.translated("airport", meta.params.airport_code, meta.params.language).city + ", " + documents.translated("airport", meta.params.airport_code, meta.params.language).country |
body.city / body.country | documents.translated("airport", meta.params.airport_code, meta.params.language).city (e .country) |
Lascia il codice IATA code e le coordinate su documents.get — sono identici in ogni lingua. nav.brand e footer.text sono già coperti dalla traduzione del componente al punto 1.
Quando tutte e tre le operazioni sono completate, /fr/SFO, /de/SFO, ecc. si risolvono interamente tradotte.
Esegui il push su GitHub:
git init
git add -A
git commit -m "Airport directory"
gh repo create airports --public --source=. --push
Importa su Vercel: Add New → Project → importa il repository airports. Aggiungi le variabili d'ambiente — PROFOUND_API_KEY, NEXT_PUBLIC_PROFOUND_WEBSITE_ID, NEXT_PUBLIC_CMS_API_URL e facoltativamente NEXT_PUBLIC_BUNNY_CDN_URL — quindi fai Deploy. Visita /en/JFK e /fr/SFO. Ogni futuro git push genera un nuovo deploy.
Entrambi inclusi nello scaffold.
<Refresher> in layout.tsx aggiorna la pagina che stai visualizzando quando modifichi e salvi nell'admin — senza redeploy.?edit_mode=true a qualsiasi URL (es. …/en/JFK?edit_mode=true) per le sovrapposizioni di editing. I visitatori pubblici vedono comunque la pagina pulita.?edit_mode=true mostra l'editor sulla pagina live.
Cinquanta aeroporti, 35 lingue, live — descritti una sola volta e alimentati dai dati: una route, quattro componenti React e una manciata di binding CEL. Il CMS conserva il contenuto, il tuo codice lo renderizza e il CEL li collega.