68 KiB
AZA – Master Handover / Operational Runbook
Arbeitsmodus / Regeln
User bastelt nicht; nur Composer-Patches (meist Opus) oder 1 exakter Command mit Pfad.
- Alle Aenderungen kommen als fertige, vollstaendige Dateien (ready-to-paste).
- User fuehrt nur vorgegebene Commands aus, keine manuellen Edits.
- Jede Aenderung in 1 Patch, kein schrittweises Anleiten.
- Keine risky Refactors – immer minimal und sicher.
AKTUELLE PROJEKTPHASE (Stand 2026-04-12)
Phase: Device-/Seat-Logik V1 implementiert. Backup-Konzept + Deinstallations-UX als naechste Hauptbloecke.
VERBINDLICHE PROJEKTKONTINUITAET (ab 2026-04-12)
Diese Punkte sind verbindlich und muessen in allen kuenftigen Handovern wiedergegeben werden.
1. V1-Lizenzmodell (IMPLEMENTIERT)
- 1 aktive Lizenz = 2 gleichzeitig aktive Computer
- Dieselbe Kaeufer-E-Mail darf mehrere Lizenzen kaufen
- Erlaubte Geraete addieren sich: 1 Lizenz = 2, 2 Lizenzen = 4, 3 Lizenzen = 6
- Backend entscheidet fuehrend (aza_device_enforcement.py)
- Desktop sendet beim Start/Lizenzcheck email + device_id an Backend
- Backend liefert: license_active, allowed_devices, used_devices, device_allowed, reason
2. Fuehrende Lizenz-/Geraetelogik (IMPLEMENTIERT)
/license/statusund/license/activateliefern strukturierte Device-Antwort- Admin-Endpoint:
GET /admin/devices?email=...fuer Geraete-Uebersicht - Desktop zeigt bei device_limit_reached klare Benutzermeldung
3. Offene Hauptpunkte (HOHE PRIORITAET)
- Deinstallation: Kein Zwangs-Neustart. Option: jetzt neu starten / spaeter neu starten
- Backup-Konzept vollstaendig: Lokale App/Code/Builds, Installer-Artefakte, Hetzner-Backend/Server-Config/Daten, Stripe-Config/Referenzen, WordPress/WooCommerce/Website, Release-/Download-Dateien, Offsite-Sicherheitskopie in Luino
4. Naechste empfohlene Hauptbloecke
- Vollstaendiges Backup-Konzept (HOHE PRIORITAET)
- Deinstallations-UX (kein Zwangs-Neustart)
- WooCommerce / Produktiver Verkaufspfad
- Browser-AZA / AZA Praxis-Chat
5. AZA Praxis-Chat – Architekturziel (VERBINDLICH, 2026-04-18)
Leitidee: AZA Praxis-Chat wird strukturell in Richtung Softros entwickelt (Benutzer, Gruppen, Direktchat, Verlauf, Status), aber im Design ruhig, modern, medizinisch und AZA-konform umgesetzt.
Softros als FUNKTIONSVORBILD (nicht Designvorbild):
- Klare Benutzer-/Gruppenliste mit Online-Status
- Direktchat zwischen Benutzern
- Gruppenchats / Kanaele (Allgemein, Empfang, Aerzte, MPA)
- Einfacher Verlauf, schnelle Interaktion ohne unnoetige Popups
AZA-Design-Grundsaetze (NICHT kopieren von Softros):
- Helle, ruhige Oberflaeche (kein Windows-90er-Look)
- Medizinisches Hellblau (#5B8DB3), dezente Grautoene
- Klare Karten/Paneele, gute Lesbarkeit
- Moderne, minimale Struktur
Zielstruktur (3-Panel-Layout):
- Links: Sidebar mit Benutzern, Gruppen/Kanaelen, Online-Status
- Mitte: Aktiver Chatbereich mit Inline-Eingabe unten (kein Popup)
- Rechts: Aufgaben-Panel (zuweisbar, offen/erledigt, pro Benutzer)
- Archiv: Erledigte Nachrichten separat, nicht im Live-Feed
Umsetzungsphasen:
- Phase 1 (kurzfristig): 3-Panel-Layout im Frontend, Sidebar, Inline-Chat-Eingabe, Archiv-Tab. Kein Backend-Umbau noetig.
- Phase 2 (mittelfristig): Backend-Kanaele, Presence-Heartbeat, Direktchat-Routing, Ungelesen-Zaehler, Typing-Indikator.
- Phase 3 (spaeter): Multi-Tenant, WebSocket, echte Auth, Datei-Upload, Push-Notifications.
Oeffentliche Subdomain: empfang.aza-medwork.ch (DNS A-Record auf Hetzner, Caddy-Block bereits konfiguriert).
FRUEHERE PHASE (Stand 2026-03-30/31)
Phase: PRODUKTIVPFAD + BETREIBER-KONTROLLE VOLLSTAENDIG BEWIESEN
STATUS: PRODUKTIVPFAD + BETREIBER-KONTROLLE VOLLSTAENDIG BEWIESEN (2026-03-30/31)
1. Stripe/Lizenz-Live-Pfad + Echter Live-Kauf BEWIESEN:
- Kompletter Lizenz-Lifecycle technisch nachgewiesen: Kauf → Lizenz active → Storno/Refund → Lizenz canceled → Desktop Testmodus
- Echter Live-Testkauf durchgefuehrt und sauber neutralisiert
- Echter Live-Kauf fuer CHF 59 (Basic Monthly) erfolgreich durchgefuehrt und NICHT storniert
- Backend-Lizenz active fuer admin@aza-medwork.ch bewiesen
- Desktop startet ohne Testfenster und im Vollmodus
- current_period_end korrekt gesetzt (1777652509)
- Desktop respektiert canceled-Status korrekt und faellt auf Testmodus zurueck
- B1-W1 bis B1-W5 alle erfolgreich abgeschlossen
- Drei Bugs in
stripe_routes.pygepatcht (COALESCE-Fix, cancel_at_period_end, sync_subscription)
2. Admin Monitor v1 + Control Panel v2 LIVE:
- 8 interne Admin-Endpunkte, geschuetzt via X-Admin-Token / AZA_ADMIN_TOKEN
- v1: system_status, licenses_overview, backup_status, billing_overview
- v2: license_customer_map, revenue_overview, alerts, dashboard_summary
- Nachweislich funktionierend (ohne Token: 401, mit falschem Token: 401, mit korrektem Token: Daten)
3. Backup/Storage-Monitor AKTIV:
- Taegliches Backup-Skript eingerichtet (/root/aza-backups/backup_aza.sh, Cronjob)
- /host_backups read-only in Container gemountet
- backup_status erkennt Backups korrekt
- Ca. 137 GB frei, ca. 4-5% belegt – kein akuter Speicherdruck
4. Geloeste Root Causes / Lessons Learned (2026-03-27 – 2026-03-30):
- Sandbox und Live muessen strikt getrennt werden
- missing_lookup_key wurde mit _lookup_key_from_price Fallback behoben
- Live-Kontext im Container wurde mit sk_live_ verifiziert
- license_debug war zuerst falsch wegen alter aktiver Sandbox-Zeile + neuer canceled-Live-Zeile ohne customer_email
- Operative Hotfix-Korrektur: DB-Backup erstellt, canceled-Zeile mit customer_email verknuepft, alter falscher active-Datensatz entfernt
- Root Cause 14: Lokales Aktivierungs-Gate vor Backend-Lizenzcheck (2026-03-30): Desktop zeigte "AZA – Testversion aktiv" trotz aktiver Remote-Lizenz. Ursache: _show_activation_gate() in basis14.py prueft lokalen Aktivierungsschluessel/Trial BEVOR der Backend-Lizenzstatus abgefragt wird. Bei Remote-Backend war das Gate irrelevant aber blockierend. Fix: Neue Funktion _has_remote_backend() erkennt ob ein nicht-localhost Backend konfiguriert ist. Wenn ja, wird das lokale Aktivierungs-Gate komplett uebersprungen. Backend-Lizenzstatus ist dann allein fuehrend. Datei: basis14.py
- Root Cause 15: current_period_end-Fallback im Webhook fehlte (2026-03-30): license_debug zeigte current_period_end=null fuer aktive Lizenz. Ursache: checkout.session.completed-Handler und subscription.updated/deleted-Handler hatten keinen Fallback auf sub["items"]["data"][0]["current_period_end"] wenn der Top-Level-Wert fehlt. Fix: Fallback-Extraktion aus items.data[0].current_period_end in beiden Handlern. Bestehender sync_subscription-Endpunkt hatte den Fallback bereits. Reparatur bestehender Daten: sync_subscription manuell aufgerufen → current_period_end korrekt gesetzt (1777652509). Datei: stripe_routes.py
- Root Cause 16: revenue_overview zeigte nur Summen, keine Einzelposten (2026-03-31): Betreiber konnte zwar Gesamtumsatz sehen (z.B. 59 CHF gross), aber nicht wer wann wie viel bezahlt hat. Fuer praktische Zahlungskontrolle fehlten Einzelposten. Fix: revenue_overview um recent_charges und recent_refunds Listen erweitert. Jeder Eintrag enthaelt amount_chf, email, date_utc, charge_id bzw. refund_id. Bewiesen: recent_charges zeigt 59.0 CHF fuer admin@aza-medwork.ch, recent_refunds zeigt 59.0 CHF Refund. Datei: admin_routes.py
Hetzner-Backend ist LIVE (2026-03-26)
- Produktiver API-Pfad:
https://api.aza-medwork.ch - DNS:
api.aza-medwork.ch→178.104.51.177 - Repo auf Hetzner:
/root/aza-app - Deploy-Verzeichnis:
/root/aza-app/deploy - Laufende Services:
aza-api+aza-caddy - Variante B technisch Ende-zu-Ende nachgewiesen
ARCHITEKTURENTSCHEIDUNG VARIANTE B (verbindlich, 2026-03-25):
- KEIN OpenAI-Key in der Desktop-App
- KEIN eigener OpenAI-Key pro Kunde als Pflicht
- KEIN gemeinsamer OpenAI-Key clientseitig
- Stattdessen: AZA Office spricht NUR mit eigenem AZA-Backend
- Nur das AZA-Backend spricht mit OpenAI
- Der OpenAI-Key liegt AUSSCHLIESSLICH serverseitig
- KEINE halben Uebergangsloesung, KEINE Shared-Key-Bastelei
Erfolgreiche Nachweise (2026-03-26):
curl https://api.aza-medwork.ch/health→ erfolgreichcurl -X POST https://api.aza-medwork.ch/v1/chatmit gueltigemX-API-Token→ success:true, content:OK- Damit nachgewiesen: Hetzner-Backend laeuft, Caddy/HTTPS laeuft, serverseitiger OpenAI-Zugriff laeuft, Variante B funktioniert technisch Ende-zu-Ende
B1 BACKEND-SPRINT (4 Wochen)
| Woche | Zeitraum ca. | Fokus |
|---|---|---|
| 1 | 25.03 – 01.04 | Backend Chat Proxy Endpoint (POST /v1/chat) + Auth + Rate Limiting |
| 2 | 02.04 – 08.04 | Desktop-App: alle OpenAI-Calls ueber Backend statt direkt |
| 3 | 09.04 – 15.04 | Hetzner Deploy: Docker/Caddy/HTTPS + Production-Env + Smoke-Tests |
| 4 | 16.04 – 22.04 | E2E-Test Desktop→Backend→OpenAI + Kundenweg ohne OpenAI-Key + Go-Live |
AKTUELLE PRIORITAETSREIHENFOLGE (B1 Backend-Sprint)
- Backend Chat Proxy POST /v1/chat (Woche 1) – Grundstein der Architektur
- Desktop-App auf Backend umstellen (Woche 2) – Alle OpenAI-Calls migrieren
- Hetzner Deploy (Woche 3) – Produktionsserver aufsetzen
- E2E-Test + Go-Live Backend-Pfad (Woche 4) – Kundenweg ohne OpenAI-Key
- WooCommerce/Stripe/Kauf-Weg laeuft PARALLEL weiter (Hostpoint)
EXPLIZIT NACHRANGIG / NICHT JETZT:
- Update-Komfort / separater Auto-Updater
- Browser-AZA Web-App (nach Backend-Architektur)
- Grosse Refactors die nicht Variante B dienen
HOSTPOINT vs. HETZNER:
- Hostpoint bleibt fuer Website/Marketing/WooCommerce/Stripe
- Hetzner ist JETZT der Backend-Pfad fuer OpenAI-Proxy/API
- Beides laeuft parallel, nicht gegeneinander
ERLEDIGT: B1-W1 Backend Chat Proxy Endpoint (2026-03-26)
POST /v1/chat – IMPLEMENTIERT UND VERIFIZIERT.
| Aspekt | Detail |
|---|---|
| Auth | require_api_token (X-API-Token Header, bestehendes Muster) |
| Rate Limiting | default_ip_limiter + default_token_limiter |
| Request-Schema | ChatRequest: model, messages[], temperature?, max_tokens?, top_p? |
| Message-Schema | ChatMessage: role (system/user/assistant), content |
| Modell-Whitelist | gpt-5.2, gpt-5-mini, gpt-5-nano, gpt-4o, gpt-4o-mini, gpt-4o-mini-search-preview |
| Input-Limits | Max 64 Messages, max 100k Zeichen/Nachricht |
| OpenAI-Call | _get_openai().chat.completions.create(**params) serverseitig |
| Response-Schema | {success, content, finish_reason, model, usage, request_id, duration_ms, error} |
| Secret-Scrubbing | sk-, sk-proj-, org- in Fehlertexten werden ersetzt |
| Tests | 7/7 gruen (Auth, Modell, Validierung, OpenAI-Proxy, /license/status, Schema) |
Datei: backend_main.py (~100 Zeilen)
ERLEDIGT: B1-W2 Desktop Chat Migration (2026-03-26)
Desktop-App: Chat-Completions laufen jetzt ueber Backend POST /v1/chat.
Migriert:
call_chat_completion()in basis14.py – zentraler Wrapper ->_backend_chat_completion()- News-Suche – direkter
self.clientCall ->_backend_chat_completion() - Kommentare – eigener
OpenAI()Client ->_backend_chat_completion() - Med-Detail Kurzinfo – eigener
OpenAI()Client ->_backend_chat_completion() - Briefstil-Analyse in
aza_text_windows_mixin.py->_backend_chat_completion()
Neue Architektur in basis14.py:
_BackendChatResponse– Wrapper-Klasse, OpenAI-Interface-kompatibel (.choices[0].message.content, .usage)_backend_chat_completion(**kwargs)– POST /v1/chat mit bestehender Token-Mechanik (get_backend_url/get_backend_token)call_chat_completion(**kwargs)– Consent/Capacity Check, dann_backend_chat_completion()- Timeout: 5s connect, 120s read
- Fehler: RuntimeError mit lesbarer Meldung, keine Secrets
Verbleibend fuer spaetere Bloecke: translate.py, congress_window.py, aza_email.py (eigenstaendige Module)
7/7 Tests gruen: Health, Auth, Model-Validation, E2E Desktop->Backend->OpenAI, Response-Schema, /license/status OK.
ERLEDIGT: B1-W3 Hetzner Deploy (2026-03-26)
Hetzner-Backend ist LIVE.
| Aspekt | Detail |
|---|---|
| Domain | https://api.aza-medwork.ch |
| DNS | api.aza-medwork.ch → 178.104.51.177 (A-Record) |
| Repo auf Hetzner | /root/aza-app |
| Deploy-Verzeichnis | /root/aza-app/deploy |
| Laufende Services | aza-api + aza-caddy |
| Compose | laeuft aus /root/aza-app/deploy |
.env produktiv |
AZA_DOMAIN=api.aza-medwork.ch, ACME_EMAIL=info@aza-medwork.ch, MEDWORK_API_TOKENS gesetzt, OPENAI_API_KEY serverseitig gesetzt |
Geloeste Root Causes beim Deploy:
- Falsches Git-Remote (
naswinterthur) war nicht geeignet → korrektes Remote verwendet - Nur
deploy/hochladen war falsch →docker-compose.ymlerwartet Repo-Root-Kontext (context: ..,dockerfile: deploy/Dockerfile) - Host-
nginxblockierte Port 80 → nginx gestoppt - Caddy DNS/ACME-Probleme wegen Resolver
127.0.0.53→ Fix: imcaddy-Service indocker-compose.ymlexplizit DNS gesetzt (1.1.1.1,8.8.8.8)
ERLEDIGT: B1-W4 Server-E2E-Test (2026-03-26)
Serverseitige Variante B Ende-zu-Ende nachgewiesen:
curl https://api.aza-medwork.ch/health→ erfolgreichcurl -X POST https://api.aza-medwork.ch/v1/chatmit gueltigemX-API-Token→ success:true, content:OK- Hetzner-Backend laeuft, Caddy/HTTPS laeuft, serverseitiger OpenAI-Zugriff laeuft
ERLEDIGT: B1 Desktop-Finalisierung (Code-Patches, 2026-03-27)
Alle Code-Patches fuer Variante B im Desktop sind verifiziert und korrekt:
| Patch | Status | Detail |
|---|---|---|
ensure_ready() |
KORREKT | Remote-Backend gilt als ready (kein lokaler OpenAI-Key noetig) |
| OpenAI-Key-Setup-Dialog | KORREKT | Dialog wird bei konfiguriertem Remote-Backend unterdrueckt |
backend_url.txt |
KORREKT | Zeigt auf https://api.aza-medwork.ch |
backend_token.txt |
KORREKT | Zentrale lokale Token-Quelle, wird von App priorisiert |
start_all.bat Guard |
KORREKT | Variante-B-Schutz: ueberschreibt URL nicht bei Live-Backend |
start_backend_autoport.bat Guard |
KORREKT | Variante-B-Schutz: ueberschreibt URL nicht bei Live-Backend |
| Chat-/Textpfad | KORREKT | Laeuft ueber POST {backend_url}/v1/chat |
Token-Prioritaet (bestaetigt):
backend_token.txt(hoechste Prioritaet)- Env
MEDWORK_API_TOKENS - Env
MEDWORK_API_TOKEN
Backend-URL-Prioritaet (bestaetigt):
- Env
MEDWORK_BACKEND_URL backend_url.txt
Nicht geaenderte Restpfade (blockieren Haupttest NICHT):
translate.py,aza_email.py,apps/diktat/diktat_app.pyhaben noch lokale OpenAI-Clients → betreffen Nebenpfadekongress2_window.pyhat hardcoded URL → Kongress ist geparktself.client = OpenAI(...)Init bleibt als Dev-Fallback → blockiert nichts bei Variante B
ERLEDIGT: B1-W5 Lokaler Desktop-Live-Test (2026-03-27)
Desktop → Hetzner → OpenAI erfolgreich in der echten App getestet.
backend_url.txtzeigt aufhttps://api.aza-medwork.chbackend_token.txtlokal vorhanden, vom Live-Backend akzeptiertbasis14.pylokal gestartet und erfolgreich gegen Live-Backend getestet- Kein lokaler OpenAI-Key noetig
- Kein OpenAI-Key-Dialog erscheint
- Chat-/Textpfad laeuft ueber Hetzner-Backend
Desktop-spezifische Hinweise (fuer kuenftige Chats):
ensure_ready()ist korrekt fuer Remote-Backend gepatcht- OpenAI-Key-Dialog wird bei Remote-Backend unterdrueckt
- Fuer Live-Test NICHT ueber lokale Starter gehen (
start_all.bat,RUN_AZA_ONECLICK.bat,START_AZA.bat,start_backend_autoport.bat) – diese setzen Env auf localhost - Bevorzugte Startmethode:
python basis14.pydirekt
ERLEDIGT: Desktop-Lizenzpfad gegen Live-Backend (2026-03-30)
Desktop-App respektiert den Backend-Lizenzstatus korrekt:
canceled/inactive→ Testmodus / DEMOactive→ Vollmodus- Relevante Stellen:
check_license_status()inbasis14.py,compute_license_decision()inaza_license_logic.py - Aktivierungsschluessel-Fallback greift nur bei fehlendem Remote-Backend
ERLEDIGT: Admin Monitor v1 + Control Panel v2 (2026-03-30)
Datei: admin_routes.py (eingebunden in backend_main.py mit prefix="/admin")
Sicherheit: X-Admin-Token / AZA_ADMIN_TOKEN (require_admin_token aus aza_security.py)
v1 Endpunkte:
GET /admin/system_status– App-Health, Uptime, Disk, Stripe-Config, DB-InfoGET /admin/licenses_overview– Lizenzen nach Status, letzte 20, ?email= FilterGET /admin/backup_status– Backup-Pfade, Groesse, neustes Backup, Log-TailGET /admin/billing_overview– Stripe-Health, Lizenz-Summary, Event-Log
v2 Endpunkte:
GET /admin/license_customer_map– Detaillierte Lizenznehmer-Uebersicht, ?email= und ?status= FilterGET /admin/revenue_overview– MRR-Schaetzung, Stripe-Live-Daten (gross/refunds/net), Event-SummaryGET /admin/alerts– Strukturierte Warnliste (info/warning/critical): Disk, Stripe, DB, Lizenzen, BackupsGET /admin/dashboard_summary– Sammel-Endpunkt fuer spaetere UI: System, Stripe, Disk, Backup, Lizenzen, Revenue, Alerts
Operative Referenz Hetzner:
- Aktuelle Datei:
/root/aza-app/admin_routes.py - Backup vor v2:
/root/aza-app/admin_routes.py.before_control_panel_v2_*
Wichtige Sicherungen:
stripe_routes.py.working_lookup_fallback_okstripe_webhook.sqlite.backup_after_sandbox_success- DB-Backup vor Email-/Hotfix-Korrektur
Wichtige Dateien Backend / Deploy:
/root/aza-app/stripe_routes.py/root/aza-app/admin_routes.py/root/aza-app/backend_main.py/root/aza-app/deploy/docker-compose.yml/root/aza-app/deploy/.env
Backup-Dateien:
/root/aza-backups/backup_aza.sh/root/aza-backups/daily/- Cronjob fuer taegliches Backup
ERLEDIGT: Echter Live-Kauf CHF 59 + Desktop Vollmodus (2026-03-30)
Status: VOLLSTAENDIG BEWIESEN. Produktivpfad funktioniert Ende-zu-Ende.
Bewiesener Ablauf:
- Echter Live-Kauf des Basic-Monatsplans (CHF 59) ueber Stripe Payment Link
- Stripe Webhook lieferte 200 OK
- Backend schrieb aktive Lizenz: status=active, lookup_key=aza_basic_monthly
- /stripe/license_debug zeigt active fuer admin@aza-medwork.ch
- /admin/license_customer_map zeigt die aktive Lizenz korrekt
- Desktop startet ohne Testfenster und im Vollmodus
- current_period_end korrekt gesetzt: 1777652509
Root Causes in diesem Block geloest:
- Root Cause 14: Lokales Aktivierungs-Gate vor Backend-Lizenzcheck → Fix: _has_remote_backend() Bypass (basis14.py)
- Root Cause 15: current_period_end-Fallback im Webhook fehlte → Fix: items.data[0] Fallback (stripe_routes.py)
Geaenderte Dateien:
- basis14.py: _has_remote_backend() + _show_activation_gate() Bypass bei Remote-Backend
- stripe_routes.py: current_period_end Fallback in checkout.session.completed + subscription.updated/deleted
Damit ist der vollstaendige Produktivpfad nachgewiesen:
- Kauf → active Lizenz → Desktop Vollmodus → current_period_end korrekt
- Storno → canceled → Desktop Testmodus (frueherer Block)
ERLEDIGT: Betreiber-/Revenue-Kontrolle mit Einzelposten (2026-03-31)
Status: BEWIESEN. Betreiber kann Lizenzen, Zahlungen, Refunds und Subscription-Status praktisch kontrollieren.
Was erweitert wurde:
- revenue_overview liefert jetzt recent_charges und recent_refunds als Einzelposten-Listen
- Jeder Charge-Eintrag: amount_chf, email, date_utc, description, charge_id
- Jeder Refund-Eintrag: amount_chf, date_utc, refund_id
Bewiesen:
- recent_charges: 59.0 CHF, admin@aza-medwork.ch
- recent_refunds: 59.0 CHF
Root Cause 16: revenue_overview war zu grob fuer praktische Betreiber-Kontrolle → Fix: Einzelposten ergaenzt (admin_routes.py)
Geaenderte Datei: admin_routes.py (revenue_overview Endpunkt)
SICHERHEITSNOTIZ: Admin-Token wurde im Chat offengelegt (2026-03-31)
WICHTIG: Der echte AZA_ADMIN_TOKEN wurde in einem Chat-Verlauf sichtbar. Er wurde NOCH NICHT rotiert. Chat loeschen rotiert den Token NICHT. Token-Rotation ist ein moeglicher spaeterer Mini-Block.
Empfehlung: Vor produktivem Kundenbetrieb Token rotieren:
- Neuen Token generieren (z.B.
python3 -c "import secrets; print(secrets.token_urlsafe(32))") - In
/root/aza-app/deploy/.envalsAZA_ADMIN_TOKEN=neuer_tokensetzen cd /root/aza-app/deploy && docker compose up -d --build --force-recreate aza-api
RELEASE + UPDATER PRODUKTIV (Stand 2026-04-02)
aza_version.pysteht korrekt aufAPP_VERSION = "1.0.0",APP_CHANNEL = "stable"- Produktiver Installer und
version.jsonwurden erfolgreich nach Hetzner hochgeladen - Desktop-Updater funktioniert im produktiven Pfad (prueft
https://api.aza-medwork.ch/download/version.json, laedt Installer herunter und startet ihn) - Kein Testzustand aktiv
- Die fruehere Update-Endlosschlaufe war durch die Testversion
0.9.0inaza_version.pyverursacht; produktiv ist dieser Zustand behoben - Fuer den weiteren Projektverlauf kein erneuter Update-Test noetig, ausser bei echter neuer Version
- Release-Skripte:
.\ship_release.ps1(Build + Upload),.\publish_update.ps1(nur Upload)
LIZENZSCHLUESSEL-FLOW PRODUKTIV (Stand 2026-04-06)
/license/activateund/license/statusfunktionieren produktiv auf Hetzner- Lizenzschluessel werden beim Kauf automatisch erzeugt (Format:
AZA-XXXX-XXXX-XXXX-XXXX) - Lizenzschluessel koennen ueber die Desktop-App aktiviert werden
/license/status?license_key=...liefertvalid: truefuer aktive Lizenzen- Device-Enforcement ist aktiv und funktioniert korrekt
- Bestehende Device-Bindings waren zeitweise Blocker; fuer den Testdatensatz wurden sie geloescht
- Produktiver Test mit aktivem Lizenzschluessel erfolgreich
- Success-Seite (
/billing/success) zeigt dem Kunden den Lizenzschluessel nach Kauf an
Mailversand produktiv ueber Resend (Stand 2026-04-06)
- Produktiver Versandkanal: Resend HTTP API (nicht Hostpoint-SMTP)
- Hostpoint-SMTP von Hetzner war nicht erreichbar (
Network is unreachableauf Port 465/587) - Umstellung auf Resend API wurde umgesetzt und produktiv getestet
- Resend-Domain:
mail.aza-medwork.ch(DNS bei Hostpoint verifiziert) - Absender:
AZA MedWork <noreply@mail.aza-medwork.ch>(via ENVMAIL_FROM) - Technischer Fix: Resend-Request braucht
User-AgentHeader (war Error 1010 ohne) - Test-Endpunkt
POST /stripe/test_license_email?email=admin@aza-medwork.chliefert:{"sent": true, "to": "admin@aza-medwork.ch"} - E-Mail kommt produktiv an
ENV-Variablen fuer Mailversand (auf Hetzner in /root/aza-app/deploy/.env):
| Variable | Wert | Rolle |
|---|---|---|
RESEND_API_KEY |
re_... (geheim) |
Resend API Credential |
MAIL_FROM |
AZA MedWork <noreply@mail.aza-medwork.ch> |
Absender |
Fallback: SMTP-Code ist noch vorhanden, wird aber nur genutzt wenn RESEND_API_KEY nicht gesetzt ist. Hostpoint-SMTP-Variablen in .env sind inaktiver Fallback.
Hetzner-Infrastruktur-Hinweise
- Repo-Root auf Hetzner:
/root/aza-app - Docker-Compose-Ordner:
/root/aza-app/deploy .env-Datei:/root/aza-app/deploy/.env- Rebuild-Befehl (auf Hetzner via SSH):
cd /root/aza-app/deploy && docker compose down && docker compose up -d --build
NAECHSTER HAUPTBLOCK: END-TO-END-KUNDENTEST
Ziel: Kompletten Kundenfluss ohne Basteln beweisen:
- Echter oder kontrollierter Kaufpfad (Stripe Checkout)
- Kunde erhaelt E-Mail mit Lizenzschluessel (ueber Resend)
- Kunde laedt AZA ueber offiziellen Download-Link herunter
- Kunde installiert AZA
- Kunde aktiviert mit Lizenzschluessel in der Desktop-App
- Desktop startet im Vollmodus
Zielbild fuer Kundenfluss: Kauf → Mail mit Lizenzschluessel + Download-Link → Download → Installation → Aktivierung
Empfehlung:
- Nicht zuerst rohen Installer-Link priorisieren
- Besser echter Kundenfluss ueber offizielle Website / Download-Seite
- Mail soll klaren Download-Link enthalten
OFFENE RESTPUNKTE (Stand 2026-04-06)
- Mailtext und Success-Seite spaeter inhaltlich polieren (kein Blocker)
- Alte SMTP-Reste in
.envsind inaktiver Fallback, nicht mehr produktiver Weg - Exposed Secrets aus Chatverlaeufen spaeter rotieren (Admin-Token, ggf. andere)
- Resend-Setup / Domain-Policy bei Bedarf weiter polieren (kein akuter Blocker)
- Device-Bindings-Management fuer Mehrgeraete-Szenarien spaeter klarer machen
ARBEITSSTIL-LEITLINIEN FUER NAECHSTEN CHAT
- Nutzer will praezise lineare Operator-Schritte
- Immer angeben, WO etwas auszufuehren ist:
[Windows PowerShell]– lokaler Rechner[Hetzner SSH]–ssh root@178.104.51.177[Browser]– URL angeben[Composer/IDE]– Cursor/Editor
- Immer konkrete Copy-Paste-Befehle
- Immer mit Pfad/Ort starten
- Nicht schreiben, was der Nutzer NICHT tun soll, sondern nur den naechsten exakten Schritt
- Keine Variantenflut
- Root-cause-first beibehalten
- Keine Monsterpatches
- Keine Rueckfragen-Orgien
VERBINDLICHER RELEASE-PROZESS (Stand 2026-04-02)
Verbindlicher Operator-Befehl fuer produktiven Build + Upload:
.\ship_release.ps1
Ablauf intern:
release.ps1(baut EXE → Installer → Manifest, verifiziert Artefakte)publish_update.ps1(Upload Installer + version.json nach Hetzner, Remote-Verifizierung)
Verbindlicher produktiver Installer-Pfad:
dist\installer\aza_desktop_setup.exe
Upload-Ziel:
scp dist\installer\aza_desktop_setup.exe root@<HETZNER_IP>:/root/aza-app/release/aza_desktop_setup.exe
Wichtig:
- NICHT
deploy\build_client_exe.ps1verwenden (erzeugt anderes Artefakt) - NICHT
deploy\aza-deploy\*verwenden (falsche Pfade) - NICHT
deploy\publish-release.ps1verwenden (andere URL-/Namenskonvention)
MOEGLICHE NAECHSTE HAUPTBLOECKE (keiner ist aktuell aktiv)
Stripe-/Webhook-/Lizenz-/Admin-Monitor-/Betreiber-Kontrolle gilt als ETABLIERT. Kein aktueller Hauptblock ist gestartet.
Moegliche naechste Bloecke (nach Prioritaet):
-
Admin-Token-Rotation (Mini-Block, schnell)
- Offengelegten Token rotieren
- 3 Commands, kein Code
-
Betreiber-Runbook / Schnellreferenz standardisieren (Klein)
- Klare Anleitung fuer Lizenz-/Zahlungskontrolle
- Welcher Endpunkt fuer was
- Curl-Beispiele fuer Alltagskontrolle
-
WooCommerce / Produktiver Verkaufspfad (Gross)
- Produkte in WooCommerce anlegen
- Checkout / Mein-Konto / Download / E-Mail
- Billing/Legal/Invoices (CHF, MwSt, AGB)
- Testkauf Ende-zu-Ende validieren
-
Lizenz-/Kundenlogik professionalisieren (Gross)
- Sauberer Kunden-/Lizenz-Lifecycle
- Team-/Praxislogik
- Lokale Persistenz / Statuskonsistenz
-
Browser-AZA (Gross, nach Go-Live)
- Step 22 nach browser_aza_mvp_spec.md
FUEHRENDE SUBSCRIPTION-PREISE (Stand 2026-03-27)
| Plan | Monatlich | Jaehrlich |
|---|---|---|
| 1 Benutzer (Basic) | CHF 59 | CHF 590 |
| 2 Benutzer (Team) | CHF 89 | CHF 890 |
Stripe Lookup-Keys und Price-IDs:
| Lookup-Key | Price-ID | Betrag |
|---|---|---|
aza_basic_monthly |
price_1T53xHL5lREAW68VbuK43lmz |
CHF 59 |
aza_basic_yearly |
price_1T542BL5lREAW68VNLQGCKWZ |
CHF 590 |
aza_team_monthly |
price_1T544tL5lREAW68VkmnmZ21Q |
CHF 89 |
aza_team_yearly |
price_1T545RL5lREAW68VLbIh73AN |
CHF 890 |
Stripe Live-Status (Stand 2026-03-27):
- Stripe Live-Konto existiert und ist eingerichtet
- Produkt
AzA Officemit 4 Preisen angelegt (Basic monatlich/jaehrlich, Team monatlich/jaehrlich) - Payment Links erstellt
- Live-Webhook eingerichtet:
https://api.aza-medwork.ch/stripe/webhook→ 200 OK STRIPE_SECRET_KEYundSTRIPE_WEBHOOK_SECRETkorrekt in Hetzner.env- Aktivierungsschluessel-Fallback im Desktop bei Remote-Backend auf Dev-only begrenzt
OFFENE PFLICHT-DOKUMENTATION – Stripe-Konto:
- Fuehrendes Stripe-Konto (Login / E-Mail): NOCH NICHT DOKUMENTIERT
- Testmodus oder Livemodus aktuell fuehrend: NOCH NICHT DOKUMENTIERT
- Bankkonto fuer Auszahlungen hinterlegt: NOCH NICHT DOKUMENTIERT
- Success-/Cancel-URLs fuehrend: NOCH NICHT DOKUMENTIERT Diese Punkte muessen vor dem ersten echten Kundenkauf dokumentiert sein.
ERLEDIGT: Stripe-/Lizenz-Nacharbeiten (2026-03-28):
Frisches Stripe-Event senden und pruefen ob admin@aza-medwork.ch sauber in DB landet→ ERLEDIGT: Sandbox-Kauf erfolgreich verarbeitettest@example.com aus SQLite bereinigen→ ERLEDIGT: geloescht- Desktop-Lizenzcheck auf
/stripe/license_debug?email={EMAIL}abstimmen → NAECHSTER HAUPTBLOCK - Nach stabilem Abschluss Stripe-Secrets rotieren → OFFEN (spaeter)
- Stripe-Konto Ownership dokumentieren → OFFEN (Admin-Block)
- Bankkonto fuer Stripe-Auszahlungen pruefen → OFFEN (Admin-Block)
ERLEDIGT: Stripe/Lizenz-Webhook-Block + Live-Test ABGESCHLOSSEN (2026-03-30)
Status: Webhook funktional. Sandbox- UND Live-Kauf erfolgreich verarbeitet. Live-Testkauf sauber neutralisiert (Storno + Refund). license_debug zeigt korrekt status=canceled.
Erfolgreicher Sandbox-Kauf (2026-03-28):
- Email:
admin@aza-medwork.ch - Subscription:
sub_1TG4fSRGaRoJio7WyM2KwN53 - Status:
active - Lookup-Key:
aza_basic_monthly - SQLite bereinigt: nur relevanter Datensatz,
test@example.comgeloescht
Erfolgreicher Live-Testkauf + Neutralisierung (2026-03-30):
- Echter Live-Kauf durchgefuehrt → Lizenz initial
active - Subscription in Stripe storniert → Zahlung vollstaendig rueckerstattet
- Webhook lieferte 200 OK fuer alle Events
license_debugzeigt korrektstatus=canceled- Live-Testkauf ist damit technisch und operativ sauber neutralisiert
Geloeste Root Causes (chronologisch):
- StripeObject vs. dict:
.get(...)auf rohen Stripe-Objekten → Fix:event = json.loads(body) .to_dict_recursive()existiert nicht: Niemals verwenden- Doppel-Prefix 404:
prefix="/stripe"in main.py +/stripe/webhookin Router → Fix: nur@router.post("/webhook") - Email-Lookup: Kaskade:
customer_email→customer_details.email→Customer.retrieve(id) - Container-Env-Falle:
docker compose restartreicht nicht →up -d --build --force-recreate - Decimal-Serialisierung:
str(StripeObject)scheitert bei Decimal-Werten → Fix:_stripe_to_dict()+_decimal_default() - Idempotenz-Bug:
_mark_processed()lief auch nach Fehler → Fix: nur nach Erfolg innerhalb try-Block - Stille Exits: Fehlende Daten fuehrten zu 200 OK ohne Log → Fix: lueckenloses Logging
- Sandbox API-Key-Mix: Sandbox-Webhook mit Live-Secret-Key →
No such subscription→ Fix: BOTH sk_test_ + whsec_ fuer Sandbox - missing_lookup_key: Sandbox setzt
price.lookup_keynicht → Fix:_lookup_key_from_price()Fallback - customer_email-Verlust bei Updates (Bug A, 2026-03-30):
_upsert_licenseueberschriebcustomer_emailmit NULL beicustomer.subscription.updated/deleted→ license_debug fand alten aktiven Datensatz statt neuen canceled → Fix: COALESCE in SQL - cancel_at_period_end ignoriert (Bug B, 2026-03-30): Webhook schrieb
status=activeobwohlcancel_at_period_end=true→ Fix: explizite Pruefung im Webhook-Handler - sync_subscription zu restriktiv (Bug C, 2026-03-30): Suchte nur
WHERE status='active'→ Fix: neueste Subscription unabhaengig vom Status, optionale subscription_id im Body
NEVER AGAIN – Stripe-Webhook-Regeln:
- Niemals
.to_dict_recursive()verwenden - Niemals rohe StripeObjects mit
.get(...)behandeln - Niemals
json.loads(str(stripe_obj))– bricht bei Decimal. Immer_stripe_to_dict()verwenden - Webhook nach Signaturpruefung immer als plain JSON:
event = json.loads(body) _mark_processed()NUR nach erfolgreicher Verarbeitung (innerhalb try)- Prefix-Routing: bei
prefix="/stripe"muss Decorator@router.post("/webhook")lauten - Bei
.env-Aenderungen:docker compose up -d --build --force-recreate aza-api - Sandbox und Live strikt trennen: BOTH
STRIPE_SECRET_KEY=sk_test_...+STRIPE_WEBHOOK_SECRET=whsec_...fuer Sandbox - Nach Sandbox-Tests wieder Live in
deploy/.envsetzen
Operative Referenz Hetzner:
- Aktuelle Datei:
/root/aza-app/stripe_routes.py - Working Backup (nach lookup-Fallback):
/root/aza-app/stripe_routes.py.working_lookup_fallback_ok - Aelteres Backup:
/root/aza-app/stripe_routes.py.working_backup - SQLite DB:
/root/aza-app/data/stripe_webhook.sqlite - DB-Backup (nach Sandbox-Erfolg):
/root/aza-app/data/stripe_webhook.sqlite.backup_after_sandbox_success - DB-Backup (vor Email-Fix):
/app/data/stripe_webhook.sqlite.before_email_fix_1774895539 - Repo:
/root/aza-app - Compose:
/root/aza-app/deploy - Logs:
docker logs -f --tail 20 aza-api - Event-Log:
tail -n 20 /root/aza-app/data/stripe_events.log.jsonl - Debug:
curl https://api.aza-medwork.ch/stripe/license_debug?email=admin@aza-medwork.ch - Sync:
curl -X POST https://api.aza-medwork.ch/stripe/sync_subscription - Live-Stripe ist aktuell wieder in
/root/aza-app/deploy/.envgesetzt
Operative Hinweise Stripe Sandbox/Live:
- Sandbox und Live in Stripe strikt getrennt behandeln
- Fuer Sandbox muessen BOTH gesetzt sein:
STRIPE_SECRET_KEY=sk_test_...+STRIPE_WEBHOOK_SECRET=whsec_... - Danach wieder sauber auf Live in
/root/aza-app/deploy/.envzurueckstellen - Im Live-Container wurde
sk_live_erfolgreich verifiziert license_debugist geeignet fuer operativen Schnellcheck- Nach Lizenz-/Subscription-Anomalien immer zuerst DB-Zuordnung pruefen: licenses-Tabelle, customer_email, subscription_id, status
- Bei Bedarf DB-Backup vor Hotfix anlegen
- Keine Secrets in Logs oder Statusdateien
BEWUSST NACHGELAGERT (Polish-Phase)
- Autotext-Fix
- Fenstergroessen anpassen
- Button-Groessen / Layout fuer Online-Praesentation
- Allgemeiner UI-Feinschliff
- Direkte OpenAI-Restpfade in Nebenmodulen bereinigen (translate.py, aza_email.py, diktat_app.py)
Blocker-Regel: Ein klarer Block nach dem anderen.
KUNDENWEG-ANALYSE (2026-03-25)
| Strecke | Status | Detail |
|---|---|---|
| Kauf (WooCommerce) | IN ARBEIT (parallel) | Doku fertig, 7 Admin-Schritte in WordPress-Admin (Hostpoint) |
| Download | TEILWEISE | Mechanik da, WooCommerce-Upload fehlt |
| Installer | FUNKTIONAL FERTIG | Kein Code-Signing (SmartScreen-Warnung) |
| Aktivierung | BRIDGE IMPLEMENTIERT | AZA-Key setzt Vollmodus, Trial-Dialog zeigt Status |
| Erster Start | VARIANTE B LIVE (2026-03-27) | Desktop → Hetzner → OpenAI funktioniert. Kein lokaler OpenAI-Key noetig. |
FOKUSBLOECKE
| Prio | Block | Beschreibung |
|---|---|---|
| ERLEDIGT | B1-W1: Backend /v1/chat | Chat Proxy Endpoint – Grundstein Variante B |
| ERLEDIGT | B1-W2: Desktop umstellen | Alle OpenAI-Calls in basis14.py + Mixin ueber Backend |
| ERLEDIGT | B1-W3: Hetzner Deploy | Backend LIVE auf api.aza-medwork.ch |
| ERLEDIGT | B1-W4: Server-E2E | /health + /v1/chat erfolgreich, Variante B serverseitig nachgewiesen |
| ERLEDIGT | B1-W5: Desktop Live-Test | basis14.py lokal gegen Live-Backend erfolgreich getestet (2026-03-27) |
| ERLEDIGT | Stripe Live-Webhook | Webhook 200 OK, Lizenzeintrag in DB, StripeObject/Routing/Env-Fallen geloest (2026-03-27) |
| ERLEDIGT | Stripe Live-Konto/Produkt/Preise | Produkt AzA Office, 4 Preise, Payment Links, Webhook eingerichtet (2026-03-27) |
| ERLEDIGT | STRIPE-W1: Webhook-Nacharbeiten | Sandbox-Kauf erfolgreich, lookup_key-Fallback, SQLite bereinigt, license_debug funktional (2026-03-28) |
| ERLEDIGT | STRIPE-W2-LIVE: Live-Testkauf | Echter Live-Kauf + Storno + Refund, license_debug=canceled, 3 Bugs gepatcht (2026-03-30) |
| ERLEDIGT | Desktop-Lizenzpfad | canceled → Testmodus, active → Vollmodus korrekt (2026-03-30) |
| ERLEDIGT | Echter Live-Kauf CHF 59 | Kauf → active → Desktop Vollmodus → current_period_end korrekt (2026-03-30) |
| ERLEDIGT | Desktop Aktivierungs-Gate Fix | _has_remote_backend() Bypass bei Remote-Backend (2026-03-30) |
| ERLEDIGT | current_period_end Fix | Fallback in Webhook-Handlern (2026-03-30) |
| ERLEDIGT | Admin Monitor v1 | system_status, licenses_overview, backup_status, billing_overview (2026-03-30) |
| ERLEDIGT | Control Panel v2 | license_customer_map, revenue_overview, alerts, dashboard_summary (2026-03-30) |
| ERLEDIGT | Backup/Storage-Monitor | Taegliches Backup, /host_backups gemountet, ~137 GB frei (2026-03-30) |
| ERLEDIGT | Betreiber-Kontrolle Einzelposten | revenue_overview mit recent_charges/recent_refunds (2026-03-31) |
| OFFEN | Admin-Token-Rotation | Token wurde im Chat offengelegt, Rotation noch offen |
| MOEGLICH | WooCommerce / Produktiver Verkaufspfad | Produkte, Checkout, Download, E-Mail, Billing/Legal |
| MOEGLICH | Lizenz-/Kundenlogik professionalisieren | Sauberer Lifecycle, Team-/Praxislogik |
| NACHGELAGERT | UI-Polish | Autotext-Fix, Fenstergroessen, Buttons, Layout |
| NACHGELAGERT | FB-C: Signing | Signing-Readiness vorbereitet |
| NACHGELAGERT | FB-D: Update-Komfort | Erst nach stabilem Kundenweg |
PRODUKTNAME – AKTUELLE RICHTUNG
Aktueller Favorit: AZA Office
Bevorzugte Langform:
- AZA Office – Ihr medizinischer KI-Arbeitsplatz fuer die Praxis
Zweite gute Variante:
- AZA Office – Die KI-Assistenz fuer medizinische Dokumentation
Status: Aktuelle bevorzugte Naming-Richtung. Noch nicht zwingend final juristisch/brand-strategisch entschieden. Soll fuer WooCommerce/Website/Download/Go-Live/Produktdarstellung wiederverwendet werden.
Fruehere Shortlist (AZA Desktop): Dokumentiert in project_roadmap.json und project_plan.json. Durch AZA Office abgeloest.
VARIANTE B – BESTANDSANALYSE (2026-03-25)
Was fuer serverseitigen OpenAI-Zugriff BEREITS existiert:
| Baustein | Status | Detail |
|---|---|---|
| POST /v1/transcribe | FUNKTIONIERT | Backend→OpenAI fuer Transkription. Muster fuer /v1/chat. |
| Auth-Contract | FUNKTIONIERT | X-API-Token + X-Device-Id. Etabliert. |
| License /license/status | FUNKTIONIERT | Lizenzpruefung ueber Backend. |
| Stripe Billing Portal | FUNKTIONIERT | Desktop holt URL vom Backend. |
| Docker/Caddy/Compose | VORBEREITET | deploy/ Ordner komplett. Lokal verifiziert. |
| OpenAI-Client in backend_main.py | VORHANDEN | from openai import OpenAI importiert. |
| Rate Limiting | VORHANDEN | aza_rate_limit.py (IP + Token Limiter). |
Was die Desktop-App DIREKT zu OpenAI ruft (zu migrieren):
| Feature | Datei | Zeile ca. | API |
|---|---|---|---|
| Chat (zentral) | basis14.py | ~5458 | chat.completions.create |
| News-Suche | basis14.py | ~3417 | chat.completions.create |
| Kommentare | basis14.py | ~7058 | chat.completions.create |
| Med-Detail Kurzinfo | basis14.py | ~7453 | chat.completions.create |
| Usage/Budget | aza_persistence.py | ~500 | /v1/usage (REST) |
| Briefgenerierung | aza_text_windows_mixin.py | diverse | chat.completions.create |
| Uebersetzer | translate.py | diverse | chat.completions.create |
| Diktat-App | apps/diktat/diktat_app.py | diverse | transcriptions/chat |
Was BEREITS ueber Backend laeuft:
- Transkription: transcribe_file_via_backend_with_fallback() → POST /v1/transcribe
- Lizenzpruefung: GET /license/status
- Billing Portal: GET /stripe/billing_portal_url
Luecken fuer Variante B (aktualisiert 2026-03-27):
KEIN /v1/chat Endpoint→ ERLEDIGT (2026-03-26)- Kein kundenbezogenes Usage-Tracking auf dem Server (spaeter)
Backend NICHT auf Hetzner deployed→ ERLEDIGT: api.aza-medwork.ch LIVE (2026-03-26)Desktop zeigt noch auf lokales Backend→ ERLEDIGT (2026-03-27): Desktop → Hetzner → OpenAI funktioniert in der echten App- Kein Kunden-Quota/Budget-Management serverseitig (spaeter)
- Lizenz-/Subscription-Lifecycle – Lizenz an Zahlung koppeln, Rueckfall bei Kuendigung (NAECHSTER HAUPTBLOCK)
ARBEITSWEISE FUER NAECHSTE CHATS
- Root-cause-first statt blindem Nachpatchen
- Ein klarer Block nach dem anderen
- Keine 10 Baustellen gleichzeitig
- Reale installierte Builds staerker gewichten als Code-Behauptungen
- Nicht zu frueh "fertig" sagen
- Desktop unterscheiden in:
- Dev-Code
- Neu gebauter Installer
- Reales Verhalten im installierten Build
KOMMUNIKATIONSHINWEIS (aktualisiert 2026-03-31):
Aktuell NICHT wieder aufmachen / als ETABLIERT betrachten:
- Hetzner-Grunddeploy – ist live und funktioniert
- DNS/Caddy/nginx-Diskussion – ist abgeschlossen
- Basis-Backend-Migration – B1-W1 bis B1-W5 erledigt
- Variante A/B-Diskussion – Variante B ist verbindlich und produktiv
- Stripe-Webhook-Stabilisierung – ABGESCHLOSSEN, alle Root Causes geloest
- Stripe Live-Test – ABGESCHLOSSEN und sauber neutralisiert (Kauf+Storno+Refund)
- Desktop-Lizenzpfad – VALIDIERT, canceled/active korrekt
- Admin Monitor v1 + Control Panel v2 – LIVE und funktional
- Backup/Storage-Monitor – AKTIV
- Stripe-/Webhook-/Lizenz-/Admin-Monitor-Basis ist TECHNISCH BEWIESEN – nicht wieder bei Grundlagen starten
- Echter Live-Kauf CHF 59 bewiesen – Kauf → active → Desktop Vollmodus → current_period_end korrekt
- Desktop Aktivierungs-Gate bei Remote-Backend geloest – _has_remote_backend() Bypass ist live
- current_period_end-Fallback in stripe_routes.py deployed – keine null-Werte mehr
- Betreiber-Kontrolle mit Einzelposten bewiesen – revenue_overview liefert recent_charges + recent_refunds (2026-03-31)
KEIN aktueller Hauptblock ist gestartet. Moegliche naechste Bloecke siehe Abschnitt oben.
SICHERHEITSHINWEIS: Admin-Token wurde im Chat offengelegt. Rotation vor Produktivbetrieb empfohlen.
Kontinuitaet die NICHT verloren gehen darf:
- User bastelt nicht – nur exakte Commands oder komplette Composer-Prompts
- Root-cause-first, keine Monsterpatches
- Hostpoint bleibt Haupt-Website, Hetzner ist Backend/API
- Desktop spricht mit Backend, OpenAI-Key bleibt serverseitig
- Backend-Lizenzstatus ist autoritativ (nicht Aktivierungsschluessel)
- Admin-Control-Panel ist Grundlage fuer Betreiber-Sicht
- Backup/Storage-Monitor ist aktiv
Aktueller lokaler Arbeitsordner
FUEHRENDER PFAD (ab 2026-03-27):
C:\Users\surov\Documents\AZA_GIT\aza\AzA march 2026
ALTER PFAD (HISTORISCH, nicht mehr verwenden):
C:\Users\surov\Documents\AZA\backup 24.2.26
Lokaler Start (Variante B Live-Test)
Bevorzugte Startmethode fuer Live-Test gegen Hetzner-Backend:
cd "C:\Users\surov\Documents\AZA_GIT\aza\AzA march 2026"
python basis14.py
NICHT verwenden fuer Live-Test (setzen Env auf localhost):
start_all.batRUN_AZA_ONECLICK.batSTART_AZA.batstart_backend_autoport.bat
Alter lokaler Dev-Start (nur fuer lokale Entwicklung mit eigenem Backend):
cd "C:\Users\surov\Documents\AZA_GIT\aza\AzA march 2026"
powershell -ExecutionPolicy Bypass -File .\deploy\local_reset_and_start.ps1
Tests (Lokal)
cd "C:\Users\surov\Documents\AZA_GIT\aza\AzA march 2026"
powershell -ExecutionPolicy Bypass -File .\deploy\authorized_test.ps1
powershell -ExecutionPolicy Bypass -File .\deploy\smoke_suite.ps1
Step 14 – Docker/Compose Smoke-Test
Ziel: Container bauen, starten, smoke_suite PASS gegen Docker.
1 Command:
cd "C:\Users\surov\Documents\AZA_GIT\aza\AzA march 2026"
powershell -ExecutionPolicy Bypass -File .\deploy\docker_smoke.ps1
Was das Script macht:
docker compose up -d --build(baut und startet Container)- Wartet bis
/healthHTTP 200 liefert (max 60s) - Fuehrt
smoke_suite.ps1gegen den Container aus - Gibt
[RESULT] PASSoder[RESULT] FAILaus - Bei FAIL bleiben Container laufen (Logs inspizierbar)
Erwartete Checks (smoke_suite):
- GET /health -> 200
- GET /version -> 200 mit {name, build}
- GET /license/status ohne Token -> 401/403
- GET /license/status mit Token -> 200 mit {valid, valid_until}
- GET /stripe/health -> 200 oder 404 (WARN)
- GET /openapi.json -> 200
Bei Fehler:
docker compose -f .\deploy\docker-compose.yml logs --follow
docker compose -f .\deploy\docker-compose.yml down
Step 15 – Caddy/HTTPS Reverse Proxy
Ziel: HTTPS live mit ACME-Zertifikat, Reverse Proxy auf :8000.
- Caddyfile finalisieren (Domain, TLS)
- ACME-Challenge testen
- Reverse Proxy pruefen (
curl https://DOMAIN/health)
Step 16 – Go-Live Runbook
Ziel: Production-Deployment auf VPS oder Buero-PC.
- Webhook erreichbar (Stripe)
- Stripe Signatur ok (STRIPE_WEBHOOK_SECRET)
- Billing Portal Return URL korrekt
- Log-Hygiene: keine Secrets in Logs
Desktop UX / Persistence Block (2026-03-18)
Benutzerdaten bei Deinstallation:
- Inno Setup
CurUninstallStepChangedfragt ob%APPDATA%\AZA Desktopgeloescht werden soll - Standard: Nein (Daten bleiben erhalten, Neuinstallation nutzt vorhandene Daten)
- Dateien:
installer/aza_installer.iss
Signatur-/Benutzername-Logik:
load_signature_name()faellt auf Profilname zurueck wenn kein expliziter Signaturname gesetzt- Einstellungsdialog: Haekchen "Profilname verwenden" + Feld fuer abweichenden Signaturnamen
- Wenn Haekchen aktiv → Profilname. Wenn aus + Name eingetragen → diesen verwenden
- Dateien:
aza_persistence.py,aza_settings_mixin.py
Rechtsklick im Minifenster:
- Gleiche Checkbox wie im Hauptfenster, teilt
_rclick_paste_var, synchronisiert - Datei:
basis14.py
Kommentare-Fenster (TEILWEISE):
- Grundstruktur: Button "Kommentare" in Toolbar, separates Fenster, KI-Kurzkommentare via GPT
- OFFEN: Live-Aktualisierung bei KG-Aenderung, Detailfenster bei Klick auf Kommentar
- Datei:
basis14.py
Briefstil-Lernen aus frueheren Word-Briefen (TEILWEISE):
- DOCX-Upload (Mehrfach), Stilprofil-Analyse via GPT, persistente Stilprofile
- Profilauswahl im Brief-Fenster, Integration in Briefgenerierung als System-Prompt
- OFFEN: Detailmodus-Erweiterung der Stilanalyse, erweiterte Formatunterstuetzung
- Dateien:
aza_persistence.py,aza_text_windows_mixin.py,basis14.py
Autotext Root-Cause-Fix:
- Root Cause:
_is_adminNameError verhinderte Autotext-Dialog im installierten Build - Listener auf bewaehrten Stand (Kopie 13) zurueckgesetzt
- Datei:
basis14.py
Uebersetzer-Stabilitaetsfix (2026-03-19):
- Root Cause: translate.main() erzeugte tk.Tk() in Hintergrund-Thread (frozen Build) – Tkinter nicht threadsafe
- Fix: translate.py akzeptiert parent-Parameter, erstellt Toplevel statt Tk(), kein eigener mainloop()
- basis14.py ruft translate.main(parent=self) direkt auf dem Main-Thread auf
- Zusaetzlich: API-Key-Fallback ueber openai_runtime_config
- Dateien:
translate.py,basis14.py
Briefstil-Profile (2026-03-19, nachgeschaerft):
- KISIM Bericht + Klinischer Bericht als feste Systemprofile (immer sichtbar, nicht loeschbar)
- KISIM = klassischer Gesamtbericht: Diagnose/Allergien/Therapie/Anamnese/Beurteilung/Diagnostik/Procedere
- Klinisch = diagnosezentriert: pro Diagnose KLINIK/DIAGNOSTIK/THERAPIE/Aktuell, dann Allergien/Beurteilung/Procedere
- Praezise medizinische Regeln: keine Ueberinterpretation, keine Halluzination, konservativ kodieren
- Vereinheitlichtes Stilprofil-System im Brief-Fenster:
- Haekchen "Stilprofil anwenden" + Dropdown (keins / Klinischer Bericht / KISIM Bericht / Benutzerprofile)
- Haekchen "Standard fuer Arztbriefe" (persistent)
- Reihenfolge Dropdown: (keins) -> Systemprofile -> gelernte Benutzerprofile
- Stilprofil-Dialog: System-Profile als feste nicht-loeschbare Eintraege, Benutzerprofile per Word-Upload
- Persistenz: stilprofil_enabled, stilprofil_name, stilprofil_default_brief in autotext_data
- Dateien:
aza_prompts.py,aza_text_windows_mixin.py,aza_persistence.py
Persistenz- und Consent-Patch:
- KI-Einwilligung direkt beim Erststart (nach Fachgebiet-Dialog, vor normalem App-Betrieb)
- Benutzerprofil um Code (ZSR/GLN) erweitert (Registrierung + Profil-Bearbeiten)
- Deinstallations-Frage listet alle Benutzerdaten einzeln auf (Profil, Transkripte, Vorlagen, Consent, Signatur etc.)
- Kommentare-Fenster: Toggle "beim Start automatisch oeffnen" + persistent
- Einstellungen logisch gruppiert: LabelFrame "Startverhalten / Fenster"
- Alle Benutzerdaten liegen in %APPDATA%\AZA Desktop und ueberleben Reinstall (Standard: behalten)
- Dateien:
basis14.py,aza_settings_mixin.py,aza_persistence.py,installer/aza_installer.iss
AZA Clean Uninstall / Reset Tool (2026-03-19)
Zweck: Saubere Deinstallation und Reset von AZA Desktop ohne Neustart. Fuer Installer-Abnahme und Reinstall-Tests.
Starten (Doppelklick):
AZA_Deinstallieren.bat
Oder direkt in PowerShell:
cd "C:\Users\surov\Documents\AZA_GIT\aza\AzA march 2026"
powershell -ExecutionPolicy Bypass -File .\tools\aza_clean_uninstall.ps1
Modi:
- Modus 1: Nur App entfernen, Benutzerdaten behalten (Standard fuer Reinstall-Tests)
- Modus 2: Vollstaendig zuruecksetzen inkl. aller Benutzerdaten
Was das Tool macht:
- AZA-Prozesse sauber beenden (erst freundlich, dann forciert)
- Inno-Setup-Uninstaller silent ausfuehren
- Installationsreste bereinigen (Verzeichnis, Shortcuts)
- Firewall-Regel entfernen
- Benutzerdaten je nach Modus behalten oder loeschen
- Registry-Reste bereinigen (falls Inno-Uninstaller nicht verfuegbar)
- Abschlussmeldung: Neustart noetig? Neuinstallation moeglich?
Benutzerdaten-Pfade:
- AppData:
%APPDATA%\AZA Desktop(Profil, Einstellungen, Lizenz, Consent, Autotext, Stilprofile) - Dokumente:
%USERPROFILE%\Documents\KG_Diktat_Ablage(Transkripte, Briefe, Rezepte, Kostengutsprachen)
Dateien: tools/aza_clean_uninstall.ps1, AZA_Deinstallieren.bat
Do-Not-Break Regeln
- Keine bestehenden API-Response-Formate aendern (besonders /license/status)
- Auth/Security nicht modifizieren (Token-Rotation, _check_token)
- Keine Secrets loggen/printen (Tokens, Keys, Passwoerter)
- backend_token.txt nie committen (steht in .gitignore)
- deploy/.env nie committen (enthaelt Produktions-Secrets)
- Immer try/except um History-Logging (darf Response nie blockieren)
- Windows PowerShell 5.1 kompatibel bleiben
- Signatur-/Profilname-Fallback: Wenn kein expliziter Signaturname gesetzt, wird Profilname verwendet
- Benutzerdaten in %APPDATA%\AZA Desktop bei Deinstallation standardmaessig NICHT loeschen
- Aus frueheren Briefen wird nur Stil/Struktur gelernt, KEINE Patientendaten/Altinhalte uebernehmen
Korrektur-Patch (FIX-01) – 2026-03-19
Sammel-Korrektur-Patch mit folgenden Aenderungen:
- Uebersetzer-Label: "Fachuebersetzer" ueberall zu "Uebersetzer" umbenannt (aza_config.py, version.json, CHANGELOG.md, web/index.html, deploy-Docs)
- Kommentare-Fenster fertiggestellt: Haekchen "beim Start automatisch oeffnen" (persistent), Live-Update bei KG-Aenderung (auto-refresh nach KG-Erstellung), klickbare Diagnose-Ueberschriften mit Detailfenster
- Korrektur-Fenster: Scrollbar fuer Liste der gespeicherten Korrekturen (height=8 statt 4), Korrekturen bleiben bei Benutzerdaten-Behalten erhalten
- Stilprofil Live-Anwendung: Bei Profilwechsel/Toggle im Brief-Fenster wird der aktuelle Brief sofort neu generiert (nicht erst beim naechsten Brief). Extrahierte Methode _build_brief_prompt_for_profile() und _regenerate_brief_live()
- Profil-anwenden-Button: Im Stilprofil-Verwaltungsdialog neuer gruener Button "Profil anwenden" – wendet das gewaehlte Profil sofort auf den aktuellen Brief an
- KG direkt im Hauptfenster: make_kg_from_text() schreibt jetzt direkt ins txt_output (via _fill_kg_and_finish), kein separates Popup-Fenster mehr
- Persistenz: dokumente_collapsed wird jetzt korrekt geladen/gespeichert in autotext_data
- Hauptfenster-Zentrierung: Robuste verzoegerte Zentrierung nach vollstaendigem Widget-Aufbau via self.after(50, _ensure_centered), statt zu fruehem center_window() im init
Nachschaerfungs-Patch (FIX-02) – 2026-03-19
- Stilprofil-Dialog nur Verwaltung: Im Dialog _open_brief_stilprofil_dialog() wurde die aktive Profilauswahl (Dropdown+Combobox+on_profile_change) entfernt. Dialog zeigt jetzt nur: aktuell aktives Profil als Status, verfuegbare System-/Benutzerprofile als Liste, Lernfunktion fuer neue Profile, Loeschen von Benutzerprofilen. Aktive Auswahl NUR im Arztbrief-Fenster (Haekchen+Dropdown).
- Kommentare-Fenster auto-open: _auto_refresh_kommentare() oeffnet jetzt das Kommentare-Fenster automatisch nach KG-Erstellung, wenn kommentare_auto_open=True und das Fenster noch nicht offen ist. Checkbox-Text geaendert zu "Kommentare-Fenster standardmaessig oeffnen (nach KG-Erstellung)".
- Logo-Trennung: Wassertropfen-Bild (assets/wassertropfen aza medwork.png) wird zu logo.ico konvertiert fuer EXE-Icon, Desktop-Shortcut, Installer-Icon und Titelleisten-Icon. Originales Logo (assets/logo.png) wird als logo.png im Root fuer internes Branding unten links verwendet. logo.ico in aza_desktop.spec datas aufgenommen fuer Runtime-Zugriff.
Dateien: basis14.py, aza_text_windows_mixin.py, aza_desktop.spec, logo.png, logo.ico
Medikamenten-Detailfenster (FIX-03) – 2026-03-20
- Klick auf Medikament/Diagnose im Kommentare-Fenster: Oeffnet strukturiertes Detailfenster (zentriert) mit KI-generierter Kurzinfo (Indikation, Nebenwirkungen, Anwendung, Schwangerschaft/Stillzeit, Hinweise).
- Quellenauswahl: Dropdown im Detailfenster: compendium.ch (Standard), BASG All-in-One Register, BfArM AMIce. Auswahl persistent in medikament_quelle (autotext_data).
- Originalquelle oeffnen: Button "Originalquelle oeffnen" im Detailfenster oeffnet passende Suchseite zur aktiven Quelle im Browser.
- Persistenz: medikament_quelle in aza_persistence.py (load/save/default).
Dateien: basis14.py, aza_persistence.py
Diagnose-Detailfenster (FIX-04) – 2026-03-20
- Getrennte Detail-Logik: Medikamente ([MED]) und Diagnosen ([DX]) haben eigene Detailfenster mit eigenen Prompts, Quellen und Persistenz-Keys.
- Diagnose-Quellen: DocCheck Flexikon (Standard bei Deutsch), MSD Manual Patienten (Standard bei anderer Sprache). Persistent in diagnose_quelle.
- Medikament-Quellen: compendium.ch / BASG / BfArM (wie bisher). Persistent in medikament_quelle.
- KI-Kommentare: Prompt erzeugt [DX]/[MED]-Tags pro Ueberschrift. _apply_kommentare erkennt Tags und leitet an _show_dx_detail bzw _show_med_detail weiter.
- Visuelle Trennung: Medikamente gruen mit Pillen-Icon, Diagnosen blau mit Krankenhaus-Icon.
Dateien: basis14.py, aza_persistence.py
Detailfenster-Nachschaerfung (FIX-05) – 2026-03-20
- Medikamenten-Prompt: Dosierung jetzt mit konkreter Standarddosierung fuer Erwachsene (z.B. "100 mg s.c. Woche 0 und 4, dann alle 8 Wochen"). Explizite Anweisung, nicht "gemaess aerztlicher Anweisung" zu schreiben. Zielgruppe: Fachpersonal.
- Diagnose-Prompt: Ebenfalls fuer Fachpersonal optimiert, konsistente Abschnittsueberschriften.
- Klickbare Abschnitte: Abschnittsueberschriften in Med- und Dx-Detailfenstern sind blau, fett, unterstrichen und klickbar. Klick oeffnet die aktuell gewaehlte Originalquelle (compendium.ch/BASG/BfArM bzw. DocCheck/MSD).
- Erkennungslogik: Ueberschriften werden anhand bekannter Headings-Liste erkannt (_DETAIL_SECTION_HEADINGS_MED / _DX), mit Umlaut-Normalisierung.
- Hint-Label: Kleiner Hinweistext unter dem Quellen-Dropdown informiert ueber Klickbarkeit.
Dateien: basis14.py
Qualitaets- und Sicherheits-Fixblock (FIX-06) – 2026-03-20
1. Keine Fantasie-Medikamente
- Kommentar-Generator-Prompt verschaerft: NUR real existierende Medikamente als [MED] taggen.
- Medikamenten-Detail-Prompt: Obligatorische Sicherheitspruefung VOR Fachinfo-Generierung. Falls kein reales Medikament erkannt: "KEIN MEDIKAMENT ERKANNT" statt halluzinierter Fachinfos. Bei Tippfehlern: "NICHT EINDEUTIG – Meinten Sie evtl. [Name]?" ohne Fachinfos.
2. Korrektur-Fenster UX
- Hint-Label: "Doppelklick auf Wort im Text = Feld Falsch wird befuellt"
- Felder mit groesserer Schrift und fetter Beschriftung
- Gruener "Uebernehmen"-Button
3. Audionotiz-Stabilitaetsfix
- Root Cause: DiktatApp(tk.Tk) erzeugte zweite Tk-Instanz in Daemon-Thread → Crashes.
- Fix: Toplevel statt Tk im eingebetteten Modus (_as_toplevel_of parameter).
- Recorder-Referenz Race-Condition behoben. Fehlerbehandlung abgesichert.
4. Resize-Griff fuer alle Toplevel-Fenster
add_resize_grip() zu: Kommentare, News, Fachgebiet, Arztzeugnis, KI-Einwilligung, KG-Vorlage, Med/Dx-Detail, Registrierung.
Dateien: basis14.py, apps/diktat/diktat_app.py
Status: Code umgesetzt, Build erstellt. Verifikation im installierten Build steht noch aus.
Nachschaerfungs-Fixblock (FIX-07) – 2026-03-20
1. Resize-Grip Root Cause Fix
- Root Cause:
grip.place()wurde von pack/grid-Inhalten ueberdeckt (Z-Order-Problem). - Fix:
grip.lift()+ wiederholteafter()-Aufrufe, um den Grip garantiert ueber allen Inhalten anzuzeigen. Cursor aufsize_nw_segeaendert. - Datei: aza_ui_helpers.py →
add_resize_grip()
2. Korrekturfenster – Sichtbare Falsch/Richtig-Felder
- Neuer
korr_frame(blauer Rahmen) direkt OBERHALB der gespeicherten Korrekturen-Liste. - Enthalt: "Falsch:" (rot) + Eingabefeld, "Richtig:" (gruen) + Eingabefeld, "Uebernehmen"-Button.
- Hint-Text: "Doppelklick auf ein Wort oben befuellt 'Falsch' automatisch."
- Alter doppelter bottom_add-Block mit Feldern entfernt.
- Datei: basis14.py
3. DocCheck-Links mit konkretem Suchbegriff
- Root Cause: DocCheck Flexikon URL verwendete
?q=(falscher Parameter). DocCheck basiert auf MediaWiki → korrekter Parameter ist?search=. - Fix: URL geaendert zu
Spezial:Suche?search={q}&go=Seite(versucht zuerst Direktartikel, dann Suchergebnis). - Datei: basis14.py →
_DX_QUELLEN
4. Medikamenten-Kurzvorschau – Zentrale Validierung VOR Anzeige (FIX-08)
- Root Cause: Die Kommentar-Generierung lief als EINZELNER AI-Call:
- GPT-4o-mini erzeugte
[MED] DermowartecremeMIT halluziniertem Kurztext _apply_kommentare()zeigte diesen Text 1:1 an- Validierung existierte NUR im ZWEITEN AI-Call des Detailfensters
- Ergebnis: Kurzansicht halluzinierte, Detailfenster sagte "KEIN MEDIKAMENT ERKANNT"
- GPT-4o-mini erzeugte
- Loesung (deterministisch, nicht prompt-basiert):
- Neue Datei
aza_med_validator.pymit ~300 realen Medikamenten/Wirkstoffen (DACH-Raum) validate_medication_name(name)prueft gegen diese Liste (exakt +difflib.get_close_matches())- Wird in
_apply_kommentare()fuer JEDEN[MED]-Eintrag VORHER aufgerufen - Ergebnis:
- Sicher erkannt → normale Anzeige + echte Fachinfo
- Nicht erkannt, aber Kandidat gefunden → ⚠ grau + "Meinten Sie evtl. X?" + klickbarer [Uebernehmen]-Link
- Nicht erkannt, kein Kandidat → ⚠ grau + "Kein sicher erkanntes Medikament."
- AI-generierte Kurzinfo wird bei nicht-erkannten Medikamenten komplett unterdrueckt (skip_until_next_heading)
_accept_med_candidate()ersetzt den Namen im AI-Text und re-rendert
- Neue Datei
- Dateien: aza_med_validator.py (NEU), basis14.py, aza_desktop.spec
Status: Code nachgeschaerft, Build + Installer erstellt (2026-03-20 17:52). Manuelle Verifikation im installierten Build erforderlich. SHA256: 27EB38F60965F23C4C2526D47BB4418306AB5ED4F2CB01910CA18D770D2EF2AB
5. Quellenstrenge Kommentarlogik – Inhaltsquelle / Originallink Trennung (FIX-09/10/11)
- Root Cause (FIX-09): LLM generierte Medikamenten-Infos rein aus Modellwissen.
- Root Cause (FIX-10): System blieb auf Wirkstoff-Ebene haengen. PharmaWiki-Regex falsch, Compendium SPA nicht scrapbar.
- Root Cause (FIX-11): Inhaltsquelle und Originallink waren im Code vermischt. Ein Dropdown steuerte beides.
- Loesung (FIX-11, 2026-03-22) – Saubere Trennung:
- INHALTSQUELLE (was im Detailfenster angezeigt wird):
_fetch_doccheck_info(med_name): DocCheck Flexikon (Standard)_fetch_pharmawiki_info(med_name): PharmaWiki (Fallback)- Benutzerwaehlbar ueber Dropdown "Inhaltsquelle:" im Detailfenster
- Persistent gespeichert als
med_content_quellein_autotext_data - Neues Dict
_MED_CONTENT_QUELLEN(DocCheck, PharmaWiki)
- ORIGINALQUELLE (externer Link / "Originalquelle oeffnen"):
- CH = Compendium, AT = BASG, DE = BfArM – UNVERAENDERT
- Weiterhin ueber
_MED_QUELLEN/medikament_quelle
- Kuratierte Fakten
_MEDICATION_FACTSals Offline-Fallback
- INHALTSQUELLE (was im Detailfenster angezeigt wird):
- Therapien/Prozeduren weiterhin getrennt mit DocCheck/PharmaWiki
- Kandidatenlogik (Dermowarte→Dermovate, Vilastin→Bilastin) unberuehrt
- Dateien: basis14.py
Medikamenten-Quellenlogik Schweiz – Zielarchitektur (ARCH-MED)
Status: Erste Stufe umgesetzt (2026-03-22). Compendium Produkt-Aufloesung + PharmaWiki Quelltext-Extraktion live.
Aktueller Stand (teilweise umgesetzt):
- Compendium.ch Produkt-Aufloesung: Wirkstoff → konkreter Praeparat-Name + Darreichungsform
- PharmaWiki Quelltext-Extraktion: Strukturierte Sektionen fuer Prompt-Injektion
- Kuratierte Faktenliste
_MEDICATION_FACTS(~18 Medikamente) als Offline-Fallback
Endziel fuer Schweizer Modus: AZA soll Medikamenteninformationen fuer die Schweiz grundsaetzlich ueber Compendium.ch nachschlagen koennen – nicht nur ueber eine kleine interne Faktenliste, nicht nur Link-Weiterleitung, nicht nur LLM-Wissen.
Zielarchitektur:
- Medikament im KG-Text erkennen (bestehendes Tagging + Validierung)
- In Compendium.ch suchen (echte Suche, nicht nur Link) – UMGESETZT
- Konkreten Produkt-/Praeparattreffer bestimmen – UMGESETZT (Name + Darreichungsform)
- Relevante Fach-/Produktinfo strukturiert auswerten – UMGESETZT via PharmaWiki, Compendium-Detailseite noch offen
- Kommentarinfo NUR aus diesen quellenbasierten Daten bauen – UMGESETZT
- Was nicht aus der Quelle kommt → weglassen, nicht erfinden – UMGESETZT
Abdeckung:
- PharmaWiki-Fetch deckt grundsaetzlich alle dort verfuegbaren Medikamente ab
- Compendium Produkt-Aufloesung liefert konkreten Praeparat-Namen (abhaengig von Compendium-HTML-Struktur)
- Lokale Faktenliste bleibt als Offline-Fallback
Naechste Schritte (ARCH-MED-01/02):
- Compendium-Detailseiten-Extraktion evaluieren (zusaetzlich zu Produkt-Aufloesung)
- Caching-Strategie festlegen (PharmaWiki-/Compendium-Antworten lokal cachen)
- Robustheit gegen HTML-Strukturaenderungen absichern
- Langfristig: HCI Solutions Datenlizenz / Compendium-API evaluieren
Spaetere Marktprofile:
- DE: BfArM / Gelbe Liste – separat
- AT: BASG – separat
- Jeweils eigenstaendig, nicht mit CH vermischen
Zukunftsblock – Internationalisierung / Laender- und Quellenprofile (GEPARKT)
Status: Zukunftsthema – NICHT fuer jetzt. Erst nach DACH-Stabilitaet und Produkterfolg.
Voraussetzung: DACH-Markt (Schweiz / Deutschland / Oesterreich) sauber stabilisiert, Go-Live gesichert, Produkt erfolgreich.
Zielbild:
- UI je nach Markt/Sprache anpassbar
- Medikamentenquellen je nach Land/Sprache anpassbar
- Diagnose-/Therapiequellen je nach Land/Sprache anpassbar
- Beispiel: DACH zuerst, spaeter franzoesische UI + franzoesische medizinische Quellen/Links
Profil-Architektur (spaeter umsetzen):
app_language– UI-Sprachemarket_region– Zielmarkt/Landmed_source_profile– Medikamentenquellen (Compendium, BASG, BfArM, …)dx_source_profile– Diagnosequellen (DocCheck, MSD, …)therapy_source_profile– Therapiequellen- Manueller Override durch Benutzer/Praxis
Wichtig:
- Nicht hart nach Herkunftsland des Users schalten, sondern saubere Profil-Logik
- Handelsnamen, Zulassungen, Fachinfos und Verfuegbarkeit sind laenderspezifisch
- Deshalb spaeter Quellenprofile pro Markt statt Einheitslogik
- Kein aktueller Implementierungsblock – reines Roadmap-Thema
Status: Build + Installer erstellt (2026-03-22 22:14). Manuelle Verifikation im installierten Build empfohlen. SHA256: ABC12791E0DB8472C78E673EC57D416A796E4B5534FF39D2B7A76B8E94B10C0E
Aktivierungsschluessel → Lizenzmodus Bridge (2026-03-24)
Root Cause: Zwei unabhaengige Gating-Systeme im Desktop-Build:
- Aktivierungsschluessel (aza_activation.py): Kontrolliert ob App STARTET (Trial oder AZA-Key)
- Subscription-Lizenz (check_license_status): Kontrolliert ob DEMO- oder VOLL-Modus
Diese waren NICHT verbunden. Ein zahlender Kunde mit gueltigem AZA-Key lief trotzdem im DEMO-Modus, weil die Subscription-Lizenzpruefung mangels MEDWORK_BACKEND_URL immer fehlschlug.
Fix: In KGDesktopApp.init (basis14.py): Nach check_license_status() wird geprueft, ob ein gueltiger Aktivierungsschluessel vorhanden ist. Falls ja und license_mode noch "demo" → auf "active" setzen.
Auswirkung: ~10 Zeilen, kein Monsterpatch. /license/status unberuehrt. Keine Auth-Aenderung. Erster Kundenweg damit praktikabel: Entwickler generiert Key, sendet per E-Mail, Kunde gibt ein → Vollmodus.
Entschaerfender Faktor: DEMO_MAX_DICTATIONS=9999 (Demo-Modus ist de facto unbeschraenkt). Die Bridge ist trotzdem korrekt, weil DEMO_MAX_DICTATIONS spaeter gesenkt werden soll.
Datei: basis14.py (KGDesktopApp.init, nach self.check_license_status())
Windows Code-Signing / Smart App Control Readiness (2026-03-23)
Problem: Windows Smart App Control (ab Windows 11 22H2) blockiert unsignierte und unbekannte Anwendungen automatisch. Auch ohne Smart App Control zeigt SmartScreen Warnungen bei unsignierten Downloads. Fuer Kundenauslieferung muessen alle ausfuehrbaren Artefakte signiert werden.
Status: Signing-Readiness vorbereitet, noch NICHT produktiv aktiviert (kein Zertifikat vorhanden).
Vorbereitete Dateien:
sign_release.ps1– Signing-Skript (signiert EXE, DLLs/PYDs, Installer; DryRun-Modus; Verifikation)build_and_test_release.ps1– Release-Pipeline mit optionalem Signing-Schritt (graceful skip ohne Zertifikat)build_release_artifacts.ps1– Artefakt-Report enthaelt jetzt signing_status und signing_subjectSIGNING_READINESS.md– Vollstaendige Dokumentation mit Artefakt-Liste, Signing-Reihenfolge, Zertifikats-Optionen, Checkliste
Artefakte die signiert werden muessen:
| Prioritaet | Artefakt | Pfad |
|---|---|---|
| Kritisch | Haupt-EXE | dist\aza_desktop\aza_desktop.exe |
| Kritisch | Installer | dist\installer\aza_desktop_setup.exe |
| Empfohlen | DLLs | dist\aza_desktop\_internal\*.dll |
| Empfohlen | PYDs | dist\aza_desktop\_internal\*.pyd |
Signing-Reihenfolge in der Pipeline:
Desktop Build → DLLs/PYDs signieren → EXE signieren → Installer Build → Installer signieren → Artefakt-Report → Publish
Noch offen vor Kundenauslieferung:
- EV Code-Signing-Zertifikat beschaffen (empfohlen: DigiCert/Sectigo, ca. CHF 400–600/Jahr; alternativ Azure Trusted Signing)
- signtool.exe installieren (Windows SDK)
- Publisher-Name im Zertifikat mit
AppPublisherinaza_installer.issabstimmen (aktuell:AZA MedWork) sign_release.ps1produktiv ausfuehren- Signierte Artefakte auf sauberem Windows-PC mit aktivem Smart App Control testen
Publisher-/Namenskonsistenz (Analyse 2026-03-23):
Im Projekt existieren 3 verschiedene Namensformen. Dies ist KEINE Inkonsistenz – jede Form hat eine klare Rolle:
| Namensform | Rolle | Signing-relevant | Stellen |
|---|---|---|---|
| AZA MedWork | Firma / Publisher | JA – signing-kritisch | aza_installer.iss, legal/privacy_policy.md, legal/ai_consent.md, deploy/WOOCOMMERCE_PRODUCT.md, deploy/WORDPRESS_GOLIVE.md |
| AZA Desktop | Produktname | Nein | aza_config.py, CHANGELOG.md, web/download.html, tools/aza_clean_uninstall.ps1, translate.py, build_exe.ps1, deploy/PRODUCT_V1.md |
| AZA Medical AI Assistant | Interner Projektname | Nein | project_status.json, project_status_routes.py, web/index.html, billing/invoice_template.json, billing/BILLING_FLOW.md |
Vor Zertifikatskauf zu klaeren:
- Offiziellen Firmennamen im Handelsregister pruefen
- EV-Zertifikats-Subject muss exakt mit HR-Name uebereinstimmen
AppPublisherinaza_installer.issauf Zertifikats-Subject abstimmen- Falls HR-Name von "AZA MedWork" abweicht: alle signing-relevanten Stellen gemeinsam anpassen
- SmartScreen-Reputation baut auf Publisher-Namen auf – nach Festlegung NICHT mehr aendern
Stellen die bei Namensaenderung gemeinsam angepasst werden muessen:
installer/aza_installer.iss→MyAppPublisherlegal/privacy_policy.md→ Zeile 5 + Zeile 27legal/ai_consent.md→ Zeile 10, 12, 132deploy/WOOCOMMERCE_PRODUCT.md→ Absendernamedeploy/WORDPRESS_GOLIVE.md→ AbsendernameSIGNING_READINESS.md→ Beispielnameapps/diktat/diktat_app.py→ Docstringaza_consent.py→ Docstring
Stellen die NICHT angepasst werden muessen (nicht signing-relevant):
project_status.json("AZA Medical AI Assistant" ist interner Projektname)project_status_routes.py(API-Response, intern)billing/invoice_template.json(Rechnungsposition, kann abweichen)web/index.html,web/download.html(Marketing-Langname)
Do-Not-Break:
- Keine echten Zertifikate oder Secrets ins Repository committen
- Signing-Schritt ist optional (Pipeline laeuft auch ohne Zertifikat durch)
- Keine Pseudo-Signierung oder Fake-Zertifikate
- Publisher-Name nach Festlegung NICHT mehr wechseln