Jesús Erro
Explorar conexiones
Arquitectura híbrida con un canal Git-first y otro DB-first que convergen en un read model común manteniendo una sola autoridad por dominio.

Git-first y DB-first: dos canales editoriales con una sola autoridad por dominio

Cuando una web empieza como un conjunto de Markdown, Git parece suficiente para todo. Es sencillo, auditable, portable y encaja de forma natural con editores como Obsidian y con generadores estáticos como Astro. Cuando esa misma web empieza a adquirir entidades, relaciones, estados, revisiones, APIs y automatizaciones, PostgreSQL empieza a ofrecer propiedades que los ficheros no deberían tener que imitar.

La tentación es escoger un único bando: todo en Git o todo en base de datos.

En jesuserro.com he preferido otra respuesta: mantener dos canales editoriales y decidir la autoridad por dominio.

Git-first                        DB-first

Obsidian                         Obsidian / UI / agente
   ↓                                ↓
Markdown                         application service
   ↓                                ↓
Git                              PostgreSQL
   ↓                                ↓
publicación                      proyección

                                  Git

La condición que hace viable este modelo no es tecnológica. Es una regla de propiedad:

cada dominio tiene una sola autoridad de escritura.

Puede existir una copia en el otro sistema. Puede existir incluso para consultas, búsqueda o grafo. Pero no puede existir una segunda verdad editable.

Git-first: cuando el contenido es principalmente un documento

Un artículo, una ADR o un runbook son fundamentalmente documentos. Su forma natural es un fichero legible por una persona:

Obsidian

Markdown

Git

PR / CI

Astro

Aquí Git ofrece casi todo lo que necesito:

  • diff textual;
  • historial;
  • branches;
  • revisión humana;
  • rollback;
  • portabilidad;
  • despliegue sencillo.

Si corrijo un párrafo de un artículo, el cambio que quiero conservar es precisamente ese cambio de texto. No necesito una transacción de negocio ni un current_revision dentro del dominio. El commit ya representa adecuadamente la evolución del documento.

Para este tipo de contenido, convertir PostgreSQL en requisito de escritura sólo añadiría fricción.

DB-first: cuando el contenido se comporta como una aplicación

Una Review empezó siendo también Markdown, pero dejó de ser únicamente texto cuando empezó a tener:

  • identidad estable;
  • Work o Edition como sujeto;
  • Readings relacionadas;
  • Topics;
  • References;
  • SourceRecords;
  • estado de publicación;
  • revisiones editoriales;
  • concurrencia y automatización futura.

En ese momento, tratar el fichero como si fuese una base de datos obliga a construir alrededor de YAML y directorios mecanismos que PostgreSQL ya resuelve mejor.

Por eso Reviews y Readings hicieron un authority pivot: PostgreSQL pasó a ser la fuente canónica y los Markdown públicos se convirtieron en proyecciones generadas.

El flujo cambia:

working copy

PLAN

application service

PostgreSQL

projection apply

Markdown generado

Git

Astro

Git no desaparece. Cambia de función.

Antes guardaba la verdad editorial. Después del pivot guarda una representación pública versionada y el artefacto que terminará desplegándose.

Estar en PostgreSQL no significa ser DB-first

Ésta es una distinción especialmente importante.

Un artículo Git-first puede terminar también en PostgreSQL.

Por ejemplo, podría existir una tabla derivada con:

article_id
title
slug
topics
published_at
body

Eso permitiría resolver consultas transversales, alimentar un grafo, una API o un agente. Pero mientras la autoridad siga siendo Git, esa fila no es el lugar donde debe editarse el artículo.

Git/Markdown = write authority
PostgreSQL   = read model derivado

El sistema puede por tanto tener una PostgreSQL muy rica sin afirmar que todo el proyecto es DB-first.

Canonical model y read model responden preguntas diferentes

Me resulta útil separar dos preguntas:

¿Dónde cambio la verdad?

Ésa es la autoridad canónica.

Para una Review DB-first:

PostgreSQL

Para un Article Git-first:

Markdown/Git

¿Dónde consulto eficientemente?

Ése es el read model.

Y aquí PostgreSQL puede ser útil para ambos.

Git-first Articles ──ingest──┐
                             ├── PostgreSQL read model
DB-first Reviews ────────────┘

Desde esa capa se pueden construir:

  • búsqueda;
  • knowledge graph;
  • APIs;
  • agentes;
  • analítica;
  • consultas que crucen dominios.

No necesito implantar un CQRS formal para aprovechar esta separación. Basta con no confundir el lugar donde se consulta con el lugar donde se escribe.

El error que quiero evitar: dos autoridades editables

El diseño peligroso es éste:

Git <────────> PostgreSQL
     editable

Al principio parece flexible. Después aparecen preguntas difíciles:

  • ¿qué ocurre si alguien cambia los dos lados?
  • ¿gana el timestamp más reciente?
  • ¿se fusionan campos?
  • ¿qué pasa con el body?
  • ¿qué ocurre si un agente y Obsidian editan a la vez?

