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
- Benutzer können pro Workflow definieren, welche **AICore-Provider** erlaubt sind
- Zuordnung auf Level **AICore-Connector**: `anthropic`, `openai`, `perplexity`, `tavily`, `internal`
- Benutzer können pro Workflow definieren, welche **AICore-Provider** verwendet werden
- 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
### 4. Transparente Kostenerfassung
@ -194,15 +195,25 @@ class UsageStatistics(BaseModel):
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
# Erweiterung: ChatWorkflow (datamodelChat.py)
class ChatWorkflow(BaseModel):
# ... bestehende Felder ...
# NEU: Mandanten-Kontext für Billing
mandateId: Optional[str] # FK → Mandate
# KEINE Änderung an ChatWorkflow erforderlich!
# ChatWorkflow bleibt "User-owned, no mandate context"
# Stattdessen: BillingTransaction speichert den Mandanten-Kontext
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").
@ -245,23 +256,35 @@ class ChatWorkflow(BaseModel):
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.openai`
- `resource.aicore.perplexity`
- `resource.aicore.tavily`
- `resource.aicore.internal`
- *(weitere zukünftig via Plug&Play)*
**Bootstrap-Berechtigungen (Mandate ROOT):**
- **SysAdmin:** Alle Provider (USE)
- **Admin:** Alle Provider (USE)
- **User:** Alle Provider (USE)
- **SysAdmin:** Alle registrierten Provider (USE)
- **Admin:** Alle registrierten Provider (USE)
- **User:** Alle registrierten Provider (USE)
**Vorteile des RBAC-Ansatzes:**
- Zentrale Verwaltung über bestehende Rollen-Struktur
- Granulare Steuerung pro Mandant möglich
- Keine zusätzlichen Datenbank-Attribute erforderlich
- Konsistent mit bestehendem Berechtigungssystem
- Automatische Erweiterung bei neuen AICore-Plugins
---
@ -463,9 +486,13 @@ def _setupRootMandate():
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']
for role in roles:
@ -696,9 +723,10 @@ Static Block: BILLING
**Integration in:** `/workflows/playground`
**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
- 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:**
1. **General** - Name, Beschreibung, Schedule, Status
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 │
│ │
│ Verfügbare Provider (basierend auf Ihren Berechtigungen):
│ Verfügbare Provider (dynamisch, RBAC-gefiltert):
│ ○ Anthropic (Claude) CHF 0.020/1k tokens │
│ ● OpenAI (GPT-4) CHF 0.015/1k tokens │
│ ○ Perplexity (Web) CHF 0.008/1k tokens │
@ -822,36 +850,36 @@ anbei erhalten Sie den monatlichen Kostenreport für Ihren Mandanten
ZUSAMMENFASSUNG
───────────────────────────────────────────────────────
Gesamtkosten: $ 156.80 USD
Gesamtkosten: CHF 156.80
Anzahl AI-Operationen: 423
Durchschnitt pro Operation: $ 0.37 USD
Durchschnitt pro Operation: CHF 0.37
AUFSCHLÜSSELUNG NACH PROVIDER
───────────────────────────────────────────────────────
Anthropic (Claude) $ 112.50 USD (72%)
OpenAI (GPT-4) $ 38.30 USD (24%)
Internal $ 6.00 USD (4%)
Anthropic (Claude) CHF 112.50 (72%)
OpenAI (GPT-4) CHF 38.30 (24%)
Internal CHF 6.00 (4%)
AUFSCHLÜSSELUNG NACH FEATURE
───────────────────────────────────────────────────────
Chat Playground $ 95.00 USD (61%)
Automation $ 45.80 USD (29%)
Chatbot (Feature) $ 16.00 USD (10%)
Chat Playground CHF 95.00 (61%)
Automation CHF 45.80 (29%)
Chatbot (Feature) CHF 16.00 (10%)
TOP 5 NUTZER (nach Verbrauch)
───────────────────────────────────────────────────────
1. Max Mustermann $ 48.50 USD
2. Anna Schmidt $ 35.20 USD
3. Peter Weber $ 28.90 USD
4. Lisa Müller $ 22.10 USD
5. Thomas Meier $ 12.30 USD
1. Max Mustermann CHF 48.50
2. Anna Schmidt CHF 35.20
3. Peter Weber CHF 28.90
4. Lisa Müller CHF 22.10
5. Thomas Meier CHF 12.30
KONTOSTAND
───────────────────────────────────────────────────────
Vorheriger Stand: $ 456.05 USD
Verbrauch: -$ 156.80 USD
Vorheriger Stand: CHF 456.05
Verbrauch: -CHF 156.80
───────────────────────────────────────────────────────
Aktueller Stand: $ 299.25 USD
Aktueller Stand: CHF 299.25
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
Warnschwelle unterschritten.
Aktuelles Guthaben: $ 45.00 USD
Warnschwelle: $ 50.00 USD (10%)
Aktuelles Guthaben: CHF 45.00
Warnschwelle: CHF 50.00 (10%)
Bitte laden Sie Ihr Guthaben auf, um Unterbrechungen zu vermeiden.
@ -888,29 +916,29 @@ PowerOn Platform
### Phase 1: Datenmodell & Grundstruktur
1. **Datenbank-Schema erstellen**
1. **Neue Billing-Datenbank erstellen** (`poweron_billing`)
- `BillingAccount`, `BillingTransaction`, `BillingSettings`, `UsageStatistics` Tabellen
- Migration für bestehende Mandanten (Default: `UNLIMITED`)
2. **Erweiterung bestehender Modelle**
- `ChatWorkflow.mandateId` hinzufügen
- `ChatWorkflow.allowedProviders` hinzufügen
- `AutomationDefinition.allowedProviders` hinzufügen
2. **Keine Änderung an Chat-Modellen**
- Chat-Daten bleiben "User-owned" (kein mandateId in ChatWorkflow)
- Mandanten-Kontext wird in BillingTransaction gespeichert
3. **BillingService implementieren**
- Balance-Prüfung
- Transaktions-Erfassung
- Provider-Validierung
- Transaktions-Erfassung mit mandateId aus Request-Context
- Provider-Validierung über RBAC
### Phase 2: Integration in Workflows
1. **ChatWorkflow erweitern**
- `mandateId` bei Start speichern
- Provider-Filter bei Model-Selection
1. **Billing-Integration in WorkflowProcessor**
- `mandateId` und `featureInstanceId` aus Request-Context verwenden
- BillingTransaction bei jedem AI-Call erstellen (mit mandateId)
- Provider-Filter über RBAC bei Model-Selection
2. **Billing-Checks einbauen**
- Vor jedem AI-Call: Balance prüfen
- Nach jedem AI-Call: Kosten erfassen
- Vor jedem AI-Call: Balance prüfen (BillingAccount des Mandanten)
- Nach jedem AI-Call: Kosten als BillingTransaction erfassen
3. **Error Handling**
- `InsufficientBalanceException`
@ -947,7 +975,8 @@ PowerOn Platform
1. **Root-Mandant Setup**
- `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**
- Accounts erstellen
@ -956,6 +985,7 @@ PowerOn Platform
3. **Bestehende Mandanten migrieren**
- Default-Settings erstellen
- `UNLIMITED` oder `PREPAY_MANDATE`
- RBAC-Berechtigungen für LLM-Provider erstellen
### 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?**
**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.
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**
- Wie laden Kunden Guthaben auf? (Stripe, Rechnung, manuell)
- Self-Service oder nur Admin?
→ Stripe-Anbindung wird vorbereitet (zukünftig)
→ Aktuell: SysAdmin-Seite für manuelle Guthaben-Aufladung
2. **Preisgestaltung**
- Aufschlag auf Provider-Kosten? (z.B. +20%)
- Fixkosten pro Mandant/User?
**50% Aufschlag** auf Provider-Kosten, direkt in AICore-Modellen definiert
→ Preise werden in CHF kalkuliert und gespeichert
3. **Währung**
- Nur USD intern, Anzeige in CHF/EUR?
- Wechselkurs-Handling?
**Alles in CHF**, keine Währungsumrechnung im System
→ Provider-Kosten werden intern auf CHF umgerechnet und mit 50% Aufschlag versehen
4. **Datenhaltung**
- Wie lange Transaktions-Historie aufbewahren?
- Archivierung alter Daten?
**10 Jahre** Aufbewahrungspflicht für Transaktionen
→ Automatische Archivierung/Löschung nach 10 Jahren
5. **GDPR/Datenschutz**
- User-Löschung: Was passiert mit Billing-Daten?
- Anonymisierung nach X Jahren?
→ Transaktionsdaten nach 10 Jahren löschen
→ 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 |
| **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 |
| **Kostenstelle** | Mandant, dem Kosten zugeordnet werden |
| **Mandate** | Mandant/Tenant in der Multi-Tenant-Architektur |
| **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/
├── 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
├── datamodels/
│ ├── datamodelChat.py # ChatWorkflow erweitern
│ ├── datamodelChat.py # ChatWorkflow.mandateId hinzufügen
│ └── datamodelUam.py # Mandate-Referenz
├── features/automation/
│ └── datamodelFeatureAutomation.py # allowedProviders hinzufügen
├── interfaces/
│ └── interfaceBootstrap.py # Root-Mandant Billing Setup
│ ├── interfaceBootstrap.py # Root-Mandant Billing Setup + RBAC
│ └── interfaceRbac.py # Resource-Berechtigungen für Provider
├── workflows/
│ ├── automation/mainWorkflow.py # Billing-Integration
│ └── processing/workflowProcessor.py # Balance-Checks
│ └── processing/workflowProcessor.py # Balance-Checks + RBAC Provider-Check
└── routes/
└── routeChat.py # mandateId im Workflow speichern
```