# AZA - Master Handover / Operational Runbook ## Working Mode Rules - User does not tinker or manually edit files. - Always provide 1:1 Composer patches (usually Opus). - One step at a time. ## CURRENT PROJECT PHASE (2026-03-30) **Phase:** Stripe/License Live Path PROVEN + Admin Control Panel v2 LIVE – Next Block: WooCommerce/Production Sales Path **STATUS: TECHNICAL FOUNDATION FULLY ESTABLISHED (2026-03-30)** **1. Stripe/License Live Path PROVEN:** - Complete license lifecycle technically proven: Purchase → License active → Cancel/Refund → License canceled → Desktop test mode - Real live test purchase executed and cleanly neutralized - Desktop correctly respects canceled status and falls back to test mode - B1-W1 through B1-W5 all successfully completed - Three bugs patched in `stripe_routes.py` (COALESCE fix, cancel_at_period_end, sync_subscription) **2. Admin Monitor v1 + Control Panel v2 LIVE:** - 8 internal admin endpoints, protected 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 - Verified: without token → 401, wrong token → 401, correct token → data **3. Backup/Storage Monitor ACTIVE:** - Daily backup script configured (/root/aza-backups/backup_aza.sh, cron) - /host_backups read-only mounted in container - backup_status correctly detects backups - ~137 GB free, ~4-5% used – no acute storage pressure **4. Solved Root Causes / Lessons Learned (2026-03-27 – 2026-03-30):** - Sandbox and live must be strictly separated - missing_lookup_key resolved with _lookup_key_from_price fallback - Live context in container verified with sk_live_ - license_debug initially wrong due to old active sandbox row + new canceled live row without customer_email - Operative hotfix: DB backup created, canceled row linked with customer_email, old incorrect active record removed **Hetzner Backend is LIVE (2026-03-26)** - Production API path: `https://api.aza-medwork.ch` - DNS: `api.aza-medwork.ch` → `178.104.51.177` - Repo on Hetzner: `/root/aza-app` - Deploy directory: `/root/aza-app/deploy` - Running services: `aza-api` + `aza-caddy` - Variant B technically proven end-to-end **ARCHITECTURE DECISION VARIANT B (mandatory, 2026-03-25):** - NO OpenAI key in the desktop app - NO per-customer OpenAI key requirement - NO shared OpenAI key client-side - Instead: AZA Office talks ONLY to own AZA backend - Only the AZA backend talks to OpenAI - The OpenAI key resides EXCLUSIVELY server-side - NO half-measures, NO shared-key hacks **Successful Proofs (2026-03-26):** - `curl https://api.aza-medwork.ch/health` → successful - `curl -X POST https://api.aza-medwork.ch/v1/chat` with valid `X-API-Token` → success:true, content:OK - Proven: Hetzner backend runs, Caddy/HTTPS runs, server-side OpenAI access works, Variant B works end-to-end **Root Causes Solved During Deploy:** 1. Wrong git remote (`naswinterthur`) was unsuitable 2. Uploading only `deploy/` was wrong – `docker-compose.yml` expects repo root context (`context: ..`, `dockerfile: deploy/Dockerfile`) 3. Host `nginx` blocked port 80 4. Caddy DNS/ACME issues due to resolver `127.0.0.53` → Fix: explicit DNS `1.1.1.1` + `8.8.8.8` in caddy service **Final Hetzner State:** - Services: `aza-api` + `aza-caddy` - Compose runs from `/root/aza-app/deploy` - `.env` is production-relevant there - `AZA_DOMAIN=api.aza-medwork.ch` - `ACME_EMAIL=info@aza-medwork.ch` - `MEDWORK_API_TOKENS` is set productively - `OPENAI_API_KEY` is set server-side ## B1 BACKEND SPRINT (4 Weeks) | Week | Approx. Dates | Focus | |------|--------------|-------| | **1** | Mar 25 – Apr 01 | Backend Chat Proxy Endpoint (POST /v1/chat) + Auth + Rate Limiting | | **2** | Apr 02 – Apr 08 | Desktop app: all OpenAI calls via backend instead of direct | | **3** | Apr 09 – Apr 15 | Hetzner Deploy: Docker/Caddy/HTTPS + Production Env + Smoke Tests | | **4** | Apr 16 – Apr 22 | E2E Test Desktop→Backend→OpenAI + Customer journey without OpenAI key + Go-Live | ## CURRENT PRIORITY ORDER (B1 Backend Sprint) 1. **Backend Chat Proxy POST /v1/chat** (Week 1) – Foundation of architecture 2. **Desktop app migration to backend** (Week 2) – Migrate all OpenAI calls 3. **Hetzner Deploy** (Week 3) – Set up production server 4. **E2E Test + Go-Live backend path** (Week 4) – Customer journey without OpenAI key 5. WooCommerce/Stripe purchase path runs IN PARALLEL (Hostpoint) **EXPLICITLY DEFERRED / NOT NOW:** - Update comfort / separate auto-updater - Browser-AZA web app (after backend architecture) - Large refactors not serving Variant B **HOSTPOINT vs. HETZNER:** - Hostpoint remains for website/marketing/WooCommerce/Stripe - Hetzner is NOW the backend path for OpenAI proxy/API - Both run in parallel, not against each other ## DONE: B1-W1 Backend Chat Proxy Endpoint (2026-03-26) **POST /v1/chat – IMPLEMENTED AND VERIFIED.** | Aspect | Detail | |---|---| | Auth | `require_api_token` (X-API-Token header, existing pattern) | | 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 | | Model 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 chars/message | | OpenAI Call | `_get_openai().chat.completions.create(**params)` server-side | | Response Schema | `{success, content, finish_reason, model, usage, request_id, duration_ms, error}` | | Secret Scrubbing | `sk-`, `sk-proj-`, `org-` in error texts are replaced | | Tests | 7/7 green (auth, model, validation, OpenAI proxy, /license/status, schema) | **File:** `backend_main.py` (~100 lines added) ## DONE: B1-W2 Desktop Chat Migration (2026-03-26) **Desktop app: Chat completions now routed through backend POST /v1/chat.** **Migrated:** 1. `call_chat_completion()` in basis14.py – central wrapper -> `_backend_chat_completion()` 2. News search – direct `self.client` call -> `_backend_chat_completion()` 3. Comments – own `OpenAI()` client -> `_backend_chat_completion()` 4. Med detail short info – own `OpenAI()` client -> `_backend_chat_completion()` 5. Letter style analysis in `aza_text_windows_mixin.py` -> `_backend_chat_completion()` **New architecture in basis14.py:** - `_BackendChatResponse` – wrapper class, OpenAI-interface compatible (.choices[0].message.content, .usage) - `_backend_chat_completion(**kwargs)` – POST /v1/chat using existing token mechanism (get_backend_url/get_backend_token) - `call_chat_completion(**kwargs)` – consent/capacity check, then `_backend_chat_completion()` - Timeout: 5s connect, 120s read - Errors: RuntimeError with readable message, no secrets **Remaining for later blocks:** translate.py, congress_window.py, aza_email.py (standalone modules) **7/7 tests green:** Health, Auth, Model validation, E2E Desktop->Backend->OpenAI, Response schema, /license/status OK. ## DONE: B1-W3 Hetzner Deploy (2026-03-26) **Hetzner backend is LIVE.** | Aspect | Detail | |---|---| | Domain | `https://api.aza-medwork.ch` | | DNS | `api.aza-medwork.ch` → `178.104.51.177` (A record) | | Repo on Hetzner | `/root/aza-app` | | Deploy directory | `/root/aza-app/deploy` | | Running services | `aza-api` + `aza-caddy` | | Compose | runs from `/root/aza-app/deploy` | | `.env` production | `AZA_DOMAIN=api.aza-medwork.ch`, `ACME_EMAIL=info@aza-medwork.ch`, `MEDWORK_API_TOKENS` set, `OPENAI_API_KEY` set server-side | ## DONE: B1-W4 Server E2E Test (2026-03-26) **Server-side Variant B proven end-to-end:** - `curl https://api.aza-medwork.ch/health` → successful - `curl -X POST /v1/chat` with valid `X-API-Token` → success:true, content:OK ## DONE: B1 Desktop Finalization (Code Patches, 2026-03-27) **All code patches for Variant B in the desktop app are verified and correct:** | Patch | Status | Detail | |---|---|---| | `ensure_ready()` | CORRECT | Remote backend counts as ready (no local OpenAI key needed) | | OpenAI key setup dialog | CORRECT | Dialog suppressed when remote backend configured | | `backend_url.txt` | CORRECT | Points to `https://api.aza-medwork.ch` | | `backend_token.txt` | CORRECT | Primary local token source, prioritized by app | | `start_all.bat` guard | CORRECT | Variant B protection: does not overwrite URL for live backend | | `start_backend_autoport.bat` guard | CORRECT | Variant B protection: does not overwrite URL for live backend | | Chat/text path | CORRECT | Routes through `POST {backend_url}/v1/chat` | **Token priority (confirmed):** `backend_token.txt` > Env `MEDWORK_API_TOKENS` > Env `MEDWORK_API_TOKEN` **Backend URL priority (confirmed):** Env `MEDWORK_BACKEND_URL` > `backend_url.txt` **Unchanged side paths (do NOT block main test):** - `translate.py`, `aza_email.py`, `apps/diktat/diktat_app.py` still have local OpenAI clients → side paths only - `kongress2_window.py` has hardcoded URL → congress feature is parked ## DONE: B1-W5 Local Desktop Live Test (2026-03-27) **Desktop → Hetzner → OpenAI successfully tested in the real app.** - `backend_url.txt` points to `https://api.aza-medwork.ch` - `backend_token.txt` locally present, accepted by live backend - `basis14.py` started locally and successfully tested against live backend - No local OpenAI key needed - No OpenAI key dialog appears - Chat/text path routes through Hetzner backend **Desktop-specific notes (for future chats):** - `ensure_ready()` is correctly patched for remote backend - OpenAI key dialog suppressed when remote backend configured - Do NOT use local starters for live test (`start_all.bat`, `RUN_AZA_ONECLICK.bat`, `START_AZA.bat`, `start_backend_autoport.bat`) – they set env to localhost - Preferred start method: `python basis14.py` directly ## DONE: Desktop License Path Against Live Backend (2026-03-30) Desktop app correctly interprets backend license status: - `canceled` / `inactive` → test mode / DEMO - `active` → full mode - Relevant code: `check_license_status()` in `basis14.py`, `compute_license_decision()` in `aza_license_logic.py` - Activation key fallback only applies when no remote backend configured ## DONE: Admin Monitor v1 + Control Panel v2 (2026-03-30) **File:** `admin_routes.py` (mounted in `backend_main.py` with `prefix="/admin"`) **Security:** X-Admin-Token / AZA_ADMIN_TOKEN (require_admin_token from aza_security.py) **v1 endpoints:** system_status, licenses_overview, backup_status, billing_overview **v2 endpoints:** license_customer_map, revenue_overview, alerts, dashboard_summary **Key files on Hetzner:** - `/root/aza-app/admin_routes.py` - `/root/aza-app/stripe_routes.py` - `/root/aza-app/backend_main.py` - `/root/aza-app/deploy/docker-compose.yml` - `/root/aza-app/deploy/.env` - `/root/aza-backups/backup_aza.sh` + `/root/aza-backups/daily/` (cron) ## CURRENT MAIN BLOCK: WooCommerce / Production Sales Path **Goal:** Make AZA Office production-ready for sale via aza-medwork.ch (Hostpoint WordPress + WooCommerce + Stripe). **Option 1 (preferred): WooCommerce / Shop Admin** 1. Create products in WooCommerce 2. Checkout / My Account / Download / Email 3. Billing/Legal/Invoices (CHF, VAT, Terms) 4. End-to-end test purchase 5. Verify bank payouts **Option 2 (technical): License/Customer Logic** 1. Clean customer/license lifecycle 2. Later team/practice logic 3. Better local persistence / status consistency **Stripe/Webhook/Admin Monitor foundation is ESTABLISHED. Focus moves forward.** ## CURRENT SUBSCRIPTION PRICES (2026-03-27) | Plan | Monthly | Yearly | |---|---|---| | **1 User (Basic)** | CHF 59 | CHF 590 | | **2 Users (Team)** | CHF 89 | CHF 890 | **Stripe Lookup Keys and Price IDs:** | Lookup Key | Price ID | Amount | |---|---|---| | `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 | **OPEN REQUIRED DOCUMENTATION – Stripe Account:** - Active Stripe account (login / email): NOT YET DOCUMENTED - Test mode or live mode currently active: NOT YET DOCUMENTED - Bank account for payouts configured: NOT YET DOCUMENTED - Webhook active and URL: NOT YET DOCUMENTED - Leading success/cancel URLs: NOT YET DOCUMENTED These items must be documented before the first real customer purchase. ## DONE: Stripe Webhook + Live Test COMPLETE (2026-03-30) **Status:** Webhook functional. Sandbox AND live purchase processed. Live test purchase successfully neutralized (canceled + refunded). `license_debug` shows `status=canceled`. **Solved problems (chronological):** 1. **StripeObject vs dict:** `.get(...)` on raw Stripe objects → Fix: `event = json.loads(body)` 2. **`.to_dict_recursive()` does not exist** → Never use it 3. **Double prefix 404:** → Fix: `@router.post("/webhook")` only 4. **Email lookup:** `customer_email` null → Cascade: `customer_email` → `customer_details.email` → `Customer.retrieve(id)` 5. **Container env trap:** `restart` not enough → `up -d --build --force-recreate` 6. **Decimal serialization:** `str(StripeObject)` fails with Decimal → Fix: `_stripe_to_dict()` + `_decimal_default()` 7. **Idempotency bug:** `_mark_processed()` ran after error → Fix: only after success inside try block 8. **Silent exits:** Missing data → 200 OK without log → Fix: comprehensive logging 9. **Sandbox API key mix:** Sandbox webhook + live secret key → Fix: BOTH sk_test_ + whsec_ for sandbox 10. **missing_lookup_key:** Sandbox omits `price.lookup_key` → Fix: `_lookup_key_from_price()` fallback 11. **customer_email loss on updates (Bug A, 2026-03-30):** `_upsert_license` overwrote `customer_email` with NULL → Fix: COALESCE in SQL 12. **cancel_at_period_end ignored (Bug B, 2026-03-30):** Webhook wrote `status=active` despite cancellation intent → Fix: explicit check 13. **sync_subscription too restrictive (Bug C, 2026-03-30):** Only searched `WHERE status='active'` → Fix: search most recent regardless of status **NEVER AGAIN – Stripe Webhook Rules:** - Never use `.to_dict_recursive()` - Never use `.get(...)` on raw StripeObjects - After signature verification: `event = json.loads(body)` - Use `_stripe_to_dict()` for Subscription/Customer objects (not `json.loads(str(...))`) - Prefix routing: with `prefix="/stripe"`, decorator must be `@router.post("/webhook")` - For `.env` changes: `docker compose up -d --build --force-recreate aza-api` - Sandbox and live strictly separated: BOTH `sk_test_` + `whsec_` for sandbox - After sandbox tests: restore live keys in `deploy/.env` - `license_debug` is suitable for operational quick check - After license anomalies: always check DB assignment first (licenses table, customer_email, subscription_id, status) **Operational reference Hetzner:** - Current file: `/root/aza-app/stripe_routes.py` - Working backup: `/root/aza-app/stripe_routes.py.working_lookup_fallback_ok` - SQLite DB: `/root/aza-app/data/stripe_webhook.sqlite` - DB backup (after sandbox): `/root/aza-app/data/stripe_webhook.sqlite.backup_after_sandbox_success` - DB backup (before email fix): `/app/data/stripe_webhook.sqlite.before_email_fix_1774895539` - 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 currently set in `/root/aza-app/deploy/.env` ## EXPLICITLY DEFERRED (Polish Phase) - Autotext fix - Window sizes adjustment - Button sizes / layout for online presentation - General UI polish - Clean up direct OpenAI side paths in secondary modules (translate.py, aza_email.py, diktat_app.py) **Blocker Rule:** One clear block at a time. ## CUSTOMER JOURNEY ANALYSIS (2026-03-25) | Step | Status | Detail | |---|---|---| | Purchase (WooCommerce) | NEXT MAIN BLOCK | WooCommerce product setup, checkout, download, email, billing/legal | | Download | PARTIAL | Mechanism exists, WooCommerce upload missing | | Installer | FUNCTIONALLY COMPLETE | No code signing (SmartScreen warning) | | Activation | STRIPE LIVE PATH PROVEN (2026-03-30) | Complete lifecycle: purchase → active → cancel/refund → canceled → test mode | | First Start | VARIANT B LIVE (2026-03-27) | Desktop → Hetzner → OpenAI works. Desktop respects canceled status correctly. | | Admin/Ops | CONTROL PANEL V2 LIVE (2026-03-30) | 8 endpoints, backup/storage/revenue/alerts/dashboard. X-Admin-Token protected. | ## FOCUS BLOCKS | Priority | Block | Description | |---|---|---| | DONE | B1-W1: Backend /v1/chat | Chat Proxy Endpoint – foundation of Variant B | | DONE | B1-W2: Desktop migration | All OpenAI calls in basis14.py + mixin via backend | | DONE | B1-W3: Hetzner Deploy | Backend LIVE on api.aza-medwork.ch | | DONE | B1-W4: Server E2E | /health + /v1/chat successful, Variant B server-side proven | | DONE | B1-W5: Desktop Live Test | basis14.py locally tested against live backend (2026-03-27) | | DONE | Stripe Live Webhook | Webhook 200 OK, license entry in DB, StripeObject/routing/env traps solved (2026-03-27) | | DONE | STRIPE-W2-LIVE: Live Test Purchase | Real live purchase + cancel + refund, license_debug=canceled, 3 bugs patched (2026-03-30) | | DONE | Desktop License Path | canceled → test mode, active → full mode correctly (2026-03-30) | | DONE | Admin Monitor v1 | system_status, licenses_overview, backup_status, billing_overview (2026-03-30) | | DONE | Control Panel v2 | license_customer_map, revenue_overview, alerts, dashboard_summary (2026-03-30) | | DONE | Backup/Storage Monitor | Daily backup, /host_backups mounted, ~137 GB free (2026-03-30) | | **CURRENT** | WooCommerce / Production Sales Path | Products, checkout, download, email, billing/legal | | NEXT | License/Customer Logic | Clean lifecycle, team/practice logic | | DEFERRED | UI Polish | Autotext fix, window sizes, buttons, layout | | DEFERRED | FB-C: Signing | Signing readiness prepared | | DEFERRED | FB-D: Update Comfort | Only after stable customer journey | ## PRODUCT NAME – CURRENT DIRECTION **Current favorite:** AZA Office **Preferred long form:** - **AZA Office – Ihr medizinischer KI-Arbeitsplatz fuer die Praxis** **Second good variant:** - AZA Office – Die KI-Assistenz fuer medizinische Dokumentation **Status:** Current preferred naming direction. Not yet legally/brand-strategically finalized. Use for WooCommerce/website/download/Go-Live/product presentation. **Earlier shortlist (AZA Desktop):** Documented in project_roadmap.json and project_plan.json. Superseded by AZA Office. ## WORKING PRINCIPLES FOR NEXT CHATS - Root-cause-first instead of blind patching - One clear block at a time - No 10 construction sites simultaneously - Weight real installed builds higher than code assertions - Don't declare "done" too early - Distinguish Desktop into: 1. Dev code 2. Newly built installer 3. Real behavior in installed build **COMMUNICATION NOTE (2026-03-30):** Do NOT reopen / consider ESTABLISHED: - Hetzner deploy – live and working - DNS/Caddy/nginx/TLS – completed - Variant A/B debate – Variant B is mandatory and productive - Stripe webhook stabilization – all root causes solved - Stripe live test – completed and neutralized (purchase + cancel + refund) - Desktop license path – validated, canceled/active correct - Admin Monitor v1 + Control Panel v2 – LIVE and functional - Backup/Storage Monitor – ACTIVE - Stripe/Webhook/License/Admin foundation is TECHNICALLY PROVEN – do not restart from basics Current focus: 1. WooCommerce / Production sales path (products, checkout, download, email, billing/legal) 2. End-to-end test purchase validation 3. Then: License/customer logic professionalization or UI polish Continuity that MUST NOT be lost: - User does not tinker – only exact commands or complete Composer prompts - Root-cause-first, no monster patches - Hostpoint remains main website, Hetzner is backend/API - Desktop talks to backend, OpenAI key stays server-side - Backend license status is authoritative (not activation key) - Admin Control Panel is foundation for operator view - Backup/Storage monitor is active ## Current Local Workspace **CURRENT PATH (from 2026-03-27):** ``` C:\Users\surov\Documents\AZA_GIT\aza\AzA march 2026 ``` **OLD PATH (HISTORICAL, do not use):** ``` C:\Users\surov\Documents\AZA\backup 24.2.26 ``` ## Key Commands **Preferred start method for live test against Hetzner backend:** ``` cd "C:\Users\surov\Documents\AZA_GIT\aza\AzA march 2026" python basis14.py ``` **DO NOT use for live test (set env to localhost):** - `start_all.bat`, `RUN_AZA_ONECLICK.bat`, `START_AZA.bat`, `start_backend_autoport.bat` **Local dev start (only for local development with own backend):** ``` cd "C:\Users\surov\Documents\AZA_GIT\aza\AzA march 2026" powershell -ExecutionPolicy Bypass -File .\deploy\local_reset_and_start.ps1 ``` **Tests:** ``` cd "C:\Users\surov\Documents\AZA_GIT\aza\AzA march 2026" powershell -ExecutionPolicy Bypass -File .\deploy\authorized_status.ps1 powershell -ExecutionPolicy Bypass -File .\deploy\smoke_suite.ps1 powershell -ExecutionPolicy Bypass -File .\deploy\docker_smoke.ps1 ``` ## Desktop UX Block (2026-03-18) - Benutzerdaten bei Deinstallation erhalten (Inno Setup, Standard: Nein) - Signatur-UI: Haekchen "Profilname verwenden" + abweichender Signaturname in Einstellungen - Rechtsklick-Haekchen im Minifenster (synchronisiert) - Kommentare-Fenster (TEILWEISE: Grundstruktur, Detailmodus + Live-Update offen) - Briefstil-Lernen (DOCX-Upload, Stilprofil-Analyse, Profilauswahl, Integration) - Briefstil-Profile Fix: KISIM/Klinisch als feste Systemprofile, vereinheitlichtes Stilprofil-UI im Brief-Bereich - Autotext Root-Cause-Fix (_is_admin NameError, Listener-Revert) - Persistenz-Patch: Erststart-Consent, Profil+Code, Kommentare-Toggle, Einstellungs-Gruppierung - Uebersetzer-Stabilitaetsfix: Toplevel-Embedded statt Tkinter-in-Thread - Briefprofile: KISIM Bericht + Klinischer Bericht als vordefinierte Profile ## AZA Clean Uninstall / Reset Tool **Per Doppelklick:** `AZA_Deinstallieren.bat` **Per PowerShell:** ``` powershell -ExecutionPolicy Bypass -File .\tools\aza_clean_uninstall.ps1 ``` - Modus 1: Nur App entfernen, Benutzerdaten behalten - Modus 2: Vollstaendig zuruecksetzen (App + Benutzerdaten) - Kein Neustart noetig (Standardfall) - Danach direkt Neuinstallation moeglich ## Do-Not-Break Rules 1. Do not change existing API response formats (especially /license/status). 2. Do not modify auth/security mechanisms. 3. Do not log or print secrets/tokens/keys. 4. Signature fallback: profile name used when no explicit signature set. 5. User data in %APPDATA%\AZA Desktop NOT deleted on uninstall by default. 6. Style learning from old letters: only style/structure, NEVER copy patient data or old content. ## Correction Patch (FIX-01) – 2026-03-19 1. Translator label: "Fachuebersetzer" renamed to "Uebersetzer" everywhere 2. Comments window: auto-open checkbox (persistent), live-update on KG change, clickable diagnosis headings with detail popups 3. Correction window: scrollbar for saved corrections list 4. Style profile live application: brief regenerated immediately on profile change/toggle 5. "Profil anwenden" button in style profile management dialog 6. KG creation writes directly to main window (no popup) 7. Persistence: dokumente_collapsed now properly saved/loaded 8. Main window centering: robust delayed centering after widget build via self.after() ## FIX-02 Nachschaerfungs-Patch (2026-03-19) 1. Style profile dialog: now management-only (status display, learn, delete). Active selection exclusively in brief window. 2. Comments window: auto-opens after KG creation when checkbox is active (not just refreshes existing window). 3. Logo separation: Wassertropfen (logo.ico) for EXE/desktop/installer/title bar icon. Original logo (logo.png) for internal branding (bottom-left). Files: basis14.py, aza_text_windows_mixin.py, aza_desktop.spec, logo.png, logo.ico ## FIX-09/10/11 Quellenstrenge Kommentarlogik – Inhaltsquelle / Originallink Trennung (2026-03-22) Root Cause (FIX-09): LLM generated medication info purely from model knowledge. Root Cause (FIX-10): PharmaWiki regex wrong (used h2/h3 instead of span#subtitle). Compendium.ch is SPA (not scrapable). Root Cause (FIX-11): Content source and external link were mixed in one dropdown/dict. Fix (FIX-11): Clean separation of content source and external link: **CONTENT SOURCE** (what is shown in detail window): - `_fetch_doccheck_info(med_name)`: DocCheck Flexikon (default) – server-rendered, h2/h3 headings - `_fetch_pharmawiki_info(med_name)`: PharmaWiki (fallback) – span#subtitle headings - User-selectable via "Inhaltsquelle:" dropdown, persistent in `med_content_quelle` - New dict `_MED_CONTENT_QUELLEN` (DocCheck, PharmaWiki) - Curated `_MEDICATION_FACTS` as offline fallback **EXTERNAL LINK** ("Originalquelle oeffnen" button): - CH = Compendium, AT = BASG, DE = BfArM – UNCHANGED - Still via `_MED_QUELLEN` / `medikament_quelle` – NOT modified Therapies/procedures: separate handling via DocCheck/PharmaWiki (unchanged). Candidate logic (Dermowarte→Dermovate etc.): untouched. Files: basis14.py ## ARCH-MED: Medication Source Architecture (2026-03-22) Architecture (implemented): 1. Detect medication in KG text (existing tagging + validation) 2. Fetch content from DocCheck Flexikon (default) or PharmaWiki (user choice/fallback) 3. Inject source text into LLM prompt (strict: only use provided data) 4. Curated facts list as offline fallback 5. External link always country-based (CH/AT/DE) 6. Omit anything not from the source Coverage: All medications available on DocCheck Flexikon + PharmaWiki. Next steps: 1. Caching strategy (cache fetched content locally) 2. Robustness against HTML structure changes 3. Long-term: Compendium API / HCI Solutions data license evaluation Later market profiles (DE: BfArM, AT: BASG) separately. ## Zukunftsblock – Internationalisierung / Laender- und Quellenprofile (GEPARKT) **Status:** Zukunftsthema – NICHT fuer jetzt. Erst nach DACH-Stabilitaet und Produkterfolg. **Voraussetzung:** DACH (CH/DE/AT) stabil, Go-Live gesichert, Produkt erfolgreich. **Zielbild:** - UI/Sprache, Medikamenten-/Diagnose-/Therapiequellen pro Markt anpassbar - Profil-Felder: app_language, market_region, med_source_profile, dx_source_profile, therapy_source_profile - Manueller Override durch Benutzer/Praxis - Nicht hart nach Herkunftsland schalten – saubere Profil-Logik - Handelsnamen/Zulassungen/Fachinfos sind laenderspezifisch → Quellenprofile pro Markt **Kein aktueller Implementierungsblock.** Erst nach Go-Live und DACH-Erfolg relevant. ## Windows Code-Signing / Smart App Control Readiness (2026-03-23) **Problem:** Windows Smart App Control blockiert unsignierte Apps bei Kunden. **Status:** Signing-Readiness vorbereitet, noch NICHT produktiv aktiviert. **Vorbereitet:** - `sign_release.ps1` – signiert EXE + DLLs/PYDs + Installer (DryRun-Modus verfuegbar) - `build_and_test_release.ps1` – Signing-Schritt integriert (optional, graceful skip) - `build_release_artifacts.ps1` – Artefakt-Report mit Signatur-Status - `SIGNING_READINESS.md` – Vollstaendige Dokumentation **Signing-Reihenfolge:** DLLs/PYDs → EXE → Installer-Build → Installer signieren → Artefakt-Report **Vor Kundenauslieferung noch offen:** 1. EV Code-Signing-Zertifikat beschaffen 2. signtool.exe installieren (Windows SDK) 3. Publisher-Name abstimmen (Zertifikat ↔ AppPublisher ↔ Handelsregister) 4. Produktiver Signierlauf + Test auf Windows-PC mit Smart App Control **Publisher-/Namenskonsistenz (Analyse 2026-03-23):** 3 Namensformen im Projekt – beabsichtigt, keine Inkonsistenz: - **AZA MedWork** = Firma/Publisher → SIGNING-KRITISCH (Installer, Legal, Consent, E-Mail-Absender) - **AZA Desktop** = Produktname → konsistent, kein Handlungsbedarf - **AZA Medical AI Assistant** = interner Projektname → nicht signing-relevant Vor Zertifikatskauf: HR-Name pruefen, AppPublisher auf Zertifikats-Subject abstimmen. Falls HR-Name abweicht: alle signing-relevanten Stellen gemeinsam anpassen (Liste in handover.md). Nach Festlegung: Publisher-Name NICHT mehr wechseln (SmartScreen-Reputation).