CMS 1.0Próximo release · En desarrollo

Conectar un proyecto de Platform

Crea el proyecto CMS, autoriza dominios y enlaza el website con un project slug estable.

10 min de lectura

Crear el proyecto CMS

En Veetcuna Platform abre CMSCrear proyecto y completa:

  1. Define nombre y URL

    Usa un nombre reconocible y la URL canónica HTTPS del website. La URL principal queda autorizada automáticamente para el editor.

  2. Conserva la referencia del proyecto

    El SDK usa la forma @tenant/project-slug. Copia la referencia exacta; no la sustituyas por el nombre visible ni por la URL.

  3. Abre el dashboard del proyecto

    Verifica que el proyecto pertenezca al tenant correcto antes de crear credenciales o conectar un website.

Configurar dominios y locales

En ConfiguraciónGeneral define los idiomas soportados, el idioma predeterminado y los dominios del editor.

  • La URL principal siempre está autorizada.
  • Añade los orígenes completos de desarrollo o preview, por ejemplo https://website.veetcuna.dev.
  • Usa solo el origen (scheme + host + puerto), sin rutas ni comodines.
  • Los hosts loopback se aceptan en desarrollo; para compartir el editor usa HTTPS.

Los locales configurados en Platform deben coincidir con defineCmsLocales en el website. Una diferencia puede crear documentos que el sitio no sabe resolver.

Crear la clave de runtime

En ConfiguraciónAPI keys crea el perfil Website runtime para el ambiente correspondiente. Ese perfil concede únicamente READ_CONTENT.

Platform muestra el secreto una sola vez. Guárdalo como VEETCUNA_CMS_API_KEY en el secret store del website. No uses la clave de sincronización/publicación para delivery público y nunca la envíes al navegador.

Declarar el sitio

Crea un módulo server-only, por ejemplo src/cms/site.ts. Este archivo reúne la identidad del proyecto, el registry generado, los idiomas y el puente que usa el editor para renderizar un borrador.

Importar el SDK y el registry

TSTypeScriptSolo lectura
import 'server-only';
 
import {
  createCmsSite,
  type CmsDocument,
  type CmsEditorPreviewContext,
} from '@veetcuna/cms-next';
import { defineCmsLocales } from '@veetcuna/cms-next/localization';
import { cmsGenerated } from './cms.generated';
  • server-only provoca un error de build si este módulo termina importado por un Client Component. Así evita que configuración o credenciales de runtime lleguen al navegador.
  • createCmsSite crea el adapter principal que después usarás como cms.page(), cms.shell() o cms.collection().
  • CmsDocument y CmsEditorPreviewContext solo aportan tipos al callback del editor; no agregan código al bundle.
  • cmsGenerated es el índice creado por withVeetcunaCms. Contiene las definiciones descubiertas y el identificador del release del registry; no se edita manualmente.

Definir idiomas

TSTypeScriptSolo lectura
const locales = defineCmsLocales({
  supported: ['es', 'en'],
  defaultLocale: 'es',
  cookie: 'website-locale',
});

supported determina las claves localizadas aceptadas por el sitio. defaultLocale se usa cuando una solicitud no contiene un idioma válido y debe pertenecer a supported. cookie indica dónde conservar la preferencia del visitante; puedes omitirla para usar el nombre predeterminado del SDK.

Los mismos idiomas deben existir en ConfiguraciónGeneral de Platform. Si el website declara en pero Platform no, o viceversa, ambos lados pueden resolver documentos distintos.

Preparar el puente del editor

TSTypeScriptSolo lectura
type WebsiteCmsSite = ReturnType<typeof createCmsSite<'es' | 'en'>>;
let cmsSite: WebsiteCmsSite;
 
export async function renderCmsEditorPreview(
  context: CmsEditorPreviewContext,
  document: CmsDocument
) {
  'use server';
  return cmsSite.renderEditorPreview(context, document);
}

El editor necesita una función de servidor que pueda pedirle al website el render de un borrador. Esta función no publica ni persiste contenido: delega en el SDK la validación de la sesión y la construcción del preview.

  • WebsiteCmsSite conserva el tipo de la instancia, incluidos los locales es | en.
  • let cmsSite se declara antes del callback porque el callback delegará en esa misma instancia cuando Platform lo invoque más tarde.
  • 'use server' mantiene la ejecución en el servidor. No retires esta directiva ni conviertas el archivo en un Client Component.
  • context lleva el contexto del preview y document el documento que debe renderizarse. Entrégalos sin modificarlos a renderEditorPreview.

Crear la instancia del sitio

TSTypeScriptSolo lectura
cmsSite = createCmsSite({
  projectSlug: process.env.VEETCUNA_CMS_PROJECT_SLUG!,
  generated: cmsGenerated,
  site: {
    name: 'Mi website',
    url: 'https://www.example.com',
    defaultSocialImage: '/og.png',
  },
  locales,
  access: 'public',
  editor: { renderDocumentPreview: renderCmsEditorPreview },
});
 
