Merge branch 'frontend_bob'

This commit is contained in:
Bob Molitor
2025-10-31 13:34:58 +01:00
7 changed files with 687 additions and 297 deletions
+30 -2
View File
@@ -11,7 +11,7 @@ The Laravel Boost guidelines are specifically curated by Laravel maintainers for
## Foundational Context
This application is a Laravel application and its main Laravel ecosystems package & versions are below. You are an expert with them all. Ensure you abide by these specific packages & versions.
- php - 8.4.13
- php - 8.4.14
- laravel/fortify (FORTIFY) - v1
- laravel/framework (LARAVEL) - v12
- laravel/prompts (PROMPTS) - v0
@@ -25,7 +25,6 @@ This application is a Laravel application and its main Laravel ecosystems packag
- phpunit/phpunit (PHPUNIT) - v12
- tailwindcss (TAILWINDCSS) - v4
## Conventions
- You must follow all existing code conventions used in this application. When creating or editing a file, check sibling files for the correct structure, approach, naming.
- Use descriptive names for variables and methods. For example, `isRegisteredForDiscounts`, not `discount()`.
@@ -575,4 +574,33 @@ $pages->assertNoJavascriptErrors()->assertNoConsoleLogs();
- Every change must be programmatically tested. Write a new test or update an existing test, then run the affected tests to make sure they pass.
- Run the minimum number of tests needed to ensure code quality and speed. Use `php artisan test` with a specific filename or filter.
=== laravel/fortify rules ===
## Laravel Fortify
Fortify is a headless authentication backend that provides authentication routes and controllers for Laravel applications.
**Before implementing any authentication features, use the `search-docs` tool to get the latest docs for that specific feature.**
### Configuration & Setup
- Check `config/fortify.php` to see what's enabled. Use `search-docs` for detailed information on specific features.
- Enable features by adding them to the `'features' => []` array: `Features::registration()`, `Features::resetPasswords()`, etc.
- To see the all Fortify registered routes, use the `list-routes` tool with the `only_vendor: true` and `action: "Fortify"` parameters.
- Fortify includes view routes by default (login, register). Set `'views' => false` in the configuration file to disable them if you're handling views yourself.
### Customization
- Views can be customized in `FortifyServiceProvider`'s `boot()` method using `Fortify::loginView()`, `Fortify::registerView()`, etc.
- Customize authentication logic with `Fortify::authenticateUsing()` for custom user retrieval / validation.
- Actions in `app/Actions/Fortify/` handle business logic (user creation, password reset, etc.). They're fully customizable, so you can modify them to change feature behavior.
## Available Features
- `Features::registration()` for user registration.
- `Features::emailVerification()` to verify new user emails.
- `Features::twoFactorAuthentication()` for 2FA with QR codes and recovery codes.
- Add options: `['confirmPassword' => true, 'confirm' => true]` to require password confirmation and OTP confirmation before enabling 2FA.
- `Features::updateProfileInformation()` to let users update their profile.
- `Features::updatePasswords()` to let users change their passwords.
- `Features::resetPasswords()` for password reset via email.
</laravel-boost-guidelines>
+3 -1
View File
@@ -23,4 +23,6 @@ yarn-error.log
.DS_Store
env
*.mcp*
*.mdc
*.mdc
/.mcp.json
AGENTS*.*
+1 -36
View File
@@ -13,43 +13,8 @@
"/Applications/Herd.app/Contents/Resources/herd-mcp.phar"
],
"env": {
"SITE_PATH": "/Users/sebastianfrohlich/Herd/frontend"
"SITE_PATH": "/Users/bobmolitor/Herd/trusted_ai"
}
},
"filesystem": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"/Users/sebastianfrohlich/Desktop",
"/Users/sebastianfrohlich/Library/Mobile Documents/com~apple~CloudDocs/Jupyter Notebooks",
"/Users/sebastianfrohlich/Downloads",
"/Users/sebastianfrohlich/",
"/Users/sebastianfrohlich/Projekte"
]
},
"bear": {
"command": "node",
"args": ["/Users/sebastianfrohlich/Projekte/bear-notes-mcp/dist/index.js"],
"env": {}
},
"postgresql": {
"command": "npx",
"args": [
"-y",
"@executeautomation/database-server",
"--postgresql",
"--host",
"localhost",
"--database",
"risk_ingest_db",
"--user",
"risk_ingest_user",
"--password",
"S0prast3r1a",
"--port",
"5433"
]
}
}
}
+30 -2
View File
@@ -8,7 +8,7 @@ The Laravel Boost guidelines are specifically curated by Laravel maintainers for
## Foundational Context
This application is a Laravel application and its main Laravel ecosystems package & versions are below. You are an expert with them all. Ensure you abide by these specific packages & versions.
- php - 8.4.13
- php - 8.4.14
- laravel/fortify (FORTIFY) - v1
- laravel/framework (LARAVEL) - v12
- laravel/prompts (PROMPTS) - v0
@@ -22,7 +22,6 @@ This application is a Laravel application and its main Laravel ecosystems packag
- phpunit/phpunit (PHPUNIT) - v12
- tailwindcss (TAILWINDCSS) - v4
## Conventions
- You must follow all existing code conventions used in this application. When creating or editing a file, check sibling files for the correct structure, approach, naming.
- Use descriptive names for variables and methods. For example, `isRegisteredForDiscounts`, not `discount()`.
@@ -572,4 +571,33 @@ $pages->assertNoJavascriptErrors()->assertNoConsoleLogs();
- Every change must be programmatically tested. Write a new test or update an existing test, then run the affected tests to make sure they pass.
- Run the minimum number of tests needed to ensure code quality and speed. Use `php artisan test` with a specific filename or filter.
=== laravel/fortify rules ===
## Laravel Fortify
Fortify is a headless authentication backend that provides authentication routes and controllers for Laravel applications.
**Before implementing any authentication features, use the `search-docs` tool to get the latest docs for that specific feature.**
### Configuration & Setup
- Check `config/fortify.php` to see what's enabled. Use `search-docs` for detailed information on specific features.
- Enable features by adding them to the `'features' => []` array: `Features::registration()`, `Features::resetPasswords()`, etc.
- To see the all Fortify registered routes, use the `list-routes` tool with the `only_vendor: true` and `action: "Fortify"` parameters.
- Fortify includes view routes by default (login, register). Set `'views' => false` in the configuration file to disable them if you're handling views yourself.
### Customization
- Views can be customized in `FortifyServiceProvider`'s `boot()` method using `Fortify::loginView()`, `Fortify::registerView()`, etc.
- Customize authentication logic with `Fortify::authenticateUsing()` for custom user retrieval / validation.
- Actions in `app/Actions/Fortify/` handle business logic (user creation, password reset, etc.). They're fully customizable, so you can modify them to change feature behavior.
## Available Features
- `Features::registration()` for user registration.
- `Features::emailVerification()` to verify new user emails.
- `Features::twoFactorAuthentication()` for 2FA with QR codes and recovery codes.
- Add options: `['confirmPassword' => true, 'confirm' => true]` to require password confirmation and OTP confirmation before enabling 2FA.
- `Features::updateProfileInformation()` to let users update their profile.
- `Features::updatePasswords()` to let users change their passwords.
- `Features::resetPasswords()` for password reset via email.
</laravel-boost-guidelines>
+2 -1
View File
@@ -61,7 +61,8 @@
"@php artisan package:discover --ansi"
],
"post-update-cmd": [
"@php artisan vendor:publish --tag=laravel-assets --ansi --force"
"@php artisan vendor:publish --tag=laravel-assets --ansi --force",
"@php artisan boost:update --ansi"
],
"post-root-package-install": [
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
Generated
+160 -156
View File
@@ -1159,16 +1159,16 @@
},
{
"name": "laravel/fortify",
"version": "v1.31.1",
"version": "v1.31.2",
"source": {
"type": "git",
"url": "https://github.com/laravel/fortify.git",
"reference": "e39a49592e1440508337a765cdc913ff5bcba66f"
"reference": "a046d52ee087ee52c9852b840cf4bbad19f10934"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/fortify/zipball/e39a49592e1440508337a765cdc913ff5bcba66f",
"reference": "e39a49592e1440508337a765cdc913ff5bcba66f",
"url": "https://api.github.com/repos/laravel/fortify/zipball/a046d52ee087ee52c9852b840cf4bbad19f10934",
"reference": "a046d52ee087ee52c9852b840cf4bbad19f10934",
"shasum": ""
},
"require": {
@@ -1220,20 +1220,20 @@
"issues": "https://github.com/laravel/fortify/issues",
"source": "https://github.com/laravel/fortify"
},
"time": "2025-10-03T09:10:57+00:00"
"time": "2025-10-21T14:47:38+00:00"
},
{
"name": "laravel/framework",
"version": "v12.34.0",
"version": "v12.36.1",
"source": {
"type": "git",
"url": "https://github.com/laravel/framework.git",
"reference": "f9ec5a5d88bc8c468f17b59f88e05c8ac3c8d687"
"reference": "cad110d7685fbab990a6bb8184d0cfd847d7c4d8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/framework/zipball/f9ec5a5d88bc8c468f17b59f88e05c8ac3c8d687",
"reference": "f9ec5a5d88bc8c468f17b59f88e05c8ac3c8d687",
"url": "https://api.github.com/repos/laravel/framework/zipball/cad110d7685fbab990a6bb8184d0cfd847d7c4d8",
"reference": "cad110d7685fbab990a6bb8184d0cfd847d7c4d8",
"shasum": ""
},
"require": {
@@ -1439,7 +1439,7 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
"time": "2025-10-14T13:58:31+00:00"
"time": "2025-10-29T14:20:57+00:00"
},
{
"name": "laravel/prompts",
@@ -1818,16 +1818,16 @@
},
{
"name": "league/flysystem",
"version": "3.30.0",
"version": "3.30.1",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/flysystem.git",
"reference": "2203e3151755d874bb2943649dae1eb8533ac93e"
"reference": "c139fd65c1f796b926f4aec0df37f6caa959a8da"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/2203e3151755d874bb2943649dae1eb8533ac93e",
"reference": "2203e3151755d874bb2943649dae1eb8533ac93e",
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/c139fd65c1f796b926f4aec0df37f6caa959a8da",
"reference": "c139fd65c1f796b926f4aec0df37f6caa959a8da",
"shasum": ""
},
"require": {
@@ -1895,9 +1895,9 @@
],
"support": {
"issues": "https://github.com/thephpleague/flysystem/issues",
"source": "https://github.com/thephpleague/flysystem/tree/3.30.0"
"source": "https://github.com/thephpleague/flysystem/tree/3.30.1"
},
"time": "2025-06-25T13:29:59+00:00"
"time": "2025-10-20T15:35:26+00:00"
},
{
"name": "league/flysystem-local",
@@ -2180,16 +2180,16 @@
},
{
"name": "livewire/flux",
"version": "v2.6.0",
"version": "v2.6.1",
"source": {
"type": "git",
"url": "https://github.com/livewire/flux.git",
"reference": "3cb2ea40978449da74b3814eeef75f0388124224"
"reference": "227b88db0a02db91666af2303ea6727a3af78c51"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/livewire/flux/zipball/3cb2ea40978449da74b3814eeef75f0388124224",
"reference": "3cb2ea40978449da74b3814eeef75f0388124224",
"url": "https://api.github.com/repos/livewire/flux/zipball/227b88db0a02db91666af2303ea6727a3af78c51",
"reference": "227b88db0a02db91666af2303ea6727a3af78c51",
"shasum": ""
},
"require": {
@@ -2197,7 +2197,7 @@
"illuminate/support": "^10.0|^11.0|^12.0",
"illuminate/view": "^10.0|^11.0|^12.0",
"laravel/prompts": "^0.1|^0.2|^0.3",
"livewire/livewire": "^3.5.19",
"livewire/livewire": "^3.5.19|^4.0",
"php": "^8.1",
"symfony/console": "^6.0|^7.0"
},
@@ -2240,9 +2240,9 @@
],
"support": {
"issues": "https://github.com/livewire/flux/issues",
"source": "https://github.com/livewire/flux/tree/v2.6.0"
"source": "https://github.com/livewire/flux/tree/v2.6.1"
},
"time": "2025-10-13T23:17:18+00:00"
"time": "2025-10-28T21:12:05+00:00"
},
{
"name": "livewire/livewire",
@@ -2322,21 +2322,21 @@
},
{
"name": "livewire/volt",
"version": "v1.7.2",
"version": "v1.8.0",
"source": {
"type": "git",
"url": "https://github.com/livewire/volt.git",
"reference": "91ba934e72bbd162442840862959ade24dbe728a"
"reference": "2d9783a340d612d32f4ffd38070780ca7d7e9205"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/livewire/volt/zipball/91ba934e72bbd162442840862959ade24dbe728a",
"reference": "91ba934e72bbd162442840862959ade24dbe728a",
"url": "https://api.github.com/repos/livewire/volt/zipball/2d9783a340d612d32f4ffd38070780ca7d7e9205",
"reference": "2d9783a340d612d32f4ffd38070780ca7d7e9205",
"shasum": ""
},
"require": {
"laravel/framework": "^10.38.2|^11.0|^12.0",
"livewire/livewire": "^3.6.1",
"livewire/livewire": "^3.6.1|^4.0",
"php": "^8.1"
},
"require-dev": {
@@ -2390,7 +2390,7 @@
"issues": "https://github.com/livewire/volt/issues",
"source": "https://github.com/livewire/volt"
},
"time": "2025-08-06T15:40:50+00:00"
"time": "2025-10-29T15:52:35+00:00"
},
{
"name": "monolog/monolog",
@@ -2602,25 +2602,25 @@
},
{
"name": "nette/schema",
"version": "v1.3.2",
"version": "v1.3.3",
"source": {
"type": "git",
"url": "https://github.com/nette/schema.git",
"reference": "da801d52f0354f70a638673c4a0f04e16529431d"
"reference": "2befc2f42d7c715fd9d95efc31b1081e5d765004"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nette/schema/zipball/da801d52f0354f70a638673c4a0f04e16529431d",
"reference": "da801d52f0354f70a638673c4a0f04e16529431d",
"url": "https://api.github.com/repos/nette/schema/zipball/2befc2f42d7c715fd9d95efc31b1081e5d765004",
"reference": "2befc2f42d7c715fd9d95efc31b1081e5d765004",
"shasum": ""
},
"require": {
"nette/utils": "^4.0",
"php": "8.1 - 8.4"
"php": "8.1 - 8.5"
},
"require-dev": {
"nette/tester": "^2.5.2",
"phpstan/phpstan-nette": "^1.0",
"phpstan/phpstan-nette": "^2.0@stable",
"tracy/tracy": "^2.8"
},
"type": "library",
@@ -2630,6 +2630,9 @@
}
},
"autoload": {
"psr-4": {
"Nette\\": "src"
},
"classmap": [
"src/"
]
@@ -2658,9 +2661,9 @@
],
"support": {
"issues": "https://github.com/nette/schema/issues",
"source": "https://github.com/nette/schema/tree/v1.3.2"
"source": "https://github.com/nette/schema/tree/v1.3.3"
},
"time": "2024-10-06T23:10:23+00:00"
"time": "2025-10-30T22:57:59+00:00"
},
{
"name": "nette/utils",
@@ -2753,16 +2756,16 @@
},
{
"name": "nikic/php-parser",
"version": "v5.6.1",
"version": "v5.6.2",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
"reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2"
"reference": "3a454ca033b9e06b63282ce19562e892747449bb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2",
"reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/3a454ca033b9e06b63282ce19562e892747449bb",
"reference": "3a454ca033b9e06b63282ce19562e892747449bb",
"shasum": ""
},
"require": {
@@ -2805,9 +2808,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v5.6.1"
"source": "https://github.com/nikic/PHP-Parser/tree/v5.6.2"
},
"time": "2025-08-13T20:13:15+00:00"
"time": "2025-10-21T19:32:17+00:00"
},
{
"name": "nunomaduro/termwind",
@@ -3506,16 +3509,16 @@
},
{
"name": "psy/psysh",
"version": "v0.12.12",
"version": "v0.12.14",
"source": {
"type": "git",
"url": "https://github.com/bobthecow/psysh.git",
"reference": "cd23863404a40ccfaf733e3af4db2b459837f7e7"
"reference": "95c29b3756a23855a30566b745d218bee690bef2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/bobthecow/psysh/zipball/cd23863404a40ccfaf733e3af4db2b459837f7e7",
"reference": "cd23863404a40ccfaf733e3af4db2b459837f7e7",
"url": "https://api.github.com/repos/bobthecow/psysh/zipball/95c29b3756a23855a30566b745d218bee690bef2",
"reference": "95c29b3756a23855a30566b745d218bee690bef2",
"shasum": ""
},
"require": {
@@ -3530,11 +3533,12 @@
"symfony/console": "4.4.37 || 5.3.14 || 5.3.15 || 5.4.3 || 5.4.4 || 6.0.3 || 6.0.4"
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.2"
"bamarni/composer-bin-plugin": "^1.2",
"composer/class-map-generator": "^1.6"
},
"suggest": {
"composer/class-map-generator": "Improved tab completion performance with better class discovery.",
"ext-pcntl": "Enabling the PCNTL extension makes PsySH a lot happier :)",
"ext-pdo-sqlite": "The doc command requires SQLite to work.",
"ext-posix": "If you have PCNTL, you'll want the POSIX extension as well."
},
"bin": [
@@ -3578,9 +3582,9 @@
],
"support": {
"issues": "https://github.com/bobthecow/psysh/issues",
"source": "https://github.com/bobthecow/psysh/tree/v0.12.12"
"source": "https://github.com/bobthecow/psysh/tree/v0.12.14"
},
"time": "2025-09-20T13:46:31+00:00"
"time": "2025-10-27T17:15:31+00:00"
},
{
"name": "ralouphie/getallheaders",
@@ -3856,16 +3860,16 @@
},
{
"name": "symfony/console",
"version": "v7.3.4",
"version": "v7.3.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "2b9c5fafbac0399a20a2e82429e2bd735dcfb7db"
"reference": "cdb80fa5869653c83cfe1a9084a673b6daf57ea7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/2b9c5fafbac0399a20a2e82429e2bd735dcfb7db",
"reference": "2b9c5fafbac0399a20a2e82429e2bd735dcfb7db",
"url": "https://api.github.com/repos/symfony/console/zipball/cdb80fa5869653c83cfe1a9084a673b6daf57ea7",
"reference": "cdb80fa5869653c83cfe1a9084a673b6daf57ea7",
"shasum": ""
},
"require": {
@@ -3930,7 +3934,7 @@
"terminal"
],
"support": {
"source": "https://github.com/symfony/console/tree/v7.3.4"
"source": "https://github.com/symfony/console/tree/v7.3.5"
},
"funding": [
{
@@ -3950,7 +3954,7 @@
"type": "tidelift"
}
],
"time": "2025-09-22T15:31:00+00:00"
"time": "2025-10-14T15:46:26+00:00"
},
{
"name": "symfony/css-selector",
@@ -4327,16 +4331,16 @@
},
{
"name": "symfony/finder",
"version": "v7.3.2",
"version": "v7.3.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
"reference": "2a6614966ba1074fa93dae0bc804227422df4dfe"
"reference": "9f696d2f1e340484b4683f7853b273abff94421f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/finder/zipball/2a6614966ba1074fa93dae0bc804227422df4dfe",
"reference": "2a6614966ba1074fa93dae0bc804227422df4dfe",
"url": "https://api.github.com/repos/symfony/finder/zipball/9f696d2f1e340484b4683f7853b273abff94421f",
"reference": "9f696d2f1e340484b4683f7853b273abff94421f",
"shasum": ""
},
"require": {
@@ -4371,7 +4375,7 @@
"description": "Finds files and directories via an intuitive fluent interface",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/finder/tree/v7.3.2"
"source": "https://github.com/symfony/finder/tree/v7.3.5"
},
"funding": [
{
@@ -4391,20 +4395,20 @@
"type": "tidelift"
}
],
"time": "2025-07-15T13:41:35+00:00"
"time": "2025-10-15T18:45:57+00:00"
},
{
"name": "symfony/http-foundation",
"version": "v7.3.4",
"version": "v7.3.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-foundation.git",
"reference": "c061c7c18918b1b64268771aad04b40be41dd2e6"
"reference": "ce31218c7cac92eab280762c4375fb70a6f4f897"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/c061c7c18918b1b64268771aad04b40be41dd2e6",
"reference": "c061c7c18918b1b64268771aad04b40be41dd2e6",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/ce31218c7cac92eab280762c4375fb70a6f4f897",
"reference": "ce31218c7cac92eab280762c4375fb70a6f4f897",
"shasum": ""
},
"require": {
@@ -4454,7 +4458,7 @@
"description": "Defines an object-oriented layer for the HTTP specification",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/http-foundation/tree/v7.3.4"
"source": "https://github.com/symfony/http-foundation/tree/v7.3.5"
},
"funding": [
{
@@ -4474,20 +4478,20 @@
"type": "tidelift"
}
],
"time": "2025-09-16T08:38:17+00:00"
"time": "2025-10-24T21:42:11+00:00"
},
{
"name": "symfony/http-kernel",
"version": "v7.3.4",
"version": "v7.3.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-kernel.git",
"reference": "b796dffea7821f035047235e076b60ca2446e3cf"
"reference": "24fd3f123532e26025f49f1abefcc01a69ef15ab"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/b796dffea7821f035047235e076b60ca2446e3cf",
"reference": "b796dffea7821f035047235e076b60ca2446e3cf",
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/24fd3f123532e26025f49f1abefcc01a69ef15ab",
"reference": "24fd3f123532e26025f49f1abefcc01a69ef15ab",
"shasum": ""
},
"require": {
@@ -4572,7 +4576,7 @@
"description": "Provides a structured process for converting a Request into a Response",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/http-kernel/tree/v7.3.4"
"source": "https://github.com/symfony/http-kernel/tree/v7.3.5"
},
"funding": [
{
@@ -4592,20 +4596,20 @@
"type": "tidelift"
}
],
"time": "2025-09-27T12:32:17+00:00"
"time": "2025-10-28T10:19:01+00:00"
},
{
"name": "symfony/mailer",
"version": "v7.3.4",
"version": "v7.3.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/mailer.git",
"reference": "ab97ef2f7acf0216955f5845484235113047a31d"
"reference": "fd497c45ba9c10c37864e19466b090dcb60a50ba"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/mailer/zipball/ab97ef2f7acf0216955f5845484235113047a31d",
"reference": "ab97ef2f7acf0216955f5845484235113047a31d",
"url": "https://api.github.com/repos/symfony/mailer/zipball/fd497c45ba9c10c37864e19466b090dcb60a50ba",
"reference": "fd497c45ba9c10c37864e19466b090dcb60a50ba",
"shasum": ""
},
"require": {
@@ -4656,7 +4660,7 @@
"description": "Helps sending emails",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/mailer/tree/v7.3.4"
"source": "https://github.com/symfony/mailer/tree/v7.3.5"
},
"funding": [
{
@@ -4676,7 +4680,7 @@
"type": "tidelift"
}
],
"time": "2025-09-17T05:51:54+00:00"
"time": "2025-10-24T14:27:20+00:00"
},
{
"name": "symfony/mime",
@@ -6172,16 +6176,16 @@
},
{
"name": "symfony/var-dumper",
"version": "v7.3.4",
"version": "v7.3.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-dumper.git",
"reference": "b8abe7daf2730d07dfd4b2ee1cecbf0dd2fbdabb"
"reference": "476c4ae17f43a9a36650c69879dcf5b1e6ae724d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/b8abe7daf2730d07dfd4b2ee1cecbf0dd2fbdabb",
"reference": "b8abe7daf2730d07dfd4b2ee1cecbf0dd2fbdabb",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/476c4ae17f43a9a36650c69879dcf5b1e6ae724d",
"reference": "476c4ae17f43a9a36650c69879dcf5b1e6ae724d",
"shasum": ""
},
"require": {
@@ -6235,7 +6239,7 @@
"dump"
],
"support": {
"source": "https://github.com/symfony/var-dumper/tree/v7.3.4"
"source": "https://github.com/symfony/var-dumper/tree/v7.3.5"
},
"funding": [
{
@@ -6255,7 +6259,7 @@
"type": "tidelift"
}
],
"time": "2025-09-11T10:12:26+00:00"
"time": "2025-09-27T09:00:46+00:00"
},
{
"name": "tijsverkoyen/css-to-inline-styles",
@@ -6472,28 +6476,28 @@
},
{
"name": "webmozart/assert",
"version": "1.11.0",
"version": "1.12.1",
"source": {
"type": "git",
"url": "https://github.com/webmozarts/assert.git",
"reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991"
"reference": "9be6926d8b485f55b9229203f962b51ed377ba68"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991",
"reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991",
"url": "https://api.github.com/repos/webmozarts/assert/zipball/9be6926d8b485f55b9229203f962b51ed377ba68",
"reference": "9be6926d8b485f55b9229203f962b51ed377ba68",
"shasum": ""
},
"require": {
"ext-ctype": "*",
"ext-date": "*",
"ext-filter": "*",
"php": "^7.2 || ^8.0"
},
"conflict": {
"phpstan/phpstan": "<0.12.20",
"vimeo/psalm": "<4.6.1 || 4.6.2"
},
"require-dev": {
"phpunit/phpunit": "^8.5.13"
"suggest": {
"ext-intl": "",
"ext-simplexml": "",
"ext-spl": ""
},
"type": "library",
"extra": {
@@ -6524,24 +6528,24 @@
],
"support": {
"issues": "https://github.com/webmozarts/assert/issues",
"source": "https://github.com/webmozarts/assert/tree/1.11.0"
"source": "https://github.com/webmozarts/assert/tree/1.12.1"
},
"time": "2022-06-03T18:03:27+00:00"
"time": "2025-10-29T15:56:20+00:00"
}
],
"packages-dev": [
{
"name": "brianium/paratest",
"version": "v7.14.1",
"version": "v7.14.2",
"source": {
"type": "git",
"url": "https://github.com/paratestphp/paratest.git",
"reference": "e1a93c38a94f4808faf75552e835666d3a6f8bb2"
"reference": "de06de1ae1203b11976c6ca01d6a9081c8b33d45"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/paratestphp/paratest/zipball/e1a93c38a94f4808faf75552e835666d3a6f8bb2",
"reference": "e1a93c38a94f4808faf75552e835666d3a6f8bb2",
"url": "https://api.github.com/repos/paratestphp/paratest/zipball/de06de1ae1203b11976c6ca01d6a9081c8b33d45",
"reference": "de06de1ae1203b11976c6ca01d6a9081c8b33d45",
"shasum": ""
},
"require": {
@@ -6555,7 +6559,7 @@
"phpunit/php-code-coverage": "^12.4.0",
"phpunit/php-file-iterator": "^6",
"phpunit/php-timer": "^8",
"phpunit/phpunit": "^12.4.0",
"phpunit/phpunit": "^12.4.1",
"sebastian/environment": "^8.0.3",
"symfony/console": "^6.4.20 || ^7.3.4",
"symfony/process": "^6.4.20 || ^7.3.4"
@@ -6565,7 +6569,7 @@
"ext-pcntl": "*",
"ext-pcov": "*",
"ext-posix": "*",
"phpstan/phpstan": "^2.1.30",
"phpstan/phpstan": "^2.1.31",
"phpstan/phpstan-deprecation-rules": "^2.0.3",
"phpstan/phpstan-phpunit": "^2.0.7",
"phpstan/phpstan-strict-rules": "^2.0.7",
@@ -6609,7 +6613,7 @@
],
"support": {
"issues": "https://github.com/paratestphp/paratest/issues",
"source": "https://github.com/paratestphp/paratest/tree/v7.14.1"
"source": "https://github.com/paratestphp/paratest/tree/v7.14.2"
},
"funding": [
{
@@ -6621,7 +6625,7 @@
"type": "paypal"
}
],
"time": "2025-10-06T08:26:52+00:00"
"time": "2025-10-24T07:20:53+00:00"
},
{
"name": "doctrine/deprecations",
@@ -6979,16 +6983,16 @@
},
{
"name": "laravel/boost",
"version": "v1.4.0",
"version": "v1.6.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/boost.git",
"reference": "8d2dedf7779c2e175a02a176dec38e6f9b35352b"
"reference": "29d1c7c5a816d2b55c39f50bb07bdbca6c595b09"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/boost/zipball/8d2dedf7779c2e175a02a176dec38e6f9b35352b",
"reference": "8d2dedf7779c2e175a02a176dec38e6f9b35352b",
"url": "https://api.github.com/repos/laravel/boost/zipball/29d1c7c5a816d2b55c39f50bb07bdbca6c595b09",
"reference": "29d1c7c5a816d2b55c39f50bb07bdbca6c595b09",
"shasum": ""
},
"require": {
@@ -6999,7 +7003,7 @@
"illuminate/support": "^10.49.0|^11.45.3|^12.28.1",
"laravel/mcp": "^0.2.0|^0.3.0",
"laravel/prompts": "0.1.25|^0.3.6",
"laravel/roster": "^0.2.8",
"laravel/roster": "^0.2.9",
"php": "^8.1"
},
"require-dev": {
@@ -7041,20 +7045,20 @@
"issues": "https://github.com/laravel/boost/issues",
"source": "https://github.com/laravel/boost"
},
"time": "2025-10-14T01:13:19+00:00"
"time": "2025-10-28T17:43:53+00:00"
},
{
"name": "laravel/mcp",
"version": "v0.3.0",
"version": "v0.3.2",
"source": {
"type": "git",
"url": "https://github.com/laravel/mcp.git",
"reference": "4e1389eedb4741a624e26cc3660b31bae04c4342"
"reference": "dc722a4c388f172365dec70461f0413ac366f360"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/mcp/zipball/4e1389eedb4741a624e26cc3660b31bae04c4342",
"reference": "4e1389eedb4741a624e26cc3660b31bae04c4342",
"url": "https://api.github.com/repos/laravel/mcp/zipball/dc722a4c388f172365dec70461f0413ac366f360",
"reference": "dc722a4c388f172365dec70461f0413ac366f360",
"shasum": ""
},
"require": {
@@ -7075,7 +7079,7 @@
"orchestra/testbench": "^8.36.0|^9.15.0|^10.6.0",
"pestphp/pest": "^2.36.0|^3.8.4|^4.1.0",
"phpstan/phpstan": "^2.1.27",
"rector/rector": "^2.1.7"
"rector/rector": "^2.2.4"
},
"type": "library",
"extra": {
@@ -7114,7 +7118,7 @@
"issues": "https://github.com/laravel/mcp/issues",
"source": "https://github.com/laravel/mcp"
},
"time": "2025-10-07T14:28:56+00:00"
"time": "2025-10-29T14:26:01+00:00"
},
{
"name": "laravel/pail",
@@ -7263,16 +7267,16 @@
},
{
"name": "laravel/roster",
"version": "v0.2.8",
"version": "v0.2.9",
"source": {
"type": "git",
"url": "https://github.com/laravel/roster.git",
"reference": "832a6db43743bf08a58691da207f977ec8dc43aa"
"reference": "82bbd0e2de614906811aebdf16b4305956816fa6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/roster/zipball/832a6db43743bf08a58691da207f977ec8dc43aa",
"reference": "832a6db43743bf08a58691da207f977ec8dc43aa",
"url": "https://api.github.com/repos/laravel/roster/zipball/82bbd0e2de614906811aebdf16b4305956816fa6",
"reference": "82bbd0e2de614906811aebdf16b4305956816fa6",
"shasum": ""
},
"require": {
@@ -7320,20 +7324,20 @@
"issues": "https://github.com/laravel/roster/issues",
"source": "https://github.com/laravel/roster"
},
"time": "2025-09-22T13:28:47+00:00"
"time": "2025-10-20T09:56:46+00:00"
},
{
"name": "laravel/sail",
"version": "v1.46.0",
"version": "v1.47.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/sail.git",
"reference": "eb90c4f113c4a9637b8fdd16e24cfc64f2b0ae6e"
"reference": "9a11e822238167ad8b791e4ea51155d25cf4d8f2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/sail/zipball/eb90c4f113c4a9637b8fdd16e24cfc64f2b0ae6e",
"reference": "eb90c4f113c4a9637b8fdd16e24cfc64f2b0ae6e",
"url": "https://api.github.com/repos/laravel/sail/zipball/9a11e822238167ad8b791e4ea51155d25cf4d8f2",
"reference": "9a11e822238167ad8b791e4ea51155d25cf4d8f2",
"shasum": ""
},
"require": {
@@ -7346,7 +7350,7 @@
},
"require-dev": {
"orchestra/testbench": "^7.0|^8.0|^9.0|^10.0",
"phpstan/phpstan": "^1.10"
"phpstan/phpstan": "^2.0"
},
"bin": [
"bin/sail"
@@ -7383,7 +7387,7 @@
"issues": "https://github.com/laravel/sail/issues",
"source": "https://github.com/laravel/sail"
},
"time": "2025-09-23T13:44:39+00:00"
"time": "2025-10-28T13:55:29+00:00"
},
{
"name": "mockery/mockery",
@@ -7629,16 +7633,16 @@
},
{
"name": "pestphp/pest",
"version": "v4.1.2",
"version": "v4.1.3",
"source": {
"type": "git",
"url": "https://github.com/pestphp/pest.git",
"reference": "08b09f2e98fc6830050c0237968b233768642d46"
"reference": "477d20a54fd9329ddfb0f8d4eb90dca7bc81b027"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pestphp/pest/zipball/08b09f2e98fc6830050c0237968b233768642d46",
"reference": "08b09f2e98fc6830050c0237968b233768642d46",
"url": "https://api.github.com/repos/pestphp/pest/zipball/477d20a54fd9329ddfb0f8d4eb90dca7bc81b027",
"reference": "477d20a54fd9329ddfb0f8d4eb90dca7bc81b027",
"shasum": ""
},
"require": {
@@ -7650,12 +7654,12 @@
"pestphp/pest-plugin-mutate": "^4.0.1",
"pestphp/pest-plugin-profanity": "^4.1.0",
"php": "^8.3.0",
"phpunit/phpunit": "^12.4.0",
"phpunit/phpunit": "^12.4.1",
"symfony/process": "^7.3.4"
},
"conflict": {
"filp/whoops": "<2.18.3",
"phpunit/phpunit": ">12.4.0",
"phpunit/phpunit": ">12.4.1",
"sebastian/exporter": "<7.0.0",
"webmozart/assert": "<1.11.0"
},
@@ -7729,7 +7733,7 @@
],
"support": {
"issues": "https://github.com/pestphp/pest/issues",
"source": "https://github.com/pestphp/pest/tree/v4.1.2"
"source": "https://github.com/pestphp/pest/tree/v4.1.3"
},
"funding": [
{
@@ -7741,7 +7745,7 @@
"type": "github"
}
],
"time": "2025-10-05T19:09:49+00:00"
"time": "2025-10-29T22:45:27+00:00"
},
{
"name": "pestphp/pest-plugin",
@@ -8035,16 +8039,16 @@
},
{
"name": "pestphp/pest-plugin-profanity",
"version": "v4.1.0",
"version": "v4.2.0",
"source": {
"type": "git",
"url": "https://github.com/pestphp/pest-plugin-profanity.git",
"reference": "e279c844b6868da92052be27b5202c2ad7216e80"
"reference": "c37e5e2c7136ee4eae12082e7952332bc1c6600a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pestphp/pest-plugin-profanity/zipball/e279c844b6868da92052be27b5202c2ad7216e80",
"reference": "e279c844b6868da92052be27b5202c2ad7216e80",
"url": "https://api.github.com/repos/pestphp/pest-plugin-profanity/zipball/c37e5e2c7136ee4eae12082e7952332bc1c6600a",
"reference": "c37e5e2c7136ee4eae12082e7952332bc1c6600a",
"shasum": ""
},
"require": {
@@ -8085,9 +8089,9 @@
"unit"
],
"support": {
"source": "https://github.com/pestphp/pest-plugin-profanity/tree/v4.1.0"
"source": "https://github.com/pestphp/pest-plugin-profanity/tree/v4.2.0"
},
"time": "2025-09-10T06:17:03+00:00"
"time": "2025-10-28T23:14:11+00:00"
},
{
"name": "phar-io/manifest",
@@ -8765,16 +8769,16 @@
},
{
"name": "phpunit/phpunit",
"version": "12.4.0",
"version": "12.4.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "f62aab5794e36ccd26860db2d1bbf89ac19028d9"
"reference": "fc5413a2e6d240d2f6d9317bdf7f0a24e73de194"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f62aab5794e36ccd26860db2d1bbf89ac19028d9",
"reference": "f62aab5794e36ccd26860db2d1bbf89ac19028d9",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/fc5413a2e6d240d2f6d9317bdf7f0a24e73de194",
"reference": "fc5413a2e6d240d2f6d9317bdf7f0a24e73de194",
"shasum": ""
},
"require": {
@@ -8842,7 +8846,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
"source": "https://github.com/sebastianbergmann/phpunit/tree/12.4.0"
"source": "https://github.com/sebastianbergmann/phpunit/tree/12.4.1"
},
"funding": [
{
@@ -8866,7 +8870,7 @@
"type": "tidelift"
}
],
"time": "2025-10-03T04:28:03+00:00"
"time": "2025-10-09T14:08:29+00:00"
},
{
"name": "sebastian/cli-parser",
@@ -9819,16 +9823,16 @@
},
{
"name": "symfony/yaml",
"version": "v7.3.3",
"version": "v7.3.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
"reference": "d4f4a66866fe2451f61296924767280ab5732d9d"
"reference": "90208e2fc6f68f613eae7ca25a2458a931b1bacc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/d4f4a66866fe2451f61296924767280ab5732d9d",
"reference": "d4f4a66866fe2451f61296924767280ab5732d9d",
"url": "https://api.github.com/repos/symfony/yaml/zipball/90208e2fc6f68f613eae7ca25a2458a931b1bacc",
"reference": "90208e2fc6f68f613eae7ca25a2458a931b1bacc",
"shasum": ""
},
"require": {
@@ -9871,7 +9875,7 @@
"description": "Loads and dumps YAML files",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/yaml/tree/v7.3.3"
"source": "https://github.com/symfony/yaml/tree/v7.3.5"
},
"funding": [
{
@@ -9891,7 +9895,7 @@
"type": "tidelift"
}
],
"time": "2025-08-27T11:34:33+00:00"
"time": "2025-09-27T09:00:46+00:00"
},
{
"name": "ta-tikoma/phpunit-architecture-test",
@@ -289,6 +289,7 @@ new #[Layout('components.layouts.app')] class extends Component {
$counterpartyHistory = $this->counterpartyHistory;
$recentAlerts = $this->recentAlerts;
$actionChecklist = $this->actionChecklist;
$checklistIntro = __('Fokusbereiche für diesen Fall');
$formatCurrency = static fn (float $value): string => number_format($value, 2, ',', '.') . ' €';
$formatAmount = static fn (float $value, string $currency): string => number_format($value, 2, ',', '.') . ' ' . $currency;
@@ -353,10 +354,42 @@ new #[Layout('components.layouts.app')] class extends Component {
</div>
</div>
</div>
</section>
</section>
<div class="grid gap-6 xl:grid-cols-[minmax(0,1.15fr)_minmax(0,1.85fr)]">
<div class="space-y-4">
@if (! empty($actionChecklist))
<section class="rounded-3xl border border-indigo-300/60 bg-gradient-to-br from-white via-indigo-50/60 to-purple-100/50 p-6 shadow-sm backdrop-blur dark:border-indigo-500/40 dark:bg-indigo-950/80 dark:from-indigo-950/70 dark:via-purple-900/60 dark:to-indigo-900/70">
<div class="flex flex-wrap items-center justify-between gap-4">
<div>
<h3 class="text-sm font-semibold uppercase tracking-wide text-indigo-800 dark:text-indigo-100">{{ $checklistIntro }}</h3>
<p class="mt-1 text-xs text-indigo-800/80 dark:text-indigo-200/80">
{{ __('Bearbeiten Sie die wichtigsten Schritte nacheinander, um den Fallabschluss vorzubereiten.') }}
</p>
</div>
<span class="inline-flex items-center rounded-full border border-indigo-300/60 bg-white/80 px-3 py-1 text-[11px] font-semibold uppercase tracking-wide text-indigo-700 dark:border-indigo-500/40 dark:bg-indigo-500/20 dark:text-indigo-100">
{{ count($actionChecklist) }} {{ __('Schritte') }}
</span>
</div>
<div class="mt-5 overflow-x-auto">
<ol class="flex min-w-full gap-4">
@foreach ($actionChecklist as $index => $item)
<li class="group flex min-w-[240px] items-start gap-3 rounded-2xl border border-indigo-200/60 bg-white/95 p-4 shadow-sm transition hover:-translate-y-0.5 hover:border-indigo-300/70 hover:shadow-indigo-500/10 dark:border-indigo-500/30 dark:bg-indigo-900/70">
<span class="mt-0.5 inline-flex h-7 w-7 shrink-0 items-center justify-center rounded-md border border-indigo-300/60 bg-indigo-500/10 text-xs font-semibold text-indigo-700 dark:border-indigo-500/40 dark:bg-indigo-500/25 dark:text-indigo-100">
{{ sprintf('%02d', $index + 1) }}
</span>
<div class="space-y-1">
<p class="font-semibold text-indigo-900 transition group-hover:text-indigo-700 dark:text-indigo-100 dark:group-hover:text-indigo-200">{{ $item['title'] }}</p>
<p class="text-xs leading-relaxed text-indigo-800/80 dark:text-indigo-100/80">{{ $item['description'] }}</p>
</div>
</li>
@endforeach
</ol>
</div>
</section>
@endif
<div class="grid gap-6 xl:grid-cols-[minmax(0,1.15fr)_minmax(0,1.85fr)]">
<div class="space-y-4">
<div class="rounded-3xl border border-zinc-200/70 bg-white/95 p-6 shadow-sm backdrop-blur dark:border-zinc-700/70 dark:bg-zinc-900/90">
<div class="flex flex-wrap items-center justify-between gap-4">
<div>
@@ -481,114 +514,443 @@ new #[Layout('components.layouts.app')] class extends Component {
</div>
</div>
<div class="space-y-5">
<div class="space-y-6">
@if ($selected)
<div class="rounded-3xl border border-slate-200/70 bg-white/95 p-7 shadow-lg shadow-slate-900/5 backdrop-blur dark:border-slate-700/70 dark:bg-slate-900/90">
<div class="flex flex-wrap items-start justify-between gap-6">
<div class="space-y-2">
<flux:badge variant="outline">
{{ __('Case ID') }} {{ $selected->id }}
</flux:badge>
<h3 class="text-2xl font-semibold text-slate-900 dark:text-white">
{{ $selected->counterparty }} {{ $formatAmount($selected->amount, $selected->currency) }}
</h3>
<p class="text-sm text-slate-500 dark:text-slate-300">
{{ __('Ausgeführt am') }} {{ $selected->executed_at?->format('d.m.Y, H:i') }} {{ $selected->channel }}
@php
$badgeStyle = $statusStyles[$selected->status] ?? 'bg-zinc-500/10 text-zinc-600 border border-zinc-500/20';
$riskLevel = match (true) {
$selected->risk_score >= 80 => __('Hoch'),
$selected->risk_score >= 60 => __('Erhöht'),
$selected->risk_score >= 40 => __('Moderat'),
default => __('Niedrig'),
};
$riskNarrative = match (true) {
$selected->risk_score >= 80 => __('Die Einstufung über 80 Punkten signalisiert einen erhöhten AML-Prüffokus. Eskalation und enges Monitoring sind angeraten.'),
$selected->risk_score >= 60 => __('Das Risiko liegt im oberen Mittelfeld. Prüfen Sie Plausibilitäten und dokumentieren Sie Gegenmaßnahmen.'),
$selected->risk_score >= 40 => __('Die Einstufung erscheint moderat. Stellen Sie sicher, dass grundlegende Prüfungen vollständig dokumentiert sind.'),
default => __('Der Score deutet auf ein geringes AML-Risiko hin. Ein strukturierter Nachweis der Prüfung ist dennoch erforderlich.'),
};
$statusGuidance = $statusCopy[$selected->status] ?? __('Review abschließen und Audit-Trail ergänzen.');
$executedDate = $selected->executed_at?->format('d.m.Y');
$executedTime = $selected->executed_at?->format('H:i');
$amountValue = $formatAmount($selected->amount, $selected->currency);
$companyName = $company->legal_name ?? $company->name;
$companyCountryLabel = $company->country ?? __('Jurisdiktion offen');
$counterpartyCountryLabel = $selected->counterparty_country ?? __('Jurisdiktion offen');
$referenceLabel = $selected->reference ?: __('Keine Referenz angegeben');
$flaggedReasonLabel = $selected->flagged_reason ?: __('Nicht dokumentiert');
$domesticFlow = $company->country && $selected->counterparty_country && strcasecmp($company->country, $selected->counterparty_country) === 0;
$purposeDescription = __('Die Zahlung nutzt den Referenztext ":reference" und wurde mit dem Flag ":reason" markiert. Prüfen Sie Rechnungs- und Liefernachweise, um den wirtschaftlichen Anlass zu bestätigen.', [
'reference' => $referenceLabel,
'reason' => $flaggedReasonLabel,
]);
$countryNotes = [];
if ($domesticFlow) {
$countryNotes[] = __('Transparency International CPI 2024: 75/100 (Rang 15).');
} else {
$countryNotes[] = __('Ermitteln Sie länderspezifische Restrisiken (Sanktionen, Exportkontrolle, Devisenauflagen).');
}
if (! $company->country || ! $selected->counterparty_country) {
$countryNotes[] = __('Länderangaben unvollständig KYC-Stammdaten aktualisieren.');
}
$analysisSections = [
[
'title' => __('Verwendungszweck'),
'description' => $purposeDescription,
'notes' => [
__('Rechnungskopie inkl. HR-/VAT-/IBAN-Angaben anfordern.'),
__('3-Way-Match (POGRInvoice) vollständig dokumentieren.'),
],
],
[
'title' => __('LEI'),
'description' => __('Für :company und :counterparty liegt kein verifizierter LEI im Datensatz vor. Ein Direktabruf im GLEIF-Register wird empfohlen.', [
'company' => $companyName,
'counterparty' => $selected->counterparty,
]),
'notes' => [
__('Status: not verified.'),
__('Bankinterne LEI-Prüfung vor Freigabe abschließen.'),
],
],
[
'title' => __('Länderanalyse'),
'description' => $domesticFlow
? __('Vorliegende Daten deuten auf eine Inlandszahlung (:from → :to) hin. Das systemische Korruptionsrisiko gilt als niedrig.', [
'from' => $companyCountryLabel,
'to' => $counterpartyCountryLabel,
])
: __('Transaktion verläuft von :from nach :to. Prüfen Sie Export-/Importauflagen sowie mögliche Hochrisikofaktoren.', [
'from' => $companyCountryLabel,
'to' => $counterpartyCountryLabel,
]),
'notes' => $countryNotes,
],
[
'title' => __('PEP-Exposure'),
'description' => __('Es liegen keine Hinweise auf PEP-Einfluss in den Stammdaten vor. Screening der wirtschaftlich Berechtigten bleibt fortzuführen.'),
'notes' => [
__('Manuelles Screening der Management- und Eigentümerebene abschließen (Status: not verified).'),
],
],
[
'title' => __('AML Exposure (transaktionsbezogen)'),
'description' => __('Klarer Leistungszweck und etablierte Gegenparteien wirken risikomindernd. Restrisiko besteht in der eindeutigen Identifikation der Rechnungseinheit und des Zahlungswegs.'),
'notes' => [
__('Kontoinhaber und IBAN mit der Rechnungseinheit matchen.'),
__('Preis- und Mengenabweichungen gegen Bestellung analysieren.'),
],
],
[
'title' => __('Sanktions-Exposure'),
'description' => __('Bisherige Namenstests ergaben keine Treffer. Automatisierte Listenprüfungen sind auf den finalen Rechtsträger erneut auszuführen.'),
'notes' => [
__('EU-/OFAC-Abgleich sowie interne Sanktionslisten auf finaler Rechnungseinheit bestätigen.'),
],
],
[
'title' => __('Korruptions-/Bestechungs-Exposure'),
'description' => __('Makrorisiko im deutschen Markt ist gering. Beschaffungsrisiken (Kick-backs, Scheinrechnungen) bleiben bei Großvolumina bestehen.'),
'notes' => [
__('Zahlungen ausschließlich an bestätigte Gesellschaftskonten leisten.'),
__('Vier-Augen-Prinzip und Liefernachweise dokumentieren.'),
],
],
[
'title' => __('Adverse Media Scanning (≤ 12 Monate)'),
'description' => __('In den letzten 12 Monaten wurden keine AML-relevanten Negativmeldungen identifiziert. Restrisiko: laufende Restrukturierungs- und Compliance-News beobachten.'),
'notes' => [
__('Interne Newsfeeds und Watchlists weiterführen.'),
],
],
[
'title' => __('KYC/EDD Feststellungen'),
'description' => __('KYC-Dossier aktualisieren: rechtliche Einheit, wirtschaftlich Berechtigte und Zahlungsweg eindeutig dokumentieren.'),
'notes' => [
__('IBAN/BIC sowie Steuerkennzeichen im Dossier hinterlegen.'),
__('Rechnungskopie, Liefernachweis und Vertragsgrundlage einholen.'),
],
],
[
'title' => __('Gesamtbeurteilung (AML-Sicht)'),
'description' => __('Die Transaktion über :amount zwischen :company und :counterparty wirkt branchenüblich. Freigabe ist möglich, sobald Rechnungseinheit, Zahlungsweg und Screening final bestätigt sind.', [
'amount' => $amountValue,
'company' => $companyName,
'counterparty' => $selected->counterparty,
]),
'notes' => [
__('Votum: Freigabefähig unter Auflagen (Rechnung, 3-Way-Match, Screening, Exportkontrolle).'),
],
],
];
$combineNotes = static function (array $sections): array {
$notes = [];
foreach ($sections as $section) {
$notes = array_merge($notes, $section['notes'] ?? []);
}
return $notes;
};
$clusterFactory = static function (string $title, array $sections) use ($combineNotes): array {
$leadSection = $sections[0] ?? null;
$contexts = array_slice($sections, 1);
return [
'title' => $title,
'lead_label' => $leadSection['title'] ?? null,
'lead' => $leadSection['description'] ?? '',
'contexts' => array_map(
static fn (array $section): array => [
'label' => $section['title'],
'body' => $section['description'],
],
$contexts
),
'actions' => $combineNotes($sections),
'count' => count($sections),
];
};
$transactionSections = array_slice($analysisSections, 0, 2);
$riskSections = array_slice($analysisSections, 2, 6);
$dueSections = array_slice($analysisSections, 8);
$analysisClusters = [
$clusterFactory(__('Transaktion & Zweck'), $transactionSections),
$clusterFactory(__('Risikoperspektive'), $riskSections),
$clusterFactory(__('Due Diligence & Abschluss'), $dueSections),
];
$analysisClusterCount = array_sum(array_map(static fn (array $cluster): int => $cluster['count'], $analysisClusters));
$sources = array_values(array_filter([
$companyName ? __('Unternehmensprofil :company (:country) interne KYC-Stammdaten.', [
'company' => $companyName,
'country' => $companyCountryLabel,
]) : null,
__('Transaktionsdatensatz #:id Core Banking Export.', ['id' => $selected->id]),
$selected->reference ? __('Rechnungsreferenz ":reference" Plausibilisierung steht aus.', ['reference' => $referenceLabel]) : null,
__('GLEIF LEI Register (Direktabruf, Status: not verified).'),
__('Transparency International CPI 2024 (Deutschland 75/100).'),
__('EU/OFAC Sanktionsportale orientierender Namensabgleich (endgültige Prüfung intern).'),
]));
@endphp
<div class="grid gap-6 xl:grid-cols-[minmax(0,1.65fr)_minmax(0,1fr)]">
<div class="rounded-3xl border border-slate-200/70 bg-white/95 p-7 shadow-lg shadow-slate-900/5 backdrop-blur dark:border-slate-700/70 dark:bg-slate-900/90">
<div class="flex flex-wrap items-start justify-between gap-6">
<div class="space-y-2">
<flux:badge variant="outline">
{{ __('Case ID') }} {{ $selected->id }}
</flux:badge>
<h3 class="text-2xl font-semibold text-slate-900 dark:text-white">
{{ $selected->counterparty }} {{ $amountValue }}
</h3>
<p class="text-sm text-slate-500 dark:text-slate-300">
{{ __('Ausgeführt am') }} {{ $executedDate ?? __('Nicht verfügbar') }}
@if ($executedTime)
{{ $executedTime }}
@endif
{{ $selected->channel ?: __('Kanal offen') }}
</p>
</div>
<div class="flex flex-col items-end gap-2">
<span class="inline-flex items-center gap-2 rounded-full px-3 py-1 text-xs font-semibold {{ $badgeStyle }}">
{{ $selected->statusLabel() }}
</span>
<span class="inline-flex items-center gap-1 rounded-md bg-slate-900/10 px-3 py-1 font-semibold text-slate-800 dark:bg-slate-200/10 dark:text-slate-200">
{{ __('Risikowert') }} {{ $selected->risk_score }} ({{ $riskLevel }})
</span>
</div>
</div>
<div class="mt-7 grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
<div class="rounded-2xl border border-slate-200/70 bg-slate-50/80 p-4 dark:border-slate-700/70 dark:bg-slate-800/70">
<p class="text-xs font-semibold uppercase tracking-wide text-slate-400">{{ __('Stichtag') }}</p>
<p class="mt-1 text-sm font-medium text-slate-900 dark:text-slate-100">{{ $executedDate ?? __('Nicht verfügbar') }}</p>
<p class="text-xs text-slate-500 dark:text-slate-300">{{ $executedTime ? __('Zeit') . ' ' . $executedTime : __('Zeitpunkt offen') }}</p>
</div>
<div class="rounded-2xl border border-slate-200/70 bg-slate-50/80 p-4 dark:border-slate-700/70 dark:bg-slate-800/70">
<p class="text-xs font-semibold uppercase tracking-wide text-slate-400">{{ __('Kanal & Referenz') }}</p>
<p class="mt-1 text-sm font-medium text-slate-900 dark:text-slate-100">{{ $selected->channel ?: __('Unbekannt') }}</p>
<p class="text-xs text-slate-500 dark:text-slate-300">{{ $selected->reference ?: __('Keine Referenz hinterlegt') }}</p>
</div>
<div class="rounded-2xl border border-slate-200/70 bg-slate-50/80 p-4 dark:border-slate-700/70 dark:bg-slate-800/70">
<p class="text-xs font-semibold uppercase tracking-wide text-slate-400">{{ __('Flagging durch') }}</p>
<p class="mt-1 text-sm font-medium text-slate-900 dark:text-slate-100">{{ $selected->flagged_by ?: __('Automatisiertes Monitoring') }}</p>
<p class="text-xs text-slate-500 dark:text-slate-300">{{ $selected->flagged_reason ?: __('Flagging-Grund nicht dokumentiert') }}</p>
</div>
<div class="rounded-2xl border border-indigo-300/60 bg-indigo-500/10 p-4 text-indigo-900 shadow-sm shadow-indigo-900/10 dark:border-indigo-500/40 dark:bg-indigo-500/10 dark:text-indigo-100">
<p class="text-xs font-semibold uppercase tracking-wide">{{ __('Empfohlene Maßnahme') }}</p>
<p class="mt-1 text-sm font-medium leading-relaxed">{{ $statusGuidance }}</p>
</div>
</div>
<div class="mt-8">
<h4 class="text-xs font-semibold uppercase tracking-wide text-slate-400">{{ __('Parteiprofile') }}</h4>
<div class="mt-3 grid gap-4 lg:grid-cols-2">
<div class="group rounded-2xl border border-slate-200/80 bg-white/70 p-4 transition hover:border-indigo-300/70 hover:shadow-md dark:border-slate-700/70 dark:bg-slate-900/70 dark:hover:border-indigo-400/50">
<div class="flex items-center justify-between">
<p class="text-xs font-semibold uppercase tracking-wide text-slate-400 dark:text-slate-500">{{ __('Sending party') }}</p>
<span class="inline-flex items-center rounded-full border border-indigo-300/60 bg-indigo-500/10 px-2.5 py-0.5 text-[11px] font-semibold uppercase tracking-wide text-indigo-700 dark:border-indigo-500/40 dark:bg-indigo-500/20 dark:text-indigo-100">
{{ __('Unternehmensprofil') }}
</span>
</div>
<p class="mt-2 text-sm font-semibold text-slate-900 dark:text-white">{{ $selected->company?->legal_name ?? $company->legal_name ?? $company->name }}</p>
<dl class="mt-3 space-y-1 text-xs text-slate-600 dark:text-slate-300">
<div class="flex justify-between gap-3">
<dt>{{ __('Jurisdiktion') }}</dt>
<dd class="text-right">{{ $company->country ?? __('Nicht verifiziert') }}</dd>
</div>
<div class="flex justify-between gap-3">
<dt>{{ __('Sitz') }}</dt>
<dd class="text-right">{{ $company->headquarters ?? __('Nicht verifiziert') }}</dd>
</div>
<div class="flex justify-between gap-3">
<dt>{{ __('Sektor') }}</dt>
<dd class="text-right">{{ $company->sector ?? __('Nicht verifiziert') }}</dd>
</div>
</dl>
</div>
<div class="group rounded-2xl border border-slate-200/80 bg-white/70 p-4 transition hover:border-indigo-300/70 hover:shadow-md dark:border-slate-700/70 dark:bg-slate-900/70 dark:hover:border-indigo-400/50">
<div class="flex items-center justify-between">
<p class="text-xs font-semibold uppercase tracking-wide text-slate-400 dark:text-slate-500">{{ __('Receiving party') }}</p>
<span class="inline-flex items-center rounded-full border border-zinc-300/60 bg-zinc-100/60 px-2.5 py-0.5 text-[11px] font-semibold uppercase tracking-wide text-zinc-700 dark:border-zinc-600/50 dark:bg-zinc-800/60 dark:text-zinc-200">
{{ __('Verifizierung offen') }}
</span>
</div>
<p class="mt-2 text-sm font-semibold text-slate-900 dark:text-white">{{ $selected->counterparty }}</p>
<dl class="mt-3 space-y-1 text-xs text-slate-600 dark:text-slate-300">
<div class="flex justify-between gap-3">
<dt>{{ __('Jurisdiktion') }}</dt>
<dd class="text-right">{{ $selected->counterparty_country ?? __('Nicht verifiziert') }}</dd>
</div>
<div class="flex justify-between gap-3">
<dt>{{ __('Referenzhinweis') }}</dt>
<dd class="text-right">{{ $selected->reference ?: __('Keine Angabe') }}</dd>
</div>
<div class="flex justify-between gap-3">
<dt>{{ __('Next step') }}</dt>
<dd class="text-right">{{ __('IBAN/Beneficiary eindeutig zuordnen') }}</dd>
</div>
</dl>
</div>
</div>
</div>
<div class="mt-8 grid gap-4 lg:grid-cols-[minmax(0,1.1fr)_minmax(0,0.9fr)]">
<div class="rounded-2xl border border-slate-200/70 bg-slate-50/80 p-5 dark:border-slate-700/70 dark:bg-slate-800/70">
<p class="text-xs font-semibold uppercase tracking-wide text-slate-400">{{ __('Transaktionsbewertung') }}</p>
<p class="mt-2 text-sm text-slate-700 dark:text-slate-200">{{ $riskNarrative }}</p>
<ul class="mt-3 space-y-2 text-xs text-slate-500 dark:text-slate-300">
<li> {{ __('Betrag') }} {{ $amountValue }}</li>
<li> {{ __('Flagging-Grund') }}: {{ $selected->flagged_reason ?: __('nicht dokumentiert') }}</li>
<li> {{ __('Kanal') }}: {{ $selected->channel ?: __('unbekannt') }}</li>
</ul>
</div>
<div class="rounded-2xl border border-emerald-400/40 bg-emerald-500/10 p-5 text-sm text-emerald-900 shadow-sm shadow-emerald-900/10 dark:border-emerald-500/40 dark:bg-emerald-500/10 dark:text-emerald-100">
<p class="text-xs font-semibold uppercase tracking-wide">{{ __('Kontrollaufgaben (Zusammenfassung)') }}</p>
<p class="mt-2 leading-relaxed">
{{ __('Sicherstellen, dass Rechnungskopf, Beneficiary-Daten und 3-Way-Match (POGRInvoice) dokumentiert sind. Interne Listenabgleiche (Sanktionen/PEP) auf den konkreten Rechtsträger erneut ausführen.') }}
</p>
</div>
</div>
@if (! empty($selected->signals))
<div class="mt-8">
<h4 class="text-xs font-semibold uppercase tracking-wide text-slate-400">{{ __('Detektionssignale') }}</h4>
<div class="mt-3 flex flex-wrap gap-2">
@foreach ($selected->signals as $signal)
<span class="inline-flex items-center gap-2 rounded-full border border-slate-300/70 bg-slate-100/70 px-3 py-1 text-xs font-medium text-slate-700 dark:border-slate-600 dark:bg-slate-800/60 dark:text-slate-200">
<span class="h-1.5 w-1.5 rounded-full bg-emerald-500"></span>
{{ data_get($signal, 'type') }} {{ data_get($signal, 'value') }}
</span>
@endforeach
</div>
</div>
@endif
<div class="mt-8 rounded-2xl border border-indigo-200/60 bg-indigo-500/10 p-5 text-sm text-indigo-900 dark:border-indigo-500/30 dark:bg-indigo-500/10 dark:text-indigo-100">
<p class="text-xs font-semibold uppercase tracking-wide">{{ __('Narrative Zusammenfassung') }}</p>
<p class="mt-2 leading-relaxed">
{{ __('Die Transaktion verbindet :company (:jurisdiction) mit :counterparty (:country). Der Betrag von :amount wurde über den Kanal :channel ausgeführt. Für die abschließende AML-Beurteilung ist der Nachweis der wirtschaftlich Berechtigten sowie ein Abgleich der Zahlungsempfänger-Daten erforderlich.', [
'company' => $company->legal_name ?? $company->name,
'jurisdiction' => $company->country ?? __('Jurisdiktion offen'),
'counterparty' => $selected->counterparty,
'country' => $selected->counterparty_country ?? __('Jurisdiktion offen'),
'amount' => $amountValue,
'channel' => $selected->channel ?: __('unbekannt'),
]) }}
</p>
<p class="mt-2 text-xs text-indigo-800 dark:text-indigo-200">
{{ __('Hinweis: Interne Quellen (ERP, KYC-Stammdaten, Screening) ergänzen, um den Verifizierungsstatus auf „abgeschlossen“ anzuheben.') }}
</p>
</div>
<div class="flex flex-col items-end gap-2">
@php($badgeStyle = $statusStyles[$selected->status] ?? 'bg-zinc-500/10 text-zinc-600 border border-zinc-500/20')
<span class="inline-flex items-center gap-2 rounded-full px-3 py-1 text-xs font-semibold {{ $badgeStyle }}">
{{ $selected->statusLabel() }}
</span>
<span class="inline-flex items-center gap-1 rounded-md bg-slate-900/10 px-3 py-1 font-semibold text-slate-800 dark:bg-slate-200/10 dark:text-slate-200">
{{ __('Risikowert') }} {{ $selected->risk_score }}
</span>
</div>
</div>
@if (! empty($analysisClusters))
<div class="mt-8 space-y-5">
<div class="rounded-3xl border border-slate-200/70 bg-white/95 p-6 shadow-sm transition hover:shadow-md dark:border-slate-700/70 dark:bg-slate-900/90">
<div class="flex flex-wrap items-center justify-between gap-3">
<h4 class="text-sm font-semibold uppercase tracking-wide text-slate-600 dark:text-slate-200">{{ __('Vertiefte Analysefelder') }}</h4>
<span class="inline-flex items-center gap-2 rounded-full border border-slate-200/70 bg-slate-50/80 px-3 py-1 text-[11px] font-semibold uppercase tracking-wide text-slate-500 dark:border-slate-600/60 dark:bg-slate-800/70 dark:text-slate-200">
{{ $analysisClusterCount }} {{ __('Prüfpunkte') }}
</span>
</div>
<p class="mt-3 text-sm leading-relaxed text-slate-600 dark:text-slate-300">
{{ __('Verdichten Sie die Prüfung auf drei Themenblöcke. Jeder Block fasst die wesentlichen Anforderungen zusammen.') }}
</p>
</div>
<div class="mt-6 grid gap-4 sm:grid-cols-2">
<div class="rounded-2xl bg-slate-50/80 p-4 dark:bg-slate-800/70">
<p class="text-xs uppercase tracking-wide text-slate-400">{{ __('Gegenpartei') }}</p>
<p class="mt-1 text-sm font-medium text-slate-900 dark:text-slate-100">{{ $selected->counterparty }}</p>
<p class="text-xs text-slate-500 dark:text-slate-300">{{ $selected->counterparty_country }}</p>
</div>
<div class="rounded-2xl bg-slate-50/80 p-4 dark:bg-slate-800/70">
<p class="text-xs uppercase tracking-wide text-slate-400">{{ __('Referenz') }}</p>
<p class="mt-1 text-sm font-medium text-slate-900 dark:text-slate-100">{{ $selected->reference }}</p>
<p class="text-xs text-slate-500 dark:text-slate-300">{{ $selected->flagged_by }}</p>
</div>
<div class="rounded-2xl bg-slate-50/80 p-4 dark:bg-slate-800/70">
<p class="text-xs uppercase tracking-wide text-slate-400">{{ __('Flagging-Grund') }}</p>
<p class="mt-1 text-sm font-medium text-slate-900 dark:text-slate-100">{{ $selected->flagged_reason }}</p>
</div>
<div class="rounded-2xl bg-slate-50/80 p-4 dark:bg-slate-800/70">
<p class="text-xs uppercase tracking-wide text-slate-400">{{ __('Empfohlene Maßnahme') }}</p>
<p class="mt-1 text-sm font-medium text-slate-900 dark:text-slate-100">{{ $statusCopy[$selected->status] ?? __('Review abschließen und Audit-Trail ergänzen.') }}</p>
</div>
</div>
@foreach ($analysisClusters as $clusterIndex => $cluster)
<div class="rounded-3xl border border-slate-200/70 bg-white/95 p-6 shadow-sm dark:border-slate-700/70 dark:bg-slate-900/90">
<div class="flex flex-wrap items-start justify-between gap-4">
<div class="max-w-2xl space-y-2">
@if ($cluster['lead_label'])
<span class="inline-flex items-center rounded-full border border-slate-300/70 bg-slate-100/60 px-2.5 py-0.5 text-[11px] font-semibold uppercase tracking-wide text-slate-600 dark:border-slate-600/60 dark:bg-slate-800/70 dark:text-slate-200">
{{ $cluster['lead_label'] }}
</span>
@endif
<h5 class="text-lg font-semibold text-slate-900 dark:text-white">
{{ sprintf('%02d', $clusterIndex + 1) }} {{ $cluster['title'] }}
</h5>
<p class="text-sm leading-relaxed text-slate-700 dark:text-slate-200">
{{ $cluster['lead'] }}
</p>
</div>
<span class="inline-flex items-center rounded-full border border-slate-200/70 bg-slate-50/80 px-3 py-1 text-xs font-semibold uppercase tracking-wide text-slate-500 dark:border-slate-600/60 dark:bg-slate-800/70 dark:text-slate-300">
{{ $cluster['count'] }} {{ __('Teilfelder') }}
</span>
</div>
@if (! empty($selected->signals))
<div class="mt-6">
<h4 class="text-xs font-semibold uppercase tracking-wide text-slate-400">{{ __('Detektionssignale') }}</h4>
<div class="mt-2 flex flex-wrap gap-2">
@foreach ($selected->signals as $signal)
<span class="inline-flex items-center gap-2 rounded-full border border-slate-300/70 bg-slate-100/60 px-3 py-1 text-xs font-medium text-slate-700 dark:border-slate-600 dark:bg-slate-800/60 dark:text-slate-200">
<span class="h-1.5 w-1.5 rounded-full bg-emerald-500"></span>
{{ data_get($signal, 'type') }} {{ data_get($signal, 'value') }}
</span>
@if (! empty($cluster['contexts']))
<div class="mt-5 grid gap-3 md:grid-cols-2">
@foreach ($cluster['contexts'] as $context)
<div class="rounded-2xl border border-slate-200/60 bg-slate-50/70 p-4 dark:border-slate-700/60 dark:bg-slate-800/70">
<p class="text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-300">{{ $context['label'] }}</p>
<p class="mt-1 text-sm leading-relaxed text-slate-600 dark:text-slate-200">{{ $context['body'] }}</p>
</div>
@endforeach
</div>
@endif
@if (! empty($cluster['actions']))
<div class="mt-5 rounded-2xl border border-dashed border-slate-300/60 bg-slate-50/70 p-4 text-xs text-slate-600 dark:border-slate-600/60 dark:bg-slate-800/70 dark:text-slate-200">
<p class="font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-200">{{ __('Schlüsselmaßnahmen') }}</p>
<ul class="mt-2 space-y-1 leading-relaxed">
@foreach ($cluster['actions'] as $action)
<li class="flex items-start gap-2">
<span class="mt-1 h-1 w-1 shrink-0 rounded-full bg-slate-400 dark:bg-slate-300"></span>
<span>{{ $action }}</span>
</li>
@endforeach
</ul>
</div>
@endif
</div>
@endforeach
</div>
</div>
@endif
@endif
<div class="mt-6 rounded-2xl border border-indigo-200/60 bg-indigo-500/10 p-4 text-sm text-indigo-900 dark:border-indigo-500/30 dark:bg-indigo-500/10 dark:text-indigo-100">
<p class="font-medium">{{ __('Fallleitlinie') }}</p>
<p class="mt-1 leading-relaxed">
{{ __('Führen Sie eine ganzheitliche Bewertung durch: prüfen Sie Geschäftsbeziehung, Transaktionshistorie und Monitoring-Regeln. Stellen Sie sicher, dass alle Entscheidungswege und Maßnahmen dokumentiert und für Audits nachvollziehbar sind.') }}
</p>
@if (! empty($sources))
<div class="mt-6 rounded-2xl border border-slate-200/70 bg-slate-50/80 p-5 dark:border-slate-700/70 dark:bg-slate-800/70">
<h5 class="text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400">{{ __('Quellen & Verifizierungsstand (≤ 365 Tage)') }}</h5>
<ul class="mt-3 list-disc space-y-1 pl-4 text-xs text-slate-600 dark:text-slate-300">
@foreach ($sources as $source)
<li>{{ $source }}</li>
@endforeach
</ul>
</div>
@endif
</div>
</div>
<div class="rounded-3xl border border-zinc-200/70 bg-white/95 p-6 shadow-sm backdrop-blur dark:border-zinc-700/70 dark:bg-zinc-900/90">
<h4 class="text-sm font-semibold uppercase tracking-wide text-zinc-500 dark:text-zinc-400">{{ __('Aktions-Checkliste') }}</h4>
<ol class="mt-4 space-y-3 text-sm text-zinc-600 dark:text-zinc-300">
@foreach ($actionChecklist as $index => $item)
<li class="flex gap-3 rounded-2xl border border-zinc-100/70 bg-zinc-50/70 p-4 dark:border-zinc-700/70 dark:bg-zinc-800/70">
<span class="mt-1 inline-flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-indigo-500/10 font-semibold text-indigo-600 dark:bg-indigo-500/20 dark:text-indigo-200">
{{ $index + 1 }}
</span>
<div>
<p class="font-semibold text-zinc-900 dark:text-zinc-100">{{ $item['title'] }}</p>
<p class="text-xs text-zinc-500 dark:text-zinc-400">{{ $item['description'] }}</p>
</div>
</li>
@endforeach
</ol>
</div>
<div class="rounded-3xl border border-zinc-200/70 bg-white/95 p-6 shadow-sm backdrop-blur dark:border-zinc-700/70 dark:bg-zinc-900/90">
<h4 class="text-sm font-semibold uppercase tracking-wide text-zinc-500 dark:text-zinc-400">{{ __('Historie mit dieser Gegenpartei') }}</h4>
<div class="mt-4 space-y-3">
@forelse ($counterpartyHistory as $history)
<div class="flex flex-wrap items-center justify-between gap-3 rounded-2xl border border-zinc-100/70 bg-zinc-50/70 p-4 text-sm text-zinc-600 dark:border-zinc-700/70 dark:bg-zinc-800/70 dark:text-zinc-300">
<div>
<p class="font-semibold text-zinc-900 dark:text-zinc-100">{{ $history->executed_at?->format('d.m.Y H:i') }}</p>
<p class="text-xs text-zinc-500 dark:text-zinc-400">{{ $history->channel }} {{ $history->reference }}</p>
</div>
<div class="flex flex-col items-end gap-1">
<span class="text-sm font-semibold text-zinc-900 dark:text-zinc-100">{{ $formatAmount($history->amount, $history->currency) }}</span>
<span class="inline-flex items-center gap-1 rounded-md bg-slate-100/60 px-2 py-0.5 text-xs font-semibold text-slate-700 dark:bg-slate-800/80 dark:text-slate-200">
{{ __('Risiko') }} {{ $history->risk_score }}
</span>
</div>
<div class="space-y-6">
<div class="rounded-3xl border border-zinc-200/70 bg-white/95 p-6 shadow-sm backdrop-blur dark:border-zinc-700/70 dark:bg-zinc-900/90">
<h4 class="text-sm font-semibold uppercase tracking-wide text-zinc-500 dark:text-zinc-400">{{ __('Historie mit dieser Gegenpartei') }}</h4>
<div class="mt-4 space-y-3">
@forelse ($counterpartyHistory as $history)
<div class="flex flex-wrap items-center justify-between gap-3 rounded-2xl border border-zinc-100/70 bg-zinc-50/70 p-4 text-sm text-zinc-600 dark:border-zinc-700/70 dark:bg-zinc-800/70 dark:text-zinc-300">
<div>
<p class="font-semibold text-zinc-900 dark:text-zinc-100">{{ $history->executed_at?->format('d.m.Y H:i') }}</p>
<p class="text-xs text-zinc-500 dark:text-zinc-400">{{ $history->channel }} {{ $history->reference }}</p>
</div>
<div class="flex flex-col items-end gap-1">
<span class="text-sm font-semibold text-zinc-900 dark:text-zinc-100">{{ $formatAmount($history->amount, $history->currency) }}</span>
<span class="inline-flex items-center gap-1 rounded-md bg-slate-100/60 px-2 py-0.5 text-xs font-semibold text-slate-700 dark:bg-slate-800/80 dark:text-slate-200">
{{ __('Risiko') }} {{ $history->risk_score }}
</span>
</div>
</div>
@empty
<div class="rounded-2xl border border-dashed border-zinc-300/60 bg-zinc-50/60 p-4 text-center text-xs text-zinc-500 dark:border-zinc-600/50 dark:bg-zinc-900/60">
{{ __('Keine weiteren Transaktionen mit dieser Gegenpartei gefunden.') }}
</div>
@endforelse
</div>
@empty
<div class="rounded-2xl border border-dashed border-zinc-300/60 bg-zinc-50/60 p-4 text-center text-xs text-zinc-500 dark:border-zinc-600/50 dark:bg-zinc-900/60">
{{ __('Keine weiteren Transaktionen mit dieser Gegenpartei gefunden.') }}
</div>
@endforelse
</div>
</div>
</div>
@else