diff --git a/apps/mumble/README.md b/apps/mumble/README.md
new file mode 100644
index 0000000..d52f298
--- /dev/null
+++ b/apps/mumble/README.md
@@ -0,0 +1,9 @@
+# Mumble cutover and recovery
+
+The published `mumble` chart owns the application and its optional Bitnami PostgreSQL subchart. This directory contains only cluster-specific values. The initial Argo sync has `mumble.enabled=false` so only a new, independent `mumble-postgresql` Service/StatefulSet/PVC are created; the legacy Mumble Deployment continues using the existing shared `default/postgresql` database. The old shared database and its PVC are not changed or removed.
+
+Before enabling Mumble, verify a local `pg_dump -Fc` from the shared database and restore it to the new database. Freeze Mumble writes for the final dump, then restore and compare schema/table counts. Only then set `mumble.enabled=true`. This rolls the existing `default/mumble` Deployment to use `mumble-postgresql.default.svc.cluster.local`. Its `Recreate` strategy avoids two server processes using the same database. Never enable both old direct-deploy CI and Argo as competing writers. If rollback is needed, freeze writes again and account for any writes made in the new database; blindly pointing Mumble back at the old copy would lose them.
+
+`default/mumble-secrets` contains the application's database, SuperUser, and registry passwords. `default/mumble-postgres` is generated once by the source repository's guarded bootstrap helper: a random PostgreSQL administrator password plus the existing Mumble database password. Neither Secret is in this public repository. Preserve and back up these Secrets with the new PostgreSQL PVC. The certificate remains `default/brunner-ninja-tls`, managed separately by cert-manager. No Mumble PVC exists; durable Mumble state is in PostgreSQL.
+
+The Service retains TCP/UDP port 64738 and the MikroTik operator annotations. Kubernetes/MetalLB should allocate the LoadBalancer address; the operator follows it. The old `192.168.0.14` pin is not a GitOps value. Do not delete the Service to change addressing. During a PostgreSQL restore, pause Argo auto-sync or scale the Mumble Application only with a recorded recovery plan, then resume once data is consistent.
diff --git a/apps/mumble/values.yaml b/apps/mumble/values.yaml
new file mode 100644
index 0000000..578ae7b
--- /dev/null
+++ b/apps/mumble/values.yaml
@@ -0,0 +1,40 @@
+# First stage: create the dedicated database without changing the live Mumble pod.
+# Set mumble.enabled=true only after a verified final pg_dump/pg_restore cutover.
+mumble:
+ enabled: false
+database:
+ host: mumble-postgresql.default.svc.cluster.local
+secrets:
+ mumble: mumble-secrets
+ postgresql: postgresql
+ tls: brunner-ninja-tls
+config:
+ welcomeText: '
Servas auf brunner.ninja.
Dieser Server ist aus Funkfeuer und manchmal auch aus dem Internet erreichbar.
Bau kan Schaß!
'
+ registrationName: brunner.ninja
+ registrationURL: https://brunner.ninja/
+ registrationHostname: brunner.ninja
+ registrationLocation: AT
+service:
+ type: LoadBalancer
+ externalTrafficPolicy: Local
+ annotations:
+ metallb.io/address-pool: default
+ mikrotik.brunner.ninja/router: newgw
+ mikrotik.brunner.ninja/forwardings: '[{"name":"tcp","servicePort":"mumble-tcp","dstAddressList":"WANs"},{"name":"udp","servicePort":"mumble-udp","dstAddressList":"WANs"}]'
+postgresql:
+ enabled: true
+ auth:
+ username: mumble
+ database: mumble
+ existingSecret: mumble-postgres
+ secretKeys:
+ adminPasswordKey: postgres-password
+ userPasswordKey: database-password
+ primary:
+ persistence:
+ storageClass: rook-ceph-block-ec
+ size: 8Gi
+ persistentVolumeClaimRetentionPolicy:
+ enabled: true
+ whenDeleted: Retain
+ whenScaled: Retain
diff --git a/bootstrap/kustomization.yaml b/bootstrap/kustomization.yaml
index 589d889..1d68020 100644
--- a/bootstrap/kustomization.yaml
+++ b/bootstrap/kustomization.yaml
@@ -67,3 +67,4 @@ resources:
- pdf-editor.yaml
- scanner.yaml
- paperless.yaml
+- mumble.yaml
diff --git a/bootstrap/mumble.yaml b/bootstrap/mumble.yaml
new file mode 100644
index 0000000..722abfd
--- /dev/null
+++ b/bootstrap/mumble.yaml
@@ -0,0 +1,25 @@
+apiVersion: argoproj.io/v1alpha1
+kind: Application
+metadata:
+ name: mumble
+ namespace: argocd
+spec:
+ project: homelab
+ sources:
+ - repoURL: https://brunner.ninja/charts
+ chart: mumble
+ targetRevision: 1.5.939
+ helm:
+ releaseName: mumble
+ valueFiles: [$values/apps/mumble/values.yaml]
+ - repoURL: https://code.brunner.ninja/feedc0de/homelab-gitops.git
+ targetRevision: main
+ ref: values
+ destination:
+ server: https://kubernetes.default.svc
+ namespace: default
+ syncPolicy:
+ automated:
+ enabled: true
+ prune: false
+ selfHeal: true
diff --git a/bootstrap/project.yaml b/bootstrap/project.yaml
index 6cfa0a7..9dcdc96 100644
--- a/bootstrap/project.yaml
+++ b/bootstrap/project.yaml
@@ -25,8 +25,12 @@ spec:
kind: ServiceAccount
- group: apps
kind: Deployment
+ - group: apps
+ kind: StatefulSet
- group: networking.k8s.io
kind: Ingress
+ - group: networking.k8s.io
+ kind: NetworkPolicy
- group: policy
kind: PodDisruptionBudget
- group: monitoring.coreos.com