global:
  # When set, ALL Catalyst-authored container image pulls route through this
  # registry. Post-handover: per-Sovereign overlays set this to
  # harbor.<sovereign-fqdn> so every image pull hits the Sovereign's own Harbor
  # proxy_cache rather than ghcr.io directly. Empty = no rewrite (image refs
  # use `images.registry` / `images.organization` defaults below). Tracked
  # under #560.
  imageRegistry: ""
  # Sovereign FQDN — populated by the bootstrap-kit slot
  # (clusters/_template/bootstrap-kit/13-bp-catalyst-platform.yaml) from
  # the ${SOVEREIGN_FQDN} envsubst. Consumed by api-deployment.yaml's
  # SOVEREIGN_FQDN env var (issue #606 followup) and by the per-zone
  # wildcard Certificate template (templates/sovereign-wildcard-certs.yaml,
  # issue #827) when parentZones is empty (single-zone fallback).
  sovereignFQDN: ""

# ─── Multi-zone parent domains (issue #827, parent epic #825) ──────────
# A franchised Sovereign supports N parent zones, NOT one. The operator
# brings 1+ parent domains at signup (`omani.works` for own use,
# `omani.trade` for the SME pool, etc.) and may add more post-handover
# via the admin console (#829). The wildcard Certificate template
# (templates/sovereign-wildcard-certs.yaml) renders ONE Certificate
# resource per entry below, each requesting `*.<zone>` + apex from the
# `letsencrypt-dns01-prod-powerdns` ClusterIssuer (shipped by
# bp-cert-manager-powerdns-webhook). Each cert renews independently;
# a stalled DNS-01 challenge on `omani.trade` does not block the
# `omani.works` cert from rolling.
#
# Per docs/INVIOLABLE-PRINCIPLES.md #4 (never hardcode) the zones list
# is fully data-driven. Default empty: when parentZones is empty the
# chart renders ZERO per-zone Certificates and the legacy
# clusters/_template/sovereign-tls/cilium-gateway-cert.yaml owns the
# single-zone wildcard cert. This avoids the helm-controller vs
# kustomize-controller ownership flap on `sovereign-wildcard-tls`.
# Once every active Sovereign has migrated to multi-zone overlays the
# legacy file is deletable.
#
# Each entry:
#   - name (required): apex domain. The Certificate is requested for
#     `*.<name>` + `<name>` (apex).
#   - role (optional): operator-meaningful tag — "primary" or
#     "sme-pool". Carried in resource labels for ops visibility.
#   - secretName (optional): K8s Secret name the Cert is written to.
#     Defaults to `sovereign-wildcard-tls-<sanitised-name>` when
#     unset. The Cilium Gateway listener for that zone references
#     this secret in its certificateRefs block.
parentZones: []

# ─── Per-zone wildcard Certificate (issue #827) ───────────────────────
# Rendered into templates/sovereign-wildcard-certs.yaml. One Certificate
# per entry in `parentZones` (or single fallback from
# global.sovereignFQDN). Each Certificate uses the
# `letsencrypt-dns01-prod-powerdns` ClusterIssuer shipped by
# bp-cert-manager-powerdns-webhook (bootstrap-kit slot 49).
wildcardCert:
  # Toggle the entire render. Default true so a Sovereign install
  # gets its wildcard certs out of the box. Operators that wire certs
  # via an external mechanism (e.g. a centralised cert-manager in a
  # different namespace) flip this off.
  enabled: true
  # Namespace the Certificate(s) land in. MUST match the namespace
  # the Cilium Gateway lives in so the resulting Secret is readable
  # by the Gateway's listener. kube-system is the canonical home of
  # cilium-gateway (clusters/_template/sovereign-tls/cilium-gateway.yaml).
  namespace: kube-system
  # ClusterIssuer to request from. `letsencrypt-dns01-prod-powerdns`
  # is shipped by bp-cert-manager-powerdns-webhook. Operators may
  # override to a per-cluster issuer (e.g. a private ACME) via
  # cluster overlay.
  issuerName: letsencrypt-dns01-prod-powerdns
  # Cert renew window. cert-manager defaults are conservative; we
  # match the per-Sovereign cilium-gateway-cert.yaml legacy values.
  duration: ""        # empty = cert-manager default (90d for LE)
  renewBefore: ""     # empty = cert-manager default (~1/3 of duration)

