Variables de entorno del backend
El backend valida su configuración al arrancar contra
src/shared/infrastructure/services/environment-service/env-schema.json, que
declara 31 variables.
La mayoría trae un valor por defecto en el propio esquema, así que su ausencia no
impide arrancar. Sólo 7 están marcadas como obligatorias y sin defecto
—ZERTIAUTH_APP_ID, RADIATION_API, RADIATION_API_CREDENTIALS,
ENERGY_PREDICTION_API, TRADE_UPDATE_DAYS, STRIPE_PRODUCT_ID y
STRIPE_PRICE_KEY—, y si falta una de ésas el proceso aborta. Las siete están
escritas literalmente en el docker-compose.yml, de modo que en la práctica
nunca faltan.
Dónde se definen
No hay archivos .env. Toda la configuración está escrita literalmente en
el docker-compose.yml de la raíz, dentro del bloque environment: de
cada servicio. Para cambiar un dominio, un puerto o un servicio externo se
edita ahí y se vuelve a levantar el stack.
La única excepción son dos valores, que llegan del entorno y no tienen valor por defecto:
DB_PASSWORD · JWT_SECRET
- En Portainer: se ponen en «Environment variables» del stack.
- En local:
./setup.sh(osetup.bat) los genera al azar y los escribe en un.env. No hay que elegirlos ni teclearlos.
Si falta alguno, el stack no arranca y dice cuál. Es deliberado: más vale
un fallo visible que una base de datos creada con la contraseña vacía. La
plantilla está en .env.production.example.
El resto de claves —las de Google, Zertiauth, Stripe, PK…— no detienen el
arranque: sin ellas el sistema funciona y sólo se pierde la función que dependa
de cada una. Ver Gestión de secretos.
Entre ellos están la clave secreta de Stripe, una clave privada de
blockchain y ZERTIAUTH_APP_SECRET, que es una clave maestra: permite
derivar la cartera de cualquier usuario.
Esta página explica qué significa cada valor, esté donde esté definido.
Base de datos
| Variable | Tipo | Descripción |
|---|---|---|
DATABASE_URL | string | Cadena de conexión que usa Prisma. Formato mysql://usuario:password@host:puerto/base. Con el Docker local: mysql://root:root@127.0.0.1:3306/zertipower-dev. |
DB_HOST | string | Host que usan las consultas SQL directas (mysql2), independientes de Prisma. |
DB_USER | string | Usuario para esas consultas directas. |
DB_PASSWORD | string | Contraseña para esas consultas directas. |
DB_DATABASE | string | Nombre de la base de datos. |
El backend usa Prisma y consultas SQL crudas con mysql2. Prisma lee
DATABASE_URL; las consultas crudas leen DB_HOST/DB_USER/DB_PASSWORD/DB_DATABASE.
Si ambos grupos no apuntan al mismo sitio, obtendrás errores incoherentes muy difíciles
de diagnosticar. Manténlos sincronizados.
Servidor
| Variable | Tipo | Descripción |
|---|---|---|
PORT | int | Puerto de escucha de la API. Por defecto 3000. |
JWT_SECRET | string | Clave de firma de los tokens JWT — y bastante más, ver el aviso de abajo. |
APPLICATION_NAME | string | Nombre que aparece en los logs. Normalmente API. |
VIEWS_FOLDER | string | Carpeta de plantillas hbs (correo, páginas públicas). Valor esperado: src/shared/infrastructure/views/public. |
JWT_SECRET es una clave maestra, no sólo la de las sesionesEl backend la reutiliza para cuatro cosas que no tienen nada que ver entre sí:
| Uso | Dónde |
|---|---|
| Firmar y verificar los tokens de sesión | auth/infrastructure/services/jose-jwt/JoseJWT.service.ts |
| Cifrar y descifrar las claves privadas guardadas en la base de datos | auth/…/auth.controller.ts, communities/communities.controller.ts |
Derivar la cartera de cada comunidad — JWT_SECRET + nombre | communities/communities.controller.ts |
Derivar carteras por referencia — keccak256(referencia + JWT_SECRET) | shared/infrastructure/services/contract-helpers.ts, minter-service.ts |
| Cifrar y descifrar las credenciales de Datadis de cada CUPS | cups/cups.controller.ts, customers/customers.controller.ts, communities/communities.controller.ts |
Consecuencia: cambiarla no cierra sólo las sesiones. Deja ilegibles las claves privadas que ya estaban cifradas y las credenciales de Datadis —con lo que el sistema deja de poder descargar los datos de consumo— y cambia las direcciones de las carteras derivadas de comunidades y referencias.
En un sistema que ya tiene datos, rotarla es una migración —hay que descifrar y
volver a cifrar con la clave nueva, y asumir que las carteras derivadas cambian—,
no un cambio de configuración. Está al mismo nivel que ZERTIAUTH_APP_SECRET.
En una instalación nueva, sin datos, se elige libremente: openssl rand -base64 48.
Lo comparten tres servicios (backend, smart-meter-backend y
realtime-energy-api) y el valor debe ser idéntico en los tres, porque unos
firman tokens que otros verifican.
URLs de los frontends
| Variable | Tipo | Descripción |
|---|---|---|
FRONTEND_URL | string | URL del Panel de Administración (http://localhost:4201). Se usa en redirecciones, no en CORS. |
COMPTADOR_FRONTEND_URL | string | URL del Contador / Smart Meter (http://localhost:4200). |
La Calculadora no tiene variable propia y no la necesita: CORS es permisivo
(cors: true en main.ts) y la Calculadora no recibe redirecciones del backend.
Google OAuth
Estas variables son las del botón «Iniciar sesión con Google» del Panel. El Contador no las usa: delega su login en Zertiauth, que tiene su propio cliente. Cómo crear el cliente, pantalla por pantalla, en Acceso con Google, paso a paso.
| Variable | Tipo | Descripción |
|---|---|---|
GOOGLE_CLIENT_ID | string | Client ID de OAuth del Panel, propio de cada despliegue. No es secreto: viaja en la URL a la que Google redirige. Opcional: sin él el sistema arranca y sólo deja de funcionar el botón «Iniciar sesión con Google»; se entra con usuario y contraseña. |
GOOGLE_CLIENT_SECRET | string | Client secret del mismo cliente. Secreto. Opcional, igual que el ID: sin él sólo deja de funcionar ese botón. Mezclarlo con el ID de otro cliente da invalid_client. |
GOOGLE_CALLBACK_URL | string | A dónde devuelve Google al usuario tras autenticarse. Debe coincidir exactamente con la URI registrada en Google Cloud Console, o Google responde redirect_uri_mismatch. |
GOOGLE_MAPS_API_KEY | string | Clave de Google Maps, para geocodificar direcciones. Opcional: sin ella el sistema arranca y sólo falla esa conversión. La comparten el Panel y la Calculadora, allí como argumento de construcción. Es de navegador: se protege restringiéndola por dominio, no ocultándola. |
Derivación de carteras
| Variable | Tipo | Descripción |
|---|---|---|
ZERTIAUTH_APP_ID | string | Identificador de la aplicación. No es secreto: ya aparece en el código de los frontends. |
ZERTIAUTH_APP_SECRET | string | Secreto de la aplicación (columna secret de la tabla apps de Zertiauth). Clave maestra. Opcional: sólo se usa al derivar la cartera en el primer acceso con Google de cada usuario. Vacía es segura —falla con un error claro—; inventada no, porque deriva carteras equivocadas sin avisar. |
La cartera de cada usuario se deriva así:
privateKey = keccak256("<idGoogle>-<ZERTIAUTH_APP_ID>-<ZERTIAUTH_APP_SECRET>")
Si cambia cualquiera de las dos, todas las carteras cambian y los usuarios
pierden el acceso a sus cuentas y a lo que tengan on-chain. Y como el id de
Google no es secreto, quien tenga ZERTIAUTH_APP_SECRET puede derivar la clave
privada de cualquier usuario.
Servicios externos
| Variable | Tipo | Descripción |
|---|---|---|
RADIATION_API | string | Endpoint del servicio de radiación solar (Wattabit). |
RADIATION_API_CREDENTIALS | string | Credenciales en formato literal usuario:password. El separador : es obligatorio. |
ENERGY_PREDICTION_API | string | Endpoint del servicio de predicción (repositorio zp_energy_pred). |
DATADIS_MONTHS | int | Meses de histórico a descargar de Datadis en cada sincronización. |
TRADE_UPDATE_DAYS | string | Ventana en días para recalcular los intercambios de energía. |
Estos servicios se consumen contra los endpoints reales también en local: no hay mocks. Sin conectividad, las tareas programadas que los usan fallan, pero el arranque del backend no se ve afectado.
Blockchain
| Variable | Tipo | Descripción |
|---|---|---|
PK | string | Clave privada (64 caracteres hexadecimales) con la que se firman las transacciones on-chain. Opcional: sin ella el sistema arranca y sólo queda inerte la capa blockchain. El instalador genera una al azar para no tener que preguntarla, pero es una cartera nueva, sin fondos ni permisos sobre los contratos: sirve para arrancar, no para firmar. |
PK es una clave privada. Quien la posea controla la wallet asociada y sus fondos.
No la escribas en tickets, capturas ni documentación.
Stripe
| Variable | Tipo | Descripción |
|---|---|---|
STRIPE_PRODUCT_ID | string | Identificador del producto (prod_…). |
STRIPE_PRICE_KEY | string | Identificador del precio (price_…). |
STRIPE_SECRET_KEY | string | Clave secreta de la API. Opcional: sin ella el sistema arranca y sólo dejan de funcionar los endpoints /stripe, que usa una única pantalla del Contador. En local debe ser siempre una clave de test (sk_test_…). |
SMTP
| Variable | Tipo | Descripción |
|---|---|---|
SMTP_USER | string | Usuario del servidor de correo. |
SMTP_DISPLAY_EMAIL | string | Dirección que aparece como remitente. |
SMTP_PASSWORD | string | Contraseña SMTP. |
SMTP_SERVER | string | Host del servidor SMTP. |
SMTP_PORT | int | Puerto, habitualmente 465 (SSL). |
En local pueden dejarse valores ficticios: el backend arranca igualmente y sólo fallará el envío real de correo (recuperación de contraseña, notificaciones).
Frontends: no usan .env
Los tres frontends Angular se configuran mediante archivos TypeScript en
src/environments/:
| Módulo | Archivo | Clave a apuntar al backend |
|---|---|---|
| Panel Admin | frontend/src/environments/environment.development.ts | api_url: "http://localhost:3000" |
| Calculadora | calculadora/src/environments/environment.development.ts | api_url: "http://localhost:3000" |
| Contador | ris3cat-smart-meter/src/environments/environment.development.ts | zertipower_url: "http://localhost:3000" |
ng serve usa la configuración development, que sustituye environment.ts por
environment.development.ts mediante fileReplacements en angular.json.