---
title: "Migraciones de base de datos"
description: "Cómo se aplica el esquema PostgreSQL de Ring en una instalación nueva, cómo llegan las migraciones incrementales a las bases de datos existentes y cómo se reconstruye el schema.sql aplanado"
locale: "es"
---
# Migraciones de base de datos

Ring guarda su esquema PostgreSQL en dos lugares dentro de `ring/web/data/`. `schema.sql` es la fuente única de verdad aplanada para bases de datos **nuevas**. `migrations/` contiene los archivos incrementales numerados que llevaron a las bases de datos **existentes** a la misma forma. Esta página explica cuál usar y cuándo.

> **Info**
> Usa las pestañas **Fundador** / **Desarrollador** de la barra lateral para filtrar esta página. Las secciones compartidas se aplican a ambos públicos.

> **Warning**
> **Estado:** `./install.sh setup-db` y `npm run db:apply-schema` fallan actualmente en los checkouts públicos porque buscan rutas que se movieron a `web/`. Además, `schema.sql` contiene `CREATE EXTENSION IF NOT EXISTS postgis;`, así que un `psql -f data/schema.sql` sin más se detiene con un error en las imágenes de PostgreSQL que no incluyen PostGIS (por ejemplo `postgres:16-alpine`). Usa los comandos del paso 2 más abajo.

| La documentación anterior decía | Comportamiento actual |
|-----------------|------------------|
| Aplica `schema.sql` y después `002`, `003`, `004` en orden | Las instalaciones nuevas aplican **solo** `web/data/schema.sql` (aplanado, versión 4.1.0) |
| Ejecuta `./scripts/run-migration.sh` o `apply-*-migrations-dev.sh` | Esos scripts no están en el árbol público. Usa `psql` directamente |
| Instala `postgresql@18` de Homebrew con un script de arranque | Sirve cualquier PostgreSQL 16 o posterior. El script de arranque es interno de Ringdom |
| Carga las noticias desde `scripts/seed-news-v1.6.0.sql` | Ese archivo no existe. Los datos iniciales de monedas, países, ajustes de tienda y categorías de noticias están dentro de `schema.sql` |
| `data/schema-delta.sql` | No se usa. Los cambios viven como archivos numerados en `data/migrations/` |

### For founders

## Qué significa esto para tu comunidad

No necesitas saber SQL para gestionar un clon de Ring, pero sí conviene que conozcas la regla que sigue tu desarrollador: **una base de datos nueva recibe un solo archivo, una base de datos existente recibe solo los archivos nuevos.** Esa regla es la que mantiene las actualizaciones aburridas.

  
- **[Clon nuevo](/docs/deployment/self-hosted.md)** — Un solo archivo de esquema crea todas las tablas (109 en la versión 4.1.0) más los datos de referencia. Sin repetir el historial.

  
- **[Actualizar un clon en producción](/docs/getting-started/troubleshooting.md)** — Tu desarrollador aplica, después de una copia de seguridad, solo los archivos numerados que tu base de datos aún no ha visto.

  
- **[Elegir una base de datos](/docs/customization/database-selection.md)** — PostgreSQL es el backend de producción predeterminado (`k8s-postgres-fcm`).

### Escenarios típicos

- **Primer lanzamiento.** Tu desarrollador crea una base de datos vacía y aplica `schema.sql`. El sitio queda listo para el primer inicio de sesión del administrador.
- **Actualización de la plataforma.** Una versión de Ring añade una migración como `051_likes_uci_favorites_indexes.sql`. Tu desarrollador hace una copia de seguridad, aplica ese único archivo y vuelve a desplegar.
- **Algo no va bien después de una actualización.** Las migraciones `051` y posteriores pueden incluir un archivo `.down.sql` correspondiente para revertir el cambio. Los archivos anteriores no lo tienen.

```mermaid
flowchart TD
  A[Base de datos] --> B{¿Vacía?}
  B -->|Sí| C[Aplicar solo web/data/schema.sql]
  B -->|No| D[Copia de seguridad]
  D --> E[Aplicar una vez los archivos numerados nuevos]
  E --> F[Volver a desplegar la app]
  C --> F
```

### For developers

## Estructura de `web/data`

| Ruta | Propósito |
|------|---------|
| `data/schema.sql` | Fuente de verdad aplanada, versión 4.1.0. Crea 109 tablas en `public`, las extensiones `uuid-ossp`, `pgcrypto` y `postgis`, y los datos de referencia |
| `data/migrations/NNN_*.sql` | Cambios incrementales, de `001` a `051` en el repositorio hoy |
| `data/migrations/NNN_*.down.sql` | Rollback opcional, presente para `051` |
| `data/migrations/README.md` | Reglas para añadir migraciones. Léelo antes de escribir una |
| `data/migrations/EMAIL-CRM-OPS.md` | Notas de operación para las tablas del CRM de correo |

Todas las migraciones numeradas del repositorio hasta `051` ya están integradas en `schema.sql`. No repitas `data/migrations/*.sql` sobre una base de datos vacía y nunca apliques `001_email_crm_schema.sql`: las tablas JSONB del CRM de `009` y `010` lo sustituyeron y forman parte de `schema.sql`.