# ─── Catalyst image coordinates ───────────────────────────────────────────────
# Default registry + org point at ghcr.io/openova-io/openova. Per-Sovereign
# overlays leave these untouched and set global.imageRegistry to the local
# Harbor mirror instead.
images:
  registry: "ghcr.io"
  organization: "openova-io/openova"
  # SHA tags — bump these via CI when building new images.
  catalystApi:
    tag: "7bdd14f"
  catalystUi:
    tag: "7bdd14f"
  marketplaceApi:
    tag: "3c2f7e4"
  console:
    tag: "3c2f7e4"
  # All 10 SME microservices share one SHA tag (built from the same mono-repo commit).
  smeTag: "046e5eb"

# bp-catalyst-platform umbrella values
#
# As of 1.1.9 this umbrella ships ONLY the Catalyst-Zero control-plane
# workloads (catalyst-ui, catalyst-api, ProvisioningState CRD, Sovereign
# HTTPRoute). The 10 foundation Blueprints (cilium, cert-manager, flux,
# crossplane, sealed-secrets, spire, nats-jetstream, openbao, keycloak,
# gitea) are installed independently by clusters/_template/bootstrap-kit/
# at slots 01..10. There are no subchart values to thread here.
#
# Historic note: 1.1.4 set `bp-keycloak.keycloak.postgresql.fullnameOverride`
# and `bp-gitea.gitea.postgresql.fullnameOverride` to deconflict bitnami
# postgresql `<release>-postgresql` collisions when both Blueprints were
# subcharts of this umbrella (issue #252). Now that they're top-level
# Flux HelmReleases under separate namespaces (bp-keycloak →
# `keycloak`, bp-gitea → `gitea`), the collision is gone and the
# overrides are unnecessary.

# ProvisioningState CRD — the canonical persistence shape for Sovereign
# provisioning runs (issue #88). Keeps observability of in-flight wizard
# runs on the K8s plane (`kubectl get provisioningstates -A`) in addition
# to the catalyst-api Pod's local flat-file store at
# /var/lib/catalyst/deployments. The two stores compose: the flat file is
# authoritative (full event log, fsync-rename atomic), the CRD is the
# coarse-grained projection (state machine pending → ... → ready | failed)
# that operators and sibling controllers consume.
provisioningState:
  crd:
    # Default true: the CRD is part of the bp-catalyst-platform contract.
    # Disable only if the cluster has the CRD installed by an out-of-band
    # mechanism (test envtest harness, sibling Catalyst instance) and a
    # second install would conflict.
    enabled: true

# ─── catalyst-api runtime config ──────────────────────────────────────────
# Knobs the api-deployment.yaml template threads as env vars. Empty values
# fall back to in-code defaults (see the deployment template). Per
# docs/INVIOLABLE-PRINCIPLES.md #4 (never hardcode) every URL is
# operator-overridable from the per-Sovereign overlay without rebuilding
# the chart.
catalystApi:
  # PowerDNS REST API base URL used by:
  #   - SME-tenant pipeline's PATCH-RRset writer (sme_tenant_dns.go)
  #   - Multi-zone parent-domain handler (parent_domains.go, issue #827)
  # Empty = in-code default (in-cluster Service FQDN of the Sovereign's
  # own PowerDNS, http://powerdns.powerdns.svc.cluster.local:8081).
  powerdnsURL: ""
  # PowerDNS server identifier per the REST API contract. Empty = "localhost".
  powerdnsServerID: ""

