# 99-kitchen-sink — every chart feature exercised in one release.
# DO NOT deploy verbatim. Use as a reference; copy sections into a real values file.

# Pins the name prefix on every resource, so the Ingress backends further down can
# name the Service the chart renders instead of guessing at the release name.
fullnameOverride: kitchen-sink

# Cluster-wide env (subchart "global:" mechanism — propagates everywhere)
global:
  env:
    OTEL_EXPORTER_OTLP_ENDPOINT:
      value: http://otel-collector.observability:4318

# Release-level env applied to every workload in this release
env:
  SERVICE_NAME:
    value: kitchen-sink
  ENVIRONMENT:
    value: prod

commonLabels:
  cost-center: platform
  team: orders
commonAnnotations:
  owner: orders-team@example.com

# Standard label toggles — leave defaults except suppress version on singletons
labels:
  standard:
    enabled: true

# ---- Integrations ----------------------------------------------------------------------

integrations:

  argocd:
    syncWaves:
      enabled: true                # use chart defaults; override one only
      ingress: 40                  # push Ingress to wave 40 because we apply a custom CRD at 35
    imageUpdater:
      enabled: true
      namespace: argocd            # CR lives in argocd namespace
      appNamePattern: kitchen-sink
      commonUpdateSettings:
        updateStrategy: digest
        allowTags: "regexp:^v[0-9]+\\.[0-9]+\\.[0-9]+$"
      writeBackConfig:
        method: argocd
      images:
        api:
          imageName: ghcr.io/example/api
          manifestTargets:
            helm:
              name: deployments.api.image.repository
              tag: deployments.api.image.tag

  stakater:
    reloader:
      enabled: true                # default auto-strategy: reloader.stakater.com/auto: "true"

  eso:
    enabled: true
    secretStores:
      vault:
        enabled: true
        kind: SecretStore
        provider:
          vault:
            server: https://vault.example.com
            path: secret
            version: v2
            auth:
              jwt:
                mountPath: jwt
                role: kitchen-sink
                audiences:
                  - vault
                expirationSeconds: 600
    externalSecrets:
      api-secrets:
        enabled: true
        secretStore: vault
        refreshInterval: 1h
        targetName: api-secrets
        data:
          API_TOKEN:
            remoteKey: kitchen-sink/api
            property: token
          DB_PASSWORD:
            remoteKey: kitchen-sink/db
            property: password
      worker-bulk:
        enabled: true
        secretStore: vault
        refreshInterval: 1h
        dataFrom:
          - remoteKey: kitchen-sink/worker
            conversionStrategy: Default
            decodingStrategy: None

  monitoring:
    defaults:
      enabled: true
      provider: victoriametrics    # VMServiceScrape / VMPodScrape
      discovery: crd
      type: service
      port: metrics
      path: /metrics
      interval: 30s
      scrapeTimeout: 10s
      exposeService:
        enabled: true              # auto-add metrics port to Services that don't declare one
        port: 9090
        targetPort: 9090

# ---- Networking ------------------------------------------------------------------------

# Singleton HTTPRoute — per-workload shorthand merges into this.
httpRoute:
  enabled: true
  parentRefs:
    - name: external
      namespace: gateway-system
      sectionName: https
  hostnames:
    - "app.example.com"

# Cross-namespace ReferenceGrant for the Gateway in gateway-system to reach our Services.
referenceGrant:
  enabled: true
  from:
    - group: gateway.networking.k8s.io
      kind: HTTPRoute
      namespace: gateway-system
  to:
    - group: ""
      kind: Service

# Two Ingresses: internal east-west + external (kept alongside HTTPRoute for legacy clients).
ingresses:
  internal:
    enabled: true
    ingressClassName: nginx-internal
    hosts:
      app.internal.example.com:
        paths:
          - path: /
            pathType: Prefix
            serviceName: kitchen-sink-api
            servicePort: 80
  external:
    enabled: true
    ingressClassName: nginx
    annotations:
      cert-manager.io/cluster-issuer: letsencrypt-prod
    hosts:
      app.example.com:
        paths:
          - path: /
            pathType: Prefix
            serviceName: kitchen-sink-api
            servicePort: 80
    tls:
      - hosts:
          - "app.example.com"
        secretName: app-example-tls

# ---- Cluster-wide policies / scheduling ------------------------------------------------

podDisruptionBudget:
  enabled: true
  minAvailable: 1

topologySpreadConstraints:
  - maxSkew: 1
    topologyKey: topology.kubernetes.io/zone
    whenUnsatisfiable: ScheduleAnyway

verticalPodAutoscaler:
  enabled: false                   # off at root; opted in per workload below

# Default image (used when a workload doesn't override).
image:
  repository: ghcr.io/example/api
  tag: v1.4.2
  pullPolicy: IfNotPresent

imagePullSecrets:
  - regcred-prod

envSecrets:
  - api-secrets                    # resolves to ESO-managed Secret named api-secrets

