RubenRWU 7d8c226da2 Onyscribe Admin: Initialer Stand
Admin-Plattform für die Tenants von Onyscribe: Editor mit Live-Vorschau (echter Core in Sandbox), Versionen, KI-Agent (Cortecs),
OIDC-Abgleich über die Login-Developer-API, Deploy-Engine (Mittwald, gesperrt ohne DEPLOY_LIVE, Freigabe pro Tenant),
Core-Vertrag (Schema/Manifest), Core-Releases mit Kompatibilitätsprüfung, Canary-Rollout und Rollback, Zustandsabgleich.
Runbook: docs/RUNBOOK_PARALLELTEST.md

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 15:30:26 +02:00
2026-10-15 15:30:26 +02:00
2026-10-15 15:30:26 +02:00
2026-10-15 15:30:26 +02:00
2026-10-15 15:30:26 +02:00
2026-10-15 15:30:26 +02:00
2026-10-15 15:30:26 +02:00
2026-10-15 15:30:26 +02:00
2026-10-15 15:30:26 +02:00
2026-10-15 15:30:26 +02:00
2026-10-15 15:30:26 +02:00

Onyscribe Admin

Separat gehostete Admin-Plattform für die Tenants von Onyscribe (Repo transkript-platform): Tenants anlegen und bearbeiten, Live-Vorschau mit dem echten Core, versionieren, Secrets/OIDC/Domain pflegen, deployen, mit KI-Agent (Cortecs).

Stand

Alles, was ohne Änderung am Core und ohne echte Deployments möglich ist, ist umgesetzt:

Bereich Stand
Tenants (7 importiert, Hash-identisch zu Git) ✔ Import, Seed, Anlegen/Klonen, Status, Ressourcen, Notizen, Archivieren/Löschen
Entwurf → Diff → Version ✔ unveränderliche Snapshots, Rollback als Entwurf, Hook-Code-Freigabe
Editor ✔ Marke/Farben, Absender, PDF-Layout, Prompt, Dateien, Flags/STT, Hook-Code, tenant.json
Live-Vorschau ✔ Web-UI + PDF mit dem echten Core in Sandbox (kein Secret, CPU-/Datei-Limits), Validierung
Prompt-Test ✔ echter LLM-Lauf (braucht Cortecs-Key), finaler Prompt inkl. Hooks
KI-Agent ✔ echter Tool-Loop (Messages- oder Chat-API gegen Cortecs), Workspace-Entwurf, Diff, Freigabe; ✔ Demo-Modus ohne Key; ⚠ gegen Live-Cortecs noch ungetestet (kein Key)
Login (OIDC) ✔ Code + Tests (Mock-IdP); ⚠ gegen login.onyva.dev noch ungetestet
Secrets ✔ Fernet-verschlüsselt, Import aus SOPS (--with-secrets)
OIDC-Clients ✔ automatischer Abgleich bei jedem Deploy über die Login-Developer-API: Client anlegen, Redirect-URIs, auth/totp, Freigaben; Secret wird sofort verschlüsselt gespeichert; Dry-Run liest nur. Gegen Fake-Login getestet, gegen login.onyva.dev ungetestet (kein Key)
Domain ✔ Subdomain/eigene Domain, DNS-Check
Deploy-Engine ✔ Port von infra/deploy.py (PATCH, Guard, Ingress, Offboard, Abbruch bei Fehler), per Fake-HTTP getestet; Schreibzugriffe gesperrt (DEPLOY_LIVE)
Bundle-Endpoint ✔ GET /api/tenants/<id>/bundle (Token); Gegenstück im Core: Branch admin-platform-integration (core/bundle.py)
Core-Vertrag ✔ Schema/Manifest/Build-Info aus dem Core gelesen (app/services/contract.py); Formulare („Funktion & STT“ + automatisch alle neuen Optionen), Einstellungen und Container-Env werden daraus erzeugt; Pflicht-Secrets laut Schema
Core-Releases (Menü „Core“) ✔ Release-Eingang für die Core-CI, Kompatibilitätsprüfung aller Tenants mit dem Core des Admins (Validierung + Fingerabdrücke von PDF/Web/Prompt gegen Baseline), Freigabe, Dry-Run, Canary-Rollout mit Abbruch, Health-Verifikation (Core-SHA, Bundle-Version), Pins pro Tenant, Rollback (Release/Tenant)
Zustandsabgleich ✔ „Zustand prüfen“ im Dashboard und „Läuft?“ pro Tenant: fragt /health ab und zeigt Abweichungen