# ─── Sovereign HTTPRoute (Cilium Gateway API, issue #387) ─────────────────
# Renders templates/httproute.yaml when `ingress.gateway.enabled=true`
# (default) AND per-Sovereign overlay supplies `ingress.hosts.console.host`
# and `ingress.hosts.api.host`. The legacy contabo Ingress templates
# (templates/ingress.yaml, templates/ingress-console-tls.yaml) are
# excluded from Sovereign installs via .helmignore — Sovereigns ingress
# exclusively through Cilium Gateway API per ADR-0001 §9.4.
ingress:
  gateway:
    enabled: true
    parentRef:
      name: cilium-gateway
      namespace: kube-system
      sectionName: https
  # Hosts populated by the bootstrap-kit slot
  # (clusters/_template/bootstrap-kit/13-bp-catalyst-platform.yaml).
  # Empty here so `helm template` without a per-Sovereign overlay fails
  # closed (Inviolable Principle #4).
  hosts:
    console:
      host: ""
    api:
      host: ""
    admin:
      host: ""
    marketplace:
      host: ""
  # Marketplace mode toggle (issue #710). When enabled, the chart renders
  # templates/sme-services/marketplace-routes.yaml exposing
  # marketplace.<sov>/{,api/,back-office/} and *.<sov> (tenant wildcard)
  # via Cilium Gateway. Default OFF — non-marketplace Sovereigns get the
  # SME workloads but no public ingress.
  marketplace:
    enabled: false

# Marketplace operator branding + payment + signup config (issue #710).
# Operator-supplied at provision time; rendered into ConfigMaps consumed
# by templates/sme-services/marketplace.yaml + admin.yaml. Defaults are
# safe placeholders so non-marketplace Sovereigns render without input.
marketplace:
  brand:
    name: ""              # Display name in storefront header (e.g. "Otech Cloud")
    tagline: ""           # Sub-headline (e.g. "Cloud + SaaS for Oman")
    logo: ""              # Logo URL (data: or remote)
    primaryColor: ""      # Hex (#RRGGBB) — falls back to chart default if empty
  currency: "USD"          # ISO-4217 (OMR / USD / EUR / SAR / AED / ...)
  paymentProvider:
    stripe:
      enabled: false
      publishableKey: ""              # safe to render in storefront JS
      secretKeyRef:                   # Secret + key holding STRIPE_SECRET_KEY
        name: ""                      # default: "" — disabled
        key: "secret-key"
      webhookSecretRef:
        name: ""
        key: "webhook-secret"
  signupPolicy:
    requireVoucher: false             # if true, /redeem must succeed before signup
    googleOAuth:
      enabled: false
      clientId: ""
      clientSecretRef:
        name: ""
        key: "client-secret"

# ─── SME Postgres cluster (issue #859) ────────────────────────────────────
# When ingress.marketplace.enabled=true the chart renders a
# CloudNativePG `Cluster` resource backing the SME microservice mesh. CNPG
# auto-creates the `<cluster>-app` Secret (basic-auth shape: username +
# password) the SME services consume via secretKeyRef.
#
# Per docs/INVIOLABLE-PRINCIPLES.md #4 (never hardcode), every operationally-
# meaningful value flows through .Values.smePostgres so per-Sovereign
# overlays can right-size storage / instances / pgVersion without forking
# the chart.
smePostgres:
  cluster:
    name: sme-pg                    # produces sme-pg-rw / sme-pg-app / sme-pg-superuser
    namespace: sme                  # the SME services live here too
    instances: 1                    # single-node by default; HA is a per-overlay decision
    pgVersion: "16"                 # tracks contabo data/postgresql.yaml + ADR-0003
    database: sme_auth              # primary DB owned by the `sme` user; secondary DBs below
    owner: sme                      # role name + secret username
    # Secondary DBs created via postInitApplicationSQL (1.4.4 — added
    # sme_documents for FerretDB, see ferretdb.yaml + cnpg-cluster.yaml).
    # Adding a new SME service is a values-only change.
    additionalDatabases:
      - sme_billing                 # billing service primary DB
      - sme_documents               # FerretDB (MongoDB-wire) backing DB — issue #861
    storageSize: 10Gi
    storageClass: local-path        # k3s default; per-Sovereign overlays may override
    resources:
      requests:
        cpu: 100m
        memory: 256Mi
      limits:
        cpu: "2"
        memory: 1Gi

