Royal Clean CRM · Documentación
Despliegue

Variables de entorno

Cada variable, qué hace, si es obligatoria y qué ocurre cuando falta.

Todas se validan con Zod al arrancar. La validación es perezosa: ocurre la primera vez que el sistema necesita una variable, no al importar el módulo. Eso es lo que permite que next build funcione en CI y en la etapa de construcción de Docker, donde los secretos no existen.

Cuando falta algo obligatorio, el error dice qué falta y dónde ponerlo, en lugar de fallar más adelante con un mensaje que no lleva a ninguna parte.

Obligatorias

Ninguna de estas se commitea jamás

DATABASE_URL, AUTH_SECRET, R2_SECRET_ACCESS_KEY, R2_ACCESS_KEY_ID y JOBS_SECRET viven sólo en el panel de Dokploy y en tu gestor de contraseñas. El archivo .env.example del repositorio documenta las variables sin contener un solo valor real.

DATABASE_URL

Cadena de conexión a PostgreSQL.

postgresql://royalclean:LA_CONTRASENA@royalclean-db:5432/royalclean?schema=public

El host es el nombre interno del servicio en Dokploy, no localhost. El puerto es el 5432: el 5433 que usa el entorno local es un mapeo del anfitrión para no chocar con un PostgreSQL ya instalado, y dentro de Docker no aplica.

Si falta: la aplicación no arranca. Si es incorrecta: arranca, pero /api/health responde degraded con "database":"unreachable".

AUTH_SECRET

Secreto con el que se firman las sesiones. Mínimo 32 caracteres.

openssl rand -base64 48

Si falta o es corto: la aplicación no arranca, y lo dice.

Cambiarlo cierra todas las sesiones

No se pierde ningún dato, pero todo el mundo tendrá que volver a entrar. Cámbialo si sospechas que se filtró; no lo cambies por rutina.

APP_URL

URL pública, con protocolo y sin barra final.

APP_URL=https://crm.royalcleancr.com

Se usa para construir enlaces absolutos. Si no coincide con el dominio real, algunos enlaces apuntarán al sitio equivocado.

Almacenamiento de fotografías

Las cuatro van juntas: o están todas, o el almacenamiento queda desactivado. La aplicación arranca igual, pero subir una fotografía devuelve un error claro en lugar de fallar de forma rara.

VariableQué es
R2_ACCOUNT_IDIdentificador de cuenta de Cloudflare
R2_ACCESS_KEY_IDDel token de API de R2
R2_SECRET_ACCESS_KEYDel mismo token. No se vuelve a mostrar
R2_BUCKET_NAMEroyal-clean-evidence

R2_ENDPOINT

Opcional. Sólo hace falta apuntando a un almacenamiento que no sea R2 —MinIO en desarrollo, por ejemplo—. Sin ella se deduce del R2_ACCOUNT_ID.

Trabajos programados

JOBS_SECRET

Token que autoriza POST /api/jobs/run.

openssl rand -hex 32

Si falta: el endpoint responde 503, no queda abierto. Es deliberado: un trabajo de mantenimiento sin protección es peor que un trabajo que no corre.

Con token incorrecto: responde 401, sin dar pistas.

Regionales

BUSINESS_TIMEZONE

Zona horaria del negocio. Por defecto America/Costa_Rica.

De ella depende qué día del calendario es un servicio. La zona se aplica explícitamente en el código, nunca se hereda del contenedor: un servicio de las 6 de la mañana en Costa Rica no puede caer en otro día según dónde corra el proceso.

NODE_ENV

production en producción. La semilla de datos de prueba se niega a ejecutarse con este valor.

Opcionales

LOG_LEVEL

debug, info, warn o error. Por defecto info en producción.

RESEND_API_KEY y EMAIL_FROM

Reservadas para una futura integración de correo. Hoy no se usan: el sistema funciona íntegramente sin correo y los avisos son internos. Ver Reglas por confirmar.

Comprobar que están bien

curl https://crm.royalcleancr.com/api/health
RespuestaQué significa
{"status":"ok","database":"ok"}Todo correcto
{"status":"degraded","database":"unreachable"}Revisa DATABASE_URL
El contenedor no arrancaFalta una obligatoria. Mira los registros: lo dice

Los secretos nunca salen en los registros

El registro redacta automáticamente contraseñas, tokens, secretos de almacenamiento, códigos de acceso a propiedades y las firmas de las URLs. No depende de que quien escribe el registro se acuerde de ocultarlos.

On this page