Una guía práctica: construye un directorio de aeropuertos internacionalizado en Profound CMS — una ruta paramétrica que renderiza una página para cada aeropuerto, en 35 idiomas.
Construye un directorio de aeropuertos real e internacionalizado en Profound CMS: un único patrón de URL que renderiza una página para cada aeropuerto, en 35 idiomas. Tú escribes el código de Next.js y construyes la estructura del CMS a mano; Claude Code (a través del MCP de Profound) se encarga de tres tareas: generar los datos de los aeropuertos, conectar un sistema de diseño y generar los cuatro componentes de React. Tres partes: Configuración, Construcción, Producción.
Mira el recorrido en video completo.
/{language}/{airport_code}.cms-renderer.curl -fsSL https://bun.sh/install | bashgh) con sesión iniciada y una cuenta de Vercel enlazada a GitHub.language) vienen incorporados.cms-renderer con una clave de API de solo lectura.Estado final: ~50 aeropuertos en el CMS, la app conectada para leerlos y el sistema de diseño configurado.
Regístrate en Profound (autenticación WorkOS) y crea un sitio web llamado airports. Copia dos cosas: el ID del sitio web (el UUID en la URL del administrador) y una clave de API de nivel de lectura desde Deployments → Create API key. La app solo lee, así que una clave de lectura es suficiente.
bunx create-profound-next airports
cd airports
Agrega tus credenciales 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
Ejecuta bun dev y abre localhost:3000 para confirmar que se conecta.
airportEn el administrador, ve a Components → Create new component y llámalo airport. Añade seis campos: code, name, city, country (Text) y latitude, longitude (Number). Marca code como el campo Route Slug y establece el estado en Active. Deja todos los campos como opcionales; no añadas ninguna etiqueta de UI Element.
El componente airport — seis campos, con code configurado como Route Slug.
bun run generate-schemas
Esto escribe airportSchema (Zod) y Airport (tipo) en generated/cms-schemas.ts, y confirma que tus credenciales funcionan.
Conecta el MCP y autentícate:
claude mcp add --transport http Profound http://107.21.107.99:8081/mcp
El servidor se autentica por OAuth (WorkOS). En Claude Code, ejecuta /mcp, elige Profound y completa el inicio de sesión en tu navegador — Claude Code también te lo solicitará automáticamente la primera vez que se invoque una herramienta de Profound. Una vez que /mcp muestre Profound como connected, pídele a Claude:
Genera cincuenta aeropuertos reales — códigos IATA correctos, nombres, ciudades, países y coordenadas. Guárdalos como JSON en una carpeta
data, valídalos con nuestro componente airport y luego crea cada uno como un documento publicado mediante el MCP de Profound, en paralelo.
Abre airport → Variants para confirmar ~50 aeropuertos publicados. La app lee con la clave de API; el MCP escribe con su propia sesión WorkOS.
Aproximadamente 50 aeropuertos, sembrados como variantes publicadas.
El andamiaje se entrega sin estilos. Coloca un DESIGN.md (un bloque @theme de Tailwind v4 más tokens) en la raíz del proyecto — uno propio o descárgalo de refero.design. Luego pídele a Claude:
Lee DESIGN.md. Configura Tailwind v4 e integra el tema y las fuentes. Usa
next/fontpara las fuentes, no una importación de Google en tiempo de ejecución. Solo estilos — nada de páginas ni componentes todavía.
Confirma que src/app/globals.css contenga @import "tailwindcss"; además del bloque @theme, y que localhost:3000 muestre los tokens.
Construye la capa de renderizado: los elementos de interfaz, los componentes de React, la ruta, los enlaces CEL y la traducción.
En el administrador, Create new component cuatro veces (sin Route Slug). Para cada uno, añade los campos como Text a menos que se indique, establece el estado en Active y añade la etiqueta UI Element en Settings → Tags:
nav → brandheadline → title, subtitlebody → code, city, country, latitude (Number), longitude (Number)footer → textbody.latitude y body.longitude deben ser Number para coincidir con el componente airport.
Cada elemento de interfaz es su propio componente — aquí body, configurado como Active con la etiqueta UI Element.
Los cuatro elementos de interfaz junto al componente airport.
bun run generate-schemas
Pídele a Claude:
Construye cuatro componentes de React — nav, headline, body, footer — en
components/. Cada uno recibe una sola propcontenttipada comoBlockComponentProps<T>decms-renderer/lib/types, dondeTes el tipo generado del elemento, y lee sus campos desdecontent. Registra los cuatro en el registro de la ruta catch-all por nombre de componente. Estílalos con nuestro sistema de diseño, pero como componentes propios — no copies el diseño del sitio fuente. Nav: marca a la izquierda. Headline: nombre del aeropuerto con un subtítulocode · city, country. Body: panel de detalles con código, ciudad, país y coordenadas. Footer: una línea estática. Solo maquetación y estilos.
Claude crea los cuatro componentes y completa el registro en src/app/[...slug]/page.tsx:
const registry = { nav: Nav, headline: Headline, body: Body, footer: Footer };
Dos reglas: cada componente lee sus campos desde content (no como props separadas), y las claves del registro deben coincidir exactamente con los nombres de los componentes del CMS — una discrepancia renderiza en blanco.
En el administrador, ve a Pages → Create page y establece el patrón /{airport_code}. En Dynamic Segment Mappings, asigna airport_code → el componente airport, campo de slug code. Guarda — aterrizarás en el Page Builder. Verifica que /JFK se resuelva.
Añadiendo un elemento de interfaz a la página desde la pestaña Custom.
Los cuatro elementos de interfaz añadidos al binding de JFK en el Page Builder.
Selecciona el binding JFK → Add UI Element → pestaña Custom → añade nav, headline, body, footer en ese orden. Profound propaga el conjunto a cada binding de aeropuerto.
Rellena cada campo. Valores estáticos (marca del nav, texto del footer): escríbelos directamente. Valores dinámicos: cambia a dinámico y escribe CEL. La búsqueda compartida es documents.get("airport", meta.params.airport_code).
| Campo | Valor 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 (y .longitude) |
nav.brand, footer.text | cadenas estáticas |
Publish la página (arriba a la derecha).
Abre localhost:3000/JFK, luego /SFO, /LAX — misma plantilla, aeropuerto diferente.
La página terminada que renderiza los datos de JFK, en inglés.
Traduce primero los componentes. En el administrador, abre cada componente (cualquier componente — no tiene que ser un elemento de interfaz) y haz clic en Translate → Submit. Profound traduce su contenido a los 35 idiomas a la vez, incluidos los valores de campos estáticos. Haz esto antes de editar la ruta o tocar cualquier CEL.
Translate → Submit envía un componente a los 35 idiomas a la vez.
Añade la dimensión de idioma. En Pages, cambia el patrón a /{language}/{airport_code}. Añade un Dynamic Segment Mapping para language → el componente System incorporado language, campo slug code. Guarda y verifica que /en/JFK se resuelva.
Añadiendo el segmento {language} a la ruta.
Dirige cada campo traducible a la obtención traducida. Internacionalizar la página significa cambiar cada campo dependiente del idioma — no solo el titular — de documents.get(...) a documents.translated("airport", meta.params.airport_code, meta.params.language):
| Campo | CEL traducido |
|---|---|
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 (y .country) |
Deja el código IATA code y las coordenadas en documents.get — son idénticos en todos los idiomas. nav.brand y footer.text ya están cubiertos por la traducción del componente del paso 1.
Cuando los tres pasos estén hechos, /fr/SFO, /de/SFO, etc. se renderizan completamente traducidos.
Haz push a GitHub:
git init
git add -A
git commit -m "Airport directory"
gh repo create airports --public --source=. --push
Importa en Vercel: Add New → Project → importa el repositorio airports. Añade las variables de entorno — PROFOUND_API_KEY, NEXT_PUBLIC_PROFOUND_WEBSITE_ID, NEXT_PUBLIC_CMS_API_URL y, opcionalmente, NEXT_PUBLIC_BUNNY_CDN_URL — luego Deploy. Visita /en/JFK y /fr/SFO. Cada git push futuro redepliega.
Ambas funciones vienen con el andamiaje.
<Refresher> en layout.tsx actualiza la página que estás previsualizando cuando editas y guardas en el administrador — sin redeploy.?edit_mode=true a cualquier URL (p. ej. …/en/JFK?edit_mode=true) para ver las superposiciones de edición. Los visitantes públicos siguen viendo la página limpia.?edit_mode=true superpone el editor sobre la página en vivo.
Cincuenta aeropuertos, 35 idiomas, en vivo — descritos una vez y completados con datos: una ruta, cuatro componentes de React y un puñado de enlaces CEL. El CMS contiene el contenido, tu código lo renderiza y CEL los conecta.