18 KiB
AZA – Detaillierte Projektuebergabe / Handover
Stand: 2026-04-06 Zweck: Diese Datei ist die verbindliche Referenz fuer jeden neuen Chat. Zuerst lesen, dann arbeiten.
1. Projektziel / Aktueller Fokus
AZA (AZA Medical AI Assistant / AZA Desktop) ist eine medizinische KI-Desktop-Anwendung fuer Windows. Sie unterstuetzt Aerzte bei Diktat, Textverarbeitung, medizinischer Recherche und Dokumentation.
Architektur (Variante B – verbindlich seit 2026-03-25):
- Desktop-App (Python/Tkinter) kommuniziert mit eigenem AZA-Backend auf Hetzner
- Backend leitet KI-Anfragen serverseitig an OpenAI weiter
- Kein OpenAI-Key beim Kunden noetig
- Kein OpenAI-Key in der Desktop-App
Aktueller Schwerpunkt: Produktiver Kundenfluss mit Lizenzschluessel. Die klare Zielsequenz ist:
Kauf → Lizenzschluessel per E-Mail → Download → Installation → Aktivierung → Nutzung
2. Aktueller stabiler technischer Stand
2.1 Lizenzschluessel-Flow (PRODUKTIV, Stand 2026-04-06)
| Aspekt | Status |
|---|---|
/license/activate |
Funktioniert produktiv auf Hetzner |
/license/status |
Funktioniert produktiv auf Hetzner |
| Lizenzschluessel-Erzeugung | Automatisch beim Kauf (Format: AZA-XXXX-XXXX-XXXX-XXXX) |
| Lizenzschluessel in DB | Gespeichert in licenses-Tabelle, Spalte license_key |
| Desktop-Aktivierung | Lizenzschluessel kann in der Desktop-App eingegeben und aktiviert werden |
/license/status?license_key=... |
Liefert valid: true fuer aktive Lizenzen |
| Device-Enforcement | Aktiv und funktioniert korrekt |
Success-Seite /billing/success |
Zeigt dem Kunden den Lizenzschluessel nach Kauf an |
| Produktiver Test | Erfolgreich mit aktivem Lizenzschluessel |
Wichtig: Device-Bindings waren zeitweise ein Blocker. Fuer den Testdatensatz (admin@aza-medwork.ch) wurden bestehende Device-Bindings aus der DB geloescht, damit der erneute Aktivierungstest funktionierte. Bei neuen Kunden tritt dieses Problem nicht auf.
2.2 Mailversand (PRODUKTIV ueber Resend, Stand 2026-04-06)
| Aspekt | Status |
|---|---|
| Produktiver Versandkanal | Resend HTTP API |
| Resend-Domain | mail.aza-medwork.ch (DNS bei Hostpoint verifiziert) |
| Absender / MAIL_FROM | AZA MedWork <noreply@mail.aza-medwork.ch> |
| Test-Endpunkt | POST /stripe/test_license_email?email=... (Admin-geschuetzt) |
| Letzter erfolgreicher Test | {"sent": true, "to": "admin@aza-medwork.ch"} |
| E-Mail Zustellung | Produktiv bestaetigt – Mail kommt an |
2.3 Stripe / Billing (PRODUKTIV)
| Aspekt | Status |
|---|---|
| Stripe-Modus | Live (sk_live_) |
| Webhook-Endpunkt | https://api.aza-medwork.ch/stripe/webhook |
| Echter Live-Kauf | CHF 59 Basic Monthly erfolgreich durchgefuehrt |
| Lizenz-Lifecycle | Kauf → active → Storno/Refund → canceled → Desktop Testmodus (bewiesen) |
| Webhook-Events | checkout.session.completed, customer.subscription.updated, customer.subscription.deleted |
2.4 Desktop-App
| Aspekt | Status |
|---|---|
| Lizenzpruefung | Ueber Backend (/license/status) mit Lizenzschluessel |
| Vollmodus | Wenn Backend valid: true liefert |
| Testmodus | Wenn keine gueltige Lizenz oder Backend nicht erreichbar |
| Lokales Aktivierungs-Gate | Bei Remote-Backend uebersprungen (Root Cause 14 behoben) |
| Update-Checker | Prueft https://api.aza-medwork.ch/download/version.json beim Start |
| Aktuelle Version | APP_VERSION = "1.0.0", APP_CHANNEL = "stable" |
2.5 Admin Control Panel (PRODUKTIV)
8 interne Admin-Endpunkte, geschuetzt via X-Admin-Token / AZA_ADMIN_TOKEN:
v1:
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:
GET /admin/license_customer_map– Detaillierte Lizenznehmer-Uebersicht,?email=und?status=FilterGET /admin/revenue_overview– MRR, Stripe-Live-Daten (gross/refunds/net), recent_charges, recent_refundsGET /admin/alerts– Strukturierte Warnliste (info/warning/critical)GET /admin/dashboard_summary– Sammel-Endpunkt fuer alle Kennzahlen
2.6 Backup / Storage
- Taegliches Backup-Skript:
/root/aza-backups/backup_aza.sh(Cronjob) - Backup-Pfad:
/root/aza-backups/daily/ - In Container gemountet als
/host_backups(read-only) - Ca. 137 GB frei, ca. 4-5% belegt – kein Speicherdruck
3. Mailversand-Historie / Root Causes / Finaler Weg
Chronologie
-
Erster Versuch: Hostpoint-SMTP
- Hostpoint-Mailbox
noreply@aza-medwork.chwurde angelegt - SMTP-Server:
asmtp.mail.hostpoint.ch - Port 465 (SSL) und 587 (STARTTLS) getestet
- SMTP-Daten wurden mehrfach geprueft und waren korrekt
- Hostpoint-Mailbox
-
Beobachtete Fehler (SMTP von Hetzner/Container):
- Erste Tests: Auth-Fehler (falscher Host
mail.hostpoint.chstattasmtp.mail.hostpoint.ch) - Nach Host-Korrektur:
OSError: [Errno 101] Network is unreachable - Port 465 → Timeout / Network unreachable
- Port 587 → Timeout / Network unreachable
- Ursache: Hetzner-Container kann Hostpoint-SMTP-Server nicht erreichen (Netzwerk-/Firewallsperre)
- Erste Tests: Auth-Fehler (falscher Host
-
Schlussfolgerung:
- Hostpoint-SMTP ist von Hetzner aus nicht nutzbar
- Das ist ein Infrastruktur-/Netzwerkproblem, kein Code-Problem
- Hostpoint-SMTP ist nicht der produktive Versandweg
-
Loesung: Umstellung auf Resend HTTP API
- Resend-Account erstellt
- Domain
mail.aza-medwork.chbei Resend registriert und via DNS bei Hostpoint verifiziert MAIL_FROMgesetzt aufAZA MedWork <noreply@mail.aza-medwork.ch>- Code in
stripe_routes.pyumgebaut:_send_via_resend()als primaerer Kanal - Wichtiger Fix: Resend-HTTP-API erfordert
User-AgentHeader (ohne → Error 1010/403) - Fix angewandt:
"User-Agent": "AZA-MedWork/1.0"im Request
-
Finaler erfolgreicher Test:
POST /stripe/test_license_email?email=admin@aza-medwork.ch → {"sent": true, "to": "admin@aza-medwork.ch"}E-Mail kam produktiv an.
Aktueller Zustand der Mailfunktion in stripe_routes.py
send_license_email(to_email, license_key)
├── RESEND_API_KEY gesetzt? → _send_via_resend() [PRODUKTIVER WEG]
└── sonst → _send_via_smtp() [INAKTIVER FALLBACK]
- SMTP-Code ist noch vorhanden als Fallback
- SMTP-Variablen in
.envsind Altlast, nicht produktiv aktiv - Wenn
RESEND_API_KEYgesetzt ist (und das ist es), wird immer Resend benutzt
4. Wichtige Pfade / Betriebsorte / Operator-Wissen
Lokaler Windows-Rechner
| Was | Pfad |
|---|---|
| Projektordner | C:\Users\surov\Documents\AZA_GIT\aza\AzA march 2026 |
| Desktop-App direkt starten | python basis14.py (im Projektordner) |
| Build-EXE | .\build_exe.ps1 |
| Build-Installer | .\build_installer.ps1 |
| Kompletter Release | .\ship_release.ps1 |
| Nur Upload | .\publish_update.ps1 |
| Installer-Artefakt | dist\installer\aza_desktop_setup.exe |
| Release-Manifest | release\version.json |
| Versionsquelle | aza_version.py (APP_VERSION, APP_CHANNEL) |
Wichtig: NICHT ueber lokale Starter starten (start_all.bat, RUN_AZA_ONECLICK.bat, START_AZA.bat, start_backend_autoport.bat) – diese setzen Env-Variablen auf localhost und ueberschreiben die Live-Backend-URL.
Hetzner-Server (SSH)
| Was | Pfad / Befehl |
|---|---|
| SSH-Zugang | ssh root@178.104.51.177 |
| Repo-Root | /root/aza-app |
| Docker-Compose-Ordner | /root/aza-app/deploy |
.env-Datei |
/root/aza-app/deploy/.env |
| Rebuild (immer im deploy-Ordner!) | cd /root/aza-app/deploy && docker compose down && docker compose up -d --build |
| Container-Logs | docker logs aza-api --tail 100 |
| ENV im Container pruefen | docker exec aza-api env | grep VARIABLE |
| Backup-Ordner | /root/aza-backups/daily/ |
WICHTIG: docker compose Befehle muessen IMMER im Ordner /root/aza-app/deploy ausgefuehrt werden, nicht im Repo-Root /root/aza-app.
Hostpoint (Website / DNS)
| Was | Detail |
|---|---|
| Haupt-Website | Hostpoint bleibt fuer Website, Marketing, WooCommerce |
| DNS-Verwaltung | Bei Hostpoint (fuer aza-medwork.ch und Subdomains) |
| Mailboxen | Hostpoint verwaltet Mailboxen (z.B. noreply@aza-medwork.ch) |
| Resend-DNS | mail.aza-medwork.ch DNS-Records fuer Resend bei Hostpoint gesetzt |
Produktive URLs
| URL | Zweck |
|---|---|
https://api.aza-medwork.ch |
Backend-API |
https://api.aza-medwork.ch/health |
Health-Check |
https://api.aza-medwork.ch/stripe/webhook |
Stripe-Webhook |
https://api.aza-medwork.ch/download/version.json |
Update-Manifest |
https://api.aza-medwork.ch/download/aza_desktop_setup.exe |
Installer-Download |
https://api.aza-medwork.ch/billing/success |
Kauf-Erfolgsseite |
5. Wichtige ENV / Konfiguration
Aktive produktive ENV-Variablen (auf Hetzner in /root/aza-app/deploy/.env)
| Variable | Rolle | Status |
|---|---|---|
RESEND_API_KEY |
Resend API Credential fuer Mailversand | AKTIV PRODUKTIV |
MAIL_FROM |
Absender fuer Lizenzschluessel-Mail | AKTIV PRODUKTIV |
STRIPE_SECRET_KEY |
Stripe Live API Key (sk_live_...) | AKTIV PRODUKTIV |
STRIPE_WEBHOOK_SECRET |
Stripe Webhook Signing Secret | AKTIV PRODUKTIV |
AZA_ADMIN_TOKEN |
Token fuer Admin-Endpunkte | AKTIV PRODUKTIV |
MEDWORK_API_TOKENS |
API-Token fuer Desktop-Backend-Kommunikation | AKTIV PRODUKTIV |
OPENAI_API_KEY |
OpenAI API Key (serverseitig) | AKTIV PRODUKTIV |
AZA_DOMAIN |
api.aza-medwork.ch |
AKTIV PRODUKTIV |
ACME_EMAIL |
info@aza-medwork.ch (fuer Caddy/HTTPS) |
AKTIV PRODUKTIV |
Inaktive / historische ENV-Variablen
| Variable | Rolle | Status |
|---|---|---|
SMTP_HOST |
Hostpoint SMTP Server | INAKTIV – Fallback, wird nicht genutzt |
SMTP_PORT |
Hostpoint SMTP Port | INAKTIV – Fallback |
SMTP_USER |
Hostpoint SMTP User | INAKTIV – Fallback |
SMTP_PASS |
Hostpoint SMTP Passwort | INAKTIV – Fallback |
SMTP_FROM |
Hostpoint SMTP Absender | INAKTIV – Fallback |
Keine Rueckkehr zu Hostpoint-SMTP noetig, solange Resend stabil laeuft.
6. Naechster Hauptblock: End-to-End-Kundentest
Ziel: Den kompletten Kundenfluss ohne Basteln, ohne manuelle DB-Eingriffe und ohne Operator-Hilfe beweisen.
Zielbild fuer den Kundenfluss
1. Kunde kauft ueber Stripe Payment Link / Checkout
2. Stripe Webhook verarbeitet den Kauf
3. Backend erzeugt Lizenzschluessel und speichert ihn in der DB
4. Resend sendet automatisch E-Mail mit Lizenzschluessel an den Kunden
5. Success-Seite zeigt dem Kunden ebenfalls den Lizenzschluessel
6. Kunde laedt AZA ueber offiziellen Download-Link herunter
7. Kunde installiert AZA
8. Kunde gibt Lizenzschluessel in der Desktop-App ein
9. Desktop aktiviert gegen Backend (/license/activate)
10. Desktop startet im Vollmodus
Was dabei noch geprueft / sichergestellt werden muss
- E-Mail mit Lizenzschluessel kommt automatisch beim Kauf an (nicht nur via Test-Endpunkt)
- Download-Link in der E-Mail ist korrekt und funktioniert
- Installer laesst sich sauber installieren
- Erststart ohne vorherige Konfiguration funktioniert
- Lizenzschluessel-Eingabe in der App funktioniert auf Anhieb
- Vollmodus wird sofort nach Aktivierung erreicht
7. Download-/Installer-Entscheidung
Fuer den naechsten Kundenfluss-Test:
- Download soll ueber die offizielle Website / Download-Seite priorisiert werden
- Nicht zuerst einen rohen Direktlink als Hauptweg verwenden
- Die E-Mail soll idealerweise einen klaren Download-Link enthalten
- Der Kundentest soll moeglichst realistisch am echten Kundenablauf orientiert sein
Zielbild: Mail mit Lizenzschluessel + klarem Download-Link → Download → Installation → Aktivierung
Aktuell verfuegbarer Direktlink:
https://api.aza-medwork.ch/download/aza_desktop_setup.exe
8. Offene Restpunkte
| Punkt | Prioritaet | Blocker? |
|---|---|---|
| Mailtext und Success-Seite inhaltlich polieren | Niedrig | Nein |
| Admin-Token rotieren (wurde im Chat offengelegt) | Mittel | Nein, aber vor echtem Kundenbetrieb empfohlen |
SMTP-Reste in .env aufraeumen |
Niedrig | Nein (inaktiv) |
| Resend-Setup / Domain-Policy weiter polieren | Niedrig | Nein |
| Device-Bindings-Management fuer Mehrgeraete klarer machen | Mittel | Nein |
| translate.py, aza_email.py, diktat_app.py auf Backend-Chat migrieren | Niedrig | Nein (Nebenpfade) |
| WooCommerce / Website-Kaufpfad professionalisieren | Mittel | Spaeterer Block |
| Browser-AZA / Web-App | Niedrig | Spaeterer Block |
9. Arbeitsstil / Nutzerpraeferenzen
Diese Regeln gelten fuer ALLE zukuenftigen Chats:
Allgemeine Regeln
- Nutzer bastelt nicht – alle Aenderungen kommen als fertige, vollstaendige Dateien (ready-to-paste)
- Nutzer fuehrt nur vorgegebene Commands aus, keine manuellen Edits
- Jede Aenderung in 1 Patch, kein schrittweises Anleiten
- Keine risky Refactors – immer minimal und sicher
- Root-cause-first bei jedem Problem
- Keine Monsterpatches
- Keine Rueckfragen-Orgien
- Keine Variantenflut – genau 1 Weg, der beste
Operator-Schritte
- Immer explizit angeben, WO ein Schritt auszufuehren ist:
[Windows PowerShell]– lokaler Rechner, Projektordner[Hetzner SSH]–ssh root@178.104.51.177[Browser]– URL angeben[Composer/IDE]– Cursor Editor
- Immer exakte Copy-Paste-Befehle liefern
- Immer mit Pfad oder Ort starten
- Nicht schreiben, was der Nutzer NICHT tun soll, sondern nur den naechsten exakten Schritt
- Keine vagen Formulierungen wie "send this" oder "do something like"
- Nutzer will moeglichst wenig manuelle Improvisation
Uebergaben
- Uebergaben fuer naechste Chats sollen ausfuehrlich sein, nicht minimal
- Wichtige Root Causes immer dokumentieren
- Geloeste Probleme klar als geloest markieren
- Nicht bei alten Problemen wieder anfangen
10. Empfohlener Chat-Start fuer den naechsten Chat
Sinnvolle naechste Hauptbloecke (nach Prioritaet)
-
End-to-End-Kundentest (EMPFOHLEN als naechstes)
- Kontrollierter Kauf → automatische E-Mail → Download → Installation → Aktivierung → Vollmodus
- Beweisen, dass der gesamte Fluss ohne Basteln funktioniert
-
Download-Seite / Website-Kaufpfad
- Offizielle Download-Seite auf der Website einrichten
- Klaren Kundenweg von Website → Kauf → Download definieren
-
Admin-Token-Rotation + Secrets-Hygiene
- Offengelegten Admin-Token rotieren
- Sicherstellen, dass keine Secrets im Repo liegen
Beste Empfehlung
Starte mit Block 1: End-to-End-Kundentest.
Erster konkreter Operator-Schritt
[Browser]
Stripe Payment Link oeffnen und kontrollierten Testkauf mit einer
frischen E-Mail-Adresse durchfuehren (NICHT admin@aza-medwork.ch,
sondern eine neue Adresse, um den Neukundenfall zu simulieren).
Danach pruefen:
[Hetzner SSH]–/stripe/license_debug?email=NEUE_EMAIL→ aktive Lizenz?[E-Mail-Postfach]– Lizenzschluessel-Mail angekommen?[Browser]– Installer herunterladen ueber Link aus der Mail[Windows]– Installer ausfuehren, App starten, Lizenzschluessel eingeben[Desktop-App]– Vollmodus bestaetigen
11. Geloeste Root Causes (Referenz)
| RC | Problem | Loesung | Datei | Datum |
|---|---|---|---|---|
| RC14 | Desktop zeigte Testversion trotz aktiver Remote-Lizenz | _has_remote_backend() Bypass fuer lokales Aktivierungs-Gate |
basis14.py |
2026-03-30 |
| RC15 | current_period_end war null fuer aktive Lizenz |
Fallback auf items.data[0].current_period_end im Webhook |
stripe_routes.py |
2026-03-30 |
| RC16 | revenue_overview zu grob fuer Betreiber | recent_charges und recent_refunds ergaenzt |
admin_routes.py |
2026-03-31 |
| RC17 | SMTP von Hetzner → Hostpoint nicht erreichbar | Umstellung auf Resend HTTP API | stripe_routes.py |
2026-04-06 |
| RC18 | Resend-API lehnte Request ab (Error 1010/403) | User-Agent: AZA-MedWork/1.0 Header ergaenzt |
stripe_routes.py |
2026-04-06 |
12. Wichtige Dateien im Projekt
Backend (auf Hetzner unter /root/aza-app/)
| Datei | Rolle |
|---|---|
backend_main.py |
FastAPI-Hauptanwendung, mountet alle Router |
stripe_routes.py |
Stripe-Webhook, Lizenz-DB, Mailversand, Lizenzschluessel-Erzeugung |
admin_routes.py |
Admin Control Panel v1+v2 Endpunkte |
aza_license_logic.py |
compute_license_decision() – Lizenzgueltigkeit berechnen |
aza_device_enforcement.py |
Device-Bindings verwalten |
aza_security.py |
require_api_token, require_admin_token |
Desktop (lokal)
| Datei | Rolle |
|---|---|
basis14.py |
Haupt-Desktop-App (8900+ Zeilen), UI, Lizenzcheck, Aktivierung |
aza_version.py |
APP_VERSION, APP_CHANNEL – zentrale Versionsquelle |
aza_style.py |
UI-Styling-Konstanten |
desktop_update_check.py |
Update-Checker beim App-Start |
aza_desktop.spec |
PyInstaller-Spezifikation |
Build / Release (lokal)
| Datei | Rolle |
|---|---|
build_exe.ps1 |
Baut EXE mit PyInstaller |
build_installer.ps1 |
Baut Installer mit Inno Setup |
build_release_manifest.ps1 |
Erzeugt release/version.json |
release.ps1 |
Lokaler Release-Prozess (Build + Verify) |
publish_update.ps1 |
Upload nach Hetzner |
ship_release.ps1 |
Verbindlicher Ein-Knopf-Release (Build + Upload) |
Abschluss
Wenn der naechste Chat startet:
- Zuerst diese Datei lesen
- Nicht wieder bei alten SMTP-/Deploy-/Pfadfehlern beginnen
- Hostpoint-SMTP ist nicht der produktive Weg – Resend funktioniert
- Lizenzschluessel-Flow ist produktiv – nicht neu bauen
- Admin-Endpunkte sind produktiv – nicht neu bauen
- Direkt beim naechsten sinnvollen Block weitermachen (siehe Abschnitt 10)