1126 lines
61 KiB
Markdown
1126 lines
61 KiB
Markdown
|
|
# 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-03-30, aktualisiert 2026-03-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.py` gepatcht (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` → erfolgreich
|
|||
|
|
- `curl -X POST https://api.aza-medwork.ch/v1/chat` mit gueltigem `X-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)
|
|||
|
|
|
|||
|
|
1. **Backend Chat Proxy POST /v1/chat** (Woche 1) – Grundstein der Architektur
|
|||
|
|
2. **Desktop-App auf Backend umstellen** (Woche 2) – Alle OpenAI-Calls migrieren
|
|||
|
|
3. **Hetzner Deploy** (Woche 3) – Produktionsserver aufsetzen
|
|||
|
|
4. **E2E-Test + Go-Live Backend-Pfad** (Woche 4) – Kundenweg ohne OpenAI-Key
|
|||
|
|
5. 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:**
|
|||
|
|
1. `call_chat_completion()` in basis14.py – zentraler Wrapper -> `_backend_chat_completion()`
|
|||
|
|
2. News-Suche – direkter `self.client` Call -> `_backend_chat_completion()`
|
|||
|
|
3. Kommentare – eigener `OpenAI()` Client -> `_backend_chat_completion()`
|
|||
|
|
4. Med-Detail Kurzinfo – eigener `OpenAI()` Client -> `_backend_chat_completion()`
|
|||
|
|
5. 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:**
|
|||
|
|
1. Falsches Git-Remote (`naswinterthur`) war nicht geeignet → korrektes Remote verwendet
|
|||
|
|
2. Nur `deploy/` hochladen war falsch → `docker-compose.yml` erwartet Repo-Root-Kontext (`context: ..`, `dockerfile: deploy/Dockerfile`)
|
|||
|
|
3. Host-`nginx` blockierte Port 80 → nginx gestoppt
|
|||
|
|
4. Caddy DNS/ACME-Probleme wegen Resolver `127.0.0.53` → Fix: im `caddy`-Service in `docker-compose.yml` explizit 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` → erfolgreich
|
|||
|
|
- `curl -X POST https://api.aza-medwork.ch/v1/chat` mit gueltigem `X-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):**
|
|||
|
|
1. `backend_token.txt` (hoechste Prioritaet)
|
|||
|
|
2. Env `MEDWORK_API_TOKENS`
|
|||
|
|
3. Env `MEDWORK_API_TOKEN`
|
|||
|
|
|
|||
|
|
**Backend-URL-Prioritaet (bestaetigt):**
|
|||
|
|
1. Env `MEDWORK_BACKEND_URL`
|
|||
|
|
2. `backend_url.txt`
|
|||
|
|
|
|||
|
|
**Nicht geaenderte Restpfade (blockieren Haupttest NICHT):**
|
|||
|
|
- `translate.py`, `aza_email.py`, `apps/diktat/diktat_app.py` haben noch lokale OpenAI-Clients → betreffen Nebenpfade
|
|||
|
|
- `kongress2_window.py` hat hardcoded URL → Kongress ist geparkt
|
|||
|
|
- `self.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.txt` zeigt auf `https://api.aza-medwork.ch`
|
|||
|
|
- `backend_token.txt` lokal vorhanden, vom Live-Backend akzeptiert
|
|||
|
|
- `basis14.py` lokal 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.py` direkt
|
|||
|
|
|
|||
|
|
## ERLEDIGT: Desktop-Lizenzpfad gegen Live-Backend (2026-03-30)
|
|||
|
|
|
|||
|
|
Desktop-App respektiert den Backend-Lizenzstatus korrekt:
|
|||
|
|
- `canceled` / `inactive` → Testmodus / DEMO
|
|||
|
|
- `active` → Vollmodus
|
|||
|
|
- Relevante Stellen: `check_license_status()` in `basis14.py`, `compute_license_decision()` in `aza_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-Info
|
|||
|
|
- `GET /admin/licenses_overview` – Lizenzen nach Status, letzte 20, ?email= Filter
|
|||
|
|
- `GET /admin/backup_status` – Backup-Pfade, Groesse, neustes Backup, Log-Tail
|
|||
|
|
- `GET /admin/billing_overview` – Stripe-Health, Lizenz-Summary, Event-Log
|
|||
|
|
|
|||
|
|
**v2 Endpunkte:**
|
|||
|
|
- `GET /admin/license_customer_map` – Detaillierte Lizenznehmer-Uebersicht, ?email= und ?status= Filter
|
|||
|
|
- `GET /admin/revenue_overview` – MRR-Schaetzung, Stripe-Live-Daten (gross/refunds/net), Event-Summary
|
|||
|
|
- `GET /admin/alerts` – Strukturierte Warnliste (info/warning/critical): Disk, Stripe, DB, Lizenzen, Backups
|
|||
|
|
- `GET /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_ok`
|
|||
|
|
- `stripe_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:**
|
|||
|
|
1. Echter Live-Kauf des Basic-Monatsplans (CHF 59) ueber Stripe Payment Link
|
|||
|
|
2. Stripe Webhook lieferte 200 OK
|
|||
|
|
3. Backend schrieb aktive Lizenz: status=active, lookup_key=aza_basic_monthly
|
|||
|
|
4. /stripe/license_debug zeigt active fuer admin@aza-medwork.ch
|
|||
|
|
5. /admin/license_customer_map zeigt die aktive Lizenz korrekt
|
|||
|
|
6. Desktop startet ohne Testfenster und im Vollmodus
|
|||
|
|
7. 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:
|
|||
|
|
1. Neuen Token generieren (z.B. `python3 -c "import secrets; print(secrets.token_urlsafe(32))"`)
|
|||
|
|
2. In `/root/aza-app/deploy/.env` als `AZA_ADMIN_TOKEN=neuer_token` setzen
|
|||
|
|
3. `cd /root/aza-app/deploy && docker compose up -d --build --force-recreate aza-api`
|
|||
|
|
|
|||
|
|
## RELEASE + UPDATER PRODUKTIV (Stand 2026-04-02)
|
|||
|
|
|
|||
|
|
- `aza_version.py` steht korrekt auf `APP_VERSION = "1.0.0"`, `APP_CHANNEL = "stable"`
|
|||
|
|
- Produktiver Installer und `version.json` wurden 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.0` in `aza_version.py` verursacht; 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)
|
|||
|
|
|
|||
|
|
## VERBINDLICHER RELEASE-PROZESS (Stand 2026-04-02)
|
|||
|
|
|
|||
|
|
**Verbindlicher Operator-Befehl fuer produktiven Build + Upload:**
|
|||
|
|
`.\ship_release.ps1`
|
|||
|
|
|
|||
|
|
**Ablauf intern:**
|
|||
|
|
1. `release.ps1` (baut EXE → Installer → Manifest, verifiziert Artefakte)
|
|||
|
|
2. `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.ps1` verwenden (erzeugt anderes Artefakt)
|
|||
|
|
- NICHT `deploy\aza-deploy\*` verwenden (falsche Pfade)
|
|||
|
|
- NICHT `deploy\publish-release.ps1` verwenden (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):**
|
|||
|
|
|
|||
|
|
1. **Admin-Token-Rotation** (Mini-Block, schnell)
|
|||
|
|
- Offengelegten Token rotieren
|
|||
|
|
- 3 Commands, kein Code
|
|||
|
|
|
|||
|
|
2. **Betreiber-Runbook / Schnellreferenz standardisieren** (Klein)
|
|||
|
|
- Klare Anleitung fuer Lizenz-/Zahlungskontrolle
|
|||
|
|
- Welcher Endpunkt fuer was
|
|||
|
|
- Curl-Beispiele fuer Alltagskontrolle
|
|||
|
|
|
|||
|
|
3. **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
|
|||
|
|
|
|||
|
|
4. **Lizenz-/Kundenlogik professionalisieren** (Gross)
|
|||
|
|
- Sauberer Kunden-/Lizenz-Lifecycle
|
|||
|
|
- Team-/Praxislogik
|
|||
|
|
- Lokale Persistenz / Statuskonsistenz
|
|||
|
|
|
|||
|
|
5. **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 Office` mit 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_KEY` und `STRIPE_WEBHOOK_SECRET` korrekt 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):**
|
|||
|
|
1. ~~Frisches Stripe-Event senden und pruefen ob admin@aza-medwork.ch sauber in DB landet~~ → ERLEDIGT: Sandbox-Kauf erfolgreich verarbeitet
|
|||
|
|
2. ~~test@example.com aus SQLite bereinigen~~ → ERLEDIGT: geloescht
|
|||
|
|
3. Desktop-Lizenzcheck auf `/stripe/license_debug?email={EMAIL}` abstimmen → NAECHSTER HAUPTBLOCK
|
|||
|
|
4. Nach stabilem Abschluss Stripe-Secrets rotieren → OFFEN (spaeter)
|
|||
|
|
5. Stripe-Konto Ownership dokumentieren → OFFEN (Admin-Block)
|
|||
|
|
6. 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.com` geloescht
|
|||
|
|
|
|||
|
|
**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_debug` zeigt korrekt `status=canceled`
|
|||
|
|
- Live-Testkauf ist damit technisch und operativ sauber neutralisiert
|
|||
|
|
|
|||
|
|
**Geloeste Root Causes (chronologisch):**
|
|||
|
|
1. **StripeObject vs. dict:** `.get(...)` auf rohen Stripe-Objekten → Fix: `event = json.loads(body)`
|
|||
|
|
2. **`.to_dict_recursive()` existiert nicht:** Niemals verwenden
|
|||
|
|
3. **Doppel-Prefix 404:** `prefix="/stripe"` in main.py + `/stripe/webhook` in Router → Fix: nur `@router.post("/webhook")`
|
|||
|
|
4. **Email-Lookup:** Kaskade: `customer_email` → `customer_details.email` → `Customer.retrieve(id)`
|
|||
|
|
5. **Container-Env-Falle:** `docker compose restart` reicht nicht → `up -d --build --force-recreate`
|
|||
|
|
6. **Decimal-Serialisierung:** `str(StripeObject)` scheitert bei Decimal-Werten → Fix: `_stripe_to_dict()` + `_decimal_default()`
|
|||
|
|
7. **Idempotenz-Bug:** `_mark_processed()` lief auch nach Fehler → Fix: nur nach Erfolg innerhalb try-Block
|
|||
|
|
8. **Stille Exits:** Fehlende Daten fuehrten zu 200 OK ohne Log → Fix: lueckenloses Logging
|
|||
|
|
9. **Sandbox API-Key-Mix:** Sandbox-Webhook mit Live-Secret-Key → `No such subscription` → Fix: BOTH sk_test_ + whsec_ fuer Sandbox
|
|||
|
|
10. **missing_lookup_key:** Sandbox setzt `price.lookup_key` nicht → Fix: `_lookup_key_from_price()` Fallback
|
|||
|
|
11. **customer_email-Verlust bei Updates (Bug A, 2026-03-30):** `_upsert_license` ueberschrieb `customer_email` mit NULL bei `customer.subscription.updated/deleted` → license_debug fand alten aktiven Datensatz statt neuen canceled → Fix: COALESCE in SQL
|
|||
|
|
12. **cancel_at_period_end ignoriert (Bug B, 2026-03-30):** Webhook schrieb `status=active` obwohl `cancel_at_period_end=true` → Fix: explizite Pruefung im Webhook-Handler
|
|||
|
|
13. **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/.env` setzen
|
|||
|
|
|
|||
|
|
**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/.env` gesetzt
|
|||
|
|
|
|||
|
|
**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/.env` zurueckstellen
|
|||
|
|
- Im Live-Container wurde `sk_live_` erfolgreich verifiziert
|
|||
|
|
- `license_debug` ist 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):
|
|||
|
|
1. ~~KEIN /v1/chat Endpoint~~ → ERLEDIGT (2026-03-26)
|
|||
|
|
2. **Kein kundenbezogenes Usage-Tracking** auf dem Server (spaeter)
|
|||
|
|
3. ~~Backend NICHT auf Hetzner deployed~~ → ERLEDIGT: api.aza-medwork.ch LIVE (2026-03-26)
|
|||
|
|
4. ~~Desktop zeigt noch auf lokales Backend~~ → ERLEDIGT (2026-03-27): Desktop → Hetzner → OpenAI funktioniert in der echten App
|
|||
|
|
5. **Kein Kunden-Quota/Budget-Management** serverseitig (spaeter)
|
|||
|
|
6. **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:
|
|||
|
|
1. Dev-Code
|
|||
|
|
2. Neu gebauter Installer
|
|||
|
|
3. 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.bat`
|
|||
|
|
- `RUN_AZA_ONECLICK.bat`
|
|||
|
|
- `START_AZA.bat`
|
|||
|
|
- `start_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 `/health` HTTP 200 liefert (max 60s)
|
|||
|
|
- Fuehrt `smoke_suite.ps1` gegen den Container aus
|
|||
|
|
- Gibt `[RESULT] PASS` oder `[RESULT] FAIL` aus
|
|||
|
|
- 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 `CurUninstallStepChanged` fragt ob `%APPDATA%\AZA Desktop` geloescht 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_admin` NameError 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:**
|
|||
|
|
1. AZA-Prozesse sauber beenden (erst freundlich, dann forciert)
|
|||
|
|
2. Inno-Setup-Uninstaller silent ausfuehren
|
|||
|
|
3. Installationsreste bereinigen (Verzeichnis, Shortcuts)
|
|||
|
|
4. Firewall-Regel entfernen
|
|||
|
|
5. Benutzerdaten je nach Modus behalten oder loeschen
|
|||
|
|
6. Registry-Reste bereinigen (falls Inno-Uninstaller nicht verfuegbar)
|
|||
|
|
7. 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
|
|||
|
|
|
|||
|
|
1. Keine bestehenden API-Response-Formate aendern (besonders /license/status)
|
|||
|
|
2. Auth/Security nicht modifizieren (Token-Rotation, _check_token)
|
|||
|
|
3. Keine Secrets loggen/printen (Tokens, Keys, Passwoerter)
|
|||
|
|
4. backend_token.txt nie committen (steht in .gitignore)
|
|||
|
|
5. deploy/.env nie committen (enthaelt Produktions-Secrets)
|
|||
|
|
6. Immer try/except um History-Logging (darf Response nie blockieren)
|
|||
|
|
7. Windows PowerShell 5.1 kompatibel bleiben
|
|||
|
|
8. Signatur-/Profilname-Fallback: Wenn kein expliziter Signaturname gesetzt, wird Profilname verwendet
|
|||
|
|
9. Benutzerdaten in %APPDATA%\AZA Desktop bei Deinstallation standardmaessig NICHT loeschen
|
|||
|
|
10. 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:
|
|||
|
|
|
|||
|
|
1. **Uebersetzer-Label**: "Fachuebersetzer" ueberall zu "Uebersetzer" umbenannt (aza_config.py, version.json, CHANGELOG.md, web/index.html, deploy-Docs)
|
|||
|
|
2. **Kommentare-Fenster fertiggestellt**: Haekchen "beim Start automatisch oeffnen" (persistent), Live-Update bei KG-Aenderung (auto-refresh nach KG-Erstellung), klickbare Diagnose-Ueberschriften mit Detailfenster
|
|||
|
|
3. **Korrektur-Fenster**: Scrollbar fuer Liste der gespeicherten Korrekturen (height=8 statt 4), Korrekturen bleiben bei Benutzerdaten-Behalten erhalten
|
|||
|
|
4. **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()
|
|||
|
|
5. **Profil-anwenden-Button**: Im Stilprofil-Verwaltungsdialog neuer gruener Button "Profil anwenden" – wendet das gewaehlte Profil sofort auf den aktuellen Brief an
|
|||
|
|
6. **KG direkt im Hauptfenster**: make_kg_from_text() schreibt jetzt direkt ins txt_output (via _fill_kg_and_finish), kein separates Popup-Fenster mehr
|
|||
|
|
7. **Persistenz**: dokumente_collapsed wird jetzt korrekt geladen/gespeichert in autotext_data
|
|||
|
|
8. **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
|
|||
|
|
|
|||
|
|
1. **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).
|
|||
|
|
2. **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)".
|
|||
|
|
3. **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
|
|||
|
|
|
|||
|
|
1. **Klick auf Medikament/Diagnose im Kommentare-Fenster**: Oeffnet strukturiertes Detailfenster (zentriert) mit KI-generierter Kurzinfo (Indikation, Nebenwirkungen, Anwendung, Schwangerschaft/Stillzeit, Hinweise).
|
|||
|
|
2. **Quellenauswahl**: Dropdown im Detailfenster: compendium.ch (Standard), BASG All-in-One Register, BfArM AMIce. Auswahl persistent in medikament_quelle (autotext_data).
|
|||
|
|
3. **Originalquelle oeffnen**: Button "Originalquelle oeffnen" im Detailfenster oeffnet passende Suchseite zur aktiven Quelle im Browser.
|
|||
|
|
4. **Persistenz**: medikament_quelle in aza_persistence.py (load/save/default).
|
|||
|
|
|
|||
|
|
**Dateien:** basis14.py, aza_persistence.py
|
|||
|
|
|
|||
|
|
## Diagnose-Detailfenster (FIX-04) – 2026-03-20
|
|||
|
|
|
|||
|
|
1. **Getrennte Detail-Logik**: Medikamente ([MED]) und Diagnosen ([DX]) haben eigene Detailfenster mit eigenen Prompts, Quellen und Persistenz-Keys.
|
|||
|
|
2. **Diagnose-Quellen**: DocCheck Flexikon (Standard bei Deutsch), MSD Manual Patienten (Standard bei anderer Sprache). Persistent in diagnose_quelle.
|
|||
|
|
3. **Medikament-Quellen**: compendium.ch / BASG / BfArM (wie bisher). Persistent in medikament_quelle.
|
|||
|
|
4. **KI-Kommentare**: Prompt erzeugt [DX]/[MED]-Tags pro Ueberschrift. _apply_kommentare erkennt Tags und leitet an _show_dx_detail bzw _show_med_detail weiter.
|
|||
|
|
5. **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
|
|||
|
|
|
|||
|
|
1. **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.
|
|||
|
|
2. **Diagnose-Prompt**: Ebenfalls fuer Fachpersonal optimiert, konsistente Abschnittsueberschriften.
|
|||
|
|
3. **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).
|
|||
|
|
4. **Erkennungslogik**: Ueberschriften werden anhand bekannter Headings-Liste erkannt (_DETAIL_SECTION_HEADINGS_MED / _DX), mit Umlaut-Normalisierung.
|
|||
|
|
5. **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()` + wiederholte `after()`-Aufrufe, um den Grip garantiert ueber allen Inhalten anzuzeigen.
|
|||
|
|
Cursor auf `size_nw_se` geaendert.
|
|||
|
|
- **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:
|
|||
|
|
1. GPT-4o-mini erzeugte `[MED] Dermowartecreme` MIT halluziniertem Kurztext
|
|||
|
|
2. `_apply_kommentare()` zeigte diesen Text 1:1 an
|
|||
|
|
3. Validierung existierte NUR im ZWEITEN AI-Call des Detailfensters
|
|||
|
|
4. Ergebnis: Kurzansicht halluzinierte, Detailfenster sagte "KEIN MEDIKAMENT ERKANNT"
|
|||
|
|
- **Loesung (deterministisch, nicht prompt-basiert):**
|
|||
|
|
- Neue Datei `aza_med_validator.py` mit ~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
|
|||
|
|
- **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_quelle` in `_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_FACTS` als Offline-Fallback
|
|||
|
|
- **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:**
|
|||
|
|
1. Medikament im KG-Text erkennen (bestehendes Tagging + Validierung)
|
|||
|
|
2. In Compendium.ch suchen (echte Suche, nicht nur Link) – UMGESETZT
|
|||
|
|
3. Konkreten Produkt-/Praeparattreffer bestimmen – UMGESETZT (Name + Darreichungsform)
|
|||
|
|
4. Relevante Fach-/Produktinfo strukturiert auswerten – UMGESETZT via PharmaWiki, Compendium-Detailseite noch offen
|
|||
|
|
5. Kommentarinfo NUR aus diesen quellenbasierten Daten bauen – UMGESETZT
|
|||
|
|
6. 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):**
|
|||
|
|
1. Compendium-Detailseiten-Extraktion evaluieren (zusaetzlich zu Produkt-Aufloesung)
|
|||
|
|
2. Caching-Strategie festlegen (PharmaWiki-/Compendium-Antworten lokal cachen)
|
|||
|
|
3. Robustheit gegen HTML-Strukturaenderungen absichern
|
|||
|
|
4. 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-Sprache
|
|||
|
|
- `market_region` – Zielmarkt/Land
|
|||
|
|
- `med_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:
|
|||
|
|
1. Aktivierungsschluessel (aza_activation.py): Kontrolliert ob App STARTET (Trial oder AZA-Key)
|
|||
|
|
2. 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_subject
|
|||
|
|
- `SIGNING_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:**
|
|||
|
|
1. EV Code-Signing-Zertifikat beschaffen (empfohlen: DigiCert/Sectigo, ca. CHF 400–600/Jahr; alternativ Azure Trusted Signing)
|
|||
|
|
2. signtool.exe installieren (Windows SDK)
|
|||
|
|
3. Publisher-Name im Zertifikat mit `AppPublisher` in `aza_installer.iss` abstimmen (aktuell: `AZA MedWork`)
|
|||
|
|
4. `sign_release.ps1` produktiv ausfuehren
|
|||
|
|
5. 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:**
|
|||
|
|
1. Offiziellen Firmennamen im Handelsregister pruefen
|
|||
|
|
2. EV-Zertifikats-Subject muss exakt mit HR-Name uebereinstimmen
|
|||
|
|
3. `AppPublisher` in `aza_installer.iss` auf Zertifikats-Subject abstimmen
|
|||
|
|
4. Falls HR-Name von "AZA MedWork" abweicht: alle signing-relevanten Stellen gemeinsam anpassen
|
|||
|
|
5. SmartScreen-Reputation baut auf Publisher-Namen auf – nach Festlegung NICHT mehr aendern
|
|||
|
|
|
|||
|
|
**Stellen die bei Namensaenderung gemeinsam angepasst werden muessen:**
|
|||
|
|
- `installer/aza_installer.iss` → `MyAppPublisher`
|
|||
|
|
- `legal/privacy_policy.md` → Zeile 5 + Zeile 27
|
|||
|
|
- `legal/ai_consent.md` → Zeile 10, 12, 132
|
|||
|
|
- `deploy/WOOCOMMERCE_PRODUCT.md` → Absendername
|
|||
|
|
- `deploy/WORDPRESS_GOLIVE.md` → Absendername
|
|||
|
|
- `SIGNING_READINESS.md` → Beispielname
|
|||
|
|
- `apps/diktat/diktat_app.py` → Docstring
|
|||
|
|
- `aza_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
|