12 KiB
BotKonzept Installer JSON API Documentation
Übersicht
Diese API stellt die Installer-JSON-Daten sicher für Frontend-Clients bereit, ohne Secrets preiszugeben.
Basis-URL: http://192.168.45.104:3000 (PostgREST auf Kunden-LXC)
Zentrale API: https://api.botkonzept.de (zentrales PostgREST/n8n)
Sicherheitsmodell
✅ Erlaubte Daten (Frontend-sicher)
ctid,hostname,fqdn,ip,vlanurls.*(alle URL-Endpunkte)supabase.url_externalsupabase.anon_keyollama.url,ollama.model,ollama.embedding_model
❌ Verbotene Daten (Secrets)
postgres.passwordsupabase.service_role_keysupabase.jwt_secretn8n.owner_passwordn8n.encryption_key
API-Endpunkte
1. Public Config (Keine Authentifizierung)
Zweck: Liefert öffentliche Konfiguration für Website (Registrierungs-Webhook)
Route: POST /rpc/get_public_config
Request:
curl -X POST 'http://192.168.45.104:3000/rpc/get_public_config' \
-H "Content-Type: application/json" \
-d '{}'
Response (Success):
{
"registration_webhook_url": "https://api.botkonzept.de/webhook/botkonzept-registration",
"api_base_url": "https://api.botkonzept.de"
}
Response (Error):
{
"code": "PGRST204",
"message": "No rows returned",
"details": null,
"hint": null
}
CORS: Erlaubt (öffentlich)
2. Instance Config by Email (Öffentlich, aber rate-limited)
Zweck: Liefert Instanz-Konfiguration für einen Kunden (via E-Mail)
Route: POST /rpc/get_instance_config_by_email
Request:
curl -X POST 'http://192.168.45.104:3000/rpc/get_instance_config_by_email' \
-H "Content-Type: application/json" \
-d '{"customer_email_param": "max@beispiel.de"}'
Response (Success):
[
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"customer_id": "123e4567-e89b-12d3-a456-426614174000",
"ctid": 769697636,
"hostname": "sb-1769697636",
"fqdn": "sb-1769697636.userman.de",
"ip": "192.168.45.104",
"vlan": 90,
"status": "active",
"created_at": "2025-01-15T10:30:00Z",
"urls": {
"n8n_internal": "http://192.168.45.104:5678/",
"n8n_external": "https://sb-1769697636.userman.de",
"postgrest": "http://192.168.45.104:3000",
"chat_webhook": "https://sb-1769697636.userman.de/webhook/rag-chat-webhook/chat",
"chat_internal": "http://192.168.45.104:5678/webhook/rag-chat-webhook/chat",
"upload_form": "https://sb-1769697636.userman.de/form/rag-upload-form",
"upload_form_internal": "http://192.168.45.104:5678/form/rag-upload-form"
},
"supabase": {
"url_external": "http://192.168.45.104:3000",
"anon_key": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
},
"ollama": {
"url": "http://192.168.45.3:11434",
"model": "ministral-3:3b",
"embedding_model": "nomic-embed-text:latest"
},
"customer_email": "max@beispiel.de",
"first_name": "Max",
"last_name": "Mustermann",
"company": "Muster GmbH",
"customer_status": "trial"
}
]
Response (Not Found):
[]
Response (Error):
{
"code": "PGRST301",
"message": "Invalid input syntax",
"details": "...",
"hint": null
}
Authentifizierung: Keine (öffentlich, aber sollte rate-limited sein)
CORS: Erlaubt
3. Instance Config by CTID (Service Role Only)
Zweck: Liefert Instanz-Konfiguration für interne Workflows (via CTID)
Route: POST /rpc/get_instance_config_by_ctid
Request:
curl -X POST 'http://192.168.45.104:3000/rpc/get_instance_config_by_ctid' \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <SERVICE_ROLE_KEY>" \
-d '{"ctid_param": 769697636}'
Response: Gleiche Struktur wie /get_instance_config_by_email
Authentifizierung: Service Role Key erforderlich
CORS: Nicht erlaubt (nur Backend-to-Backend)
4. Store Installer JSON (Service Role Only)
Zweck: Speichert Installer-JSON nach Instanz-Erstellung (wird von install.sh aufgerufen)
Route: POST /rpc/store_installer_json
Request:
curl -X POST 'http://192.168.45.104:3000/rpc/store_installer_json' \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <SERVICE_ROLE_KEY>" \
-d '{
"customer_email_param": "max@beispiel.de",
"lxc_id_param": 769697636,
"installer_json_param": {
"ctid": 769697636,
"hostname": "sb-1769697636",
"fqdn": "sb-1769697636.userman.de",
"ip": "192.168.45.104",
"vlan": 90,
"urls": {
"n8n_internal": "http://192.168.45.104:5678/",
"n8n_external": "https://sb-1769697636.userman.de",
"postgrest": "http://192.168.45.104:3000",
"chat_webhook": "https://sb-1769697636.userman.de/webhook/rag-chat-webhook/chat",
"chat_internal": "http://192.168.45.104:5678/webhook/rag-chat-webhook/chat",
"upload_form": "https://sb-1769697636.userman.de/form/rag-upload-form",
"upload_form_internal": "http://192.168.45.104:5678/form/rag-upload-form"
},
"postgres": {
"host": "postgres",
"port": 5432,
"db": "customer",
"user": "customer",
"password": "REDACTED"
},
"supabase": {
"url": "http://postgrest:3000",
"url_external": "http://192.168.45.104:3000",
"anon_key": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"service_role_key": "REDACTED",
"jwt_secret": "REDACTED"
},
"ollama": {
"url": "http://192.168.45.3:11434",
"model": "ministral-3:3b",
"embedding_model": "nomic-embed-text:latest"
},
"n8n": {
"encryption_key": "REDACTED",
"owner_email": "admin@userman.de",
"owner_password": "REDACTED",
"secure_cookie": false
}
}
}'
Response (Success):
{
"success": true,
"instance_id": "550e8400-e29b-41d4-a716-446655440000",
"customer_id": "123e4567-e89b-12d3-a456-426614174000",
"message": "Installer JSON stored successfully"
}
Response (Error):
{
"success": false,
"error": "Instance not found for customer email and LXC ID"
}
Authentifizierung: Service Role Key erforderlich
CORS: Nicht erlaubt (nur Backend-to-Backend)
5. Direct View Access (Authenticated)
Zweck: Direkter Zugriff auf View (für authentifizierte Benutzer)
Route: GET /api/instance_config
Request:
curl -X GET 'http://192.168.45.104:3000/api/instance_config' \
-H "Authorization: Bearer <USER_JWT_TOKEN>"
Response: Array von Instanz-Konfigurationen (gefiltert nach RLS)
Authentifizierung: JWT Token erforderlich (Supabase Auth)
CORS: Erlaubt
Authentifizierung
1. Keine Authentifizierung (Public)
/rpc/get_public_config/rpc/get_instance_config_by_email(sollte rate-limited sein)
2. Service Role Key
Header:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoic2VydmljZV9yb2xlIiwiaXNzIjoic3VwYWJhc2UiLCJpYXQiOjE3MDAwMDAwMDAsImV4cCI6MjAwMDAwMDAwMH0...
Verwendung:
/rpc/get_instance_config_by_ctid/rpc/store_installer_json
3. User JWT Token (Supabase Auth)
Header:
Authorization: Bearer <USER_JWT_TOKEN>
Verwendung:
/api/instance_config(direkter View-Zugriff)
CORS-Konfiguration
PostgREST CORS Headers
In der PostgREST-Konfiguration (docker-compose.yml):
postgrest:
environment:
PGRST_SERVER_CORS_ALLOWED_ORIGINS: "*"
# Oder spezifisch:
# PGRST_SERVER_CORS_ALLOWED_ORIGINS: "https://botkonzept.de,https://www.botkonzept.de"
Nginx Reverse Proxy CORS
Falls über Nginx:
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization';
Rate Limiting
Empfehlung: Rate Limiting für öffentliche Endpunkte implementieren
Nginx Rate Limiting
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
location /rpc/get_instance_config_by_email {
limit_req zone=api_limit burst=20 nodelay;
proxy_pass http://postgrest:3000;
}
PostgREST Rate Limiting
Alternativ: Verwende einen API Gateway (Kong, Tyk) vor PostgREST.
Fehlerbehandlung
HTTP Status Codes
200 OK- Erfolgreiche Anfrage204 No Content- Keine Daten gefunden (PostgREST)400 Bad Request- Ungültige Eingabe401 Unauthorized- Fehlende/ungültige Authentifizierung403 Forbidden- Keine Berechtigung404 Not Found- Ressource nicht gefunden500 Internal Server Error- Serverfehler
PostgREST Error Format
{
"code": "PGRST301",
"message": "Invalid input syntax for type integer",
"details": "invalid input syntax for type integer: \"abc\"",
"hint": null
}
Integration mit install.sh
Schritt 1: SQL-Schema anwenden
# Auf dem Proxmox Host
pct exec <CTID> -- bash -c "
docker exec customer-postgres psql -U customer -d customer < /opt/customer-stack/sql/add_installer_json_api.sql
"
Schritt 2: install.sh erweitern
Am Ende von install.sh (nach JSON-Generierung):
# Store installer JSON in database via PostgREST
info "Storing installer JSON in database..."
STORE_RESPONSE=$(curl -sS -X POST "http://${CT_IP}:${POSTGREST_PORT}/rpc/store_installer_json" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${SERVICE_ROLE_KEY}" \
-d "{
\"customer_email_param\": \"${N8N_OWNER_EMAIL}\",
\"lxc_id_param\": ${CTID},
\"installer_json_param\": ${JSON_OUTPUT}
}" 2>&1)
if echo "$STORE_RESPONSE" | grep -q '"success":true'; then
info "Installer JSON stored successfully"
else
warn "Failed to store installer JSON: ${STORE_RESPONSE}"
fi
Testing
Test 1: Public Config
curl -X POST 'http://192.168.45.104:3000/rpc/get_public_config' \
-H "Content-Type: application/json" \
-d '{}'
# Erwartete Antwort:
# {"registration_webhook_url":"https://api.botkonzept.de/webhook/botkonzept-registration","api_base_url":"https://api.botkonzept.de"}
Test 2: Instance Config by Email
curl -X POST 'http://192.168.45.104:3000/rpc/get_instance_config_by_email' \
-H "Content-Type: application/json" \
-d '{"customer_email_param": "max@beispiel.de"}'
# Erwartete Antwort: Array mit Instanz-Konfiguration (siehe oben)
Test 3: Store Installer JSON (mit Service Role Key)
SERVICE_ROLE_KEY="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
curl -X POST 'http://192.168.45.104:3000/rpc/store_installer_json' \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${SERVICE_ROLE_KEY}" \
-d '{
"customer_email_param": "max@beispiel.de",
"lxc_id_param": 769697636,
"installer_json_param": {"ctid": 769697636, "urls": {...}}
}'
# Erwartete Antwort:
# {"success":true,"instance_id":"...","customer_id":"...","message":"Installer JSON stored successfully"}
Test 4: Verify No Secrets Exposed
curl -X POST 'http://192.168.45.104:3000/rpc/get_instance_config_by_email' \
-H "Content-Type: application/json" \
-d '{"customer_email_param": "max@beispiel.de"}' | jq .
# Prüfe: Response enthält KEINE der folgenden Felder:
# - postgres.password
# - supabase.service_role_key
# - supabase.jwt_secret
# - n8n.owner_password
# - n8n.encryption_key
Deployment Checklist
- SQL-Schema auf allen Instanzen anwenden
- PostgREST CORS konfigurieren
- Rate Limiting aktivieren
- install.sh erweitern (Installer JSON speichern)
- Frontend auf neue API umstellen
- Tests durchführen
- Monitoring einrichten (API-Zugriffe loggen)
Monitoring & Logging
Audit Log
Alle API-Zugriffe werden in audit_log Tabelle protokolliert:
SELECT * FROM audit_log
WHERE action = 'api_config_access'
ORDER BY created_at DESC
LIMIT 10;
PostgREST Logs
docker logs customer-postgrest --tail 100 -f
Sicherheitshinweise
- Service Role Key schützen: Niemals im Frontend verwenden!
- Rate Limiting: Öffentliche Endpunkte müssen rate-limited sein
- HTTPS: In Produktion nur über HTTPS (OPNsense Reverse Proxy)
- Input Validation: PostgREST validiert automatisch, aber zusätzliche Checks empfohlen
- Audit Logging: Alle API-Zugriffe werden geloggt
Support
Bei Fragen oder Problemen:
- Dokumentation:
customer-installer/wiki/ - Troubleshooting:
customer-installer/REGISTRATION_TROUBLESHOOTING.md