19 KiB
Runbook: Admin-Plattform parallel zum Altbetrieb testen (ohne Merge, nur mit Demo-Tenant)
Ziel: Die neue Admin-Plattform und den neuen Core parallel zu den laufenden Tenants betreiben – mit einem neuen Test-Tenant
demo-admin. Nichts Bestehendes wird angefasst, es wird nichts gemergt, und jeder Schritt lässt sich einzeln zurücknehmen.
0. So läuft das Ganze parallel (und warum der Altbetrieb sicher ist)
ALTBETRIEB (unverändert) NEUBETRIEB (Test)
──────────────────────── ─────────────────
Gitea: main / cortecs-llm-migration Gitea: Branch admin-platform-integration
└ build-deploy.yml → :latest + deploy-all └ build-branch-image.yml → NUR Image :<sha> (kein :latest, kein Deploy)
Mittwald: app-demo, app-rotary, app-sprinz, … Mittwald: app-demo-admin ← neuer, eigener Service + Volume + Ingress
Domain: demo.<DOMAIN> … Domain: demo-admin.<DOMAIN>
Daten: ins Image gebacken (tenants/) Daten: Bundle von der Admin-Plattform (TENANT_SOURCE=admin)
OIDC-Client: von Hand angelegt OIDC-Client: automatisch über die Login-API
Admin-Plattform auf Coolify (eigene Domain, eigene Postgres)
Schutzmechanismen (alle eingebaut und getestet):
| Schutz | Wirkung |
|---|---|
| Branch-Trennung | build-deploy.yml läuft nur auf main/cortecs-llm-migration (auch nicht per „Run workflow“ vom Test-Branch). Der Test-Branch baut nur ein Image mit Tag = Git-SHA. |
| Eigener Tenant | demo-admin hat eigenen Service app-demo-admin, eigenes Volume vol-demo-admin, eigenen Host und eigenen OIDC-Client. app-demo bleibt unberührt. |
DEPLOY_ALLOWED_TENANTS=demo-admin |
Die Admin-Plattform darf nur diesen Tenant live anfassen (Mittwald und Login-API). Auch „Alle neu deployen“ trifft nur ihn. |
DEPLOY_LIVE=false zum Start |
Erst nur Dry-Run (liest den Stack, schreibt nichts). |
| Differenzielles PATCH + Guard | Es wird nur app-demo-admin geschrieben; danach prüft der Admin, dass alle fremden Services noch da sind. |
Default TENANT_SOURCE=git im Core |
Der neue Core verhält sich ohne Env wie der alte. |
Rückgängig machen: siehe Abschnitt 11.
1. Werte zusammentragen (einmalig)
| Wert | Woher | Verwendung |
|---|---|---|
DOMAIN |
Gitea → Repo transkriptipt-platform → Einstellungen → Actions → Variablen |
Basis-Domain in der Admin-Plattform |
PROJECT_ID, STACK_ID |
dito | Mittwald-Ziel |
REGISTRY (z. B. gitea.onyva.dev/onyva) |
dito | Registry in der Admin-Plattform |
MITTWALD_API_TOKEN |
Gitea → Secrets (du kennst den Wert; derselbe Token) | Env der Admin-Plattform |
Weitere Variablen: OIDC_ISSUER, AUTH_ENABLED, APP_COOKIE_SECURE, MAX_FILE_SIZE_MB, CORTECS_BASE_URL, LLM_MODEL, LLM_MAX_TOKENS, LLM_TEMPERATURE, SMTP_HOST/PORT/USER/FROM, MISTRAL_*, COST_* |
dito | in Einstellungen der Admin-Plattform (Abschnitt 6) |
CORTECS_API_KEY, SMTP_PASSWORD |
cd ~/PycharmProjects/transkript-platform && sops -d --extract '["CORTECS_API_KEY"]' secrets/shared.enc.yaml (analog SMTP_PASSWORD) |
Einstellungen → Geteilte Secrets |
COST_INGEST_KEY von demo |
sops -d --extract '["COST_INGEST_KEY"]' tenants/demo/secrets.enc.yaml |
Secret des Test-Tenants (Abschnitt 7, Punkt 7.4) |
<ADMIN_HOST> |
du wählst: Domain, unter der Coolify die Admin-Plattform ausliefert, z. B. admin.deine-domain.de |
muss öffentlich per HTTPS erreichbar sein (der Tenant-Container holt von dort sein Bundle) |
<DEINE_MAIL> |
deine Login-E-Mail bei login.onyva.dev (Konto muss dort existieren) | Admin-Zugriff + Freigabe im Test-Tenant |
Werte nicht in Chats oder Tickets kopieren (Keys, Secrets).
2. Core-Branch pushen (Image bauen lassen)
cd ~/PycharmProjects/transkript-platform
git branch --show-current # → admin-platform-integration
git log --oneline -3 # 13055b8 CI: build-deploy nur von Produktions-Branches …
git rev-parse HEAD # → voller SHA; z. B. 13055b811ca0030841f41ce1f10e4f30cba1a7db ← MERKEN (= CORE_SHA)
git push -u origin admin-platform-integration
Was jetzt in Gitea passiert (Repo → Actions):
| Workflow | Erwartung |
|---|---|
test |
grün (Schema ↔ Code ↔ Tenants, Bundle-Loader) |
build-branch-image |
grün; Log-Zeile „Image gebaut: <registry>/transkript-platform:<SHA>“ |
build-deploy |
läuft nicht (Branch nicht gelistet) – wenn doch: sofort abbrechen und melden |
Prüfen: Gitea → Repo → Packages → transkript-platform hat einen neuen Tag = voller SHA. Der Tag latest ist unverändert (Zeitstempel!).
✅ Ergebnis:
CORE_SHA(voller 40-stelliger SHA). Lege ihn in deine Notizen.
3. Admin-Plattform ins eigene Repo
- Gitea → Neues Repository: Organisation
Onyva, Nameonyscribe-admin, privat, leer (ohne README/.gitignore/Lizenz). - Lokal:
cd ~/PycharmProjects/onyscribe-admin
git status --short | head # .env und .data dürfen NICHT erscheinen (sind ignoriert)
git ls-files | grep -E '(^|/)\.env$|\.db$' || echo "ok: keine Secrets/DB im Index"
git add -A
git commit -m "Onyscribe Admin: Initialer Stand"
git remote add origin https://gitea.onyva.dev/Onyva/onyscribe-admin.git
git push -u origin main
Hinweis: seed/tenants.seed.json.gz enthält die Tenant-Konfigurationen inkl. Zusatzdateien (z. B. namensliste.txt – personenbezogen). Das liegt heute schon im Altrepo; Repo privat halten.
4. Login-System: Client + API-Key für die Admin-Plattform
Im Login-Dashboard (login.onyva.dev), als Admin:
- API-Keys → neuer Key („onyscribe-admin“, ggf. Ablaufdatum). Klartext
onyva_…einmalig kopieren → späterONYVA_LOGIN_API_KEY. - Client für die Admin-Plattform selbst anlegen (Dashboard oder per API):
KEY=onyva_… # der Key aus 1.
curl -sX POST https://login.onyva.dev/api/v1/apps -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"name":"Onyscribe Admin","redirect_uris":["https://<ADMIN_HOST>/auth/callback"],"auth_mode":"required","totp_mode":"disabled"}'
# → client_id + client_secret SOFORT sichern (nur einmal sichtbar)
curl -sX PUT https://login.onyva.dev/api/v1/apps/<client_id>/memberships -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"user_email":"<DEINE_MAIL>","role":"admin"}'
Ergebnis: client_id, client_secret (Admin-Login), ONYVA_LOGIN_API_KEY.
5. Coolify: Admin-Plattform deployen
Neue Ressource → Docker Compose (aus Git): Repo Onyva/onyscribe-admin, Branch main, Compose-Datei docker-compose.yml
(Zugriff auf das private Repo per Deploy-Key/Token einrichten).
Umgebungsvariablen (Coolify → Ressource → Environment):
| Variable | Wert | Phase |
|---|---|---|
POSTGRES_PASSWORD |
langes Zufallspasswort | immer |
SECRET_KEY |
python3 -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())" – sichern! ohne ihn sind die Secrets in der DB unlesbar |
immer |
AUTH_ENABLED |
true |
immer |
OIDC_ISSUER |
https://login.onyva.dev |
immer |
OIDC_CLIENT_ID / OIDC_CLIENT_SECRET |
aus Abschnitt 4 (Punkt 2) | immer |
OIDC_REDIRECT_URI |
https://<ADMIN_HOST>/auth/callback |
immer |
OIDC_LOGOUT_REDIRECT_URI |
https://<ADMIN_HOST>/ |
immer |
APP_COOKIE_SECURE |
true |
immer |
ADMIN_ALLOWED_EMAILS |
<DEINE_MAIL> (weitere kommagetrennt) |
immer – ohne Regel wird jeder Login abgelehnt |
MITTWALD_API_TOKEN |
derselbe Token wie in Gitea | immer |
ONYVA_LOGIN_API_KEY |
aus Abschnitt 4 (Punkt 1) | immer |
DEPLOY_ALLOWED_TENANTS |
demo-admin |
immer |
DEPLOY_LIVE |
false |
Phase 1 (Dry-Run) → in Abschnitt 8 auf true |
OIDC_SYNC_LIVE |
false |
optional true, um den Login-Abgleich separat vor dem Deploy zu testen |
CORE_RELEASE_TOKEN |
leer | erst in Abschnitt 10 |
CORTECS_API_KEY |
leer (wird in der UI als Secret gesetzt) | optional |
Domain: Service admin → Domain https://<ADMIN_HOST>:8300 (Port 8300 = Container-Port). Persistente Daten: Volume pgdata (Postgres) – Backup einrichten.
Deploy starten. Der erste Build nutzt das normale Dockerfile (mitgelieferter Core-Snapshot, keine Registry nötig).
Prüfen:
https://<ADMIN_HOST>/healthz→{"ok":true}https://<ADMIN_HOST>/→ Weiterleitung zu login.onyva.dev → Login → Dashboard mit 7 Tenants (Seed).- Seitenleiste unten: „Deploy: gesperrt · Dry-Run“, „<DEINE_MAIL>“.
https://<ADMIN_HOST>/auth/mezeigt"auth_enabled": true. Steht dortfalse(Seitenleiste: rot „Login aus – offen!“), ist die Plattform für jeden offen:AUTH_ENABLED=true(ohne Anführungszeichen) und die OIDC-Variablen prüfen. Ohne Login sind Live-Aktionen automatisch gesperrt.- Probleme: „Kein Zugriff“ →
ADMIN_ALLOWED_EMAILS;redirect_uri-Fehler → Redirect-URI im Login-Client exakt wie inOIDC_REDIRECT_URI.
6. Admin-Plattform konfigurieren (Menü „Einstellungen“)
Felder (Spalte „Gitea“ = dieselbe Variable wie bisher), dann oben „Alles speichern“:
| Feld in der Admin-Plattform | Wert / Gitea |
|---|---|
| Basis-Domain | DOMAIN |
| Mittwald PROJECT_ID / STACK_ID | PROJECT_ID / STACK_ID |
| Registry | REGISTRY |
| Image-Name | transkript-platform |
| Öffentliche URL der Admin-Plattform | https://<ADMIN_HOST> |
| Core kann Bundle laden | ✔ aktivieren (betrifft nur Tenants mit Quelle „Admin“, also nur demo-admin) |
| Login (OIDC) & Limits | OIDC_ISSUER, AUTH_ENABLED (true), APP_COOKIE_SECURE (true), MAX_FILE_SIZE_MB |
| LLM & Transkription | CORTECS_BASE_URL, LLM_MODEL, LLM_MAX_TOKENS, LLM_TEMPERATURE, MISTRAL_* |
| E-Mail (SMTP) | SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_FROM |
| Kostenerfassung | COST_API_BASE, COST_TRACKING_ENABLED |
| „Weitere Core-Einstellungen“ (aus dem Schema) | nur ausfüllen, was du in Gitea auch gesetzt hast (COST_LLM_*, COST_STT_PER_MINUTE, STT_* …); leer = Standard des Cores |
| Rollout → Canary-Tenants | demo-admin |
Geteilte Secrets → CORTECS_API_KEY |
Wert setzen (aus sops -d …) |
Geteilte Secrets → SMTP_PASSWORD |
Wert setzen (nur nötig, wenn der Test E-Mail-Versand prüfen soll) |
Dann: Karte „Login-API“ → „Verbindung testen“ → ✔ Verbindung ok – N App(s) im Login.
7. Test-Tenant demo-admin anlegen und konfigurieren
7.1 Anlegen: Dashboard → + Neuer Tenant → Name Onyva Demo (Admin-Test), ID demo-admin, Ausgangspunkt „Kopie von Onyva Demo“ → Anlegen.
(Quelle ist automatisch „Admin“, OIDC-Verwaltung „managed“.)
7.2 Spracherkennung: Tenant → Funktion & STT → Provider cortecs, Modell voxtral-mini-transcribe-2602
(dann reicht der geteilte Cortecs-Key; demo nutzt sonst Mistral und bräuchte einen eigenen MISTRAL_API_KEY).
7.3 Optisch unterscheidbar machen: Marke & Farben → Akzent z. B. #E8590C → „Töne aus Akzent ableiten“. Oben rechts Prüfen & veröffentlichen → Nachricht „Test-Tenant“ → v2.
7.4 Secrets: Tenant → Secrets → COST_INGEST_KEY Wert setzen (der Wert von demo; Kosten laufen dann unter demo, für den Test okay).
SESSION_SECRET und ADMIN_BUNDLE_TOKEN sind schon erzeugt. OIDC_CLIENT_ID/SECRET legt der Deploy automatisch an.
7.5 Login: Tenant → Domain & Login: Subdomain demo-admin; OIDC-Verwaltung managed, Zugriff required; Freigaben: <DEINE_MAIL> als editor (Nutzer muss im Login existieren) → Speichern.
„Gegen Login prüfen“ (nur lesend) → erwartet: „würde App ‚Onyscribe – Onyva Demo (Admin-Test)‘ anlegen (Redirect: https://demo-admin./auth/callback …)“ und „würde <DEINE_MAIL> als editor freigeben“.
7.6 Core pinnen: Tenant → Übersicht → Karte „Core-Version“ → Pin = voller SHA aus Abschnitt 2 → Pin setzen. (Der Pin sorgt dafür, dass genau das Branch-Image läuft und der Health-Check die Core-Version prüfen kann.)
7.7 Vorflug-Check + Dry-Run: Tenant → Deploy → Vorflug-Check → Prüfen.
Erwartet in Phase 1: alles grün/gelb, gelb nur „DEPLOY_LIVE nicht aktiv“; keine roten Punkte. Typische rote Punkte und Fix stehen direkt dabei
(z. B. Registry/PROJECT_ID/Token fehlen, CORTECS_API_KEY/COST_INGEST_KEY fehlen, „Core kann Bundle laden“ aus, Admin-URL nicht erreichbar).
Dann Dry-Run → Log lesen: „geschützte bestehende Services (bleiben unangetastet): [app-demo, app-rotary, …]“, [DRY-RUN] PATCH … für Volume und Service, kein Schreibzugriff.
8. Live-Deploy des Test-Tenants
- Coolify → Admin-Ressource →
DEPLOY_LIVE=truesetzen (DEPLOY_ALLOWED_TENANTS=demo-adminbleibt) → neu deployen (Daten bleiben). - Admin →
demo-admin→ Deploy → Vorflug-Check → muss „Bereit“ zeigen → Deployen.
Was passiert (Log): OIDC-Client im Login anlegen und Secret speichern → Pflicht-Secrets prüfen → Volume + Service per PATCH → Service neu erzeugen → Ingress
demo-admin.<DOMAIN> → Health-Check (bis ~90 s Wartezeit für Start + Zertifikat).
Abnahme-Checkliste:
- Deploy-Log endet mit
Health-Check … ✔ · Core 13055b811c · Bundle v2und✔ Fertig - mStudio: Service
app-demo-adminläuft; alle anderen Services unverändert (Image-Tags wie vorher) https://demo-admin.<DOMAIN>/health→core.version= dein SHA,bundle={"source":"admin","version":2,"stale":false}- Seite öffnen → Login → freigegebener Nutzer kommt rein → Oberfläche in der neuen Farbe
- Protokoll erzeugen (kleines Transkript hochladen) → Zusammenfassung → PDF/Word → Aussehen = Vorschau in der Admin-Plattform
- Admin → Dashboard → Zustand prüfen:
demo-admingrün. Die Altbetrieb-Tenants zeigen „Core ohne Vertrag (alte Version)“ – erwartet und harmlos (sie laufen noch auf dem alten Image) - Altbetrieb:
demo.<DOMAIN>und die anderen Kunden funktionieren unverändert
9. Änderung ohne Core-Änderung testen
- Admin →
demo-admin→ Marke & Farben: Akzent ändern → Prüfen & veröffentlichen (v3) → Deploy → Deployen (nur Neustart, kein Image-Build). - Erwartung: Health-Check
Bundle v3 ✔; Seite neu laden → neue Farbe. - Agent: KI-Agent → „Setze die Akzentfarbe auf #0B6E4F“ → Live-Vorschau beobachten → „In Entwurf übernehmen“ → veröffentlichen → deployen.
- Ausfallsicherheit (nur
demo-admin!): Coolify → Admin-Ressource stoppen; in mStudio den Containerapp-demo-adminneu starten → er startet mit gecachtem Bundle:https://demo-admin.<DOMAIN>/health→bundle.source = "cache",stale = true. Admin wieder starten → nächster Container-Neustart holt wiederadmin.
10. (Optional) Den kompletten Core-Release-Weg testen
- Coolify:
CORE_RELEASE_TOKEN= langes Zufallstoken, Admin neu deployen. Gitea → Repo → Einstellungen → Actions: VariableADMIN_URL=https://<ADMIN_HOST>, SecretADMIN_RELEASE_TOKEN= dasselbe Token. (Wirkt nur auf Workflows des Test-Branches;mainkennt dennotify-admin-Job nicht.) - Im Core-Repo eine Kleinigkeit committen und auf den Branch pushen →
build-branch-imagebaut und meldet das Release. - Admin → Menü Core: neues Release, Badge „Admin älter/anders“ (die Admin-Plattform enthält noch den alten Core-Snapshot).
- Angleichen:
cd ~/PycharmProjects/onyscribe-admin && scripts/sync_core.sh && git add -A && git commit -m "Core-Snapshot aktualisiert" && git push→ Coolify deployt → Badge „gleicher Core“. (Später ersetztDockerfile.fromcorediesen Schritt: Admin wird direkt auf dem Core-Image gebaut.) - Prüfen → Matrix mit allen 7 Tenants (beim ersten Mal „neu (keine Baseline)“) → Freigeben → Dry-Run → Tenant
demo-admin: Pin aufheben → Ausrollen → nurdemo-adminwird live ausgerollt (Allowlist), Health-Check prüft die neue Core-SHA. - Rollback testen: Zurückrollen (stellt den vorherigen Tag wieder her).
11. Abbruch / Rückbau (jederzeit)
| Was | Wie |
|---|---|
| Test-Tenant live entfernen | Admin → demo-admin → Übersicht → Gefahrenbereich → Offboard-Dry-Run prüfen → Offboard (live) (entfernt Service, Volume, Ingress) |
| OIDC-Client des Test-Tenants | Gefahrenbereich → OIDC-Client im Login löschen |
| Admin-Plattform | Coolify-Ressource stoppen/löschen; Login-Client „Onyscribe Admin“ und API-Key im Login löschen |
| Branch/Image | Gitea: Branch admin-platform-integration löschen, Package-Tag (SHA) löschen |
| Alles Live sperren | DEPLOY_LIVE=false (und/oder DEPLOY_ALLOWED_TENANTS leeren) → Admin neu deployen |
Der Altbetrieb braucht in keinem dieser Fälle eine Änderung.
12. Fehlersuche
| Symptom | Ursache / Fix |
|---|---|
| Vorflug: „Mittwald-Stack lesbar“ rot | Token-Rechte, PROJECT_ID/STACK_ID in Einstellungen prüfen (dieselben Werte wie Gitea) |
| Deploy: „Pflicht-Secrets ohne Wert: …“ | CORTECS_API_KEY (Einstellungen → Geteilte Secrets), COST_INGEST_KEY (Tenant → Secrets), ggf. MISTRAL_API_KEY (nur bei STT-Provider mistral) |
| Deploy: „… nicht für Live-Schreibzugriffe freigegeben“ | DEPLOY_ALLOWED_TENANTS enthält die Tenant-ID nicht |
| Deploy: „Quelle ‚Admin‘ ist noch gesperrt“ | Einstellungen → „Core kann Bundle laden“ aktivieren |
| Deploy: „OIDC-Abgleich fehlgeschlagen: API-Key ungültig (401)“ | ONYVA_LOGIN_API_KEY falsch/abgelaufen; Key im Login neu erzeugen |
| Deploy: „… Freigaben: existiert im Login nicht“ (Warnung) | Nutzer im Login anlegen, dann Domain & Login → Jetzt abgleichen |
| Health-Check: „Core X statt Y“ | Pin/Tag stimmt nicht mit dem Image überein oder Image fehlt in der Registry (mStudio-Container-Log) |
| Health-Check: „Bundle cache v… (veraltet)“ | Container erreicht die Admin-URL nicht: Domain/HTTPS/Firewall, admin_public_url, Bundle-Token |
| Container-Log: „Tenant-Bundle … nicht verfügbar“ | wie oben; zusätzlich ADMIN_URL/ADMIN_BUNDLE_TOKEN im Plan (Deploy → Service-Definition) prüfen |
Login der Tenant-Seite: redirect_uri-Fehler |
Domain & Login → Gegen Login prüfen → Jetzt abgleichen (ergänzt die Redirect-URI) |
Login: invalid_client |
OIDC_CLIENT_SECRET fehlt/ist veraltet → Jetzt abgleichen bzw. neu deployen |
| Zertifikat/Ingress fehlt | Token braucht Domain/Ingress-Recht (Log: „Ingress … NICHT angelegt“); Service läuft trotzdem, nach Rechteänderung erneut deployen |
| Admin „Zustand prüfen“: „nicht erreichbar“ | Tenant noch nicht deployt bzw. DNS/Zertifikat noch nicht fertig |
13. Danach (nicht Teil dieses Tests)
Erst wenn der Test-Tenant mehrere Tage sauber läuft: Core-Branch reviewen und mergen (→ build-deploy baut dann den neuen Core für alle),
Secrets der echten Tenants importieren (python scripts/import_tenants.py --with-secrets), pro Tenant die Cut-over-Checkliste abarbeiten und
DEPLOY_ALLOWED_TENANTS schrittweise erweitern. Die echten Tenants stellst du einzeln um – Rückweg: Quelle zurück auf „Git“.