> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lerian.studio/llms.txt
> Use this file to discover all available pages before exploring further.

# Referencia de values para producción

> Referencia anotada de values.yaml lista para producción para desplegar Midaz en Kubernetes con Helm, que cubre ingress, recursos, bases de datos y observabilidad.

<Warning>
  Los values de `crm` que se conservan en esta página configuran el workload de compatibilidad legacy del Helm chart. Midaz v4 despliega CRM a través del Ledger unificado, no mediante este workload.
</Warning>

Esta es una referencia completa y anotada de `values.yaml` para despliegues de producción. Cópiala, adapta los placeholders a tu entorno y despliega.

<Warning>
  Esta es una **configuración de referencia**. Debes reemplazar todos los valores de placeholder (marcados con `{...}`) por los datos reales de tu infraestructura antes de desplegar.
</Warning>

## Cómo usarla

***

1. Copia la configuración completa de abajo en un archivo llamado `values-production.yaml`
2. Reemplaza todos los placeholders `{...}` por tus valores reales
3. Revisa cada sección y ajusta los límites de recursos para la carga de trabajo que esperas
4. Despliega:

```bash theme={null}
helm install midaz oci://registry-1.docker.io/lerianstudio/midaz-helm \
  --version <version> \
  -n midaz \
  --create-namespace \
  -f values-production.yaml
```

## Values completos de producción

***

<Warning>
  La **Ledger Settings API** reemplaza las variables de entorno obsoletas `ACCOUNT_TYPE_VALIDATION` y `TRANSACTION_ROUTE_VALIDATION`. Usa `PATCH /v1/organizations/{org_id}/ledgers/{ledger_id}/settings` para configurar la validación contable por ledger.
</Warning>