# ─── SME secrets bundle (issue #859) ──────────────────────────────────────
# When ingress.marketplace.enabled=true the chart renders a `sme-secrets`
# Kubernetes Secret in the `sme` namespace consumed by 10 of the 11 SME
# service Deployments (auth, billing, catalog, console, domain, gateway,
# marketplace, notification, provisioning, tenant).
#
# JWT_SECRET / JWT_REFRESH_SECRET / ADMIN_PASSWORD are auto-generated on
# first install via sprig randAlphaNum and PERSIST across reconciles via
# Helm `lookup` (same pattern as platform/gitea/chart/templates/
# admin-secret.yaml — see issue #830 Bug 2). Without lookup every
# reconcile would invalidate every active SME session and lock out every
# admin.
#
# GOOGLE_CLIENT_* and SMTP_* are operator-supplied at provision time
# (typically via the per-Sovereign overlay or admin-console signup).
# Defaults are safe placeholders so the chart renders cleanly even when
# the operator hasn't wired OAuth or SMTP yet — non-marketplace
# Sovereigns simply don't render this Secret.
#
# Per docs/INVIOLABLE-PRINCIPLES.md #4 + #10: no hardcoded plaintext
# credentials; every value flows from .Values.smeSecrets or via lookup'd
# external Secret refs.
smeSecrets:
  secretName: sme-secrets
  namespace: sme
  smtp:
    # In-cluster Stalwart Service URL, or per-Sovereign override pointing
    # at the operator's preferred relay. Empty default means non-
    # marketplace Sovereigns stay clean (the Secret renders with empty
    # SMTP_HOST and the SMTP-using services degrade gracefully — no
    # outbound mail attempted).
    host: ""                                  # e.g. "stalwart-mail.stalwart.svc.cluster.local"
    port: ""                                  # e.g. "587"
    from: ""                                  # e.g. "noreply@<sov-fqdn>"
    user: ""                                  # SMTP submission username (often == from)
    # SMTP_PASS is sensitive — never inline it. Reference an existing
    # Secret in the `sme` namespace (the per-Sovereign overlay typically
    # creates this from cloud-init or via OpenBao + ExternalSecret).
    # Empty `name` skips the lookup and renders SMTP_PASS as empty.
    passwordSecretRef:
      name: ""                                # default: "" — no SMTP auth
      key: "password"
  admin:
    # Bootstrap admin email rendered into Secret as ADMIN_EMAIL. The
    # paired ADMIN_PASSWORD is auto-generated via lookup-persisted
    # randAlphaNum (32 chars) on first install — never settable from
    # values per Inviolable Principle #10.
    email: "admin@openova.io"