export const cms = cmsSite;
projectSlug

Referencia exacta @tenant/project-slug copiada desde Platform. La variable debe existir en todos los ambientes que se conecten al CMS.

generated

Registry code-first generado durante desarrollo y build. Permite que Platform conozca qué componentes puede editar el release desplegado.

site

Metadata base del website. url debe ser su origen canónico y defaultSocialImage actúa como fallback para Open Graph.

locales

Configuración creada con defineCmsLocales; centraliza validación, idioma predeterminado y cookie.

access

Usa public para delivery público. Usa private cuando la ausencia de VEETCUNA_CMS_API_KEY deba forzar el fallback local.

editor

Registra el callback server-side. El editor se habilita cuando existe VEETCUNA_CMS_API_URL, salvo que configures enabled explícitamente.

La exportación cms es la única instancia que debe consumir el resto del website. Importa desde este módulo al declarar páginas, shells, colecciones y navegación, en lugar de llamar createCmsSite varias veces.

Ejemplo completo

TSTypeScriptSolo lectura
import 'server-only';
 
import {
  createCmsSite,
  type CmsDocument,
  type CmsEditorPreviewContext,
} from '@veetcuna/cms-next';
import { defineCmsLocales } from '@veetcuna/cms-next/localization';
import { cmsGenerated } from './cms.generated';
 
// Debe coincidir con los idiomas configurados para el proyecto en Platform.
const locales = defineCmsLocales({
  supported: ['es', 'en'],
  defaultLocale: 'es',
  cookie: 'website-locale',
});
 
type WebsiteCmsSite = ReturnType<typeof createCmsSite<'es' | 'en'>>;
let cmsSite: WebsiteCmsSite;
 
// Platform invoca esta Server Action para renderizar borradores autorizados.
export async function renderCmsEditorPreview(
  context: CmsEditorPreviewContext,
  document: CmsDocument
) {
  'use server';
  return cmsSite.renderEditorPreview(context, document);
}
 
cmsSite = createCmsSite({
  // Copia en el entorno la referencia exacta @tenant/project-slug.
  projectSlug: process.env.VEETCUNA_CMS_PROJECT_SLUG!,
 
  // Índice machine-owned producido por withVeetcunaCms.
  generated: cmsGenerated,
 
  // Identidad y metadata base del website.
  site: {
    name: 'Mi website',
    url: 'https://www.example.com',
    defaultSocialImage: '/og.png',
  },
 
  locales,
 
  // Cambia a private si el delivery siempre exige VEETCUNA_CMS_API_KEY.
  access: 'public',
 
  // Mantiene el render del borrador dentro del servidor del website.
  editor: { renderDocumentPreview: renderCmsEditorPreview },
});
 
// Usa esta instancia al declarar páginas, shells y colecciones.
export const cms = cmsSite;

Primera conexión

Ejecuta el website con VEETCUNA_CMS_API_URL y el project slug correctos. Abre una página declarada con cms.page() y selecciona Conectar editor o Editar.

Al autenticarte, Platform valida acceso al módulo CMS, tenant, proyecto, origen y permisos. Si el documento aún no existe, la sesión con capacidad document:bootstrap registra el registry y crea su primera revisión a partir del documento local. El render público nunca escribe en el CMS.

Revalidación inmediata

El SDK conserva contenido publicado hasta 24 horas como red de seguridad. Para reflejar una publicación antes, crea un Route Handler firmado en el website:

TSTypeScriptSolo lectura
import { revalidateTag } from 'next/cache';
import {
  getCmsRevalidationTags,
  verifyCmsRevalidationRequest,
} from '@veetcuna/cms-next';
 
export const runtime = 'nodejs';
 
export async function POST(request: Request) {
  const secret = process.env.VEETCUNA_CMS_REVALIDATION_SECRET;
  if (!secret)
    return Response.json({ error: 'Not configured' }, { status: 503 });
 
  const event = await verifyCmsRevalidationRequest(request, { secret });
  if (
    !event ||
    event.payload.projectSlug !== process.env.VEETCUNA_CMS_PROJECT_SLUG
  ) {
    return Response.json({ error: 'Invalid request' }, { status: 401 });
  }
 
  for (const tag of getCmsRevalidationTags(event.payload)) {
    revalidateTag(tag, 'max');
  }
  return Response.json({ revalidated: true });
}

Genera un secreto aleatorio de al menos 32 caracteres, guárdalo como VEETCUNA_CMS_REVALIDATION_SECRET y registra en Platform la URL HTTPS del handler con el mismo secreto para los eventos cms.published y cms.rolled_back. El secreto no es una API key y tampoco debe llegar al cliente.