Bewusst offen (braucht Core- bzw. Produktionsentscheidung):

  1. Core-Branch admin-platform-integration (Vertrag, Bundle-Loader, /health) reviewen und mergen/deployen. Erst danach core_supports_bundle aktivieren (Einstellungen) – bis dahin sind Deploys von Tenants mit Quelle „Admin“ gesperrt.
  2. DEPLOY_LIVE=true + MITTWALD_API_TOKEN + Projekt-/Stack-ID, sobald echte Deployments gewollt sind.
  3. Cortecs-Key hinterlegen → Agent-Modell auswählen (Einstellungen → „Modelle von Cortecs laden“) und gegen Live testen.
  4. OIDC-Client für die Admin-Plattform in login.onyva.dev anlegen, AUTH_ENABLED=true. 4b. Admin-Key im Login-Dashboard erzeugen → ONYVA_LOGIN_API_KEY setzen; mit „Verbindung testen“ (Einstellungen) prüfen; zum Schreiben OIDC_SYNC_LIVE=true.
  5. Datenbank-Migrationen (Alembic) vor dem ersten produktiven Schemawechsel; Tabellen entstehen derzeit per create_all.

Starten

# lokal (SQLite, kein Docker)
python3 -m venv .venv && . .venv/bin/activate && pip install -r requirements.txt
# System-Libs für WeasyPrint: libpango-1.0-0 libpangoft2-1.0-0 fonts-noto-core
cp .env.example .env                       # Keys eintragen (wird beim Start eingelesen; echte Env-Variablen haben Vorrang)
uvicorn app.main:app --port 8300          # http://localhost:8300  (Seed lädt die 7 Tenants automatisch) – nach .env-Änderungen neu starten

# mit Postgres (wie Coolify)
export POSTGRES_PASSWORD=...  SECRET_KEY=$(python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())")
docker compose up -d --build

Coolify: Neue Ressource → Docker Compose → dieses Repo. Env POSTGRES_PASSWORD und SECRET_KEY setzen (weitere Variablen: .env.example), Domain auf Service admin, Port 8300. Backup: Volume pgdata und SECRET_KEY.

