fix: medium audit items — CORS config, invoice description, path helper, node failure, order prefix

M3: cors_origins setting in config.py (env CORS_ORIGINS); main.py reads from settings.
M4: add build_order_line_step_render_dir() to render_paths.py; tasks.py drops placeholder.mp4 trick.
M5: unknown workflow graph nodes now fail the run (status="failed" + logger.error) instead of silently skipping.
M6: invoice line description is now "{product} — {output_type}" instead of bare UUID; eager-loads relations.
M7: order_number_prefix setting in config.py (env ORDER_NUMBER_PREFIX, default "SA").

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-07-22 13:57:04 +02:00
co-authored by Claude Sonnet 4.6
parent 3c2d0816e5
commit 507858cf31
8 changed files with 61 additions and 13 deletions
+12
View File
@@ -534,6 +534,18 @@ Der Admin-Settings-Endpunkt (`GET /api/admin/settings`) erfordert `global_admin`
### 2026-07-22 | Workflow-Editor | _legacy_dispatch umging cancelled/rejected Pre-Check
`_legacy_dispatch` in `dispatch_service.py` rief `render_order_line_task.delay()` direkt auf und umging damit den Pre-Check in `dispatch_order_line_render` (der cancelled/rejected Lines überspringt). Alle Legacy-Dispatch-Pfade (auch im Graph-Fallback) liefen so durch, auch für bereits gecancelte Jobs. **Lösung:** `_legacy_dispatch` ruft jetzt `dispatch_order_line_render.delay()` auf statt `render_order_line_task.delay()` direkt.
### 2026-07-22 | Architecture | CORS-Origins und Order-Prefix nicht konfigurierbar
`main.py` hatte CORS-Origins hardcoded als Python-Liste. `orders/service.py` hatte den Ordernummer-Prefix `SA-` hardcoded. Beide Werte lassen sich jetzt per Umgebungsvariable überschreiben: `CORS_ORIGINS='["https://myapp.com"]'` und `ORDER_NUMBER_PREFIX=HM`. Default-Werte bleiben unverändert, keine Migration nötig.
### 2026-07-22 | Refactoring | placeholder.mp4 als Pfad-Trick in tasks.py
`tasks.py:934` nutzte `build_order_line_step_render_path(..., "placeholder.mp4", ensure_exists=True).parent` um das Render-Verzeichnis zu erzeugen — ein fake Dateiname nur um `.parent` aufzurufen. **Lösung:** neue Funktion `build_order_line_step_render_dir(step_path, order_line_id, *, ensure_exists=False)` in `render_paths.py` hinzugefügt. `tasks.py` nutzt die direkte Funktion ohne Workaround.
### 2026-07-22 | Correctness | Unbekannte Workflow-Nodes wurden lautlos übersprungen
`workflow_graph_runtime.py:511` setzte Status `"skipped"` für Steps ohne Executor — der Workflow-Run galt als erfolgreich obwohl Nodes nicht ausgeführt wurden. **Lösung:** Status zu `"failed"` geändert und `logger.error` ergänzt. Der Run-Status-Check (`if any(...status == "failed")`) markiert den gesamten Run als failed.
### 2026-07-22 | Correctness | Invoice-Beschreibung war nackte UUID
`billing/service.py:259` setzte `description=f"Render: {ol.id}"` — im PDF erschien eine UUID als Rechnungsposition. **Lösung:** `OrderLine` wird jetzt mit `selectinload(product)` und `selectinload(output_type)` geladen; Beschreibung ist `f"{product_name} — {ot_name}"`.
### 2026-07-22 | Security | JWT secret "changeme" ohne Startup-Guard
`jwt_secret_key` in `config.py` hatte den Standardwert `"changeme"`. Deployments, die vergessen `JWT_SECRET_KEY` zu setzen, ließen gültige JWTs fälschen. **Lösung:** `@model_validator(mode="after")` in `Settings` — wirft `ValueError` wenn key `"changeme"` ist UND `_is_running_in_container()` True ist. Lokale Entwicklung außerhalb Docker ist nicht betroffen.