La respuesta suele terminar en reconciliación compleja o en last write wins, que puede destruir una edición perfectamente válida.

Prefiero una flecha inequívoca.

Git-first

Git ─────────► PostgreSQL
authority      derived

DB-first

PostgreSQL ─────────► Git
 authority            derived

Si la copia derivada cambia por fuera del flujo soportado, eso no es una nueva versión: es drift.

Obsidian puede vivir encima de los dos canales

Esta arquitectura no obliga a renunciar a Obsidian.

En Git-first funciona como siempre:

Obsidian → Markdown authoritative

En DB-first cambia ligeramente:

PostgreSQL
↓ checkout
working copy

Obsidian
↓ plan/apply
application service

PostgreSQL Revision N+1

La experiencia humana sigue siendo escribir un Markdown cómodo. Lo que cambia es el contrato al guardar.

En vez de copiar el fichero directamente sobre la web pública, la working copy se transforma en una mutación controlada del dominio.

Esta diferencia permite mantener una interfaz de escritura agradable sin sacrificar transacciones, revisionado o concurrency control.

Una Review puede tener dos historias distintas

El modelo DB-first también permite separar algo que en Git suele quedar mezclado.

PostgreSQL ReviewRevision
= historia editorial del contenido

Git commit
= historia técnica/publicada del repositorio

Una Review puede pasar de Revision 3 a Revision 4 aunque ese cambio termine compartiendo un commit con el manifest y otras proyecciones técnicas.

El historial intelectual de la reseña ya no depende de interpretar el historial completo del repositorio.

Migrar más dominios en el futuro

Esta arquitectura no decide que Articles deban quedarse Git-first para siempre.

Si dentro de unos años un artículo empieza a necesitar workflows, varias superficies de edición, relaciones fuertes o revisionado explícito, puede hacerse otro authority pivot.

El proceso que quiero repetir es incremental:

1. identificar baseline
2. definir contrato DB
3. expandir schema
4. backfill
5. demostrar paridad
6. introducir writer DB
7. crear proyección + drift detection
8. declarar PostgreSQL authority
9. deshabilitar el viejo writer Git

Lo importante es el paso 9. Una migración no está terminada cuando los datos existen en PostgreSQL. Está terminada cuando existe una sola ruta autorizada para cambiar la verdad.

No todo debe migrarse porque pueda migrarse

PostgreSQL es una herramienta magnífica, pero no convierte automáticamente un documento en una entidad de aplicación.

Mi regla práctica queda así:

Si algo es principalmente documento, empieza Git-first. Si algo es principalmente entidad con ciclo de vida, relaciones y mutaciones, DB-first puede ser el modelo correcto.

Y después observar.

El enfoque incremental que describo en Modernizar una base de datos legacy sin reescribirla encaja bien aquí: primero dejo que las necesidades reales demuestren qué complejidad existe y después consolido el modelo que la soporta.

Plan antes de mutar

El canal DB-first también conecta con el Rehearsal Pattern: observar, calcular un PLAN, comprobar precondiciones, aplicar y verificar.

state

plan

approval

mutation

verification

En un sistema donde PostgreSQL es autoridad, esta separación es más importante que un simple botón de guardar. Permite detectar una revisión obsoleta, un cambio inesperado o una proyección con drift antes de mutar el estado canónico.

Git sigue siendo esencial en DB-first

DB-first no significa «sin Git».

Git continúa aportando:

  • versionado del código y schema;
  • manifest e integridad de proyecciones;
  • review mediante PR;
  • CI;
  • deployment;
  • trazabilidad técnica.

En el Director–Implementer Loop R4.1 GitHub también es bus de handoff y audit trail. Pero transporte y auditoría no equivalen a autoridad editorial.

Esta separación de responsabilidades es precisamente la idea común entre ambos diseños.

Una arquitectura híbrida, no una transición inacabada

Tener Git-first y DB-first al mismo tiempo no significa que la migración esté a medias.

Puede ser el estado correcto durante mucho tiempo:

                    AUTHORING

          ┌────────────┴────────────┐
          │                         │
      Git-first                 DB-first
          │                         │
          ▼                         ▼
         Git                    PostgreSQL
      authority                  authority
          │                         │
          └──────────┬──────────────┘

              unified read model

        ┌────────────┼────────────┐
        ▼            ▼            ▼
      graph         API         agents

La arquitectura puede evolucionar hacia más DB-first si el producto lo necesita. Pero no necesito pagar hoy el coste de convertir cada documento en una entidad transaccional.

La decisión que sí quiero conservar desde el principio es más pequeña y más fuerte:

un dominio puede tener muchas representaciones, pero sólo una autoridad de escritura.

A partir de ahí, Git y PostgreSQL dejan de competir. Cada uno hace el trabajo para el que resulta mejor.