Files
AFC-Demo/docs/architecture-overview.md
T
cbazza 2f7bd923df
Build and Push Docker Image only on Conventional Commits / build (push) Has been cancelled
local-docker-db branch openend
2025-12-03 12:59:30 +01:00

37 KiB

System-Architektur: Risk Intelligence Platform

📋 Inhaltsverzeichnis

  1. Übersicht
  2. System-Diagramm
  3. Technologie-Stack
  4. Datenbank-Architektur
  5. Datenfluss & ETL-Pipeline
  6. Applikations-Schichten
  7. Frontend-Architektur
  8. Backend-Integration
  9. Scheduling & Automation
  10. Sicherheit & Authentication
  11. 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_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

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