billing concept

This commit is contained in:
ValueOn AG 2026-02-04 15:35:23 +01:00
parent 92c9e37f1e
commit e4ba4d8328

View file

@ -26,8 +26,9 @@ Mandant (Kostenstelle)
``` ```
### 3. LLM-Provider-Steuerung ### 3. LLM-Provider-Steuerung
- Benutzer können pro Workflow definieren, welche **AICore-Provider** erlaubt sind - Benutzer können pro Workflow definieren, welche **AICore-Provider** verwendet werden
- Zuordnung auf Level **AICore-Connector**: `anthropic`, `openai`, `perplexity`, `tavily`, `internal` - Provider-Liste ist **dynamisch** basierend auf registrierten AICore-Plugins (Plug&Play)
- Zuordnung auf Level **AICore-Connector** (z.B. `anthropic`, `openai`, `perplexity`, `tavily`, `internal`, weitere zukünftig)
- Ermöglicht Kostenkontrolle und Compliance-Anforderungen - Ermöglicht Kostenkontrolle und Compliance-Anforderungen
### 4. Transparente Kostenerfassung ### 4. Transparente Kostenerfassung
@ -194,15 +195,25 @@ class UsageStatistics(BaseModel):
costByFeature: Dict[str, float] # {'playground': 15.00, 'automation': 5.80} costByFeature: Dict[str, float] # {'playground': 15.00, 'automation': 5.80}
``` ```
### Erweiterung bestehender Modelle ### Hinweis: Chat-Daten bleiben User-owned
**Wichtig:** Die Chat-Modelle (`ChatWorkflow`, `ChatStat`, `ChatMessage`, etc.) speichern **keine** `mandateId`. Sie sind "User-owned" und die Mandanten-Zuordnung erfolgt über RBAC-Filterung zur Laufzeit.
**Billing-Zuordnung:** Der Mandanten-Kontext wird **in der BillingTransaction** gespeichert, nicht im ChatWorkflow:
- Bei jedem AI-Call wird der `mandateId` aus dem Request-Context in der Transaktion gespeichert
- Die Verknüpfung Workflow → Mandant erfolgt über `BillingTransaction.workflowId`
- Statistiken werden aus den BillingTransactions aggregiert, nicht aus ChatStat
```python ```python
# Erweiterung: ChatWorkflow (datamodelChat.py) # KEINE Änderung an ChatWorkflow erforderlich!
class ChatWorkflow(BaseModel): # ChatWorkflow bleibt "User-owned, no mandate context"
# ... bestehende Felder ...
# NEU: Mandanten-Kontext für Billing # Stattdessen: BillingTransaction speichert den Mandanten-Kontext
mandateId: Optional[str] # FK → Mandate class BillingTransaction(BaseModel):
# ...
workflowId: Optional[str] # Referenz zum Workflow
featureInstanceId: Optional[str] # Feature-Instanz (z.B. chatplayground)
# mandateId kommt über BillingAccount
``` ```
**Hinweis:** Die Provider-Steuerung erfolgt NICHT über Datenbank-Attribute, sondern über das RBAC-System (siehe Abschnitt "LLM-Provider als RBAC Resources"). **Hinweis:** Die Provider-Steuerung erfolgt NICHT über Datenbank-Attribute, sondern über das RBAC-System (siehe Abschnitt "LLM-Provider als RBAC Resources").
@ -245,23 +256,35 @@ class ChatWorkflow(BaseModel):
Die Steuerung, welche LLM-Provider ein Benutzer verwenden darf, erfolgt über das RBAC-System: Die Steuerung, welche LLM-Provider ein Benutzer verwenden darf, erfolgt über das RBAC-System:
**Registrierte Resources:** **Resource-Namenskonvention:**
```
resource.aicore.{connectorType}
```
**Dynamische Registrierung:**
- Jedes AICore-Plugin registriert sich automatisch als RBAC-Resource
- Die Liste der verfügbaren Provider wird aus `ModelRegistry.getConnectors()` ermittelt
- Neue Plugins werden automatisch erkannt (Plug&Play)
**Beispiel aktuell registrierter Provider:**
- `resource.aicore.anthropic` - `resource.aicore.anthropic`
- `resource.aicore.openai` - `resource.aicore.openai`
- `resource.aicore.perplexity` - `resource.aicore.perplexity`
- `resource.aicore.tavily` - `resource.aicore.tavily`
- `resource.aicore.internal` - `resource.aicore.internal`
- *(weitere zukünftig via Plug&Play)*
**Bootstrap-Berechtigungen (Mandate ROOT):** **Bootstrap-Berechtigungen (Mandate ROOT):**
- **SysAdmin:** Alle Provider (USE) - **SysAdmin:** Alle registrierten Provider (USE)
- **Admin:** Alle Provider (USE) - **Admin:** Alle registrierten Provider (USE)
- **User:** Alle Provider (USE) - **User:** Alle registrierten Provider (USE)
**Vorteile des RBAC-Ansatzes:** **Vorteile des RBAC-Ansatzes:**
- Zentrale Verwaltung über bestehende Rollen-Struktur - Zentrale Verwaltung über bestehende Rollen-Struktur
- Granulare Steuerung pro Mandant möglich - Granulare Steuerung pro Mandant möglich
- Keine zusätzlichen Datenbank-Attribute erforderlich - Keine zusätzlichen Datenbank-Attribute erforderlich
- Konsistent mit bestehendem Berechtigungssystem - Konsistent mit bestehendem Berechtigungssystem
- Automatische Erweiterung bei neuen AICore-Plugins
--- ---
@ -463,9 +486,13 @@ def _setupRootMandate():
def _setupAicoreRbacPermissions(mandateId: str): def _setupAicoreRbacPermissions(mandateId: str):
"""Erstellt RBAC-Berechtigungen für LLM-Provider""" """Erstellt RBAC-Berechtigungen für LLM-Provider (dynamisch)"""
# Provider dynamisch aus ModelRegistry laden (Plug&Play)
from modules.aicore.aicoreModelRegistry import modelRegistry
connectors = modelRegistry.discoverConnectors()
providers = [c.getConnectorType() for c in connectors]
providers = ['anthropic', 'openai', 'perplexity', 'tavily', 'internal']
roles = ['sysadmin', 'admin', 'user'] roles = ['sysadmin', 'admin', 'user']
for role in roles: for role in roles:
@ -696,9 +723,10 @@ Static Block: BILLING
**Integration in:** `/workflows/playground` **Integration in:** `/workflows/playground`
**Funktionen:** **Funktionen:**
- Dropdown/Checkboxen für erlaubte Provider - Provider-Liste wird **dynamisch** aus registrierten AICore-Plugins geladen
- Zeigt nur Provider an, für die der User RBAC-Berechtigung hat - Zeigt nur Provider an, für die der User RBAC-Berechtigung hat
- Auswahl gilt für den nächsten AI-Call - Auswahl gilt für den nächsten AI-Call
- Preise werden aus den Plugin-Definitionen gelesen
``` ```
┌─────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────┐
@ -729,7 +757,7 @@ Das Automation-Editor Modal wird in drei Tabs aufgeteilt:
**Tab-Struktur:** **Tab-Struktur:**
1. **General** - Name, Beschreibung, Schedule, Status 1. **General** - Name, Beschreibung, Schedule, Status
2. **Modellierung** - Template, Placeholders, Preview 2. **Modellierung** - Template, Placeholders, Preview
3. **LLM Modelle** - Provider-Auswahl basierend auf RBAC-Berechtigungen 3. **LLM Modelle** - Provider-Auswahl (dynamisch aus AICore-Plugins, gefiltert nach RBAC)
``` ```
┌─────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────┐
@ -739,7 +767,7 @@ Das Automation-Editor Modal wird in drei Tabs aufgeteilt:
│ ───────────────────────────────────────────────────── │ │ ───────────────────────────────────────────────────── │
│ TAB: LLM Modelle │ │ TAB: LLM Modelle │
│ │ │ │
│ Verfügbare Provider (basierend auf Ihren Berechtigungen): │ Verfügbare Provider (dynamisch, RBAC-gefiltert):
│ ○ Anthropic (Claude) CHF 0.020/1k tokens │ │ ○ Anthropic (Claude) CHF 0.020/1k tokens │
│ ● OpenAI (GPT-4) CHF 0.015/1k tokens │ │ ● OpenAI (GPT-4) CHF 0.015/1k tokens │
│ ○ Perplexity (Web) CHF 0.008/1k tokens │ │ ○ Perplexity (Web) CHF 0.008/1k tokens │
@ -822,36 +850,36 @@ anbei erhalten Sie den monatlichen Kostenreport für Ihren Mandanten
ZUSAMMENFASSUNG ZUSAMMENFASSUNG
─────────────────────────────────────────────────────── ───────────────────────────────────────────────────────
Gesamtkosten: $ 156.80 USD Gesamtkosten: CHF 156.80
Anzahl AI-Operationen: 423 Anzahl AI-Operationen: 423
Durchschnitt pro Operation: $ 0.37 USD Durchschnitt pro Operation: CHF 0.37
AUFSCHLÜSSELUNG NACH PROVIDER AUFSCHLÜSSELUNG NACH PROVIDER
─────────────────────────────────────────────────────── ───────────────────────────────────────────────────────
Anthropic (Claude) $ 112.50 USD (72%) Anthropic (Claude) CHF 112.50 (72%)
OpenAI (GPT-4) $ 38.30 USD (24%) OpenAI (GPT-4) CHF 38.30 (24%)
Internal $ 6.00 USD (4%) Internal CHF 6.00 (4%)
AUFSCHLÜSSELUNG NACH FEATURE AUFSCHLÜSSELUNG NACH FEATURE
─────────────────────────────────────────────────────── ───────────────────────────────────────────────────────
Chat Playground $ 95.00 USD (61%) Chat Playground CHF 95.00 (61%)
Automation $ 45.80 USD (29%) Automation CHF 45.80 (29%)
Chatbot (Feature) $ 16.00 USD (10%) Chatbot (Feature) CHF 16.00 (10%)
TOP 5 NUTZER (nach Verbrauch) TOP 5 NUTZER (nach Verbrauch)
─────────────────────────────────────────────────────── ───────────────────────────────────────────────────────
1. Max Mustermann $ 48.50 USD 1. Max Mustermann CHF 48.50
2. Anna Schmidt $ 35.20 USD 2. Anna Schmidt CHF 35.20
3. Peter Weber $ 28.90 USD 3. Peter Weber CHF 28.90
4. Lisa Müller $ 22.10 USD 4. Lisa Müller CHF 22.10
5. Thomas Meier $ 12.30 USD 5. Thomas Meier CHF 12.30
KONTOSTAND KONTOSTAND
─────────────────────────────────────────────────────── ───────────────────────────────────────────────────────
Vorheriger Stand: $ 456.05 USD Vorheriger Stand: CHF 456.05
Verbrauch: -$ 156.80 USD Verbrauch: -CHF 156.80
─────────────────────────────────────────────────────── ───────────────────────────────────────────────────────
Aktueller Stand: $ 299.25 USD Aktueller Stand: CHF 299.25
Bei Fragen stehen wir Ihnen gerne zur Verfügung. Bei Fragen stehen wir Ihnen gerne zur Verfügung.
@ -871,8 +899,8 @@ Betreff: ⚠️ PowerOn - Niedriges Guthaben für SOHA Treuhand AG
Ihr Guthaben für den Mandanten "SOHA Treuhand AG" hat die Ihr Guthaben für den Mandanten "SOHA Treuhand AG" hat die
Warnschwelle unterschritten. Warnschwelle unterschritten.
Aktuelles Guthaben: $ 45.00 USD Aktuelles Guthaben: CHF 45.00
Warnschwelle: $ 50.00 USD (10%) Warnschwelle: CHF 50.00 (10%)
Bitte laden Sie Ihr Guthaben auf, um Unterbrechungen zu vermeiden. Bitte laden Sie Ihr Guthaben auf, um Unterbrechungen zu vermeiden.
@ -888,29 +916,29 @@ PowerOn Platform
### Phase 1: Datenmodell & Grundstruktur ### Phase 1: Datenmodell & Grundstruktur
1. **Datenbank-Schema erstellen** 1. **Neue Billing-Datenbank erstellen** (`poweron_billing`)
- `BillingAccount`, `BillingTransaction`, `BillingSettings`, `UsageStatistics` Tabellen - `BillingAccount`, `BillingTransaction`, `BillingSettings`, `UsageStatistics` Tabellen
- Migration für bestehende Mandanten (Default: `UNLIMITED`) - Migration für bestehende Mandanten (Default: `UNLIMITED`)
2. **Erweiterung bestehender Modelle** 2. **Keine Änderung an Chat-Modellen**
- `ChatWorkflow.mandateId` hinzufügen - Chat-Daten bleiben "User-owned" (kein mandateId in ChatWorkflow)
- `ChatWorkflow.allowedProviders` hinzufügen - Mandanten-Kontext wird in BillingTransaction gespeichert
- `AutomationDefinition.allowedProviders` hinzufügen
3. **BillingService implementieren** 3. **BillingService implementieren**
- Balance-Prüfung - Balance-Prüfung
- Transaktions-Erfassung - Transaktions-Erfassung mit mandateId aus Request-Context
- Provider-Validierung - Provider-Validierung über RBAC
### Phase 2: Integration in Workflows ### Phase 2: Integration in Workflows
1. **ChatWorkflow erweitern** 1. **Billing-Integration in WorkflowProcessor**
- `mandateId` bei Start speichern - `mandateId` und `featureInstanceId` aus Request-Context verwenden
- Provider-Filter bei Model-Selection - BillingTransaction bei jedem AI-Call erstellen (mit mandateId)
- Provider-Filter über RBAC bei Model-Selection
2. **Billing-Checks einbauen** 2. **Billing-Checks einbauen**
- Vor jedem AI-Call: Balance prüfen - Vor jedem AI-Call: Balance prüfen (BillingAccount des Mandanten)
- Nach jedem AI-Call: Kosten erfassen - Nach jedem AI-Call: Kosten als BillingTransaction erfassen
3. **Error Handling** 3. **Error Handling**
- `InsufficientBalanceException` - `InsufficientBalanceException`
@ -947,7 +975,8 @@ PowerOn Platform
1. **Root-Mandant Setup** 1. **Root-Mandant Setup**
- `PREPAY_USER` Modell - `PREPAY_USER` Modell
- 10 USD Startguthaben für neue User - 10 CHF Startguthaben für neue User
- RBAC-Berechtigungen für alle LLM-Provider
2. **Bestehende User migrieren** 2. **Bestehende User migrieren**
- Accounts erstellen - Accounts erstellen
@ -956,6 +985,7 @@ PowerOn Platform
3. **Bestehende Mandanten migrieren** 3. **Bestehende Mandanten migrieren**
- Default-Settings erstellen - Default-Settings erstellen
- `UNLIMITED` oder `PREPAY_MANDATE` - `UNLIMITED` oder `PREPAY_MANDATE`
- RBAC-Berechtigungen für LLM-Provider erstellen
### Phase 6: Email-Reports ### Phase 6: Email-Reports
@ -973,9 +1003,9 @@ PowerOn Platform
--- ---
## Offene Fragen und Entscheidungen ## Entscheidungen
### Beantwortet ### Architektur-Entscheidungen
1. **Soll Chat Playground über Mandanten laufen?** 1. **Soll Chat Playground über Mandanten laufen?**
**Ja**, dies ist für konsistente Verrechnung notwendig. `ChatWorkflow.mandateId` wird aus dem Request-Context übernommen. **Ja**, dies ist für konsistente Verrechnung notwendig. `ChatWorkflow.mandateId` wird aus dem Request-Context übernommen.
@ -984,29 +1014,47 @@ PowerOn Platform
`data.chat.*` und `data.files.*` sind aktuell `USER_OWNED`. Für Billing muss `ChatWorkflow` den Mandanten-Kontext speichern. `data.chat.*` und `data.files.*` sind aktuell `USER_OWNED`. Für Billing muss `ChatWorkflow` den Mandanten-Kontext speichern.
3. **Läuft Automation bereits über Mandanten?** 3. **Läuft Automation bereits über Mandanten?**
**Ja**, `AutomationDefinition.mandateId` existiert bereits. Erweiterung nur um `allowedProviders`. **Ja**, `AutomationDefinition.mandateId` existiert bereits.
### Noch zu klären 4. **Provider-Steuerung**
→ Über RBAC-System als Resources (`resource.aicore.*`), NICHT als Datenbank-Attribute.
### Geschäftsentscheidungen
1. **Payment-Integration** 1. **Payment-Integration**
- Wie laden Kunden Guthaben auf? (Stripe, Rechnung, manuell) → Stripe-Anbindung wird vorbereitet (zukünftig)
- Self-Service oder nur Admin? → Aktuell: SysAdmin-Seite für manuelle Guthaben-Aufladung
2. **Preisgestaltung** 2. **Preisgestaltung**
- Aufschlag auf Provider-Kosten? (z.B. +20%) **50% Aufschlag** auf Provider-Kosten, direkt in AICore-Modellen definiert
- Fixkosten pro Mandant/User? → Preise werden in CHF kalkuliert und gespeichert
3. **Währung** 3. **Währung**
- Nur USD intern, Anzeige in CHF/EUR? **Alles in CHF**, keine Währungsumrechnung im System
- Wechselkurs-Handling? → Provider-Kosten werden intern auf CHF umgerechnet und mit 50% Aufschlag versehen
4. **Datenhaltung** 4. **Datenhaltung**
- Wie lange Transaktions-Historie aufbewahren? **10 Jahre** Aufbewahrungspflicht für Transaktionen
- Archivierung alter Daten? → Automatische Archivierung/Löschung nach 10 Jahren
5. **GDPR/Datenschutz** 5. **GDPR/Datenschutz**
- User-Löschung: Was passiert mit Billing-Daten? → Transaktionsdaten nach 10 Jahren löschen
- Anonymisierung nach X Jahren? → Gelöschte User: Nur ID-Referenz in Transaktionen (bereits anonym, da keine personenbezogenen Daten)
→ Daten im System belassen für Mandanten-Abrechnungen
### Preistabelle (50% Aufschlag) - Beispiele
Jedes AICore-Plugin definiert seine eigenen Preise via `calculatePriceCHF()`. Die Preise werden dynamisch aus den Plugins geladen.
| Provider | Provider-Kosten (ca.) | Interner Preis (CHF) |
|------------|----------------------|----------------------|
| Anthropic | $0.015/1k tokens | CHF 0.020/1k tokens |
| OpenAI | $0.010/1k tokens | CHF 0.015/1k tokens |
| Perplexity | $0.005/1k tokens | CHF 0.008/1k tokens |
| Tavily | $0.003/1k tokens | CHF 0.005/1k tokens |
| Internal | $0.001/1k tokens | CHF 0.002/1k tokens |
**Hinweis:** Preise werden direkt in den AICore-Plugin-Modellen definiert (`calculatePriceCHF`) und beinhalten bereits den 50% Aufschlag.
--- ---
@ -1016,11 +1064,13 @@ PowerOn Platform
|---------|--------------| |---------|--------------|
| **AICore** | Plugin-System für LLM-Provider Integration | | **AICore** | Plugin-System für LLM-Provider Integration |
| **Billing Account** | Konto für Guthaben/Saldo (pro Mandant oder User) | | **Billing Account** | Konto für Guthaben/Saldo (pro Mandant oder User) |
| **Billing Address** | Rechnungsadresse, erforderlich für CREDIT_POSTPAY |
| **Connector** | AICore-Plugin für einen spezifischen Provider | | **Connector** | AICore-Plugin für einen spezifischen Provider |
| **Kostenstelle** | Mandant, dem Kosten zugeordnet werden | | **Kostenstelle** | Mandant, dem Kosten zugeordnet werden |
| **Mandate** | Mandant/Tenant in der Multi-Tenant-Architektur | | **Mandate** | Mandant/Tenant in der Multi-Tenant-Architektur |
| **Provider** | LLM-Anbieter (anthropic, openai, etc.) | | **Provider** | LLM-Anbieter (anthropic, openai, etc.) |
| **priceCHF** | Berechneter Preis einer AI-Operation in USD | | **priceCHF** | Berechneter Preis einer AI-Operation in CHF (inkl. 50% Aufschlag) |
| **RBAC Resource** | Berechtigungs-Objekt für Provider-Zugriff (z.B. `resource.aicore.anthropic`) |
--- ---
@ -1031,18 +1081,19 @@ PowerOn Platform
``` ```
gateway/modules/ gateway/modules/
├── aicore/ ├── aicore/
│ ├── aicoreModelSelector.py # Provider-Filter hinzufügen │ ├── aicoreModelSelector.py # Provider-Filter via RBAC
│ ├── aicorePluginAnthropic.py # Preise auf CHF mit 50% Aufschlag
│ ├── aicorePluginOpenai.py # Preise auf CHF mit 50% Aufschlag
│ └── aicoreBase.py # connectorType für Billing │ └── aicoreBase.py # connectorType für Billing
├── datamodels/ ├── datamodels/
│ ├── datamodelChat.py # ChatWorkflow erweitern │ ├── datamodelChat.py # ChatWorkflow.mandateId hinzufügen
│ └── datamodelUam.py # Mandate-Referenz │ └── datamodelUam.py # Mandate-Referenz
├── features/automation/
│ └── datamodelFeatureAutomation.py # allowedProviders hinzufügen
├── interfaces/ ├── interfaces/
│ └── interfaceBootstrap.py # Root-Mandant Billing Setup │ ├── interfaceBootstrap.py # Root-Mandant Billing Setup + RBAC
│ └── interfaceRbac.py # Resource-Berechtigungen für Provider
├── workflows/ ├── workflows/
│ ├── automation/mainWorkflow.py # Billing-Integration │ ├── automation/mainWorkflow.py # Billing-Integration
│ └── processing/workflowProcessor.py # Balance-Checks │ └── processing/workflowProcessor.py # Balance-Checks + RBAC Provider-Check
└── routes/ └── routes/
└── routeChat.py # mandateId im Workflow speichern └── routeChat.py # mandateId im Workflow speichern
``` ```