wiki/concepts/Billing-Konzept.md
2026-02-04 10:13:46 +01:00

41 KiB

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 erlaubt sind
  • Zuordnung auf Level AICore-Connector: anthropic, openai, perplexity, tavily, internal
  • 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

# 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}

Erweiterung bestehender Modelle

# Erweiterung: ChatWorkflow (datamodelChat.py)
class ChatWorkflow(BaseModel):
    # ... bestehende Felder ...
    
    # NEU: Mandanten-Kontext für Billing
    mandateId: Optional[str]            # FK → Mandate

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:

Registrierte Resources:

  • resource.aicore.anthropic
  • resource.aicore.openai
  • resource.aicore.perplexity
  • resource.aicore.tavily
  • resource.aicore.internal

Bootstrap-Berechtigungen (Mandate ROOT):

  • SysAdmin: Alle Provider (USE)
  • Admin: Alle Provider (USE)
  • User: Alle 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

Backend-Integration

1. Billing Service

# 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

# 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

# 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

# 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"""
    
    providers = ['anthropic', 'openai', 'perplexity', 'tavily', 'internal']
    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

// 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:

  • Dropdown/Checkboxen für erlaubte Provider
  • Zeigt nur Provider an, für die der User RBAC-Berechtigung hat
  • Auswahl gilt für den nächsten AI-Call
┌─────────────────────────────────────────────────────────┐
│  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 basierend auf RBAC-Berechtigungen
┌─────────────────────────────────────────────────────────┐
│  Automation bearbeiten: "Täglicher Report"              │
├─────────────────────────────────────────────────────────┤
│  [General] [Modellierung] [LLM Modelle]                 │
│  ─────────────────────────────────────────────────────  │
│  TAB: LLM Modelle                                       │
│                                                         │
│  Verfügbare Provider (basierend auf Ihren Berechtigungen):
│  ○ 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:                          $ 156.80 USD
Anzahl AI-Operationen:                 423
Durchschnitt pro Operation:            $ 0.37 USD

AUFSCHLÜSSELUNG NACH PROVIDER
───────────────────────────────────────────────────────
Anthropic (Claude)                     $ 112.50 USD (72%)
OpenAI (GPT-4)                         $  38.30 USD (24%)
Internal                               $   6.00 USD (4%)

AUFSCHLÜSSELUNG NACH FEATURE
───────────────────────────────────────────────────────
Chat Playground                        $  95.00 USD (61%)
Automation                             $  45.80 USD (29%)
Chatbot (Feature)                      $  16.00 USD (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

KONTOSTAND
───────────────────────────────────────────────────────
Vorheriger Stand:                      $ 456.05 USD
Verbrauch:                            -$ 156.80 USD
───────────────────────────────────────────────────────
Aktueller Stand:                       $ 299.25 USD

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:    $ 45.00 USD
Warnschwelle:          $ 50.00 USD (10%)

Bitte laden Sie Ihr Guthaben auf, um Unterbrechungen zu vermeiden.

[Guthaben aufladen →]

Freundliche Grüsse
PowerOn Platform

Implementierungsschritte

Phase 1: Datenmodell & Grundstruktur

  1. Datenbank-Schema erstellen

    • 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
  3. BillingService implementieren

    • Balance-Prüfung
    • Transaktions-Erfassung
    • Provider-Validierung

Phase 2: Integration in Workflows

  1. ChatWorkflow erweitern

    • mandateId bei Start speichern
    • Provider-Filter bei Model-Selection
  2. Billing-Checks einbauen

    • Vor jedem AI-Call: Balance prüfen
    • Nach jedem AI-Call: Kosten 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 USD Startguthaben für neue User
  2. Bestehende User migrieren

    • Accounts erstellen
    • Initiales Guthaben gutschreiben
  3. Bestehende Mandanten migrieren

    • Default-Settings erstellen
    • UNLIMITED oder PREPAY_MANDATE

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

Offene Fragen und Entscheidungen

Beantwortet

  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. Erweiterung nur um allowedProviders.

Noch zu klären

  1. Payment-Integration

    • Wie laden Kunden Guthaben auf? (Stripe, Rechnung, manuell)
    • Self-Service oder nur Admin?
  2. Preisgestaltung

    • Aufschlag auf Provider-Kosten? (z.B. +20%)
    • Fixkosten pro Mandant/User?
  3. Währung

    • Nur USD intern, Anzeige in CHF/EUR?
    • Wechselkurs-Handling?
  4. Datenhaltung

    • Wie lange Transaktions-Historie aufbewahren?
    • Archivierung alter Daten?
  5. GDPR/Datenschutz

    • User-Löschung: Was passiert mit Billing-Daten?
    • Anonymisierung nach X Jahren?

Glossar

Begriff Beschreibung
AICore Plugin-System für LLM-Provider Integration
Billing Account Konto für Guthaben/Saldo (pro Mandant oder User)
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

Anhang: Wichtige Dateien

Bestehend (zu erweitern)

gateway/modules/
├── aicore/
│   ├── aicoreModelSelector.py      # Provider-Filter hinzufügen
│   └── aicoreBase.py               # connectorType für Billing
├── datamodels/
│   ├── datamodelChat.py            # ChatWorkflow erweitern
│   └── datamodelUam.py             # Mandate-Referenz
├── features/automation/
│   └── datamodelFeatureAutomation.py  # allowedProviders hinzufügen
├── interfaces/
│   └── interfaceBootstrap.py       # Root-Mandant Billing Setup
├── workflows/
│   ├── automation/mainWorkflow.py  # Billing-Integration
│   └── processing/workflowProcessor.py  # Balance-Checks
└── routes/
    └── routeChat.py                # mandateId im Workflow speichern

Neu zu erstellen

gateway/modules/
├── datamodels/
│   └── datamodelBilling.py         # Neue Billing-Modelle
├── interfaces/
│   └── interfaceDbBilling.py       # Billing CRUD-Operationen
├── services/
│   └── serviceBilling/
│       ├── mainServiceBilling.py   # Zentrale Billing-Logik
│       └── subBillingReports.py    # Report-Generierung
└── routes/
    └── routeBilling.py             # Billing API-Endpoints