La app se conecta con `DB_HOST`, `DB_PORT`, `DB_NAME`, `DB_USER`, `DB_PASSWORD` y `DB_SSL`. No lee `DATABASE_URL`. Consulta [Entorno](/docs/deployment/environment.md).

## Instalación nueva

### Crea una base de datos vacía

{`createdb -h localhost -U postgres ring_platform`}

Ejecuta el siguiente paso como superusuario o como propietario de la base de datos, porque `schema.sql` crea extensiones.

### Aplica schema.sql

Si tu servidor tiene PostGIS instalado (por ejemplo una imagen `postgis/postgis`), aplica el archivo tal cual:

{`cd ring/web
psql -h localhost -U postgres -d ring_platform \\
  -v ON_ERROR_STOP=1 -f data/schema.sql`}

En PostgreSQL sin PostGIS, elimina antes la línea de PostGIS. Ninguna tabla usa un tipo de PostGIS, así que no cambia nada más:

{`cd ring/web
sed '/^CREATE EXTENSION IF NOT EXISTS postgis;$/d' data/schema.sql \\
  | psql -h localhost -U postgres -d ring_platform -v ON_ERROR_STOP=1`}

### Comprueba el resultado

{`psql -h localhost -U postgres -d ring_platform \\
  -c "SELECT version, applied_at FROM schema_versions ORDER BY applied_at DESC LIMIT 5;"`}

Da acceso al esquema `public` al rol de tu app (`DB_USER`) y después inicia la app.

## Base de datos existente

Aplica solo los archivos que tu base de datos no ha visto. Algunas migraciones se registran en `schema_versions` con un `INSERT ... WHERE NOT EXISTS` (`016` a `025`, `037`, `043` a `046`, `050`, `051`). Las demás no, así que antes de aplicarlas comprueba si existen las tablas o índices que crean.

{`pg_dump -h localhost -U postgres -d ring_platform -Fc -f ring-before-051.dump
psql -h localhost -U postgres -d ring_platform -v ON_ERROR_STOP=1 \\
  -f data/migrations/051_likes_uci_favorites_indexes.sql`}

Para revertir una migración que incluye un archivo down, aplica `051_likes_uci_favorites_indexes.down.sql` de la misma forma. También borra su fila de `schema_versions`.

## Añadir una migración (colaboradores)

### Escribe el siguiente archivo numerado

Usa el siguiente número libre después del archivo más alto de `data/migrations/`. Hazlo idempotente (`IF NOT EXISTS`), regístralo en `schema_versions` y añade un `.down.sql` cuando el cambio sea reversible.

### Vuelve a aplanar schema.sql

{`cd ring/web
npm run db:flatten-schema`}

Esto ejecuta `ring/scripts/flatten-schema-from-migrations.sh`. Necesita un PostgreSQL local donde tu rol pueda crear bases de datos (`PGHOST` y `PGUSER` toman por defecto `localhost` y `ring_user`). Recrea una base de datos temporal `ring_schema_flatten`, guarda una copia de `schema.sql` como `schema.sql.bak-pre-flatten-`, aplica el esquema anterior más todas las migraciones excepto `001`, vuelca el DDL más los datos de referencia y verifica el resultado en `ring_schema_flatten_verify`. El paso de verificación necesita PostGIS por el motivo indicado arriba.

## Preguntas frecuentes

### Impacto

#### ¿Pierdo datos cuando se vuelve a aplanar el esquema?

No. El aplanado solo reescribe el archivo `schema.sql` del repositorio. Nunca toca las bases de datos en producción.

### Migración

#### Mi base de datos se creó con un `schema.sql` antiguo. ¿Qué archivos necesito?

Compara `SELECT version FROM schema_versions` con los archivos numerados y después aplica en orden los que falten, tras una copia de seguridad. Solo algunos archivos registran una versión (consulta Base de datos existente más arriba), así que en caso de duda comprueba sus tablas. Ten en cuenta que una instalación nueva con el `schema.sql` de hoy muestra versiones hasta `045`, aunque las tablas e índices de `046` a `051` ya estén presentes.

### Operación

#### ¿Por qué falla `CREATE EXTENSION postgis`?

Tu build de PostgreSQL no incluye PostGIS. Elimina esa línea como se muestra en el paso 2 o usa una imagen con PostGIS.

  
- [deployment/self-hosted](/docs/deployment/self-hosted.md) — Siguiente paso: ejecuta la app contra la base de datos que acabas de crear.

  
- [deployment/docker](/docs/deployment/docker.md) — Mismo flujo: aplica el esquema al contenedor de Postgres de compose.

  
- [architecture/backend-modes-and-databases](/docs/architecture/backend-modes-and-databases.md) — Requisito previo: por qué k8s-postgres-fcm necesita este esquema.

  
- [development/community-tooling](/docs/development/community-tooling.md) — Ver también: install.sh y los scripts npm de base de datos, incluidos los que fallan hoy.
