Bedienseite für das Credits-Monatskontingent des Monitors. Das Portal
setzt jetzt alle Stellwerte, der Monitor bleibt Herr der Laufzeitfelder.
- Lizenz-Modal und Budget-Formular um Abrechnungszeitraum (monthly/total),
Übertrag-Checkbox und Warnschwelle erweitert, Vorbelegungen auf das
beschlossene Modell (10.000 Credits, monatlich, Übertrag an, 0,20 USD).
- Neue Organisation kann direkt eine Lizenz mit Kontingent anlegen
(OrgCreate.license, verschachtelt). Org- und Lizenz-Insert laufen in
EINER Transaktion, schlägt der Lizenz-Teil fehl, entsteht keine
halbe Organisation. Gemeinsamer Helper insert_license_row statt
Duplikation der Widerruf- und Audit-Logik.
- PUT /api/token-usage/budget validiert credits_period (monthly|total)
und budget_warning_percent (1 bis 100), credits_rollover wird wie
unlimited_budget normalisiert. Laufzeitfelder bleiben bewusst
außerhalb der Whitelist.
- Overview und Org-Detail rechnen den Rest jetzt gegen verfügbar =
Kontingent + Übertrag, dieselbe Bezugsgröße wie der Hard-Stop im
Monitor. Neuer read-only Block Laufzeitwerte im Token-Subtab.
- Startup-Check loggt einen deutlichen Fehler, wenn die licenses-Tabelle
die Credits-Spalten noch nicht hat (falsche Deploy-Reihenfolge).
- Migration migrations/2026-07-25_credits_period.py (idempotent,
wortgleich mit der Monitor-Migration) für die Portal-Staging-DB,
auf Live gilt: Monitor VOR Portal promoten.
- 13 neue Modell-Tests, pytest grün (die zwei bekannten
shared-Import-Fehlschläge bestehen unverändert seit vorher).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- migrations/2026-05-09d_source_health_history.py NEU: source_health_history-Tabelle
(Append-only Verlauf der Health-Check-Runs mit run_id und archived_at)
- shared/services/source_health.py:
- tenant_id IS NULL Filter raus -> auch Tenant-Quellen werden gecheckt
- Mojibake (Triple-Encoded UTF-8) via ftfy gefixt
- DELETE FROM source_health_checks: vorher Stand mit run_id (uuid4) in
source_health_history archivieren -> kein Datenverlust mehr
- User-Agent + Timeout aus config.HEALTH_CHECK_* statt hardcoded
- routers/sources.py /health/run-stream: gleiche Änderungen wie oben
- config.py: HEALTH_CHECK_USER_AGENT + HEALTH_CHECK_TIMEOUT_S ergänzt
Idempotente Migration mit --db Parameter, Backup vor Lauf, Sample-Output.
Behandelt headline_de + content_de bei allen Artikeln; bei language=de
zusaetzlich headline + content_original. Nutzt das gleiche hunspell-Dict
wie der Live-QC.
Idempotente Migration mit --db Parameter (Live + Staging benutzbar),
Backup vor Lauf, Verifikations-Check nach Lauf. Selektiert alle Artikel
mit HTML-Tag-Pattern, strippt via html_to_text-Helper aus dem Monitor-Repo,
respektiert 1000-Zeichen-Cap.
- Schema-Migration: ON DELETE SET NULL fuer incidents.created_by, magic_links.user_id,
network_analyses.created_by (behebt 500er beim User-Loeschen). Neue Spalte
licenses.unlimited_budget. Neue Tabellen portal_audit_log, portal_login_attempts.
- Audit-Log: alle CREATE/UPDATE/DELETE auf Org/User/Lizenz/Quelle + Login-Events
werden mit before/after-Diff in portal_audit_log geschrieben.
- Brute-Force-Schutz: 5 Fehlversuche pro IP+Username/15min -> 429 mit Retry-After.
- Token-Budget: expliziter Schalter unlimited_budget pro Lizenz. UI zeigt ehrlich
>100%-Verbrauch (kein Math.min mehr) und ungebremste Anzeige bei unlimited.
- Neuer Audit-Log Tab mit Filter (Aktion/Ressource/Admin/Zeitraum) und Pagination.