Desplegar, paso a paso
Esta página es el recorrido completo, sin dar nada por sabido: qué se toca, en qué orden, desde qué carpeta y en qué plataforma.
Puesta en producción explica cómo se armó la infraestructura una vez. Esta explica cómo se despliega cada cambio.
Y Checklist de despliegue es la que se recorre cada vez: qué verificar en cada ambiente, el respaldo antes de migrar, y las cinco cosas que nunca se hacen contra producción ahora que hay clientes reales cargados.
Primero: el mapa
Sección titulada «Primero: el mapa»Tres repositorios separados, tres plataformas, una sola base de datos.
| Repo | Dónde vive en tu máquina | Se despliega en | Qué es |
|---|---|---|---|
api |
~/code/aquazaku/api |
Railway | El backend. Habla con Postgres |
web |
~/code/aquazaku/web |
Vercel | El front. Habla con api, nunca con Postgres |
docs |
~/code/aquazaku/docs |
(sitio estático) | Esta documentación |
Y la base:
| Dónde | Schema | |
|---|---|---|
| Producción | Supabase | public |
| Preview | la MISMA Supabase | preview |
| Local | Postgres de tu máquina | public de aquazaku_dev |
La regla que hay que entender antes de nada
Sección titulada «La regla que hay que entender antes de nada»Railway y Vercel despliegan solos al mergear a main. Las migraciones NO.
El startCommand de producción está vacío a propósito: el container solo
arranca el servidor. Migrar es un acto separado, deliberado, que hacés vos desde
tu máquina.
De ahí salen las dos preguntas de todo despliegue:
- ¿Este cambio trae una migración?
- Si la trae, ¿el código nuevo aguanta el schema viejo, o al revés?
Caso A — Sin migraciones
Sección titulada «Caso A — Sin migraciones»El caso común. No hay nada que coordinar.
gh pr merge --mergeRailway y Vercel detectan el push a main y redespliegan. Listo.
Caso B — Con migración ADITIVA que el código nuevo NO usa todavía
Sección titulada «Caso B — Con migración ADITIVA que el código nuevo NO usa todavía»Aditiva quiere decir que solo agrega: una columna nullable, una tabla, un índice. Y la condición que importa es la segunda mitad: que el código que se está desplegando no la lea.
Ahí el orden documentado funciona: mergear primero, migrar después.
gh pr merge --mergecd ~/code/aquazaku/apiDATABASE_MIGRATION_URL='<cadena de Supabase>' pnpm db:migrateCaso C — Con migración que RENOMBRA, CONVIERTE o rompe el código viejo
Sección titulada «Caso C — Con migración que RENOMBRA, CONVIERTE o rompe el código viejo»Acá el orden se invierte, y no es una preferencia: es que el otro orden rompe la planta.
Una migración que renombra nombre a nombre_libre deja al código viejo y al
nuevo incompatibles en direcciones opuestas. Medido:
| Leer clientes | Registrar cliente | |
|---|---|---|
| Código viejo + schema nuevo | ✅ | ❌ |
| Código nuevo + schema viejo | ❌ | ❌ |
Migrar primero deja el sistema funcionando: se vende, se consulta, se cobra, y lo único que falla es dar de alta un cliente nuevo durante los dos minutos del deploy. Al revés se cae todo lo de clientes, y con eso ventas, retornables y cartera.
C.1 — Respaldo
Sección titulada «C.1 — Respaldo»cd ~/code/aquazaku/apiDATABASE_MIGRATION_URL='<cadena de Supabase>' pnpm db:respaldoC.2 — Migrar producción, ANTES de mergear
Sección titulada «C.2 — Migrar producción, ANTES de mergear»La rama tiene que estar en tu máquina —ahí vive el archivo de la migración—.
cd ~/code/aquazaku/apigit checkout <la-rama-de-la-PR>DATABASE_MIGRATION_URL='<cadena de Supabase>' pnpm db:migrateC.3 — Mergear
Sección titulada «C.3 — Mergear»gh pr merge --mergeapi primero y web después: el front llama al backend, no al revés.
C.4 — Verificar
Sección titulada «C.4 — Verificar»curl -s https://api.aquazaku.com/healthDe dónde sale la cadena de Supabase
Sección titulada «De dónde sale la cadena de Supabase»Es la parte que más se traba, y tiene dos trampas.
En el panel de Supabase: Project Settings → Database → Connection string.
Para migrar hacen falta estas características:
| Valor | |
|---|---|
| Modo | sesión (no transacción) |
| Puerto | 5432 |
| Usuario | postgres.<ref-del-proyecto> |
El modo sesión es obligatorio porque las migraciones hacen DDL y REVOKE, y el
modo transacción no los sostiene.
Lo que el migrador imprime, y por qué hay que leerlo
Sección titulada «Lo que el migrador imprime, y por qué hay que leerlo»Antes de tocar nada, el script anuncia a dónde va:
→ migrando postgres.taytdxptguvrszjtsroz@aws-0-us-east-1.pooler.supabase.com/postgres → schema "public"✓ migraciones aplicadasLa contraseña nunca aparece — está sacada a propósito, porque esta línea termina en logs y en capturas de pantalla.
Cómo saber si quedó bien
Sección titulada «Cómo saber si quedó bien»curl -s https://api.aquazaku.com/healthBien:
{"status":"ok","service":"aquazaku-api","base":"ok","desdeHaceMs":19608}Mal — faltan migraciones:
{"status":"ok","service":"aquazaku-api","base":"ok","desdeHaceMs":97950, "esquema":"pendientes","faltan":["0016_nombre_partido"]}Mientras aparezca faltan, el código desplegado está pidiéndole a la base algo
que no tiene. status sigue diciendo ok porque el servidor está sano —
lo que está mal es el schema, y por eso se reporta aparte.
Y la comprobación que ninguna consola reemplaza: entrá a app.aquazaku.com y registrá un cliente de verdad.
El preview, que es otro camino
Sección titulada «El preview, que es otro camino»Un push a una PR despliega dos cosas más:
| Plataforma | Qué |
|---|---|
| Vercel | La URL xxx-git-<rama>-aquazaku.vercel.app |
Railway (staging) |
La api del preview, contra el schema preview |
El startCommand de staging sí migra, porque va contra un schema
desechable:
pnpm db:sync-preview && pnpm db:seed && pnpm startCómo entrar al preview y qué usuario usar está en Entornos.
Cuando algo sale mal
Sección titulada «Cuando algo sale mal»| Síntoma | Qué pasó | Qué hacer |
|---|---|---|
/health dice faltan: [...] |
Se mergeó sin migrar | Correr la migración |
ENOTFOUND db.<ref>.supabase.co |
Es la conexión directa, IPv6 | Usar la del pooler |
El migrador dice localhost |
La cadena no es la de producción | Ctrl+C |
| 500 en todas las pantallas de clientes | Casi siempre el schema atrasado | Mirar /health |
| El preview no acepta ningún usuario | La api de staging no arrancó | Log del deploy en Railway |
| CI en rojo pero GitHub deja mergear | main no tiene protección de rama |
Decidirlo aparte |
Rollback
Sección titulada «Rollback»Código: revert del commit. Railway y Vercel redespliegan solos.
Migración: revertir el código no la deshace. Si la migración ya corrió, hay que escribir otra que la deshaga explícitamente y correrla igual que la primera. Por eso el respaldo del paso C.1 no es ceremonia.
