Configurar Payload Content Studio y email marketing
Configura el CMS Payload independiente, crea el primer editor en privado, procesa jobs y entrega campañas revisadas mediante el gateway SaaS.
Content Studio es la tercera aplicación opcional del starter. Usa Payload/Next.js para páginas, posts, briefs, medios y borradores de campaña. Web y Admin comparten datos/auth SaaS; Studio posee base, sesiones editoriales, migraciones y cola propias. El sitio de documentación independiente no consume este CMS automáticamente.
Iniciar y crear el primer editor
Desde la raíz del starter:
./scripts/setup.sh development
pnpm dev:doctor
pnpm dev:allSetup escribe apps/content-studio/.env.development.local, crea sushi_content y aplica migraciones Payload sin reemplazar valores existentes. Después puedes iniciar solo authoring con pnpm dev:studio y abrir http://localhost:3002/admin.
La primera cuenta en una base Studio vacía se convierte en administrador. El código actual permite crearla sin una sesión editorial previa. Mantén el despliegue accesible solo a operadores de confianza hasta terminar ese paso; no publiques un Studio vacío. No se incluye CLI bootstrap:admin. Después, crear usuarios exige un administrador y las cuentas nuevas reciben writer por defecto.
Los roles son writer, seo-manager, reviewer, publisher, admin; son independientes de admin_ro/admin_rw SaaS. El enlace Publishing de Admin no concede acceso editorial.
Preparar producción separada
Ejecuta pnpm env:setup:prod interactivamente y acepta configurar Studio. Solo esa elección crea apps/content-studio/.env.production.local; el modo no interactivo prepara únicamente SaaS. También puedes copiar el .env.example de Studio a su perfil productivo y completarlo a mano.
| Variable | Significado |
|---|---|
CONTENT_DATABASE_URL | Base Payload separada, nunca la base SaaS |
PAYLOAD_SECRET | Secreto editorial independiente de 32 bytes |
CONTENT_STUDIO_URL | Origen Studio, también proporcionado a Admin para su enlace |
CONTENT_CORS_ORIGINS | Orígenes browser exactos, incluido el origen del propio editor |
SAAS_MARKETING_API_URL | Origen SaaS que acepta marketing firmado |
CONTENT_MARKETING_SECRET | Valor exacto compartido con SaaS |
CRON_SECRET | Secreto scheduler Studio, distinto de cron/auth SaaS |
CONTENT_STORAGE_* | Almacenamiento privado y durable de medios |
El código usa la misma allowlist para CORS y CSRF. Incluye el propio origen Studio y solo frontends fiables que necesiten API desde browser. En local, por ejemplo, http://localhost:3002,http://localhost:3000; reemplaza todos los localhost en producción.
CONTENT_STUDIO_URL=https://studio.example.com
CONTENT_CORS_ORIGINS=https://studio.example.com,https://www.example.com
SAAS_MARKETING_API_URL=https://app.example.com
CONTENT_STORAGE_BUCKET=product-content
CONTENT_STORAGE_REGION=auto
CONTENT_STORAGE_ENDPOINT=https://ACCOUNT_ID.r2.cloudflarestorage.com
CONTENT_STORAGE_ACCESS_KEY=
CONTENT_STORAGE_SECRET_KEY=
CONTENT_STORAGE_FORCE_PATH_STYLE=trueRellena base y credenciales en privado. El plugin solo se activa con bucket, región, access key y secret key completos. Disco local es fallback de desarrollo; serverless/contenedores de solo lectura necesitan objetos durables. Usa bucket Studio privado dedicado y credenciales limitadas; ajusta región, endpoint y path-style al proveedor.
openssl rand -hex 32 # PAYLOAD_SECRET
openssl rand -hex 32 # Studio CRON_SECRET
openssl rand -hex 32 # CONTENT_MARKETING_SECRET; mismo valor en SaaS y Studio
openssl rand -hex 32 # MARKETING_UNSUBSCRIBE_SECRET; solo SaaS, otro valor
pnpm env:check:prodEl check valida un perfil Studio existente, incluida base separada y secreto marketing coincidente. No prueba login CSRF, conectividad storage ni primer administrador. La Configuración de entorno explica los requisitos completos SaaS y la carga explícita por proceso.
Migrar antes de desplegar
Con valores productivos Studio disponibles en el proceso de release:
NODE_ENV=production pnpm studio:migrate
pnpm build:studio
NODE_ENV=production pnpm start:studioEl CLI Payload lee el perfil productivo Next de Studio con NODE_ENV=production; las variables exportadas tienen prioridad. Los contenedores no migran al arrancar. Tras cambiar colecciones, genera y confirma tipos, import map y migración independiente:
pnpm studio:generate
pnpm studio:migrate:create
pnpm studio:migrate
pnpm --dir apps/content-studio checkPara Payload 3.90.2, aplica 20261005_024231_payload_security_fields antes de promover Studio. Añade campos nullable para limitación de reset de contraseña y keys de medios; no mueve objetos existentes. Captura las API keys de Service Accounts al generarlas: lecturas posteriores ya no las revelan. Recrea publicaciones/despublicaciones programadas pendientes tras actualizar, porque la referencia de usuario ahora incluye su colección de autenticación.
Borrador, revisión, publicación y automatización
Páginas/posts admiten cinco idiomas, borrador, autosave, preview, revisión, aprobación, publicación programada e historial. Los bloques registrados incluyen hero, rich text, callout, FAQ, CTA y herramientas conocidas; el contenido no instala HTML, CSS, JavaScript ni herramientas ejecutables arbitrarios. Revisa idioma, copy, SEO y preview, y deja que publisher/admin apruebe y publique la versión prevista.
Tu sitio debe consumir Payload publicado o /api/content/v1/published; Studio no sustituye el loader MDX de este sitio. Crea un Service Account con mínimos scopes, como content:draft:create y content:read; separa content:publish. Guarda la key mostrada una vez en el gestor de secretos de automatización.
Payload exige Authorization: service-accounts API-Key <key>. Con CONTENT_API_KEY exportada privadamente, crea un borrador:
curl --fail-with-body https://studio.example.com/api/content/v1/drafts \
-H "Authorization: service-accounts API-Key $CONTENT_API_KEY" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: first-product-update-v1' \
--data '{"collection":"posts","locale":"es","slug":"first-product-update","title":"Primera actualización","summary":"Qué cambió y por qué ayuda.","blocks":[{"type":"richText","markdown":"Una actualización útil para clientes."}]}'Reintenta la misma operación con key/body iguales; usa otra key para trabajo nuevo. Reutilizar key con otro payload se rechaza. La API también lee/reemplaza borradores, envía revisión, publica con scope separado y gestiona briefs/imports. El import devuelve job ID; consulta /api/content/v1/jobs/:id con su scope. Encolado no significa publicado.
Procesar la cola Payload
SaaS pnpm jobs:work no procesa la cola Payload. El timer Studio actual procesa hasta cinco jobs content cada minuto mientras vive el proceso. En serverless configura scheduler; no dependas de ese timer.
Con variables Studio productivas cargadas, programa cada minuto:
NODE_ENV=production pnpm --dir apps/content-studio jobs:run --all-queues --handle-schedulesO programa el runner HTTP autenticado, con todas las colas y publicaciones programadas:
curl --fail-with-body \
-H "Authorization: Bearer $STUDIO_CRON_SECRET" \
'https://studio.example.com/api/payload-jobs/run?allQueues=true&limit=5'STUDIO_CRON_SECRET es la variable privada del scheduler que contiene el CRON_SECRET exacto de Studio, no una nueva configuración app ni el secreto SaaS. Prueba import y publicación vencida completos; supervisa errores/retrasos.
Marketing mediante SaaS
Studio posee layout, copy, preview, aprobación y calendario. SaaS posee direcciones, consentimiento, bajas/supresión, audiencia, secretos Resend, jobs y auditoría. Automatiza con scopes marketing:* y actions revisadas; una actualización genérica de collection no inicia entrega.
Comparte exactamente CONTENT_MARKETING_SECRET. En SaaS configura MARKETING_UNSUBSCRIBE_SECRET distinto y estable, RESEND_API_KEY, EMAIL_FROM y RESEND_WEBHOOK_SECRET del proveedor. Registra https://app.example.com/api/marketing/webhooks/resend para entrega, bounce, complaint, failure y suppression. Obtén el secreto de ese endpoint desde Resend; no lo generes con OpenSSL.
Crea template con dirección postal física, compón campaña, preview/valida, comprueba conteo consentido, envía test, aprueba/publica la versión exacta y lanza. SaaS deduplica y vuelve a comprobar consentimiento antes de Resend, añade pie postal/baja y headers one-click. Repetir lanzamiento no duplica. Cancela pendientes desde la campaña; un mensaje aceptado no se recupera. Refresca estado y demuestra que una baja bloquea el siguiente envío.
Revalidación de tu sitio
PUBLIC_SITE_REVALIDATE_URL opcional apunta a tu receptor. Genera otro CONTENT_REVALIDATION_SECRET, compartido solo con ese handler. Studio firma timestamp.rawBody mediante HMAC-SHA256 y envía x-content-timestamp y x-content-signature. Tu sitio implementa verificación, frescura y caché; sushisaas.com no tiene receptor automático.
Evidencia de lanzamiento: primer admin creado en privado, bases aisladas, login CSRF del origen editor, medios durables, dos historiales migrados, replay crea un borrador, imports/publicaciones ejecutados y consentimiento/duplicado/baja probados con destinatario desechable.
Relacionado: Entorno, Email transaccional, Jobs y readiness, Despliegue.
Fuente: contrato Studio, config Payload, primer usuario, marketing.