Docker Compose with 24+ services: - PostgreSQL (PostGIS), Valkey, MinIO, Qdrant - Vault (PKI/TLS), Nginx (Reverse Proxy) - Backend Core API, Consent Service, Billing Service - RAG Service, Embedding Service - Gitea, Woodpecker CI/CD - Night Scheduler, Health Aggregator - Jitsi (Web/XMPP/JVB/Jicofo), Mailpit Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
7.6 KiB
7.6 KiB
Billing Service
Go-Microservice fuer Stripe-basiertes Subscription Management mit Task-basierter Abrechnung.
Uebersicht
Der Billing Service verwaltet:
- Subscription Lifecycle (Trial, Active, Canceled)
- Task-basierte Kontingentierung (1 Task = 1 Einheit)
- Carryover-Logik (Tasks sammeln sich bis zu 5 Monate an)
- Stripe Integration (Checkout, Webhooks, Portal)
- Feature Gating und Entitlements
Quick Start
Voraussetzungen
- Go 1.21+
- PostgreSQL 14+
- Docker (optional)
Lokale Entwicklung
# 1. Dependencies installieren
go mod download
# 2. Umgebungsvariablen setzen
export DATABASE_URL="postgres://user:pass@localhost:5432/breakpilot?sslmode=disable"
export JWT_SECRET="your-jwt-secret"
export STRIPE_SECRET_KEY="sk_test_..."
export STRIPE_WEBHOOK_SECRET="whsec_..."
export BILLING_SUCCESS_URL="http://localhost:3000/billing/success"
export BILLING_CANCEL_URL="http://localhost:3000/billing/cancel"
export INTERNAL_API_KEY="internal-api-key"
export TRIAL_PERIOD_DAYS="7"
export PORT="8083"
# 3. Service starten
go run cmd/server/main.go
# 4. Tests ausfuehren
go test -v ./...
Mit Docker
# Service bauen und starten
docker compose up billing-service
# Nur bauen
docker build -t billing-service .
Architektur
billing-service/
├── cmd/server/main.go # Entry Point
├── internal/
│ ├── config/config.go # Konfiguration
│ ├── database/database.go # DB Connection + Migrations
│ ├── models/models.go # Datenmodelle
│ ├── middleware/middleware.go # JWT Auth, CORS, Rate Limiting
│ ├── services/
│ │ ├── subscription_service.go # Subscription Management
│ │ ├── task_service.go # Task Consumption
│ │ ├── entitlement_service.go # Feature Gating
│ │ ├── usage_service.go # Usage Tracking (Legacy)
│ │ └── stripe_service.go # Stripe API
│ └── handlers/
│ ├── billing_handlers.go # API Endpoints
│ └── webhook_handlers.go # Stripe Webhooks
├── Dockerfile
└── go.mod
Task-basiertes Billing
Konzept
- 1 Task = 1 Kontingentverbrauch (unabhaengig von Seitenanzahl, Tokens, etc.)
- Monatliches Kontingent: Plan-abhaengig (Basic: 30, Standard: 100, Premium: Fair Use)
- Carryover: Ungenutzte Tasks sammeln sich bis zu 5 Monate an
- Max Balance:
monthly_allowance * 5(z.B. Basic: max 150 Tasks)
Task Types
TaskTypeCorrection = "correction" // Korrekturaufgabe
TaskTypeLetter = "letter" // Brief erstellen
TaskTypeMeeting = "meeting" // Meeting-Protokoll
TaskTypeBatch = "batch" // Batch-Verarbeitung
TaskTypeOther = "other" // Sonstige
Monatswechsel-Logik
Bei jedem API-Aufruf wird geprueft, ob ein Monat vergangen ist:
last_renewal_atpruefen- Falls >= 1 Monat:
task_balance += monthly_allowance - Cap bei
max_task_balance last_renewal_ataktualisieren
API Endpoints
User Endpoints (JWT Auth)
| Methode | Endpoint | Beschreibung |
|---|---|---|
| GET | /api/v1/billing/status |
Aktueller Billing Status |
| GET | /api/v1/billing/plans |
Verfuegbare Plaene |
| POST | /api/v1/billing/trial/start |
Trial starten |
| POST | /api/v1/billing/change-plan |
Plan wechseln |
| POST | /api/v1/billing/cancel |
Abo kuendigen |
| GET | /api/v1/billing/portal |
Stripe Portal URL |
Internal Endpoints (API Key)
| Methode | Endpoint | Beschreibung |
|---|---|---|
| GET | /api/v1/billing/entitlements/:userId |
Entitlements abrufen |
| GET | /api/v1/billing/entitlements/check/:userId/:feature |
Feature pruefen |
| GET | /api/v1/billing/tasks/check/:userId |
Task erlaubt? |
| POST | /api/v1/billing/tasks/consume |
Task konsumieren |
| GET | /api/v1/billing/tasks/usage/:userId |
Task Usage Info |
Webhook
| Methode | Endpoint | Beschreibung |
|---|---|---|
| POST | /api/v1/billing/webhook |
Stripe Webhooks |
Plaene und Preise
| Plan | Preis | Tasks/Monat | Max Balance | Features |
|---|---|---|---|---|
| Basic | 9.90 EUR | 30 | 150 | Basis-Features |
| Standard | 19.90 EUR | 100 | 500 | + Templates, Batch |
| Premium | 39.90 EUR | Fair Use | 5000 | + Team, Admin, API |
Fair Use Mode (Premium)
Im Premium-Plan:
- Keine praktische Begrenzung
- Tasks werden trotzdem getrackt (fuer Monitoring)
- Balance wird nicht dekrementiert
CheckTaskAllowedgibt immertruezurueck
Datenbank
Wichtige Tabellen
-- Task-basierte Nutzung pro Account
CREATE TABLE account_usage (
account_id UUID UNIQUE,
plan VARCHAR(50),
monthly_task_allowance INT,
max_task_balance INT,
task_balance INT,
last_renewal_at TIMESTAMPTZ
);
-- Einzelne Task-Records
CREATE TABLE tasks (
id UUID PRIMARY KEY,
account_id UUID,
task_type VARCHAR(50),
consumed BOOLEAN,
created_at TIMESTAMPTZ
);
Tests
# Alle Tests
go test -v ./...
# Mit Coverage
go test -cover ./...
# Nur Models
go test -v ./internal/models/...
# Nur Services
go test -v ./internal/services/...
# Nur Handlers
go test -v ./internal/handlers/...
Stripe Integration
Webhooks
Konfiguriere im Stripe Dashboard:
URL: https://your-domain.com/api/v1/billing/webhook
Events:
- checkout.session.completed
- customer.subscription.created
- customer.subscription.updated
- customer.subscription.deleted
- invoice.paid
- invoice.payment_failed
Lokales Testing
# Stripe CLI installieren
brew install stripe/stripe-cli/stripe
# Webhook forwarding
stripe listen --forward-to localhost:8083/api/v1/billing/webhook
# Test Events triggern
stripe trigger checkout.session.completed
stripe trigger invoice.paid
Umgebungsvariablen
| Variable | Beschreibung | Beispiel |
|---|---|---|
DATABASE_URL |
PostgreSQL Connection String | postgres://... |
JWT_SECRET |
JWT Signing Secret | your-secret |
STRIPE_SECRET_KEY |
Stripe Secret Key | sk_test_... |
STRIPE_WEBHOOK_SECRET |
Webhook Signing Secret | whsec_... |
BILLING_SUCCESS_URL |
Checkout Success Redirect | http://... |
BILLING_CANCEL_URL |
Checkout Cancel Redirect | http://... |
INTERNAL_API_KEY |
Service-to-Service Auth | internal-key |
TRIAL_PERIOD_DAYS |
Trial Dauer in Tagen | 7 |
PORT |
Server Port | 8083 |
Error Handling
Task Limit Reached
{
"error": "TASK_LIMIT_REACHED",
"message": "Dein Aufgaben-Kontingent ist aufgebraucht.",
"current_balance": 0,
"plan": "basic"
}
HTTP Status: 402 Payment Required
No Subscription
{
"error": "NO_SUBSCRIPTION",
"message": "Kein aktives Abonnement gefunden."
}
HTTP Status: 403 Forbidden
Frontend Integration
Task Usage anzeigen
// Response von GET /api/v1/billing/status
interface TaskUsageInfo {
tasks_available: number; // z.B. 45
max_tasks: number; // z.B. 150
info_text: string; // "Aufgaben verfuegbar: 45 von max. 150"
tooltip_text: string; // "Aufgaben koennen sich bis zu 5 Monate ansammeln."
}
Task konsumieren
// Vor jeder KI-Aktion
const response = await fetch('/api/v1/billing/tasks/check/' + userId);
const { allowed, message } = await response.json();
if (!allowed) {
showUpgradeDialog(message);
return;
}
// Nach erfolgreicher KI-Aktion
await fetch('/api/v1/billing/tasks/consume', {
method: 'POST',
body: JSON.stringify({ user_id: userId, task_type: 'correction' })
});