# INSIGHT MVP - Entwickler-Integrationshandbuch > **Zielgruppe:** Entwickler von Container-Anwendungen, die nahtlos in die > INSIGHT-Plattform integriert werden sollen. > > **Version:** 1.0.0-alpha | **Stand:** 2026-03-10 --- ## Inhaltsverzeichnis 1. [Ueberblick](#1-ueberblick) 2. [Architektur](#2-architektur) 3. [Docker-Integration](#3-docker-integration) 4. [Authentifizierung & Autorisierung](#4-authentifizierung--autorisierung) 5. [API-Kommunikation](#5-api-kommunikation) 6. [Traefik-Routing (API Gateway)](#6-traefik-routing-api-gateway) 7. [Datenbank-Anbindung](#7-datenbank-anbindung) 8. [Redis / Cache](#8-redis--cache) 9. [Frontend-Integration (Sidebar)](#9-frontend-integration-sidebar) 10. [Sicherheitsanforderungen](#10-sicherheitsanforderungen) 11. [Health-Checks & Monitoring](#11-health-checks--monitoring) 12. [Checkliste fuer neue Container-Apps](#12-checkliste-fuer-neue-container-apps) 13. [Beispiel: docker-compose Erweiterung](#13-beispiel-docker-compose-erweiterung) --- ## 1. Ueberblick INSIGHT ist eine modulare Multi-Tenant-Plattform, die als Docker-Compose-Stack betrieben wird. Externe Container-Anwendungen koennen ueber folgende Wege integriert werden: | Integrationsart | Beschreibung | |-------------------------|---------------------------------------------------| | **API-Integration** | REST-API-Aufrufe gegen den Core-Service | | **Sidebar-Link** | Anwendung als externer Link im INSIGHT-Menue | | **Shared Authentication** | JWT-basierte Authentifizierung (SSO) | | **Shared Database** | Eigenes Schema in der gemeinsamen PostgreSQL-DB | | **Docker-Netzwerk** | Direkter Zugriff auf interne Services | --- ## 2. Architektur ``` Internet / Intranet | [Traefik Gateway] Port 80 (HTTP) | +------------+------------+ | | | [Frontend] [Core-API] [Deine App] React/Vite NestJS Container Port 8080 Port 3000 Port XXXX | | | +-----+------+-----+------+ | | [PostgreSQL] [Redis] via PgBouncer Port 6379 Port 6432 ``` ### Docker-Netzwerke | Netzwerk | Typ | Zweck | |------------------|----------|------------------------------------------| | `insight-web` | bridge | Traefik-Routing, oeffentliche APIs | | `insight-db` | internal | PostgreSQL + PgBouncer (isoliert) | | `insight-cache` | internal | Redis (isoliert) | > **Wichtig:** `insight-db` und `insight-cache` sind als `internal` markiert > und somit nicht von aussen erreichbar. Deine Anwendung muss explizit in > diese Netzwerke eingebunden werden. --- ## 3. Docker-Integration ### 3.1 Netzwerk-Anbindung Dein Container muss in die benoetigten Netzwerke eingebunden werden: ```yaml # In deiner docker-compose.yml oder als Erweiterung services: meine-app: image: git.xinion.lan/gitadmin/insight-meine-app:latest networks: - insight-web # Pflicht: fuer Traefik-Routing - insight-db # Optional: nur bei direktem DB-Zugriff - insight-cache # Optional: nur bei Redis-Zugriff labels: - "traefik.enable=true" # Routing-Labels (siehe Abschnitt 6) networks: insight-web: external: true insight-db: external: true insight-cache: external: true ``` ### 3.2 Container Registry | Parameter | Wert | |-------------------|--------------------------------------------| | Registry-URL | `git.xinion.lan` | | Image-Prefix | `git.xinion.lan/gitadmin/insight-{name}` | | Authentifizierung | Forgejo Login-Credentials | ```bash # Image bauen und pushen docker build -t git.xinion.lan/gitadmin/insight-meine-app:latest . docker push git.xinion.lan/gitadmin/insight-meine-app:latest ``` ### 3.3 Service Discovery (DNS) Innerhalb des Docker-Netzwerks sind Services ueber ihre Servicenamen erreichbar: | Service | Hostname | Port | Netzwerk | |--------------|-------------|-------|----------------| | Core-API | `core` | 3000 | insight-web | | PostgreSQL | `postgres` | 5432 | insight-db | | PgBouncer | `pgbouncer` | 6432 | insight-db | | Redis | `redis` | 6379 | insight-cache | | Frontend | `frontend` | 8080 | insight-web | | Traefik | `traefik` | 80 | insight-web | --- ## 4. Authentifizierung & Autorisierung ### 4.1 JWT-Token-Architektur INSIGHT verwendet RS256 (asymmetrische) JWT-Tokens: | Token-Typ | Speicherort | Lebensdauer | Zweck | |-----------------|-------------------|-------------|--------------------------| | **Access Token** | Memory (Variable) | 15 Minuten | API-Authentifizierung | | **Refresh Token** | HttpOnly Cookie | 7 Tage | Token-Erneuerung | ### 4.2 JWT-Payload-Struktur ```json { "sub": "550e8400-e29b-41d4-a716-446655440000", "email": "user@example.com", "role": "USER", "tenantId": "...", "tenantSlug": "tenant_acme", "jti": "unique-token-id", "iat": 1710000000, "exp": 1710000900 } ``` **Rollen:** | Rolle | Beschreibung | |-------------------|-------------------------------------------| | `PLATFORM_ADMIN` | Plattform-Administrator (voller Zugriff) | | `TENANT_ADMIN` | Mandanten-Administrator | | `USER` | Standard-Benutzer | ### 4.3 Token-Validierung in deiner Anwendung Um eingehende Requests zu validieren, brauchst du den **oeffentlichen JWT-Schluessel** (RS256 Public Key). Dieser liegt im Core-Service unter `/app/keys/jwt-public.pem`. **Option A: Public Key mounten (empfohlen)** ```yaml # docker-compose.yml services: meine-app: volumes: - ./keys/jwt-public.pem:/app/keys/jwt-public.pem:ro ``` Dann in deiner Anwendung: ``` 1. Lese den Public Key aus /app/keys/jwt-public.pem 2. Validiere den JWT aus dem Authorization-Header: - Algorithmus: RS256 - Issuer: (optional, je nach Konfiguration) - Pruefe exp (Ablaufzeit) - Pruefe jti gegen Redis-Blocklist (optional, fuer Revocation) 3. Extrahiere sub (User-ID), role, tenantId aus dem Payload ``` **Option B: API-Proxy (einfacher)** Leite Requests ueber den Core-Service und nutze dessen eingebaute JWT-Validierung: ``` Client -> Traefik -> Core-Service (validiert JWT) -> Deine App ``` ### 4.4 Token-Revocation (optional) Gesperrte Tokens werden in Redis unter dem Key-Pattern `blocked_token:{jti}` gespeichert. Fuer Echtzeit-Revocation pruefe den `jti`-Claim gegen Redis: ``` Redis Key: blocked_token:{jti} Redis Value: "1" TTL: Restlaufzeit des Tokens ``` ### 4.5 Login-Flow fuer externe Anwendungen ``` Benutzer oeffnet deine App (via INSIGHT Sidebar-Link) | v Kein gueltiger Token vorhanden? | v Redirect zu INSIGHT Login: http://{HOST}/login?redirect={DEINE_APP_URL} | v Benutzer meldet sich an (E-Mail/Passwort oder Microsoft SSO) | v INSIGHT setzt Tokens und redirectet zurueck zu deiner App | v Deine App liest den Access Token und nutzt ihn fuer API-Calls ``` ### 4.6 API-Endpunkte fuer Authentifizierung | Methode | Endpunkt | Auth | Beschreibung | |---------|----------------------------|--------|-----------------------------| | POST | `/api/v1/auth/login` | Nein | Login (E-Mail + Passwort) | | POST | `/api/v1/auth/refresh` | Cookie | Token erneuern | | POST | `/api/v1/auth/logout` | Ja | Logout + Token-Revocation | | GET | `/api/v1/users/me` | Ja | Aktuelle User-Daten | --- ## 5. API-Kommunikation ### 5.1 Basis-URL | Umgebung | Basis-URL | |-------------|---------------------------------------| | Entwicklung | `http://172.20.10.59/api/v1` | | Docker-intern| `http://core:3000/api/v1` | ### 5.2 Request-Format Alle API-Requests muessen folgende Header enthalten: ```http Authorization: Bearer Content-Type: application/json X-Tenant-ID: # Optional: fuer Mandanten-spezifische Operationen X-Request-ID: # Optional: fuer Request-Tracing ``` ### 5.3 Verfuegbare API-Endpunkte **Benutzer-Verwaltung:** | Methode | Endpunkt | Rolle | Beschreibung | |---------|------------------------|----------------|---------------------------| | GET | `/api/v1/users/me` | Alle | Eigene User-Daten | | PATCH | `/api/v1/users/me` | Alle | Eigene Daten aktualisieren| | GET | `/api/v1/users` | PLATFORM_ADMIN | Alle User auflisten | | POST | `/api/v1/users` | PLATFORM_ADMIN | User anlegen | | PATCH | `/api/v1/users/:id` | PLATFORM_ADMIN | User bearbeiten | **Mandanten (Tenants):** | Methode | Endpunkt | Rolle | Beschreibung | |---------|-----------------------------------|----------------|------------------------| | GET | `/api/v1/tenants` | PLATFORM_ADMIN | Alle Mandanten | | GET | `/api/v1/tenants/:id` | TENANT_ADMIN+ | Mandant-Details | | POST | `/api/v1/tenants` | PLATFORM_ADMIN | Mandant erstellen | | PATCH | `/api/v1/tenants/:id` | PLATFORM_ADMIN | Mandant bearbeiten | **Einstellungen:** | Methode | Endpunkt | Rolle | Beschreibung | |---------|-----------------------------------|----------------|------------------------| | GET | `/api/v1/settings/external-links` | Alle | Sidebar-Links abrufen | | POST | `/api/v1/settings/external-links` | PLATFORM_ADMIN | Sidebar-Links setzen | | GET | `/api/v1/settings/branding` | Alle | Branding-Einstellungen | **Gesundheit:** | Methode | Endpunkt | Auth | Beschreibung | |---------|-----------|------|-----------------------------| | GET | `/health` | Nein | Health-Check (DB + Redis) | ### 5.4 Fehler-Responses Alle Fehler folgen einem einheitlichen Format: ```json { "statusCode": 401, "message": "Unauthorized", "error": "Unauthorized" } ``` | HTTP-Code | Bedeutung | |-----------|----------------------------------------------| | 400 | Ungueltige Eingabe (Validierungsfehler) | | 401 | Nicht authentifiziert (Token fehlt/ungueltig) | | 403 | Keine Berechtigung (Rolle nicht ausreichend) | | 404 | Ressource nicht gefunden | | 429 | Rate-Limit ueberschritten | --- ## 6. Traefik-Routing (API Gateway) ### 6.1 Eigene Route registrieren Um deine Anwendung ueber Traefik erreichbar zu machen, verwende Docker-Labels: ```yaml services: meine-app: labels: - "traefik.enable=true" - "traefik.http.routers.meine-app.rule=PathPrefix(`/meine-app`)" - "traefik.http.routers.meine-app.entrypoints=web" - "traefik.http.services.meine-app.loadbalancer.server.port=8080" # Optional: Middleware fuer CORS und Security - "traefik.http.routers.meine-app.middlewares=cors-headers@file,security-headers@file" ``` ### 6.2 Bestehende Routen (nicht verwenden!) Diese Pfade sind bereits belegt: | Pfad-Prefix | Service | Beschreibung | |---------------|-------------|------------------------| | `/api/*` | core | Backend-API | | `/health` | core | Health-Check | | `/*` | frontend | React-Frontend (Catch-all, niedrige Prioritaet) | ### 6.3 Verfuegbare Middlewares Die folgenden Middlewares sind bereits konfiguriert und koennen referenziert werden: | Middleware | Funktion | |-----------------------|---------------------------------------------------| | `cors-headers@file` | CORS-Header (Origin, Methoden, Custom-Headers) | | `security-headers@file` | CSP, XSS-Filter, HSTS, Frame-Deny | | `api-ratelimit@file` | Rate-Limiting (100 avg, 50 burst) | | `gzip-compress@file` | Gzip-Komprimierung | ### 6.4 CORS-Konfiguration Standardmaessig erlaubte Methoden und Header: ``` Methoden: GET, POST, PUT, PATCH, DELETE, OPTIONS Header: Authorization, Content-Type, X-Tenant-ID, X-Request-ID Origin: Konfigurierbar via CORS_ORIGINS Umgebungsvariable ``` Falls deine Anwendung zusaetzliche Header benoetigt, muss die `config/traefik/dynamic/middlewares.yml` erweitert werden. --- ## 7. Datenbank-Anbindung ### 7.1 Verbindung ueber PgBouncer (empfohlen) ``` Host: pgbouncer Port: 6432 Datenbank: platform_core (oder eigene DB) Pool-Mode: transaction ``` **Connection-String:** ``` postgresql://{DB_USER}:{DB_PASSWORD}@pgbouncer:6432/{DB_NAME} ``` > **Hinweis:** Die DB-Credentials stehen in der `.env`-Datei auf dem Server. > Niemals in Git committen! ### 7.2 Direkte Verbindung (nur fuer Migrationen) ``` postgresql://{DB_USER}:{DB_PASSWORD}@postgres:5432/{DB_NAME} ``` PgBouncer im `transaction`-Modus unterstuetzt keine `SET`-Befehle, `LISTEN/NOTIFY` oder `PREPARE`-Statements. Fuer Migrationen immer die direkte Verbindung verwenden. ### 7.3 Eigenes Datenbank-Schema Fuer neue Anwendungen empfehlen wir ein eigenes Schema in der bestehenden PostgreSQL-Instanz: ```sql -- Schema fuer deine Anwendung erstellen CREATE SCHEMA IF NOT EXISTS app_meine_app; -- Tabellen im Schema anlegen CREATE TABLE app_meine_app.beispiel ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name TEXT NOT NULL, created_at TIMESTAMPTZ DEFAULT NOW() ); ``` **Namenskonvention:** `app_{anwendungsname}` fuer das Schema. ### 7.4 Zugriff auf bestehende INSIGHT-Daten Die Core-Datenbank (`platform_core`) enthaelt folgende relevante Tabellen: | Tabelle | Beschreibung | |-----------------|--------------------------------------| | `User` | Benutzer (ID, Name, E-Mail, Rolle) | | `Tenant` | Mandanten (ID, Name, Slug) | | `TenantUser` | Mandant-Benutzer-Zuordnung | | `AuthProvider` | Authentifizierungsmethoden pro User | > **Achtung:** Direkter Schreibzugriff auf Core-Tabellen ist untersagt! > Verwende die REST-API fuer Aenderungen an Core-Daten. --- ## 8. Redis / Cache ### 8.1 Verbindung ``` Host: redis Port: 6379 Netzwerk: insight-cache ``` ### 8.2 Key-Namenskonventionen Um Konflikte zu vermeiden, verwende einen App-spezifischen Prefix: ``` app:{anwendungsname}:{key} ``` **Bestehende Prefixes (NICHT verwenden):** | Prefix | Verwendet von | |-------------------------|------------------| | `blocked_token:*` | Auth (Revocation)| | `platform_*` | Core-Settings | | `favicon:*` | Favicon-Cache | | `sso:state:*` | SSO CSRF-Schutz | ### 8.3 TTL-Empfehlung Setze immer einen TTL auf deine Keys, um Speicher-Leaks zu vermeiden: ``` Kurzlebige Daten (Sessions): 5 - 30 Minuten Cache-Daten: 1 - 24 Stunden Konfiguration: 24 - 48 Stunden ``` --- ## 9. Frontend-Integration (Sidebar) ### 9.1 Externe Links im INSIGHT-Menue Deine Anwendung wird als externer Link in der INSIGHT-Sidebar angezeigt. Die Konfiguration erfolgt durch einen PLATFORM_ADMIN unter **Administration > Externe Links**. Jeder Link hat folgende Eigenschaften: | Feld | Beschreibung | |-------------|---------------------------------------------| | `label` | Anzeigename im Menue (z.B. "Meine App") | | `url` | URL deiner Anwendung | | `sortOrder` | Reihenfolge in der Sidebar | | `customIcon`| Optionales Icon (Base64, max 100KB) | ### 9.2 Favicon-Erkennung INSIGHT erkennt automatisch das Favicon deiner Anwendung ueber HTML-Parsing: 1. Deine Anwendung muss ein `` Tag im HTML-`` haben 2. Alternativ: `/favicon.ico` im Root-Verzeichnis bereitstellen 3. Oder: Eigenes Icon als Base64 in der Admin-Konfiguration hochladen ### 9.3 Oeffnungs-Verhalten Externe Links werden in einem **separaten Browser-Fenster** geoeffnet (`window.open` mit `popup,noopener`). Deine Anwendung laeuft eigenstaendig und kommuniziert ueber die REST-API mit INSIGHT. --- ## 10. Sicherheitsanforderungen ### 10.1 Verbindliche Regeln | Regel | Details | |----------------------------------------|----------------------------------------| | **Kein localStorage fuer Tokens** | Access Token nur im Memory speichern | | **HTTPS in Produktion** | Aktuell HTTP (Dev), spaeter Pflicht | | **Keine Secrets in Git** | `.env`, Keys, Passwoerter nie committen | | **Input-Validierung** | Whitelist-Validierung, kein raw SQL | | **Rate-Limiting beachten** | Max 200 Req/Min global, 100/50 pro Route| | **CORS-Origin registrieren** | Deine Domain in `CORS_ORIGINS` eintragen| ### 10.2 Validierung (GlobalPipe) Der Core-Service nutzt einen globalen `ValidationPipe`: ``` - whitelist: true (unbekannte Felder werden entfernt) - forbidNonWhitelisted: true (unbekannte Felder fuehren zu 400) - transform: true (Typen werden automatisch konvertiert) ``` Stelle sicher, dass deine API-Requests nur die dokumentierten Felder enthalten. ### 10.3 Body-Size-Limit Das maximale Request-Body ist auf **12 MB** begrenzt (fuer Base64-Uploads). Fuer groessere Dateien implementiere einen separaten Upload-Endpunkt. ### 10.4 Account-Lockout Nach **5 fehlgeschlagenen Login-Versuchen** wird der Account fuer **15 Minuten** gesperrt. Implementiere entsprechende Fehlerbehandlung. --- ## 11. Health-Checks & Monitoring ### 11.1 Health-Check Endpunkt Deine Anwendung sollte einen Health-Check bereitstellen: ``` GET /meine-app/health Response: { "status": "ok" } ``` Konfiguriere den Docker-Healthcheck: ```yaml services: meine-app: healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/health"] interval: 30s timeout: 10s retries: 3 start_period: 10s ``` ### 11.2 Logging Nutze strukturiertes JSON-Logging fuer die Integration mit dem Observability-Stack (Loki/Grafana): ```json { "level": "info", "timestamp": "2026-03-10T12:00:00Z", "message": "Request verarbeitet", "service": "meine-app", "requestId": "...", "userId": "...", "duration": 42 } ``` ### 11.3 Observability-Stack (optional) | Service | Port | Zugriff | |-------------|-------|------------------------------| | Grafana | 3001 | SSH-Tunnel (nur intern) | | Prometheus | 9090 | Nur intern | | Loki | 3100 | Nur intern (Log-Aggregation) | | Tempo | 3200 | Nur intern (Tracing) | --- ## 12. Checkliste fuer neue Container-Apps ### Vor der Entwicklung - [ ] Tech-Stack festlegen (Empfehlung: TypeScript/Node.js, Go, oder Python) - [ ] Datenbank-Schema planen (`app_{name}` Schema) - [ ] API-Endpunkte definieren - [ ] Traefik-Route planen (Pfad-Prefix `/{app-name}`) ### Implementierung - [ ] Dockerfile erstellen (Multi-Stage-Build empfohlen) - [ ] JWT-Validierung implementieren (RS256, Public Key) - [ ] Health-Check-Endpunkt implementieren - [ ] Strukturiertes JSON-Logging einrichten - [ ] CORS korrekt konfigurieren - [ ] Input-Validierung implementieren - [ ] Fehler-Responses im INSIGHT-Format zurueckgeben ### Docker-Integration - [ ] Image in Container Registry pushen (`git.xinion.lan`) - [ ] `docker-compose.override.yml` oder separates Compose-File erstellen - [ ] Netzwerke einbinden (`insight-web`, ggf. `insight-db`, `insight-cache`) - [ ] Traefik-Labels konfigurieren - [ ] Healthcheck konfigurieren - [ ] Umgebungsvariablen dokumentieren ### Deployment - [ ] `.env`-Eintraege auf dem Server ergaenzen - [ ] Traefik-Route testen (`curl http://172.20.10.59/{app-name}/health`) - [ ] JWT-Validierung testen (mit gueltigem/ungueltigem Token) - [ ] In INSIGHT-Sidebar als externen Link eintragen - [ ] Favicon / Custom-Icon konfigurieren ### Dokumentation - [ ] API-Dokumentation erstellen (OpenAPI/Swagger empfohlen) - [ ] Umgebungsvariablen dokumentieren - [ ] Datenbank-Schema dokumentieren - [ ] README.md im Repository anlegen --- ## 13. Beispiel: docker-compose Erweiterung Erstelle eine `docker-compose.meine-app.yml` Datei: ```yaml # docker-compose.meine-app.yml # Starten mit: docker compose -f docker-compose.yml -f docker-compose.meine-app.yml up -d services: meine-app: image: git.xinion.lan/gitadmin/insight-meine-app:latest container_name: insight-meine-app restart: unless-stopped environment: - NODE_ENV=production - PORT=8080 - DATABASE_URL=postgresql://${DB_USER}:${DB_PASSWORD}@pgbouncer:6432/platform_core?schema=app_meine_app - REDIS_HOST=redis - REDIS_PORT=6379 - JWT_PUBLIC_KEY_PATH=/app/keys/jwt-public.pem - INSIGHT_API_URL=http://core:3000/api/v1 volumes: - ./keys/jwt-public.pem:/app/keys/jwt-public.pem:ro networks: - insight-web - insight-db - insight-cache labels: - "traefik.enable=true" - "traefik.http.routers.meine-app.rule=PathPrefix(`/meine-app`)" - "traefik.http.routers.meine-app.entrypoints=web" - "traefik.http.services.meine-app.loadbalancer.server.port=8080" - "traefik.http.routers.meine-app.middlewares=cors-headers@file,security-headers@file" healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/health"] interval: 30s timeout: 10s retries: 3 start_period: 10s depends_on: pgbouncer: condition: service_healthy redis: condition: service_healthy networks: insight-web: external: true insight-db: external: true insight-cache: external: true ``` ### Starten ```bash # Auf dem Server (insight-dev-01) cd /home/deploy/insight # Zusammen mit der Hauptanwendung starten docker compose \ -f docker-compose.yml \ -f docker-compose.meine-app.yml \ up -d # Nur die neue App starten (Hauptanwendung laeuft bereits) docker compose \ -f docker-compose.yml \ -f docker-compose.meine-app.yml \ up -d meine-app # Logs pruefen docker compose \ -f docker-compose.yml \ -f docker-compose.meine-app.yml \ logs -f meine-app ``` --- ## Kontakt & Support Bei Fragen zur Integration wende dich an das INSIGHT-Plattform-Team: - **Repository:** `ssh://git@git.xinion.lan/gitadmin/INSIGHT-MVP.git` - **Admin-E-Mail:** `admin@xinion.de` --- > **Hinweis:** Dieses Dokument bezieht sich auf die Alpha-Version (v1.0.0-alpha). > API-Endpunkte und Konfigurationen koennen sich in spaeteren Versionen aendern.