feat(abrechnung): Monatskontingent in Credits mit festen Sätzen, Hard-Stop und Warnschwelle
Portierung aus dem Lokal-Fork (AegisSight-Monitor-Local, Commit d2b9168, per Cherry-Pick übernommen und an den Server-Stand angepasst). - Feste Sätze je Aktion (BILLING_MODE=flat) statt echter Kosten geteilt durch cost_per_credit. Sätze auf die am 23.07.2026 beschlossenen Verkaufswerte gesetzt. Live-Lauf 45, Recherche je Durchlauf 40, Studio-Bausteine 12, Chat/Beschreibung/Globe 1. Per ENV überschreibbar, der alte Modus bleibt als BILLING_MODE=actual erhalten. - Abrechnungsperiode. licenses.credits_period trennt monthly von total, träger Monatsreset bei der nächsten Lizenzprüfung, optionaler Übertrag (credits_rollover, gedeckelt auf ein Monatskontingent). Bestandslizenzen ohne Periodenmarke behalten ihren Verbrauch. - Hard-Stop gegen das verfügbare Monatskontingent (Kontingent plus Übertrag) statt gegen das Lebenszeit-Total. - Warnschwelle budget_warning_percent (Default 80 Prozent) wird erstmals ausgewertet, einmalige Meldung an alle aktiven Nutzer der Organisation. - DB-Migration additiv und idempotent (credits_period, credits_period_start, credits_rollover, credits_carried, budget_warning_sent, unlimited_budget). - /api/auth/me liefert credits_available als Bezugsgröße plus credits_period, das Credits-Widget zeigt "Credits diesen Monat". - Wortlaut überall Credits (nicht Guthaben/Einheiten), docs/ABRECHNUNG.md auf den Online-Stand gebracht. Abweichungen zur Fork-Vorlage. Die Takt-Änderungen (Untergrenze 30 Min, Kostenvorschau im Anlege-Dialog, Fork-Commit 5b0b578) sind bewusst NICHT enthalten, die Sätze stehen auf 45/40 statt der Fork-Defaults 24/33. Getestet gegen eine Kopie der Staging-DB, 20 Prüfungen bestanden. Migration, Flat-Buchung adhoc/research/chat, Warnschwelle einmalig, Hard-Stop, Monatsreset, Übertrag gedeckelt, Bestandslizenz ohne Marke. Die vier Live-Lizenzen stehen auf unlimited_budget und sind unbeeinflusst. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Dieser Commit ist enthalten in:
149
docs/ABRECHNUNG.md
Normale Datei
149
docs/ABRECHNUNG.md
Normale Datei
@@ -0,0 +1,149 @@
|
||||
# Credits und Abrechnung
|
||||
|
||||
Wie das Kontingent eines Kunden funktioniert, welche Stellschrauben es gibt und
|
||||
was die Verwaltung setzen muss. Stand 2026-07-25 (Portierung aus dem Lokal-Fork,
|
||||
Sätze auf die am 23.07.2026 beschlossenen Verkaufswerte gesetzt).
|
||||
|
||||
## Begriffe
|
||||
|
||||
Der Kunde sieht **Credits**, nicht Token und nicht Dollar. Das ist Absicht.
|
||||
"Token" ist ein KI-Fachbegriff mit einer festen Bedeutung, und 10.000 echte
|
||||
Token wären etwa 7.500 Wörter, also ein einziger längerer Artikel. Wer den
|
||||
Begriff kennt, hält so eine Angabe für einen Fehler. Intern heißen die Felder
|
||||
`credits_*`, nach außen steht überall "Credits" (Entscheidung vom 25.07.2026,
|
||||
einheitlich in Monitor und Verwaltungsportal).
|
||||
|
||||
## Was eine Aktion kostet
|
||||
|
||||
Im Modus `flat` (Voreinstellung) kostet jede Aktion einen festen Satz aus
|
||||
`CREDIT_TARIFF` in `src/config.py`, unabhängig davon, was sie uns tatsächlich
|
||||
verursacht hat. 1 Credit entspricht 0,20 USD.
|
||||
|
||||
| Aktion | Credits | Herkunft des Werts |
|
||||
|---|---|---|
|
||||
| Live-Refresh (adhoc) | 45 | beschlossen 23.07.2026 (gemessener Median 24 Credits = 4,76 USD) |
|
||||
| Recherche je Durchlauf | 40 | beschlossen 23.07.2026 (gemessener Median 33 Credits = 6,54 USD) |
|
||||
| Analyse-Baustein (Studio) | 12 | geschätzt, rund ein Viertel eines Live-Laufs |
|
||||
| Faktencheck-Baustein (Studio) | 12 | geschätzt |
|
||||
| Chat, Beschreibungs-Assistent, Globe | 1 | real 0,02 bis 0,03 USD je Aufruf |
|
||||
|
||||
Die erste Aktualisierung einer Recherche-Lage fährt drei Durchläufe, kostet also
|
||||
120 Credits. Die Verkaufssätze liegen bewusst über den gemessenen Medianen.
|
||||
Messgrundlage sind 1.341 abgeschlossene Refreshes des Live-Systems aus dem
|
||||
Zeitraum 28.02.2026 bis 21.06.2026 (`refresh_log`). Der Verbrauchsrechner im
|
||||
Verwaltungsportal rechnet mit denselben Sätzen.
|
||||
|
||||
### Warum feste Sätze und nicht die echten Kosten
|
||||
|
||||
Vorher wurde `echte_kosten / cost_per_credit` abgebucht. Das hatte zwei Nachteile.
|
||||
Der Kunde konnte nicht planen, weil ein Refresh einer großen Lage ein Vielfaches
|
||||
eines Refreshs einer frischen kostet, ohne dass er den Unterschied sieht. Und
|
||||
sobald das Modell-Backend billiger wird, etwa beim Wechsel von Anthropic auf eine
|
||||
EU-Cloud, hätte derselbe Kunde plötzlich ein Vielfaches an Aktionen bekommen,
|
||||
oder wir hätten `cost_per_credit` nachziehen müssen, was nach einer heimlichen
|
||||
Preiserhöhung aussieht.
|
||||
|
||||
Der alte Modus lebt weiter unter `BILLING_MODE=actual` als Rückfallebene. Die
|
||||
echten Kosten wandern in beiden Modi unverändert nach `token_usage_monthly`, die
|
||||
interne Kostenkontrolle bleibt also vollständig erhalten.
|
||||
|
||||
## Abrechnungsperiode
|
||||
|
||||
`licenses.credits_period` steuert den Bezugszeitraum.
|
||||
|
||||
- `monthly` (Voreinstellung) füllt die Credits zum Monatswechsel neu auf.
|
||||
- `total` lässt das Kontingent für die gesamte Lizenzlaufzeit gelten.
|
||||
|
||||
Der Wechsel passiert träge bei der nächsten Lizenzprüfung, nicht über einen
|
||||
Zeitplan. Ein verpasster Monatswechsel wird dadurch beim nächsten Zugriff
|
||||
nachgeholt, und ohne Nutzung wird ohnehin nichts verbraucht.
|
||||
|
||||
`credits_rollover` überträgt ungenutzte Credits in den Folgemonat, gedeckelt
|
||||
auf ein Monatskontingent. Der Übertrag steht in `credits_carried` und zählt beim
|
||||
Hard-Stop mit. Das ist empfehlenswert, weil OSINT-Nutzung ereignisgetrieben ist.
|
||||
Bricht eine Krise aus, braucht der Kunde in einer Woche mehr als sonst im
|
||||
Quartal, und genau dann darf das System nicht dichtmachen.
|
||||
|
||||
Eine Bestandslizenz ohne Periodenmarke bekommt beim ersten Zugriff die aktuelle
|
||||
Periode eingetragen, **ohne** den Verbrauch zurückzusetzen. Sonst würden ihr
|
||||
Credits geschenkt, die im laufenden Monat bereits verbraucht wurden.
|
||||
|
||||
## Warnung und Sperre
|
||||
|
||||
Bei Erreichen von `budget_warning_percent` (Voreinstellung 80) bekommen alle
|
||||
aktiven Nutzer der Organisation eine Meldung im Benachrichtigungsbereich. Das
|
||||
Flag `budget_warning_sent` verhindert, dass sich die Warnung bei jeder weiteren
|
||||
Buchung wiederholt, und wird beim Periodenwechsel zurückgesetzt.
|
||||
|
||||
Sind die Credits aufgebraucht, wechselt die Organisation in den Nur-Lese-Modus.
|
||||
Bestehende Lagen bleiben vollständig lesbar, es lassen sich nur keine neuen
|
||||
Aktualisierungen mehr starten. Abgeschaltet wird nichts.
|
||||
|
||||
**Offen.** Die Warnung geht bisher nur in die Oberfläche, nicht per E-Mail. Wer
|
||||
sich nicht anmeldet, sieht sie nicht. Ein Versand über `email_utils` wäre der
|
||||
nächste Schritt.
|
||||
|
||||
## Was die Verwaltung je Lizenz setzen muss
|
||||
|
||||
| Spalte | Bedeutung | Beispiel |
|
||||
|---|---|---|
|
||||
| `credits_total` | Kontingent je Periode | 10000 |
|
||||
| `cost_per_credit` | nur für `BILLING_MODE=actual` und die interne Rechnung | 0.20 |
|
||||
| `credits_period` | `monthly` oder `total` | monthly |
|
||||
| `credits_rollover` | Übertrag erlauben | 1 |
|
||||
| `budget_warning_percent` | Warnschwelle in Prozent | 80 |
|
||||
| `unlimited_budget` | Kontingent aushebeln | 0 |
|
||||
|
||||
Ohne `credits_total` läuft die Organisation ohne Kontingent, dann wird nichts
|
||||
belastet. So stehen aktuell alle vier Live-Lizenzen (`unlimited_budget=1`), die
|
||||
Umstellung ändert für sie nichts, bis ihnen ein Kontingent gesetzt wird.
|
||||
Das Verwaltungsportal hat für diese Stellwerte noch keine Eingabefelder, das ist
|
||||
ein eigenes, offenes Arbeitspaket auf der Portal-Seite.
|
||||
|
||||
## Einordnung der Größenordnung
|
||||
|
||||
Bei einem Satz von 45 Credits je Live-Lauf entspricht ein Monatskontingent von
|
||||
10.000 Credits rund 222 Live-Refreshes oder rund 83 neu angelegten Recherchen.
|
||||
Zum Vergleich, das gesamte Live-System mit 46 aktiven Lagen verbrauchte im Mai
|
||||
2026 nach den gemessenen Medianen rund 11.700 Credits, mit den Verkaufssätzen
|
||||
bewertet wären es grob 20.000 bis 22.000.
|
||||
|
||||
Ein Hinweis zur Fortschreibung. Die Ist-Kosten je Refresh sind zwischen März und
|
||||
Mai 2026 von 3,54 auf 7,80 Dollar gestiegen, vermutlich weil ein Lagebild mit
|
||||
wachsendem Materialbestand auf mehr Kontext aufsetzt. Falls sich das bestätigt,
|
||||
verbraucht derselbe Kunde im zweiten Jahr mehr als im ersten. Die Sätze in
|
||||
`CREDIT_TARIFF` sollten deshalb regelmäßig gegen `token_usage_monthly` geprüft
|
||||
werden.
|
||||
|
||||
## Auto-Refresh-Takt
|
||||
|
||||
Der Takt ist die wichtigste Stellschraube am Verbrauch. Achtung, im Online-Monitor
|
||||
liegt die Untergrenze derzeit noch bei 10 Minuten und die Voreinstellung bei
|
||||
15 Minuten. Ein Live-Refresh dauert gemessen im Median aber 12,7 Minuten, jeder
|
||||
zehnte länger als 22,9 Minuten, und im 15-Minuten-Takt verbraucht eine einzige
|
||||
Lage bei 45 Credits je Lauf rund 130.000 Credits im Monat. Der Lokal-Fork hat
|
||||
dafür bereits eine Lösung (Untergrenze 30 Minuten, Voreinstellung 12 Stunden,
|
||||
Kostenvorschau im Anlege-Dialog, Commit 5b0b578), deren Portierung noch offen ist.
|
||||
|
||||
Zur Orientierung bei einem Kontingent von 10.000 Credits und 45 Credits je Lauf.
|
||||
|
||||
| Takt | Refreshes je Monat | Credits | Anteil |
|
||||
|---|---|---|---|
|
||||
| 30 Min | 1.440 | 64.800 | 648 Prozent |
|
||||
| 1 Stunde | 720 | 32.400 | 324 Prozent |
|
||||
| 6 Stunden | 120 | 5.400 | 54 Prozent |
|
||||
| 12 Stunden | 60 | 2.700 | 27 Prozent |
|
||||
| 24 Stunden | 30 | 1.350 | 14 Prozent |
|
||||
|
||||
## Offene Punkte
|
||||
|
||||
- E-Mail-Versand der Budget-Warnung.
|
||||
- Eingabefelder für die Stellwerte im Verwaltungsportal (heute erzeugt das
|
||||
Anlegen einer Organisation dort nicht einmal eine Lizenz).
|
||||
- Takt-Untergrenze und Kostenvorschau aus dem Lokal-Fork portieren (siehe oben).
|
||||
- Nachkaufpakete. Ohne sie ist der Deckel eine Sackgasse, mit ihnen eine
|
||||
Umsatzquelle. Der Verkauf gehört ins Verwaltungsportal, im Monitor müsste nur
|
||||
der Hinweistext bei aufgebrauchten Credits darauf zeigen.
|
||||
- Sätze für die Studio-Bausteine sind geschätzt und sollten nachgemessen werden,
|
||||
sobald `token_usage_monthly` Zeilen mit `source='analysis'` und `'factcheck'`
|
||||
enthält.
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren