1180 lines
47 KiB
Markdown
1180 lines
47 KiB
Markdown
# Billing & Verrechnungssystem Konzept
|
|
|
|
## Übersicht
|
|
|
|
Dieses Dokument beschreibt das Konzept für ein Kosten- und Verrechnungssystem (Billing) für LLM-Nutzung in der PowerOn-Plattform. Das System ermöglicht die Abrechnung von AI-Services auf Mandanten- und Benutzerebene mit verschiedenen Abrechnungsmodellen.
|
|
|
|
## Grundprinzipien
|
|
|
|
### 1. Mandantenzentrierte Verrechnung
|
|
- **Alle Kosten** werden einem Mandanten zugeordnet
|
|
- Der **Mandant** ist die zentrale Abrechnungseinheit
|
|
- Benutzer können mehreren Mandanten angehören → Kosten werden pro Mandant getrennt erfasst
|
|
|
|
### 2. Kostenstellen-Hierarchie
|
|
```
|
|
Mandant (Kostenstelle)
|
|
├── Abrechnungsmodell (definiert durch SysAdmin)
|
|
├── Budget/Guthaben
|
|
├── Benutzer mit Zugriff
|
|
│ ├── User A → individuelle Nutzung
|
|
│ └── User B → individuelle Nutzung
|
|
└── Features mit LLM-Nutzung
|
|
├── Chat Playground
|
|
├── Chatbot (Feature-Instanzen)
|
|
└── Automation
|
|
```
|
|
|
|
### 3. LLM-Provider-Steuerung
|
|
- 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
|
|
- Jede AI-Operation wird mit Kosten erfasst (`priceCHF`)
|
|
- Echtzeit-Sichtbarkeit für Benutzer
|
|
- Monatliche Abrechnungsberichte
|
|
|
|
---
|
|
|
|
## Abrechnungsmodelle
|
|
|
|
### Übersicht der Modelle
|
|
|
|
| Modell | Beschreibung | Kostenstelle | Nutzung |
|
|
|--------|--------------|--------------|---------|
|
|
| `PREPAY_MANDATE` | Vorbezahltes Guthaben auf Mandantenebene | Mandant | Gemeinsames Budget für alle User |
|
|
| `PREPAY_USER` | Vorbezahltes Guthaben pro User | User (im Mandanten-Kontext) | Individuelles Budget |
|
|
| `CREDIT_POSTPAY` | Nutzung auf Kredit mit Nachzahlung | Mandant (Rechnungsadresse erforderlich) | Monatsrechnung |
|
|
| `UNLIMITED` | Keine Kostenlimitierung | - | Nur für interne Mandanten |
|
|
|
|
### Modell: PREPAY_MANDATE
|
|
|
|
```
|
|
Mandant "SOHA Treuhand AG"
|
|
├── Abrechnungsmodell: PREPAY_MANDATE
|
|
├── Guthaben: 500.00 CHF
|
|
├── Warnschwelle: 50.00 CHF (10%)
|
|
└── Nutzer:
|
|
├── User A: verbraucht 120.50 CHF → Mandanten-Konto -120.50
|
|
└── User B: verbraucht 80.25 CHF → Mandanten-Konto -80.25
|
|
|
|
Restguthaben: 299.25 CHF
|
|
```
|
|
|
|
**Eigenschaften:**
|
|
- Mandant lädt Guthaben auf (via Admin oder Payment)
|
|
- Alle User des Mandanten teilen das Guthaben
|
|
- Bei Guthaben = 0 → AI-Features blockiert (mit Warnung)
|
|
- Warnschwelle konfigurierbar (Email-Benachrichtigung)
|
|
|
|
### Modell: PREPAY_USER
|
|
|
|
```
|
|
Mandant "ROOT" (Bootstrap-Mandant)
|
|
├── Abrechnungsmodell: PREPAY_USER
|
|
├── Startguthaben für neue User: 10.00 CHF
|
|
└── Nutzer:
|
|
├── User A: Guthaben 10.00 CHF → verbraucht 3.50 → Rest 6.50 CHF
|
|
└── User B: Guthaben 25.00 CHF → verbraucht 12.00 → Rest 13.00 CHF
|
|
```
|
|
|
|
**Eigenschaften:**
|
|
- Jeder User hat eigenes Guthaben im Mandanten-Kontext
|
|
- Neuer User erhält Startguthaben (konfigurierbar)
|
|
- User kann Guthaben aufladen
|
|
- Bei Guthaben = 0 → AI-Features blockiert für diesen User
|
|
|
|
### Modell: CREDIT_POSTPAY
|
|
|
|
```
|
|
Mandant "Enterprise AG"
|
|
├── Abrechnungsmodell: CREDIT_POSTPAY
|
|
├── Rechnungsadresse: Enterprise AG, Musterstrasse 1, 8000 Zürich
|
|
├── Kreditlimit: 2000.00 CHF (optional)
|
|
├── Aktueller Saldo: -450.00 CHF (Schulden)
|
|
└── Monatsende: Rechnung über 450.00 CHF
|
|
```
|
|
|
|
**Eigenschaften:**
|
|
- Nutzung ohne Vorauszahlung
|
|
- Monatliche Abrechnung
|
|
- Optionales Kreditlimit
|
|
- Für verifizierte Geschäftskunden
|
|
|
|
---
|
|
|
|
## Datenmodell
|
|
|
|
### Neue Tabellen
|
|
|
|
```python
|
|
# modules/datamodels/datamodelBilling.py
|
|
|
|
class BillingAddress(BaseModel):
|
|
"""Rechnungsadresse für CREDIT_POSTPAY Mandanten"""
|
|
|
|
company: str # Firmenname
|
|
street: str # Strasse und Hausnummer
|
|
zip: str # PLZ
|
|
city: str # Ort
|
|
country: str # Land (Default: "CH")
|
|
vatNumber: Optional[str] # MwSt-Nummer (optional)
|
|
|
|
|
|
class BillingAccount(BaseModel):
|
|
"""Abrechnungskonto pro Mandant oder User-Mandant-Kombination"""
|
|
|
|
id: str # UUID
|
|
mandateId: str # FK → Mandate
|
|
userId: Optional[str] # FK → User (nur bei PREPAY_USER)
|
|
accountType: str # MANDATE | USER
|
|
balance: float # Aktuelles Guthaben/Saldo in CHF
|
|
creditLimit: Optional[float] # Kreditlimit in CHF (nur CREDIT_POSTPAY)
|
|
warningThreshold: float # Warnschwelle in CHF
|
|
lastWarningAt: Optional[datetime] # Letzte Warnung gesendet
|
|
enabled: bool # Account aktiv
|
|
|
|
|
|
class BillingTransaction(BaseModel):
|
|
"""Einzelne Transaktion (Aufladung, Verbrauch, Gutschrift)"""
|
|
|
|
id: str # UUID
|
|
accountId: str # FK → BillingAccount
|
|
transactionType: str # CREDIT | DEBIT | ADJUSTMENT
|
|
amount: float # Betrag in CHF (positiv)
|
|
description: str # Beschreibung
|
|
|
|
# Referenz zur Quelle
|
|
referenceType: Optional[str] # WORKFLOW | PAYMENT | ADMIN | SYSTEM
|
|
referenceId: Optional[str] # ID des referenzierten Objekts
|
|
|
|
# Kontext
|
|
workflowId: Optional[str] # Bei WORKFLOW-Verbrauch
|
|
featureInstanceId: Optional[str] # Bei Feature-Nutzung
|
|
aicoreProvider: Optional[str] # anthropic, openai, etc.
|
|
|
|
|
|
class BillingSettings(BaseModel):
|
|
"""Abrechnungseinstellungen pro Mandant"""
|
|
|
|
id: str # UUID
|
|
mandateId: str # FK → Mandate (UNIQUE)
|
|
billingModel: str # PREPAY_MANDATE | PREPAY_USER | CREDIT_POSTPAY | UNLIMITED
|
|
|
|
# Konfiguration
|
|
defaultUserCredit: float # Startguthaben in CHF für neue User (bei PREPAY_USER)
|
|
warningThresholdPercent: float # Warnschwelle in % (z.B. 10)
|
|
blockOnZeroBalance: bool # AI blockieren bei Guthaben = 0
|
|
|
|
# Rechnungsadresse (erforderlich für CREDIT_POSTPAY)
|
|
billingAddress: Optional[BillingAddress]
|
|
|
|
# Benachrichtigungen
|
|
notifyEmails: List[str] # Email-Adressen für Monatsberichte
|
|
notifyOnWarning: bool # Email bei Unterschreitung Warnschwelle
|
|
|
|
|
|
class UsageStatistics(BaseModel):
|
|
"""Aggregierte Nutzungsstatistiken (für schnellen Abruf)"""
|
|
|
|
id: str # UUID
|
|
accountId: str # FK → BillingAccount
|
|
periodType: str # DAY | MONTH | YEAR
|
|
periodStart: date # Beginn der Periode
|
|
|
|
# Aggregierte Werte
|
|
totalCostCHF: float # Gesamtkosten in CHF
|
|
transactionCount: int # Anzahl Transaktionen
|
|
|
|
# Aufschlüsselung nach Provider
|
|
costByProvider: Dict[str, float] # {'anthropic': 12.50, 'openai': 8.30}
|
|
|
|
# Aufschlüsselung nach Feature
|
|
costByFeature: Dict[str, float] # {'playground': 15.00, 'automation': 5.80}
|
|
```
|
|
|
|
### 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
|
|
# 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").
|
|
|
|
### ER-Diagramm
|
|
|
|
```
|
|
┌─────────────────┐ ┌─────────────────────┐
|
|
│ Mandate │────<│ BillingSettings │
|
|
│ │ 1:1│ │
|
|
│ id │ │ mandateId │
|
|
│ name │ │ billingModel │
|
|
└────────┬────────┘ │ billingAddress │
|
|
│ └─────────────────────┘
|
|
│
|
|
│ 1:n
|
|
▼
|
|
┌─────────────────────┐ ┌─────────────────────┐
|
|
│ BillingAccount │────<│ BillingTransaction │
|
|
│ │ 1:n │ │
|
|
│ mandateId │ │ accountId │
|
|
│ userId (optional) │ │ amount (CHF) │
|
|
│ balance (CHF) │ │ transactionType │
|
|
│ accountType │ │ workflowId │
|
|
└─────────────────────┘ └─────────────────────┘
|
|
│
|
|
│ 1:n RBAC Resources
|
|
▼ ┌─────────────────────┐
|
|
┌─────────────────────┐ │ resource.aicore.* │
|
|
│ UsageStatistics │ │ │
|
|
│ │ │ .anthropic │
|
|
│ accountId │ │ .openai │
|
|
│ periodType │ │ .perplexity │
|
|
│ totalCostCHF │ │ .tavily │
|
|
│ costByProvider │ │ .internal │
|
|
└─────────────────────┘ └─────────────────────┘
|
|
```
|
|
|
|
### LLM-Provider als RBAC Resources
|
|
|
|
Die Steuerung, welche LLM-Provider ein Benutzer verwenden darf, erfolgt über das RBAC-System:
|
|
|
|
**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 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
|
|
|
|
---
|
|
|
|
## Backend-Integration
|
|
|
|
### 1. Billing Service
|
|
|
|
```python
|
|
# modules/services/serviceBilling/mainServiceBilling.py
|
|
|
|
class BillingService:
|
|
"""Zentrale Service-Klasse für Billing-Operationen"""
|
|
|
|
def __init__(self, currentUser: User, mandateId: str):
|
|
self.currentUser = currentUser
|
|
self.mandateId = mandateId
|
|
self._loadSettings()
|
|
|
|
def _loadSettings(self):
|
|
"""Lädt BillingSettings für den Mandanten"""
|
|
self.settings = getBillingSettings(self.mandateId)
|
|
|
|
def getAccount(self) -> BillingAccount:
|
|
"""Gibt das relevante Account zurück (Mandate oder User)"""
|
|
if self.settings.billingModel == 'PREPAY_USER':
|
|
return getOrCreateUserAccount(self.mandateId, self.currentUser.id)
|
|
else:
|
|
return getMandateAccount(self.mandateId)
|
|
|
|
def checkBalance(self, estimatedCost: float) -> BillingCheckResult:
|
|
"""Prüft ob genug Guthaben vorhanden ist"""
|
|
account = self.getAccount()
|
|
|
|
if self.settings.billingModel == 'UNLIMITED':
|
|
return BillingCheckResult(allowed=True)
|
|
|
|
if account.balance < estimatedCost:
|
|
if self.settings.blockOnZeroBalance:
|
|
return BillingCheckResult(
|
|
allowed=False,
|
|
reason='INSUFFICIENT_BALANCE',
|
|
currentBalance=account.balance,
|
|
requiredAmount=estimatedCost
|
|
)
|
|
|
|
return BillingCheckResult(allowed=True, currentBalance=account.balance)
|
|
|
|
def recordUsage(self, priceCHF: float, context: UsageContext) -> BillingTransaction:
|
|
"""Erfasst Nutzungskosten und erstellt Transaktion"""
|
|
account = self.getAccount()
|
|
|
|
transaction = BillingTransaction(
|
|
id=generateUuid(),
|
|
accountId=account.id,
|
|
transactionType='DEBIT',
|
|
amount=priceCHF,
|
|
description=f"AI Usage: {context.process}",
|
|
referenceType='WORKFLOW',
|
|
referenceId=context.workflowId,
|
|
workflowId=context.workflowId,
|
|
featureInstanceId=context.featureInstanceId,
|
|
aicoreProvider=context.provider
|
|
)
|
|
|
|
# Account-Balance aktualisieren (atomar in DB)
|
|
account.balance -= priceCHF
|
|
|
|
# Warnung prüfen
|
|
self._checkWarningThreshold(account)
|
|
|
|
# Statistiken aktualisieren
|
|
self._updateStatistics(transaction)
|
|
|
|
return transaction
|
|
|
|
def isProviderAllowed(self, provider: str) -> bool:
|
|
"""Prüft ob User Berechtigung für Provider hat via RBAC"""
|
|
resourceKey = f"resource.aicore.{provider}"
|
|
return self.rbacService.hasPermission(
|
|
user=self.currentUser,
|
|
mandateId=self.mandateId,
|
|
objectKey=resourceKey,
|
|
action='USE'
|
|
)
|
|
```
|
|
|
|
### 2. Integration in AICore
|
|
|
|
```python
|
|
# modules/aicore/aicoreModelSelector.py - Erweiterung
|
|
|
|
class ModelSelector:
|
|
|
|
def selectModel(
|
|
self,
|
|
operationType: str,
|
|
promptBytes: int,
|
|
processingMode: str = 'BASIC',
|
|
priority: str = 'BALANCED',
|
|
allowedProviders: Optional[List[str]] = None # NEU
|
|
) -> Optional[AiModel]:
|
|
"""
|
|
Wählt das beste Model basierend auf Kriterien.
|
|
NEU: Filtert nach erlaubten Providern.
|
|
"""
|
|
availableModels = self._getAvailableModels()
|
|
|
|
# NEU: Provider-Filter anwenden
|
|
if allowedProviders:
|
|
availableModels = [
|
|
m for m in availableModels
|
|
if m.connectorType in allowedProviders
|
|
]
|
|
|
|
# ... bestehende Selektionslogik ...
|
|
```
|
|
|
|
### 3. Integration in Workflow-Verarbeitung
|
|
|
|
```python
|
|
# modules/workflows/processing/workflowProcessor.py - Erweiterung
|
|
|
|
class WorkflowProcessor:
|
|
|
|
def __init__(self, ...):
|
|
# ... bestehende Initialisierung ...
|
|
|
|
# NEU: Billing Service initialisieren
|
|
self.billingService = BillingService(
|
|
currentUser=self.currentUser,
|
|
mandateId=self.mandateId
|
|
)
|
|
|
|
async def _processAiCall(self, ...):
|
|
"""Erweitert um Billing-Checks"""
|
|
|
|
# Provider-Check
|
|
if not self.billingService.isProviderAllowed(selectedModel.connectorType):
|
|
raise ProviderNotAllowedException(
|
|
f"Provider '{selectedModel.connectorType}' not allowed for this mandate"
|
|
)
|
|
|
|
# Balance-Check (mit Kostenschätzung)
|
|
estimatedCost = self._estimateCost(selectedModel, inputBytes)
|
|
balanceCheck = self.billingService.checkBalance(estimatedCost)
|
|
|
|
if not balanceCheck.allowed:
|
|
raise InsufficientBalanceException(
|
|
f"Insufficient balance. Current: {balanceCheck.currentBalance}, "
|
|
f"Required: {balanceCheck.requiredAmount}"
|
|
)
|
|
|
|
# AI-Aufruf durchführen
|
|
response = await self._callAi(...)
|
|
|
|
# NEU: Kosten erfassen
|
|
if response.priceCHF:
|
|
self.billingService.recordUsage(
|
|
priceCHF=response.priceCHF,
|
|
context=UsageContext(
|
|
workflowId=self.workflowId,
|
|
featureInstanceId=self.featureInstanceId,
|
|
provider=selectedModel.connectorType,
|
|
process=response.process
|
|
)
|
|
)
|
|
|
|
return response
|
|
```
|
|
|
|
### 4. Bootstrap: Root-Mandant Setup
|
|
|
|
```python
|
|
# modules/interfaces/interfaceBootstrap.py - Erweiterung
|
|
|
|
def _setupRootMandate():
|
|
"""Setup für Root-Mandant mit PREPAY_USER Modell"""
|
|
|
|
rootMandate = getOrCreateMandate(
|
|
name="ROOT",
|
|
description="System Root Mandate"
|
|
)
|
|
|
|
# Billing Settings für Root
|
|
billingSettings = BillingSettings(
|
|
id=generateUuid(),
|
|
mandateId=rootMandate.id,
|
|
billingModel='PREPAY_USER',
|
|
defaultUserCredit=10.0, # 10 CHF Startguthaben
|
|
warningThresholdPercent=20,
|
|
blockOnZeroBalance=True,
|
|
notifyOnWarning=True
|
|
)
|
|
|
|
saveBillingSettings(billingSettings)
|
|
|
|
# RBAC: LLM-Provider Berechtigungen für alle Rollen
|
|
_setupAicoreRbacPermissions(rootMandate.id)
|
|
|
|
|
|
def _setupAicoreRbacPermissions(mandateId: str):
|
|
"""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]
|
|
|
|
roles = ['sysadmin', 'admin', 'user']
|
|
|
|
for role in roles:
|
|
for provider in providers:
|
|
createAccessRule(
|
|
mandateId=mandateId,
|
|
roleLabel=role,
|
|
context='RESOURCE',
|
|
item=f'resource.aicore.{provider}',
|
|
use=True
|
|
)
|
|
|
|
|
|
def _setupNewUserInRoot(user: User):
|
|
"""Erstellt Billing-Account für neuen User im Root-Mandanten"""
|
|
|
|
rootMandate = getRootMandate()
|
|
settings = getBillingSettings(rootMandate.id)
|
|
|
|
# User-Account erstellen
|
|
account = BillingAccount(
|
|
id=generateUuid(),
|
|
mandateId=rootMandate.id,
|
|
userId=user.id,
|
|
accountType='USER',
|
|
balance=settings.defaultUserCredit, # 10 CHF
|
|
warningThreshold=settings.defaultUserCredit * 0.2, # 20%
|
|
enabled=True
|
|
)
|
|
|
|
# Initiale Gutschrift-Transaktion
|
|
transaction = BillingTransaction(
|
|
id=generateUuid(),
|
|
accountId=account.id,
|
|
transactionType='CREDIT',
|
|
amount=settings.defaultUserCredit,
|
|
description='Initial credit for new user registration',
|
|
referenceType='SYSTEM'
|
|
)
|
|
|
|
saveAccount(account)
|
|
saveTransaction(transaction)
|
|
```
|
|
|
|
---
|
|
|
|
## API-Endpoints
|
|
|
|
### Billing Management (Admin)
|
|
|
|
```
|
|
# Mandanten-Billing-Einstellungen
|
|
GET /api/admin/billing/mandates/{mandateId}/settings
|
|
PUT /api/admin/billing/mandates/{mandateId}/settings
|
|
POST /api/admin/billing/mandates/{mandateId}/credit # Guthaben aufladen
|
|
|
|
# Transaktionen einsehen
|
|
GET /api/admin/billing/mandates/{mandateId}/transactions
|
|
GET /api/admin/billing/mandates/{mandateId}/accounts
|
|
```
|
|
|
|
### User-Billing (Self-Service)
|
|
|
|
```
|
|
# Eigenes Guthaben
|
|
GET /api/billing/balance # Aktueller Stand pro Mandant
|
|
GET /api/billing/balance/{mandateId} # Stand für spezifischen Mandanten
|
|
|
|
# Eigene Transaktionen
|
|
GET /api/billing/transactions # Alle eigenen Transaktionen
|
|
GET /api/billing/transactions/{mandateId} # Transaktionen pro Mandant
|
|
|
|
# Statistiken
|
|
GET /api/billing/statistics # Aggregierte Stats
|
|
GET /api/billing/statistics/{mandateId} # Stats pro Mandant
|
|
GET /api/billing/statistics/{mandateId}/chart # Chart-Daten (Tag/Monat/Jahr)
|
|
```
|
|
|
|
### Provider-Konfiguration
|
|
|
|
```
|
|
# Erlaubte Provider für Workflows
|
|
GET /api/billing/providers # Alle verfügbaren Provider
|
|
GET /api/billing/providers/{mandateId} # Erlaubte Provider für Mandant
|
|
|
|
# Workflow-spezifische Provider-Einstellung
|
|
PUT /api/chat/playground/{workflowId}/providers # Provider für Workflow setzen
|
|
PUT /api/automations/{automationId}/providers # Provider für Automation setzen
|
|
```
|
|
|
|
### Response-Beispiele
|
|
|
|
```json
|
|
// GET /api/billing/balance
|
|
{
|
|
"balances": [
|
|
{
|
|
"mandateId": "root-mandate-id",
|
|
"mandateName": "ROOT",
|
|
"billingModel": "PREPAY_USER",
|
|
"balance": 6.50,
|
|
"currency": "CHF",
|
|
"warningThreshold": 2.00,
|
|
"isWarning": false
|
|
},
|
|
{
|
|
"mandateId": "soha-mandate-id",
|
|
"mandateName": "SOHA Treuhand AG",
|
|
"billingModel": "PREPAY_MANDATE",
|
|
"balance": 299.25,
|
|
"currency": "CHF",
|
|
"warningThreshold": 50.00,
|
|
"isWarning": false
|
|
}
|
|
]
|
|
}
|
|
|
|
// GET /api/billing/statistics/root-mandate-id/chart?period=month&year=2026
|
|
{
|
|
"mandateId": "root-mandate-id",
|
|
"period": "month",
|
|
"year": 2026,
|
|
"currency": "CHF",
|
|
"data": [
|
|
{"label": "Jan", "totalCost": 12.50, "byProvider": {"anthropic": 10.00, "openai": 2.50}},
|
|
{"label": "Feb", "totalCost": 8.30, "byProvider": {"anthropic": 8.30}},
|
|
// ...
|
|
],
|
|
"totals": {
|
|
"totalCost": 45.80,
|
|
"byProvider": {"anthropic": 38.30, "openai": 7.50}
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## UI-Seiten
|
|
|
|
**Billing wird als separater Navigation-Container gerendert:**
|
|
|
|
```
|
|
Static Block: BILLING
|
|
├── page.billing.dashboard → /billing
|
|
├── page.billing.transactions → /billing/transactions
|
|
├── page.billing.statistics → /billing/statistics/{mandateId}
|
|
└── page.billing.admin → /billing/admin (nur SysAdmin)
|
|
```
|
|
|
|
### 1. Billing Dashboard (User)
|
|
|
|
**Pfad:** `/billing`
|
|
|
|
**Funktionen:**
|
|
- Übersicht aller Mandanten mit Guthaben
|
|
- Restbudget für ROOT-Mandant prominent anzeigen
|
|
- Quick-Stats: Ausgaben heute/diese Woche/diesen Monat
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────┐
|
|
│ MEIN GUTHABEN │
|
|
├─────────────────────────────────────────────────────────┤
|
|
│ ┌──────────────────┐ ┌──────────────────────────────┐ │
|
|
│ │ ROOT │ │ Chart: Ausgaben pro Tag │ │
|
|
│ │ ────────────────│ │ ┌─┐ ┌─┐ ┌─┐ │ │
|
|
│ │ CHF 6.50 │ │ │█│ │█│ ┌─┐ │█│ ┌─┐ │ │
|
|
│ │ [████████░░] 65% │ │ │█│ │█│ │█│ │█│ │█│ ┌─┐ │ │
|
|
│ │ │ │ Mo Di Mi Do Fr Sa So │ │
|
|
│ │ Warnschwelle: 2 │ └──────────────────────────────┘ │
|
|
│ └──────────────────┘ │
|
|
│ │
|
|
│ MANDANTEN-ÜBERSICHT │
|
|
│ ┌──────────────────────────────────────────────────┐ │
|
|
│ │ SOHA Treuhand AG CHF 299.25 ████████████░░ │ │
|
|
│ │ Partner AG CHF 150.00 ██████████░░░░ │ │
|
|
│ └──────────────────────────────────────────────────┘ │
|
|
└─────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### 2. Detailansicht pro Mandant
|
|
|
|
**Pfad:** `/billing/statistics/{mandateId}`
|
|
|
|
**Funktionen:**
|
|
- Detaillierte Kostengrafik (Tag/Monat/Jahr umschaltbar)
|
|
- Aufschlüsselung nach Provider
|
|
- Aufschlüsselung nach Feature
|
|
- Transaktionshistorie
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────┐
|
|
│ SOHA Treuhand AG - Kostenübersicht │
|
|
├─────────────────────────────────────────────────────────┤
|
|
│ Zeitraum: [Tag ▼] [Monat] [Jahr] Feb 2026 │
|
|
│ │
|
|
│ ┌─────────────────────────────────────────────────┐ │
|
|
│ │ [Bar-Chart: Kosten pro Tag im Februar] │ │
|
|
│ │ 25 ─┬─ (CHF) │ │
|
|
│ │ │ ██ │ │
|
|
│ │ 20 ─┤ ██ ██ │ │
|
|
│ │ │ ██ ██ ██ ██ │ │
|
|
│ │ 10 ─┤ ██ ██ ██ ██ ██ ██ │ │
|
|
│ │ │──██──██───██───██───██──██─────────────│ │
|
|
│ │ 1 5 10 15 20 25 │ │
|
|
│ └─────────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ AUFSCHLÜSSELUNG │
|
|
│ ┌────────────────┐ ┌────────────────┐ │
|
|
│ │ Nach Provider │ │ Nach Feature │ │
|
|
│ │ Anthropic 70% │ │ Playground 60% │ │
|
|
│ │ OpenAI 25% │ │ Automation 30% │ │
|
|
│ │ Internal 5% │ │ Chatbot 10% │ │
|
|
│ └────────────────┘ └────────────────┘ │
|
|
│ │
|
|
│ LETZTE TRANSAKTIONEN │
|
|
│ ┌──────────────────────────────────────────────────┐ │
|
|
│ │ 04.02.2026 14:32 AI Usage: Document Analysis │ │
|
|
│ │ anthropic -CHF 0.15 │ │
|
|
│ │ 04.02.2026 14:28 AI Usage: Chat Response │ │
|
|
│ │ anthropic -CHF 0.08 │ │
|
|
│ │ ... │ │
|
|
│ └──────────────────────────────────────────────────┘ │
|
|
└─────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### 3. Provider-Auswahl im Chat Playground
|
|
|
|
**Integration in:** `/workflows/playground`
|
|
|
|
**Funktionen:**
|
|
- 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
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────┐
|
|
│ Chat Playground │
|
|
├─────────────────────────────────────────────────────────┤
|
|
│ ┌─────────────────────────────────────────────────┐ │
|
|
│ │ EINSTELLUNGEN │ │
|
|
│ │ │ │
|
|
│ │ AI-Provider für nächsten Call: │ │
|
|
│ │ ○ Anthropic (Claude) ~CHF 0.020/1k tokens │ │
|
|
│ │ ● OpenAI (GPT-4) ~CHF 0.015/1k tokens │ │
|
|
│ │ ○ Perplexity (Web) ~CHF 0.008/1k tokens │ │
|
|
│ │ ○ Internal (Document) ~CHF 0.002/1k tokens │ │
|
|
│ │ │ │
|
|
│ │ Geschätzte Kosten: ~CHF 0.02 pro Nachricht │ │
|
|
│ └─────────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ [Chat-Interface...] │
|
|
└─────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### 4. Automation Editor (Modal mit Tabs)
|
|
|
|
**Integration in:** `/automations/{id}/edit`
|
|
|
|
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 (dynamisch aus AICore-Plugins, gefiltert nach RBAC)
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────┐
|
|
│ Automation bearbeiten: "Täglicher Report" │
|
|
├─────────────────────────────────────────────────────────┤
|
|
│ [General] [Modellierung] [LLM Modelle] │
|
|
│ ───────────────────────────────────────────────────── │
|
|
│ TAB: LLM Modelle │
|
|
│ │
|
|
│ 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 │
|
|
│ ○ Internal (Document) CHF 0.002/1k tokens │
|
|
│ │
|
|
│ Geschätzte Kosten pro Ausführung: ~CHF 0.05 │
|
|
│ Bei täglicher Ausführung: ~CHF 1.50/Monat │
|
|
│ │
|
|
│ [Speichern] [Abbrechen] │
|
|
└─────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### 5. Admin: Billing-Verwaltung (nur SysAdmin)
|
|
|
|
**Pfad:** `/billing/admin`
|
|
|
|
**Funktionen:**
|
|
- Übersicht aller Mandanten mit Billing-Status
|
|
- Abrechnungsmodell ändern
|
|
- Guthaben manuell aufladen (Stripe-Vorbereitung für Zukunft)
|
|
- Rechnungsadresse verwalten (für CREDIT_POSTPAY)
|
|
- Email-Empfänger verwalten
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────┐
|
|
│ BILLING ADMINISTRATION │
|
|
├─────────────────────────────────────────────────────────┤
|
|
│ MANDANTEN │
|
|
│ ┌──────────────────────────────────────────────────┐ │
|
|
│ │ Mandant Modell Balance Status │ │
|
|
│ │ ──────────────────────────────────────────────── │ │
|
|
│ │ ROOT PREPAY_USER n/a ✓ │ │
|
|
│ │ SOHA Treuhand PREPAY_MANDATE CHF 299 ✓ │ │
|
|
│ │ Enterprise AG CREDIT_POSTPAY CHF -450 ✓ │ │
|
|
│ │ Test GmbH PREPAY_MANDATE CHF 5 ⚠ │ │
|
|
│ └──────────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ [+ Neuer Mandant] [Export Monatsreport] │
|
|
│ │
|
|
│ MANDANT BEARBEITEN: SOHA Treuhand AG │
|
|
│ ┌──────────────────────────────────────────────────┐ │
|
|
│ │ Abrechnungsmodell: [PREPAY_MANDATE ▼] │ │
|
|
│ │ │ │
|
|
│ │ Warnschwelle: [10] % │ │
|
|
│ │ Blockieren bei 0: [✓] │ │
|
|
│ │ │ │
|
|
│ │ Rechnungsadresse (für CREDIT_POSTPAY): │ │
|
|
│ │ [Firma: ________________] [Strasse: _________] │ │
|
|
│ │ [PLZ: ____] [Ort: _______] [MwSt-Nr: ________] │ │
|
|
│ │ │ │
|
|
│ │ Benachrichtigungs-Emails: │ │
|
|
│ │ [admin@soha.ch, billing@soha.ch ] │ │
|
|
│ │ │ │
|
|
│ │ [Speichern] [Guthaben aufladen] │ │
|
|
│ └──────────────────────────────────────────────────┘ │
|
|
└─────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
**Hinweis:** Provider-Berechtigungen werden über das RBAC-System verwaltet (Administration → Rollen).
|
|
|
|
---
|
|
|
|
## Email-Reports
|
|
|
|
### Monatsende-Report
|
|
|
|
**Trigger:** Automatisch am 1. jeden Monats (Cronjob)
|
|
|
|
**Empfänger:** `BillingSettings.notifyEmails` pro Mandant
|
|
|
|
**Template:**
|
|
|
|
```
|
|
Betreff: PowerOn Kostenreport Januar 2026 - SOHA Treuhand AG
|
|
|
|
Sehr geehrte Damen und Herren,
|
|
|
|
anbei erhalten Sie den monatlichen Kostenreport für Ihren Mandanten
|
|
"SOHA Treuhand AG" für den Zeitraum Januar 2026.
|
|
|
|
ZUSAMMENFASSUNG
|
|
───────────────────────────────────────────────────────
|
|
Gesamtkosten: CHF 156.80
|
|
Anzahl AI-Operationen: 423
|
|
Durchschnitt pro Operation: CHF 0.37
|
|
|
|
AUFSCHLÜSSELUNG NACH PROVIDER
|
|
───────────────────────────────────────────────────────
|
|
Anthropic (Claude) CHF 112.50 (72%)
|
|
OpenAI (GPT-4) CHF 38.30 (24%)
|
|
Internal CHF 6.00 (4%)
|
|
|
|
AUFSCHLÜSSELUNG NACH FEATURE
|
|
───────────────────────────────────────────────────────
|
|
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 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: CHF 456.05
|
|
Verbrauch: -CHF 156.80
|
|
───────────────────────────────────────────────────────
|
|
Aktueller Stand: CHF 299.25
|
|
|
|
Bei Fragen stehen wir Ihnen gerne zur Verfügung.
|
|
|
|
Freundliche Grüsse
|
|
PowerOn Platform
|
|
```
|
|
|
|
### Warnung bei niedriger Balance
|
|
|
|
**Trigger:** Balance unterschreitet `warningThreshold`
|
|
|
|
**Empfänger:** `BillingSettings.notifyEmails`
|
|
|
|
```
|
|
Betreff: ⚠️ PowerOn - Niedriges Guthaben für SOHA Treuhand AG
|
|
|
|
Ihr Guthaben für den Mandanten "SOHA Treuhand AG" hat die
|
|
Warnschwelle unterschritten.
|
|
|
|
Aktuelles Guthaben: CHF 45.00
|
|
Warnschwelle: CHF 50.00 (10%)
|
|
|
|
Bitte laden Sie Ihr Guthaben auf, um Unterbrechungen zu vermeiden.
|
|
|
|
[Guthaben aufladen →]
|
|
|
|
Freundliche Grüsse
|
|
PowerOn Platform
|
|
```
|
|
|
|
---
|
|
|
|
## Implementierungsschritte
|
|
|
|
### Phase 1: Datenmodell & Grundstruktur
|
|
|
|
1. **Neue Billing-Datenbank erstellen** (`poweron_billing`)
|
|
- `BillingAccount`, `BillingTransaction`, `BillingSettings`, `UsageStatistics` Tabellen
|
|
- Migration für bestehende Mandanten (Default: `UNLIMITED`)
|
|
|
|
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 mit mandateId aus Request-Context
|
|
- Provider-Validierung über RBAC
|
|
|
|
### Phase 2: Integration in Workflows
|
|
|
|
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 (BillingAccount des Mandanten)
|
|
- Nach jedem AI-Call: Kosten als BillingTransaction erfassen
|
|
|
|
3. **Error Handling**
|
|
- `InsufficientBalanceException`
|
|
- `ProviderNotAllowedException`
|
|
- User-freundliche Fehlermeldungen
|
|
|
|
### Phase 3: API-Endpoints
|
|
|
|
1. **User-Billing APIs**
|
|
- Balance-Abfrage
|
|
- Transaktions-Historie
|
|
- Statistiken mit Chart-Daten
|
|
|
|
2. **Admin-Billing APIs**
|
|
- Settings verwalten
|
|
- Guthaben aufladen
|
|
- Report-Export
|
|
|
|
### Phase 4: UI-Integration
|
|
|
|
1. **Billing Dashboard**
|
|
- Neue Seite: `/billing`
|
|
- Chart-Komponenten für Statistiken
|
|
|
|
2. **Provider-Auswahl**
|
|
- Chat Playground erweitern
|
|
- Automation-Editor erweitern
|
|
|
|
3. **Admin-Seiten**
|
|
- Billing-Verwaltung
|
|
- Mandanten-Konfiguration
|
|
|
|
### Phase 5: Bootstrap & Migration
|
|
|
|
1. **Root-Mandant Setup**
|
|
- `PREPAY_USER` Modell
|
|
- 10 CHF Startguthaben für neue User
|
|
- RBAC-Berechtigungen für alle LLM-Provider
|
|
|
|
2. **Bestehende User migrieren**
|
|
- Accounts erstellen
|
|
- Initiales Guthaben gutschreiben
|
|
|
|
3. **Bestehende Mandanten migrieren**
|
|
- Default-Settings erstellen
|
|
- `UNLIMITED` oder `PREPAY_MANDATE`
|
|
- RBAC-Berechtigungen für LLM-Provider erstellen
|
|
|
|
### Phase 6: Email-Reports
|
|
|
|
1. **Email-Templates erstellen**
|
|
- Monatsreport
|
|
- Balance-Warnung
|
|
|
|
2. **Scheduler einrichten**
|
|
- Monatsende-Cronjob
|
|
- Warnschwellen-Check
|
|
|
|
3. **Email-Service integrieren**
|
|
- Template-Rendering
|
|
- Email-Versand
|
|
|
|
---
|
|
|
|
## Entscheidungen
|
|
|
|
### 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.
|
|
|
|
2. **Welche Services laufen noch nicht über Mandanten?**
|
|
→ `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.
|
|
|
|
4. **Provider-Steuerung**
|
|
→ Über RBAC-System als Resources (`resource.aicore.*`), NICHT als Datenbank-Attribute.
|
|
|
|
### Geschäftsentscheidungen
|
|
|
|
1. **Payment-Integration**
|
|
→ Stripe-Anbindung wird vorbereitet (zukünftig)
|
|
→ Aktuell: SysAdmin-Seite für manuelle Guthaben-Aufladung
|
|
|
|
2. **Preisgestaltung**
|
|
→ **50% Aufschlag** auf Provider-Kosten, direkt in AICore-Modellen definiert
|
|
→ Preise werden in CHF kalkuliert und gespeichert
|
|
|
|
3. **Währung**
|
|
→ **Alles in CHF**, keine Währungsumrechnung im System
|
|
→ Provider-Kosten werden intern auf CHF umgerechnet und mit 50% Aufschlag versehen
|
|
|
|
4. **Datenhaltung**
|
|
→ **10 Jahre** Aufbewahrungspflicht für Transaktionen
|
|
→ Automatische Archivierung/Löschung nach 10 Jahren
|
|
|
|
5. **GDPR/Datenschutz**
|
|
→ 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.
|
|
|
|
---
|
|
|
|
## Glossar
|
|
|
|
| Begriff | Beschreibung |
|
|
|---------|--------------|
|
|
| **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 CHF (inkl. 50% Aufschlag) |
|
|
| **RBAC Resource** | Berechtigungs-Objekt für Provider-Zugriff (z.B. `resource.aicore.anthropic`) |
|
|
|
|
---
|
|
|
|
## Anhang: Wichtige Dateien
|
|
|
|
### Bestehend (zu erweitern)
|
|
|
|
```
|
|
gateway/modules/
|
|
├── aicore/
|
|
│ ├── aicoreModelSelector.py # Provider-Filter via RBAC
|
|
│ ├── aicorePluginAnthropic.py # Preise auf CHF mit 50% Aufschlag anpassen
|
|
│ ├── aicorePluginOpenai.py # Preise auf CHF mit 50% Aufschlag anpassen
|
|
│ ├── aicorePluginPerplexity.py # Preise auf CHF mit 50% Aufschlag anpassen
|
|
│ ├── aicorePluginTavily.py # Preise auf CHF mit 50% Aufschlag anpassen
|
|
│ └── aicoreBase.py # connectorType für Billing
|
|
├── datamodels/
|
|
│ └── datamodelUam.py # Mandate-Referenz (keine Änderung an Chat-Modellen!)
|
|
├── interfaces/
|
|
│ ├── interfaceBootstrap.py # Root-Mandant Billing Setup + RBAC für Provider
|
|
│ └── interfaceRbac.py # Resource-Berechtigungen für Provider
|
|
├── workflows/
|
|
│ └── processing/workflowProcessor.py # Balance-Checks + RBAC Provider-Check + BillingTransaction
|
|
└── features/
|
|
├── chatplayground/ # Billing-Integration (mandateId aus Context)
|
|
└── automation/ # Billing-Integration (mandateId bereits vorhanden)
|
|
```
|
|
|
|
### Neu zu erstellen
|
|
|
|
```
|
|
gateway/modules/
|
|
├── datamodels/
|
|
│ └── datamodelBilling.py # Neue Billing-Modelle
|
|
├── interfaces/
|
|
│ └── interfaceDbBilling.py # Billing CRUD-Operationen (poweron_billing DB)
|
|
├── services/
|
|
│ └── serviceBilling/
|
|
│ ├── mainServiceBilling.py # Zentrale Billing-Logik
|
|
│ └── subBillingReports.py # Report-Generierung
|
|
└── routes/
|
|
└── routeBilling.py # Billing API-Endpoints
|
|
|
|
frontend_nyla/src/
|
|
├── pages/
|
|
│ └── billing/ # Billing UI-Seiten
|
|
└── components/
|
|
└── billing/ # Billing-Komponenten (Charts, etc.)
|
|
```
|
|
|
|
---
|
|
|
|
## Implementierungs-Checkliste
|
|
|
|
### Vor der Implementierung zu klären
|
|
|
|
- [ ] **AICore Preise:** Aktuelle Preise sind in USD definiert. Müssen auf CHF umgestellt werden mit 50% Aufschlag.
|
|
- [ ] **Datenbank:** Neue `poweron_billing` Datenbank oder in `poweron_app` integrieren?
|
|
- [ ] **Email-Service:** Welcher Email-Provider wird für Billing-Benachrichtigungen verwendet?
|
|
|
|
### Phase 1: Backend Grundstruktur
|
|
|
|
- [ ] `datamodelBilling.py` erstellen (BillingAccount, BillingTransaction, BillingSettings, UsageStatistics, BillingAddress)
|
|
- [ ] `interfaceDbBilling.py` erstellen (CRUD-Operationen)
|
|
- [ ] Datenbank-Migrations-Script erstellen
|
|
- [ ] AICore-Plugins: Preise von USD auf CHF umstellen (`calculatepriceCHF` mit echten CHF-Werten)
|
|
|
|
### Phase 2: Service-Layer
|
|
|
|
- [ ] `mainServiceBilling.py` implementieren (Balance-Check, Transaction-Recording, Provider-Check via RBAC)
|
|
- [ ] RBAC-Integration: `resource.aicore.*` Resources registrieren
|
|
- [ ] Bootstrap: Billing-Settings für ROOT-Mandant, RBAC-Berechtigungen für Provider
|
|
|
|
### Phase 3: Workflow-Integration
|
|
|
|
- [ ] `workflowProcessor.py`: BillingService integrieren
|
|
- [ ] Vor AI-Call: Balance prüfen, Provider-Berechtigung prüfen
|
|
- [ ] Nach AI-Call: BillingTransaction erstellen (mit mandateId aus Request-Context)
|
|
- [ ] Exception-Handling: InsufficientBalanceException, ProviderNotAllowedException
|
|
|
|
### Phase 4: API-Endpoints
|
|
|
|
- [ ] `routeBilling.py` erstellen
|
|
- [ ] User-Endpoints: Balance, Transactions, Statistics
|
|
- [ ] Admin-Endpoints: Settings, Credit-Aufladung, Mandanten-Übersicht
|
|
|
|
### Phase 5: Frontend (Nyla)
|
|
|
|
- [ ] Billing-Container in Navigation integrieren
|
|
- [ ] Dashboard-Seite: Guthaben-Übersicht, Charts
|
|
- [ ] Transaktions-Seite: Historie mit Filterung
|
|
- [ ] Admin-Seite: Mandanten-Verwaltung, Guthaben-Aufladung
|
|
- [ ] Chat Playground: Provider-Auswahl UI
|
|
- [ ] Automation Editor: Tab "LLM Modelle"
|
|
|
|
### Phase 6: Reports & Notifications
|
|
|
|
- [ ] Email-Templates erstellen (Monatsreport, Balance-Warnung)
|
|
- [ ] Scheduler für Monatsreport (1. jeden Monats)
|
|
- [ ] Balance-Warnung bei Unterschreitung der Schwelle
|
|
|
|
### Qualitätssicherung
|
|
|
|
- [ ] Unit-Tests für BillingService
|
|
- [ ] Integration-Tests für Workflow mit Billing
|
|
- [ ] E2E-Tests für Billing-UI
|
|
- [ ] Datenmigration für bestehende Mandanten testen
|