```yaml expandable theme={null}
# =============================================================================
# Midaz Production Values Reference
# =============================================================================
# This file configures Midaz for a production Kubernetes environment with:
# - Unified Ledger service
# - External databases (PostgreSQL, MongoDB, RabbitMQ, Valkey/Redis)
# - Ingress with TLS
# - Observability enabled
# - CRM enabled
# - High availability with autoscaling
# =============================================================================

# -- Global name overrides
nameOverride: "midaz"
fullnameOverride: ""
namespaceOverride: "midaz"

# =============================================================================
# GLOBAL: External database bootstrap jobs
# =============================================================================
# These jobs run once on install to create databases, users, and permissions.
# Enable them when using external (non-bundled) databases.

global:
  # -- Bootstrap job for external PostgreSQL
  externalPostgresDefinitions:
    enabled: true
    connection:
      host: "{your-postgres-host}"       # e.g., "prod-postgres.example.com"
      port: "5432"
    postgresAdminLogin:
      # Recommended: use an existing Kubernetes Secret
      useExistingSecret:
        name: "{your-postgres-admin-secret}"  # Must contain DB_USER_ADMIN and DB_ADMIN_PASSWORD keys
      # Alternative: inline credentials (NOT recommended for production)
      # username: "postgres"
      # password: "{your-admin-password}"
    midazCredentials:
      useExistingSecret:
        name: "{your-midaz-credentials-secret}"  # Must contain DB_PASSWORD_MIDAZ key
      # Alternative: inline
      # password: "{your-midaz-password}"

  # -- Bootstrap job for external RabbitMQ
  externalRabbitmqDefinitions:
    enabled: true
    connection:
      protocol: "https"                   # Use "https" for production
      host: "{your-rabbitmq-host}"        # e.g., "prod-rabbitmq.example.com"
      port: "15672"                       # HTTP management port
      portAmqp: "5672"                    # AMQP port
    rabbitmqAdminLogin:
      useExistingSecret:
        name: "{your-rabbitmq-admin-secret}"  # Must contain RABBITMQ_ADMIN_USER and RABBITMQ_ADMIN_PASS
    appCredentials:
      useExistingSecret:
        name: "{your-rabbitmq-app-credentials}"  # Must contain RABBITMQ_DEFAULT_PASS and RABBITMQ_CONSUMER_PASS

# =============================================================================
# LEDGER: Unified service (recommended for new installations)
# =============================================================================
# The Ledger service combines onboarding and transaction into a single
# deployment. This is the recommended approach for all new installations.

ledger:
  enabled: true

  # -- High availability: start with 3 replicas
  replicaCount: 3

  image:
    repository: lerianstudio/midaz-ledger
    pullPolicy: IfNotPresent
    tag: ""  # Defaults to Chart.AppVersion; pin a specific version for production

  # -- Security context (non-root, read-only filesystem)
  securityContext:
    runAsGroup: 1000
    runAsUser: 1000
    runAsNonRoot: true
    capabilities:
      drop:
        - ALL
    readOnlyRootFilesystem: true

  # -- PodDisruptionBudget: ensure at least 2 pods during disruptions
  pdb:
    enabled: true
    minAvailable: 2
    maxUnavailable: 1

  # -- Rolling update with zero downtime
  deploymentUpdate:
    type: RollingUpdate
    maxSurge: 1
    maxUnavailable: 0

  service:
    type: ClusterIP
    port: 3002

  # -- Ingress with TLS
  ingress:
    enabled: true
    className: "{your-ingress-class}"     # e.g., "nginx", "alb", "traefik"
    annotations:
      # NGINX example:
      nginx.ingress.kubernetes.io/proxy-body-size: "10m"
      nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
      # AWS ALB example (uncomment if using ALB):
      # alb.ingress.kubernetes.io/scheme: internal
      # alb.ingress.kubernetes.io/target-type: ip
      # alb.ingress.kubernetes.io/group.name: "midaz"
    hosts:
      - host: "{your-midaz-api-domain}"   # e.g., "api.midaz.example.com"
        paths:
          - path: /
            pathType: Prefix
    tls:
      - secretName: "{your-tls-secret}"   # e.g., "midaz-api-tls"
        hosts:
          - "{your-midaz-api-domain}"

  # -- Resource limits for production
  # Adjust based on your workload. These are starting recommendations.
  resources:
    requests:
      cpu: "1000m"
      memory: "512Mi"
    limits:
      cpu: "2000m"
      memory: "2Gi"

  # -- Autoscaling
  autoscaling:
    enabled: true
    minReplicas: 3
    maxReplicas: 10
    targetCPUUtilizationPercentage: 70
    targetMemoryUtilizationPercentage: 80

  # -- Pod anti-affinity: spread across nodes for high availability
  affinity:
    podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
        - weight: 100
          podAffinityTerm:
            labelSelector:
              matchExpressions:
                - key: app.kubernetes.io/name
                  operator: In
                  values:
                    - ledger
            topologyKey: kubernetes.io/hostname

  # -- External database configuration
  configmap:
    ENABLE_TELEMETRY: "true"
    # Auth Plugin (enable if using access management)
    PLUGIN_AUTH_ENABLED: "false"
    PLUGIN_AUTH_HOST: ""
    # Accounting Configuration
    # Managed via Ledger Settings API. See PATCH /v1/organizations/{org_id}/ledgers/{ledger_id}/settings
    # Request body: {"accounting": {"validateRoutes": true, "validateAccountType": true}}
    # -- PostgreSQL: Onboarding module
    DB_ONBOARDING_HOST: "{your-postgres-host}"
    DB_ONBOARDING_USER: "midaz"
    DB_ONBOARDING_NAME: "onboarding"
    DB_ONBOARDING_PORT: "5432"
    DB_ONBOARDING_REPLICA_HOST: "{your-postgres-replica-host}"
    DB_ONBOARDING_REPLICA_USER: "midaz"
    DB_ONBOARDING_REPLICA_NAME: "onboarding"
    DB_ONBOARDING_REPLICA_PORT: "5432"
    # -- MongoDB: Onboarding module
    MONGO_ONBOARDING_URI: "mongodb"
    MONGO_ONBOARDING_HOST: "{your-mongodb-host}"
    MONGO_ONBOARDING_NAME: "onboarding"
    MONGO_ONBOARDING_USER: "midaz"
    MONGO_ONBOARDING_PORT: "27017"
    # -- PostgreSQL: Transaction module
    DB_TRANSACTION_HOST: "{your-postgres-host}"
    DB_TRANSACTION_USER: "midaz"
    DB_TRANSACTION_NAME: "transaction"
    DB_TRANSACTION_PORT: "5432"
    DB_TRANSACTION_REPLICA_HOST: "{your-postgres-replica-host}"
    DB_TRANSACTION_REPLICA_USER: "midaz"
    DB_TRANSACTION_REPLICA_NAME: "transaction"
    DB_TRANSACTION_REPLICA_PORT: "5432"
    # -- MongoDB: Transaction module
    MONGO_TRANSACTION_URI: "mongodb"
    MONGO_TRANSACTION_HOST: "{your-mongodb-host}"
    MONGO_TRANSACTION_NAME: "transaction"
    MONGO_TRANSACTION_USER: "midaz"
    MONGO_TRANSACTION_PORT: "27017"
    # -- Redis/Valkey
    REDIS_HOST: "{your-redis-host}:6379"
    # -- RabbitMQ
    RABBITMQ_URI: "amqps"                 # Use "amqps" for TLS, "amqp" without
    RABBITMQ_HOST: "{your-rabbitmq-host}"
    RABBITMQ_PORT_HOST: "5672"
    RABBITMQ_PORT_AMQP: "15672"
    RABBITMQ_DEFAULT_USER: "transaction"
    RABBITMQ_CONSUMER_USER: "consumer"
    RABBITMQ_TRANSACTION_ASYNC: "false"
    # -- Audit
    AUDIT_LOG_ENABLED: "true"             # Enable audit logging for production
    # -- Balance Sync Worker
    BALANCE_SYNC_BATCH_SIZE: "100"
    BALANCE_SYNC_FLUSH_TIMEOUT_MS: "1000"
    BALANCE_SYNC_POLL_INTERVAL_MS: "500"

  # -- Use existing Kubernetes Secrets (recommended)
  useExistingSecret: true
  existingSecretName: "midaz-ledger"
  # Create this secret manually before deploying:
  # kubectl create secret generic midaz-ledger \
  #   --from-literal=DB_ONBOARDING_PASSWORD='{password}' \
  #   --from-literal=DB_ONBOARDING_REPLICA_PASSWORD='{password}' \
  #   --from-literal=MONGO_ONBOARDING_PASSWORD='{password}' \
  #   --from-literal=DB_TRANSACTION_PASSWORD='{password}' \
  #   --from-literal=DB_TRANSACTION_REPLICA_PASSWORD='{password}' \
  #   --from-literal=MONGO_TRANSACTION_PASSWORD='{password}' \
  #   --from-literal=REDIS_PASSWORD='{password}' \
  #   --from-literal=RABBITMQ_DEFAULT_PASS='{password}' \
  #   --from-literal=RABBITMQ_CONSUMER_PASS='{password}' \
  #   -n midaz

  serviceAccount:
    create: true
    annotations: {}

# =============================================================================
# CRM: Customer Relationship Management
# =============================================================================

crm:
  enabled: true

  replicaCount: 2

  image:
    repository: lerianstudio/midaz-crm
    pullPolicy: IfNotPresent
    tag: ""  # Defaults to Chart.AppVersion

  securityContext:
    runAsGroup: 1000
    runAsUser: 1000
    runAsNonRoot: true
    capabilities:
      drop:
        - ALL
    readOnlyRootFilesystem: true

  pdb:
    enabled: true
    minAvailable: 1
    maxUnavailable: 1

  service:
    type: ClusterIP
    port: 4003

  ingress:
    enabled: true
    className: "{your-ingress-class}"
    hosts:
      - host: "{your-crm-api-domain}"     # e.g., "crm.midaz.example.com"
        paths:
          - path: /
            pathType: Prefix
    tls:
      - secretName: "{your-crm-tls-secret}"
        hosts:
          - "{your-crm-api-domain}"

  resources:
    requests:
      cpu: "200m"
      memory: "256Mi"
    limits:
      cpu: "500m"
      memory: "512Mi"

  autoscaling:
    enabled: true
    minReplicas: 2
    maxReplicas: 5
    targetCPUUtilizationPercentage: 80
    targetMemoryUtilizationPercentage: 80

  configmap:
    ENV_NAME: "production"
    PLUGIN_AUTH_ENABLED: "false"
    PLUGIN_AUTH_ADDRESS: ""
    MONGO_HOST: "{your-mongodb-host}"
    MONGO_NAME: "crm"
    MONGO_PORT: "27017"
    MONGO_USER: "midaz"

  useExistingSecret: true
  existingSecretName: "midaz-crm"
  # Create this secret manually before deploying:
  # kubectl create secret generic midaz-crm \
  #   --from-literal=LCRYPTO_HASH_SECRET_KEY='{generate-a-random-64-hex-string}' \
  #   --from-literal=LCRYPTO_ENCRYPT_SECRET_KEY='{generate-a-random-64-hex-string}' \
  #   --from-literal=MONGO_PASSWORD='{password}' \
  #   -n midaz

# =============================================================================
# BUNDLED DEPENDENCIES: All disabled (using external databases)
# =============================================================================
# In production, use managed database services (AWS RDS, Atlas, etc.)
# instead of bundled containers.

postgresql:
  enabled: false

mongodb:
  enabled: false

rabbitmq:
  enabled: false

valkey:
  enabled: false

# =============================================================================
# OBSERVABILITY
# =============================================================================

# -- Inject OTEL env vars into the ledger, crm and tracer deployments.
# The schema accepts ONLY `enabled`. The exporter endpoint is fixed at
# $(HOST_IP):4317, so this needs an OTLP collector on every node.
# To export elsewhere, set enabled: false and put
# OTEL_EXPORTER_OTLP_ENDPOINT in each component's configmap instead.
otel-collector-lerian:
  enabled: true
```

