Skip to main content

Build en modo standalone

next.config.ts activa output: "standalone". El build empaqueta solo lo que Next.js necesita para arrancar (.next/standalone + .next/static + public), sin el resto de node_modules.
El CLI de Prisma no viaja dentro del bundle standalone. Por eso la imagen final incluye, aparte, un toolkit de migraciones separado (más abajo).
next.config.ts también fuerza el file-tracing de sharp y @img con outputFileTracingIncludes, porque el tracing automático de Next.js no siempre los detecta al construir el bundle standalone; sin ese ajuste, el procesamiento de imágenes falla en producción.

Arranque: docker-entrypoint.sh

Al arrancar el contenedor, un script de entrypoint corre antes que node server.js:
  1. Crea los directorios de upload (public/uploads/avatars, public/uploads/camellos) por si la imagen arranca sin volumen o con un volumen montado vacío.
  2. Aplica prisma migrate deploy usando un toolkit de Prisma (CLI, schema y cliente generado) instalado aparte, en /migrate, precisamente porque el CLI no está incluido en el bundle standalone.
El seed no corre en cada deploy — se asume que el entorno ya tiene datos. Se ejecuta a mano, con npm run db:seed, solo cuando hace falta.

Salud del deploy

/salud (y GET /api/admin/health) comprueba, además de la base y de que public/uploads sea escribible, dos señales del deploy:
  • Migraciones: filas de _prisma_migrations sin finished_at, o con rolled_back_at. El proceso de Next no trae la carpeta prisma/migrations (el CLI vive en /migrate), así que no compara archivos pendientes.
  • Disco: bytes libres en public/uploads (o en el directorio de trabajo si esa carpeta no existe). Por debajo de 100 MB el estado queda degradado.
El probe público GET /api/health sigue mirando solo la base. El recordatorio de cita no corre dentro del proceso. Un cron externo puede llamar:

Integración continua

El workflow de CI corre en cada push y pull request contra master, en una matriz con Node.js 22 y 25:

Construir y ejecutar la imagen

Seed o creación de un admin dentro del contenedor (si tienes shell):