envConfigMaps:
  - app-config                     # chart-owned (declared below) — chart-owned wins

configMaps:
  app-config:
    enabled: true
    mountPath: /etc/app
    data:
      logging.yaml: |
        level: info
        format: json

serviceAccount:
  create: true
  name: kitchen-sink

rbac:
  enabled: true
  rules:
    - apiGroups:
        - ""
      resources:
        - "configmaps"
      verbs:
        - "get"
        - "list"
        - "watch"

automountServiceAccountToken: true

# ---- Deployments -----------------------------------------------------------------------

deployments:

  api:
    enabled: true
    replicaCount: 3
    # image inherited from root (.Values.image)
    service:
      enabled: true
      type: ClusterIP
      ports:
        # Order-irrelevant in source; chart renders http first, metrics last (ADR 014)
        admin:
          port: 8081
          targetPort: 8081
        http:
          port: 80
          targetPort: 8080
        grpc:
          port: 9000
          targetPort: 9000
        metrics:
          port: 9090
          targetPort: 9090

    metrics:
      enabled: true
      port: metrics

    httpRoute:
      enabled: true
      priority: 10
      rules:
        - matches:
            - path:
                type: PathPrefix
                value: /api

    hpa:
      enabled: true
      minReplicas: 3
      maxReplicas: 20
      metrics:
        - type: Resource
          resource:
            name: cpu
            target:
              type: Utilization
              averageUtilization: 70

    sidecars:
      otel-collector:
        image:
          repository: otel/opentelemetry-collector-contrib
          tag: "0.103.0"
        args:
          - "--config=/etc/otel/config.yaml"
        ports:
          otlp:
            containerPort: 4318
        resources:
          requests:
            cpu: 50m
            memory: 64Mi
          limits:
            memory: 128Mi

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

  worker:
    enabled: true
    image:
      repository: ghcr.io/example/worker
      tag: v0.9.0
    service:
      enabled: false               # no main service; auto metrics-only Service is emitted (ADR 016)
    metrics:
      enabled: true
      type: pod                    # PodMonitor / VMPodScrape — no Service needed for scrape

    inherit:
      env:
        global: false              # this worker doesn't talk to OTel collector
      configMapMount:
        app-config: false          # don't auto-mount the chart-owned configmap here

    keda:
      enabled: true
      minReplicas: 1
      maxReplicas: 30
      pollingInterval: 30
      cooldownPeriod: 300
      triggers:
        - type: kafka
          metadata:
            bootstrapServers: kafka.kafka:9092
            consumerGroup: kitchen-sink-worker
            topic: orders
            lagThreshold: "100"

    verticalPodAutoscaler:
      enabled: true
      updateMode: Initial

    resources:
      requests:
        cpu: 100m
        memory: 256Mi
      limits:
        memory: 512Mi

# ---- StatefulSet -----------------------------------------------------------------------

statefulSets:

  db:
    enabled: true
    replicaCount: 1
    image:
      repository: postgres
      tag: "16.3"
    service:
      enabled: true
      clusterIP: None              # headless
      ports:
        postgres:
          port: 5432
          targetPort: 5432
    metrics:
      enabled: false               # postgres-exporter not in this example

    volumeClaimTemplates:
      - metadata:
          name: data
        spec:
          accessModes:
            - ReadWriteOnce
          storageClassName: standard
          resources:
            requests:
              storage: 10Gi

    volumeMounts:
      data:
        mountPath: /var/lib/postgresql/data

    env:
      POSTGRES_DB:
        value: kitchen
      POSTGRES_USER:
        value: app

    envSecrets:
      - api-secrets                # picks up DB_PASSWORD from the same ESO secret

    resources:
      requests:
        cpu: 100m
        memory: 256Mi
      limits:
        memory: 1Gi

# ---- jobGroups -------------------------------------------------------------------------

jobGroups:

  migrations:
    enabled: true
    kind: Job
    image:
      repository: ghcr.io/example/migrator
      tag: v1.0.0
    envSecrets:
      - api-secrets                # need DB_PASSWORD
    hooks:
      argocd:
        hook: PreSync
        syncWave: "-2"
    hashSuffix: true
    jobs:
      schema:
        enabled: true
        # Tasks run in the alphabetical order of their map keys (Kubernetes runs
        # initContainers sequentially); prefix names with 01-, 02- to make ordering explicit.
        tasks:
          01-structure:
            command: |
              psql -c "CREATE TABLE IF NOT EXISTS ..."
          02-seed:
            args:
              - "seed"
              - "--rows=100"
        backoffLimit: 2
        ttlSecondsAfterFinished: 3600

  nightly:
    enabled: true
    kind: CronJob
    image:
      repository: ghcr.io/example/cleaner
      tag: v0.5.0
    jobs:
      cleanup:
        enabled: true
        schedule: "0 2 * * *"
        timeZone: UTC
        concurrencyPolicy: Forbid
        successfulJobsHistoryLimit: 3
        failedJobsHistoryLimit: 1
        command: ./cleanup.sh