<Warning>
  No agregues `external`, `extraEnvs`, `exporters` ni `opentelemetry-collector` bajo `otel-collector-lerian`. El esquema del chart es estricto y `helm install`/`helm upgrade` falla con `additional properties … not allowed`. Configuras el enrutamiento del collector (processors, exporters, claves de API) en el chart propio del collector, no aquí. Consulta [Configurar observabilidad](/es/platform/deploy/midaz/midaz-observability).
</Warning>

<Note>
  El chart no incluye plantillas de Grafana. Un bloque `grafana:` en tu archivo de values no renderiza nada.
</Note>

## Explicación de las decisiones principales

***

### ¿Por qué Ledger en lugar de Onboarding + Transaction?

El servicio `ledger` unificado es el enfoque recomendado para todas las instalaciones nuevas. Combina ambos módulos en un solo deployment, lo que reduce la carga operativa:

* Menos pods que gestionar y monitorear
* Configuración simplificada (un solo configmap/secret)
* Un solo endpoint de ingress
* Mejor uso de los recursos
* Pasará a ser la única opción en releases futuros

### ¿Por qué bases de datos externas?

Se recomienda que los despliegues de producción usen servicios de base de datos gestionados para:

* Backups automáticos y recuperación a un punto en el tiempo
* Alta disponibilidad con failover automático
* Monitoreo y alertas integrados
* Escalado sin downtime de la aplicación
* Parches de seguridad gestionados por el proveedor

