apiVersion: catalyst.openova.io/v1alpha1
kind: Blueprint
metadata:
  name: bp-stalwart-tenant
  labels:
    catalyst.openova.io/category: communication
    catalyst.openova.io/section: pts-4-5-communication
spec:
  version: 0.1.0
  card:
    title: Stalwart (per-tenant)
    summary: |
      Dedicated per-SME (per-vcluster) Stalwart mail server. Implements
      locked decision [Q3] of EPIC #795 — every SME on a Sovereign gets
      its OWN Stalwart instance in its tenant namespace, with its OWN
      domain, OWN MTA reputation, and OWN queue. NOT a shared otech-
      level multi-domain Stalwart.

      Webmail UI at `https://mail.<sme-domain>`; SMTP/IMAP via
      LoadBalancer. SSO authenticated against the SME-vcluster Keycloak
      realm (NOT otech-level Keycloak). Per-user mailbox provisioning
      is event-driven (ADR-0003 §3).
    icon: stalwart.svg
    category: communication
    tags: [mail, smtp, imap, jmap, sme, multi-tenant, vcluster, sso, oidc]
    documentation: https://stalw.art/
    license: AGPL-3.0
  visibility: listed
  owner:
    team: platform
    contact: catalyst@openova.io
  configSchema:
    type: object
    required: [domain, keycloak]
    properties:
      domain:
        type: object
        required: [primary]
        properties:
          primary:
            type: string
            description: Mail domain (free-sub like 'acme.<otech-fqdn>' or BYO like 'acme.com').
          mode:
            type: string
            enum: [free-subdomain, byo]
            default: free-subdomain
      keycloak:
        type: object
        required: [realmURL]
        properties:
          realmURL:
            type: string
            description: SME-vcluster Keycloak realm issuer URL (e.g. https://auth.<sme-domain>/realms/sme).
          clientID:
            type: string
            default: stalwart
          clientSecretName:
            type: string
            default: stalwart-oidc
      persistence:
        type: object
        properties:
          spool:
            type: object
            properties:
              size:
                type: string
                default: 20Gi
              storageClassName:
                type: string
                description: Empty = cluster default; per-Sovereign overlay supplies.
      admin:
        type: object
        properties:
          secretName:
            type: string
            default: stalwart-admin
          username:
            type: string
            default: admin
      ingress:
        type: object
        properties:
          webmail:
            type: object
            properties:
              mode:
                type: string
                enum: [gateway, ingress]
                default: gateway
              host:
                type: string
                description: Empty = composed as 'mail.<domain.primary>'.
      dns:
        type: object
        properties:
          spf:
            type: object
            properties:
              policy:
                type: string
                enum: ["-all", "~all"]
                default: "-all"
          dmarc:
            type: object
            properties:
              policy:
                type: string
                enum: [reject, quarantine, none]
                default: reject
              rua:
                type: string
                description: Empty = composed as 'dmarc@<domain.primary>'.
  placementSchema:
    modes: [single-region]
    default: single-region
  manifests:
    chart: ./chart
  depends:
    - blueprint: bp-keycloak
      version: ^1.3
      alias: idp
    - blueprint: bp-external-secrets
      version: ^1.0
      alias: eso
    - blueprint: bp-cert-manager
      version: ^1.0
      alias: certs
    - blueprint: bp-powerdns
      version: ^1.0
      alias: dns
      optional: true
  upgrades:
    from: []
  observability:
    metrics: prometheus
    logs: stdout
