Skip to main content

Configuración y despliegue

1. Variables de entorno

Todas son de servidor (ninguna con prefijo NEXT_PUBLIC_). En local se definen en .env.local (ignorado por git); en el clúster proceden del Secret de Kubernetes customer-back-office.

Auth0 (sesión de empleado)

VariableDescripciónValor de referencia
AUTH0_SECRETSecreto de cifrado de la cookie de sesión del SDKsecreto
APP_BASE_URLURL base de la app; el SDK la usa para el callback y los redirectshttp://localhost en local
AUTH0_DOMAINTenant de Auth0https://robo-hawkers.eu.auth0.com
AUTH0_ISSUER_BASE_URLIssuer del tenantigual que el dominio
AUTH0_CLIENT_IDClient ID de la aplicaciónsecreto
AUTH0_CLIENT_SECRETClient secretsecreto
AUTH0_AUDIENCEAudience del API — permite usar el access token contra robo-apihttps://robo-api.hawkersco.net
AUTH0_SCOPEScopes solicitados. Debe pasarse explícitamente en el SDK v4openid profile email admin atc customer store

robo-api

VariableDescripciónValor de referencia
ROBO_API_URLURL base de robo-apihttps://robo-api.hawkersco.net

Marketing Cloud

VariableDescripción
MC_AUTH_URLEndpoint /v2/token del tenant
MC_API_URLEndpoint REST base del tenant
MC_CLIENT_IDClient ID del paquete instalado
MC_CLIENT_SECRETClient secret
MC_EVENT_KEY_CREATEDEventDefinitionKey del journey de creación
MC_EVENT_KEY_APPROVEDEventDefinitionKey del journey de aprobación
MC_EVENT_KEY_REFUNDEDEventDefinitionKey del journey de reembolso (sin uso hoy)

PDF y pruebas

VariableDescripción
PDF_SIGNATURE_SECRETSecreto HMAC de las URLs de PDF. Debe ser idéntico al del portal del cliente
TEST_EMAILEmail que reemplaza al del cliente en los journeys cuando NODE_ENV !== "production"
API_TEST_HEADERCabecera de modo de pruebas de robo-api — X-Test-Mode
API_TEST_HEADER_VALUEValor de esa cabecera (true). Solo se envía si NODE_ENV !== "production"

En total, 19 variables. No hay .env.example en el repositorio.

2. Ejecución en local

Requisitos: Node 22 (.nvmrc) y npm.

nvm use
npm install
npm run dev # next dev --turbopack -p 80 → http://localhost
  • El puerto es el 80 en dev y en start, coherente con la imagen y el manifiesto de Kubernetes. APP_BASE_URL=http://localhost (sin puerto) debe coincidir con eso, o el callback de Auth0 fallará.
  • La URL de callback (http://localhost/auth/callback) tiene que estar dada de alta en la aplicación de Auth0.
  • Se necesita un .env.local con las ocho AUTH0_*, ROBO_API_URL y PDF_SIGNATURE_SECRET como mínimo. Sin las MC_*, todo funciona salvo el envío de emails.
  • Con API_TEST_HEADER=X-Test-Mode y API_TEST_HEADER_VALUE=true, las escrituras van a las tablas sombra de robo-api: es el modo recomendado para desarrollar.
  • El usuario con el que se entre debe tener rol ADMIN en Auth0 para ver todas las secciones; con otro rol solo se verá Devoluciones.
  • .vscode/launch.json incluye una configuración Debug Next.js que arranca npm run dev con NODE_OPTIONS=--inspect en el puerto 9229.
note

El README.md del repositorio es el generado por create-next-app y no se ha actualizado: menciona http://localhost:3000, que no es el puerto de este proyecto.

Otros comandos: npm run build, npm start, npm run lint.

3. Imagen Docker

Dockerfile multi-stage, ambas etapas sobre node:22-alpine (coincide con .nvmrc) y con libc6-compat instalado en las dos:

  1. builder: npm cache clean --force && npm ci --legacy-peer-deps y npm run build.
  2. runner: copia public, .next, node_modules y package.json, crea el usuario no-root appuser:appgroup, hace chown -R sobre /app, cambia a USER appuser, EXPOSE 80 y arranca con npm start.

--legacy-peer-deps es necesario por conflictos de peer dependencies del árbol actual; quitarlo requiere resolver esos conflictos primero.

4. Pipeline de Jenkins

Jenkinsfile declarativo con tres etapas, idéntico en estructura al del portal del cliente:

EtapaAcción
Checkoutcheckout scm
Build & Pushgcloud builds submit --tag <REGISTRY>/customer-back-office:<BUILD_NUMBER> (Cloud Build → Artifact Registry)
DeployCredenciales del clúster, borrado del deployment anterior, sed del tag en k8s/deployment.yaml, kubectl apply y kubectl rollout status
VariableValor
GCP_PROJECTpi-saldum
GKE_CLUSTERpi-cluster-hw
GKE_ZONEeurope-west3-a
REGISTRYeurope-west3-docker.pkg.dev/pi-saldum/pi-repo
IMAGE_NAMEcustomer-back-office
GKE_NAMESPACEpi

Ojo con el nombre: la imagen, el deployment y el Secret se llaman customer-back-office, no customer-back-office-returns-portal como el repositorio.

El deploy borra el Deployment y espera a que mueran los pods antes de reaplicarlo, así que hay corte de servicio de unos segundos en cada release.

Una revisión anterior del pipeline incluía análisis con SonarQube; se eliminó (commit 2846e89).

5. Kubernetes (k8s/deployment.yaml)

PropiedadValor
Namespacepi
Réplicas1
EstrategiaRecreate
Imagen…/pi-repo/customer-back-office:latest (placeholder; sed lo sustituye)
imagePullPolicyIfNotPresent
containerPort80 (coincide con el puerto real de la app)
ConfiguraciónenvFrom.secretRef: customer-back-office
automountServiceAccountTokenfalse
Requests256 Mi memoria / 100m CPU / 256 Mi ephemeral-storage
Limits512 Mi memoria / 500m CPU / 512 Mi ephemeral-storage

El repositorio solo contiene el Deployment: el Service y el Ingress se gestionan fuera.

6. Manejo de errores y logging

  • Las funciones de actions/ lanzan Error(DEFAULT_ERROR_MESSAGE) — un mensaje genérico en español del diccionario — cuando la respuesta de robo-api no es OK. El detalle del error de la API no llega al usuario.
  • Los route handlers devuelven 500 con "Failed to fetch data" y hacen console.log(error).
  • En cliente, fetchWrapper (en services/api.ts) centraliza el tratamiento: los 401 con missing_session / missing_refresh_token redirigen a login/logout, y cualquier otro fallo se convierte en DEFAULT_ERROR_MESSAGE mostrado como toast de sonner.
  • Cada ruta del dashboard tiene su loading.tsx, pero los error.tsx solo existen en cuatro segmentos — returns, methods, methods/[id] y reasons/[id] —, así que en el resto (returns/[id], reasons, users, warehouses) un error de carga sube al error boundary global de Next.js.
  • No hay integración con Sentry ni logging estructurado: solo console.log/console.error, visibles en los logs del pod.