Login aktivieren: Client in login.onyva.dev anlegen (Redirect https://<admin>/auth/callback), dann AUTH_ENABLED=true, OIDC_CLIENT_ID/SECRET, OIDC_REDIRECT_URI, OIDC_LOGOUT_REDIRECT_URI und eine Zugriffsregel (ADMIN_ALLOWED_EMAILS und/oder ADMIN_REQUIRED_ROLE). Ohne Regel wird jeder Login abgelehnt.

Zusammenspiel mit dem Core

Spezifikation: transkript-platform/docs/CONTRACT.md. Kurz: Der Core liefert Image + Schema + Manifest + Bundle-Format + /health, der Admin liest das – er hält keine eigene Kopie der Tenant-Optionen.

Core-Push → CI: Tests → Image (:sha) → POST /api/core/releases (Job „notify-admin“)
          → Admin neu bauen (Dockerfile.fromcore, FROM Core-Image) → „Core“: Prüfen (alle Tenants) → Freigeben → Ausrollen (Canary zuerst) → Health-Check je Tenant
Tenant-Änderung (ohne Core): Veröffentlichen → Deploy mit dem aktiven Core-Tag (nur Bundle-Neustart, kein Image-Build)
  • Admin auf Basis des Core-Images: Dockerfile.fromcore (CORE_IMAGE=<registry>/transkript-platform:<tag>). Sandbox, Schriften und Pakete sind identisch zur Produktion. Läuft der Admin auf einem anderen Core als ein gemeldetes Release, zeigt „Core“ das an und erlaubt keine Prüfung/Freigabe. Noch zu verifizieren in Coolify: wie der Neubau mit neuem Tag ausgelöst wird (Webhook + CORE_IMAGE per Env/API oder latest mit „immer pullen“).
  • Lokal ohne Core-Image: vendored Snapshot (scripts/sync_core.sh, zieht den aktuellen Stand der Quelle inkl. Branch).
  • Neue Core-Option? Steht sie im Schema des Cores (CI erzwingt das), erscheint sie hier automatisch in Formularen, Einstellungen und Container-Env.
  • Release-Eingang: Env CORE_RELEASE_TOKEN (Admin) = Secret ADMIN_RELEASE_TOKEN (Core-CI) + Variable ADMIN_URL.

OIDC-Abgleich (Login-Developer-API)

Pro Tenant (Domain & Login) gibt es einen Soll-Zustand und eine Verwaltung:

Modus Verhalten beim Deploy
off nichts anfassen
adopt (Standard für die 7 importierten Altclients) prüfen, dass die Redirect-URIs (Subdomain + ggf. eigene Domain) enthalten sind, fehlende ergänzen – sonst nichts ändern
managed (Standard für neue Tenants) Client fehlt → anlegen; sonst Redirect-URIs, auth_mode, totp_mode, allow_registration, Backchannel exakt wie konfiguriert; Freigaben setzen (optional „exakt“: überzählige entziehen)

Ablauf eines Deploys: 1. OIDC abgleichen (bei Neuanlage Client-ID/-Secret sofort verschlüsselt speichern) → 2. Pflicht-Secrets prüfen → 3. Service-PATCH mit den Werten im Env → 4. Ingress/Health. Schlägt der Abgleich fehl, wird vor dem Service-Eingriff abgebrochen. Dry-Run liest nur und zeigt „würde anlegen/anpassen“. Zusätzlich manuell: „Gegen Login prüfen“, „Jetzt abgleichen“, „Aus Login übernehmen“ (Freigaben), „Secret rotieren“, „OIDC-Client im Login löschen“ (Gefahrenbereich). Das Secret ist nur bei Anlage/Rotation sichtbar; ein Altclient ohne Secret in der Admin-DB wird nie automatisch rotiert (er würde laufende Logins unterbrechen) – Secret eintragen oder bewusst rotieren. Lokal ausprobieren ohne echtes Login: python scripts/fake_login_server.py (siehe Datei-Kopf).

KI-Agent

Bedienung: Header → „KI-Agent“. Der Chat ersetzt in der Mitte das Formular, die Live-Vorschau bleibt rechts und zeigt den Arbeitsstand des Agenten während er arbeitet („Agent-Stand (live)“, rendert nach jeder Änderung neu), danach den „Agent-Vorschlag“. „In Entwurf übernehmen“ schreibt ihn in den Entwurf, „Verwerfen“ lässt alles unverändert. Key-Suche: geteiltes Secret (Einstellungen) → Env/.env CORTECS_API_KEY → Key des Tenants. Der Chat zeigt, woher der Key kommt, bzw. „Demo-Modus – kein Key gefunden“.

Cortecs bietet neben Chat-Completions auch das Anthropic-Messages-Protokoll (/v1/messages) – der Agent nutzt standardmäßig dieses (Einstellung agent_api), mit Fallback auf Chat-Completions. Modell: Einstellung agent_model (Standard claude-4-6-sonnet, wie das Protokoll-Modell; „Modelle von Cortecs laden“ zeigt die verfügbaren IDs und markiert Tool-Unterstützung). Der Agent arbeitet nur auf einem Entwurfs-Workspace; Namenslisten sind gesperrt; Secrets kennt er nicht; Veröffentlichen/Deployen kann er nicht.

Aufbau

app/
  main.py            FastAPI, Startup (DB anlegen, Seed laden)
  models.py          Tenant, Version (unveränderlich), Blob (content-addressed), Secret (verschlüsselt), Deployment, AuditLog, ChatMessage
  services/
    store.py         Entwurf ↔ Version, Diff, Bundle (tar.gz) – Kern der Versionierung
    preview.py       Live-Vorschau: Subprozess mit Kopie des Cores + Tenant, ohne Secrets (preview_worker.py)
    importer.py      Import aus ../transkript-platform (tenants/*, Secrets nur als Schlüsselnamen)
    deploy_sim.py    Deploy-Plan (wie infra/deploy.py) + Simulation  ← hier später die echte Mittwald-Logik
    agent_mock.py    Mock-Agent                                      ← hier später der Cortecs-Loop
    seed.py          Start-Daten (seed/tenants.seed.json.gz)
  routers/           api.py (JSON), pages.py (HTML)
vendor/platform/     Snapshot des Cores (CORE_VERSION) – Vorschau führt genau diesen Stand aus
scripts/             import_tenants.py, verify_import.py, export_seed.py, sync_core.sh
tests/test_flow.py   E2E: Import, Vorschau, Entwurf→Veröffentlichen, Validierung, Bundle, Deploy-Sim, Agent

Wichtige Abläufe

python scripts/import_tenants.py                # Tenants (+ Secret-SCHLÜSSEL) aus ../transkript-platform importieren
python scripts/import_tenants.py --with-secrets # zusätzlich Secret-WERTE via `sops -d` lesen und verschlüsselt speichern (Cut-over)
python scripts/verify_import.py                 # Beweis: DB-Bundle == Git-Ordner (Hash-Vergleich)
python scripts/export_seed.py                   # DB-Stand als Seed-Datei ins Repo (ohne Secret-Werte)
scripts/sync_core.sh                            # vendored Core aus transkript-platform aktualisieren
python -m pytest tests                          # Tests (51) (isoliert: lesen weder .env noch echte Keys, eigene Temp-DB)

Bundle-Endpoint (Schnittstelle zum Core)

GET /api/tenants/<id>/bundle mit Authorization: Bearer <ADMIN_BUNDLE_TOKEN> liefert tenant.json + alle Dateien (+ MANIFEST.json mit Hashes) – ohne Secrets. Das ist, was ein Tenant-Container später beim Start abholt (TENANT_SOURCE=admin, Phase 1 im Core – noch nicht umgesetzt).

Nächste Schritte

  1. Core: TENANT_SOURCE=git|admin + Bundle-Loader mit Cache (Phase 1)
  2. OIDC-Login der Admin-Plattform über login.onyva.dev
  3. Spike: Cortecs-Modell für den Agent (Tool-Calling, Streaming, Bild-Input) → agent_mock.py ersetzen
  4. Echte Deploys (Mittwald) aus deploy_sim.py, Rollout-Abbruch bei Fehler, Health-Check
  5. Hook-Code-Freigabe härten (Sandbox ohne Netz), Rollen
Description
No description provided
Readme 1.5 MiB
Languages
Python 69.9%
JavaScript 15.1%
HTML 10.7%
CSS 3.9%
Shell 0.2%
Other 0.2%