Saltar al contenido
Paco Segovia
Reservar 20 min

CMS

Cómo se edita esta web

El contenido se edita en Payload y la web se compila con él. La web publicada no llama nunca al CMS: si el CMS se cae, nadie que la visite lo nota.

Payload 3, Next y Postgres para editar; Astro estático para publicar. Ver también el sistema de diseño y cómo trabajo con IA.

Arquitectura

Del panel a la web, en seis pasos

  1. Payload

    Editar

    Payload 3 en cms.pacosegovia.es, sobre Next, Postgres (Neon) e imágenes en R2.

  2. Hook de Payload

    Publicar

    Publicar la Portada, o guardar Ajustes o Tiendas, lanza un aviso a GitHub.

  3. GitHub Actions

    Disparar

    El aviso arranca el workflow de despliegue con un token que no puede tocar el código.

  4. cms-pull

    Bajar

    Un script baja lo publicado a un JSON y copia las imágenes dentro de la web.

  5. Astro

    Compilar

    Astro mezcla ese JSON con los textos de interfaz del repositorio y genera HTML estático.

  6. FTPS

    Subir

    Un script revisa qué se borraría y para el despliegue si algo no cuadra. Después sube a Apache.

Son dos proyectos en un repositorio, con sus propias dependencias y versiones de Node. Un cambio dentro de cms/ no despliega la web, y un cambio en la web no toca el CMS.

Decisiones

Por qué está montado así

La web no llama al CMS
El CMS solo se usa al editar y al compilar. Si se cae o se actualiza, la web publicada sigue igual, y nadie que la visite carga nada de él.
Texto plano, sin rich text
La web enlaza sola los nombres de tiendas y estudios y anima el titular palabra a palabra. Quien edita no puede romper la maquetación con un formato.
Borradores solo en la Portada
Es lo que se reescribe con calma. Ajustes y Tiendas son interruptores y listas: se publican al guardar.
Dos idiomas independientes
Cada texto tiene versión en español e inglés. Si falta la inglesa, Payload devuelve la española.
Imágenes desde el propio dominio
Se copian al compilar. La política de seguridad sigue sin admitir dominios externos.
Si el CMS falla, no se despliega
cms-pull para el build con error. La web publicada se queda como estaba.
Sin CMS_URL, datos del repositorio
La web compila sin conexión con los textos que guarda el repositorio. Sirve para desarrollar y como respaldo.
Migraciones obligatorias
Cada cambio de esquema genera una migración versionada que se aplica al arrancar el servidor.

Modelo de contenido

85 campos, 46 en dos idiomas

Esta sección se genera al compilar leyendo el esquema de Payload en cms/src: si cambia un campo, cambia aquí. Los globales son documentos únicos; las colecciones, listas de elementos.

Portada

home
GlobalBorrador y publicación54 campos
SEO3 campos
  • TítulotitleTextoES · ENobligatorio
  • DescripcióndescriptionTexto largoES · ENobligatorio
  • PuestojobTitleTextoES · ENobligatorio

    Para los datos estructurados.

Portada7 campos
  • EtiquetatagTextoES · ENobligatorio
  • UbicaciónlocationTextoES · ENobligatorio
  • TitulartitleTextoES · ENobligatorio
  • TextobodyTexto largoES · ENobligatorio
  • Botón a los casosseeCasesTextoES · ENobligatorio
  • Nota bajo el botónbookingNoteTextoES · ENobligatorio
  • Título de los logosfeaturedTextoES · ENobligatorio
Servicios12 campos
  • Etiqueta del menúlabelTextoES · ENobligatorio
  • TitulartitleTextoES · ENobligatorio
  • ServiciositemsListaobligatorio
    • IconoiconSelecciónobligatorio

      Opciones: Tienda, Accesibilidad, Acuerdo

    • TítulotitleTextoES · ENobligatorio
    • Para quiénaudienceTextoES · ENobligatorio
    • TextotextTexto largoES · ENobligatorio
    • Qué se llevadeliverableTexto largoES · ENobligatorio
    • PlazotimeTextoES · EN

      Vacío: no se muestra.

    • Precio desdepriceTextoES · EN

      Vacío: no se muestra.

    • BotónctaTextoES · ENobligatorio
    • Asunto del mensajesubjectTextoES · ENobligatorio
Casos9 campos
  • Etiqueta del menúlabelTextoES · ENobligatorio
  • TitulartitleTextoES · ENobligatorio
  • CasositemsListaobligatorio

    El primero ocupa la fila entera.

    • TiendastoreRelación → Tiendasobligatorio
    • FechaswhenTextoES · ENobligatorio
    • PapelroleTextoES · ENobligatorio
    • AlcancescopeTextoES · ENobligatorio
    • TextotextTexto largoES · ENobligatorio
    • Resultado mediblemetricTextoES · EN

      Vacío: no se muestra.

Trayectoria11 campos
  • Etiqueta del menúlabelTextoES · ENobligatorio
  • TitulartitleTextoES · ENobligatorio
  • TextotextTexto largoES · ENobligatorio
  • FotoimageImagen → Imágenesobligatorio
  • Texto alternativo de la fotophotoTextoES · ENobligatorio
  • EtapasstagesListaobligatorio
    • FechaswhenTextoES · ENobligatorio
    • DóndewhereTextoES · ENobligatorio
    • TextotextTexto largoES · ENobligatorio
  • Título de otras tiendasmoreTextoES · ENobligatorio
  • Fuera del ecommerceotherTexto largoES · ENobligatorio
