Carlos Bautista

Architecture Decision · 30 de agosto de 2026

Diseñando un pipeline de contenido MDX desacoplado del almacenamiento

Diseño de una arquitectura de contenido que permite publicar mediante MDX y Static Export sin acoplar la interfaz al filesystem, dejando preparada una futura migración a API o base de datos.

Architecture · Static Export · Content Pipeline

Arquitectura desacoplada de contenido mediante ContentService, ContentRepository y MdxContentRepository
El almacenamiento MDX implementa el contrato actual mientras la UI permanece desacoplada de la fuente de contenido.

Problema

El portal necesita publicar tres tipos de contenido editorial —Articles, Projects y LabEntries— a partir de archivos MDX versionados en el repositorio. El requisito de fondo es que la interfaz no debe saber que hoy ese contenido vive en el filesystem. Si cada página lee archivos directamente, cambiar el origen del contenido más adelante obliga a tocar toda la capa de presentación.

Restricción

El sitio se compila como Next.js Static Export:

  • sin backend en ejecución;
  • sin base de datos;
  • todo el contenido se resuelve en build time.

Cualquier diseño tiene que producir HTML estático desplegable en Cloudflare Pages, sin introducir un servidor ni funciones en el borde.

Diseño

La lectura de contenido pasa por tres capas con una única dependencia hacia adentro:

Presentation (páginas y componentes)
  → ContentService        (orquestación de la aplicación)
    → ContentRepository    (contrato de lectura, sin implementación)
      ← MdxContentRepository (adapter concreto: filesystem + MDX)
        → archivos MDX

La presentación solo conoce ContentService. ContentService solo conoce la interfaz ContentRepository. MdxContentRepository es la única pieza que toca fs y que compila MDX, y se inyecta en un único punto de composición.

Por qué una interfaz

ContentRepository separa el contrato de lectura de su almacenamiento. Ese es el beneficio concreto y medible: se puede sustituir el origen del contenido sin que las páginas importen fs ni conozcan rutas de disco.

No se persigue aquí una Clean Architecture completa ni se afirman ventajas no comprobadas de testabilidad o velocidad. La abstracción es una sola interfaz con un puñado de métodos de lectura, no una jerarquía de puertos y adaptadores.

Build time

El contenido se resuelve entero durante next build:

MDX
  → MdxContentRepository (parsea frontmatter, deriva métricas y TOC)
    → ContentService (filtra borradores, ordena, arma la vista)
      → React Server Components
        → next build
          → HTML estático
            → Cloudflare Pages

No hay compilación de MDX ni resolución de contenido en el navegador: el resaltado de sintaxis y el render de MDX ocurren en el servidor de build y se serializan en la salida.

Evolución futura

El mismo contrato ContentRepository admitiría otros adapters —por ejemplo ApiContentRepository o DatabaseContentRepository— que traerían el contenido desde una API o una base de datos sin obligar a las páginas a cambiar. Ninguno de esos adapters está implementado; hoy solo existe MdxContentRepository. Se mencionan para explicar por qué el contrato tiene la forma que tiene, no para dar a entender que ya haya un backend.

Trusted MDX Boundary

El MDX actual es contenido controlado por el repositorio: lo escribe y lo revisa el owner, se versiona en git y se compila en build. Esa es la razón por la que es aceptable ejecutarlo como código.

MDX de usuarios, formularios o cualquier fuente no confiable nunca debe pasar por el compilador. Un futuro ApiContentRepository solo podría servir MDX si el origen estuviera bajo la misma revisión editorial; el contenido no confiable tendría que llegar como HTML ya sanitizado.

Aprendizaje

La abstracción se justifica por mantener separadas presentación, aplicación y almacenamiento sin introducir infraestructura antes de necesitarla. Se paga el coste de una interfaz y un punto de composición; a cambio, migrar de MDX a una API o una base de datos será un cambio localizado en un adapter, no una reescritura de la interfaz.