openova/core
e3mrah e83d08ea4e
feat(sandbox+tenant): CNPG active-hot-standby (ReplicaCluster) default for marketplace tenants when SOVEREIGN_ENABLE_HOT_STANDBY=true (#1661)
Sovereign DoD D31 — CNPG-backed apps must replicate across the
Sovereign's regions when the operator opts in. PR #1562 wired this
into bp-wordpress-tenant chart-level. This change extends the same
toggle across BOTH user-facing paths:

1. Marketplace tenant flow (sme_tenant_gitops.go)
   - smeTenantTemplateData gains EnableHotStandby/PrimaryRegion/
     ReplicaRegion. renderSMETenantOverlay reads them from the
     catalyst-api Pod env (SOVEREIGN_ENABLE_HOT_STANDBY +
     SOVEREIGN_PRIMARY_REGION + SOVEREIGN_REPLICA_REGION).
   - Bp-wordpress-tenant HelmRelease emits pg.activeHotStandby.*
     when the trio is valid; bp-wordpress-tenant chart 0.2.0+
     (PR #1562) renders the primary + replica Cluster CR pair.
   - Defence-in-depth: degenerate inputs (empty/identical regions)
     fall back to single-Cluster shape rather than emitting a
     HelmRelease the chart's validateActiveHotStandbyRegions helper
     would fail at template time.

2. Sandbox plane (sandbox.db.provision)
   - Env struct + NewEnvFromOS read the same Sovereign-level trio.
   - sandbox.db.provision emits a primary + replica Cluster CR pair
     when hotStandbyActive() — same shape bp-cnpg-pair renders for
     marketplace apps + bp-wordpress-tenant cnpg-cluster.yaml: WAL
     streaming via spec.managed.services.additional annotated
     service.cilium.io/global=true, nodeAffinity pinning each side
     to its declared region, replica.enabled=true with externalCluster
     resolving the primary through the ClusterMesh-global Service alias.
   - Best-effort rollback if the replica Create fails so the operator
     never sees an orphan primary.

3. Plumbing (one knob, both paths)
   - catalyst chart: values.sovereign.{enableHotStandby,primaryRegion,
     replicaRegion} -> sovereign-fqdn ConfigMap keys -> catalyst-api env.
   - sandbox chart: cnpg.activeHotStandby.{enabled,primaryRegion,
     replicaRegion} -> controller env -> per-Sandbox MCP Pod env.
   - Bootstrap-kit slot 13 + slot 19a wire SOVEREIGN_ENABLE_HOT_STANDBY/
     SOVEREIGN_PRIMARY_REGION/SOVEREIGN_REPLICA_REGION envsubst
     placeholders to BOTH chart paths so the operator flips one knob
     on the per-Sovereign overlay and gets HA across the marketplace
     tenant install AND the sandbox.db plane.

Default empty/false: every Sovereign that has not opted in keeps
rendering single-Cluster CNPG (zero regression).

gitlab-tenant + nextcloud-tenant charts: NOT shipped in this repo
today, so they are out of scope. When they land they can copy the
same value contract (pg.activeHotStandby.*) and the gitops writer
wiring already handles them — no chart-bump or controller change
required.

Tests
- sme_tenant_active_hot_standby_test.go: 8 cases (off, on-happy-path,
  degenerate matrix incl. empty primary, empty replica, identical
  regions, toggle off with regions).
- sandbox_db_hot_standby_test.go: 11 cases covering hotStandbyActive
  matrix + replicaClusterName/replicationServiceName suffix rules +
  full primary + replica CR shapes (nodeAffinity, switchover, managed
  service, externalClusters).
- platform/wordpress-tenant/chart/tests/active-hot-standby-render.sh
  still passes (5/5 gates green).
- catalyst-api SMETenant suite GREEN.
- sandbox-controller suite GREEN.
- helm template clean for sandbox chart (HA + default-off) and
  catalyst chart (sovereign-fqdn-configmap + api-deployment).

Hard rules respected: READ-ONLY clusters, no Chart.yaml bump on
bp-catalyst-platform (envsubst-only wiring change in slot 13), no
host-cluster touch outside the chart-level seam.

Refs DoD D31.

Co-authored-by: hatiyildiz <269457768+hatiyildiz@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 12:53:57 +04:00
..
admin fix(admin,billing): drop unsafe state-write in snippet — spinner stays forever (#1000) (#1001) 2026-05-05 23:36:50 +04:00
cmd feat(epic-4): K+P+X1+G — k8s-ws-proxy + projector + WebSocket logs + Guacamole chart (#1099) (#1164) 2026-05-09 09:27:39 +04:00
console feat(consolidation): Phase 1 — move Catalyst-Zero apps + CI + manifests into public monorepo 2026-04-28 12:08:09 +02:00
controllers feat(sandbox+tenant): CNPG active-hot-standby (ReplicaCluster) default for marketplace tenants when SOVEREIGN_ENABLE_HOT_STANDBY=true (#1661) 2026-05-18 12:53:57 +04:00
marketplace test(marketplace): codified customer-journey regression (17 steps) (#1655) 2026-05-18 12:02:39 +04:00
marketplace-api feat(consolidation): Phase 1 — move Catalyst-Zero apps + CI + manifests into public monorepo 2026-04-28 12:08:09 +02:00
pkg/dynadot-client fix(pdm/dynadot): remove fictional ResponseHeader wrapper from api3.json adapter (#939) (#948) 2026-05-05 15:11:39 +04:00
pool-domain-manager fix(pdm/dynadot): auto-register NS glue records before set_ns (#1496) 2026-05-15 13:32:49 +04:00
services fix(provisioning): set Organization.spec.tenantPublic on product-install (was empty; HTTPRoute reconciler had nothing to render) (#1650) 2026-05-18 11:44:00 +04:00
README.md feat(consolidation): Phase 1 — move Catalyst-Zero apps + CI + manifests into public monorepo 2026-04-28 12:08:09 +02:00

Catalyst Control Plane (core/)

The user-facing Catalyst control plane modules. Status: Consolidated and deployed on Catalyst-Zero (Contabo k3s) as of Pass 105 (2026-04-28).

Read first: docs/PROVISIONING-PLAN.md, docs/GLOSSARY.md, docs/ARCHITECTURE.md, docs/IMPLEMENTATION-STATUS.md.


What this is

The four modules that constitute the Catalyst control plane's user-facing surface, plus the Go backend they share. Each is its own Containerfile-built workload, deployed on every Catalyst Sovereign (starting with Catalyst-Zero on Contabo, and on every franchised Sovereign provisioned thereafter).

Module Stack Purpose Deployed image
console/ Astro + Svelte Primary user-facing UI. Form / Advanced / IaC editor depths. The Sovereign-provisioning wizard at /sovereign (Phase 3) lives here. ghcr.io/openova-io/openova/console:<sha>
admin/ Astro + Svelte Sovereign-admin operations UI. Includes the canonical voucher / billing / catalog / orders / tenants admin surface that sovereign-admin uses to issue vouchers to franchised tenants. ghcr.io/openova-io/openova/admin:<sha>
marketplace/ Astro + Svelte Public-facing Blueprint card grid (the "App Store"). 5-step Plan → Apps → Addons → Checkout → Review flow. ghcr.io/openova-io/openova/marketplace:<sha>
marketplace-api/ Go Backend API for marketplace and console. Handlers (handlers/), provisioner (provisioner/), store (store/). Phase 4 extends this with full Hetzner provisioning. ghcr.io/openova-io/openova/marketplace-api:<sha>

The Helm chart that deploys all four (plus catalyst-ui, catalyst-api, and the legacy SME backend services) lives at products/catalyst/chart/.


CI / Build

Each module has a corresponding GitHub Actions workflow:

Each workflow watches its module path, builds the Containerfile, pushes to GHCR with a SHA tag, and pins the SHA into the corresponding manifest in products/catalyst/chart/templates/ (so Flux on Catalyst-Zero picks up the new image on the next reconciliation).


Migration history

  • Pass 105 (2026-04-28): console/, admin/, marketplace/ consolidated from openova-private/apps/{console,admin,marketplace}/ into this directory. marketplace-api/ consolidated from openova-private/website/marketplace-api/. Six CI workflows migrated to .github/workflows/ of the public repo. Catalyst-Zero K8s manifests migrated from openova-private/clusters/contabo-mkt/apps/{catalyst,sme/services,marketplace-api}/ into products/catalyst/chart/templates/. Image references updated from ghcr.io/openova-io/openova-private/sme-{admin,console,marketplace} to ghcr.io/openova-io/openova/{admin,console,marketplace}. The 8 legacy SME backend services (auth, billing, catalog, domain, gateway, notification, provisioning, tenant) keep their openova-private/sme-* image refs until their source code migrates in a follow-up phase.

Part of OpenOva