# ─── SME service backing-store endpoints (issue #861) ─────────────────────
# When ingress.marketplace.enabled=true the chart renders:
#   - templates/sme-services/ferretdb.yaml — FerretDB Deployment + Service
#     in `sme` ns, MongoDB-wire-compatible front end backed by sme-pg.
#   - templates/sme-services/valkey-cross-ns-policy.yaml —
#     CiliumNetworkPolicy in `valkey` ns allowing ingress from `sme` ns.
#   - templates/sme-services/configmap.yaml — MONGODB_URI + VALKEY_ADDR
#     populated from the values below.
#
# Per docs/INVIOLABLE-PRINCIPLES.md #4 (never hardcode), every URL,
# image ref, and resource value is operator-overridable. Defaults match
# the known-working contabo-mkt shape (FerretDB v1.24 against vanilla
# CNPG postgres:16; valkey-primary as the bp-valkey 1.0.0 read/write
# Service name).
smeServices:
  ferretdb:
    namespace: sme
    # FerretDB v1.24 — works against vanilla CNPG postgres:16. v2.x
    # requires PostgreSQL with the DocumentDB extension which the
    # sme-pg cluster does not ship; bumping is a separate change that
    # also needs a custom CNPG image. See Chart.yaml 1.4.4 changelog.
    image: ghcr.io/ferretdb/ferretdb
    tag: "1.24"
    imagePullPolicy: IfNotPresent
    replicas: 1
    # Postgres connection target — sme-pg-rw read/write Service in
    # `sme` ns, sme_documents DB created by sme-pg's
    # postInitApplicationSQL block (see smePostgres.cluster.
    # additionalDatabases above).
    postgresPort: 5432
    postgresDatabase: sme_documents
    sslmode: disable                          # ClusterIP traffic is overlay-encrypted; CNPG default issuer chain not bundled
    # Service FQDN exposed to other SME services via configmap MONGODB_URI.
    # Per-Sovereign overlays MAY swap to an external MongoDB endpoint.
    host: ferretdb.sme.svc.cluster.local
    port: 27017
    resources:
      requests:
        cpu: 25m
        memory: 64Mi
      limits:
        cpu: 500m
        memory: 256Mi
  valkey:
    # bp-valkey 1.0.0 (slot 17) deploys to namespace `valkey` with
    # bitnami valkey 5.5.1 + architecture: replication. Service names:
    #   - valkey-primary.valkey.svc.cluster.local (read/write)
    #   - valkey-replicas.valkey.svc.cluster.local (read-only)
    #   - valkey-headless.valkey.svc.cluster.local (StatefulSet headless)
    # SME services pin to the primary by default so writes succeed; per-
    # Sovereign overlays MAY split read traffic to -replicas via a
    # second VALKEY_READ_ADDR (separate ticket).
    host: valkey-primary.valkey.svc.cluster.local
    port: 6379
    namespace: valkey
    # ─── Cross-ns auth Secret mirror (issue #863) ──────────────────────
    # bp-valkey 1.0.0 ships auth.enabled=true; bitnami auto-generates a
    # random password and exposes it via the `valkey` Secret in the
    # `valkey` namespace. The catalyst chart renders templates/
    # sme-services/valkey-cross-ns-secret.yaml which uses Helm `lookup`
    # to read that password and re-emit it as `sme-valkey-auth` in
    # `sme` ns — auth.yaml + gateway.yaml then wire VALKEY_PASSWORD via
    # secretKeyRef. Each knob below is operator-overridable in case a
    # Sovereign uses a forked bp-valkey with a different Secret name
    # or key.
    sourceSecretName: valkey
    sourcePasswordKey: valkey-password
    destNamespace: sme
    destSecretName: sme-valkey-auth
    crossNsPolicy:
      # Render templates/sme-services/valkey-cross-ns-policy.yaml — a
      # CiliumNetworkPolicy in the `valkey` namespace allowing ingress
      # from the `sme` namespace on Valkey's port. Default true since
      # the cross-ns wire is the canonical Sovereign topology. Disable
      # via per-Sovereign overlay only when bp-valkey is repackaged
      # into the `sme` namespace (rare).
      enabled: true
      sourceNamespace: sme
  # ─── provisioning service GitHub token (issue #866) ──────────────────
  # The SME `provisioning` service Deployment references
  # `secret/provisioning-github-token` with key `GITHUB_TOKEN`. On
  # contabo-mkt this is pre-provisioned via SealedSecret. On a freshly
  # franchised Sovereign, templates/sme-services/provisioning-github-
  # token.yaml mirrors the gitea-admin password (already generated by
  # platform/gitea/chart/templates/admin-secret.yaml with the same
  # lookup-persistence pattern) into `sme` ns under the canonical
  # GITHUB_TOKEN key the provisioning service reads. This unblocks the
  # provisioning Pod reaching Running 1/1 on a fresh Sovereign — the
  # last 1/13 SME pod that #859 + #861 + #863 didn't already cover.
  #
  # Per Inviolable Principle #4 (never hardcode), every source/dest
  # name + key is operator-overridable so a Sovereign that points
  # provisioning at a non-Gitea Git host (e.g. a per-Sovereign
  # GitHub PAT delivered via OpenBao + ExternalSecret) can wire the
  # source-side ref without forking the chart.
  provisioning:
    gitToken:
      # Source: bp-gitea's auto-generated admin Secret. Slot 10
      # reaches Ready before slot 13 (Flux dependsOn in
      # clusters/_template/bootstrap-kit/13-bp-catalyst-platform.yaml),
      # so the lookup has data by the time this template renders.
      sourceNamespace: gitea
      sourceSecretName: gitea-admin-secret
      sourcePasswordKey: password
      # Destination: the Secret + key shape that the provisioning
      # Deployment's secretKeyRef in
      # templates/sme-services/provisioning.yaml reads.
      destNamespace: sme
      destSecretName: provisioning-github-token
      destKey: GITHUB_TOKEN
