10 KiB
Implementation Summary: Backend Schema Integration
✅ Was wurde implementiert
1. Database Configuration
Datei: config/database.php
Zwei Verbindungen hinzugefügt:
pgsql→ public Schema (Default)backend→ backend Schema (search_path: 'backend')
'default' => env('DB_CONNECTION', 'pgsql'), // Geändert von sqlite zu pgsql
'pgsql' => [
'search_path' => 'public',
],
'backend' => [
'search_path' => 'backend', // Zugriff auf backend Schema
],
2. Backend Models
Backend\Transaction Model
Datei: app/Models/Backend/Transaction.php
Eigenschaften:
- Connection:
backend - Table:
transactions - 14 Felder (Rohdaten aus CSV Upload)
Relationships:
outputs()- HasMany zu TransactionOutput
Helper Methods:
// Outputs abrufen
getOutput(string $key): ?array
getOutputsArray(): array
getCompanyInfo(): ?array
getRiskAssessment(): ?array
getSanctionsCheck(): ?array
getPepCheck(): ?array
// Status & Review
hasOutput(string $key): bool
isProcessed(): bool
requiresReview(): bool
// Display Helpers
getCompanyName(): string
getRiskScore(): int
getRiskLevel(): string
Backend\TransactionOutput Model
Datei: app/Models/Backend/TransactionOutput.php
Eigenschaften:
- Connection:
backend - Table:
transaction_outputs - 5 Felder (KI-generierte Outputs)
Relationships:
transaction()- BelongsTo Transaction
Konstanten (Output-Keys):
KEY_COMPANY_INFO = 'company_info'
KEY_RISK_ASSESSMENT = 'risk_assessment'
KEY_SANCTIONS = 'sanctions'
KEY_PEP = 'pep'
KEY_REGISTRY = 'registry'
KEY_GLEIF = 'gleif'
KEY_INSOLVENCY = 'insolvency'
KEY_BUNDESANZEIGER = 'bundesanzeiger'
KEY_RSS = 'rss'
KEY_EU_SANCTIONS = 'eu_sanctions'
KEY_HANDELSREGISTER = 'handelsregister'
KEY_GENESIS = 'genesis'
KEY_GOVDATA = 'govdata'
Helper Methods:
availableKeys(): array
getKeyLabel(string $key): string
3. Repository Layer
Datei: app/Repositories/TransactionRepository.php
Methoden:
// Basic CRUD
all(): Collection
find(int $id): ?Transaction
paginated(int $perPage = 20)
// Filtering
requiresReview(): Collection
highRisk(int $threshold = 70): Collection
byCompany(string $companyName): Collection
byStatus(string $status): Collection
byDateRange(string $startDate, string $endDate): Collection
search(string $query): Collection
// Status-specific
pending(): Collection
processing(): Collection
completed(): Collection
failed(): Collection
// Statistics
stats(): array
dashboardData(): array
getAllCompanies(): Collection
4. Tests
Datei: tests/Feature/BackendModelsTest.php
11 Tests geschrieben (3 laufen ohne DB-Verbindung):
- ✅ Connection Tests
- ✅ Model Relationship Tests
- ✅ Helper Method Tests
- ✅ Constant Tests
📋 Nächste Schritte: Component-Migration
Betroffene Components
1. transaction-review.blade.php
Aktuell: Verwendet App\Models\Transaction und App\Models\Company
Änderungen:
// Alt
use App\Models\Transaction;
use App\Models\Company;
// Neu
use App\Models\Backend\Transaction;
use App\Repositories\TransactionRepository;
// Repository verwenden statt direkte Model-Queries
public function __construct(
private TransactionRepository $transactions
) {}
$transactions = $this->transactions->all();
Mapping:
| Alt (public.transactions) | Neu (backend) |
|---|---|
$transaction->company->name |
$transaction->getCompanyName() |
$transaction->company->legal_name |
$transaction->getCompanyInfo()['legal_name'] |
$transaction->company->sector |
$transaction->getCompanyInfo()['sector'] |
$transaction->risk_score |
$transaction->getRiskScore() |
$transaction->requires_review |
$transaction->requiresReview() |
$transaction->amount |
$transaction->tx_amount |
$transaction->counterparty |
$transaction->corporate_counterparty |
$transaction->executed_at |
$transaction->tx_date (⚠️ ist text) |
2. companies/transactions.blade.php
Aktuell: Verwendet App\Models\Company Parameter
Änderungen:
- Company-Daten kommen jetzt aus
transaction_outputs - Grouping nach
corporate_entitystattcompany_id
Neuer Ansatz:
// Alle Transaktionen für eine Firma
$companyName = 'Siemens AG'; // Aus Route oder Parameter
$transactions = $this->transactions->byCompany($companyName);
// Company-Info aus erster Transaction
$companyInfo = $transactions->first()?->getCompanyInfo();
3. company-search.blade.php
Änderungen:
- Suche jetzt in
backend.transactions.corporate_entity - Keine separate Company-Tabelle mehr
// Repository Method
public function getAllCompanies(): Collection
{
return DB::connection('backend')
->table('transactions')
->select('corporate_entity as name')
->distinct()
->orderBy('corporate_entity')
->get();
}
🔄 Migrationsplan (Step-by-Step)
Phase 1: Testen ohne Breaking Changes (empfohlen)
Option A: Feature Flag
// config/features.php
'use_backend_schema' => env('FEATURE_USE_BACKEND_SCHEMA', false),
// In Components
if (config('features.use_backend_schema')) {
$transactions = app(TransactionRepository::class)->all();
} else {
$transactions = Transaction::all(); // Alt
}
Option B: Neue Routes (empfohlen für parallele Tests)
// routes/web.php
Route::get('/beta/transactions', ...); // Nutzt Backend-Schema
Route::get('/transactions', ...); // Alte Implementation
Phase 2: Direkte Migration (schneller, aber riskanter)
- Alle
use App\Models\Transactionersetzen:
find resources/views/livewire -type f -name "*.php" -exec sed -i '' 's/use App\\Models\\Transaction/use App\\Models\\Backend\\Transaction/g' {} +
- Alle
use App\Models\Companyentfernen:
find resources/views/livewire -type f -name "*.php" -exec sed -i '' 's/use App\\Models\\Company;//g' {} +
- Component für Component anpassen:
- transaction-review.blade.php
- companies/transactions.blade.php
- company-search.blade.php
🗺️ Daten-Mapping Referenz
Transaction Fields
| public.transactions | backend.transactions | Typ-Unterschied |
|---|---|---|
| id | id | bigint → integer |
| company_id | - (via corporate_entity) | Relationship entfällt |
| reference | - | Neu: auto-generated |
| amount | tx_amount | numeric → double |
| currency | tx_currency | ✓ |
| counterparty | corporate_counterparty | ✓ |
| counterparty_country | tx_country_incoming | ✓ |
| channel | - | Nicht in backend |
| executed_at | tx_date | timestamp → text! |
| risk_score | - (in outputs) | Via getRiskScore() |
| status | status | ✓ |
| requires_review | - (computed) | Via requiresReview() |
| flagged_by | - | Nicht in backend |
| flagged_reason | tx_purpose | Ähnlich |
| signals | - | Nicht in backend |
Company Fields (jetzt in transaction_outputs)
| public.companies | transaction_outputs (key='company_info') |
|---|---|
| name | content['name'] |
| legal_name | content['legal_name'] |
| ticker | content['ticker'] |
| sector | content['sector'] |
| country | content['country'] |
| headquarters | content['headquarters'] |
| kyc_risk_level | content['kyc_risk_level'] |
| summary | content['summary'] |
Enrichment Fields (in transaction_outputs)
Alle 35 Enrichment-Felder aus public.transactions sind jetzt separate Outputs:
// Alt
$transaction->sanctions_data // JSON
// Neu
$transaction->getOutput('sanctions') // Array
⚠️ Breaking Changes
1. Timestamps sind Text
// Alt
$transaction->executed_at->format('d.m.Y')
// Neu (ACHTUNG: tx_date ist Text!)
$transaction->tx_date // Already string, no format()
Empfehlung: Migration hinzufügen um tx_date von text zu timestamp zu ändern.
2. Company Relationship entfällt
// Alt
$transaction->company->name
$transaction->company()->where(...)
// Neu
$transaction->getCompanyName()
$transaction->getCompanyInfo()['name']
// Kein Relationship mehr verfügbar
3. Feld-Namen ändern sich
// Alt → Neu
amount → tx_amount
counterparty → corporate_counterparty
executed_at → tx_date
Empfehlung: Accessor in Model für Backward-Compatibility:
// In Backend\Transaction Model
protected $appends = ['amount', 'counterparty', 'executed_at'];
public function getAmountAttribute(): float
{
return $this->tx_amount;
}
public function getCounterpartyAttribute(): string
{
return $this->corporate_counterparty;
}
public function getExecutedAtAttribute(): string
{
return $this->tx_date;
}
🎯 Empfohlenes Vorgehen
Option 1: Schrittweise mit Feature Flags (Sicher, 2-3 Wochen)
- ✅ Backend Models & Repository erstellt
- ⬜ Feature Flag System einrichten
- ⬜ Parallele Routes
/beta/*erstellen - ⬜ Einen Component nach dem anderen migrieren
- ⬜ Testen mit echten Nutzern (10%)
- ⬜ Gradual Rollout
- ⬜ Alte Components entfernen
Option 2: Direkte Migration (Schnell, 3-5 Tage)
- ✅ Backend Models & Repository erstellt
- ⬜ Alle Components in einem PR umstellen
- ⬜ Accessor für Backward-Compatibility hinzufügen
- ⬜ Intensives Testing
- ⬜ Deploy mit Rollback-Plan
Option 3: Hybrid (Empfohlen, 1 Woche)
- ✅ Backend Models & Repository erstellt
- ⬜ Accessor für Backward-Compatibility in Backend Models
- ⬜
transaction-reviewComponent migrieren (wichtigster) - ⬜ 1-2 Tage Testing
- ⬜ Restliche Components migrieren
- ⬜ Deploy
📝 Checkliste für Component-Migration
Für jeden Component:
- Import
App\Models\Transaction→App\Models\Backend\Transaction - Import
App\Models\Companyentfernen - Repository injecten statt direkte Model-Queries
company->zugetCompanyInfo()ändern- Field-Namen anpassen (
amount→tx_amount, etc.) executed_atzutx_dateändern->format()Calls beitx_dateentfernen (ist schon Text)- Tests schreiben/anpassen
- Manuell testen
- PR erstellen
🚀 Los geht's!
Möchten Sie:
A) Dass ich jetzt transaction-review.blade.php auf Backend-Schema umstelle?
B) Erst Accessors für Backward-Compatibility hinzufügen?
C) Ein Feature-Flag-System einrichten?
D) Etwas anderes?
Was ist Ihr bevorzugter Ansatz?