Cómo trabajo5 campos
  • Etiqueta del menúlabelTextoES · ENobligatorio
  • TitulartitleTextoES · ENobligatorio
  • PasosstepsListaobligatorio
    • TítulotitleTextoES · ENobligatorio
    • TextotextTexto largoES · ENobligatorio
Contacto7 campos
  • Etiqueta del menúlabelTextoES · ENobligatorio
  • TitulartitleTextoES · ENobligatorio
  • TextotextTexto largoES · ENobligatorio
  • Página de graciasthanksGrupo
    • TitulartitleTextoES · ENobligatorio
    • TextotextTexto largoES · ENobligatorio
    • Enlace de vueltabackTextoES · ENobligatorio

Ajustes

settings
Global23 campos
  • DisponibilidadavailabilityGrupo
    • EstadostatusSelecciónobligatorio

      Opciones: Disponible, Limitada, Sin hueco, Oculta

    • Texto propionoteGrupo

      Vacío: el texto por defecto del estado.

      • EspañolesTexto
      • InglésenTexto
  • Botón principalctaGrupo
    • Mostrar en la cabecerashowInHeaderCasilla
    • Enlace de reservabookingUrlTexto

      Vacío: abre un correo.

  • LinkedInlinkedinGrupo
    • MostrarshowCasilla
    • URLurlTexto
  • CVcvGrupo
    • Mostrar el enlace al PDFshowCasilla
  • Selector de idiomalanguageSwitchGrupo
    • MostrarshowCasilla
  • Secciones de la portadasectionsGrupo
    • ServiciosoffersCasilla
    • CasoscasesCasilla
    • TrayectoriaaboutCasilla
    • Cómo trabajoprocessCasilla
  • EstudiosstudiosLista

    Su nombre se enlaza solo en los textos.

    • NombrenameTextoobligatorio
    • WebhrefTextoobligatorio

Tiendas

stores
Colección8 campos

Tiendas, clientes y empresas. Su nombre se enlaza solo en los textos. El orden se cambia arrastrando.

  • NombrenameTextoobligatorio
  • WebhrefTexto

    Vacío si ya no está en producción.

  • LogologoImagen → Imágenesobligatorio
  • Logo para fondo oscurologoDarkImagen → Imágenes

    Solo si el logo de color no se puede invertir.

  • Destacada en la portadafeaturedCasilla
  • No es una tiendaotherCasilla

    Cliente corporativo o empresa.

  • Conserva sus colorescolorCasilla

    Si no, se invierte en oscuro.

  • Corrección ópticascaleNúmero

    Si el logo pesa más o menos de lo que dice su proporción. Vacío: 1.

Imágenes

media
Colección0 campos

Solo el archivo: Payload guarda el nombre, el tamaño y las dimensiones.

Usuarios

users
Colección0 campos

Solo correo y contraseña, para entrar al panel.

CMS o repositorio

Qué se edita dónde

Dónde se edita cada contenido y cuándo llega a la web
ContenidoDóndeCuándo llega a la web
Portada: SEO, titular, servicios, casos, trayectoria, pasos y contactoCMS · PortadaCon borrador; hay que publicar
Disponibilidad, botón principal, secciones visibles, estudiosCMS · AjustesAl guardar
Tiendas y logos, y su ordenCMS · TiendasAl guardar
Textos de interfaz, formulario y pieRepositorio · content.tsCon un PR
Correo y buzones del formularioRepositorio · site.config.tsAcaban dentro de contacto.php
Imagen para compartir y CVRepositorio · og/ y cv/Se regeneran a mano

El correo y los buzones se quedan en el repositorio a propósito: terminan dentro del PHP del formulario y no deberían cambiar desde un panel. El repositorio guarda también una copia de los textos del CMS, pero en producción solo se usa si el CMS no está configurado.

Publicar

Qué pasa al pulsar el botón

  • Portada

    • Guardar deja un borrador, que la web no ve
    • Publicar lanza el despliegue
    • Hay hasta 50 versiones para volver atrás
  • Ajustes y Tiendas

    • Guardar publica y despliega
    • Las tiendas se ordenan arrastrando
    • Una tienda nueva se enlaza sola en los textos
  • Si hay varios cambios seguidos

    • Cada uno pide un despliegue
    • GitHub deja solo el último pendiente
    • Si GitHub falla, se guarda igual y queda en el registro

Cambiar el esquema

Un campo nuevo cruza cuatro capas

  1. Esquema

    El campo en cms/src, con su etiqueta en español y si se traduce.

  2. Migración

    payload migrate:create, probada contra una base de datos que no sea la de producción.

  3. cms-pull

    Que el dato llegue al JSON con la forma que espera la web.

  4. Componente

    El tipo en content.ts o site.config.ts, su valor por defecto y dónde se pinta.

  5. Despliegue

    Primero el CMS, para que la migración se aplique; después la web.

Si falta una capa, el build puede fallar o el dato no llega a la web. Por eso hay una skill, cms-schema, que recorre los cinco pasos cada vez. Y una regla: la base de datos del CMS publicado no se usa para probar cambios de esquema.

Seguridad

Lo justo para editar, nada más

Lectura
La Portada publicada es pública; los borradores solo se ven con sesión. Ajustes y Tiendas son de lectura pública porque acaban en la web de todas formas.
Token de despliegue
De GitHub, fine-grained, limitado a este repositorio y con un único permiso, Actions: write, para lanzar el despliegue. No puede tocar el código.
Secretos
Solo en variables de entorno del servidor. El agente de IA no los imprime ni para diagnosticar.
Superficie mínima
GraphQL desactivado y sin editor de texto enriquecido en uso. Todo lo que se sube como imagen es público, porque acaba en la web.