diff --git a/.DS_Store b/.DS_Store
index 5ceb50c..f54e6e7 100644
Binary files a/.DS_Store and b/.DS_Store differ
diff --git a/.env b/.env
index 85901cb..fc83495 100644
--- a/.env
+++ b/.env
@@ -27,15 +27,15 @@ LOG_LEVEL=debug
# DB_USERNAME=root
# DB_PASSWORD=
-# Secondary PostgreSQL Connection (for backend schema)
+# Secondary PostgreSQL Connection (for backend schema) - Local Docker
DB_CONNECTION2=pgsql
DB_HOST2=127.0.0.1
-DB_PORT2=5433
-DB_DATABASE2=risk_ingest_db
-DB_USERNAME2=risk_ingest_user
-DB_PASSWORD2=S0prast3r1a
+DB_PORT2=5432
+DB_DATABASE2=ingest_db
+DB_USERNAME2=ingest_user
+DB_PASSWORD2=ingest_pwd
-SESSION_DRIVER=database
+SESSION_DRIVER=file
SESSION_LIFETIME=120
SESSION_ENCRYPT=false
SESSION_PATH=/
@@ -43,9 +43,9 @@ SESSION_DOMAIN=null
BROADCAST_CONNECTION=log
FILESYSTEM_DISK=local
-QUEUE_CONNECTION=database
+QUEUE_CONNECTION=sync
-CACHE_STORE=database
+CACHE_STORE=file
# CACHE_PREFIX=
MEMCACHED_HOST=127.0.0.1
diff --git a/backup_backend_20251203_101741.dump b/backup_backend_20251203_101741.dump
new file mode 100644
index 0000000..13846d7
Binary files /dev/null and b/backup_backend_20251203_101741.dump differ
diff --git a/backup_devbackend_20251203_103857.dump b/backup_devbackend_20251203_103857.dump
new file mode 100644
index 0000000..68c2886
Binary files /dev/null and b/backup_devbackend_20251203_103857.dump differ
diff --git a/backup_public_20251203_101723.dump b/backup_public_20251203_101723.dump
new file mode 100644
index 0000000..5222b51
Binary files /dev/null and b/backup_public_20251203_101723.dump differ
diff --git a/config/database.php b/config/database.php
index 22117ed..6fca29e 100644
--- a/config/database.php
+++ b/config/database.php
@@ -86,10 +86,10 @@ return [
'driver' => 'pgsql',
'url' => env('DB_URL'),
'host' => env('DB_HOST2', '127.0.0.1'),
- 'port' => env('DB_PORT2', '5433'),
- 'database' => env('DB_DATABASE2', 'risk_ingest_db'),
- 'username' => env('DB_USERNAME2', 'risk_ingest_user'),
- 'password' => env('DB_PASSWORD2', ''),
+ 'port' => env('DB_PORT2', '5432'),
+ 'database' => env('DB_DATABASE2', 'ingest_db'),
+ 'username' => env('DB_USERNAME2', 'ingest_user'),
+ 'password' => env('DB_PASSWORD2', 'ingest_pwd'),
'charset' => env('DB_CHARSET', 'utf8'),
'prefix' => '',
'prefix_indexes' => true,
@@ -101,9 +101,9 @@ return [
'driver' => env('DB_CONNECTION2'),
'host' => env('DB_HOST2', '127.0.0.1'),
'port' => env('DB_PORT2', '5432'),
- 'database' => env('DB_DATABASE2', 'laravel'),
- 'username' => env('DB_USERNAME2', 'root'),
- 'password' => env('DB_PASSWORD2', ''),
+ 'database' => env('DB_DATABASE2', 'ingest_db'),
+ 'username' => env('DB_USERNAME2', 'ingest_user'),
+ 'password' => env('DB_PASSWORD2', 'ingest_pwd'),
'charset' => env('DB_CHARSET', 'utf8'),
'prefix' => '',
'prefix_indexes' => true,
@@ -115,9 +115,9 @@ return [
'driver' => env('DB_CONNECTION2'),
'host' => env('DB_HOST2', '127.0.0.1'),
'port' => env('DB_PORT2', '5432'),
- 'database' => env('DB_DATABASE2', 'laravel'),
- 'username' => env('DB_USERNAME2', 'root'),
- 'password' => env('DB_PASSWORD2', ''),
+ 'database' => env('DB_DATABASE2', 'ingest_db'),
+ 'username' => env('DB_USERNAME2', 'ingest_user'),
+ 'password' => env('DB_PASSWORD2', 'ingest_pwd'),
'charset' => env('DB_CHARSET', 'utf8'),
'prefix' => '',
'prefix_indexes' => true,
diff --git a/docs/api-documentation.md b/docs/api-documentation.md
new file mode 100644
index 0000000..edca5f2
--- /dev/null
+++ b/docs/api-documentation.md
@@ -0,0 +1,999 @@
+# API-Dokumentation: Risk Intelligence Platform
+
+## ð Inhaltsverzeichnis
+
+1. [Ãbersicht](#ÃŒbersicht)
+2. [API-Spezifikation](#api-spezifikation)
+3. [Authentication](#authentication)
+4. [Endpoints](#endpoints)
+5. [Datenmodelle](#datenmodelle)
+6. [Beispiele](#beispiele)
+7. [Error Handling](#error-handling)
+8. [Rate Limiting](#rate-limiting)
+9. [Changelog](#changelog)
+
+---
+
+## Ãbersicht
+
+Die **Trusted AI Analyst Data API** stellt Daten fÃŒr das Analyst Dashboard, Transaction Review, Company Search und Company Drill-Down bereit.
+
+### API-Version
+
+**Version:** 1.0.0
+**Format:** JSON
+**Authentifizierung:** Session-basiert (Laravel Session Cookie)
+
+### Base URLs
+
+| Environment | URL |
+|-------------|-----|
+| **Development** | `http://trusted_ai.test/api` |
+| **Production** | `https://afc.trai.sft.comstack.de/api` |
+
+### OpenAPI Spezifikation
+
+Die vollstÀndige API-Spezifikation ist in [swagger.yaml](../swagger.yaml) dokumentiert.
+
+**Swagger UI:** Die Spezifikation kann mit [Swagger Editor](https://editor.swagger.io) oder Swagger UI visualisiert werden.
+
+---
+
+## API-Spezifikation
+
+### API-Kategorien
+
+| Tag | Beschreibung | Endpoints |
+|-----|--------------|-----------|
+| **Dashboard** | KPIs und Alert-Ãbersichten | 1 Endpoint |
+| **Transactions** | Portfolio-weite Transaction Review | 2 Endpoints |
+| **Companies** | Company Discovery & Drill-Down | 4 Endpoints |
+
+**Gesamt:** 7 API-Endpoints
+
+---
+
+## Authentication
+
+### Session-basierte Authentifizierung
+
+Die API nutzt **Laravel Session Cookies** fÃŒr die Authentifizierung.
+
+```yaml
+securitySchemes:
+ sessionCookie:
+ type: apiKey
+ in: cookie
+ name: laravel_session
+```
+
+### Login-Flow
+
+1. **Login via Web-Interface:**
+```http
+POST /login HTTP/1.1
+Content-Type: application/x-www-form-urlencoded
+
+email=user@example.com&password=secret
+```
+
+2. **Session Cookie erhalten:**
+```http
+HTTP/1.1 302 Found
+Set-Cookie: laravel_session=eyJ....; Path=/; HttpOnly; SameSite=lax
+```
+
+3. **API-Request mit Cookie:**
+```http
+GET /api/dashboard/overview HTTP/1.1
+Cookie: laravel_session=eyJ....
+```
+
+### Authentifizierungs-Fehler
+
+```json
+HTTP/1.1 401 Unauthorized
+{
+ "message": "Unauthenticated."
+}
+```
+
+**Wichtig:** Alle API-Endpoints erfordern eine gÃŒltige Session!
+
+---
+
+## Endpoints
+
+### 1. Dashboard
+
+#### GET /dashboard/overview
+
+Liefert aggregierte KPIs und Alert-Ãbersichten fÃŒr das Dashboard.
+
+**Request:**
+```http
+GET /api/dashboard/overview HTTP/1.1
+Cookie: laravel_session=...
+```
+
+**Response:** `200 OK`
+```json
+{
+ "generatedAt": "2025-01-19T07:30:00Z",
+ "activeAnalysts": 24,
+ "totalTransactions": 312,
+ "totalVolume": 98765432.10,
+ "alertsToday": 56,
+ "averageAlertsPerAnalyst": 3,
+ "precisionRate": 84,
+ "activeAlerts": {
+ "count": 128,
+ "highRiskCount": 19
+ },
+ "riskSegments": [
+ {
+ "label": "Kritisch (â¥80)",
+ "count": 17,
+ "volume": 8900000.0
+ },
+ {
+ "label": "Hoch (60-79)",
+ "count": 42,
+ "volume": 15200000.0
+ },
+ {
+ "label": "Mittel (40-59)",
+ "count": 89,
+ "volume": 32100000.0
+ }
+ ],
+ "topCompanies": [
+ {
+ "companyId": 24,
+ "companyName": "Allianz SE",
+ "ticker": "ALV",
+ "sector": "Insurance",
+ "alerts": 6,
+ "alertVolume": 1450000.0,
+ "avgRiskScore": 82
+ }
+ ],
+ "runbooksExecutedToday": 41
+}
+```
+
+---
+
+### 2. Transactions
+
+#### GET /transactions
+
+Liste alle Transaktionen mit globalen Filtern (Portfolio-weite Transaction Review).
+
+**Query Parameters:**
+
+| Parameter | Typ | Default | Beschreibung |
+|-----------|-----|---------|--------------|
+| `search` | string | - | Match gegen Reference, Counterparty, Company |
+| `status` | enum | `all` | `all`, `true_positive`, `false_positive`, `cleared` |
+| `page` | integer | `1` | Seiten-Nummer (min: 1) |
+| `perPage` | integer | `12` | Items pro Seite (min: 1, max: 100) |
+
+**Request:**
+```http
+GET /api/transactions?status=true_positive&page=1&perPage=12 HTTP/1.1
+Cookie: laravel_session=...
+```
+
+**Response:** `200 OK`
+```json
+{
+ "filters": {
+ "statusOptions": [
+ {
+ "value": "true_positive",
+ "label": "BestÀtigte Treffer"
+ },
+ {
+ "value": "false_positive",
+ "label": "Fehlalarme"
+ },
+ {
+ "value": "cleared",
+ "label": "Freigegeben"
+ }
+ ],
+ "perPage": 12
+ },
+ "metrics": {
+ "total": {
+ "count": 312,
+ "amount": 98765432.10
+ },
+ "byStatus": {
+ "true_positive": {
+ "count": 42,
+ "amount": 15200000.0
+ },
+ "false_positive": {
+ "count": 89,
+ "amount": 32100000.0
+ },
+ "cleared": {
+ "count": 181,
+ "amount": 51465432.10
+ }
+ }
+ },
+ "data": [
+ {
+ "id": 512,
+ "company": {
+ "id": 12,
+ "name": "Allianz",
+ "legalName": "Allianz SE",
+ "ticker": "ALV",
+ "sector": "Insurance",
+ "country": "Germany",
+ "headquarters": "Munich",
+ "kycRiskLevel": "high",
+ "summary": "Multinational insurance provider with EMEA focus."
+ },
+ "counterparty": "Alpine Holdings Ltd.",
+ "counterpartyCountry": "Switzerland",
+ "status": "true_positive",
+ "statusLabel": "BestÀtigter Treffer",
+ "requiresReview": true,
+ "riskScore": 87,
+ "amount": 245000.75,
+ "currency": "EUR",
+ "reference": "PAY-2024-10-1942",
+ "channel": "SWIFT",
+ "executedAt": "2025-01-18T09:14:00Z",
+ "flaggedReason": "Counterparty on sanctions watchlist"
+ }
+ ],
+ "pagination": {
+ "page": 1,
+ "perPage": 12,
+ "total": 128,
+ "lastPage": 11
+ },
+ "selectedTransactionId": null,
+ "selectedTransaction": null
+}
+```
+
+---
+
+#### GET /transactions/{transactionId}
+
+Hole detaillierte Transaction Case File.
+
+**Path Parameters:**
+
+| Parameter | Typ | Beschreibung |
+|-----------|-----|--------------|
+| `transactionId` | integer | Transaction ID |
+
+**Request:**
+```http
+GET /api/transactions/512 HTTP/1.1
+Cookie: laravel_session=...
+```
+
+**Response:** `200 OK`
+```json
+{
+ "id": 512,
+ "company": { ... },
+ "counterparty": "Alpine Holdings Ltd.",
+ "status": "true_positive",
+ "statusLabel": "BestÀtigter Treffer",
+ "requiresReview": true,
+ "riskScore": 87,
+ "amount": 245000.75,
+ "currency": "EUR",
+ "reference": "PAY-2024-10-1942",
+ "channel": "SWIFT",
+ "executedAt": "2025-01-18T09:14:00Z",
+ "flaggedBy": "Screening Engine",
+ "flaggedReason": "Counterparty matched to EU sanctions list",
+ "signals": [
+ {
+ "type": "Adverse Media",
+ "value": "Enforcement action reported in 2024-11",
+ "weight": 0.8
+ },
+ {
+ "type": "Sanctions",
+ "value": "EU Sanctions List Match",
+ "weight": 1.0
+ }
+ ]
+}
+```
+
+**Errors:**
+- `401 Unauthorized` - Session ungÃŒltig
+- `404 Not Found` - Transaction existiert nicht
+
+---
+
+### 3. Companies
+
+#### GET /companies/search
+
+Suche Companies und erhalte Screening-Ãbersicht.
+
+**Query Parameters:**
+
+| Parameter | Typ | Default | Beschreibung |
+|-----------|-----|---------|--------------|
+| `q` | string | - | Freitext-Suche (Name, Legal Name, Ticker, Sector) |
+| `limit` | integer | `6` | Max. Ergebnisse (min: 1, max: 25) |
+
+**Request:**
+```http
+GET /api/companies/search?q=Allianz&limit=6 HTTP/1.1
+Cookie: laravel_session=...
+```
+
+**Response:** `200 OK`
+```json
+{
+ "overview": {
+ "totalCompanies": 40,
+ "openAlerts": 112,
+ "openAlertVolume": 5640000.0,
+ "averageRiskScore": 71,
+ "watchlistHits": 9,
+ "automationShare": 82
+ },
+ "results": [
+ {
+ "id": 12,
+ "name": "Allianz",
+ "legalName": "Allianz SE",
+ "ticker": "ALV",
+ "sector": "Insurance",
+ "country": "Germany",
+ "headquarters": "Munich",
+ "kycRiskLevel": "high",
+ "summary": "Multinational insurance provider with EMEA focus.",
+ "alertCount": 7,
+ "alertVolume": 980000.0,
+ "alertRiskScore": 79,
+ "latestAlert": {
+ "transactionId": 731,
+ "counterparty": "Baltic Commodities LLC",
+ "executedAt": "2025-01-17T11:48:00Z",
+ "channel": "SWIFT",
+ "flaggedReason": "Pattern matches sanctions typology",
+ "riskScore": 88
+ }
+ }
+ ],
+ "meta": {
+ "query": "Allianz",
+ "resultCount": 6,
+ "limit": 6
+ }
+}
+```
+
+---
+
+#### GET /companies/{companyId}
+
+Hole Company-Profil.
+
+**Path Parameters:**
+
+| Parameter | Typ | Beschreibung |
+|-----------|-----|--------------|
+| `companyId` | integer | Company ID |
+
+**Request:**
+```http
+GET /api/companies/12 HTTP/1.1
+Cookie: laravel_session=...
+```
+
+**Response:** `200 OK`
+```json
+{
+ "id": 12,
+ "name": "Allianz",
+ "legalName": "Allianz SE",
+ "ticker": "ALV",
+ "sector": "Insurance",
+ "country": "Germany",
+ "headquarters": "Munich",
+ "kycRiskLevel": "high",
+ "summary": "Multinational insurance provider with EMEA focus.",
+ "createdAt": "2024-10-15T08:30:00Z",
+ "updatedAt": "2025-01-18T14:22:00Z"
+}
+```
+
+**Errors:**
+- `401 Unauthorized` - Session ungÃŒltig
+- `404 Not Found` - Company existiert nicht
+
+---
+
+#### GET /companies/{companyId}/transactions
+
+Liste alle Transactions fÃŒr eine Company.
+
+**Path Parameters:**
+
+| Parameter | Typ | Beschreibung |
+|-----------|-----|--------------|
+| `companyId` | integer | Company ID |
+
+**Query Parameters:**
+
+| Parameter | Typ | Default | Beschreibung |
+|-----------|-----|---------|--------------|
+| `status` | enum | `all` | `all`, `true_positive`, `false_positive`, `cleared` |
+| `channel` | string | `all` | Channel-Filter (z.B. `SWIFT`, `SEPA`) |
+| `page` | integer | `1` | Seiten-Nummer |
+| `perPage` | integer | `10` | Items pro Seite (min: 1, max: 100) |
+
+**Request:**
+```http
+GET /api/companies/12/transactions?status=true_positive&page=1&perPage=10 HTTP/1.1
+Cookie: laravel_session=...
+```
+
+**Response:** `200 OK`
+```json
+{
+ "company": {
+ "id": 12,
+ "name": "Allianz",
+ "legalName": "Allianz SE",
+ "ticker": "ALV",
+ "sector": "Insurance",
+ "country": "Germany",
+ "headquarters": "Munich",
+ "kycRiskLevel": "high",
+ "summary": "Multinational insurance provider..."
+ },
+ "filters": {
+ "statusOptions": [
+ {
+ "value": "true_positive",
+ "label": "BestÀtigte Treffer"
+ }
+ ],
+ "channelOptions": [
+ {
+ "value": "SWIFT",
+ "label": "SWIFT"
+ },
+ {
+ "value": "SEPA",
+ "label": "SEPA"
+ }
+ ]
+ },
+ "metrics": {
+ "totalCount": 96,
+ "totalVolume": 7200000.0,
+ "openAlerts": {
+ "count": 12,
+ "amount": 1850000.0
+ },
+ "highRiskShare": 28,
+ "last30Days": {
+ "count": 15,
+ "amount": 980000.0
+ },
+ "byStatus": {
+ "true_positive": {
+ "count": 12,
+ "amount": 1850000.0
+ },
+ "false_positive": {
+ "count": 24,
+ "amount": 2100000.0
+ },
+ "cleared": {
+ "count": 60,
+ "amount": 3250000.0
+ }
+ }
+ },
+ "data": [
+ {
+ "id": 877,
+ "company": { ... },
+ "counterparty": "Alpine Holdings Ltd.",
+ "status": "true_positive",
+ "riskScore": 87,
+ "amount": 245000.75,
+ "currency": "EUR",
+ "reference": "PAY-2024-10-1942",
+ "channel": "SWIFT",
+ "executedAt": "2025-01-18T09:14:00Z"
+ }
+ ],
+ "pagination": {
+ "page": 1,
+ "perPage": 10,
+ "total": 12,
+ "lastPage": 2
+ },
+ "selectedTransactionId": null,
+ "selectedTransaction": null,
+ "recentAlerts": [
+ {
+ "id": 911,
+ "counterparty": "Northbridge Trading Ltd.",
+ "executedAt": "2025-01-18T14:52:00Z",
+ "channel": "SWIFT",
+ "status": "true_positive",
+ "statusLabel": "BestÀtigter Treffer",
+ "riskScore": 92
+ }
+ ]
+}
+```
+
+**Errors:**
+- `401 Unauthorized` - Session ungÃŒltig
+- `404 Not Found` - Company nicht gefunden oder keine Transactions
+
+---
+
+#### GET /companies/{companyId}/transactions/{transactionId}
+
+Hole Transaction Case File mit Company-Context und History.
+
+**Path Parameters:**
+
+| Parameter | Typ | Beschreibung |
+|-----------|-----|--------------|
+| `companyId` | integer | Company ID |
+| `transactionId` | integer | Transaction ID |
+
+**Request:**
+```http
+GET /api/companies/12/transactions/877 HTTP/1.1
+Cookie: laravel_session=...
+```
+
+**Response:** `200 OK`
+```json
+{
+ "id": 877,
+ "company": { ... },
+ "counterparty": "Alpine Holdings Ltd.",
+ "status": "true_positive",
+ "statusLabel": "BestÀtigter Treffer",
+ "requiresReview": true,
+ "riskScore": 87,
+ "amount": 245000.75,
+ "currency": "EUR",
+ "reference": "PAY-2024-10-1942",
+ "channel": "SWIFT",
+ "executedAt": "2025-01-18T09:14:00Z",
+ "flaggedBy": "Screening Engine",
+ "flaggedReason": "Counterparty matched to EU sanctions list",
+ "signals": [
+ {
+ "type": "Adverse Media",
+ "value": "Enforcement action reported in 2024-11",
+ "weight": 0.8
+ }
+ ],
+ "recommendedActions": [
+ {
+ "title": "Verdachtsmeldung vorbereiten",
+ "description": "Erstellen Sie den Meldeentwurf fÃŒr die FIU und sichern Sie Belege."
+ },
+ {
+ "title": "Enhanced Due Diligence",
+ "description": "PrÌfen Sie zusÀtzliche Informationsquellen zur Counterparty."
+ }
+ ],
+ "counterpartyHistory": [
+ {
+ "id": 765,
+ "executedAt": "2024-12-22T15:37:00Z",
+ "channel": "SWIFT",
+ "reference": "PAY-2024-12-1187",
+ "amount": 99000.0,
+ "currency": "EUR",
+ "riskScore": 74
+ }
+ ]
+}
+```
+
+**Errors:**
+- `401 Unauthorized` - Session ungÃŒltig
+- `404 Not Found` - Transaction nicht gefunden fÃŒr diese Company
+
+---
+
+## Datenmodelle
+
+### Transaction Status
+
+```typescript
+enum TransactionStatus {
+ TRUE_POSITIVE = 'true_positive', // Kritisches Risiko
+ FALSE_POSITIVE = 'false_positive', // Hohes Risiko
+ CLEARED = 'cleared' // Geringes Risiko
+}
+```
+
+### KYC Risk Level
+
+```typescript
+enum KycRiskLevel {
+ LOW = 'low',
+ HIGH = 'high',
+ CRITICAL = 'critical'
+}
+```
+
+### Pagination Meta
+
+```json
+{
+ "page": 1,
+ "perPage": 12,
+ "total": 128,
+ "lastPage": 11
+}
+```
+
+### Count Amount Summary
+
+```json
+{
+ "count": 42,
+ "amount": 2750000.50
+}
+```
+
+### Transaction Signal
+
+```json
+{
+ "type": "Adverse Media",
+ "value": "Enforcement action reported in 2024-11",
+ "weight": 0.8
+}
+```
+
+### Recommended Action
+
+```json
+{
+ "title": "Verdachtsmeldung vorbereiten",
+ "description": "Erstellen Sie den Meldeentwurf fÃŒr die FIU..."
+}
+```
+
+---
+
+## Beispiele
+
+### cURL-Beispiele
+
+#### Login & Session Cookie erhalten
+
+```bash
+# Login
+curl -c cookies.txt -X POST http://trusted_ai.test/login \
+ -H "Content-Type: application/x-www-form-urlencoded" \
+ -d "email=user@example.com&password=secret"
+
+# Session Cookie ist jetzt in cookies.txt gespeichert
+```
+
+#### Dashboard Overview abrufen
+
+```bash
+curl -b cookies.txt http://trusted_ai.test/api/dashboard/overview
+```
+
+#### Transactions filtern
+
+```bash
+curl -b cookies.txt "http://trusted_ai.test/api/transactions?status=true_positive&page=1&perPage=12"
+```
+
+#### Company suchen
+
+```bash
+curl -b cookies.txt "http://trusted_ai.test/api/companies/search?q=Allianz&limit=6"
+```
+
+#### Company Transactions abrufen
+
+```bash
+curl -b cookies.txt "http://trusted_ai.test/api/companies/12/transactions?status=all&page=1"
+```
+
+---
+
+### JavaScript (Fetch API)
+
+```javascript
+// Session Cookie wird automatisch vom Browser gesendet
+
+// Dashboard Overview
+const overview = await fetch('/api/dashboard/overview', {
+ credentials: 'include' // Wichtig: Session Cookie mitsenden
+}).then(r => r.json());
+
+console.log(overview);
+
+// Transactions mit Filter
+const transactions = await fetch('/api/transactions?status=true_positive&page=1&perPage=12', {
+ credentials: 'include'
+}).then(r => r.json());
+
+console.log(transactions.data);
+
+// Company Search
+const companies = await fetch('/api/companies/search?q=Allianz', {
+ credentials: 'include'
+}).then(r => r.json());
+
+console.log(companies.results);
+```
+
+---
+
+### TypeScript Types
+
+```typescript
+// Dashboard Overview Response
+interface DashboardOverview {
+ generatedAt: string;
+ activeAnalysts: number;
+ totalTransactions: number;
+ totalVolume: number;
+ alertsToday: number;
+ averageAlertsPerAnalyst: number;
+ precisionRate: number;
+ activeAlerts: {
+ count: number;
+ highRiskCount: number;
+ };
+ riskSegments: RiskSegment[];
+ topCompanies: TopCompanyAlert[];
+ runbooksExecutedToday: number;
+}
+
+// Transaction Collection Response
+interface TransactionCollectionResponse {
+ filters: {
+ statusOptions: StatusOption[];
+ perPage: number;
+ };
+ metrics: TransactionMetrics;
+ data: TransactionPreview[];
+ pagination: PaginationMeta;
+ selectedTransactionId: number | null;
+ selectedTransaction: TransactionDetail | null;
+}
+
+// Company Search Response
+interface CompanySearchResponse {
+ overview: CompanySearchOverview;
+ results: CompanySearchResult[];
+ meta: {
+ query: string | null;
+ resultCount: number;
+ limit: number;
+ };
+}
+```
+
+---
+
+## Error Handling
+
+### Standard Error Response
+
+```json
+{
+ "message": "Error message",
+ "errors": {
+ "field": ["Validation error"]
+ }
+}
+```
+
+### HTTP Status Codes
+
+| Code | Bedeutung | Beschreibung |
+|------|-----------|--------------|
+| `200` | OK | Request erfolgreich |
+| `401` | Unauthorized | Session ungÃŒltig oder abgelaufen |
+| `404` | Not Found | Resource nicht gefunden |
+| `422` | Unprocessable Entity | Validierungsfehler |
+| `500` | Internal Server Error | Server-Fehler |
+
+### Beispiel: 401 Unauthorized
+
+```json
+HTTP/1.1 401 Unauthorized
+Content-Type: application/json
+
+{
+ "message": "Unauthenticated."
+}
+```
+
+**Aktion:** Redirect zu `/login`
+
+### Beispiel: 404 Not Found
+
+```json
+HTTP/1.1 404 Not Found
+Content-Type: application/json
+
+{
+ "message": "Company not found."
+}
+```
+
+### Beispiel: 422 Validation Error
+
+```json
+HTTP/1.1 422 Unprocessable Entity
+Content-Type: application/json
+
+{
+ "message": "The given data was invalid.",
+ "errors": {
+ "status": ["The selected status is invalid."],
+ "page": ["The page must be at least 1."]
+ }
+}
+```
+
+---
+
+## Rate Limiting
+
+### Aktueller Status
+
+**Aktuell:** Kein Rate Limiting implementiert.
+
+### Geplant (Future)
+
+```
+Rate Limit: 60 Requests pro Minute pro User
+Header: X-RateLimit-Limit, X-RateLimit-Remaining
+```
+
+**Response bei Ãberschreitung:**
+```json
+HTTP/1.1 429 Too Many Requests
+Content-Type: application/json
+Retry-After: 60
+
+{
+ "message": "Too many requests. Please try again later."
+}
+```
+
+---
+
+## Changelog
+
+### Version 1.0.0 (2025-01-19)
+
+**Initial Release**
+
+**Endpoints:**
+- â
`GET /dashboard/overview` - Dashboard KPIs
+- â
`GET /transactions` - Portfolio-wide Transactions
+- â
`GET /transactions/{id}` - Transaction Detail
+- â
`GET /companies/search` - Company Search
+- â
`GET /companies/{id}` - Company Profile
+- â
`GET /companies/{id}/transactions` - Company Transactions
+- â
`GET /companies/{id}/transactions/{id}` - Company Transaction Detail
+
+**Features:**
+- Session-basierte Authentifizierung
+- Pagination Support
+- Filter & Search
+- Metrics & Aggregationen
+- OpenAPI 3.1 Spezifikation
+
+---
+
+## Implementierungs-Status
+
+### â ïž Wichtig: API noch nicht implementiert!
+
+Die in diesem Dokument beschriebenen Endpoints sind **aktuell noch nicht implementiert**.
+
+**Status:**
+- â
OpenAPI Spezifikation vorhanden ([swagger.yaml](../swagger.yaml))
+- â API Routes noch nicht definiert (`routes/api.php` ist leer)
+- â API Controllers noch nicht erstellt
+- â API Responses noch nicht implementiert
+
+### NÀchste Schritte zur Implementierung
+
+1. **API Routes definieren:**
+```php
+// routes/api.php
+Route::middleware(['auth:sanctum'])->group(function () {
+ Route::get('/dashboard/overview', [DashboardController::class, 'overview']);
+ Route::get('/transactions', [TransactionController::class, 'index']);
+ Route::get('/transactions/{transaction}', [TransactionController::class, 'show']);
+ Route::get('/companies/search', [CompanyController::class, 'search']);
+ Route::get('/companies/{company}', [CompanyController::class, 'show']);
+ Route::get('/companies/{company}/transactions', [CompanyController::class, 'transactions']);
+});
+```
+
+2. **API Controllers erstellen:**
+```bash
+php artisan make:controller Api/DashboardController
+php artisan make:controller Api/TransactionController
+php artisan make:controller Api/CompanyController
+```
+
+3. **API Resources erstellen:**
+```bash
+php artisan make:resource TransactionResource
+php artisan make:resource CompanyResource
+```
+
+4. **Tests schreiben:**
+```bash
+php artisan make:test Api/DashboardTest
+php artisan make:test Api/TransactionTest
+php artisan make:test Api/CompanyTest
+```
+
+---
+
+## Zusammenfassung
+
+### API-Ãbersicht
+
+| Kategorie | Endpoints | Status |
+|-----------|-----------|--------|
+| Dashboard | 1 | â ïž Spezifiziert, nicht implementiert |
+| Transactions | 2 | â ïž Spezifiziert, nicht implementiert |
+| Companies | 4 | â ïž Spezifiziert, nicht implementiert |
+| **Gesamt** | **7** | - |
+
+### Datenmodelle
+
+- **DashboardOverview** - Dashboard-KPIs
+- **TransactionCollectionResponse** - Paginierte Transactions
+- **TransactionDetail** - Detaillierte Transaction
+- **CompanySearchResponse** - Company-Suchergebnisse
+- **CompanyDetail** - Company-Profil
+- **CompanyTransactionsResponse** - Company-spezifische Transactions
+
+### Authentifizierung
+
+**Session-basiert** via Laravel Session Cookie
+- Login erforderlich
+- Cookie-basierte Authentifizierung
+- CSRF-Protection
+
+---
+
+**Erstellt:** 2025-11-24
+**Version:** 1.0.0
+**Autor:** Risk Intelligence Platform Team
+**OpenAPI Spec:** [swagger.yaml](../swagger.yaml)
diff --git a/docs/architecture-overview.md b/docs/architecture-overview.md
new file mode 100644
index 0000000..61981d0
--- /dev/null
+++ b/docs/architecture-overview.md
@@ -0,0 +1,1010 @@
+# System-Architektur: Risk Intelligence Platform
+
+## ð Inhaltsverzeichnis
+
+1. [Ãbersicht](#ÃŒbersicht)
+2. [System-Diagramm](#system-diagramm)
+3. [Technologie-Stack](#technologie-stack)
+4. [Datenbank-Architektur](#datenbank-architektur)
+5. [Datenfluss & ETL-Pipeline](#datenfluss--etl-pipeline)
+6. [Applikations-Schichten](#applikations-schichten)
+7. [Frontend-Architektur](#frontend-architektur)
+8. [Backend-Integration](#backend-integration)
+9. [Scheduling & Automation](#scheduling--automation)
+10. [Sicherheit & Authentication](#sicherheit--authentication)
+11. [Deployment-Architektur](#deployment-architektur)
+
+---
+
+## Ãbersicht
+
+Die **Risk Intelligence Platform** ist eine Laravel-basierte Web-Applikation zur Analyse und Bewertung von Unternehmenstransaktionen hinsichtlich KYC (Know Your Customer) und Compliance-Risiken.
+
+### Kernfunktionen
+
+- â
**Unternehmenssuche & -bewertung** mit KYC Risk Levels
+- â
**Transaktionsanalyse** mit 139 Datenfeldern (37 Core + 102 JSONB)
+- â
**Automatische Backend-Synchronisation** (ETL-Pipeline)
+- â
**Risk Score Berechnung** basierend auf Multi-Faktoren-Analyse
+- â
**Compliance-Checks** (EU/OFAC/UK Sanctions, PEP, AML)
+- â
**Benutzer-Authentication** mit 2FA-UnterstÃŒtzung
+
+### Zielgruppe
+
+- Compliance-Teams
+- Risk Analysts
+- KYC-Spezialisten
+
+---
+
+## System-Diagramm
+
+```
+âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+â FRONTEND (Browser) â
+â Livewire Volt Components + Flux UI â
+âââââââââââââââââââââââââââ¬ââââââââââââââââââââââââââââââââââââââââââââââââ
+ â
+ âŒ
+âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+â LARAVEL APPLICATION â
+â âââââââââââââââââââ âââââââââââââââââââ âââââââââââââââââââââââ â
+â â Controllers â â Livewire Volt â â API Endpoints â â
+â â (Minimal) â â Components â â (Future) â â
+â ââââââââââ¬âââââââââ ââââââââââ¬âââââââââ âââââââââââââââââââââââ â
+â â â â
+â ⌠⌠â
+â âââââââââââââââââââââââââââââââââââââââââââââââ â
+â â Eloquent Models & Repositories â â
+â â Company â Transaction â User â â
+â ââââââââââââââââââââ¬âââââââââââââââââââââââââââ â
+â â â
+â âââââââââââŽââââââââââ â
+â ⌠⌠â
+â ââââââââââââââââââââ ââââââââââââââââââââ â
+â â Jobs/Queue â â Services â â
+â â - SyncDataPool â â - KycRiskCalc â â
+â â - Transform â â - DataExtract â â
+â ââââââââââââââââââââ ââââââââââââââââââââ â
+ââââââââââââââ¬âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ â
+ âŒ
+âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+â POSTGRESQL DATABASE (Port 5433) â
+â âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ â
+â â Schema: PUBLIC (Default Connection) â â
+â â âââââââââââââââ ââââââââââââââââââââ âââââââââââââââââââ â â
+â â â companies â â transactions â â backend_data_ â â â
+â â â â â (139 cols) â â pool â â â
+â â â - name âââ†- company_id â â â â â
+â â â - kyc_risk â â - risk_score â â - transaction_ â â â
+â â â - sector â â - 102 JSONB colsâ â id â â â
+â â âââââââââââââââ ââââââââââââââââââââ â - output_key â â â
+â â â - content â â â
+â â âââââââââââââââââââ â â
+â âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ â
+â â
+â âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ â
+â â Schema: BACKEND (Backend Connection) â â
+â â ââââââââââââââââââââ ââââââââââââââââââââââââââââââââââââ â â
+â â â transactions â â transaction_outputs â â â
+â â â â â â â â
+â â â - id âââ†- transaction_id â â â
+â â â - status â â - prompt_id â â â
+â â â - tx_amount â â - output_key â â â
+â â â - risk_score â â - content (JSONB) â â â
+â â ââââââââââââââââââââ ââââââââââââââââââââââââââââââââââââ â â
+â âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ â
+âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ â²
+ â
+ â (ETL Pipeline - Scheduled Jobs)
+ â
+ââââââââââââââŽâââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+â LARAVEL SCHEDULER (Cron) â
+â âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ â
+â â Every 6h (0:00, 6:00, 12:00, 18:00): â â
+â â â SyncBackendDataPool (Incremental) â â
+â â â â
+â â Every 6h (0:30, 6:30, 12:30, 18:30): â â
+â â â TransformDataPoolToProduction â â
+â â â â
+â â Sunday 3:00: â â
+â â â SyncBackendDataPool (Full Rebuild) â â
+â âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ â
+âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+```
+
+---
+
+## Technologie-Stack
+
+### Backend
+
+| Komponente | Version | Zweck |
+|-----------|---------|-------|
+| **PHP** | 8.4.14 | Runtime |
+| **Laravel Framework** | 12.x | Application Framework |
+| **PostgreSQL** | Latest | PrimÀre Datenbank |
+| **Laravel Fortify** | 1.x | Authentication |
+| **Livewire** | 3.x | Reactive Components |
+| **Livewire Volt** | 1.x | Single-File Components |
+
+### Frontend
+
+| Komponente | Version | Zweck |
+|-----------|---------|-------|
+| **Flux UI** | 2.x (Free) | Component Library |
+| **Tailwind CSS** | 4.x | Styling Framework |
+| **Alpine.js** | Latest (via Livewire) | JavaScript Interactivity |
+| **Vite** | Latest | Asset Bundling |
+
+### Development & Testing
+
+| Komponente | Version | Zweck |
+|-----------|---------|-------|
+| **Pest** | 4.x | Testing Framework |
+| **PHPUnit** | 12.x | Unit Testing |
+| **Laravel Pint** | 1.x | Code Formatting |
+| **Laravel Sail** | 1.x | Docker Development |
+| **Laravel Boost** | 1.4+ | MCP Server (Development) |
+
+### Infrastructure
+
+- **Docker** - Containerization
+- **Kubernetes** - Orchestration (k8s-cronjob.yaml)
+- **Cron** - Scheduling (Laravel Scheduler)
+- **Queue System** - Asynchronous Jobs
+
+---
+
+## Datenbank-Architektur
+
+### Verbindungen
+
+Die Applikation nutzt **eine PostgreSQL-Datenbank** mit **zwei Schemas**:
+
+```php
+// config/database.php
+
+'default' => 'pgsql_second', // Default: public schema
+
+'connections' => [
+ // Frontend Schema (Production Tables)
+ 'pgsql_second' => [
+ 'search_path' => 'public',
+ 'port' => env('DB_PORT2', 5432),
+ 'database' => env('DB_DATABASE2'),
+ ],
+
+ // Backend Schema (Source Data)
+ 'backend' => [
+ 'search_path' => 'backend',
+ 'port' => env('DB_PORT2', 5432),
+ 'database' => env('DB_DATABASE2'), // Same DB, different schema
+ ],
+]
+```
+
+### Schema: PUBLIC (Production)
+
+#### Companies Tabelle
+```sql
+CREATE TABLE public.companies (
+ id SERIAL PRIMARY KEY,
+ name VARCHAR(255) NOT NULL,
+ legal_name VARCHAR(255),
+ ticker VARCHAR(50),
+ sector VARCHAR(100),
+ country VARCHAR(2), -- ISO 3166-1 alpha-2
+ headquarters TEXT,
+ kyc_risk_level VARCHAR(20), -- low | high | critical
+ summary TEXT,
+ created_at TIMESTAMP,
+ updated_at TIMESTAMP
+);
+```
+
+#### Transactions Tabelle (139 Spalten)
+
+**Core Felder (37):**
+```sql
+CREATE TABLE public.transactions (
+ -- Identity & Relationships
+ id SERIAL PRIMARY KEY,
+ company_id INTEGER REFERENCES companies(id),
+ reference VARCHAR(255) UNIQUE NOT NULL,
+
+ -- Transaction Details
+ amount DECIMAL(15,2),
+ currency VARCHAR(3),
+ counterparty VARCHAR(255),
+ counterparty_country VARCHAR(2),
+ channel VARCHAR(50),
+ executed_at TIMESTAMP,
+
+ -- Risk Assessment
+ risk_score INTEGER, -- 0-255 normalized
+ status VARCHAR(50), -- true_positive | false_positive | cleared
+ requires_review BOOLEAN,
+ flagged_by VARCHAR(255),
+ flagged_reason TEXT,
+ signals JSONB,
+
+ -- Additional Entity Data
+ entity VARCHAR(255), -- Corporate entity name
+ counterparty_kyc_risk_level VARCHAR(20),
+
+ -- Risk Breakdown
+ transaction_risk_score INTEGER,
+ sanctions_risk_score INTEGER,
+ country_risk_score INTEGER,
+ pep_adverse_risk_score INTEGER,
+ corruption_risk_score INTEGER,
+
+ -- Timestamps
+ created_at TIMESTAMP,
+ updated_at TIMESTAMP,
+
+ -- ... 102 JSONB Columns (siehe unten)
+);
+```
+
+**JSONB Output Columns (102):**
+
+Alle `output_key` Werte aus `backend.transaction_outputs` werden als JSONB-Spalten gespeichert:
+
+
+VollstÀndige Liste der 102 JSONB Spalten (klicken zum Ausklappen)
+
+**Corporate Information:**
+- `corporate_summary`
+- `corporate_history`
+- `corporate_legalname`
+- `corporate_sector`
+- `corporate_HQ`
+- `corporate_keyexecs`
+- `corporate_shareholding`
+- `corporate_parentcompany`
+- `corporate_subsidiaries`
+- `corporate_countryofincorporation`
+- `corporate_ticker`
+- `corporate_counterparty`
+- `corporate_counterpartysector`
+- `corporate_counterpartycountry`
+- `corporate_counterpartysummary`
+- `corporate_counterpartyhistory`
+
+**Sanctions & Compliance:**
+- `corporate_eusanctions`
+- `corporate_ofacsanctions`
+- `corporate_uksanctions`
+- `corporate_pepexposure`
+- `corporate_AMLexposure`
+- `corporate_adverse`
+- `sanctions_circumvention`
+
+**Country Risk:**
+- `country_risk`
+- `country_name`
+- `country_iso2`
+- `country_iso3`
+- `country_cpi`
+- `country_euprivacy`
+- `country_dataprivacy`
+- `country_gdpr`
+- `country_sanctions`
+- `country_wgi`
+- `country_pep`
+
+**Corruption:**
+- `corruption_sector`
+- `corruption_country`
+- `corruption_relationship`
+
+**Financial & Transaction:**
+- `tranx_score`
+- `tranx_reasoning`
+- `tranx_amount`
+- `tranx_currency`
+- `tranx_date`
+- `tranx_counterparty`
+- `tranx_channel`
+- `financial_assessment`
+
+... und weitere 60+ Spalten fÃŒr detaillierte Analysen
+
+
+#### Backend Data Pool Tabelle
+```sql
+CREATE TABLE public.backend_data_pool (
+ id SERIAL PRIMARY KEY,
+
+ -- Foreign Keys (Backend Schema)
+ transaction_id INTEGER NOT NULL,
+ prompt_id INTEGER NOT NULL,
+
+ -- Transaction Core Data
+ corporate_entity VARCHAR(255),
+ tx_amount DECIMAL(15,2),
+ tx_currency VARCHAR(3),
+ tx_date DATE,
+ status VARCHAR(50),
+
+ -- Risk Scores
+ risk_score INTEGER, -- Backend risk_score (-100 to 100)
+
+ -- Output Data
+ output_key VARCHAR(255),
+ content JSONB,
+
+ -- Metadata
+ synced_at TIMESTAMP DEFAULT NOW(),
+
+ UNIQUE(transaction_id, prompt_id)
+);
+
+CREATE INDEX idx_backend_data_pool_transaction_id ON backend_data_pool(transaction_id);
+CREATE INDEX idx_backend_data_pool_output_key ON backend_data_pool(output_key);
+```
+
+### Schema: BACKEND (Source Data)
+
+#### Backend Transactions
+```sql
+CREATE TABLE backend.transactions (
+ id SERIAL PRIMARY KEY,
+ corporate_entity VARCHAR(255),
+ tx_amount DECIMAL(15,2),
+ tx_currency VARCHAR(3),
+ tx_date DATE,
+ status VARCHAR(50), -- pending | processing | done | failed
+ risk_score INTEGER, -- -100 to 100 (Backend Scale)
+ last_modified_at TIMESTAMP,
+ created_at TIMESTAMP
+);
+```
+
+#### Backend Transaction Outputs
+```sql
+CREATE TABLE backend.transaction_outputs (
+ id SERIAL PRIMARY KEY,
+ transaction_id INTEGER REFERENCES transactions(id),
+ prompt_id INTEGER,
+ output_key VARCHAR(255), -- z.B. "corporate_summary", "tranx_score"
+ content JSONB, -- LLM-Generated Output
+ created_at TIMESTAMP,
+
+ UNIQUE(transaction_id, prompt_id)
+);
+```
+
+---
+
+## Datenfluss & ETL-Pipeline
+
+### Dreistufiger Datenprozess
+
+```
+âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+â STUFE 0: Backend Processing (Extern) â
+â â
+â LLM Analysis â backend.transactions â
+â â backend.transaction_outputs â
+âââââââââââââââ¬ââââââââââââââââââââââââââââââââââââââââââââââââ
+ â
+ âŒ
+âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+â STUFE 1: Data Pool Sync â
+â â
+â Job: SyncBackendDataPool â
+â Schedule: Every 6h (Incremental) | Sunday 3am (Full) â
+â â
+â Source: backend.transactions â
+â + backend.transaction_outputs â
+â â
+â Target: public.backend_data_pool â
+â â
+â Process: â
+â 1. Query backend schema (WHERE status='done') â
+â 2. Join transactions + outputs â
+â 3. Batch insert into data pool (1000 records/batch) â
+â 4. Track sync timestamp â
+â â
+â Performance: â
+â - Full Sync: ~30-60s (7,471 records) â
+â - Incremental: ~5-10s (new records only) â
+âââââââââââââââ¬ââââââââââââââââââââââââââââââââââââââââââââââââ
+ â
+ âŒ
+âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+â STUFE 2: Production Transformation â
+â â
+â Job: TransformDataPoolToProduction â
+â Schedule: Every 6h at :30 (30min after Sync) â
+â â
+â Source: public.backend_data_pool â
+â â
+â Targets: public.companies â
+â + public.transactions â
+â â
+â Process: â
+â 1. Group by transaction_id â
+â 2. For each transaction: â
+â a) Extract/Update Company (by corporate_entity) â
+â - Calculate KYC Risk Level â
+â - Enrich with sector, country, HQ â
+â b) Create/Update Transaction â
+â - Map all 139 columns â
+â - Link to company_id â
+â - Transform risk_score (-100..100 â 0..255) â
+â 3. Batch process (100 records/batch) â
+â â
+â Features: â
+â - Idempotent (updateOrCreate) â
+â - Deduplication by reference â
+â - Risk Score Normalization â
+â â
+â Performance: â
+â - Initial: ~30-60s (74 transactions â ~70 companies) â
+â - Updates: ~5-10s â
+âââââââââââââââ¬ââââââââââââââââââââââââââââââââââââââââââââââââ
+ â
+ âŒ
+âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+â STUFE 3: Frontend Display (Real-time) â
+â â
+â Livewire Volt Components query: â
+â - public.companies â
+â - public.transactions â
+â â
+â No additional processing required â
+âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+```
+
+### Risk Score Transformation
+
+Backend nutzt eine Skala von **-100 bis 100**, Frontend **0 bis 255**:
+
+```php
+// Backend â Frontend Normalization
+$normalizedScore = (($backendScore + 100) / 200) * 255;
+
+// Beispiele:
+// Backend: -100 â Frontend: 0 (Sehr gut)
+// Backend: 0 â Frontend: 127 (Neutral)
+// Backend: 100 â Frontend: 255 (Sehr schlecht)
+```
+
+**Risk Level Mapping:**
+
+| Backend Score | Frontend Score | Risk Level | Transaction Status |
+|--------------|----------------|------------|-------------------|
+| -100 to 20 | 0 to 153 | `low` | `cleared` |
+| 20 to 80 | 153 to 229 | `high` | `false_positive` |
+| 80 to 100 | 229 to 255 | `critical` | `true_positive` |
+
+---
+
+## Applikations-Schichten
+
+### Layer Architecture
+
+```
+ââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+â PRESENTATION LAYER â
+â - Livewire Volt Components (resources/views/ â
+â livewire/) â
+â - Blade Templates â
+â - Flux UI Components â
+ââââââââââââââââââââ¬ââââââââââââââââââââââââââââââââââââ
+ â
+ âŒ
+ââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+â APPLICATION LAYER â
+â - Controllers (minimal, mostly Volt) â
+â - Livewire Actions (app/Livewire/Actions/) â
+â - Form Requests (validation) â
+ââââââââââââââââââââ¬ââââââââââââââââââââââââââââââââââââ
+ â
+ âŒ
+ââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+â DOMAIN LAYER â
+â - Eloquent Models (app/Models/) â
+â · Company â
+â · Transaction â
+â · User â
+â · Backend\Transaction â
+â · Backend\TransactionOutput â
+â - Repositories (app/Repositories/) â
+â · TransactionRepository â
+â - Services (app/Services/) â
+â · KycRiskCalculator â
+ââââââââââââââââââââ¬ââââââââââââââââââââââââââââââââââââ
+ â
+ âŒ
+ââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+â INFRASTRUCTURE LAYER â
+â - Jobs (app/Jobs/) â
+â · SyncBackendDataPool â
+â · TransformDataPoolToProduction â
+â - Commands (app/Console/Commands/) â
+â · SyncBackendDataPoolCommand â
+â · TransformDataPoolCommand â
+â · RebuildFromDataPoolCommand â
+â - Database Migrations â
+â - Schedulers (routes/console.php) â
+ââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+```
+
+---
+
+## Frontend-Architektur
+
+### Livewire Volt Components
+
+Die Applikation nutzt **Single-File Components** mit Livewire Volt:
+
+```php
+// resources/views/livewire/company-search.blade.php
+ Company::query()
+ ->when($this->search, fn($q) =>
+ $q->where('name', 'ilike', "%{$this->search}%")
+ )
+ ->limit(20)
+ ->get(),
+ ];
+ }
+}
+?>
+
+
+
+
+
+```
+
+### Routen-Struktur
+
+```php
+// routes/web.php
+
+// Public
+Route::get('/', fn() => view('welcome'))->name('home');
+
+// Authenticated Routes
+Route::middleware(['auth', 'verified'])->group(function () {
+ Route::view('dashboard', 'dashboard')->name('dashboard');
+
+ // Volt Routes
+ Volt::route('company-search', 'company-search')->name('company-search');
+ Volt::route('transaction-review', 'transaction-review')->name('transaction-review');
+ Volt::route('companies/{company}/transactions', 'companies.transactions')
+ ->name('company.transactions');
+ Volt::route('upload', 'upload.index')->name('upload');
+
+ // Settings
+ Volt::route('settings/profile', 'settings.profile')->name('profile.edit');
+ Volt::route('settings/password', 'settings.password')->name('password.edit');
+ Volt::route('settings/two-factor', 'settings.two-factor')
+ ->middleware(['password.confirm'])
+ ->name('two-factor.show');
+});
+```
+
+### Hauptseiten
+
+| Route | Component | Beschreibung |
+|-------|-----------|--------------|
+| `/` | welcome.blade.php | Landing Page |
+| `/dashboard` | dashboard.blade.php | Dashboard-Ãbersicht |
+| `/company-search` | company-search.blade.php | Unternehmenssuche |
+| `/transaction-review` | transaction-review.blade.php | TransaktionsÃŒbersicht |
+| `/companies/{id}/transactions` | companies.transactions.blade.php | Company-Detail mit Transactions |
+| `/upload` | upload.index.blade.php | Upload-FunktionalitÀt |
+
+---
+
+## Backend-Integration
+
+### Models & Relationships
+
+```php
+// app/Models/Company.php
+class Company extends Model
+{
+ protected $fillable = [
+ 'name', 'legal_name', 'ticker', 'sector',
+ 'country', 'headquarters', 'kyc_risk_level', 'summary',
+ ];
+
+ public function transactions(): HasMany
+ {
+ return $this->hasMany(Transaction::class);
+ }
+}
+
+// app/Models/Transaction.php
+class Transaction extends Model
+{
+ protected $guarded = []; // Allow all (for 102 JSONB columns)
+
+ // Dynamic JSONB casting
+ protected function casts(): array
+ {
+ $allColumns = Schema::getColumnListing('transactions');
+ $jsonbColumns = array_diff($allColumns, $standardColumns);
+
+ foreach ($jsonbColumns as $column) {
+ $casts[$column] = 'array';
+ }
+
+ return $casts;
+ }
+
+ public function company(): BelongsTo
+ {
+ return $this->belongsTo(Company::class);
+ }
+}
+```
+
+### Jobs
+
+#### SyncBackendDataPool
+
+```php
+// app/Jobs/SyncBackendDataPool.php
+
+class SyncBackendDataPool implements ShouldQueue
+{
+ public function __construct(
+ public bool $fullSync = false,
+ public int $batchSize = 1000,
+ ) {}
+
+ public function handle(): void
+ {
+ if ($this->fullSync) {
+ DB::table('backend_data_pool')->truncate();
+ }
+
+ $query = DB::connection('pgsql')
+ ->table('backend.transactions as t')
+ ->join('backend.transaction_outputs as tout', 't.id', '=', 'tout.transaction_id')
+ ->where('t.status', 'done')
+ ->select([
+ 't.id as transaction_id',
+ 'tout.prompt_id',
+ 't.corporate_entity',
+ 't.tx_amount',
+ 't.tx_currency',
+ 't.tx_date',
+ 't.status',
+ 't.risk_score',
+ 'tout.output_key',
+ 'tout.content',
+ ]);
+
+ $query->chunk($this->batchSize, function ($records) {
+ DB::table('backend_data_pool')->insert(
+ $records->map(fn($r) => [
+ ...(array) $r,
+ 'synced_at' => now(),
+ ])->toArray()
+ );
+ });
+ }
+}
+```
+
+#### TransformDataPoolToProduction
+
+```php
+// app/Jobs/TransformDataPoolToProduction.php
+
+class TransformDataPoolToProduction implements ShouldQueue
+{
+ public function handle(): void
+ {
+ $transactionIds = DB::table('backend_data_pool')
+ ->distinct()
+ ->pluck('transaction_id');
+
+ foreach ($transactionIds as $transactionId) {
+ $outputs = DB::table('backend_data_pool')
+ ->where('transaction_id', $transactionId)
+ ->get();
+
+ $company = $this->createOrUpdateCompany($outputs);
+ $this->createOrUpdateTransaction($company, $outputs);
+ }
+ }
+
+ private function createOrUpdateCompany($outputs): Company
+ {
+ $first = $outputs->first();
+
+ return Company::updateOrCreate(
+ ['name' => $first->corporate_entity],
+ [
+ 'sector' => $this->extractValue($outputs, 'corporate_sector'),
+ 'country' => $this->extractValue($outputs, 'corporate_countryofincorporation'),
+ 'headquarters' => $this->extractValue($outputs, 'corporate_HQ'),
+ 'kyc_risk_level' => $this->calculateKycRiskLevel($first->risk_score),
+ 'summary' => $this->extractValue($outputs, 'corporate_summary'),
+ ]
+ );
+ }
+}
+```
+
+### Commands
+
+```bash
+# Manuelle Sync-Commands
+php artisan backend:sync-data-pool --full
+php artisan backend:sync-data-pool --incremental
+php artisan backend:transform-data-pool
+php artisan backend:rebuild # Full Sync + Transform
+```
+
+---
+
+## Scheduling & Automation
+
+### Laravel Scheduler Configuration
+
+```php
+// routes/console.php
+
+// Incremental Sync: 0:00, 6:00, 12:00, 18:00
+Schedule::job(new SyncBackendDataPool(fullSync: false, batchSize: 1000))
+ ->everySixHours()
+ ->name('sync-backend-data-pool-incremental')
+ ->withoutOverlapping(1800);
+
+// Full Sync: Sonntag 3:00 Uhr
+Schedule::job(new SyncBackendDataPool(fullSync: true, batchSize: 1000))
+ ->weeklyOn(0, '03:00')
+ ->name('sync-backend-data-pool-full')
+ ->withoutOverlapping(3600);
+
+// Transformation: 0:30, 6:30, 12:30, 18:30
+Schedule::job(new TransformDataPoolToProduction(batchSize: 100))
+ ->cron('30 */6 * * *')
+ ->name('transform-data-pool-to-production')
+ ->withoutOverlapping(1800);
+```
+
+### Aktivierung
+
+#### Lokale Entwicklung
+```bash
+php artisan schedule:work
+```
+
+#### Produktion (Crontab)
+```bash
+crontab -e
+
+# FÃŒge hinzu:
+* * * * * cd /path/to/project && php artisan schedule:run >> /dev/null 2>&1
+```
+
+#### Mit Supervisor
+```ini
+[program:laravel-scheduler]
+command=php /path/to/project/artisan schedule:work
+autostart=true
+autorestart=true
+```
+
+---
+
+## Sicherheit & Authentication
+
+### Laravel Fortify
+
+Die Applikation nutzt **Laravel Fortify** fÃŒr Authentication:
+
+```php
+// config/fortify.php - Enabled Features
+
+Features::registration(),
+Features::resetPasswords(),
+Features::emailVerification(),
+Features::updateProfileInformation(),
+Features::updatePasswords(),
+Features::twoFactorAuthentication([
+ 'confirm' => true,
+ 'confirmPassword' => true,
+]),
+```
+
+### Two-Factor Authentication (2FA)
+
+- QR-Code basierte 2FA mit TOTP
+- Recovery Codes
+- Passwort-BestÀtigung erforderlich
+
+### Authorization
+
+- Route Middleware: `auth`, `verified`
+- Password Confirmation fÃŒr sensible Aktionen
+
+### Session Management
+
+- Standard Laravel Session-Driver
+- CSRF Protection aktiviert
+
+---
+
+## Deployment-Architektur
+
+### Docker Setup
+
+```yaml
+# docker-compose.yml
+
+services:
+ app:
+ build:
+ context: .
+ dockerfile: Dockerfile
+ ports:
+ - "8000:8000"
+ volumes:
+ - .:/var/www/html
+ environment:
+ - DB_CONNECTION2=pgsql
+ - DB_HOST2=db
+ - DB_PORT2=5432
+```
+
+### Kubernetes CronJob
+
+```yaml
+# k8s-cronjob.yaml
+
+apiVersion: batch/v1
+kind: CronJob
+metadata:
+ name: backend-sync
+spec:
+ schedule: "0 */6 * * *" # Every 6 hours
+ jobTemplate:
+ spec:
+ template:
+ spec:
+ containers:
+ - name: sync
+ image: risk-platform:latest
+ command: ["php", "artisan", "backend:sync-data-pool", "--incremental"]
+```
+
+### Environment Configuration
+
+```bash
+# .env (Production)
+
+APP_ENV=production
+APP_DEBUG=false
+
+DB_CONNECTION2=pgsql
+DB_HOST2=postgres.internal
+DB_PORT2=5432
+DB_DATABASE2=risk_platform_db
+DB_USERNAME2=risk_user
+DB_PASSWORD2=***
+
+CACHE_STORE=redis
+QUEUE_CONNECTION=redis
+SESSION_DRIVER=redis
+```
+
+### Scaling Considerations
+
+**Horizontal Scaling:**
+- Stateless Laravel App â Load Balancer â Multiple App Instances
+- Shared Redis fÃŒr Sessions/Cache
+- Shared PostgreSQL Cluster
+
+**Performance Optimization:**
+- Redis Caching fÃŒr Companies/Transactions
+- Database Indexing (transaction_id, output_key, company_id)
+- Query Optimization mit Eager Loading
+- CDN fÃŒr Static Assets
+
+---
+
+## Monitoring & Logging
+
+### Laravel Logs
+
+```bash
+# Application Logs
+tail -f storage/logs/laravel.log
+
+# Nur Sync-Logs
+tail -f storage/logs/laravel.log | grep SyncBackendDataPool
+
+# Nur Transform-Logs
+tail -f storage/logs/laravel.log | grep TransformDataPoolToProduction
+```
+
+### Queue Monitoring
+
+```bash
+php artisan queue:work --tries=3
+php artisan queue:monitor
+```
+
+### Database Performance Monitoring
+
+```sql
+-- Sync-Performance (Records pro Minute)
+SELECT
+ DATE_TRUNC('minute', synced_at) as minute,
+ COUNT(*) as records_synced
+FROM public.backend_data_pool
+WHERE synced_at >= NOW() - INTERVAL '1 hour'
+GROUP BY DATE_TRUNC('minute', synced_at)
+ORDER BY minute DESC;
+```
+
+### Optional: Laravel Telescope
+
+```bash
+composer require laravel/telescope --dev
+php artisan telescope:install
+php artisan migrate
+```
+
+---
+
+## Zusammenfassung
+
+### System-Eigenschaften
+
+â
**Monolithische Laravel-Applikation** mit klarer Layer-Trennung
+â
**ETL-Pipeline** mit zweistufiger Transformation (Sync â Transform)
+â
**Automatisierung** via Laravel Scheduler (alle 6h)
+â
**Reactive Frontend** mit Livewire Volt + Flux UI
+â
**Skalierbar** via Queue-System und horizontaler App-Skalierung
+â
**Sicher** mit Fortify Authentication + 2FA
+â
**Testbar** mit Pest Testing Framework
+
+### Performance-Metriken
+
+| Operation | Datenmenge | Dauer | Frequenz |
+|-----------|-----------|-------|----------|
+| Incremental Sync | ~100-500 Records | 5-10s | Alle 6h |
+| Full Sync | 7,471 Records | 30-60s | Sonntag 3am |
+| Transformation | 74 Transactions | 30-60s | Alle 6h (30min nach Sync) |
+| Page Load (Companies) | 20 Records | <100ms | On Demand |
+
+### NÀchste Schritte
+
+- [ ] API-Dokumentation (OpenAPI/Swagger)
+- [ ] Testing-Guide & Coverage-Ziele
+- [ ] Deployment-Runbooks
+- [ ] Entwickler-Onboarding-Guide
+- [ ] Performance-Optimierung (Caching-Strategie)
+
+---
+
+**Erstellt:** 2025-11-24
+**Version:** 1.0
+**Autor:** Risk Intelligence Platform Team
diff --git a/docs/data-model-documentation.md b/docs/data-model-documentation.md
new file mode 100644
index 0000000..ec248cf
--- /dev/null
+++ b/docs/data-model-documentation.md
@@ -0,0 +1,1153 @@
+# Datenmodell-Dokumentation: Risk Intelligence Platform
+
+## ð Inhaltsverzeichnis
+
+1. [Ãbersicht](#ÃŒbersicht)
+2. [Entity-Relationship-Diagramm](#entity-relationship-diagramm)
+3. [Schema-Architektur](#schema-architektur)
+4. [Production Models (PUBLIC Schema)](#production-models-public-schema)
+5. [Backend Models (BACKEND Schema)](#backend-models-backend-schema)
+6. [ETL-Modell (Data Pool)](#etl-modell-data-pool)
+7. [Beziehungen & Constraints](#beziehungen--constraints)
+8. [Indizes & Performance](#indizes--performance)
+9. [JSONB-Spalten](#jsonb-spalten)
+10. [Business-Logik](#business-logik)
+
+---
+
+## Ãbersicht
+
+Die Risk Intelligence Platform nutzt ein **Multi-Schema PostgreSQL-Design** mit klarer Trennung zwischen:
+
+- **PUBLIC Schema** - Production Tables (Companies, Transactions, Users)
+- **BACKEND Schema** - Source Data vom KI-Backend (Transactions, Outputs)
+- **ETL Layer** - Backend Data Pool als Zwischenspeicher
+
+### Datenbankverbindungen
+
+```php
+'pgsql_second' => [
+ 'search_path' => 'public', // Default Connection
+],
+
+'backend' => [
+ 'search_path' => 'backend', // Backend Connection
+],
+```
+
+**Wichtig:** Beide Connections nutzen **dieselbe Datenbank**, aber unterschiedliche Schemas.
+
+---
+
+## Entity-Relationship-Diagramm
+
+```
+âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+â PUBLIC SCHEMA (Production) â
+âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+
+ ââââââââââââââââââââ
+ â users â
+ ââââââââââââââââââââ€
+ â id â PK
+ â name â
+ â email â UNIQUE
+ â password â
+ â email_verified_atâ
+ â two_factor_secretâ
+ â two_factor_codes â
+ â remember_token â
+ â created_at â
+ â updated_at â
+ ââââââââââââââââââââ
+
+
+ ââââââââââââââââââââ
+ â companies â
+ ââââââââââââââââââââ€
+ â id â PK
+ â name â UNIQUE
+ â legal_name â
+ â ticker â
+ â sector â
+ â country â (ISO 3166-1 alpha-2)
+ â headquarters â
+ â kyc_risk_level â (low|high|critical)
+ â summary â
+ â created_at â
+ â updated_at â
+ ââââââââââ¬ââââââââââ
+ â
+ â 1:N (One Company has Many Transactions)
+ â
+ ââââââââââŒââââââââââ
+ â transactions â
+ ââââââââââââââââââââ€
+ â id â PK
+ â company_id â FK â companies.id (CASCADE DELETE)
+ â reference â UNIQUE (e.g., "MIGRATED-1")
+ â â
+ â âââ Core âââââââ â
+ â amount â DECIMAL(16,2)
+ â currency â (3 chars, default: EUR)
+ â counterparty â
+ â counterparty_country â
+ â channel â
+ â executed_at â DATETIME
+ â â
+ â âââ Risk âââââââ â
+ â risk_score â TINYINT (0-255)
+ â status â (true_positive|false_positive|cleared)
+ â requires_review â BOOLEAN
+ â flagged_by â
+ â flagged_reason â
+ â signals â JSON
+ â â
+ â âââ Entity âââââ â
+ â entity â Corporate entity name
+ â counterparty_kyc_risk_level â
+ â â
+ â âââ Risk Breakdown âââ â
+ â transaction_risk_score â
+ â sanctions_risk_score â
+ â country_risk_score â
+ â pep_adverse_risk_score â
+ â corruption_risk_score â
+ â â
+ â âââ External Data (JSONB) âââ â
+ â registry_data â
+ â genesis_context â
+ â govdata_data â
+ â bundesanzeiger_data â
+ â insolvency_data â
+ â rss_alerts â
+ â sanctions_data â
+ â pep_data â
+ â gleif_data â
+ â eu_sanctions_dataâ
+ â handelsregister_data â
+ â â
+ â âââ 102 JSONB Output Columns âââ â
+ â corporate_summaryâ JSONB
+ â corporate_historyâ JSONB
+ â tranx_score â JSONB
+ â ... (99 weitere) â
+ â â
+ â created_at â
+ â updated_at â
+ ââââââââââââââââââââ
+
+
+âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+â ETL LAYER (PUBLIC Schema) â
+âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+
+ ââââââââââââââââââââââââââââ
+ â backend_data_pool â
+ ââââââââââââââââââââââââââââ€
+ â id â PK
+ â â
+ â âââ From backend.transactions âââ â
+ â transaction_id â INDEX
+ â corporate_entity â
+ â corporate_counterparty â
+ â tx_date â
+ â tx_amount â
+ â tx_currency â
+ â tx_purpose â
+ â tx_country_outgoing â
+ â tx_country_incoming â
+ â source_file â
+ â raw_payload â
+ â status â INDEX
+ â created_at â
+ â last_modified_at â
+ â â
+ â âââ From backend.transaction_outputs âââ â
+ â prompt_id â
+ â output_key â INDEX
+ â content â TEXT (JSON)
+ â run_id â
+ â â
+ â âââ Metadata âââââ â
+ â synced_at â INDEX
+ â updated_at â
+ â â
+ â UNIQUE(transaction_id, prompt_id) â
+ ââââââââââââââââââââââââââââ
+
+
+âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+â BACKEND SCHEMA (Source Data) â
+âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+
+ ââââââââââââââââââââââââ
+ â backend.transactions â
+ ââââââââââââââââââââââââ€
+ â id â PK
+ â corporate_entity â
+ â corporate_counterpartyâ
+ â tx_date â
+ â tx_amount â
+ â tx_currency â
+ â tx_purpose â
+ â tx_country_outgoing â
+ â tx_country_incoming â
+ â source_file â
+ â raw_payload â
+ â status â (pending|processing|done|failed)
+ â risk_score â INTEGER (-100 to 100)
+ â created_at â
+ â last_modified_at â
+ ââââââââââââ¬ââââââââââââ
+ â
+ â 1:N (One Transaction has Many Outputs)
+ â
+ ââââââââââââŒâââââââââââââââââââ
+ â backend.transaction_outputs â
+ âââââââââââââââââââââââââââââââ€
+ â id â PK
+ â transaction_id â FK â backend.transactions.id
+ â prompt_id â
+ â output_key â VARCHAR (e.g., "corporate_summary")
+ â content â JSONB (LLM-Generated)
+ â run_id â
+ â created_at â
+ â â
+ â UNIQUE(transaction_id, prompt_id) â
+ âââââââââââââââââââââââââââââââ
+```
+
+---
+
+## Schema-Architektur
+
+### 1. PUBLIC Schema (Production)
+
+**Zweck:** Produktive Applikationsdaten
+**Models:**
+- `Company` - Unternehmensprofile mit KYC Risk Level
+- `Transaction` - Transaktionsanalysen mit 139 Spalten
+- `User` - Benutzeraccounts
+- `BackendDataPool` - ETL Zwischenspeicher
+
+**Besonderheit:** Alle produktiven Daten, optimiert fÃŒr Frontend-Zugriff
+
+### 2. BACKEND Schema (Source)
+
+**Zweck:** KI-Backend Source Data (Read-Only aus Frontend-Sicht)
+**Models:**
+- `Backend\Transaction` - Rohdaten vom KI-System
+- `Backend\TransactionOutput` - LLM-generierte Analysen
+
+**Besonderheit:** Wird nur gelesen, nie geschrieben (auÃer vom Backend-System)
+
+---
+
+## Production Models (PUBLIC Schema)
+
+### Company Model
+
+**Tabelle:** `public.companies`
+**Model:** `App\Models\Company`
+
+#### Struktur
+
+```sql
+CREATE TABLE public.companies (
+ id SERIAL PRIMARY KEY,
+ name VARCHAR(255) UNIQUE NOT NULL,
+ legal_name VARCHAR(255),
+ ticker VARCHAR(50),
+ sector VARCHAR(100),
+ country VARCHAR(2) DEFAULT 'DE', -- ISO 3166-1 alpha-2
+ headquarters TEXT,
+ kyc_risk_level VARCHAR(20) DEFAULT 'medium',
+ summary TEXT,
+ created_at TIMESTAMP,
+ updated_at TIMESTAMP
+);
+```
+
+#### Felder-ErklÀrung
+
+| Feld | Typ | Beschreibung | Beispiel |
+|------|-----|--------------|----------|
+| `id` | SERIAL | Primary Key | `1` |
+| `name` | VARCHAR(255) | Firmenname (Unique) | `"Mercedes-Benz Group AG"` |
+| `legal_name` | VARCHAR(255) | Offizieller rechtlicher Name | `"Mercedes-Benz Group Aktiengesellschaft"` |
+| `ticker` | VARCHAR(50) | Börsen-Ticker | `"MBG"` |
+| `sector` | VARCHAR(100) | Branche | `"Automotive"` |
+| `country` | VARCHAR(2) | Land (ISO 3166-1 alpha-2) | `"DE"` |
+| `headquarters` | TEXT | Hauptsitz | `"Stuttgart, Germany"` |
+| `kyc_risk_level` | VARCHAR(20) | KYC Risiko-Level | `"low"`, `"high"`, `"critical"` |
+| `summary` | TEXT | Zusammenfassung | `"German automobile manufacturer..."` |
+
+#### KYC Risk Levels
+
+| Level | Beschreibung | Bedeutung |
+|-------|--------------|-----------|
+| `low` | Geringes Risiko | UnauffÀlliges Unternehmen, Standard-KYC |
+| `high` | Hohes Risiko | Erhöhte Due Diligence erforderlich |
+| `critical` | Kritisches Risiko | Sanctions/PEP/AML Flags, intensive PrÃŒfung |
+
+#### Relationships
+
+```php
+class Company extends Model
+{
+ // 1:N - Eine Company hat viele Transactions
+ public function transactions(): HasMany
+ {
+ return $this->hasMany(Transaction::class);
+ }
+}
+```
+
+#### Constraints & Indizes
+
+```sql
+-- Unique Constraint auf Name
+ALTER TABLE companies ADD CONSTRAINT companies_name_unique UNIQUE (name);
+
+-- Index auf country fÃŒr geografische Queries
+CREATE INDEX idx_companies_country ON companies(country);
+
+-- Index auf kyc_risk_level fÃŒr Risiko-Filtering
+CREATE INDEX idx_companies_kyc_risk_level ON companies(kyc_risk_level);
+```
+
+---
+
+### Transaction Model
+
+**Tabelle:** `public.transactions`
+**Model:** `App\Models\Transaction`
+
+#### Struktur (139 Spalten)
+
+Die Transaction-Tabelle ist in mehrere logische Gruppen unterteilt:
+
+##### Core Fields (31 Spalten)
+
+```sql
+-- Identity & Relationships
+id SERIAL PRIMARY KEY
+company_id INTEGER REFERENCES companies(id) ON DELETE CASCADE
+reference VARCHAR(255) UNIQUE
+
+-- Transaction Details
+amount DECIMAL(16,2)
+currency VARCHAR(3) DEFAULT 'EUR'
+counterparty VARCHAR(255)
+counterparty_country VARCHAR(2)
+channel VARCHAR(50)
+executed_at TIMESTAMP
+
+-- Risk Assessment
+risk_score TINYINT(0-255)
+status VARCHAR(32) -- true_positive | false_positive | cleared
+requires_review BOOLEAN DEFAULT true
+flagged_by VARCHAR(255)
+flagged_reason TEXT
+signals JSON
+
+-- Entity Information
+entity VARCHAR(255)
+counterparty_kyc_risk_level VARCHAR(20)
+
+-- Risk Breakdown
+transaction_risk_score INTEGER
+sanctions_risk_score INTEGER
+country_risk_score INTEGER
+pep_adverse_risk_score INTEGER
+corruption_risk_score INTEGER
+
+-- Timestamps
+created_at TIMESTAMP
+updated_at TIMESTAMP
+```
+
+##### External Data Sources (11 JSONB Spalten)
+
+```sql
+-- Registry & Official Data
+registry_data JSONB
+registry_company_number TEXT
+registry_source TEXT
+registry_match_score DOUBLE
+registry_last_refreshed_at TIMESTAMP
+
+-- Government & Public Data
+genesis_context JSONB
+genesis_last_refreshed_at TIMESTAMP
+
+govdata_data JSONB
+govdata_last_refreshed_at TIMESTAMP
+
+bundesanzeiger_data JSONB
+bundesanzeiger_last_refreshed_at TIMESTAMP
+
+handelsregister_data JSONB
+handelsregister_last_refreshed_at TIMESTAMP
+handelsregister_status TEXT
+handelsregister_entity_id BIGINT
+
+-- Compliance Data
+insolvency_data JSONB
+insolvency_last_refreshed_at TIMESTAMP
+
+sanctions_data JSONB
+sanctions_last_refreshed_at TIMESTAMP
+
+eu_sanctions_data JSONB
+eu_sanctions_last_refreshed_at TIMESTAMP
+
+pep_data JSONB
+pep_last_refreshed_at TIMESTAMP
+
+-- GLEIF (Legal Entity Identifier)
+gleif_lei TEXT
+gleif_data JSON
+gleif_last_refreshed_at TIMESTAMP
+
+-- Alerts
+rss_alerts JSONB
+rss_last_refreshed_at TIMESTAMP
+```
+
+##### LLM-Generated Output Fields (102 JSONB Spalten)
+
+
+ð VollstÀndige Liste der 102 JSONB Output-Spalten (klicken zum Ausklappen)
+
+**Corporate Information (57 Spalten):**
+```sql
+corporate_summary JSONB
+corporate_history JSONB
+corporate_purpose JSONB
+corporate_sector JSONB
+corporate_nace JSONB
+corporate_products JSONB
+corporate_markets JSONB
+corporate_supply JSONB
+corporate_name JSONB
+corporate_form JSONB
+corporate_forum JSONB
+corporate_HQ JSONB
+corporate_locations JSONB
+corporate_holding JSONB
+corporate_shareholders JSONB
+corporate_board JSONB
+corporate_supervisory JSONB
+corporate_powerofattorney JSONB
+corporate_taxID JSONB
+corporate_LEI JSONB
+corporate_UBO JSONB
+corporate_employeecount JSONB
+corporate_turnover JSONB
+corporate_EBIT JSONB
+corporate_netprofits JSONB
+corporate_balancesheet JSONB
+corporate_auditfindings JSONB
+corporate_insolvency JSONB
+corporate_liquidation JSONB
+corporate_adhoc JSONB
+corporate_pressrelease JSONB
+corporate_votes JSONB
+corporate_directordealings JSONB
+corporate_brands JSONB
+corporate_website JSONB
+corporate_domain JSONB
+corporate_IBAN JSONB
+corporate_solvency JSONB
+corporate_rating JSONB
+corporate_ESG JSONB
+corporate_license JSONB
+corporate_warnings JSONB
+corporate_eusanctions JSONB
+corporate_ofacsanctions JSONB
+corporate_uksanctions JSONB
+corporate_pepexposure JSONB
+corporate_adversemediascanning JSONB
+corporate_corruptionexposure JSONB
+corporate_AMLexposure JSONB
+corporate_CTYexposure JSONB
+corporate_adverse JSONB
+corporate_pep JSONB
+corporate_adverse2 JSONB
+corporate_exportcontrol JSONB
+corporate_mediamatch JSONB
+corporate_haven JSONB
+corporate_haven2 JSONB
+```
+
+**Transaction Analysis (30 Spalten):**
+```sql
+tranx_TX_AMOUNT JSONB
+tranx_historical JSONB
+tranx_TX_PURPOSE JSONB
+tranx_counterpartyassessment JSONB
+tranx_context JSONB
+tranx_report JSONB
+tranx_PURPOSEbase JSONB
+tranx_performanceperiod JSONB
+tranx_seasonality JSONB
+tranx_resolution JSONB
+trans_IBANvalidation JSONB
+tranx_businesslogic JSONB
+tranx_plausibilty JSONB
+tranx_outliers JSONB
+tranx_patterns JSONB
+tranx_revenueimpact JSONB
+tranx_profitimpact JSONB
+tranx_marketimpact JSONB
+tranx_duplicate JSONB
+tranx_pattern2 JSONB
+tranx_contracttenor JSONB
+tranx_mismatch JSONB
+tranx_fakepurposecheck JSONB
+tranx_structuring JSONB
+tranx_newbankaccount JSONB
+tranx_weekday JSONB
+tranx_holdingobfuscation JSONB
+tranx_score JSONB
+tranx_reasoning JSONB
+tranx_recommendation JSONB
+```
+
+**Risk & Compliance (10 Spalten):**
+```sql
+sanctions_circumvention JSONB
+corruption_sector JSONB
+corruption_country JSONB
+corruption_relationship JSONB
+country_risk JSONB
+corporate_insiders JSONB
+corporate_courtcases JSONB
+corporate_manda JSONB
+corporate_pepdetail JSONB
+tranx_sourcerepository JSONB
+```
+
+**Source Validation (5 Spalten):**
+```sql
+source_domaincheck JSONB
+source_check JSONB
+source_approveuniqueID JSONB
+source_randomplausibility JSONB
+```
+
+
+#### Status-Werte
+
+```php
+class Transaction extends Model
+{
+ const STATUS_TRUE_POSITIVE = 'true_positive'; // Kritisches Risiko
+ const STATUS_FALSE_POSITIVE = 'false_positive'; // Hohes Risiko
+ const STATUS_CLEARED = 'cleared'; // Geringes Risiko
+}
+```
+
+| Status | Label (DE) | Bedeutung |
+|--------|-----------|-----------|
+| `true_positive` | Kritisches Risiko | BestÀtigtes Risiko, Aktion erforderlich |
+| `false_positive` | Hohes Risiko | Potenzielles Risiko, Review erforderlich |
+| `cleared` | Geringes Risiko | GeprÃŒft und freigegeben |
+
+#### Relationships
+
+```php
+class Transaction extends Model
+{
+ // N:1 - Viele Transactions gehören zu einer Company
+ public function company(): BelongsTo
+ {
+ return $this->belongsTo(Company::class);
+ }
+}
+```
+
+#### Dynamic JSONB Casting
+
+```php
+// app/Models/Transaction.php
+protected function casts(): array
+{
+ // Automatisches Casting aller JSONB-Spalten als Array
+ $allColumns = Schema::getColumnListing('transactions');
+ $standardColumns = ['id', 'company_id', 'reference', ...];
+
+ $jsonbColumns = array_diff($allColumns, $standardColumns);
+
+ foreach ($jsonbColumns as $column) {
+ $casts[$column] = 'array';
+ }
+
+ return $casts;
+}
+```
+
+#### Business Logic Methods
+
+```php
+// Status Label
+public function statusLabel(): string
+{
+ return match($this->status) {
+ self::STATUS_TRUE_POSITIVE => 'Kritisches Risiko',
+ self::STATUS_FALSE_POSITIVE => 'Hohes Risiko',
+ self::STATUS_CLEARED => 'Geringes Risiko',
+ default => 'Unbekanntes Risiko',
+ };
+}
+```
+
+---
+
+### User Model
+
+**Tabelle:** `public.users`
+**Model:** `App\Models\User`
+
+#### Struktur
+
+```sql
+CREATE TABLE public.users (
+ id SERIAL PRIMARY KEY,
+ name VARCHAR(255) NOT NULL,
+ email VARCHAR(255) UNIQUE NOT NULL,
+ email_verified_at TIMESTAMP,
+ password VARCHAR(255) NOT NULL,
+
+ -- Two-Factor Authentication (Laravel Fortify)
+ two_factor_secret TEXT,
+ two_factor_recovery_codes TEXT,
+ two_factor_confirmed_at TIMESTAMP,
+
+ remember_token VARCHAR(100),
+ created_at TIMESTAMP,
+ updated_at TIMESTAMP
+);
+```
+
+#### Features
+
+- â
Email/Password Authentication
+- â
Email Verification
+- â
Two-Factor Authentication (2FA)
+- â
Password Reset
+- â
Remember Me
+
+---
+
+## Backend Models (BACKEND Schema)
+
+### Backend\Transaction Model
+
+**Tabelle:** `backend.transactions`
+**Model:** `App\Models\Backend\Transaction`
+**Connection:** `backend`
+
+#### Struktur
+
+```sql
+CREATE TABLE backend.transactions (
+ id SERIAL PRIMARY KEY,
+ corporate_entity TEXT,
+ corporate_counterparty TEXT,
+ tx_date DATE,
+ tx_amount DECIMAL(15,2),
+ tx_currency VARCHAR(3),
+ tx_purpose TEXT,
+ tx_country_outgoing VARCHAR(2),
+ tx_country_incoming VARCHAR(2),
+ source_file TEXT,
+ raw_payload TEXT,
+ status VARCHAR(50), -- pending|processing|done|failed
+ risk_score INTEGER, -- -100 to 100 (Backend Scale)
+ created_at TIMESTAMP,
+ last_modified_at TIMESTAMP
+);
+```
+
+#### Status-Werte
+
+| Status | Bedeutung |
+|--------|-----------|
+| `pending` | Wartet auf Verarbeitung |
+| `processing` | KI-Analyse lÀuft |
+| `done` | Verarbeitung abgeschlossen |
+| `failed` | Fehler bei Verarbeitung |
+
+#### Relationships
+
+```php
+class Transaction extends Model
+{
+ protected $connection = 'backend';
+
+ // 1:N - Eine Transaction hat viele Outputs
+ public function outputs(): HasMany
+ {
+ return $this->hasMany(TransactionOutput::class, 'transaction_id');
+ }
+}
+```
+
+#### Helper Methods
+
+```php
+// Hole spezifischen Output-Typ
+public function getOutput(string $key): ?array
+{
+ return $this->outputs()
+ ->where('output_key', $key)
+ ->first()
+ ?->content;
+}
+
+// Alle Outputs als Key-Value Array
+public function getOutputsArray(): array
+{
+ return $this->outputs()
+ ->get()
+ ->pluck('content', 'output_key')
+ ->toArray();
+}
+
+// Convenience Methods
+public function getCompanyInfo(): ?array;
+public function getRiskAssessment(): ?array;
+public function getSanctionsCheck(): ?array;
+public function getPepCheck(): ?array;
+```
+
+---
+
+### Backend\TransactionOutput Model
+
+**Tabelle:** `backend.transaction_outputs`
+**Model:** `App\Models\Backend\TransactionOutput`
+**Connection:** `backend`
+
+#### Struktur
+
+```sql
+CREATE TABLE backend.transaction_outputs (
+ id SERIAL PRIMARY KEY,
+ transaction_id INTEGER REFERENCES transactions(id),
+ prompt_id INTEGER,
+ output_key VARCHAR(255), -- z.B. "corporate_summary", "tranx_score"
+ content JSONB, -- LLM-Generated Output
+ run_id INTEGER,
+ created_at TIMESTAMP,
+
+ UNIQUE(transaction_id, prompt_id)
+);
+```
+
+#### Output Keys (Konstanten)
+
+```php
+class TransactionOutput extends Model
+{
+ const KEY_COMPANY_INFO = 'company_info';
+ const KEY_RISK_ASSESSMENT = 'risk_assessment';
+ const KEY_SANCTIONS = 'sanctions';
+ const KEY_PEP = 'pep';
+ const KEY_REGISTRY = 'registry';
+ const KEY_GLEIF = 'gleif';
+ // ... weitere 96 Keys
+}
+```
+
+#### Relationships
+
+```php
+// N:1 - Viele Outputs gehören zu einer Transaction
+public function transaction(): BelongsTo
+{
+ return $this->belongsTo(Transaction::class, 'transaction_id');
+}
+```
+
+---
+
+## ETL-Modell (Data Pool)
+
+### BackendDataPool Model
+
+**Tabelle:** `public.backend_data_pool`
+**Model:** `App\Models\BackendDataPool` (via DB Facade)
+
+#### Zweck
+
+Denormalisierte Zwischentabelle fÃŒr ETL-Pipeline:
+```sql
+SELECT * FROM backend.transactions t
+LEFT JOIN backend.transaction_outputs tout ON t.id = tout.transaction_id
+WHERE t.status = 'done'
+```
+
+#### Struktur
+
+```sql
+CREATE TABLE public.backend_data_pool (
+ id SERIAL PRIMARY KEY,
+
+ -- From backend.transactions
+ transaction_id INTEGER INDEX,
+ corporate_entity TEXT,
+ corporate_counterparty TEXT,
+ tx_date TEXT,
+ tx_amount DOUBLE,
+ tx_currency TEXT,
+ tx_purpose TEXT,
+ tx_country_outgoing TEXT,
+ tx_country_incoming TEXT,
+ source_file TEXT,
+ raw_payload TEXT,
+ status TEXT INDEX,
+ created_at TEXT,
+ last_modified_at TEXT,
+
+ -- From backend.transaction_outputs
+ prompt_id INTEGER,
+ output_key TEXT INDEX,
+ content TEXT, -- JSON als Text gespeichert
+ run_id INTEGER,
+
+ -- Metadata
+ synced_at TIMESTAMP DEFAULT NOW(),
+ updated_at TIMESTAMP,
+
+ UNIQUE(transaction_id, prompt_id)
+);
+```
+
+#### Indizes
+
+```sql
+CREATE INDEX idx_backend_data_pool_transaction_id ON backend_data_pool(transaction_id);
+CREATE INDEX idx_backend_data_pool_output_key ON backend_data_pool(output_key);
+CREATE INDEX idx_backend_data_pool_transaction_output ON backend_data_pool(transaction_id, output_key);
+CREATE INDEX idx_backend_data_pool_transaction_prompt ON backend_data_pool(transaction_id, prompt_id);
+CREATE INDEX idx_backend_data_pool_synced_at ON backend_data_pool(synced_at);
+CREATE INDEX idx_backend_data_pool_status ON backend_data_pool(status);
+```
+
+---
+
+## Beziehungen & Constraints
+
+### Foreign Key Constraints
+
+```sql
+-- Companies â Transactions (1:N)
+ALTER TABLE transactions
+ ADD CONSTRAINT fk_transactions_company_id
+ FOREIGN KEY (company_id)
+ REFERENCES companies(id)
+ ON DELETE CASCADE;
+
+-- Backend: Transactions â Outputs (1:N)
+ALTER TABLE backend.transaction_outputs
+ ADD CONSTRAINT fk_outputs_transaction_id
+ FOREIGN KEY (transaction_id)
+ REFERENCES backend.transactions(id)
+ ON DELETE CASCADE;
+```
+
+### Unique Constraints
+
+```sql
+-- Company Name muss eindeutig sein
+ALTER TABLE companies
+ ADD CONSTRAINT companies_name_unique
+ UNIQUE (name);
+
+-- Transaction Reference muss eindeutig sein
+ALTER TABLE transactions
+ ADD CONSTRAINT transactions_reference_unique
+ UNIQUE (reference);
+
+-- User Email muss eindeutig sein
+ALTER TABLE users
+ ADD CONSTRAINT users_email_unique
+ UNIQUE (email);
+
+-- Backend: Ein Output pro (transaction_id, prompt_id) Kombination
+ALTER TABLE backend.transaction_outputs
+ ADD CONSTRAINT transaction_outputs_unique
+ UNIQUE (transaction_id, prompt_id);
+
+-- Data Pool: Ein Record pro (transaction_id, prompt_id) Kombination
+ALTER TABLE backend_data_pool
+ ADD CONSTRAINT backend_data_pool_unique
+ UNIQUE (transaction_id, prompt_id);
+```
+
+---
+
+## Indizes & Performance
+
+### Performance-kritische Indizes
+
+```sql
+-- Companies
+CREATE INDEX idx_companies_country ON companies(country);
+CREATE INDEX idx_companies_kyc_risk_level ON companies(kyc_risk_level);
+CREATE INDEX idx_companies_sector ON companies(sector);
+
+-- Transactions
+CREATE INDEX idx_transactions_company_id ON transactions(company_id);
+CREATE INDEX idx_transactions_status ON transactions(status);
+CREATE INDEX idx_transactions_executed_at ON transactions(executed_at);
+CREATE INDEX idx_transactions_risk_score ON transactions(risk_score);
+CREATE INDEX idx_transactions_requires_review ON transactions(requires_review);
+CREATE INDEX idx_transactions_counterparty_country ON transactions(counterparty_country);
+
+-- Backend Transactions
+CREATE INDEX idx_backend_transactions_status ON backend.transactions(status);
+CREATE INDEX idx_backend_transactions_last_modified ON backend.transactions(last_modified_at);
+
+-- Backend Outputs
+CREATE INDEX idx_backend_outputs_transaction_id ON backend.transaction_outputs(transaction_id);
+CREATE INDEX idx_backend_outputs_output_key ON backend.transaction_outputs(output_key);
+
+-- Data Pool (siehe oben)
+```
+
+### Query-Optimierungen
+
+#### Beispiel: Companies mit High-Risk Transactions
+
+```sql
+-- Ohne Index: Full Table Scan
+SELECT c.*, COUNT(t.id) as high_risk_count
+FROM companies c
+JOIN transactions t ON c.id = t.company_id
+WHERE t.status = 'true_positive'
+GROUP BY c.id;
+
+-- Mit Indizes: Index Scan
+-- Index auf t.status ermöglicht schnelles Filtern
+-- Index auf t.company_id ermöglicht schnelles Join
+```
+
+---
+
+## JSONB-Spalten
+
+### Vorteile von JSONB
+
+1. **FlexibilitÀt:** Dynamische Struktur ohne Schema-Ãnderungen
+2. **Performance:** BinÀres Format, schneller als JSON
+3. **Indexierung:** GIN-Indizes fÃŒr schnelle Queries
+4. **Query-Support:** Volle PostgreSQL JSONB-Funktionen
+
+### Typische JSONB-Struktur
+
+#### corporate_summary
+
+```json
+{
+ "answer": "Mercedes-Benz Group AG ist ein deutscher Automobilhersteller...",
+ "confidence": 0.95,
+ "sources": [
+ "https://www.mercedes-benz-group.com",
+ "Wikipedia"
+ ],
+ "generated_at": "2025-11-24T10:30:00Z"
+}
+```
+
+#### tranx_score
+
+```json
+{
+ "score": 45,
+ "level": "medium",
+ "breakdown": {
+ "transaction": 20,
+ "sanctions": 0,
+ "country": 15,
+ "pep": 0,
+ "corruption": 10
+ },
+ "reasoning": "Moderate risk due to transaction amount and country...",
+ "generated_at": "2025-11-24T10:30:00Z"
+}
+```
+
+### JSONB Queries
+
+```sql
+-- Zugriff auf JSONB-Felder
+SELECT
+ reference,
+ corporate_summary->>'answer' as summary,
+ tranx_score->'score' as risk_score
+FROM transactions
+WHERE tranx_score->>'level' = 'high';
+
+-- JSONB Array-Elemente
+SELECT
+ reference,
+ jsonb_array_elements(corporate_shareholders->'shareholders') as shareholder
+FROM transactions;
+
+-- JSONB Aggregation
+SELECT
+ AVG((tranx_score->>'score')::int) as avg_risk_score
+FROM transactions;
+```
+
+---
+
+## Business-Logik
+
+### Risk Score Transformation
+
+Backend nutzt **-100 bis 100**, Frontend **0 bis 255**:
+
+```php
+// TransformDataPoolToProduction Job
+private function normalizeRiskScore(int $backendScore): int
+{
+ return (int) round((($backendScore + 100) / 200) * 255);
+}
+
+// Beispiele:
+// Backend: -100 â Frontend: 0 (Sehr niedrig)
+// Backend: 0 â Frontend: 127 (Medium)
+// Backend: 100 â Frontend: 255 (Sehr hoch)
+```
+
+### Risk Level Mapping
+
+```php
+private function calculateRiskLevel(int $normalizedScore): string
+{
+ return match(true) {
+ $normalizedScore <= 153 => 'low', // 0-153
+ $normalizedScore <= 229 => 'high', // 154-229
+ default => 'critical', // 230-255
+ };
+}
+```
+
+### Transaction Status Mapping
+
+```php
+private function mapStatus(string $riskLevel): string
+{
+ return match($riskLevel) {
+ 'low' => Transaction::STATUS_CLEARED,
+ 'high' => Transaction::STATUS_FALSE_POSITIVE,
+ 'critical' => Transaction::STATUS_TRUE_POSITIVE,
+ };
+}
+```
+
+### Company KYC Risk Calculation
+
+```php
+// KycRiskCalculator Service
+public function calculateCompanyRisk(Collection $transactions): string
+{
+ $criticalCount = $transactions->where('status', 'true_positive')->count();
+ $highCount = $transactions->where('status', 'false_positive')->count();
+ $total = $transactions->count();
+
+ // Worst-Case-Prinzip
+ if ($criticalCount > 0) {
+ return 'critical';
+ }
+
+ // >30% high â critical
+ if (($highCount / $total) > 0.3) {
+ return 'critical';
+ }
+
+ // >10% high â high
+ if (($highCount / $total) > 0.1) {
+ return 'high';
+ }
+
+ return 'low';
+}
+```
+
+---
+
+## Daten-Lifecycle
+
+### ETL-Pipeline
+
+```
+1. Backend Processing
+ â
+ backend.transactions (status='done')
+ + backend.transaction_outputs
+
+2. Sync to Data Pool (Every 6h)
+ â
+ public.backend_data_pool
+ (Denormalized JOIN)
+
+3. Transform to Production (30min after Sync)
+ â
+ public.companies (updateOrCreate by name)
+ + public.transactions (updateOrCreate by reference)
+
+4. Frontend Display
+ â
+ Livewire Components query Production Tables
+```
+
+### Data Retention
+
+- **Backend Schema:** Unbegrenzt (Source of Truth)
+- **Data Pool:** Unbegrenzt (fÃŒr Re-Processing)
+- **Production Tables:** Unbegrenzt
+- **User Sessions:** 120 Minuten (configurable)
+- **Cache:** AbhÀngig von Cache-Driver
+
+---
+
+## Zusammenfassung
+
+### Datenbank-Ãbersicht
+
+| Schema | Tables | Zweck | Zugriff |
+|--------|--------|-------|---------|
+| `public` | 4 | Production Data | Read/Write (Frontend) |
+| `backend` | 2 | Source Data | Read-Only (Frontend) |
+
+### Model-Ãbersicht
+
+| Model | Table | Schema | Relationships |
+|-------|-------|--------|---------------|
+| `Company` | companies | public | hasMany(Transaction) |
+| `Transaction` | transactions | public | belongsTo(Company) |
+| `User` | users | public | - |
+| `Backend\Transaction` | transactions | backend | hasMany(TransactionOutput) |
+| `Backend\TransactionOutput` | transaction_outputs | backend | belongsTo(Transaction) |
+| - | backend_data_pool | public | ETL Layer (DB Facade) |
+
+### Datenmenge (Beispiel)
+
+- **Companies:** ~70 unique
+- **Transactions:** 74
+- **Backend Transactions:** 74
+- **Backend Outputs:** 7,471 (74 Ã ~101 outputs)
+- **Data Pool Records:** 7,471
+
+---
+
+**Erstellt:** 2025-11-24
+**Version:** 1.0
+**Autor:** Risk Intelligence Platform Team
diff --git a/docs/deployment-guide.md b/docs/deployment-guide.md
new file mode 100644
index 0000000..72f2c6b
--- /dev/null
+++ b/docs/deployment-guide.md
@@ -0,0 +1,1035 @@
+# Deployment-Guide: Risk Intelligence Platform
+
+## ð Inhaltsverzeichnis
+
+1. [Ãbersicht](#ÃŒbersicht)
+2. [Voraussetzungen](#voraussetzungen)
+3. [Docker Deployment](#docker-deployment)
+4. [Kubernetes Deployment](#kubernetes-deployment)
+5. [Production Checklist](#production-checklist)
+6. [Environment Configuration](#environment-configuration)
+7. [Database Migration](#database-migration)
+8. [Monitoring & Logging](#monitoring--logging)
+9. [Backup & Recovery](#backup--recovery)
+10. [Rollback-Strategie](#rollback-strategie)
+11. [Troubleshooting](#troubleshooting)
+
+---
+
+## Ãbersicht
+
+Die Risk Intelligence Platform kann auf verschiedene Arten deployed werden:
+
+- **Docker** - Standalone Container oder Docker Compose
+- **Kubernetes** - Production-ready mit CronJobs fÃŒr Scheduled Tasks
+- **Traditional** - Apache/Nginx + PHP-FPM auf Linux-Server
+
+### Deployment-Architektur
+
+```
+âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+â Production Environment â
+âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ€
+â â
+â ââââââââââââââââ ââââââââââââââââ ââââââââââââââââ â
+â â Nginx â â PHP-FPM â â Supervisor â â
+â â (Port 80) â â (Laravel) â â (Queue) â â
+â ââââââââ¬ââââââââ ââââââââ¬ââââââââ ââââââââ¬ââââââââ â
+â â â â â
+â âââââââââââââââââââŽââââââââââââââââââ â
+â â â
+â ⌠â
+â ââââââââââââââââââââââââââââââââââ â
+â â PostgreSQL Database â â
+â â (Public + Backend Schema) â â
+â ââââââââââââââââââââââââââââââââââ â
+â â
+â ââââââââââââââââââââââââââââââââââââââââââââââââââââââ â
+â â Kubernetes CronJob (Laravel Scheduler) â â
+â â - SyncBackendDataPool (every 6h) â â
+â â - TransformDataPool (every 6h at :30) â â
+â ââââââââââââââââââââââââââââââââââââââââââââââââââââââ â
+â â
+âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+```
+
+---
+
+## Voraussetzungen
+
+### System Requirements
+
+| Komponente | Minimum | Empfohlen |
+|------------|---------|-----------|
+| **CPU** | 2 Cores | 4 Cores |
+| **RAM** | 2 GB | 4 GB |
+| **Disk** | 20 GB | 50 GB SSD |
+| **OS** | Linux (Ubuntu 22.04+) | Alpine Linux 3.22 |
+
+### Software Requirements
+
+| Software | Version | Zweck |
+|----------|---------|-------|
+| **PHP** | 8.2+ | Runtime |
+| **Composer** | 2.0+ | Dependencies |
+| **Node.js** | 18+ | Asset Building |
+| **PostgreSQL** | 14+ | Database |
+| **Nginx** | 1.24+ | Web Server |
+| **Supervisor** | 4.0+ | Process Management |
+| **Docker** | 24.0+ | Containerization (optional) |
+| **Kubernetes** | 1.28+ | Orchestration (optional) |
+
+---
+
+## Docker Deployment
+
+### Multi-Stage Dockerfile
+
+Die Applikation nutzt einen **Multi-Stage Build** fÃŒr optimale Image-GröÃe.
+
+```dockerfile
+# Stage 1: Composer Dependencies
+FROM composer:2 AS vendor
+WORKDIR /app
+COPY composer.json composer.lock ./
+RUN composer install --no-dev --optimize-autoloader
+
+# Stage 2: Runtime
+FROM alpine:3.22
+# Install PHP 8.2, Nginx, Supervisor, PostgreSQL Client
+RUN apk add --no-cache \
+ nginx supervisor php82 php82-fpm \
+ php82-pgsql php82-pdo_pgsql \
+ nodejs npm
+
+# Copy vendor from build stage
+COPY --from=vendor /app/vendor ./vendor
+COPY . ./
+
+# Build frontend assets
+RUN npm ci && npm run build
+
+# Optimize Laravel
+RUN php artisan config:cache && \
+ php artisan route:cache && \
+ php artisan view:cache
+
+EXPOSE 80
+CMD ["supervisord", "-c", "/etc/supervisor/supervisord.conf"]
+```
+
+### Build & Run
+
+```bash
+# Build Image
+docker build -t risk-platform:latest .
+
+# Run Container
+docker run -d \
+ --name risk-platform \
+ -p 8080:80 \
+ -v $(pwd)/.env:/var/www/html/.env \
+ -v $(pwd)/storage:/var/www/html/storage \
+ risk-platform:latest
+```
+
+### Docker Compose
+
+```yaml
+# docker-compose.yml
+version: "3.9"
+
+services:
+ app:
+ build:
+ context: .
+ dockerfile: Dockerfile
+ container_name: risk-platform
+ restart: unless-stopped
+ ports:
+ - "8080:80"
+ volumes:
+ - .env:/var/www/html/.env
+ - ./storage:/var/www/html/storage
+ depends_on:
+ - postgres
+ networks:
+ - risk-net
+
+ postgres:
+ image: postgres:16-alpine
+ container_name: risk-postgres
+ restart: unless-stopped
+ environment:
+ POSTGRES_DB: risk_platform_db
+ POSTGRES_USER: risk_user
+ POSTGRES_PASSWORD: ${DB_PASSWORD}
+ volumes:
+ - postgres-data:/var/lib/postgresql/data
+ ports:
+ - "5432:5432"
+ networks:
+ - risk-net
+
+ scheduler:
+ build:
+ context: .
+ dockerfile: Dockerfile
+ container_name: risk-scheduler
+ restart: unless-stopped
+ command: ["php", "artisan", "schedule:work"]
+ volumes:
+ - .env:/var/www/html/.env
+ depends_on:
+ - postgres
+ networks:
+ - risk-net
+
+volumes:
+ postgres-data:
+
+networks:
+ risk-net:
+ driver: bridge
+```
+
+**Starten:**
+```bash
+docker-compose up -d
+```
+
+---
+
+## Kubernetes Deployment
+
+### Namespace erstellen
+
+```yaml
+# namespace.yaml
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: risk-platform
+```
+
+```bash
+kubectl apply -f namespace.yaml
+```
+
+### ConfigMap fÃŒr Environment
+
+```yaml
+# configmap.yaml
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: risk-platform-config
+ namespace: risk-platform
+data:
+ env: |
+ APP_NAME="Risk Intelligence Platform"
+ APP_ENV=production
+ APP_KEY=base64:xxx
+ APP_DEBUG=false
+ APP_URL=https://risk.example.com
+
+ DB_CONNECTION2=pgsql
+ DB_HOST2=postgres-service
+ DB_PORT2=5432
+ DB_DATABASE2=risk_platform_db
+ DB_USERNAME2=risk_user
+ DB_PASSWORD2=xxx
+
+ CACHE_STORE=redis
+ SESSION_DRIVER=redis
+ QUEUE_CONNECTION=redis
+
+ REDIS_HOST=redis-service
+ REDIS_PORT=6379
+```
+
+```bash
+kubectl apply -f configmap.yaml
+```
+
+### Deployment
+
+```yaml
+# deployment.yaml
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: risk-platform
+ namespace: risk-platform
+ labels:
+ app: risk-platform
+spec:
+ replicas: 2
+ selector:
+ matchLabels:
+ app: risk-platform
+ template:
+ metadata:
+ labels:
+ app: risk-platform
+ spec:
+ containers:
+ - name: app
+ image: registry.example.com/risk-platform:latest
+ imagePullPolicy: Always
+ ports:
+ - containerPort: 80
+ name: http
+ env:
+ - name: APP_ENV
+ value: "production"
+ volumeMounts:
+ - name: config
+ mountPath: /var/www/html/.env
+ subPath: env
+ - name: storage
+ mountPath: /var/www/html/storage
+ resources:
+ requests:
+ memory: "512Mi"
+ cpu: "250m"
+ limits:
+ memory: "1Gi"
+ cpu: "500m"
+ livenessProbe:
+ httpGet:
+ path: /
+ port: 80
+ initialDelaySeconds: 30
+ periodSeconds: 10
+ readinessProbe:
+ httpGet:
+ path: /
+ port: 80
+ initialDelaySeconds: 10
+ periodSeconds: 5
+ volumes:
+ - name: config
+ configMap:
+ name: risk-platform-config
+ - name: storage
+ persistentVolumeClaim:
+ claimName: risk-platform-storage
+```
+
+```bash
+kubectl apply -f deployment.yaml
+```
+
+### Service
+
+```yaml
+# service.yaml
+apiVersion: v1
+kind: Service
+metadata:
+ name: risk-platform-service
+ namespace: risk-platform
+spec:
+ selector:
+ app: risk-platform
+ ports:
+ - protocol: TCP
+ port: 80
+ targetPort: 80
+ type: ClusterIP
+```
+
+### Ingress (Optional)
+
+```yaml
+# ingress.yaml
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: risk-platform-ingress
+ namespace: risk-platform
+ annotations:
+ cert-manager.io/cluster-issuer: "letsencrypt-prod"
+ nginx.ingress.kubernetes.io/ssl-redirect: "true"
+spec:
+ ingressClassName: nginx
+ tls:
+ - hosts:
+ - risk.example.com
+ secretName: risk-platform-tls
+ rules:
+ - host: risk.example.com
+ http:
+ paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: risk-platform-service
+ port:
+ number: 80
+```
+
+### CronJob fÃŒr Laravel Scheduler
+
+```yaml
+# cronjob.yaml
+apiVersion: batch/v1
+kind: CronJob
+metadata:
+ name: sync-backend-data-pool
+ namespace: risk-platform
+spec:
+ schedule: "0 */6 * * *" # Every 6 hours
+ successfulJobsHistoryLimit: 3
+ failedJobsHistoryLimit: 3
+ concurrencyPolicy: Forbid
+ jobTemplate:
+ spec:
+ template:
+ metadata:
+ labels:
+ app: sync-backend-data-pool
+ spec:
+ restartPolicy: OnFailure
+ containers:
+ - name: sync
+ image: registry.example.com/risk-platform:latest
+ command: ["php", "artisan", "schedule:run"]
+ volumeMounts:
+ - name: config
+ mountPath: /var/www/html/.env
+ subPath: env
+ volumes:
+ - name: config
+ configMap:
+ name: risk-platform-config
+```
+
+```bash
+kubectl apply -f cronjob.yaml
+```
+
+### Alle Ressourcen deployen
+
+```bash
+# Complete Deployment
+kubectl apply -f namespace.yaml
+kubectl apply -f configmap.yaml
+kubectl apply -f deployment.yaml
+kubectl apply -f service.yaml
+kubectl apply -f ingress.yaml
+kubectl apply -f cronjob.yaml
+
+# Status prÃŒfen
+kubectl get all -n risk-platform
+
+# Logs anschauen
+kubectl logs -f deployment/risk-platform -n risk-platform
+```
+
+---
+
+## Production Checklist
+
+### Pre-Deployment
+
+- [ ] **Environment Configuration**
+ - [ ] `.env` auf `production` gesetzt
+ - [ ] `APP_DEBUG=false`
+ - [ ] `APP_KEY` generiert
+ - [ ] Sichere Passwörter fÌr DB
+
+- [ ] **Database**
+ - [ ] PostgreSQL lÀuft
+ - [ ] Schemas erstellt (public, backend)
+ - [ ] User-Rechte vergeben
+ - [ ] Backup-Strategie definiert
+
+- [ ] **Dependencies**
+ - [ ] `composer install --no-dev --optimize-autoloader`
+ - [ ] `npm ci && npm run build`
+
+- [ ] **Laravel Optimization**
+ - [ ] `php artisan config:cache`
+ - [ ] `php artisan route:cache`
+ - [ ] `php artisan view:cache`
+ - [ ] `php artisan event:cache`
+
+- [ ] **Security**
+ - [ ] HTTPS aktiviert (SSL/TLS)
+ - [ ] Firewall konfiguriert
+ - [ ] `.env` nicht im Git
+ - [ ] Secrets in Vault/ConfigMap
+
+### Post-Deployment
+
+- [ ] **Migrations**
+ - [ ] `php artisan migrate --force`
+ - [ ] Backup vor Migration
+
+- [ ] **Tests**
+ - [ ] Health Check (`/`)
+ - [ ] Login funktioniert
+ - [ ] Database Connection
+ - [ ] Scheduled Jobs
+
+- [ ] **Monitoring**
+ - [ ] Logs werden geschrieben
+ - [ ] Metrics werden gesammelt
+ - [ ] Alerts konfiguriert
+
+- [ ] **Performance**
+ - [ ] OPcache aktiviert
+ - [ ] Redis fÃŒr Cache/Session
+ - [ ] Database Indizes
+
+---
+
+## Environment Configuration
+
+### Production .env
+
+```ini
+# Application
+APP_NAME="Risk Intelligence Platform"
+APP_ENV=production
+APP_KEY=base64:xxx # Generate with: php artisan key:generate
+APP_DEBUG=false
+APP_URL=https://risk.example.com
+
+# Locale
+APP_LOCALE=de
+APP_FALLBACK_LOCALE=en
+
+# Database (PostgreSQL)
+DB_CONNECTION2=pgsql
+DB_HOST2=postgres-host
+DB_PORT2=5432
+DB_DATABASE2=risk_platform_db
+DB_USERNAME2=risk_user
+DB_PASSWORD2=xxx # Use strong password!
+
+# Cache & Session (Redis)
+CACHE_STORE=redis
+SESSION_DRIVER=redis
+SESSION_LIFETIME=120
+
+# Queue
+QUEUE_CONNECTION=redis
+
+# Redis
+REDIS_HOST=redis-host
+REDIS_PASSWORD=null
+REDIS_PORT=6379
+
+# Mail
+MAIL_MAILER=smtp
+MAIL_HOST=smtp.example.com
+MAIL_PORT=587
+MAIL_USERNAME=noreply@example.com
+MAIL_PASSWORD=xxx
+MAIL_ENCRYPTION=tls
+MAIL_FROM_ADDRESS=noreply@example.com
+MAIL_FROM_NAME="${APP_NAME}"
+
+# Logging
+LOG_CHANNEL=stack
+LOG_LEVEL=error # Production: error, nicht debug!
+
+# Security
+SESSION_SECURE_COOKIE=true
+SESSION_SAME_SITE=strict
+```
+
+### Secrets Management
+
+**Kubernetes Secrets:**
+```bash
+# Create Secret
+kubectl create secret generic risk-platform-secrets \
+ --from-literal=APP_KEY=base64:xxx \
+ --from-literal=DB_PASSWORD=xxx \
+ --from-literal=REDIS_PASSWORD=xxx \
+ -n risk-platform
+
+# Use in Deployment
+env:
+- name: APP_KEY
+ valueFrom:
+ secretKeyRef:
+ name: risk-platform-secrets
+ key: APP_KEY
+```
+
+---
+
+## Database Migration
+
+### Pre-Migration Backup
+
+```bash
+# PostgreSQL Backup
+pg_dump -h localhost -U risk_user -d risk_platform_db > backup_$(date +%Y%m%d_%H%M%S).sql
+
+# Verify Backup
+psql -h localhost -U risk_user -d risk_platform_db_test < backup_xxx.sql
+```
+
+### Run Migrations
+
+```bash
+# Production Migration
+php artisan migrate --force
+
+# With Output
+php artisan migrate --force --verbose
+
+# Rollback (if needed)
+php artisan migrate:rollback --force
+```
+
+### Zero-Downtime Migration
+
+```bash
+# 1. Maintenance Mode
+php artisan down --message="Updating..." --retry=60
+
+# 2. Pull latest code
+git pull origin main
+
+# 3. Update dependencies
+composer install --no-dev --optimize-autoloader
+
+# 4. Run migrations
+php artisan migrate --force
+
+# 5. Clear & cache
+php artisan optimize:clear
+php artisan config:cache
+php artisan route:cache
+php artisan view:cache
+
+# 6. Restart services
+sudo supervisorctl restart all
+
+# 7. Exit maintenance mode
+php artisan up
+```
+
+---
+
+## Monitoring & Logging
+
+### Application Logs
+
+```bash
+# Laravel Logs
+tail -f storage/logs/laravel.log
+
+# Nur Errors
+tail -f storage/logs/laravel.log | grep ERROR
+
+# Mit Laravel Pail
+php artisan pail --filter=error
+```
+
+### Nginx Logs
+
+```bash
+# Access Log
+tail -f /var/log/nginx/access.log
+
+# Error Log
+tail -f /var/log/nginx/error.log
+```
+
+### Kubernetes Logs
+
+```bash
+# Pod Logs
+kubectl logs -f deployment/risk-platform -n risk-platform
+
+# Alle Pods
+kubectl logs -f -l app=risk-platform -n risk-platform
+
+# CronJob Logs
+kubectl logs -f cronjob/sync-backend-data-pool -n risk-platform
+```
+
+### Health Checks
+
+```bash
+# Application Health
+curl https://risk.example.com/
+
+# Database Connection
+php artisan tinker
+>>> DB::connection()->getPdo()
+
+# Queue Status
+php artisan queue:monitor
+
+# Scheduler Status
+php artisan schedule:list
+```
+
+### Monitoring-Tools (Optional)
+
+**Laravel Telescope:**
+```bash
+composer require laravel/telescope --dev
+php artisan telescope:install
+php artisan migrate
+```
+
+**Prometheus + Grafana:**
+- Metrics-Export via Laravel Package
+- Custom Dashboards fÃŒr Transactions, Companies
+- Alerts bei hoher Error-Rate
+
+---
+
+## Backup & Recovery
+
+### Automated Backup Script
+
+```bash
+#!/bin/bash
+# backup.sh
+
+DATE=$(date +%Y%m%d_%H%M%S)
+BACKUP_DIR="/backups"
+DB_NAME="risk_platform_db"
+
+# Database Backup
+pg_dump -h localhost -U risk_user $DB_NAME > $BACKUP_DIR/db_$DATE.sql
+
+# Storage Backup
+tar -czf $BACKUP_DIR/storage_$DATE.tar.gz storage/
+
+# Keep only last 7 days
+find $BACKUP_DIR -type f -mtime +7 -delete
+
+echo "Backup completed: $DATE"
+```
+
+**Crontab:**
+```bash
+# Daily backup at 2 AM
+0 2 * * * /path/to/backup.sh >> /var/log/backup.log 2>&1
+```
+
+### Kubernetes Backup
+
+```yaml
+# backup-cronjob.yaml
+apiVersion: batch/v1
+kind: CronJob
+metadata:
+ name: database-backup
+ namespace: risk-platform
+spec:
+ schedule: "0 2 * * *" # Daily at 2 AM
+ jobTemplate:
+ spec:
+ template:
+ spec:
+ containers:
+ - name: backup
+ image: postgres:16-alpine
+ command:
+ - /bin/sh
+ - -c
+ - |
+ pg_dump -h postgres-service -U risk_user risk_platform_db > /backup/db_$(date +%Y%m%d).sql
+ volumeMounts:
+ - name: backup-storage
+ mountPath: /backup
+ volumes:
+ - name: backup-storage
+ persistentVolumeClaim:
+ claimName: backup-pvc
+ restartPolicy: OnFailure
+```
+
+### Recovery Procedure
+
+```bash
+# 1. Stop Application
+kubectl scale deployment risk-platform --replicas=0 -n risk-platform
+
+# 2. Restore Database
+psql -h localhost -U risk_user -d risk_platform_db < backup_xxx.sql
+
+# 3. Verify Data
+psql -h localhost -U risk_user -d risk_platform_db
+\dt
+SELECT COUNT(*) FROM companies;
+
+# 4. Restart Application
+kubectl scale deployment risk-platform --replicas=2 -n risk-platform
+```
+
+---
+
+## Rollback-Strategie
+
+### Git-based Rollback
+
+```bash
+# 1. Identify previous version
+git log --oneline -10
+
+# 2. Checkout previous version
+git checkout
+
+# 3. Rebuild & Deploy
+docker build -t risk-platform:rollback .
+docker push registry.example.com/risk-platform:rollback
+
+# 4. Update Kubernetes
+kubectl set image deployment/risk-platform \
+ app=registry.example.com/risk-platform:rollback \
+ -n risk-platform
+```
+
+### Database Rollback
+
+```bash
+# Rollback last migration
+php artisan migrate:rollback --step=1 --force
+
+# Rollback specific batch
+php artisan migrate:rollback --batch=3 --force
+
+# Full rollback to fresh state (CAUTION!)
+php artisan migrate:fresh --force
+```
+
+### Blue-Green Deployment
+
+```yaml
+# deployment-blue.yaml (current)
+metadata:
+ name: risk-platform-blue
+ labels:
+ app: risk-platform
+ version: blue
+
+# deployment-green.yaml (new version)
+metadata:
+ name: risk-platform-green
+ labels:
+ app: risk-platform
+ version: green
+
+# Switch Traffic
+# Change service selector from blue to green
+kubectl patch service risk-platform-service \
+ -p '{"spec":{"selector":{"version":"green"}}}' \
+ -n risk-platform
+```
+
+---
+
+## Troubleshooting
+
+### Problem: Container startet nicht
+
+**Diagnose:**
+```bash
+docker logs risk-platform
+kubectl logs deployment/risk-platform -n risk-platform
+```
+
+**HÀufige Ursachen:**
+- `.env` fehlt oder ungÃŒltig
+- Database Connection fehlgeschlagen
+- Permissions auf `storage/` fehlen
+
+**Lösung:**
+```bash
+# Check .env
+docker exec -it risk-platform cat /var/www/html/.env
+
+# Fix permissions
+docker exec -it risk-platform chown -R nginx:nginx storage
+```
+
+---
+
+### Problem: "500 Internal Server Error"
+
+**Diagnose:**
+```bash
+# Laravel Logs
+tail -f storage/logs/laravel.log
+
+# Nginx Error Log
+tail -f /var/log/nginx/error.log
+```
+
+**HÀufige Ursachen:**
+- `APP_KEY` nicht gesetzt
+- Config Cache veraltet
+- Database Connection Error
+
+**Lösung:**
+```bash
+# Generate APP_KEY
+php artisan key:generate --force
+
+# Clear caches
+php artisan optimize:clear
+
+# Test DB connection
+php artisan tinker
+>>> DB::connection()->getPdo()
+```
+
+---
+
+### Problem: Scheduled Jobs laufen nicht
+
+**Diagnose:**
+```bash
+# Check CronJob Status
+kubectl get cronjobs -n risk-platform
+
+# Check Job History
+kubectl get jobs -n risk-platform
+
+# Check Logs
+kubectl logs job/sync-backend-data-pool-xxx -n risk-platform
+```
+
+**Lösung:**
+```bash
+# Test Schedule manually
+php artisan schedule:run
+
+# Test specific Job
+php artisan backend:sync-data-pool --incremental
+```
+
+---
+
+### Problem: High Memory Usage
+
+**Diagnose:**
+```bash
+# Container Stats
+docker stats risk-platform
+
+# Pod Resource Usage
+kubectl top pod -n risk-platform
+```
+
+**Lösung:**
+- Reduce batch size in Jobs
+- Increase memory limits
+- Enable OPcache
+- Use Redis for cache/session
+
+---
+
+## Performance Optimization
+
+### OPcache Configuration
+
+```ini
+; /etc/php82/conf.d/opcache.ini
+opcache.enable=1
+opcache.memory_consumption=256
+opcache.interned_strings_buffer=16
+opcache.max_accelerated_files=10000
+opcache.revalidate_freq=60
+opcache.fast_shutdown=1
+```
+
+### Redis Configuration
+
+```yaml
+# redis.conf
+maxmemory 512mb
+maxmemory-policy allkeys-lru
+```
+
+### Database Optimization
+
+```sql
+-- Index on frequently queried columns
+CREATE INDEX idx_transactions_status ON transactions(status);
+CREATE INDEX idx_transactions_risk_score ON transactions(risk_score);
+CREATE INDEX idx_companies_kyc_risk_level ON companies(kyc_risk_level);
+
+-- Vacuum regularly
+VACUUM ANALYZE companies;
+VACUUM ANALYZE transactions;
+```
+
+---
+
+## Security Best Practices
+
+### SSL/TLS
+
+```yaml
+# ingress.yaml with TLS
+spec:
+ tls:
+ - hosts:
+ - risk.example.com
+ secretName: risk-platform-tls
+```
+
+### Firewall Rules
+
+```bash
+# Allow HTTP/HTTPS only
+ufw allow 80/tcp
+ufw allow 443/tcp
+ufw enable
+```
+
+### Security Headers
+
+```nginx
+# nginx.conf
+add_header X-Frame-Options "SAMEORIGIN";
+add_header X-Content-Type-Options "nosniff";
+add_header X-XSS-Protection "1; mode=block";
+add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
+```
+
+---
+
+## Zusammenfassung
+
+### Deployment-Optionen
+
+| Option | KomplexitÀt | Skalierbarkeit | Empfohlen fÌr |
+|--------|-------------|----------------|---------------|
+| **Docker** | Niedrig | Mittel | Development, Small Production |
+| **Kubernetes** | Hoch | Hoch | Production, Enterprise |
+| **Traditional** | Mittel | Niedrig | Legacy Systems |
+
+### Checkliste fÃŒr Production
+
+â
Environment auf `production` gesetzt
+â
`APP_DEBUG=false`
+â
HTTPS aktiviert
+â
Database-Backup automatisiert
+â
Monitoring & Logging konfiguriert
+â
Scheduled Jobs laufen
+â
Health Checks aktiv
+â
Secrets sicher gespeichert
+â
Rollback-Strategie getestet
+
+---
+
+**Erstellt:** 2025-11-24
+**Version:** 1.0
+**Autor:** Risk Intelligence Platform Team
diff --git a/docs/developer-setup-guide.md b/docs/developer-setup-guide.md
new file mode 100644
index 0000000..3129b81
--- /dev/null
+++ b/docs/developer-setup-guide.md
@@ -0,0 +1,991 @@
+# Entwickler-Setup-Guide: Risk Intelligence Platform
+
+## ð Inhaltsverzeichnis
+
+1. [Voraussetzungen](#voraussetzungen)
+2. [Schnellstart](#schnellstart)
+3. [Detaillierte Installation](#detaillierte-installation)
+4. [Datenbank-Setup](#datenbank-setup)
+5. [Environment-Konfiguration](#environment-konfiguration)
+6. [Frontend-Assets](#frontend-assets)
+7. [Erste Schritte](#erste-schritte)
+8. [Development-Workflow](#development-workflow)
+9. [Troubleshooting](#troubleshooting)
+10. [NÃŒtzliche Commands](#nÃŒtzliche-commands)
+
+---
+
+## Voraussetzungen
+
+### Erforderliche Software
+
+| Software | Mindestversion | Empfohlen | Installation |
+|----------|---------------|-----------|--------------|
+| **PHP** | 8.2 | 8.4.14+ | [Laravel Herd](https://herd.laravel.com) |
+| **Composer** | 2.0 | Latest | Via Herd oder [getcomposer.org](https://getcomposer.org) |
+| **Node.js** | 18.x | 20.x+ | [nodejs.org](https://nodejs.org) |
+| **npm** | 9.x | Latest | Mit Node.js installiert |
+| **PostgreSQL** | 14.x | 16.x+ | [postgresql.org](https://www.postgresql.org) |
+| **Git** | 2.x | Latest | [git-scm.com](https://git-scm.com) |
+
+### Empfohlene Tools
+
+- **Laravel Herd** - Lokale PHP-Entwicklungsumgebung (macOS)
+- **TablePlus** / **pgAdmin** - PostgreSQL GUI
+- **VS Code** - Editor mit PHP/Laravel Extensions
+- **Postman** / **Insomnia** - API Testing (optional)
+
+### PHP Extensions
+
+Folgende PHP Extensions werden benötigt:
+
+```bash
+# PrÃŒfe installierte Extensions
+php -m
+
+# Benötigte Extensions:
+- pdo_pgsql # PostgreSQL Driver
+- mbstring # Multibyte String
+- xml # XML Support
+- curl # HTTP Client
+- bcmath # Precision Math
+- fileinfo # File Information
+- json # JSON Support
+- openssl # Encryption
+- tokenizer # PHP Tokenizer
+- zip # ZIP Archive
+```
+
+---
+
+## Schnellstart
+
+FÌr erfahrene Entwickler - vollstÀndige Installation in 5 Minuten:
+
+```bash
+# 1. Repository klonen
+git clone risk-platform
+cd risk-platform
+
+# 2. Dependencies installieren & Setup ausfÃŒhren
+composer setup
+
+# 3. PostgreSQL-Datenbank erstellen (siehe unten)
+# Anpassen: .env mit DB-Credentials
+
+# 4. Migrations ausfÃŒhren
+php artisan migrate --seed
+
+# 5. Development-Server starten
+composer run dev
+```
+
+**Fertig!** Die Applikation lÀuft auf [http://localhost:8000](http://localhost:8000)
+
+---
+
+## Detaillierte Installation
+
+### Schritt 1: Repository klonen
+
+```bash
+# Via HTTPS
+git clone https://github.com/your-org/risk-platform.git
+cd risk-platform
+
+# Oder via SSH
+git clone git@github.com:your-org/risk-platform.git
+cd risk-platform
+```
+
+### Schritt 2: PHP Dependencies installieren
+
+```bash
+composer install
+```
+
+**Was passiert dabei?**
+- Installiert alle Laravel-Pakete
+- Installiert Livewire, Flux UI, Fortify
+- Installiert Dev-Dependencies (Pest, Pint, Boost)
+- Generiert Autoload-Files
+
+### Schritt 3: Environment-Datei erstellen
+
+```bash
+# .env.example nach .env kopieren
+cp .env.example .env
+
+# Application Key generieren
+php artisan key:generate
+```
+
+### Schritt 4: Node Dependencies installieren
+
+```bash
+npm install
+```
+
+**Was passiert dabei?**
+- Installiert Vite
+- Installiert Tailwind CSS v4
+- Installiert Build-Tools
+
+---
+
+## Datenbank-Setup
+
+### PostgreSQL Installation
+
+#### macOS (mit Homebrew)
+
+```bash
+# PostgreSQL installieren
+brew install postgresql@16
+
+# Als Service starten
+brew services start postgresql@16
+
+# Verbindung testen
+psql postgres
+```
+
+#### macOS (mit Postgres.app)
+
+1. Download von [postgresapp.com](https://postgresapp.com)
+2. App starten
+3. Default Server initialisieren
+
+#### Ubuntu/Debian
+
+```bash
+sudo apt update
+sudo apt install postgresql postgresql-contrib
+sudo systemctl start postgresql
+sudo systemctl enable postgresql
+```
+
+### Datenbank erstellen
+
+```bash
+# Als postgres User einloggen
+psql postgres
+
+# Oder direkt mit spezifischem User
+sudo -u postgres psql
+```
+
+```sql
+-- Datenbank erstellen
+CREATE DATABASE risk_platform_db;
+
+-- User erstellen (optional)
+CREATE USER risk_user WITH ENCRYPTED PASSWORD 'your_secure_password';
+
+-- Rechte vergeben
+GRANT ALL PRIVILEGES ON DATABASE risk_platform_db TO risk_user;
+
+-- In PostgreSQL 15+ auch Schema-Rechte vergeben
+\c risk_platform_db
+GRANT ALL ON SCHEMA public TO risk_user;
+
+-- Exit
+\q
+```
+
+### Schemas erstellen
+
+```sql
+-- Verbindung zur DB
+psql -U risk_user -d risk_platform_db
+
+-- PUBLIC Schema (wird automatisch erstellt)
+-- BACKEND Schema erstellen
+CREATE SCHEMA IF NOT EXISTS backend;
+
+-- Rechte fÃŒr BACKEND Schema
+GRANT ALL ON SCHEMA backend TO risk_user;
+
+-- Exit
+\q
+```
+
+### Verbindung testen
+
+```bash
+# Direkter Connect
+psql -h 127.0.0.1 -p 5432 -U risk_user -d risk_platform_db
+
+# Mit Laravel Tinker
+php artisan tinker
+>>> DB::connection('pgsql_second')->select('SELECT version()');
+>>> DB::connection('backend')->select('SELECT current_schema()');
+```
+
+---
+
+## Environment-Konfiguration
+
+### .env Datei anpassen
+
+```bash
+# .env öffnen und anpassen
+nano .env
+```
+
+#### Grundkonfiguration
+
+```ini
+APP_NAME="Risk Intelligence Platform"
+APP_ENV=local
+APP_KEY=base64:xxx # Wird von key:generate erstellt
+APP_DEBUG=true
+APP_URL=http://localhost:8000
+
+APP_LOCALE=de
+APP_FALLBACK_LOCALE=en
+APP_FAKER_LOCALE=de_DE
+```
+
+#### Datenbank-Konfiguration (Wichtig!)
+
+```ini
+# Default Connection (PUBLIC Schema)
+DB_CONNECTION=pgsql
+DB_CONNECTION2=pgsql
+DB_HOST2=127.0.0.1
+DB_PORT2=5432
+DB_DATABASE2=risk_platform_db
+DB_USERNAME2=risk_user
+DB_PASSWORD2=your_secure_password
+```
+
+**Wichtig:** Die Applikation nutzt `DB_*2` Variablen fÃŒr PostgreSQL!
+
+#### Cache & Session
+
+```ini
+CACHE_STORE=database
+SESSION_DRIVER=database
+QUEUE_CONNECTION=database
+```
+
+**Warum database?**
+- Einfaches Setup ohne Redis
+- Funktioniert out-of-the-box
+- FÃŒr Produktion: Wechsel zu Redis empfohlen
+
+#### Mail-Konfiguration (Development)
+
+```ini
+MAIL_MAILER=log
+MAIL_FROM_ADDRESS="noreply@risk-platform.test"
+MAIL_FROM_NAME="${APP_NAME}"
+```
+
+Mails werden in `storage/logs/laravel.log` gespeichert.
+
+#### Optional: Redis (fÃŒr bessere Performance)
+
+```ini
+CACHE_STORE=redis
+SESSION_DRIVER=redis
+QUEUE_CONNECTION=redis
+
+REDIS_HOST=127.0.0.1
+REDIS_PASSWORD=null
+REDIS_PORT=6379
+```
+
+### VollstÀndige .env Vorlage
+
+
+Klicken fÌr vollstÀndige .env Beispiel-Datei
+
+```ini
+APP_NAME="Risk Intelligence Platform"
+APP_ENV=local
+APP_KEY=base64:xxx
+APP_DEBUG=true
+APP_URL=http://localhost:8000
+
+APP_LOCALE=de
+APP_FALLBACK_LOCALE=en
+APP_FAKER_LOCALE=de_DE
+
+APP_MAINTENANCE_DRIVER=file
+PHP_CLI_SERVER_WORKERS=4
+BCRYPT_ROUNDS=12
+
+LOG_CHANNEL=stack
+LOG_STACK=single
+LOG_DEPRECATIONS_CHANNEL=null
+LOG_LEVEL=debug
+
+# PostgreSQL Configuration
+DB_CONNECTION=pgsql
+DB_CONNECTION2=pgsql
+DB_HOST2=127.0.0.1
+DB_PORT2=5432
+DB_DATABASE2=risk_platform_db
+DB_USERNAME2=risk_user
+DB_PASSWORD2=your_secure_password
+
+# Session & Cache
+SESSION_DRIVER=database
+SESSION_LIFETIME=120
+SESSION_ENCRYPT=false
+SESSION_PATH=/
+SESSION_DOMAIN=null
+
+CACHE_STORE=database
+QUEUE_CONNECTION=database
+
+# Broadcasting & Filesystem
+BROADCAST_CONNECTION=log
+FILESYSTEM_DISK=local
+
+# Mail
+MAIL_MAILER=log
+MAIL_FROM_ADDRESS="noreply@risk-platform.test"
+MAIL_FROM_NAME="${APP_NAME}"
+
+# Vite
+VITE_APP_NAME="${APP_NAME}"
+```
+
+
+---
+
+## Frontend-Assets
+
+### Assets kompilieren
+
+```bash
+# Development Build (einmalig)
+npm run build
+
+# Development mit Hot Reload
+npm run dev
+```
+
+### Was macht `npm run dev`?
+
+```
+âââââââââââââââââââââââââââââââââââââââââââââââââââ
+â VITE v7.0.4 ready in X ms â
+â â
+â â Local: http://localhost:5173/ â
+â â Network: use --host to expose â
+â â
+â â Laravel: http://localhost:8000 â
+âââââââââââââââââââââââââââââââââââââââââââââââââââ
+
+â compiled successfully
+```
+
+- Startet Vite Dev-Server auf Port 5173
+- Hot Module Replacement (HMR) aktiviert
+- Tailwind CSS v4 wird kompiliert
+- Livewire-Assets werden gebundled
+
+### Production Build
+
+```bash
+npm run build
+
+# Output:
+# dist/assets/app-xxxxx.js
+# dist/assets/app-xxxxx.css
+```
+
+---
+
+## Erste Schritte
+
+### 1. Migrations ausfÃŒhren
+
+```bash
+# Alle Migrations ausfÃŒhren
+php artisan migrate
+
+# Mit Seeding (Test-Daten)
+php artisan migrate --seed
+
+# Migration-Status prÃŒfen
+php artisan migrate:status
+```
+
+**Erwartete Tabellen nach Migration:**
+
+```
+ââââââââââââââââââââââââââââââââââââ¬âââââââââ
+â Migration â Ran? â
+ââââââââââââââââââââââââââââââââââââŒâââââââââ€
+â 0001_01_01_000000_create_users â Yes â
+â 0001_01_01_000001_create_cache â Yes â
+â 0001_01_01_000002_create_jobs â Yes â
+â 2025_09_02_075243_add_two_factor â Yes â
+â 2025_10_20_181750_create_companies â Yes â
+â 2025_10_20_181753_create_transactions â Yes â
+â 2025_11_16_140224_add_output_columns â Yes â
+â 2025_11_16_150000_create_backend_data_pool â Yes â
+â ... â â
+ââââââââââââââââââââââââââââââââââââŽâââââââââ
+```
+
+### 2. Test-User erstellen
+
+```bash
+php artisan tinker
+```
+
+```php
+// Test-User erstellen
+$user = App\Models\User::create([
+ 'name' => 'Admin User',
+ 'email' => 'admin@example.com',
+ 'password' => bcrypt('password'),
+ 'email_verified_at' => now(),
+]);
+
+// Oder mit Factory
+App\Models\User::factory()->create([
+ 'email' => 'test@example.com',
+]);
+
+exit
+```
+
+### 3. Development-Server starten
+
+#### Option A: Composer Dev Command (Empfohlen)
+
+```bash
+composer run dev
+```
+
+**Startet parallel:**
+- `php artisan serve` â http://localhost:8000
+- `php artisan queue:listen` â Queue Worker
+- `php artisan pail` â Live Logs
+- `npm run dev` â Vite Dev Server
+
+#### Option B: Einzelne Services manuell
+
+```bash
+# Terminal 1: Laravel Server
+php artisan serve
+
+# Terminal 2: Vite Dev Server
+npm run dev
+
+# Terminal 3 (optional): Queue Worker
+php artisan queue:work
+
+# Terminal 4 (optional): Logs
+php artisan pail
+```
+
+#### Option C: Laravel Herd (macOS)
+
+Wenn du Laravel Herd nutzt:
+
+1. Projekt in Herd-Verzeichnis verschieben
+2. Automatische Domain: `risk-platform.test`
+3. HTTPS automatisch aktiviert
+4. Kein `php artisan serve` notwendig
+
+```bash
+# In Herd-Verzeichnis verschieben
+mv ~/risk-platform ~/Herd/risk-platform
+
+# Browser öffnen
+open https://risk-platform.test
+```
+
+### 4. Applikation öffnen
+
+Browser öffnen: [http://localhost:8000](http://localhost:8000)
+
+**Login-Credentials:**
+- Email: `test@example.com`
+- Password: `password`
+
+---
+
+## Development-Workflow
+
+### Typischer Entwicklungstag
+
+```bash
+# 1. Morgen: Repository aktualisieren
+git pull origin main
+
+# 2. Dependencies aktualisieren (falls composer.lock geÀndert)
+composer install
+npm install
+
+# 3. Neue Migrations (falls vorhanden)
+php artisan migrate
+
+# 4. Dev-Server starten
+composer run dev
+
+# 5. Am Ende: Code formatieren
+vendor/bin/pint
+
+# 6. Tests ausfÃŒhren
+php artisan test
+
+# 7. Commit & Push
+git add .
+git commit -m "feat: neue feature"
+git push
+```
+
+### Code-Formatierung
+
+```bash
+# Alle Dateien formatieren
+vendor/bin/pint
+
+# Nur geÀnderte Dateien
+vendor/bin/pint --dirty
+
+# Test-Modus (ohne Ãnderungen)
+vendor/bin/pint --test
+```
+
+### Tests ausfÃŒhren
+
+```bash
+# Alle Tests
+php artisan test
+
+# Nur Feature Tests
+php artisan test --testsuite=Feature
+
+# Nur Unit Tests
+php artisan test --testsuite=Unit
+
+# Spezifische Test-Datei
+php artisan test tests/Feature/CompanyTest.php
+
+# Mit Filter
+php artisan test --filter=testCompanyCreation
+
+# Mit Coverage (benötigt Xdebug)
+php artisan test --coverage
+```
+
+### Backend-Daten synchronisieren
+
+```bash
+# Stats anzeigen (kein Sync)
+php artisan backend:sync-data-pool --stats
+
+# Incremental Sync
+php artisan backend:sync-data-pool --incremental
+
+# Full Sync
+php artisan backend:sync-data-pool --full
+
+# Transformation
+php artisan backend:transform-data-pool
+
+# Kompletter Rebuild
+php artisan backend:rebuild
+```
+
+### Scheduler lokal testen
+
+```bash
+# Schedule Worker (lÀuft dauerhaft)
+php artisan schedule:work
+
+# Oder: NÀchste Due-Tasks anzeigen
+php artisan schedule:list
+
+# Einzelnen Task testen
+php artisan schedule:test sync-backend-data-pool-incremental
+```
+
+---
+
+## Troubleshooting
+
+### Problem: "SQLSTATE[08006] Connection refused"
+
+**Ursache:** PostgreSQL lÀuft nicht oder falsche Credentials
+
+**Lösung:**
+```bash
+# PostgreSQL-Status prÃŒfen
+brew services list | grep postgresql
+
+# PostgreSQL starten
+brew services start postgresql@16
+
+# Verbindung testen
+psql -h 127.0.0.1 -p 5432 -U risk_user -d risk_platform_db
+
+# .env prÃŒfen
+cat .env | grep DB_
+```
+
+---
+
+### Problem: "Class 'PDO' not found"
+
+**Ursache:** PHP PostgreSQL Extension fehlt
+
+**Lösung:**
+```bash
+# Installierte Extensions prÃŒfen
+php -m | grep pdo
+
+# Mit Herd (macOS)
+# Extensions sind normalerweise vorinstalliert
+
+# Oder PHP neu installieren via Homebrew
+brew reinstall php@8.4
+```
+
+---
+
+### Problem: "Vite manifest not found"
+
+**Ursache:** Frontend-Assets nicht kompiliert
+
+**Lösung:**
+```bash
+# Development Build
+npm run build
+
+# Oder Dev-Server starten
+npm run dev
+```
+
+---
+
+### Problem: "419 Page Expired" bei Forms
+
+**Ursache:** CSRF-Token ungÃŒltig (Session abgelaufen)
+
+**Lösung:**
+```bash
+# Cache leeren
+php artisan config:clear
+php artisan cache:clear
+php artisan view:clear
+
+# Browser: Hard Refresh (Cmd+Shift+R / Ctrl+Shift+R)
+```
+
+---
+
+### Problem: Migrations laufen nicht
+
+**Ursache:** Datenbank-Schema fehlt oder keine Rechte
+
+**Lösung:**
+```bash
+# Schema-Rechte prÃŒfen
+psql -U risk_user -d risk_platform_db
+
+# In psql:
+SELECT schema_name FROM information_schema.schemata;
+
+# Rechte vergeben
+GRANT ALL ON SCHEMA public TO risk_user;
+GRANT ALL ON ALL TABLES IN SCHEMA public TO risk_user;
+
+# Migration erneut versuchen
+php artisan migrate
+```
+
+---
+
+### Problem: Queue-Jobs laufen nicht
+
+**Ursache:** Queue-Worker lÀuft nicht
+
+**Lösung:**
+```bash
+# Queue-Worker starten
+php artisan queue:work
+
+# Oder mit Auto-Restart bei Code-Ãnderungen
+php artisan queue:listen
+
+# Failed Jobs anzeigen
+php artisan queue:failed
+
+# Failed Jobs erneut versuchen
+php artisan queue:retry all
+```
+
+---
+
+### Problem: "Class not found" Fehler
+
+**Ursache:** Autoload-Cache veraltet
+
+**Lösung:**
+```bash
+# Autoload neu generieren
+composer dump-autoload
+
+# Alle Caches leeren
+php artisan optimize:clear
+
+# Oder einzeln:
+php artisan config:clear
+php artisan cache:clear
+php artisan route:clear
+php artisan view:clear
+```
+
+---
+
+### Problem: Livewire-Components laden nicht
+
+**Ursache:** Volt-Components nicht registriert
+
+**Lösung:**
+```bash
+# Volt Provider prÃŒfen
+cat bootstrap/providers.php | grep Volt
+
+# Cache leeren
+php artisan optimize:clear
+
+# Browser Cache leeren
+# Cmd+Shift+R (macOS) oder Ctrl+Shift+R (Windows/Linux)
+```
+
+---
+
+### Problem: Styling fehlt / Tailwind funktioniert nicht
+
+**Ursache:** Vite-Server lÀuft nicht oder falsche Konfiguration
+
+**Lösung:**
+```bash
+# Vite Dev-Server neu starten
+npm run dev
+
+# Oder Production-Build
+npm run build
+
+# Tailwind-Config prÃŒfen
+cat tailwind.config.js
+
+# Node-Modules neu installieren
+rm -rf node_modules package-lock.json
+npm install
+```
+
+---
+
+## NÃŒtzliche Commands
+
+### Laravel Artisan
+
+```bash
+# Liste aller Commands
+php artisan list
+
+# Command-Hilfe
+php artisan help migrate
+
+# Interaktive Shell
+php artisan tinker
+
+# Cache Management
+php artisan cache:clear
+php artisan config:clear
+php artisan route:clear
+php artisan view:clear
+php artisan optimize:clear # Alle Caches auf einmal
+
+# Database
+php artisan db:show # DB-Info anzeigen
+php artisan migrate:status # Migration-Status
+php artisan migrate:fresh --seed # DB neu aufsetzen + Seeds
+
+# Make Commands
+php artisan make:model Company
+php artisan make:controller CompanyController
+php artisan make:migration create_companies_table
+php artisan make:livewire CompanySearch
+php artisan make:test CompanyTest
+php artisan make:class Services/MyService
+
+# Routes
+php artisan route:list # Alle Routes anzeigen
+php artisan route:list --path=companies # Gefiltert
+```
+
+### Composer
+
+```bash
+# Dependencies installieren
+composer install
+
+# Development-Dependencies ÃŒberspringen
+composer install --no-dev
+
+# Einzelnes Package installieren
+composer require laravel/telescope
+
+# Package entfernen
+composer remove laravel/telescope
+
+# Autoload regenerieren
+composer dump-autoload
+
+# Setup ausfÃŒhren (custom script)
+composer setup
+
+# Dev-Server starten (custom script)
+composer run dev
+
+# Tests ausfÃŒhren (custom script)
+composer test
+```
+
+### NPM
+
+```bash
+# Dependencies installieren
+npm install
+
+# Dev-Server starten
+npm run dev
+
+# Production Build
+npm run build
+
+# Package installieren
+npm install alpine.js
+
+# Package entfernen
+npm uninstall alpine.js
+
+# Outdated Packages prÃŒfen
+npm outdated
+
+# Updates installieren
+npm update
+```
+
+### Git
+
+```bash
+# Aktueller Branch
+git branch
+
+# Neuen Branch erstellen
+git checkout -b feature/neue-funktion
+
+# Ãnderungen anzeigen
+git status
+git diff
+
+# Commit
+git add .
+git commit -m "feat: neue funktion"
+git push origin feature/neue-funktion
+
+# Main aktualisieren
+git checkout main
+git pull origin main
+```
+
+### PostgreSQL
+
+```bash
+# Verbinden
+psql -U risk_user -d risk_platform_db
+
+# In psql:
+\dt # Alle Tabellen
+\d companies # Tabellen-Schema anzeigen
+\dn # Alle Schemas
+\du # Alle User
+\l # Alle Datenbanken
+\q # Exit
+
+# Backup erstellen
+pg_dump -U risk_user risk_platform_db > backup.sql
+
+# Backup einspielen
+psql -U risk_user risk_platform_db < backup.sql
+```
+
+---
+
+## NÀchste Schritte
+
+Nach erfolgreichem Setup:
+
+1. **Architektur-Dokumentation lesen** â [docs/architecture-overview.md](architecture-overview.md)
+2. **Backend-Sync Commands kennenlernen** â [docs/backend-sync-commands.md](backend-sync-commands.md)
+3. **Code-Konventionen studieren** â [CLAUDE.md](../CLAUDE.md)
+4. **Tests schreiben & ausfÃŒhren** â `php artisan test`
+5. **Erste Ãnderungen committen** â `git commit`
+
+---
+
+## Hilfe & Support
+
+### Dokumentation
+
+- **Architektur-Ãbersicht:** [docs/architecture-overview.md](architecture-overview.md)
+- **Backend-Sync:** [docs/backend-sync-commands.md](backend-sync-commands.md)
+- **Scheduling:** [docs/scheduling-setup.md](scheduling-setup.md)
+- **Migration:** [docs/sync-migration-instructions.md](sync-migration-instructions.md)
+
+### Laravel Dokumentation
+
+- **Laravel 12:** [https://laravel.com/docs/12.x](https://laravel.com/docs/12.x)
+- **Livewire 3:** [https://livewire.laravel.com](https://livewire.laravel.com)
+- **Flux UI:** [https://flux.laravel.com](https://flux.laravel.com)
+- **Pest Testing:** [https://pestphp.com](https://pestphp.com)
+
+### Logs prÃŒfen
+
+```bash
+# Application Logs (Live)
+tail -f storage/logs/laravel.log
+
+# Nur Fehler
+tail -f storage/logs/laravel.log | grep ERROR
+
+# Mit Laravel Pail (farbig)
+php artisan pail
+```
+
+### Debugging
+
+```bash
+# Laravel Debugbar (installiert)
+# Aktiviert automatisch wenn APP_DEBUG=true
+# Erscheint am unteren Bildschirmrand im Browser
+
+# Tinker fÃŒr schnelle Tests
+php artisan tinker
+>>> App\Models\Company::count()
+>>> DB::table('transactions')->latest()->first()
+```
+
+---
+
+**Setup-Zeit:** ~15-30 Minuten
+**Erstellt:** 2025-11-24
+**Version:** 1.0
+**Autor:** Risk Intelligence Platform Team
+
+Viel Erfolg beim Entwickeln! ð
diff --git a/docs/testing-guide.md b/docs/testing-guide.md
new file mode 100644
index 0000000..a2d8fce
--- /dev/null
+++ b/docs/testing-guide.md
@@ -0,0 +1,1047 @@
+# Testing-Guide: Risk Intelligence Platform
+
+## ð Inhaltsverzeichnis
+
+1. [Ãbersicht](#ÃŒbersicht)
+2. [Test-Framework: Pest](#test-framework-pest)
+3. [Test-Struktur](#test-struktur)
+4. [Tests ausfÃŒhren](#tests-ausfÃŒhren)
+5. [Feature Tests schreiben](#feature-tests-schreiben)
+6. [Unit Tests schreiben](#unit-tests-schreiben)
+7. [Livewire/Volt Tests](#livewirevoltt-tests)
+8. [Database Testing](#database-testing)
+9. [Test-Factories](#test-factories)
+10. [Best Practices](#best-practices)
+11. [Coverage & CI/CD](#coverage--cicd)
+12. [Troubleshooting](#troubleshooting)
+
+---
+
+## Ãbersicht
+
+Die Risk Intelligence Platform nutzt **Pest v4** als Testing-Framework - eine moderne, ausdrucksstarke Alternative zu PHPUnit.
+
+### Test-Philosophie
+
+â
**Feature Tests ÃŒber Unit Tests** - Teste Verhalten, nicht Implementierung
+â
**Factories fÃŒr Test-Daten** - Konsistente, realistische Test-Daten
+â
**RefreshDatabase** - Jeder Test startet mit sauberer DB
+â
**Arrange-Act-Assert** - Klare Test-Struktur
+â
**Beschreibende Test-Namen** - Tests als lebende Dokumentation
+
+### Aktuelle Test-Coverage
+
+```
+tests/
+âââ Feature/ # 19 Test-Dateien
+â âââ Auth/ # Authentication & 2FA
+â âââ Settings/ # User Settings
+â âââ Jobs/ # Background Jobs
+â âââ Livewire/ # Livewire Components
+âââ Unit/ # 1 Test-Datei
+ âââ ExampleTest.php
+```
+
+**Gesamt:** ~20 Test-Dateien mit 50+ einzelnen Tests
+
+---
+
+## Test-Framework: Pest
+
+### Warum Pest?
+
+**Pest v4** bietet moderne Testing-Features:
+
+- â
**Ausdrucksstarke Syntax** - `test()` statt `public function test...()`
+- â
**Expectations API** - `expect($value)->toBe(true)`
+- â
**Datasets** - Parametrisierte Tests
+- â
**Higher Order Tests** - `->it()` Syntax
+- â
**Browser Testing** - Integriertes Browser-Testing (Pest v4)
+- â
**Parallel Execution** - Schnellere Test-AusfÃŒhrung
+
+### Pest vs PHPUnit
+
+```php
+// PHPUnit (alt)
+class UserTest extends TestCase
+{
+ public function test_user_can_login()
+ {
+ $this->assertTrue(true);
+ }
+}
+
+// Pest (modern)
+test('user can login', function () {
+ expect(true)->toBeTrue();
+});
+```
+
+---
+
+## Test-Struktur
+
+### Verzeichnis-Layout
+
+```
+tests/
+âââ Pest.php # Pest-Konfiguration
+âââ TestCase.php # Basis Test-Klasse
+â
+âââ Feature/ # Feature Tests (End-to-End)
+â âââ Auth/
+â â âââ AuthenticationTest.php
+â â âââ RegistrationTest.php
+â â âââ PasswordResetTest.php
+â â âââ EmailVerificationTest.php
+â â âââ PasswordConfirmationTest.php
+â â âââ TwoFactorChallengeTest.php
+â â
+â âââ Settings/
+â â âââ ProfileUpdateTest.php
+â â âââ PasswordUpdateTest.php
+â â âââ TwoFactorAuthenticationTest.php
+â â
+â âââ Jobs/
+â â âââ SyncBackendDataPoolTest.php
+â â
+â âââ Livewire/
+â â âââ Upload/
+â â âââ IndexTest.php
+â â
+â âââ CompanySearchTest.php
+â âââ TransactionReviewTest.php
+â âââ CompanyTransactionsTest.php
+â âââ BackendModelsTest.php
+â âââ NavigationTest.php
+â âââ DashboardTest.php
+â âââ ExampleTest.php
+â
+âââ Unit/ # Unit Tests (isoliert)
+ âââ ExampleTest.php
+```
+
+### Test-Typen
+
+| Typ | Zweck | Beispiel |
+|-----|-------|----------|
+| **Feature** | End-to-End User Flows | "User kann sich einloggen" |
+| **Unit** | Einzelne Klassen/Methoden | "calculateRiskScore() gibt korrekten Wert zurÃŒck" |
+| **Browser** | UI-Tests im echten Browser | "Click-Flow durch Transaction Review" |
+
+---
+
+## Tests ausfÃŒhren
+
+### Basis-Commands
+
+```bash
+# Alle Tests ausfÃŒhren
+php artisan test
+
+# Oder direkt mit Pest
+./vendor/bin/pest
+
+# Nur Feature Tests
+php artisan test --testsuite=Feature
+
+# Nur Unit Tests
+php artisan test --testsuite=Unit
+
+# Parallele AusfÃŒhrung (schneller)
+php artisan test --parallel
+```
+
+### Spezifische Tests
+
+```bash
+# Einzelne Test-Datei
+php artisan test tests/Feature/CompanySearchTest.php
+
+# Test mit bestimmtem Namen
+php artisan test --filter="user can login"
+
+# Test-Gruppe
+php artisan test --group=auth
+
+# Mit Ausgabe-Details
+php artisan test --verbose
+
+# Stopp beim ersten Fehler
+php artisan test --stop-on-failure
+```
+
+### Output-Formate
+
+```bash
+# Minimal (nur Zusammenfassung)
+php artisan test --compact
+
+# Mit Coverage (benötigt Xdebug)
+php artisan test --coverage
+
+# Mit Coverage-Minimum
+php artisan test --coverage --min=80
+
+# HTML Coverage Report
+php artisan test --coverage-html coverage/
+```
+
+---
+
+## Feature Tests schreiben
+
+Feature Tests testen **User Flows** und **End-to-End Szenarien**.
+
+### Beispiel 1: Authentifizierung
+
+```php
+create([
+ 'email' => 'test@example.com',
+ 'password' => bcrypt('password'),
+ ]);
+
+ // Act - Login-Versuch
+ $response = $this->post('/login', [
+ 'email' => 'test@example.com',
+ 'password' => 'password',
+ ]);
+
+ // Assert - PrÃŒfungen
+ $response->assertRedirect('/dashboard');
+ $this->assertAuthenticated();
+});
+
+test('user cannot login with invalid password', function () {
+ $user = User::factory()->create([
+ 'email' => 'test@example.com',
+ 'password' => bcrypt('password'),
+ ]);
+
+ $response = $this->post('/login', [
+ 'email' => 'test@example.com',
+ 'password' => 'wrong-password',
+ ]);
+
+ $response->assertSessionHasErrors();
+ $this->assertGuest();
+});
+```
+
+### Beispiel 2: Company Search
+
+```php
+actingAs(User::factory()->create());
+
+ // Act
+ $response = $this->get(route('company-search'));
+
+ // Assert
+ $response->assertOk();
+ $response->assertSee('Unternehmensauskunft');
+});
+
+test('search filters companies by name', function () {
+ $this->actingAs(User::factory()->create());
+
+ // Arrange - Test-Companies erstellen
+ $mercedes = Company::factory()->create([
+ 'name' => 'Mercedes-Benz Group AG',
+ 'ticker' => 'MBG',
+ ]);
+
+ $volkswagen = Company::factory()->create([
+ 'name' => 'Volkswagen AG',
+ 'ticker' => 'VOW',
+ ]);
+
+ Transaction::factory()->for($mercedes)->create();
+ Transaction::factory()->for($volkswagen)->create();
+
+ // Act - Suche nach "Mercedes"
+ $component = Livewire\Volt\Volt::test('company-search')
+ ->set('search', 'Mercedes');
+
+ // Assert - Nur Mercedes gefunden
+ $companies = $component->get('companies');
+
+ expect($companies)
+ ->toHaveCount(1)
+ ->and($companies->first()->id)->toBe($mercedes->id);
+});
+```
+
+### Beispiel 3: Job Testing
+
+```php
+insert([
+ 'transaction_id' => 999,
+ 'corporate_entity' => 'Old Company',
+ 'tx_amount' => 1000.00,
+ 'status' => 'done',
+ 'prompt_id' => 1,
+ 'output_key' => 'test_key',
+ 'content' => 'test content',
+ 'created_at' => now(),
+ 'last_modified_at' => now(),
+ 'synced_at' => now(),
+ ]);
+
+ expect(DB::table('backend_data_pool')->count())->toBe(1);
+
+ // Act - Full Sync ausfÃŒhren
+ $job = new SyncBackendDataPool(fullSync: true, batchSize: 100);
+ $job->handle();
+
+ // Assert - Alte Daten entfernt
+ $oldRecord = DB::table('backend_data_pool')
+ ->where('transaction_id', 999)
+ ->first();
+
+ expect($oldRecord)->toBeNull();
+});
+
+test('incremental sync only adds new records', function () {
+ // Arrange - Initial Sync
+ $job = new SyncBackendDataPool(fullSync: true);
+ $job->handle();
+
+ $initialCount = DB::table('backend_data_pool')->count();
+
+ // Act - Incremental Sync
+ $incrementalJob = new SyncBackendDataPool(fullSync: false);
+ $incrementalJob->handle();
+
+ // Assert - Keine Duplikate
+ $newCount = DB::table('backend_data_pool')->count();
+ expect($newCount)->toBe($initialCount);
+});
+```
+
+---
+
+## Unit Tests schreiben
+
+Unit Tests testen **einzelne Klassen/Methoden** isoliert.
+
+### Beispiel 1: KYC Risk Calculator
+
+```php
+calculate([
+ 'transaction_score' => 20,
+ 'sanctions' => 0,
+ 'country_risk' => 10,
+ 'pep' => 0,
+ 'corruption' => 0,
+ ]);
+
+ expect($result['level'])->toBe('low')
+ ->and($result['score'])->toBeLessThan(50);
+});
+
+test('calculates critical risk with sanctions', function () {
+ $calculator = new KycRiskCalculator();
+
+ $result = $calculator->calculate([
+ 'transaction_score' => 50,
+ 'sanctions' => 100, // Critical!
+ 'country_risk' => 30,
+ 'pep' => 20,
+ 'corruption' => 10,
+ ]);
+
+ expect($result['level'])->toBe('critical')
+ ->and($result['score'])->toBeGreaterThan(70);
+});
+```
+
+### Beispiel 2: Model Methods
+
+```php
+make([
+ 'status' => Transaction::STATUS_TRUE_POSITIVE,
+ ]);
+
+ expect($transaction->statusLabel())->toBe('Kritisches Risiko');
+
+ $transaction->status = Transaction::STATUS_CLEARED;
+ expect($transaction->statusLabel())->toBe('Geringes Risiko');
+});
+
+test('company has many transactions relationship', function () {
+ $company = Company::factory()
+ ->has(Transaction::factory()->count(3))
+ ->create();
+
+ expect($company->transactions)->toHaveCount(3);
+ expect($company->transactions->first())->toBeInstanceOf(Transaction::class);
+});
+```
+
+---
+
+## Livewire/Volt Tests
+
+### Livewire Volt Component Tests
+
+```php
+actingAs(User::factory()->create());
+
+ Volt::test('company-search')
+ ->assertSet('search', '')
+ ->assertOk();
+});
+
+test('search input updates component state', function () {
+ $this->actingAs(User::factory()->create());
+
+ Volt::test('company-search')
+ ->assertSet('search', '')
+ ->set('search', 'Mercedes')
+ ->assertSet('search', 'Mercedes');
+});
+
+test('component displays search results', function () {
+ $this->actingAs(User::factory()->create());
+
+ Company::factory()->create(['name' => 'Mercedes-Benz AG']);
+
+ Volt::test('company-search')
+ ->set('search', 'Mercedes')
+ ->assertSee('Mercedes-Benz AG');
+});
+
+test('component calls action method', function () {
+ $this->actingAs(User::factory()->create());
+
+ $company = Company::factory()->create();
+
+ Volt::test('company-search')
+ ->call('viewCompany', $company->id)
+ ->assertRedirect(route('company.transactions', $company));
+});
+```
+
+### Testing Livewire Properties
+
+```php
+test('component has required properties', function () {
+ $this->actingAs(User::factory()->create());
+
+ Volt::test('company-search')
+ ->assertPropertyWired('search') // wire:model="search"
+ ->assertSee('wire:model.live.debounce.300ms="search"', false);
+});
+
+test('component computes overview correctly', function () {
+ $this->actingAs(User::factory()->create());
+
+ Company::factory()
+ ->has(Transaction::factory()->requiresReview()->count(5))
+ ->create();
+
+ $component = Volt::test('company-search');
+
+ $overview = $component->get('overview');
+
+ expect($overview)
+ ->toHaveKey('companies')
+ ->toHaveKey('open_alerts')
+ ->toHaveKey('open_volume');
+});
+```
+
+---
+
+## Database Testing
+
+### RefreshDatabase Trait
+
+```php
+// tests/Pest.php
+pest()->extend(Tests\TestCase::class)
+ ->use(Illuminate\Foundation\Testing\RefreshDatabase::class)
+ ->in('Feature');
+```
+
+**Was macht RefreshDatabase?**
+- Migriert DB vor jedem Test
+- Rollt Ãnderungen nach jedem Test zurÃŒck
+- Nutzt Transactions fÃŒr Speed
+
+### Database Assertions
+
+```php
+use Illuminate\Foundation\Testing\RefreshDatabase;
+
+test('company is created in database', function () {
+ $company = Company::factory()->create([
+ 'name' => 'Test AG',
+ ]);
+
+ // Assert in DB
+ $this->assertDatabaseHas('companies', [
+ 'name' => 'Test AG',
+ ]);
+
+ // Oder mit Pest Expectation
+ expect(Company::where('name', 'Test AG')->exists())->toBeTrue();
+});
+
+test('transaction is deleted with company', function () {
+ $company = Company::factory()
+ ->has(Transaction::factory())
+ ->create();
+
+ $transactionId = $company->transactions->first()->id;
+
+ // Delete Company (CASCADE DELETE)
+ $company->delete();
+
+ // Assert Transaction auch gelöscht
+ $this->assertDatabaseMissing('transactions', [
+ 'id' => $transactionId,
+ ]);
+});
+```
+
+### Seeding in Tests
+
+```php
+test('can filter high risk transactions', function () {
+ // Seed Daten
+ $this->seed(CompanySeeder::class);
+
+ // Oder inline
+ Company::factory()
+ ->has(
+ Transaction::factory()
+ ->status(Transaction::STATUS_TRUE_POSITIVE)
+ ->count(3)
+ )
+ ->create();
+
+ $highRisk = Transaction::where('status', 'true_positive')->get();
+
+ expect($highRisk)->toHaveCount(3);
+});
+```
+
+---
+
+## Test-Factories
+
+Factories generieren konsistente Test-Daten.
+
+### Company Factory
+
+```php
+// database/factories/CompanyFactory.php
+
+namespace Database\Factories;
+
+use Illuminate\Database\Eloquent\Factories\Factory;
+
+class CompanyFactory extends Factory
+{
+ public function definition(): array
+ {
+ return [
+ 'name' => fake()->company(),
+ 'legal_name' => fake()->company() . ' AG',
+ 'ticker' => strtoupper(fake()->lexify('???')),
+ 'sector' => fake()->randomElement([
+ 'Automotive', 'Technology', 'Finance', 'Healthcare'
+ ]),
+ 'country' => fake()->countryCode(),
+ 'headquarters' => fake()->city() . ', ' . fake()->country(),
+ 'kyc_risk_level' => fake()->randomElement(['low', 'high', 'critical']),
+ 'summary' => fake()->paragraph(),
+ ];
+ }
+
+ // Custom States
+ public function highRisk(): static
+ {
+ return $this->state(fn (array $attributes) => [
+ 'kyc_risk_level' => 'high',
+ ]);
+ }
+
+ public function criticalRisk(): static
+ {
+ return $this->state(fn (array $attributes) => [
+ 'kyc_risk_level' => 'critical',
+ ]);
+ }
+}
+```
+
+### Transaction Factory
+
+```php
+// database/factories/TransactionFactory.php
+
+class TransactionFactory extends Factory
+{
+ public function definition(): array
+ {
+ return [
+ 'company_id' => Company::factory(),
+ 'reference' => 'TXN-' . fake()->unique()->randomNumber(6),
+ 'amount' => fake()->randomFloat(2, 100, 1000000),
+ 'currency' => 'EUR',
+ 'counterparty' => fake()->company(),
+ 'counterparty_country' => fake()->countryCode(),
+ 'channel' => fake()->randomElement(['SEPA', 'SWIFT', 'Internal']),
+ 'executed_at' => fake()->dateTimeBetween('-1 year', 'now'),
+ 'risk_score' => fake()->numberBetween(0, 255),
+ 'status' => fake()->randomElement([
+ Transaction::STATUS_CLEARED,
+ Transaction::STATUS_FALSE_POSITIVE,
+ Transaction::STATUS_TRUE_POSITIVE,
+ ]),
+ 'requires_review' => fake()->boolean(),
+ ];
+ }
+
+ // States
+ public function requiresReview(bool $value = true): static
+ {
+ return $this->state(fn (array $attributes) => [
+ 'requires_review' => $value,
+ ]);
+ }
+
+ public function status(string $status): static
+ {
+ return $this->state(fn (array $attributes) => [
+ 'status' => $status,
+ ]);
+ }
+
+ public function highRisk(): static
+ {
+ return $this->state(fn (array $attributes) => [
+ 'risk_score' => fake()->numberBetween(150, 200),
+ 'status' => Transaction::STATUS_FALSE_POSITIVE,
+ 'requires_review' => true,
+ ]);
+ }
+
+ public function criticalRisk(): static
+ {
+ return $this->state(fn (array $attributes) => [
+ 'risk_score' => fake()->numberBetween(200, 255),
+ 'status' => Transaction::STATUS_TRUE_POSITIVE,
+ 'requires_review' => true,
+ ]);
+ }
+}
+```
+
+### Factory-Nutzung in Tests
+
+```php
+// Einfach
+$company = Company::factory()->create();
+
+// Mit Overrides
+$company = Company::factory()->create([
+ 'name' => 'Custom Name AG',
+]);
+
+// Mit State
+$company = Company::factory()->highRisk()->create();
+
+// Mit Beziehungen
+$company = Company::factory()
+ ->has(Transaction::factory()->count(5))
+ ->create();
+
+// Oder anders herum
+$transaction = Transaction::factory()
+ ->for(Company::factory()->highRisk())
+ ->create();
+
+// Mehrere mit State-Chain
+$companies = Company::factory()
+ ->count(3)
+ ->highRisk()
+ ->create();
+
+// Ohne DB-Speicherung (nur Object)
+$company = Company::factory()->make();
+```
+
+---
+
+## Best Practices
+
+### 1. Arrange-Act-Assert Pattern
+
+```php
+test('user can update profile', function () {
+ // Arrange - Setup
+ $user = User::factory()->create(['name' => 'Old Name']);
+ $this->actingAs($user);
+
+ // Act - Aktion ausfÃŒhren
+ $response = $this->put('/profile', [
+ 'name' => 'New Name',
+ 'email' => $user->email,
+ ]);
+
+ // Assert - PrÃŒfungen
+ $response->assertRedirect();
+ expect($user->fresh()->name)->toBe('New Name');
+});
+```
+
+### 2. Beschreibende Test-Namen
+
+```php
+// â
Gut
+test('user cannot delete other users transactions', function () { ... });
+
+// â Schlecht
+test('test1', function () { ... });
+```
+
+### 3. One Concept per Test
+
+```php
+// â
Gut - Ein Test pro Konzept
+test('validates required name field', function () { ... });
+test('validates email format', function () { ... });
+test('validates unique email', function () { ... });
+
+// â Schlecht - Zu viel in einem Test
+test('validates all form fields', function () {
+ // Tests name, email, password, etc...
+});
+```
+
+### 4. Nutze Datasets fÌr Àhnliche Tests
+
+```php
+test('validates email format', function (string $email, bool $valid) {
+ $response = $this->post('/register', [
+ 'email' => $email,
+ 'password' => 'password',
+ ]);
+
+ if ($valid) {
+ $response->assertSessionHasNoErrors('email');
+ } else {
+ $response->assertSessionHasErrors('email');
+ }
+})->with([
+ 'valid email' => ['test@example.com', true],
+ 'missing @' => ['testexample.com', false],
+ 'missing domain' => ['test@', false],
+ 'spaces' => ['test @example.com', false],
+]);
+```
+
+### 5. beforeEach & afterEach Hooks
+
+```php
+beforeEach(function () {
+ // Vor jedem Test in dieser Datei
+ $this->user = User::factory()->create();
+ $this->actingAs($this->user);
+});
+
+afterEach(function () {
+ // Nach jedem Test
+ // Cleanup falls nötig
+});
+
+test('can access dashboard', function () {
+ // $this->user ist bereits verfÃŒgbar
+ $this->get('/dashboard')->assertOk();
+});
+```
+
+### 6. Test Doubles & Mocking
+
+```php
+use Illuminate\Support\Facades\Mail;
+use App\Mail\WelcomeMail;
+
+test('sends welcome email on registration', function () {
+ // Arrange - Mail mocken
+ Mail::fake();
+
+ // Act
+ $this->post('/register', [
+ 'name' => 'Test User',
+ 'email' => 'test@example.com',
+ 'password' => 'password',
+ ]);
+
+ // Assert - Mail wurde gesendet
+ Mail::assertSent(WelcomeMail::class, function ($mail) {
+ return $mail->hasTo('test@example.com');
+ });
+});
+```
+
+---
+
+## Coverage & CI/CD
+
+### Code Coverage generieren
+
+```bash
+# Einfacher Coverage-Report
+php artisan test --coverage
+
+# Mit Minimum-Schwellwert
+php artisan test --coverage --min=80
+
+# HTML Report
+php artisan test --coverage-html coverage/
+
+# Report öffnen
+open coverage/index.html
+```
+
+### Coverage-Konfiguration
+
+```xml
+
+
+
+ app
+
+
+ app/Console/Commands
+ app/Providers/AppServiceProvider.php
+
+
+```
+
+### GitHub Actions Integration
+
+```yaml
+# .github/workflows/tests.yml
+name: Tests
+
+on: [push, pull_request]
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: 8.4
+ extensions: pdo_pgsql, mbstring, xml
+
+ - name: Install Dependencies
+ run: composer install --no-interaction
+
+ - name: Run Tests
+ run: php artisan test --parallel
+```
+
+---
+
+## Troubleshooting
+
+### Problem: "Database file does not exist"
+
+**Lösung:**
+```bash
+# SQLite DB erstellen
+touch database/database.sqlite
+
+# Oder in .env.testing
+DB_CONNECTION=sqlite
+DB_DATABASE=:memory:
+```
+
+---
+
+### Problem: "Class not found in test"
+
+**Lösung:**
+```bash
+composer dump-autoload
+php artisan optimize:clear
+```
+
+---
+
+### Problem: "RefreshDatabase Migration failed"
+
+**Lösung:**
+```bash
+# Migrations prÃŒfen
+php artisan migrate:status
+
+# Rollback & Fresh
+php artisan migrate:fresh --env=testing
+```
+
+---
+
+### Problem: Tests laufen sehr langsam
+
+**Lösungen:**
+
+1. **Parallele AusfÃŒhrung:**
+```bash
+php artisan test --parallel
+```
+
+2. **SQLite statt PostgreSQL:**
+```xml
+
+
+
+```
+
+3. **Bcrypt Rounds reduzieren:**
+```xml
+
+```
+
+---
+
+### Problem: "Too many connections" Error
+
+**Ursache:** Zu viele parallele DB-Connections
+
+**Lösung:**
+```bash
+# Weniger Prozesse
+php artisan test --parallel --processes=2
+```
+
+---
+
+## NÃŒtzliche Commands
+
+```bash
+# Test-Liste anzeigen
+php artisan test --list-tests
+
+# Neue Test-Datei erstellen
+php artisan make:test CompanyTest # Feature Test
+php artisan make:test CompanyTest --unit # Unit Test
+php artisan make:test CompanyTest --pest # Pest Syntax
+
+# Test mit Debugging
+php artisan test --filter="specific test" --stop-on-failure
+
+# Watch Mode (re-run bei Ãnderungen)
+./vendor/bin/pest --watch
+
+# Nur fehlgeschlagene Tests
+php artisan test --failed
+```
+
+---
+
+## Test-Checkliste
+
+Beim Schreiben neuer Features:
+
+- [ ] Feature Test geschrieben?
+- [ ] Edge Cases getestet?
+- [ ] Validation getestet?
+- [ ] Authorization getestet?
+- [ ] Database-Constraints getestet?
+- [ ] Error Handling getestet?
+- [ ] Factories aktualisiert?
+- [ ] Tests laufen durch (`php artisan test`)?
+- [ ] Code formatiert (`vendor/bin/pint`)?
+
+---
+
+## Zusammenfassung
+
+### Test-Pyramide
+
+```
+ /\
+ / \ Unit Tests (schnell, viele)
+ /____\
+ / \
+ / Feature \ Feature Tests (mittel, weniger)
+ /___________\
+ / \
+ / Browser \ Browser Tests (langsam, wenige)
+/_________________\
+```
+
+### Coverage-Ziele
+
+| Bereich | Target Coverage |
+|---------|----------------|
+| Models | 90%+ |
+| Services | 85%+ |
+| Jobs | 80%+ |
+| Controllers | 70%+ |
+| Commands | 60%+ |
+
+### Test-Performance
+
+| Anzahl Tests | Laufzeit (sequenziell) | Laufzeit (parallel) |
+|--------------|------------------------|---------------------|
+| 50 Tests | ~30s | ~10s |
+| 100 Tests | ~60s | ~20s |
+| 200 Tests | ~120s | ~40s |
+
+---
+
+**Erstellt:** 2025-11-24
+**Version:** 1.0
+**Autor:** Risk Intelligence Platform Team