Servicios gestionados recomendados:

| Dependencia  | AWS                               | GCP                   | Azure                         |
| :----------- | :-------------------------------- | :-------------------- | :---------------------------- |
| PostgreSQL   | Amazon RDS                        | Cloud SQL             | Azure Database for PostgreSQL |
| MongoDB      | Amazon DocumentDB o MongoDB Atlas | MongoDB Atlas         | Azure Cosmos DB (MongoDB API) |
| RabbitMQ     | Amazon MQ                         | Autogestionado en GKE | Autogestionado en AKS         |
| Redis/Valkey | Amazon ElastiCache                | Memorystore           | Azure Cache for Redis         |

### ¿Por qué usar Secrets de Kubernetes en lugar de contraseñas en línea?

Las contraseñas en línea en `values.yaml` son visibles en el historial del Helm release y pueden terminar en el control de versiones. Usar `useExistingSecret: true` con Secrets de Kubernetes creados previamente:

* Mantiene las credenciales fuera de los values de Helm
* Permite la rotación sin un Helm upgrade
* Se integra con herramientas de gestión de secrets (Vault, External Secrets Operator, Sealed Secrets)

### Anti-afinidad de pods

La regla `podAntiAffinity` distribuye los pods de Ledger entre nodos distintos, así que la falla de un solo nodo no tumba todo el servicio.

