Deploy
El backend se deploya en Dokploy; el frontend en Cloudflare Pages. Mismo código, un deploy por entorno.
Backend (Dokploy)
El servicio de pre usa el mismo provider/repo, build type y Dockerfile (auth-panel/dokploy/Dockerfile) que prod. Por entorno solo cambian:
- Environment variables — ver la matriz de entornos y las de auth.
- Dominio —
pupo-pre.anfibia.io(pre) vspupo.anfibia.io(prod). - Branch —
dev(pre) vsmaster(prod).
Dominio
- Crear un record A para
pupo-pre.anfibia.ioapuntando a la misma IP del servidor de Dokploy que prod. - En Dokploy → servicio de pre → Domains → agregar
pupo-pre.anfibia.io, HTTPS on (Let's Encrypt), Container Port4700(elEXPOSEdel Dockerfile — el mismo que prod; contenedores separados no colisionan).
Migraciones
El entrypoint corre pnpm migration:up al arrancar → crea/actualiza schemas y tablas en la DB del entorno automáticamente.
GITHUB_TOKEN (build secret)
El Dockerfile instala paquetes privados @cuatro-quinas y lee el token como build secret (--mount=type=secret,id=GITHUB_TOKEN). Tiene que estar cargado en Dokploy como secret de build. El token debe ser un classic PAT con scope read:packages y, si el org usa SSO, autorizado para @cuatro-quinas.
Frontend (Cloudflare Pages)
Un solo proyecto de Pages con el split nativo Production / Preview:
| Setting | Valor |
|---|---|
| Build command | pnpm build |
| Build output directory | dist |
| Production branch | master |
| Framework preset | None / Vite |
Variables de entorno (por environment)
Se cargan por separado para Production y Preview. Las dos VITE_* apuntan al dominio del backend del entorno (en pre, el backend proxya /api/auth):
Preview (dev):
VITE_API_URL = https://pupo-pre.anfibia.io
VITE_AUTH_URL = https://pupo-pre.anfibia.io
Production (master):
VITE_API_URL = https://pupo.anfibia.io
VITE_AUTH_URL = <URL pública del ajolote de prod>
Las VITE_* se hornean en build-time; Cloudflare las inyecta durante el build de cada environment.
Build vars obligatorias (en Production Y Preview)
GITHUB_TOKEN— para instalar los paquetes privados@cuatro-quinas(el.npmrclo pide). Sin esto el build falla enpnpm install.NODE_VERSION=20— no hay.nvmrc; React 19 + Vite necesitan Node 20+.
Dominios
- Prod:
https://pupo-panel.pages.dev - Pre:
https://dev.pupo-panel.pages.dev(alias estable de la ramadev)
Troubleshooting
Problemas reales que aparecieron al montar el entorno de pre:
| Síntoma | Causa | Solución |
|---|---|---|
Build Docker: ERR_PNPM_FETCH_401 ... @cuatro-quinas | GITHUB_TOKEN inválido/ausente/sin read:packages o SSO no autorizado | Regenerar classic PAT con read:packages (+ autorizar SSO), cargarlo en Dokploy, rebuild sin cache |
getaddrinfo ENOTFOUND postgresqldb-rw2aop | DB_HOST incompleto | Usar el host interno completo: databases-postgresqldb-rw2aop |
Cannot find module 'express' (runtime) | express era transitiva; pnpm no la resuelve en el node_modules de prod | Declararla como dep directa en package.json |
TypeError: cors_1.default is not a function | Default import de un módulo CJS sin esModuleInterop | Importar con import cors = require("cors") |
OPTIONS /api/auth/... → 502 + "CORS Missing Allow Origin" | El backend estaba caído (crash al boot) → Traefik devuelve 502 sin headers CORS | El 502 es el problema real, no CORS: arreglar el crash del backend (ver filas de arriba) |
New Relic requires that you name this application | Falta NEW_RELIC_APP_NAME | Setear NEW_RELIC_APP_NAME=Pupo-pre o NEW_RELIC_ENABLED=false (no es fatal) |
tRPC: El proyecto no tiene una URL de afiliado configurada | DB de pre vacía; falta el Project con su affiliateUrl | Loguearse como superuser y crear el proyecto con su URL de afiliado (dato local por entorno) |
Un 502 en un endpoint casi siempre significa que el contenedor no le dio una respuesta válida a Traefik (caído, puerto mal, o el proxy no alcanza a ajolote). Verificar primero curl -i https://pupo-pre.anfibia.io/health.