mirror of
http://172.20.10.11:3000/gitadmin/INSIGHT-MVP.git
synced 2026-06-24 22:46:39 +02:00
Compare commits
5 commits
v1.0.0-alp
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
718d0c38c9 | ||
|
|
ffd48a38a3 | ||
|
|
b18fe9376c | ||
|
|
a0f5474119 | ||
|
|
15ea7627e8 |
4 changed files with 1251 additions and 0 deletions
BIN
docs/CLAUDE_BRIEFING.docx
Normal file
BIN
docs/CLAUDE_BRIEFING.docx
Normal file
Binary file not shown.
505
docs/CRM_HANDOFF.md
Normal file
505
docs/CRM_HANDOFF.md
Normal file
|
|
@ -0,0 +1,505 @@
|
|||
# CRM-Service Handoff — Briefing fuer neuen Claude Code Chat
|
||||
|
||||
> **Zweck:** Dieses Dokument enthaelt alle technischen Informationen, damit ein
|
||||
> neuer Claude Code Chat den CRM-Service im Monorepo entwickeln kann, ohne
|
||||
> bestehende Funktionalitaet zu beschaedigen.
|
||||
>
|
||||
> **Stand:** 2026-03-10 | **Basis:** INSIGHT MVP v1.0.0-alpha
|
||||
|
||||
---
|
||||
|
||||
## 1. Dein Auftrag
|
||||
|
||||
Entwickle den CRM-Service als eigenstaendiges Package unter
|
||||
`packages/crm-service/` im bestehenden Monorepo. Der Service ist ein
|
||||
NestJS-Backend, das als eigener Docker-Container laeuft und sich in die
|
||||
INSIGHT-Plattform integriert.
|
||||
|
||||
**Lese zuerst:** `docs/INTEGRATION.md` — dort steht, wie Container-Apps
|
||||
sich in die Plattform integrieren.
|
||||
|
||||
---
|
||||
|
||||
## 2. Was du NICHT anfassen darfst
|
||||
|
||||
> **KRITISCH:** Diese Dateien/Verzeichnisse gehoeren dem Core-Service.
|
||||
> Aenderungen daran koennen die gesamte Plattform zerstoeren.
|
||||
|
||||
| Pfad | Grund |
|
||||
|------|-------|
|
||||
| `packages/core-service/**` | Bestehender Backend-Service (Auth, Users, Tenants) |
|
||||
| `packages/frontend/**` | Bestehende React-App (wird spaeter separat erweitert) |
|
||||
| `config/traefik/**` | Traefik-Konfiguration (nur lesen, nicht aendern) |
|
||||
| `.forgejo/workflows/**` | CI/CD Pipeline (wird spaeter fuer CRM erweitert) |
|
||||
| `docker-compose.yml` | Haupt-Compose (nur lesen — du erstellst ein Override) |
|
||||
| `.keys/**` | JWT-Schluessel und SSH-Keys |
|
||||
| `prisma/core.schema.prisma` | Core-Datenbank-Schema |
|
||||
|
||||
**Ausnahmen:** Du darfst folgende Dateien ergaenzen (nicht ueberschreiben):
|
||||
- `.env.example` — Neue CRM-spezifische Variablen **anhaengen**
|
||||
- `docs/` — Eigene Dokumentation hinzufuegen
|
||||
|
||||
---
|
||||
|
||||
## 3. Verzeichnisstruktur (Ziel)
|
||||
|
||||
```
|
||||
INSIGHT-MVP/
|
||||
├── packages/
|
||||
│ ├── core-service/ ← NICHT ANFASSEN
|
||||
│ ├── frontend/ ← NICHT ANFASSEN
|
||||
│ └── crm-service/ ← DEIN BEREICH
|
||||
│ ├── Dockerfile
|
||||
│ ├── package.json
|
||||
│ ├── tsconfig.json
|
||||
│ ├── nest-cli.json
|
||||
│ ├── .dockerignore
|
||||
│ ├── prisma/
|
||||
│ │ └── crm.schema.prisma ← Eigenes Schema!
|
||||
│ └── src/
|
||||
│ ├── main.ts
|
||||
│ ├── app.module.ts
|
||||
│ ├── config/
|
||||
│ ├── contacts/
|
||||
│ ├── activities/
|
||||
│ ├── pipelines/
|
||||
│ └── ...
|
||||
├── docker-compose.crm.yml ← Docker Override fuer CRM
|
||||
└── docs/
|
||||
└── CRM_HANDOFF.md ← Diese Datei
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Bestehende Architektur (Referenz)
|
||||
|
||||
### 4.1 Docker-Netzwerke
|
||||
|
||||
| Netzwerk | Typ | Dein Zugriff |
|
||||
|----------|-----|-------------|
|
||||
| `insight-web` | bridge | **JA** — Pflicht fuer Traefik-Routing |
|
||||
| `insight-db` | internal | **JA** — Fuer Datenbankzugriff |
|
||||
| `insight-cache` | internal | **JA** — Fuer Redis-Zugriff |
|
||||
|
||||
### 4.2 Verfuegbare Infrastruktur-Services
|
||||
|
||||
| Service | Hostname (Docker) | Port | Zugriff |
|
||||
|---------|-------------------|------|---------|
|
||||
| PostgreSQL | `postgres` | 5432 | Direkt (nur Migrationen) |
|
||||
| PgBouncer | `pgbouncer` | 6432 | Pooled (Runtime) |
|
||||
| Redis | `redis` | 6379 | Cache + Events |
|
||||
| Core-API | `core` | 3000 | REST-Aufrufe |
|
||||
| Traefik | `traefik` | 80 | Gateway |
|
||||
|
||||
### 4.3 Datenbank-Verbindung
|
||||
|
||||
```
|
||||
# Runtime (via PgBouncer — Connection Pooling)
|
||||
DATABASE_URL=postgresql://${DB_USER}:${DB_PASSWORD}@pgbouncer:6432/${DB_NAME}
|
||||
|
||||
# Migrationen (direkt — PgBouncer unterstuetzt kein DDL)
|
||||
DATABASE_URL_DIRECT=postgresql://${DB_USER}:${DB_PASSWORD}@postgres:5432/${DB_NAME}
|
||||
```
|
||||
|
||||
- **DB_USER:** `insight` (Standard)
|
||||
- **DB_NAME:** `platform_core` (gemeinsame DB)
|
||||
- **Dein Schema:** `app_crm` (eigenes Schema innerhalb der gleichen DB)
|
||||
- **Pool-Mode:** `transaction` (kein `LISTEN/NOTIFY`, kein `SET`)
|
||||
|
||||
### 4.4 Redis
|
||||
|
||||
```
|
||||
Host: redis
|
||||
Port: 6379
|
||||
Passwort: optional (${REDIS_PASSWORD})
|
||||
```
|
||||
|
||||
**Key-Prefix fuer CRM:** `app:crm:*`
|
||||
|
||||
Bereits belegte Prefixes (NICHT verwenden):
|
||||
- `blocked_token:*` — Token-Revocation
|
||||
- `platform_*` — Core-Settings
|
||||
- `favicon:*` — Favicon-Cache
|
||||
- `sso:state:*` — SSO CSRF
|
||||
- `refresh_token_family:*` — Token-Rotation
|
||||
|
||||
---
|
||||
|
||||
## 5. Authentifizierung & Autorisierung
|
||||
|
||||
### 5.1 JWT-Token-Architektur
|
||||
|
||||
Der CRM-Service empfaengt Requests mit einem `Authorization: Bearer <token>`
|
||||
Header. Der Token wurde vom Core-Service ausgestellt (RS256).
|
||||
|
||||
**JWT-Payload:**
|
||||
```json
|
||||
{
|
||||
"sub": "user-uuid",
|
||||
"email": "user@example.com",
|
||||
"role": "USER | TENANT_ADMIN | PLATFORM_ADMIN",
|
||||
"tenantId": "tenant-uuid",
|
||||
"tenantSlug": "tenant_acme",
|
||||
"jti": "unique-token-id",
|
||||
"iat": 1710000000,
|
||||
"exp": 1710000900
|
||||
}
|
||||
```
|
||||
|
||||
### 5.2 Token-Validierung implementieren
|
||||
|
||||
Du brauchst den oeffentlichen JWT-Schluessel:
|
||||
|
||||
```yaml
|
||||
# In docker-compose.crm.yml
|
||||
volumes:
|
||||
- ./keys/jwt-public.pem:/app/keys/jwt-public.pem:ro
|
||||
```
|
||||
|
||||
**NestJS-Implementierung:**
|
||||
```typescript
|
||||
// Passport JWT Strategy (wie im Core-Service)
|
||||
// Algorithmus: RS256
|
||||
// Public Key: aus /app/keys/jwt-public.pem
|
||||
// Header: Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
**Optional — Token-Revocation pruefen:**
|
||||
```typescript
|
||||
// Redis-Key: blocked_token:{jti}
|
||||
// Wenn vorhanden → Token ist gesperrt → 401
|
||||
```
|
||||
|
||||
### 5.3 Rollen
|
||||
|
||||
| Rolle | CRM-Zugriff |
|
||||
|-------|-------------|
|
||||
| `PLATFORM_ADMIN` | Voller Zugriff auf alle Mandanten |
|
||||
| `TENANT_ADMIN` | Voller Zugriff auf eigenen Mandanten |
|
||||
| `USER` | Lese-/Schreibzugriff auf eigene Daten |
|
||||
|
||||
### 5.4 Multi-Tenancy
|
||||
|
||||
**Jeder CRM-Request muss mandanten-bezogen sein!**
|
||||
|
||||
Der `tenantId` kommt aus dem JWT-Payload. Alle Datenbankabfragen muessen
|
||||
nach `tenantId` gefiltert werden:
|
||||
|
||||
```sql
|
||||
-- IMMER so:
|
||||
SELECT * FROM app_crm.contacts WHERE tenant_id = :tenantId;
|
||||
|
||||
-- NIEMALS so:
|
||||
SELECT * FROM app_crm.contacts; -- Datenleck!
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Datenbank-Schema (Empfehlung)
|
||||
|
||||
Verwende ein eigenes Prisma-Schema unter `packages/crm-service/prisma/crm.schema.prisma`.
|
||||
|
||||
**Schema-Name:** `app_crm`
|
||||
|
||||
```prisma
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
output = "../node_modules/.prisma/crm-client"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
url = env("DATABASE_URL")
|
||||
directUrl = env("DATABASE_URL_DIRECT")
|
||||
schemas = ["app_crm"]
|
||||
}
|
||||
```
|
||||
|
||||
**Wichtig:**
|
||||
- Eigener Prisma-Client-Output (`crm-client`), damit kein Konflikt mit dem Core-Client
|
||||
- Eigenes Schema `app_crm` — keine Tabellen im `public` Schema anlegen
|
||||
- `tenantId` als Pflichtfeld in jeder Tabelle (Multi-Tenancy)
|
||||
- `createdBy` / `updatedBy` als UUID fuer Audit-Trail (User-IDs aus Core)
|
||||
|
||||
### 6.1 Referenz: Bestehende Tenant-Schema-Entwuerfe
|
||||
|
||||
Im Core-Service existiert bereits ein Entwurf unter
|
||||
`packages/core-service/prisma/tenant.schema.prisma` mit Modellen fuer
|
||||
`Contact` und `Activity`. Diese dienen als Referenz — du kannst sie
|
||||
uebernehmen oder anpassen.
|
||||
|
||||
**Contact-Modell (Referenz):**
|
||||
- Typen: PERSON, ORGANIZATION
|
||||
- Felder: Name, Firma, Kontaktdaten, Adresse, Tags, Notizen
|
||||
- Tracking: `createdBy`, `updatedBy` (User-UUIDs)
|
||||
|
||||
**Activity-Modell (Referenz):**
|
||||
- Typen: NOTE, CALL, EMAIL, MEETING, TASK
|
||||
- Felder: Subject, Beschreibung, Zeitplanung, Status
|
||||
|
||||
---
|
||||
|
||||
## 7. Docker-Integration
|
||||
|
||||
### 7.1 docker-compose.crm.yml (Beispiel)
|
||||
|
||||
Erstelle diese Datei im Projekt-Root:
|
||||
|
||||
```yaml
|
||||
# docker-compose.crm.yml
|
||||
# Start: docker compose -f docker-compose.yml -f docker-compose.crm.yml up -d
|
||||
|
||||
services:
|
||||
crm:
|
||||
build:
|
||||
context: ./packages/crm-service
|
||||
dockerfile: Dockerfile
|
||||
target: development
|
||||
container_name: insight-crm
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- NODE_ENV=${NODE_ENV:-development}
|
||||
- APP_PORT=3100
|
||||
- DATABASE_URL=postgresql://${DB_USER:-insight}:${DB_PASSWORD}@pgbouncer:6432/${DB_NAME:-platform_core}?schema=app_crm
|
||||
- DATABASE_URL_DIRECT=postgresql://${DB_USER:-insight}:${DB_PASSWORD}@postgres:5432/${DB_NAME:-platform_core}?schema=app_crm
|
||||
- REDIS_HOST=redis
|
||||
- REDIS_PORT=6379
|
||||
- REDIS_PASSWORD=${REDIS_PASSWORD:-}
|
||||
- JWT_PUBLIC_KEY_PATH=/app/keys/jwt-public.pem
|
||||
volumes:
|
||||
- ./packages/crm-service:/app
|
||||
- /app/node_modules
|
||||
- ./.keys/jwt-public.pem:/app/keys/jwt-public.pem:ro
|
||||
networks:
|
||||
- insight-web
|
||||
- insight-db
|
||||
- insight-cache
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.crm.rule=PathPrefix(`/api/v1/crm`)"
|
||||
- "traefik.http.routers.crm.entrypoints=web"
|
||||
- "traefik.http.services.crm.loadbalancer.server.port=3100"
|
||||
- "traefik.http.routers.crm.middlewares=cors-headers@file,security-headers@file"
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3100/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 15s
|
||||
depends_on:
|
||||
pgbouncer:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
|
||||
networks:
|
||||
insight-web:
|
||||
external: true
|
||||
insight-db:
|
||||
external: true
|
||||
insight-cache:
|
||||
external: true
|
||||
```
|
||||
|
||||
### 7.2 Traefik-Route
|
||||
|
||||
| Route-Prefix | Service | Port |
|
||||
|-------------|---------|------|
|
||||
| `/api/v1/crm/*` | crm | 3100 |
|
||||
|
||||
**Bereits belegte Routen:**
|
||||
- `/api/*` → core-service:3000
|
||||
- `/health` → core-service:3000
|
||||
- `/*` → frontend:8080 (Catch-all, Priority 1)
|
||||
|
||||
**Wichtig:** Die CRM-Route `/api/v1/crm` hat hoehere Prioritaet als der
|
||||
Core-Catch-all `/api`, weil sie spezifischer ist. Traefik matched die
|
||||
laengste Prefix-Uebereinstimmung zuerst.
|
||||
|
||||
### 7.3 Port-Konvention
|
||||
|
||||
| Service | Port |
|
||||
|---------|------|
|
||||
| Core-Service | 3000 |
|
||||
| CRM-Service | **3100** |
|
||||
| Frontend | 8080 |
|
||||
|
||||
---
|
||||
|
||||
## 8. NestJS-Konfiguration (Orientierung am Core-Service)
|
||||
|
||||
### 8.1 Tech-Stack (identisch zum Core)
|
||||
|
||||
| Komponente | Version | Zweck |
|
||||
|-----------|---------|-------|
|
||||
| NestJS | >= 10 | Framework |
|
||||
| TypeScript | strict | Sprache |
|
||||
| Prisma | >= 6 | ORM |
|
||||
| ioredis | >= 5 | Redis-Client |
|
||||
| passport-jwt | latest | JWT-Validierung |
|
||||
| class-validator | latest | DTO-Validierung |
|
||||
| class-transformer | latest | Typ-Transformation |
|
||||
|
||||
### 8.2 main.ts Konfiguration (kopiere das Pattern)
|
||||
|
||||
```typescript
|
||||
// Wichtige Einstellungen (gleich wie Core):
|
||||
// - helmet() fuer Security-Headers
|
||||
// - cookieParser() fuer Cookies
|
||||
// - JSON Body Limit: 12MB
|
||||
// - Global Prefix: api/v1/crm (ACHTUNG: nicht api/v1 — das ist der Core!)
|
||||
// - Global ValidationPipe (whitelist, forbidNonWhitelisted, transform)
|
||||
// - CORS mit credentials: true
|
||||
// - Port: 3100
|
||||
```
|
||||
|
||||
**ACHTUNG beim Global Prefix:**
|
||||
```typescript
|
||||
// RICHTIG:
|
||||
app.setGlobalPrefix('api/v1/crm', { exclude: ['/health'] });
|
||||
|
||||
// FALSCH (wuerde Core-Routes ueberlagern):
|
||||
app.setGlobalPrefix('api/v1');
|
||||
```
|
||||
|
||||
### 8.3 Swagger
|
||||
|
||||
Stelle Swagger unter `/api/v1/crm/docs` bereit (nur Development).
|
||||
|
||||
---
|
||||
|
||||
## 9. CI/CD (spaeter)
|
||||
|
||||
Die CI/CD Pipeline wird **spaeter separat** erweitert. Fokussiere dich
|
||||
auf die Entwicklung. Die Pipeline-Erweiterung beinhaltet:
|
||||
|
||||
1. Neuer CI-Job `crm-service` (analog zu `core-service`)
|
||||
2. Docker-Image: `git.xinion.lan/gitadmin/insight-crm:TAG`
|
||||
3. Deploy-Job erweitert um CRM-Container
|
||||
|
||||
---
|
||||
|
||||
## 10. Konventionen
|
||||
|
||||
### 10.1 Git
|
||||
|
||||
- **Branch:** `feature/crm-service` (von `develop` abzweigen)
|
||||
- **Commits:** Conventional Commits mit `feat(crm):`, `fix(crm):`, etc.
|
||||
- **Kein Push auf `main`** — nur ueber Merge von `develop`
|
||||
|
||||
### 10.2 Code-Style
|
||||
|
||||
- **Strict TypeScript** — kein `any`
|
||||
- **ESLint + Prettier** (gleiche Config wie Core)
|
||||
- **DTOs** mit class-validator fuer alle Inputs
|
||||
- **Guards** fuer Authentifizierung und Autorisierung
|
||||
|
||||
### 10.3 Datenbank
|
||||
|
||||
- Schema: `app_crm`
|
||||
- Tabellen-Prefix: keiner (Schema ist schon der Namespace)
|
||||
- Migrations: `npx prisma migrate dev --schema=prisma/crm.schema.prisma`
|
||||
- Seed: `npx ts-node prisma/seed.ts`
|
||||
|
||||
### 10.4 Redis-Keys
|
||||
|
||||
```
|
||||
app:crm:{feature}:{id}
|
||||
```
|
||||
|
||||
Beispiele:
|
||||
```
|
||||
app:crm:pipeline:config:tenant_acme
|
||||
app:crm:cache:contacts:tenant_acme:page1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. API-Design (Empfehlung)
|
||||
|
||||
Alle CRM-Endpunkte unter `/api/v1/crm/`:
|
||||
|
||||
```
|
||||
# Kontakte
|
||||
GET /api/v1/crm/contacts — Liste (paginiert, filterbar)
|
||||
POST /api/v1/crm/contacts — Erstellen
|
||||
GET /api/v1/crm/contacts/:id — Detail
|
||||
PATCH /api/v1/crm/contacts/:id — Aktualisieren
|
||||
DELETE /api/v1/crm/contacts/:id — Loeschen
|
||||
|
||||
# Aktivitaeten
|
||||
GET /api/v1/crm/activities — Liste
|
||||
POST /api/v1/crm/activities — Erstellen
|
||||
GET /api/v1/crm/activities/:id — Detail
|
||||
PATCH /api/v1/crm/activities/:id — Aktualisieren
|
||||
DELETE /api/v1/crm/activities/:id — Loeschen
|
||||
|
||||
# Pipelines (Sales-Pipeline)
|
||||
GET /api/v1/crm/pipelines — Liste
|
||||
POST /api/v1/crm/pipelines — Erstellen
|
||||
...
|
||||
|
||||
# Deals
|
||||
GET /api/v1/crm/deals — Liste
|
||||
POST /api/v1/crm/deals — Erstellen
|
||||
...
|
||||
|
||||
# Health
|
||||
GET /health — Health-Check (public)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 12. Zusammenfassung der Regeln
|
||||
|
||||
1. **Arbeite NUR in `packages/crm-service/` und `docker-compose.crm.yml`**
|
||||
2. **Aendere NICHTS am Core-Service, Frontend oder der Infrastruktur**
|
||||
3. **Eigenes Prisma-Schema** mit eigenem Client-Output
|
||||
4. **Eigener Docker-Container** auf Port 3100
|
||||
5. **JWT-Validierung** mit dem shared Public Key (RS256)
|
||||
6. **Multi-Tenancy** — jede Query filtert nach `tenantId` aus dem JWT
|
||||
7. **Redis-Keys** mit Prefix `app:crm:`
|
||||
8. **Git-Branch:** `feature/crm-service` von `develop`
|
||||
9. **Conventional Commits:** `feat(crm):`, `fix(crm):`
|
||||
10. **Strict TypeScript** — kein `any`, volle Validierung
|
||||
|
||||
---
|
||||
|
||||
## 13. Schnellstart
|
||||
|
||||
```bash
|
||||
# 1. Branch erstellen
|
||||
git checkout develop
|
||||
git checkout -b feature/crm-service
|
||||
|
||||
# 2. Package anlegen
|
||||
mkdir -p packages/crm-service
|
||||
cd packages/crm-service
|
||||
npm init -y
|
||||
|
||||
# 3. NestJS installieren
|
||||
npm install @nestjs/common @nestjs/core @nestjs/config @nestjs/platform-express
|
||||
npm install @nestjs/passport @nestjs/jwt passport passport-jwt
|
||||
npm install @prisma/client ioredis class-validator class-transformer
|
||||
npm install helmet cookie-parser
|
||||
npm install -D typescript @types/node @nestjs/cli prisma
|
||||
npm install -D @types/passport-jwt @types/cookie-parser
|
||||
|
||||
# 4. Prisma initialisieren
|
||||
npx prisma init --schema=prisma/crm.schema.prisma
|
||||
|
||||
# 5. Schema erstellen (app_crm)
|
||||
# ... (siehe Abschnitt 6)
|
||||
|
||||
# 6. Migration ausfuehren
|
||||
npx prisma migrate dev --schema=prisma/crm.schema.prisma --name init
|
||||
|
||||
# 7. Entwickeln
|
||||
npm run start:dev
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
> **Fuer den neuen Chat:**
|
||||
> Oeffne dieses Dokument zu Beginn mit: *"Lies bitte `docs/CRM_HANDOFF.md`
|
||||
> und `docs/INTEGRATION.md` bevor du mit der Entwicklung startest."*
|
||||
BIN
docs/INSIGHT_Konzept_v1.0.docx
Normal file
BIN
docs/INSIGHT_Konzept_v1.0.docx
Normal file
Binary file not shown.
746
docs/INTEGRATION.md
Normal file
746
docs/INTEGRATION.md
Normal file
|
|
@ -0,0 +1,746 @@
|
|||
# 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 <access_token>
|
||||
Content-Type: application/json
|
||||
X-Tenant-ID: <tenant-uuid> # Optional: fuer Mandanten-spezifische Operationen
|
||||
X-Request-ID: <uuid> # 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 `<link rel="icon">` Tag im HTML-`<head>` 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.
|
||||
Loading…
Add table
Reference in a new issue