## Lista de verificación antes de desplegar

***

<Steps>
  <Step title="Crear los Secrets de Kubernetes">
    Crea todos los secrets requeridos en el namespace `midaz` antes de ejecutar `helm install`:

    * `midaz-ledger` (credenciales de base de datos y del message broker)
    * `midaz-crm` (claves de cifrado y contraseña de MongoDB)
    * `otel-api-key` (si usas la telemetría de Lerian)
  </Step>

  <Step title="Configurar el DNS">
    Apunta tus dominios a la IP externa del ingress controller:

    * `{your-midaz-api-domain}` → IP del ingress
    * `{your-crm-api-domain}` → IP del ingress
    * `{your-grafana-domain}` → IP del ingress (solo si ejecutas Grafana de forma independiente, ya que este chart no renderiza ninguno)
  </Step>

  <Step title="Provisionar los certificados TLS">
    Usa cert-manager para el provisionamiento automático de certificados o crea manualmente secrets de TLS para cada dominio.
  </Step>

  <Step title="Verificar la conectividad con las bases de datos">
    Confirma que tu cluster de Kubernetes puede alcanzar todas las bases de datos externas. Pruébalo con:

    ```bash theme={null}
    kubectl run test-pg --rm -it --image=postgres:17 -- \
      psql -h {your-postgres-host} -U midaz -d onboarding -c "SELECT 1"
    ```
  </Step>

  <Step title="Revisar los límites de recursos">
    Ajusta los límites de CPU y memoria según el volumen de transacciones que esperas. Usa los valores de esta referencia como punto de partida para cargas de trabajo moderadas.
  </Step>

  <Step title="Desplegar">
    ```bash theme={null}
    helm install midaz oci://registry-1.docker.io/lerianstudio/midaz-helm \
      --version <version> \
      -n midaz \
      --create-namespace \
      -f values-production.yaml
    ```
  </Step>

  <Step title="Verificar el despliegue">
    ```bash theme={null}
    kubectl get pods -n midaz -o wide
    kubectl get ingress -n midaz
    helm list -n midaz
    ```
  </Step>
</Steps>

## Recursos relacionados

***

* [Usar Helm](/es/platform/deploy/midaz/midaz-installation) - Guía de instalación completa con todas las opciones de configuración
* [Actualizar Midaz](/es/platform/deploy/midaz/midaz-upgrade-guide) - Procedimientos de actualización paso a paso
* [Solución de problemas](/es/platform/deploy/midaz/midaz-troubleshooting) - Diagnóstico de problemas comunes de despliegue
* [Desinstalar Midaz](/es/platform/deploy/midaz/midaz-uninstall) - Procedimientos de limpieza
* [Código fuente del Helm chart](https://github.com/LerianStudio/helm) - `values.yaml` completo con todos los parámetros disponibles
