37 KiB
System-Architektur: Risk Intelligence Platform
📋 Inhaltsverzeichnis
- Übersicht
- System-Diagramm
- Technologie-Stack
- Datenbank-Architektur
- Datenfluss & ETL-Pipeline
- Applikations-Schichten
- Frontend-Architektur
- Backend-Integration
- Scheduling & Automation
- Sicherheit & Authentication
- 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:
// 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
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):
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_summarycorporate_historycorporate_legalnamecorporate_sectorcorporate_HQcorporate_keyexecscorporate_shareholdingcorporate_parentcompanycorporate_subsidiariescorporate_countryofincorporationcorporate_tickercorporate_counterpartycorporate_counterpartysectorcorporate_counterpartycountrycorporate_counterpartysummarycorporate_counterpartyhistory
Sanctions & Compliance:
corporate_eusanctionscorporate_ofacsanctionscorporate_uksanctionscorporate_pepexposurecorporate_AMLexposurecorporate_adversesanctions_circumvention
Country Risk:
country_riskcountry_namecountry_iso2country_iso3country_cpicountry_euprivacycountry_dataprivacycountry_gdprcountry_sanctionscountry_wgicountry_pep
Corruption:
corruption_sectorcorruption_countrycorruption_relationship
Financial & Transaction:
tranx_scoretranx_reasoningtranx_amounttranx_currencytranx_datetranx_counterpartytranx_channelfinancial_assessment
... und weitere 60+ Spalten für detaillierte Analysen
Backend Data Pool Tabelle
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
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
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:
// 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:
// resources/views/livewire/company-search.blade.php
<?php
use Livewire\Volt\Component;
use App\Models\Company;
new class extends Component {
public string $search = '';
public function with(): array
{
return [
'companies' => Company::query()
->when($this->search, fn($q) =>
$q->where('name', 'ilike', "%{$this->search}%")
)
->limit(20)
->get(),
];
}
}
?>
<div>
<flux:input wire:model.live.debounce.300ms="search" />
<!-- UI -->
</div>
Routen-Struktur
// 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
// 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
// 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
// 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
# 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
// 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
php artisan schedule:work
Produktion (Crontab)
crontab -e
# Füge hinzu:
* * * * * cd /path/to/project && php artisan schedule:run >> /dev/null 2>&1
Mit Supervisor
[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:
// 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
# 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
# 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
# .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
# 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
php artisan queue:work --tries=3
php artisan queue:monitor
Database Performance Monitoring
-- 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
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