diff --git a/app/Helpers/ThemeHelper.php b/app/Helpers/ThemeHelper.php
index c1c446f..4d17ba6 100644
--- a/app/Helpers/ThemeHelper.php
+++ b/app/Helpers/ThemeHelper.php
@@ -10,6 +10,15 @@ class ThemeHelper
public static function getLogoPath(string $type = 'positive'): string
{
$theme = config('app.theme', 'b2in');
+ return self::getLogoPathForBrand($theme, $type);
+ }
+
+ /**
+ * Get the logo path for a specific brand
+ */
+ public static function getLogoPathForBrand(?string $brand = null, string $type = 'positive'): string
+ {
+ $brand = $brand ?? config('app.theme', 'b2in');
$logoMap = [
'b2in' => [
@@ -30,7 +39,7 @@ class ThemeHelper
]
];
- return $logoMap[$theme][$type] ?? $logoMap['b2in'][$type];
+ return $logoMap[$brand][$type] ?? $logoMap['b2in'][$type];
}
/**
@@ -110,4 +119,45 @@ class ThemeHelper
$config = self::getDomainConfig();
return $config['url'] ?? config('app.url');
}
+
+ /**
+ * Get brand colors for a specific brand
+ */
+ public static function getBrandColors(?string $brand = null): array
+ {
+ $brand = $brand ?? config('app.theme', 'b2in');
+ $config = config("domains.domains.{$brand}", []);
+
+ return [
+ 'primary' => $config['color_scheme']['primary'] ?? '#2b3f51',
+ 'secondary' => $config['color_scheme']['secondary'] ?? '#20a0da',
+ 'accent' => $config['color_scheme']['accent'] ?? null,
+ ];
+ }
+
+ /**
+ * Get brand name for a specific brand
+ */
+ public static function getBrandName(?string $brand = null): string
+ {
+ $brand = $brand ?? config('app.theme', 'b2in');
+
+ $brandNames = [
+ 'b2in' => 'B2IN',
+ 'b2a' => 'B2A',
+ 'stileigentum' => 'StilEigentum',
+ 'style2own' => 'Style2Own',
+ ];
+
+ return $brandNames[$brand] ?? strtoupper($brand);
+ }
+
+ /**
+ * Get all brand configuration for a specific brand
+ */
+ public static function getBrandConfig(?string $brand = null): array
+ {
+ $brand = $brand ?? config('app.theme', 'b2in');
+ return config("domains.domains.{$brand}", []);
+ }
}
diff --git a/app/Http/Controllers/Api/DisplayConfigController.php b/app/Http/Controllers/Api/DisplayConfigController.php
new file mode 100644
index 0000000..6f9bade
--- /dev/null
+++ b/app/Http/Controllers/Api/DisplayConfigController.php
@@ -0,0 +1,43 @@
+get()->map(function ($video) {
+ return [
+ 'src' => $video->full_path,
+ 'position' => $video->position,
+ ];
+ });
+
+ $footerContent = DisplayFooterContent::active()->get()->map(function ($footer) {
+ $data = [
+ 'headline' => $footer->headline,
+ 'subline' => $footer->subline,
+ ];
+
+ // URL nur hinzufügen wenn vorhanden
+ if ($footer->url) {
+ $data['url'] = $footer->short_url;
+ }
+
+ return $data;
+ });
+
+ return response()->json([
+ 'videoPlaylist' => $videos,
+ 'footerContent' => $footerContent,
+ ]);
+ }
+}
diff --git a/app/Http/Middleware/BasicAuthMiddleware.php b/app/Http/Middleware/BasicAuthMiddleware.php
index 5767e29..6c7e383 100644
--- a/app/Http/Middleware/BasicAuthMiddleware.php
+++ b/app/Http/Middleware/BasicAuthMiddleware.php
@@ -28,6 +28,16 @@ class BasicAuthMiddleware
return $next($request);
}
+ // Skip Basic Auth für Flux UI Assets (flux.js, flux.min.js, editor.js, etc.)
+ if (str_starts_with($path, 'flux/')) {
+ return $next($request);
+ }
+
+ // Skip Basic Auth für Display-API und Short-Links (öffentlicher Zugriff für Display-Seite)
+ if ($request->is('api/display/*') || $request->is('_cabinet/*')) {
+ return $next($request);
+ }
+
// Credentials from .env file
$user = config('auth.basic.user');
$pass = config('auth.basic.password');
diff --git a/app/Http/Middleware/SetDomainUrl.php b/app/Http/Middleware/SetDomainUrl.php
new file mode 100644
index 0000000..494438e
--- /dev/null
+++ b/app/Http/Middleware/SetDomainUrl.php
@@ -0,0 +1,59 @@
+getHost();
+
+ // Suche nach der Domain-Konfiguration
+ $domainConfig = null;
+ $domains = config('domains.domains', []);
+
+ foreach ($domains as $name => $config) {
+ if (is_array($config) && isset($config['domain_name']) && $config['domain_name'] === $host) {
+ $domainConfig = $config;
+ break;
+ }
+ }
+
+ // Wenn eine Domain-Konfiguration gefunden wurde, setze die URL
+ if ($domainConfig && isset($domainConfig['url'])) {
+ $domainUrl = $domainConfig['url'];
+
+ // URL-Generator konfigurieren
+ URL::forceRootUrl($domainUrl);
+ URL::forceScheme(parse_url($domainUrl, PHP_URL_SCHEME) ?: 'https');
+
+ // Asset-Root setzen
+ /** @var UrlGenerator $urlGenerator */
+ $urlGenerator = app('url');
+ $urlGenerator->useAssetOrigin($domainUrl);
+
+ // Config aktualisieren
+ config([
+ 'app.url' => $domainUrl,
+ 'app.asset_url' => $domainUrl,
+ ]);
+ }
+
+ return $next($request);
+ }
+}
diff --git a/app/Http/Middleware/ThemeMiddleware.php b/app/Http/Middleware/ThemeMiddleware.php
index 391260f..27a9166 100644
--- a/app/Http/Middleware/ThemeMiddleware.php
+++ b/app/Http/Middleware/ThemeMiddleware.php
@@ -19,13 +19,13 @@ class ThemeMiddleware
$path = $request->path();
// Theme-Switching über Subdomains
- if (str_contains($host, 'b2in.test')) {
+ if (str_contains($host, 'b2in')) {
config(['app.theme' => 'b2in']);
- } elseif (str_contains($host, 'b2a.test')) {
+ } elseif (str_contains($host, 'b2a') || str_contains($host, 'bridges2america')) {
config(['app.theme' => 'b2a']);
- } elseif (str_contains($host, 'stileigentum.test')) {
+ } elseif (str_contains($host, 'stileigentum')) {
config(['app.theme' => 'stileigentum']);
- } elseif (str_contains($host, 'style2own.test')) {
+ } elseif (str_contains($host, 'style2own')) {
config(['app.theme' => 'style2own']);
}
@@ -41,7 +41,7 @@ class ThemeMiddleware
if (str_starts_with($path, 'b2in/')) {
config(['app.theme' => 'b2in']);
$request->server->set('REQUEST_URI', '/' . substr($path, 5)); // Entferne 'b2in/' vom Pfad
- } elseif (str_starts_with($path, 'b2a/')) {
+ } elseif (str_starts_with($path, 'b2a/') || str_starts_with($path, 'bridges2america/')) {
config(['app.theme' => 'b2a']);
$request->server->set('REQUEST_URI', '/' . substr($path, 4)); // Entferne 'b2a/' vom Pfad
} elseif (str_starts_with($path, 'stileigentum/')) {
diff --git a/app/Livewire/Admin/CMS/CabinetDisplay.php b/app/Livewire/Admin/CMS/CabinetDisplay.php
new file mode 100644
index 0000000..78e86db
--- /dev/null
+++ b/app/Livewire/Admin/CMS/CabinetDisplay.php
@@ -0,0 +1,292 @@
+loadAvailableVideos();
+ }
+
+ /**
+ * Lädt alle verfügbaren Video-Dateien aus dem assets-Ordner
+ */
+ public function loadAvailableVideos()
+ {
+ $assetsPath = public_path('_cabinet/assets');
+
+ if (File::exists($assetsPath)) {
+ $files = File::files($assetsPath);
+ $this->availableVideos = collect($files)
+ ->map(fn($file) => $file->getFilename())
+ ->filter(fn($filename) => in_array(pathinfo($filename, PATHINFO_EXTENSION), ['mp4', 'webm', 'mov']))
+ ->values()
+ ->toArray();
+ }
+ }
+
+ // ========================================
+ // VIDEO-VERWALTUNG
+ // ========================================
+
+ public function openVideoModal($id = null)
+ {
+ if ($id) {
+ $video = DisplayVideo::findOrFail($id);
+ $this->videoId = $video->id;
+ $this->videoFilename = $video->filename;
+ $this->videoTitle = $video->title ?? '';
+ $this->videoPosition = $video->position;
+ $this->videoIsActive = $video->is_active;
+ } else {
+ $this->resetVideoForm();
+ }
+ $this->showVideoModal = true;
+ }
+
+ public function saveVideo()
+ {
+ $this->validate([
+ 'videoFilename' => 'required|string',
+ 'videoPosition' => 'required|integer|min:0|max:100',
+ ], [
+ 'videoFilename.required' => 'Bitte wählen Sie ein Video aus.',
+ 'videoPosition.required' => 'Die Position ist erforderlich.',
+ 'videoPosition.min' => 'Die Position muss zwischen 0 und 100 liegen.',
+ 'videoPosition.max' => 'Die Position muss zwischen 0 und 100 liegen.',
+ ]);
+
+ $data = [
+ 'filename' => $this->videoFilename,
+ 'title' => $this->videoTitle,
+ 'position' => $this->videoPosition,
+ 'is_active' => $this->videoIsActive,
+ ];
+
+ if ($this->videoId) {
+ $video = DisplayVideo::findOrFail($this->videoId);
+ $video->update($data);
+ session()->flash('success', 'Video erfolgreich aktualisiert!');
+ } else {
+ $maxSortOrder = DisplayVideo::max('sort_order') ?? 0;
+ $data['sort_order'] = $maxSortOrder + 1;
+ DisplayVideo::create($data);
+ session()->flash('success', 'Video erfolgreich hinzugefügt!');
+ }
+
+ $this->closeVideoModal();
+ }
+
+ public function deleteVideo($id)
+ {
+ DisplayVideo::findOrFail($id)->delete();
+ session()->flash('success', 'Video erfolgreich gelöscht!');
+ }
+
+ public function toggleVideoStatus($id)
+ {
+ $video = DisplayVideo::findOrFail($id);
+ $video->update(['is_active' => !$video->is_active]);
+ }
+
+ public function moveVideo($id, $direction)
+ {
+ $video = DisplayVideo::findOrFail($id);
+ $currentOrder = $video->sort_order;
+
+ if ($direction === 'up' && $currentOrder > 0) {
+ $swapVideo = DisplayVideo::where('sort_order', $currentOrder - 1)->first();
+ if ($swapVideo) {
+ $video->update(['sort_order' => $currentOrder - 1]);
+ $swapVideo->update(['sort_order' => $currentOrder]);
+ }
+ } elseif ($direction === 'down') {
+ $swapVideo = DisplayVideo::where('sort_order', $currentOrder + 1)->first();
+ if ($swapVideo) {
+ $video->update(['sort_order' => $currentOrder + 1]);
+ $swapVideo->update(['sort_order' => $currentOrder]);
+ }
+ }
+ }
+
+ public function resetVideoForm()
+ {
+ $this->videoId = null;
+ $this->videoFilename = '';
+ $this->videoTitle = '';
+ $this->videoPosition = 25;
+ $this->videoIsActive = true;
+ }
+
+ public function closeVideoModal()
+ {
+ $this->showVideoModal = false;
+ $this->resetVideoForm();
+ }
+
+ // ========================================
+ // FOOTER-CONTENT-VERWALTUNG
+ // ========================================
+
+ public function openFooterModal($id = null)
+ {
+ if ($id) {
+ $footer = DisplayFooterContent::findOrFail($id);
+ $this->footerId = $footer->id;
+ $this->footerHeadline = $footer->headline;
+ $this->footerSubline = $footer->subline;
+ $this->footerUrl = $footer->url;
+ $this->footerIsActive = $footer->is_active;
+ } else {
+ $this->resetFooterForm();
+ }
+ $this->showFooterModal = true;
+ }
+
+ public function saveFooter()
+ {
+ $this->validate([
+ 'footerHeadline' => 'required|string|max:255',
+ 'footerSubline' => 'required|string|max:255',
+ 'footerUrl' => 'nullable|url',
+ ], [
+ 'footerHeadline.required' => 'Die Überschrift ist erforderlich.',
+ 'footerSubline.required' => 'Die Unterzeile ist erforderlich.',
+ 'footerUrl.url' => 'Bitte geben Sie eine gültige URL ein.',
+ ]);
+
+ $data = [
+ 'headline' => $this->footerHeadline,
+ 'subline' => $this->footerSubline,
+ 'url' => $this->footerUrl ?: null,
+ 'is_active' => $this->footerIsActive,
+ ];
+
+ if ($this->footerId) {
+ $footer = DisplayFooterContent::findOrFail($this->footerId);
+ $footer->update($data);
+
+ // Short-Code generieren falls URL vorhanden aber noch kein Short-Code
+ if ($footer->url && !$footer->short_code) {
+ $footer->short_code = DisplayFooterContent::generateUniqueShortCode();
+ $footer->save();
+ }
+
+ session()->flash('success', 'Footer-Inhalt erfolgreich aktualisiert!');
+ } else {
+ $maxSortOrder = DisplayFooterContent::max('sort_order') ?? 0;
+ $data['sort_order'] = $maxSortOrder + 1;
+
+ $footer = DisplayFooterContent::create($data);
+
+ // Short-Code nur generieren wenn URL vorhanden
+ if ($footer->url) {
+ $footer->short_code = DisplayFooterContent::generateUniqueShortCode();
+ $footer->save();
+ session()->flash('success', 'Footer-Inhalt erfolgreich hinzugefügt! Short-Link: ' . $footer->short_url);
+ } else {
+ session()->flash('success', 'Footer-Inhalt erfolgreich hinzugefügt! (Ohne QR-Code)');
+ }
+ }
+
+ $this->closeFooterModal();
+ }
+
+ public function regenerateShortCode($id)
+ {
+ $footer = DisplayFooterContent::findOrFail($id);
+ $footer->short_code = DisplayFooterContent::generateUniqueShortCode();
+ $footer->save();
+ session()->flash('success', 'Short-Code wurde neu generiert!');
+ }
+
+ public function resetClicks($id)
+ {
+ $footer = DisplayFooterContent::findOrFail($id);
+ $footer->clicks = 0;
+ $footer->save();
+ session()->flash('success', 'Klick-Zähler wurde zurückgesetzt!');
+ }
+
+ public function deleteFooter($id)
+ {
+ DisplayFooterContent::findOrFail($id)->delete();
+ session()->flash('success', 'Footer-Inhalt erfolgreich gelöscht!');
+ }
+
+ public function toggleFooterStatus($id)
+ {
+ $footer = DisplayFooterContent::findOrFail($id);
+ $footer->update(['is_active' => !$footer->is_active]);
+ }
+
+ public function moveFooter($id, $direction)
+ {
+ $footer = DisplayFooterContent::findOrFail($id);
+ $currentOrder = $footer->sort_order;
+
+ if ($direction === 'up' && $currentOrder > 0) {
+ $swapFooter = DisplayFooterContent::where('sort_order', $currentOrder - 1)->first();
+ if ($swapFooter) {
+ $footer->update(['sort_order' => $currentOrder - 1]);
+ $swapFooter->update(['sort_order' => $currentOrder]);
+ }
+ } elseif ($direction === 'down') {
+ $swapFooter = DisplayFooterContent::where('sort_order', $currentOrder + 1)->first();
+ if ($swapFooter) {
+ $footer->update(['sort_order' => $currentOrder + 1]);
+ $swapFooter->update(['sort_order' => $currentOrder]);
+ }
+ }
+ }
+
+ public function resetFooterForm()
+ {
+ $this->footerId = null;
+ $this->footerHeadline = '';
+ $this->footerSubline = '';
+ $this->footerUrl = '';
+ $this->footerIsActive = true;
+ }
+
+ public function closeFooterModal()
+ {
+ $this->showFooterModal = false;
+ $this->resetFooterForm();
+ }
+
+ public function render()
+ {
+ $videos = DisplayVideo::orderBy('sort_order')->get();
+ $footerContents = DisplayFooterContent::orderBy('sort_order')->get();
+
+ return view('livewire.admin.c-m-s.cabinet-display', [
+ 'videos' => $videos,
+ 'footerContents' => $footerContents,
+ ]);
+ }
+}
diff --git a/app/Livewire/Web/Components/UI/Header.php b/app/Livewire/Web/Components/UI/Header.php
index 2807b8c..c3916e9 100644
--- a/app/Livewire/Web/Components/UI/Header.php
+++ b/app/Livewire/Web/Components/UI/Header.php
@@ -16,7 +16,18 @@ class Header extends Component
$this->domainName = \App\Helpers\ThemeHelper::getDomainName();
$this->domainUrl = \App\Helpers\ThemeHelper::getDomainUrl();
$theme = config('app.theme', 'b2in');
- $this->content = config("content.themes.{$theme}.header", []);
+ $this->content = config("content.themes.{$theme}.header", [
+ 'portal_login' => 'Portal Login',
+ 'navigation' => []
+ ]);
+
+ // Ensure required keys exist
+ if (!isset($this->content['portal_login'])) {
+ $this->content['portal_login'] = 'Portal Login';
+ }
+ if (!isset($this->content['navigation']) || !is_array($this->content['navigation'])) {
+ $this->content['navigation'] = [];
+ }
}
public function toggleMobileMenu()
diff --git a/app/Models/DisplayFooterContent.php b/app/Models/DisplayFooterContent.php
new file mode 100644
index 0000000..3ff0f7f
--- /dev/null
+++ b/app/Models/DisplayFooterContent.php
@@ -0,0 +1,89 @@
+ 'boolean',
+ 'sort_order' => 'integer',
+ 'clicks' => 'integer',
+ ];
+
+ /**
+ * Boot-Methode für automatische Short-Code-Generierung
+ */
+ protected static function boot()
+ {
+ parent::boot();
+
+ static::creating(function ($model) {
+ // Short-Code nur generieren wenn URL vorhanden ist
+ if ($model->url && empty($model->short_code)) {
+ $model->short_code = self::generateUniqueShortCode();
+ }
+ });
+ }
+
+ /**
+ * Generiert einen eindeutigen Short-Code
+ */
+ public static function generateUniqueShortCode(): string
+ {
+ do {
+ // Generiere einen 6-stelligen alphanumerischen Code
+ $code = strtolower(substr(str_shuffle('abcdefghijklmnopqrstuvwxyz0123456789'), 0, 6));
+ } while (self::where('short_code', $code)->exists());
+
+ return $code;
+ }
+
+ /**
+ * Gibt die Short-URL zurück (dynamisch je nach Umgebung)
+ */
+ public function getShortUrlAttribute(): string
+ {
+ $basePath = config('display.base_path', '_display-b2in-eu');
+ $subdomain = config('display.subdomain');
+ $domain = config('display.domain', 'b2in.eu');
+
+ // Wenn Subdomain konfiguriert ist, verwende diese (Live-Server)
+ if ($subdomain) {
+ // Nutze HTTPS für Produktion
+ $protocol = config('app.env') === 'production' ? 'https' : 'http';
+ return "{$protocol}://{$subdomain}.{$domain}/go.php?z={$this->short_code}";
+ }
+
+ // Ansonsten verwende APP_URL + Base-Path (Testserver)
+ $baseUrl = rtrim(config('app.url'), '/');
+ return "{$baseUrl}/{$basePath}/go.php?z={$this->short_code}";
+ }
+
+ /**
+ * Erhöht den Klick-Zähler
+ */
+ public function incrementClicks(): void
+ {
+ $this->increment('clicks');
+ }
+
+ /**
+ * Scope für aktive Footer-Inhalte in sortierter Reihenfolge
+ */
+ public function scopeActive($query)
+ {
+ return $query->where('is_active', true)->orderBy('sort_order');
+ }
+}
diff --git a/app/Models/DisplayVideo.php b/app/Models/DisplayVideo.php
new file mode 100644
index 0000000..0be1bed
--- /dev/null
+++ b/app/Models/DisplayVideo.php
@@ -0,0 +1,38 @@
+ 'boolean',
+ 'position' => 'integer',
+ 'sort_order' => 'integer',
+ ];
+
+ /**
+ * Scope für aktive Videos in sortierter Reihenfolge
+ */
+ public function scopeActive($query)
+ {
+ return $query->where('is_active', true)->orderBy('sort_order');
+ }
+
+ /**
+ * Gibt den vollständigen Pfad zum Video zurück
+ */
+ public function getFullPathAttribute(): string
+ {
+ return "assets/{$this->filename}";
+ }
+}
diff --git a/app/Models/Partner.php b/app/Models/Partner.php
index c3a0afa..36ecb9b 100644
--- a/app/Models/Partner.php
+++ b/app/Models/Partner.php
@@ -6,6 +6,7 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
+use Illuminate\Database\Eloquent\Relations\HasOne;
class Partner extends Model
{
@@ -13,9 +14,22 @@ class Partner extends Model
protected $fillable = [
'company_name',
+ 'display_name',
'slug',
'type',
+ 'brand',
'hub_id',
+ 'parent_partner_id',
+ 'salutation',
+ 'first_name',
+ 'last_name',
+ 'street',
+ 'house_number',
+ 'zip',
+ 'city',
+ 'country',
+ 'phone',
+ 'website',
'description',
'logo_url',
'is_active',
@@ -50,6 +64,46 @@ class Partner extends Model
return $this->hasMany(User::class);
}
+ /**
+ * Für Kunden: Zugeordneter Makler/Händler (Parent-Partner)
+ */
+ public function parentPartner(): BelongsTo
+ {
+ return $this->belongsTo(Partner::class, 'parent_partner_id');
+ }
+
+ /**
+ * Für Makler/Händler: Zugeordnete Kunden (Child-Partners)
+ */
+ public function childPartners(): HasMany
+ {
+ return $this->hasMany(Partner::class, 'parent_partner_id');
+ }
+
+ /**
+ * Alias für parentPartner (für bessere Lesbarkeit im Code)
+ */
+ public function broker(): BelongsTo
+ {
+ return $this->parentPartner();
+ }
+
+ /**
+ * Alias für childPartners (für bessere Lesbarkeit im Code)
+ */
+ public function customers(): HasMany
+ {
+ return $this->childPartners();
+ }
+
+ /**
+ * Ein Partner (Manufacturer) kann eine Marke haben
+ */
+ public function brand(): HasOne
+ {
+ return $this->hasOne(Brand::class);
+ }
+
// TODO: Später die Beziehung zu Products hinzufügen
// public function products(): HasMany
// {
diff --git a/app/Models/RegistrationCode.php b/app/Models/RegistrationCode.php
new file mode 100644
index 0000000..2b9a0a5
--- /dev/null
+++ b/app/Models/RegistrationCode.php
@@ -0,0 +1,87 @@
+ 'array',
+ 'expires_at' => 'datetime',
+ 'used_at' => 'datetime',
+ ];
+
+ public function broker(): BelongsTo
+ {
+ return $this->belongsTo(Partner::class, 'broker_partner_id');
+ }
+
+ public function partner(): BelongsTo
+ {
+ return $this->belongsTo(Partner::class);
+ }
+
+ public function usedBy(): BelongsTo
+ {
+ return $this->belongsTo(User::class, 'used_by_user_id');
+ }
+
+ public function assignedToCode(): BelongsTo
+ {
+ return $this->belongsTo(RegistrationCode::class, 'assigned_to_code_id');
+ }
+
+ public function scopeAvailable($query)
+ {
+ return $query->where('status', self::STATUS_AVAILABLE);
+ }
+
+ public function isAvailable(): bool
+ {
+ if ($this->status !== self::STATUS_AVAILABLE) {
+ return false;
+ }
+
+ if ($this->expires_at && now()->greaterThan($this->expires_at)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public function markUsed(?User $user = null): void
+ {
+ $this->status = self::STATUS_USED;
+ $this->used_at = now();
+ if ($user) {
+ $this->used_by_user_id = $user->id;
+ if ($user->partner_id && !$this->partner_id) {
+ $this->partner_id = $user->partner_id;
+ }
+ }
+ $this->save();
+ }
+}
diff --git a/app/Models/User.php b/app/Models/User.php
index bb3b3e2..11cff19 100644
--- a/app/Models/User.php
+++ b/app/Models/User.php
@@ -2,8 +2,11 @@
namespace App\Models;
-// use Illuminate\Contracts\Auth\MustVerifyEmail;
+use App\Notifications\CustomResetPasswordNotification;
+use App\Notifications\CustomVerifyEmailNotification;
+use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Str;
@@ -11,11 +14,12 @@ use Laravel\Fortify\TwoFactorAuthenticatable;
use Laravel\Sanctum\HasApiTokens;
use Spatie\Permission\Traits\HasRoles;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
+use Illuminate\Database\Eloquent\Relations\HasOne;
-class User extends Authenticatable
+class User extends Authenticatable implements MustVerifyEmail
{
/** @use HasFactory<\Database\Factories\UserFactory> */
- use HasApiTokens, HasFactory, HasRoles, Notifiable, TwoFactorAuthenticatable;
+ use HasApiTokens, HasFactory, HasRoles, Notifiable, TwoFactorAuthenticatable, SoftDeletes;
/**
* The attributes that are mass assignable.
@@ -25,6 +29,7 @@ class User extends Authenticatable
protected $fillable = [
'partner_id',
'name',
+ 'display_name',
'email',
'password',
'email_verified_at',
@@ -49,6 +54,7 @@ class User extends Authenticatable
{
return [
'email_verified_at' => 'datetime',
+ 'deleted_at' => 'datetime',
'password' => 'hashed',
];
}
@@ -57,6 +63,15 @@ class User extends Authenticatable
{
return $this->belongsTo(Partner::class);
}
+
+ /**
+ * Get the registration code used by this user
+ */
+ public function registrationCode(): HasOne
+ {
+ return $this->hasOne(RegistrationCode::class, 'used_by_user_id');
+ }
+
/**
* Get the user's initials
*/
@@ -67,4 +82,56 @@ class User extends Authenticatable
->map(fn(string $name) => Str::of($name)->substr(0, 1))
->implode('');
}
+
+ /**
+ * Anonymize user data (for users with dependencies)
+ */
+ public function anonymize(): void
+ {
+ $this->update([
+ 'name' => 'Gelöschter Benutzer #' . $this->id,
+ 'display_name' => null,
+ 'email' => 'deleted_' . $this->id . '@anonymized.local',
+ 'password' => bcrypt(Str::random(64)),
+ ]);
+
+ // Entferne alle Rollen
+ $this->syncRoles([]);
+
+ // Soft Delete
+ $this->delete();
+ }
+
+ /**
+ * Check if user has dependencies that require anonymization instead of deletion
+ */
+ public function hasDependencies(): bool
+ {
+ // TODO: Später erweitern mit weiteren Verknüpfungen
+ // Beispiele: Orders, Projects, Documents, etc.
+
+ // Aktuell: Prüfe ob Partner existiert
+ return $this->partner_id !== null;
+ }
+
+ /**
+ * Send the password reset notification.
+ *
+ * @param string $token
+ * @return void
+ */
+ public function sendPasswordResetNotification($token): void
+ {
+ $this->notify(new CustomResetPasswordNotification($token));
+ }
+
+ /**
+ * Send the email verification notification.
+ *
+ * @return void
+ */
+ public function sendEmailVerificationNotification(): void
+ {
+ $this->notify(new CustomVerifyEmailNotification);
+ }
}
diff --git a/app/Notifications/CustomResetPasswordNotification.php b/app/Notifications/CustomResetPasswordNotification.php
new file mode 100644
index 0000000..07a4162
--- /dev/null
+++ b/app/Notifications/CustomResetPasswordNotification.php
@@ -0,0 +1,30 @@
+subject('Passwort zurücksetzen - ' . config('app.name'))
+ ->greeting('Hallo!')
+ ->line('Sie erhalten diese E-Mail, weil wir eine Anfrage zum Zurücksetzen des Passworts für Ihr Konto erhalten haben.')
+ ->line('Klicken Sie auf den folgenden Button, um ein neues Passwort zu vergeben:')
+ ->action('Passwort zurücksetzen', $url)
+ ->line('Dieser Link ist **' . $expiryMinutes . ' Minuten** gültig.')
+ ->line('Falls Sie keine Passwort-Zurücksetzung angefordert haben, ist keine weitere Aktion erforderlich. Ihr Passwort bleibt unverändert.')
+ ->salutation('Mit freundlichen Grüßen, ' . PHP_EOL . 'Ihr **' . config('app.name') . '** Team');
+ }
+}
diff --git a/app/Notifications/CustomVerifyEmailNotification.php b/app/Notifications/CustomVerifyEmailNotification.php
new file mode 100644
index 0000000..c63122d
--- /dev/null
+++ b/app/Notifications/CustomVerifyEmailNotification.php
@@ -0,0 +1,29 @@
+subject('E-Mail-Adresse bestätigen - ' . config('app.name'))
+ ->greeting('Willkommen bei ' . config('app.name') . '!')
+ ->line('Vielen Dank für Ihre Registrierung!')
+ ->line('Bitte bestätigen Sie Ihre E-Mail-Adresse, indem Sie auf den folgenden Button klicken:')
+ ->action('E-Mail-Adresse bestätigen', $url)
+ ->line('Dieser Bestätigungslink läuft in **60 Minuten** ab.')
+ ->line('Falls Sie kein Konto bei uns erstellt haben, ignorieren Sie bitte diese E-Mail.')
+ ->salutation('Mit freundlichen Grüßen, ' . PHP_EOL . 'Ihr **' . config('app.name') . '** Team');
+ }
+}
diff --git a/app/Providers/ThemeServiceProvider.php b/app/Providers/ThemeServiceProvider.php
index 7ec33e5..5341c30 100644
--- a/app/Providers/ThemeServiceProvider.php
+++ b/app/Providers/ThemeServiceProvider.php
@@ -2,7 +2,9 @@
namespace App\Providers;
+use Illuminate\Routing\UrlGenerator;
use Illuminate\Support\Facades\Request;
+use Illuminate\Support\Facades\URL;
use Illuminate\Support\Facades\View;
use Illuminate\Support\Facades\Vite;
use Illuminate\Support\ServiceProvider;
@@ -55,23 +57,55 @@ class ThemeServiceProvider extends ServiceProvider
$domainConfig = array_merge($domainConfig, $confiDomains[$themeOverride]);
}
+ // Dynamische ASSET_URL basierend auf der aktuellen Domain setzen
+ // Verhindert CORS-Probleme, da Assets immer von derselben Domain geladen werden
+ $assetUrl = $domainConfig['url'];
+
// Grundlegende Konfiguration im Anwendungskontext verfügbar machen
config([
'app.theme' => $domainConfig['theme'],
'app.view_prefix' => $domainConfig['view_prefix'],
'app.domain_name' => $domainConfig['domain_name'],
'app.url' => $domainConfig['url'],
+ 'app.asset_url' => $assetUrl, // Dynamische Asset-URL für die aktuelle Domain
]);
+ // URL-Generator für die aktuelle Domain konfigurieren
+ // Dies ist wichtig, damit asset() und url() die richtige Domain verwenden
+ URL::forceRootUrl($domainConfig['url']);
+ URL::forceScheme(parse_url($domainConfig['url'], PHP_URL_SCHEME) ?: 'https');
+
+ // WICHTIG: Asset-Root direkt im UrlGenerator setzen
+ // Der asset() Helper verwendet einen separaten Asset-Root
+ /** @var UrlGenerator $urlGenerator */
+ $urlGenerator = app('url');
+ $urlGenerator->useAssetOrigin($assetUrl);
+
// Spezifischere Daten für die Views verfügbar machen
View::share('theme', $domainConfig['theme']);
View::share('viewPrefix', $domainConfig['view_prefix']);
View::share('domainName', $domainConfig['domain_name']);
View::share('domainConfig', $domainConfig);
View::share('domainUrl', $domainConfig['url']);
+ View::share('assetUrl', $assetUrl);
+
// Vite-Assets-Konfiguration für die aktuelle Domain
- if (! app()->runningInConsole() && isset($domainConfig['assets_dir'])) {
- Vite::useBuildDirectory($domainConfig['assets_dir']);
+ if (! app()->runningInConsole()) {
+ if (isset($domainConfig['assets_dir'])) {
+ Vite::useBuildDirectory($domainConfig['assets_dir']);
+ }
+
+ if (app()->environment('local')) {
+ // Entwicklung: Vite Dev Server mit HMR
+ $viteDevServerUrl = env('VITE_DEV_SERVER_URL', 'https://assets.b2in.test');
+ Vite::useHotFile(public_path('hot'));
+ config(['app.vite_dev_server_url' => $viteDevServerUrl]);
+ View::share('viteDevServerUrl', $viteDevServerUrl);
+ } else {
+ // Produktion: Assets von der aktuellen Domain laden (kein CORS nötig)
+ Vite::useScriptTagAttributes(['crossorigin' => false]);
+ Vite::useStyleTagAttributes(['crossorigin' => false]);
+ }
}
}
}
diff --git a/bootstrap/app.php b/bootstrap/app.php
index 879db7d..77e223e 100644
--- a/bootstrap/app.php
+++ b/bootstrap/app.php
@@ -11,6 +11,10 @@ return Application::configure(basePath: dirname(__DIR__))
health: '/up',
)
->withMiddleware(function (Middleware $middleware) {
+ // Domain-URL Konfiguration - muss ganz am Anfang ausgeführt werden
+ // um sicherzustellen, dass url() und asset() die richtige Domain verwenden
+ $middleware->prepend(\App\Http\Middleware\SetDomainUrl::class);
+
// Partner Setup-Zwang für eingeloggte User
$middleware->alias([
'partner.setup' => \App\Http\Middleware\EnsurePartnerSetupCompleted::class,
diff --git a/bootstrap/providers.php b/bootstrap/providers.php
index d6f82d0..5a431ce 100644
--- a/bootstrap/providers.php
+++ b/bootstrap/providers.php
@@ -2,8 +2,8 @@
return [
App\Providers\AppServiceProvider::class,
+ App\Providers\ThemeServiceProvider::class, // Muss früh geladen werden für URL-Konfiguration
App\Providers\FortifyServiceProvider::class,
- App\Providers\ThemeServiceProvider::class,
App\Providers\VoltServiceProvider::class,
Barryvdh\Debugbar\ServiceProvider::class,
FluxPro\FluxProServiceProvider::class,
diff --git a/composer.json b/composer.json
index afa3286..25e3ef2 100644
--- a/composer.json
+++ b/composer.json
@@ -74,7 +74,9 @@
},
"extra": {
"laravel": {
- "dont-discover": []
+ "dont-discover": [
+ "orchestra/workbench"
+ ]
}
},
"config": {
diff --git a/composer.lock b/composer.lock
index 2d3672f..fcd38df 100644
--- a/composer.lock
+++ b/composer.lock
@@ -8,16 +8,16 @@
"packages": [
{
"name": "bacon/bacon-qr-code",
- "version": "v3.0.1",
+ "version": "v3.0.3",
"source": {
"type": "git",
"url": "https://github.com/Bacon/BaconQrCode.git",
- "reference": "f9cc1f52b5a463062251d666761178dbdb6b544f"
+ "reference": "36a1cb2b81493fa5b82e50bf8068bf84d1542563"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/f9cc1f52b5a463062251d666761178dbdb6b544f",
- "reference": "f9cc1f52b5a463062251d666761178dbdb6b544f",
+ "url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/36a1cb2b81493fa5b82e50bf8068bf84d1542563",
+ "reference": "36a1cb2b81493fa5b82e50bf8068bf84d1542563",
"shasum": ""
},
"require": {
@@ -27,8 +27,9 @@
},
"require-dev": {
"phly/keep-a-changelog": "^2.12",
- "phpunit/phpunit": "^10.5.11 || 11.0.4",
+ "phpunit/phpunit": "^10.5.11 || ^11.0.4",
"spatie/phpunit-snapshot-assertions": "^5.1.5",
+ "spatie/pixelmatch-php": "^1.2.0",
"squizlabs/php_codesniffer": "^3.9"
},
"suggest": {
@@ -56,9 +57,9 @@
"homepage": "https://github.com/Bacon/BaconQrCode",
"support": {
"issues": "https://github.com/Bacon/BaconQrCode/issues",
- "source": "https://github.com/Bacon/BaconQrCode/tree/v3.0.1"
+ "source": "https://github.com/Bacon/BaconQrCode/tree/v3.0.3"
},
- "time": "2024-10-01T13:55:55+00:00"
+ "time": "2025-11-19T17:15:36+00:00"
},
{
"name": "blade-ui-kit/blade-heroicons",
@@ -212,16 +213,16 @@
},
{
"name": "brick/math",
- "version": "0.14.0",
+ "version": "0.14.1",
"source": {
"type": "git",
"url": "https://github.com/brick/math.git",
- "reference": "113a8ee2656b882d4c3164fa31aa6e12cbb7aaa2"
+ "reference": "f05858549e5f9d7bb45875a75583240a38a281d0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/brick/math/zipball/113a8ee2656b882d4c3164fa31aa6e12cbb7aaa2",
- "reference": "113a8ee2656b882d4c3164fa31aa6e12cbb7aaa2",
+ "url": "https://api.github.com/repos/brick/math/zipball/f05858549e5f9d7bb45875a75583240a38a281d0",
+ "reference": "f05858549e5f9d7bb45875a75583240a38a281d0",
"shasum": ""
},
"require": {
@@ -260,7 +261,7 @@
],
"support": {
"issues": "https://github.com/brick/math/issues",
- "source": "https://github.com/brick/math/tree/0.14.0"
+ "source": "https://github.com/brick/math/tree/0.14.1"
},
"funding": [
{
@@ -268,7 +269,7 @@
"type": "github"
}
],
- "time": "2025-08-29T12:40:03+00:00"
+ "time": "2025-11-24T14:40:29+00:00"
},
{
"name": "carbonphp/carbon-doctrine-types",
@@ -764,31 +765,31 @@
},
{
"name": "fruitcake/php-cors",
- "version": "v1.3.0",
+ "version": "v1.4.0",
"source": {
"type": "git",
"url": "https://github.com/fruitcake/php-cors.git",
- "reference": "3d158f36e7875e2f040f37bc0573956240a5a38b"
+ "reference": "38aaa6c3fd4c157ffe2a4d10aa8b9b16ba8de379"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/fruitcake/php-cors/zipball/3d158f36e7875e2f040f37bc0573956240a5a38b",
- "reference": "3d158f36e7875e2f040f37bc0573956240a5a38b",
+ "url": "https://api.github.com/repos/fruitcake/php-cors/zipball/38aaa6c3fd4c157ffe2a4d10aa8b9b16ba8de379",
+ "reference": "38aaa6c3fd4c157ffe2a4d10aa8b9b16ba8de379",
"shasum": ""
},
"require": {
- "php": "^7.4|^8.0",
- "symfony/http-foundation": "^4.4|^5.4|^6|^7"
+ "php": "^8.1",
+ "symfony/http-foundation": "^5.4|^6.4|^7.3|^8"
},
"require-dev": {
- "phpstan/phpstan": "^1.4",
+ "phpstan/phpstan": "^2",
"phpunit/phpunit": "^9",
- "squizlabs/php_codesniffer": "^3.5"
+ "squizlabs/php_codesniffer": "^4"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.2-dev"
+ "dev-master": "1.3-dev"
}
},
"autoload": {
@@ -819,7 +820,7 @@
],
"support": {
"issues": "https://github.com/fruitcake/php-cors/issues",
- "source": "https://github.com/fruitcake/php-cors/tree/v1.3.0"
+ "source": "https://github.com/fruitcake/php-cors/tree/v1.4.0"
},
"funding": [
{
@@ -831,7 +832,7 @@
"type": "github"
}
],
- "time": "2023-10-12T05:21:21+00:00"
+ "time": "2025-12-03T09:33:47+00:00"
},
{
"name": "graham-campbell/result-type",
@@ -1308,16 +1309,16 @@
},
{
"name": "laravel/fortify",
- "version": "v1.31.2",
+ "version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/fortify.git",
- "reference": "a046d52ee087ee52c9852b840cf4bbad19f10934"
+ "reference": "e0666dabeec0b6428678af1d51f436dcfb24e3a9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/fortify/zipball/a046d52ee087ee52c9852b840cf4bbad19f10934",
- "reference": "a046d52ee087ee52c9852b840cf4bbad19f10934",
+ "url": "https://api.github.com/repos/laravel/fortify/zipball/e0666dabeec0b6428678af1d51f436dcfb24e3a9",
+ "reference": "e0666dabeec0b6428678af1d51f436dcfb24e3a9",
"shasum": ""
},
"require": {
@@ -1325,14 +1326,12 @@
"ext-json": "*",
"illuminate/support": "^10.0|^11.0|^12.0",
"php": "^8.1",
- "pragmarx/google2fa": "^8.0",
+ "pragmarx/google2fa": "^9.0",
"symfony/console": "^6.0|^7.0"
},
"require-dev": {
- "mockery/mockery": "^1.0",
- "orchestra/testbench": "^8.16|^9.0|^10.0",
- "phpstan/phpstan": "^1.10",
- "phpunit/phpunit": "^10.4|^11.3"
+ "orchestra/testbench": "^8.36|^9.15|^10.8",
+ "phpstan/phpstan": "^1.10"
},
"type": "library",
"extra": {
@@ -1369,20 +1368,20 @@
"issues": "https://github.com/laravel/fortify/issues",
"source": "https://github.com/laravel/fortify"
},
- "time": "2025-10-21T14:47:38+00:00"
+ "time": "2025-12-15T14:48:33+00:00"
},
{
"name": "laravel/framework",
- "version": "v12.37.0",
+ "version": "v12.43.1",
"source": {
"type": "git",
"url": "https://github.com/laravel/framework.git",
- "reference": "3c3c4ad30f5b528b164a7c09aa4ad03118c4c125"
+ "reference": "195b893593a9298edee177c0844132ebaa02102f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/framework/zipball/3c3c4ad30f5b528b164a7c09aa4ad03118c4c125",
- "reference": "3c3c4ad30f5b528b164a7c09aa4ad03118c4c125",
+ "url": "https://api.github.com/repos/laravel/framework/zipball/195b893593a9298edee177c0844132ebaa02102f",
+ "reference": "195b893593a9298edee177c0844132ebaa02102f",
"shasum": ""
},
"require": {
@@ -1470,6 +1469,7 @@
"illuminate/process": "self.version",
"illuminate/queue": "self.version",
"illuminate/redis": "self.version",
+ "illuminate/reflection": "self.version",
"illuminate/routing": "self.version",
"illuminate/session": "self.version",
"illuminate/support": "self.version",
@@ -1494,13 +1494,13 @@
"league/flysystem-sftp-v3": "^3.25.1",
"mockery/mockery": "^1.6.10",
"opis/json-schema": "^2.4.1",
- "orchestra/testbench-core": "^10.7.0",
+ "orchestra/testbench-core": "^10.8.1",
"pda/pheanstalk": "^5.0.6|^7.0.0",
"php-http/discovery": "^1.15",
"phpstan/phpstan": "^2.0",
"phpunit/phpunit": "^10.5.35|^11.5.3|^12.0.1",
"predis/predis": "^2.3|^3.0",
- "resend/resend-php": "^0.10.0",
+ "resend/resend-php": "^0.10.0|^1.0",
"symfony/cache": "^7.2.0",
"symfony/http-client": "^7.2.0",
"symfony/psr-http-message-bridge": "^7.2.0",
@@ -1534,7 +1534,7 @@
"predis/predis": "Required to use the predis connector (^2.3|^3.0).",
"psr/http-message": "Required to allow Storage::put to accept a StreamInterface (^1.0).",
"pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^6.0|^7.0).",
- "resend/resend-php": "Required to enable support for the Resend mail transport (^0.10.0).",
+ "resend/resend-php": "Required to enable support for the Resend mail transport (^0.10.0|^1.0).",
"symfony/cache": "Required to PSR-6 cache bridge (^7.2).",
"symfony/filesystem": "Required to enable support for relative symbolic links (^7.2).",
"symfony/http-client": "Required to enable support for the Symfony API mail transports (^7.2).",
@@ -1556,6 +1556,7 @@
"src/Illuminate/Filesystem/functions.php",
"src/Illuminate/Foundation/helpers.php",
"src/Illuminate/Log/functions.php",
+ "src/Illuminate/Reflection/helpers.php",
"src/Illuminate/Support/functions.php",
"src/Illuminate/Support/helpers.php"
],
@@ -1564,7 +1565,8 @@
"Illuminate\\Support\\": [
"src/Illuminate/Macroable/",
"src/Illuminate/Collections/",
- "src/Illuminate/Conditionable/"
+ "src/Illuminate/Conditionable/",
+ "src/Illuminate/Reflection/"
]
}
},
@@ -1588,20 +1590,20 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
- "time": "2025-11-04T15:39:33+00:00"
+ "time": "2025-12-16T18:53:08+00:00"
},
{
"name": "laravel/prompts",
- "version": "v0.3.7",
+ "version": "v0.3.8",
"source": {
"type": "git",
"url": "https://github.com/laravel/prompts.git",
- "reference": "a1891d362714bc40c8d23b0b1d7090f022ea27cc"
+ "reference": "096748cdfb81988f60090bbb839ce3205ace0d35"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/prompts/zipball/a1891d362714bc40c8d23b0b1d7090f022ea27cc",
- "reference": "a1891d362714bc40c8d23b0b1d7090f022ea27cc",
+ "url": "https://api.github.com/repos/laravel/prompts/zipball/096748cdfb81988f60090bbb839ce3205ace0d35",
+ "reference": "096748cdfb81988f60090bbb839ce3205ace0d35",
"shasum": ""
},
"require": {
@@ -1617,7 +1619,7 @@
"require-dev": {
"illuminate/collections": "^10.0|^11.0|^12.0",
"mockery/mockery": "^1.5",
- "pestphp/pest": "^2.3|^3.4",
+ "pestphp/pest": "^2.3|^3.4|^4.0",
"phpstan/phpstan": "^1.12.28",
"phpstan/phpstan-mockery": "^1.1.3"
},
@@ -1645,22 +1647,22 @@
"description": "Add beautiful and user-friendly forms to your command-line applications.",
"support": {
"issues": "https://github.com/laravel/prompts/issues",
- "source": "https://github.com/laravel/prompts/tree/v0.3.7"
+ "source": "https://github.com/laravel/prompts/tree/v0.3.8"
},
- "time": "2025-09-19T13:47:56+00:00"
+ "time": "2025-11-21T20:52:52+00:00"
},
{
"name": "laravel/sanctum",
- "version": "v4.2.0",
+ "version": "v4.2.1",
"source": {
"type": "git",
"url": "https://github.com/laravel/sanctum.git",
- "reference": "fd6df4f79f48a72992e8d29a9c0ee25422a0d677"
+ "reference": "f5fb373be39a246c74a060f2cf2ae2c2145b3664"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/sanctum/zipball/fd6df4f79f48a72992e8d29a9c0ee25422a0d677",
- "reference": "fd6df4f79f48a72992e8d29a9c0ee25422a0d677",
+ "url": "https://api.github.com/repos/laravel/sanctum/zipball/f5fb373be39a246c74a060f2cf2ae2c2145b3664",
+ "reference": "f5fb373be39a246c74a060f2cf2ae2c2145b3664",
"shasum": ""
},
"require": {
@@ -1674,9 +1676,8 @@
},
"require-dev": {
"mockery/mockery": "^1.6",
- "orchestra/testbench": "^9.0|^10.0",
- "phpstan/phpstan": "^1.10",
- "phpunit/phpunit": "^11.3"
+ "orchestra/testbench": "^9.15|^10.8",
+ "phpstan/phpstan": "^1.10"
},
"type": "library",
"extra": {
@@ -1711,20 +1712,20 @@
"issues": "https://github.com/laravel/sanctum/issues",
"source": "https://github.com/laravel/sanctum"
},
- "time": "2025-07-09T19:45:24+00:00"
+ "time": "2025-11-21T13:59:03+00:00"
},
{
"name": "laravel/serializable-closure",
- "version": "v2.0.6",
+ "version": "v2.0.7",
"source": {
"type": "git",
"url": "https://github.com/laravel/serializable-closure.git",
- "reference": "038ce42edee619599a1debb7e81d7b3759492819"
+ "reference": "cb291e4c998ac50637c7eeb58189c14f5de5b9dd"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/038ce42edee619599a1debb7e81d7b3759492819",
- "reference": "038ce42edee619599a1debb7e81d7b3759492819",
+ "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/cb291e4c998ac50637c7eeb58189c14f5de5b9dd",
+ "reference": "cb291e4c998ac50637c7eeb58189c14f5de5b9dd",
"shasum": ""
},
"require": {
@@ -1733,7 +1734,7 @@
"require-dev": {
"illuminate/support": "^10.0|^11.0|^12.0",
"nesbot/carbon": "^2.67|^3.0",
- "pestphp/pest": "^2.36|^3.0",
+ "pestphp/pest": "^2.36|^3.0|^4.0",
"phpstan/phpstan": "^2.0",
"symfony/var-dumper": "^6.2.0|^7.0.0"
},
@@ -1772,20 +1773,20 @@
"issues": "https://github.com/laravel/serializable-closure/issues",
"source": "https://github.com/laravel/serializable-closure"
},
- "time": "2025-10-09T13:42:30+00:00"
+ "time": "2025-11-21T20:52:36+00:00"
},
{
"name": "laravel/tinker",
- "version": "v2.10.1",
+ "version": "v2.10.2",
"source": {
"type": "git",
"url": "https://github.com/laravel/tinker.git",
- "reference": "22177cc71807d38f2810c6204d8f7183d88a57d3"
+ "reference": "3bcb5f62d6f837e0f093a601e26badafb127bd4c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/tinker/zipball/22177cc71807d38f2810c6204d8f7183d88a57d3",
- "reference": "22177cc71807d38f2810c6204d8f7183d88a57d3",
+ "url": "https://api.github.com/repos/laravel/tinker/zipball/3bcb5f62d6f837e0f093a601e26badafb127bd4c",
+ "reference": "3bcb5f62d6f837e0f093a601e26badafb127bd4c",
"shasum": ""
},
"require": {
@@ -1836,22 +1837,22 @@
],
"support": {
"issues": "https://github.com/laravel/tinker/issues",
- "source": "https://github.com/laravel/tinker/tree/v2.10.1"
+ "source": "https://github.com/laravel/tinker/tree/v2.10.2"
},
- "time": "2025-01-27T14:24:01+00:00"
+ "time": "2025-11-20T16:29:12+00:00"
},
{
"name": "league/commonmark",
- "version": "2.7.1",
+ "version": "2.8.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/commonmark.git",
- "reference": "10732241927d3971d28e7ea7b5712721fa2296ca"
+ "reference": "4efa10c1e56488e658d10adf7b7b7dcd19940bfb"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/10732241927d3971d28e7ea7b5712721fa2296ca",
- "reference": "10732241927d3971d28e7ea7b5712721fa2296ca",
+ "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/4efa10c1e56488e658d10adf7b7b7dcd19940bfb",
+ "reference": "4efa10c1e56488e658d10adf7b7b7dcd19940bfb",
"shasum": ""
},
"require": {
@@ -1888,7 +1889,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "2.8-dev"
+ "dev-main": "2.9-dev"
}
},
"autoload": {
@@ -1945,7 +1946,7 @@
"type": "tidelift"
}
],
- "time": "2025-07-20T12:47:49+00:00"
+ "time": "2025-11-26T21:48:24+00:00"
},
{
"name": "league/config",
@@ -2031,16 +2032,16 @@
},
{
"name": "league/flysystem",
- "version": "3.30.1",
+ "version": "3.30.2",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/flysystem.git",
- "reference": "c139fd65c1f796b926f4aec0df37f6caa959a8da"
+ "reference": "5966a8ba23e62bdb518dd9e0e665c2dbd4b5b277"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/c139fd65c1f796b926f4aec0df37f6caa959a8da",
- "reference": "c139fd65c1f796b926f4aec0df37f6caa959a8da",
+ "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/5966a8ba23e62bdb518dd9e0e665c2dbd4b5b277",
+ "reference": "5966a8ba23e62bdb518dd9e0e665c2dbd4b5b277",
"shasum": ""
},
"require": {
@@ -2108,22 +2109,22 @@
],
"support": {
"issues": "https://github.com/thephpleague/flysystem/issues",
- "source": "https://github.com/thephpleague/flysystem/tree/3.30.1"
+ "source": "https://github.com/thephpleague/flysystem/tree/3.30.2"
},
- "time": "2025-10-20T15:35:26+00:00"
+ "time": "2025-11-10T17:13:11+00:00"
},
{
"name": "league/flysystem-local",
- "version": "3.30.0",
+ "version": "3.30.2",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/flysystem-local.git",
- "reference": "6691915f77c7fb69adfb87dcd550052dc184ee10"
+ "reference": "ab4f9d0d672f601b102936aa728801dd1a11968d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/6691915f77c7fb69adfb87dcd550052dc184ee10",
- "reference": "6691915f77c7fb69adfb87dcd550052dc184ee10",
+ "url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/ab4f9d0d672f601b102936aa728801dd1a11968d",
+ "reference": "ab4f9d0d672f601b102936aa728801dd1a11968d",
"shasum": ""
},
"require": {
@@ -2157,9 +2158,9 @@
"local"
],
"support": {
- "source": "https://github.com/thephpleague/flysystem-local/tree/3.30.0"
+ "source": "https://github.com/thephpleague/flysystem-local/tree/3.30.2"
},
- "time": "2025-05-21T10:34:19+00:00"
+ "time": "2025-11-10T11:23:37+00:00"
},
{
"name": "league/mime-type-detection",
@@ -2219,33 +2220,38 @@
},
{
"name": "league/uri",
- "version": "7.5.1",
+ "version": "7.7.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/uri.git",
- "reference": "81fb5145d2644324614cc532b28efd0215bda430"
+ "reference": "8d587cddee53490f9b82bf203d3a9aa7ea4f9807"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/thephpleague/uri/zipball/81fb5145d2644324614cc532b28efd0215bda430",
- "reference": "81fb5145d2644324614cc532b28efd0215bda430",
+ "url": "https://api.github.com/repos/thephpleague/uri/zipball/8d587cddee53490f9b82bf203d3a9aa7ea4f9807",
+ "reference": "8d587cddee53490f9b82bf203d3a9aa7ea4f9807",
"shasum": ""
},
"require": {
- "league/uri-interfaces": "^7.5",
- "php": "^8.1"
+ "league/uri-interfaces": "^7.7",
+ "php": "^8.1",
+ "psr/http-factory": "^1"
},
"conflict": {
"league/uri-schemes": "^1.0"
},
"suggest": {
"ext-bcmath": "to improve IPV4 host parsing",
+ "ext-dom": "to convert the URI into an HTML anchor tag",
"ext-fileinfo": "to create Data URI from file contennts",
"ext-gmp": "to improve IPV4 host parsing",
"ext-intl": "to handle IDN host with the best performance",
+ "ext-uri": "to use the PHP native URI class",
"jeremykendall/php-domain-parser": "to resolve Public Suffix and Top Level Domain",
"league/uri-components": "Needed to easily manipulate URI objects components",
+ "league/uri-polyfill": "Needed to backport the PHP URI extension for older versions of PHP",
"php-64bit": "to improve IPV4 host parsing",
+ "rowbot/url": "to handle WHATWG URL",
"symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present"
},
"type": "library",
@@ -2273,6 +2279,7 @@
"description": "URI manipulation library",
"homepage": "https://uri.thephpleague.com",
"keywords": [
+ "URN",
"data-uri",
"file-uri",
"ftp",
@@ -2285,9 +2292,11 @@
"psr-7",
"query-string",
"querystring",
+ "rfc2141",
"rfc3986",
"rfc3987",
"rfc6570",
+ "rfc8141",
"uri",
"uri-template",
"url",
@@ -2297,7 +2306,7 @@
"docs": "https://uri.thephpleague.com",
"forum": "https://thephpleague.slack.com",
"issues": "https://github.com/thephpleague/uri-src/issues",
- "source": "https://github.com/thephpleague/uri/tree/7.5.1"
+ "source": "https://github.com/thephpleague/uri/tree/7.7.0"
},
"funding": [
{
@@ -2305,26 +2314,25 @@
"type": "github"
}
],
- "time": "2024-12-08T08:40:02+00:00"
+ "time": "2025-12-07T16:02:06+00:00"
},
{
"name": "league/uri-interfaces",
- "version": "7.5.0",
+ "version": "7.7.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/uri-interfaces.git",
- "reference": "08cfc6c4f3d811584fb09c37e2849e6a7f9b0742"
+ "reference": "62ccc1a0435e1c54e10ee6022df28d6c04c2946c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/08cfc6c4f3d811584fb09c37e2849e6a7f9b0742",
- "reference": "08cfc6c4f3d811584fb09c37e2849e6a7f9b0742",
+ "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/62ccc1a0435e1c54e10ee6022df28d6c04c2946c",
+ "reference": "62ccc1a0435e1c54e10ee6022df28d6c04c2946c",
"shasum": ""
},
"require": {
"ext-filter": "*",
"php": "^8.1",
- "psr/http-factory": "^1",
"psr/http-message": "^1.1 || ^2.0"
},
"suggest": {
@@ -2332,6 +2340,7 @@
"ext-gmp": "to improve IPV4 host parsing",
"ext-intl": "to handle IDN host with the best performance",
"php-64bit": "to improve IPV4 host parsing",
+ "rowbot/url": "to handle WHATWG URL",
"symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present"
},
"type": "library",
@@ -2356,7 +2365,7 @@
"homepage": "https://nyamsprod.com"
}
],
- "description": "Common interfaces and classes for URI representation and interaction",
+ "description": "Common tools for parsing and resolving RFC3987/RFC3986 URI",
"homepage": "https://uri.thephpleague.com",
"keywords": [
"data-uri",
@@ -2381,7 +2390,7 @@
"docs": "https://uri.thephpleague.com",
"forum": "https://thephpleague.slack.com",
"issues": "https://github.com/thephpleague/uri-src/issues",
- "source": "https://github.com/thephpleague/uri-interfaces/tree/7.5.0"
+ "source": "https://github.com/thephpleague/uri-interfaces/tree/7.7.0"
},
"funding": [
{
@@ -2389,20 +2398,20 @@
"type": "github"
}
],
- "time": "2024-12-08T08:18:47+00:00"
+ "time": "2025-12-07T16:03:21+00:00"
},
{
"name": "livewire/flux",
- "version": "v2.6.1",
+ "version": "v2.10.1",
"source": {
"type": "git",
"url": "https://github.com/livewire/flux.git",
- "reference": "227b88db0a02db91666af2303ea6727a3af78c51"
+ "reference": "11f04bca8cd57e05d594a96188c26f0c118c4c4f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/livewire/flux/zipball/227b88db0a02db91666af2303ea6727a3af78c51",
- "reference": "227b88db0a02db91666af2303ea6727a3af78c51",
+ "url": "https://api.github.com/repos/livewire/flux/zipball/11f04bca8cd57e05d594a96188c26f0c118c4c4f",
+ "reference": "11f04bca8cd57e05d594a96188c26f0c118c4c4f",
"shasum": ""
},
"require": {
@@ -2415,7 +2424,7 @@
"symfony/console": "^6.0|^7.0"
},
"conflict": {
- "livewire/blaze": "<0.1.0"
+ "livewire/blaze": "<1.0.0"
},
"type": "library",
"extra": {
@@ -2453,29 +2462,33 @@
],
"support": {
"issues": "https://github.com/livewire/flux/issues",
- "source": "https://github.com/livewire/flux/tree/v2.6.1"
+ "source": "https://github.com/livewire/flux/tree/v2.10.1"
},
- "time": "2025-10-28T21:12:05+00:00"
+ "time": "2025-12-17T23:17:22+00:00"
},
{
"name": "livewire/flux-pro",
- "version": "2.6.1",
+ "version": "2.10.1",
"dist": {
"type": "zip",
- "url": "https://composer.fluxui.dev/download/a0397651-df75-43ac-b21a-8a5ac8ad46b4/flux-pro-2.6.1.zip",
- "reference": "12a6570b061c858739b40a9509424c4b4cc42b62",
- "shasum": "10e8f4dad0b0232e5b47ce291ef1c55610be5298"
+ "url": "https://composer.fluxui.dev/download/a09e36f4-80ea-4712-8049-63bb48f28bab/flux-pro-2.10.1.zip",
+ "reference": "f10c97d73b952f60923b8769b333e052e4f72636",
+ "shasum": "9609b7fb4135979caba039ab9eb1970ca4ce27dd"
},
"require": {
"illuminate/console": "^10.0|^11.0|^12.0",
"illuminate/support": "^10.0|^11.0|^12.0",
"illuminate/view": "^10.0|^11.0|^12.0",
"laravel/prompts": "^0.1.24|^0.2|^0.3",
- "livewire/flux": "2.6.1|dev-main",
- "livewire/livewire": "^3.6.2|^4.0",
+ "livewire/flux": "2.10.1|dev-main",
+ "livewire/livewire": "^3.7.0|^4.0",
"php": "^8.1",
"symfony/console": "^6.0|^7.0"
},
+ "require-dev": {
+ "livewire/volt": "*",
+ "orchestra/testbench": "^10.8"
+ },
"type": "library",
"extra": {
"laravel": {
@@ -2495,6 +2508,18 @@
"FluxPro\\": "src/"
}
},
+ "autoload-dev": {
+ "psr-4": {
+ "App\\": "workbench/app/"
+ }
+ },
+ "scripts": {
+ "serve": [
+ "Composer\\Config::disableProcessTimeout",
+ "@php vendor/bin/testbench workbench:build --ansi",
+ "@php vendor/bin/testbench serve --port 3000 --ansi"
+ ]
+ },
"license": [
"proprietary"
],
@@ -2512,20 +2537,20 @@
"livewire",
"ui"
],
- "time": "2025-10-28T21:23:07+00:00"
+ "time": "2025-12-17T23:24:34+00:00"
},
{
"name": "livewire/livewire",
- "version": "v3.6.4",
+ "version": "v3.7.2",
"source": {
"type": "git",
"url": "https://github.com/livewire/livewire.git",
- "reference": "ef04be759da41b14d2d129e670533180a44987dc"
+ "reference": "b13a1e50aad156d382815c64e6c7da4a4fd08407"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/livewire/livewire/zipball/ef04be759da41b14d2d129e670533180a44987dc",
- "reference": "ef04be759da41b14d2d129e670533180a44987dc",
+ "url": "https://api.github.com/repos/livewire/livewire/zipball/b13a1e50aad156d382815c64e6c7da4a4fd08407",
+ "reference": "b13a1e50aad156d382815c64e6c7da4a4fd08407",
"shasum": ""
},
"require": {
@@ -2580,7 +2605,7 @@
"description": "A front-end framework for Laravel.",
"support": {
"issues": "https://github.com/livewire/livewire/issues",
- "source": "https://github.com/livewire/livewire/tree/v3.6.4"
+ "source": "https://github.com/livewire/livewire/tree/v3.7.2"
},
"funding": [
{
@@ -2588,20 +2613,20 @@
"type": "github"
}
],
- "time": "2025-07-17T05:12:15+00:00"
+ "time": "2025-12-17T01:53:59+00:00"
},
{
"name": "livewire/volt",
- "version": "v1.9.0",
+ "version": "v1.10.1",
"source": {
"type": "git",
"url": "https://github.com/livewire/volt.git",
- "reference": "4b289eef2f15398987a923d9f813cad6a6a19ea4"
+ "reference": "48cff133990c6261c63ee279fc091af6f6c6654e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/livewire/volt/zipball/4b289eef2f15398987a923d9f813cad6a6a19ea4",
- "reference": "4b289eef2f15398987a923d9f813cad6a6a19ea4",
+ "url": "https://api.github.com/repos/livewire/volt/zipball/48cff133990c6261c63ee279fc091af6f6c6654e",
+ "reference": "48cff133990c6261c63ee279fc091af6f6c6654e",
"shasum": ""
},
"require": {
@@ -2611,9 +2636,8 @@
},
"require-dev": {
"laravel/folio": "^1.1",
- "mockery/mockery": "^1.6",
- "orchestra/testbench": "^8.15.0|^9.0|^10.0",
- "pestphp/pest": "^2.9.5|^3.0",
+ "orchestra/testbench": "^8.36|^9.15|^10.8",
+ "pestphp/pest": "^2.9.5|^3.0|^4.0",
"phpstan/phpstan": "^1.10"
},
"type": "library",
@@ -2660,7 +2684,7 @@
"issues": "https://github.com/livewire/volt/issues",
"source": "https://github.com/livewire/volt"
},
- "time": "2025-10-30T02:46:00+00:00"
+ "time": "2025-11-25T16:19:15+00:00"
},
{
"name": "monolog/monolog",
@@ -2767,16 +2791,16 @@
},
{
"name": "nesbot/carbon",
- "version": "3.10.3",
+ "version": "3.11.0",
"source": {
"type": "git",
"url": "https://github.com/CarbonPHP/carbon.git",
- "reference": "8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f"
+ "reference": "bdb375400dcd162624531666db4799b36b64e4a1"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f",
- "reference": "8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f",
+ "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/bdb375400dcd162624531666db4799b36b64e4a1",
+ "reference": "bdb375400dcd162624531666db4799b36b64e4a1",
"shasum": ""
},
"require": {
@@ -2784,9 +2808,9 @@
"ext-json": "*",
"php": "^8.1",
"psr/clock": "^1.0",
- "symfony/clock": "^6.3.12 || ^7.0",
+ "symfony/clock": "^6.3.12 || ^7.0 || ^8.0",
"symfony/polyfill-mbstring": "^1.0",
- "symfony/translation": "^4.4.18 || ^5.2.1 || ^6.0 || ^7.0"
+ "symfony/translation": "^4.4.18 || ^5.2.1 || ^6.0 || ^7.0 || ^8.0"
},
"provide": {
"psr/clock-implementation": "1.0"
@@ -2868,7 +2892,7 @@
"type": "tidelift"
}
],
- "time": "2025-09-06T13:39:36+00:00"
+ "time": "2025-12-02T21:04:28+00:00"
},
{
"name": "nette/schema",
@@ -2937,20 +2961,20 @@
},
{
"name": "nette/utils",
- "version": "v4.0.8",
+ "version": "v4.1.0",
"source": {
"type": "git",
"url": "https://github.com/nette/utils.git",
- "reference": "c930ca4e3cf4f17dcfb03037703679d2396d2ede"
+ "reference": "fa1f0b8261ed150447979eb22e373b7b7ad5a8e0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nette/utils/zipball/c930ca4e3cf4f17dcfb03037703679d2396d2ede",
- "reference": "c930ca4e3cf4f17dcfb03037703679d2396d2ede",
+ "url": "https://api.github.com/repos/nette/utils/zipball/fa1f0b8261ed150447979eb22e373b7b7ad5a8e0",
+ "reference": "fa1f0b8261ed150447979eb22e373b7b7ad5a8e0",
"shasum": ""
},
"require": {
- "php": "8.0 - 8.5"
+ "php": "8.2 - 8.5"
},
"conflict": {
"nette/finder": "<3",
@@ -2973,7 +2997,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "4.0-dev"
+ "dev-master": "4.1-dev"
}
},
"autoload": {
@@ -3020,22 +3044,22 @@
],
"support": {
"issues": "https://github.com/nette/utils/issues",
- "source": "https://github.com/nette/utils/tree/v4.0.8"
+ "source": "https://github.com/nette/utils/tree/v4.1.0"
},
- "time": "2025-08-06T21:43:34+00:00"
+ "time": "2025-12-01T17:49:23+00:00"
},
{
"name": "nikic/php-parser",
- "version": "v5.6.2",
+ "version": "v5.7.0",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
- "reference": "3a454ca033b9e06b63282ce19562e892747449bb"
+ "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/3a454ca033b9e06b63282ce19562e892747449bb",
- "reference": "3a454ca033b9e06b63282ce19562e892747449bb",
+ "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82",
+ "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82",
"shasum": ""
},
"require": {
@@ -3078,37 +3102,37 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
- "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.2"
+ "source": "https://github.com/nikic/PHP-Parser/tree/v5.7.0"
},
- "time": "2025-10-21T19:32:17+00:00"
+ "time": "2025-12-06T11:56:16+00:00"
},
{
"name": "nunomaduro/termwind",
- "version": "v2.3.2",
+ "version": "v2.3.3",
"source": {
"type": "git",
"url": "https://github.com/nunomaduro/termwind.git",
- "reference": "eb61920a53057a7debd718a5b89c2178032b52c0"
+ "reference": "6fb2a640ff502caace8e05fd7be3b503a7e1c017"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/eb61920a53057a7debd718a5b89c2178032b52c0",
- "reference": "eb61920a53057a7debd718a5b89c2178032b52c0",
+ "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/6fb2a640ff502caace8e05fd7be3b503a7e1c017",
+ "reference": "6fb2a640ff502caace8e05fd7be3b503a7e1c017",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"php": "^8.2",
- "symfony/console": "^7.3.4"
+ "symfony/console": "^7.3.6"
},
"require-dev": {
"illuminate/console": "^11.46.1",
"laravel/pint": "^1.25.1",
"mockery/mockery": "^1.6.12",
- "pestphp/pest": "^2.36.0 || ^3.8.4",
+ "pestphp/pest": "^2.36.0 || ^3.8.4 || ^4.1.3",
"phpstan/phpstan": "^1.12.32",
"phpstan/phpstan-strict-rules": "^1.6.2",
- "symfony/var-dumper": "^7.3.4",
+ "symfony/var-dumper": "^7.3.5",
"thecodingmachine/phpstan-strict-rules": "^1.0.0"
},
"type": "library",
@@ -3151,7 +3175,7 @@
],
"support": {
"issues": "https://github.com/nunomaduro/termwind/issues",
- "source": "https://github.com/nunomaduro/termwind/tree/v2.3.2"
+ "source": "https://github.com/nunomaduro/termwind/tree/v2.3.3"
},
"funding": [
{
@@ -3167,7 +3191,7 @@
"type": "github"
}
],
- "time": "2025-10-18T11:10:27+00:00"
+ "time": "2025-11-20T02:34:59+00:00"
},
{
"name": "paragonie/constant_time_encoding",
@@ -3315,16 +3339,16 @@
},
{
"name": "pragmarx/google2fa",
- "version": "v8.0.3",
+ "version": "v9.0.0",
"source": {
"type": "git",
"url": "https://github.com/antonioribeiro/google2fa.git",
- "reference": "6f8d87ebd5afbf7790bde1ffc7579c7c705e0fad"
+ "reference": "e6bc62dd6ae83acc475f57912e27466019a1f2cf"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/antonioribeiro/google2fa/zipball/6f8d87ebd5afbf7790bde1ffc7579c7c705e0fad",
- "reference": "6f8d87ebd5afbf7790bde1ffc7579c7c705e0fad",
+ "url": "https://api.github.com/repos/antonioribeiro/google2fa/zipball/e6bc62dd6ae83acc475f57912e27466019a1f2cf",
+ "reference": "e6bc62dd6ae83acc475f57912e27466019a1f2cf",
"shasum": ""
},
"require": {
@@ -3361,9 +3385,9 @@
],
"support": {
"issues": "https://github.com/antonioribeiro/google2fa/issues",
- "source": "https://github.com/antonioribeiro/google2fa/tree/v8.0.3"
+ "source": "https://github.com/antonioribeiro/google2fa/tree/v9.0.0"
},
- "time": "2024-09-05T11:56:40+00:00"
+ "time": "2025-09-19T22:51:08+00:00"
},
{
"name": "psr/clock",
@@ -3779,16 +3803,16 @@
},
{
"name": "psy/psysh",
- "version": "v0.12.14",
+ "version": "v0.12.18",
"source": {
"type": "git",
"url": "https://github.com/bobthecow/psysh.git",
- "reference": "95c29b3756a23855a30566b745d218bee690bef2"
+ "reference": "ddff0ac01beddc251786fe70367cd8bbdb258196"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/bobthecow/psysh/zipball/95c29b3756a23855a30566b745d218bee690bef2",
- "reference": "95c29b3756a23855a30566b745d218bee690bef2",
+ "url": "https://api.github.com/repos/bobthecow/psysh/zipball/ddff0ac01beddc251786fe70367cd8bbdb258196",
+ "reference": "ddff0ac01beddc251786fe70367cd8bbdb258196",
"shasum": ""
},
"require": {
@@ -3796,8 +3820,8 @@
"ext-tokenizer": "*",
"nikic/php-parser": "^5.0 || ^4.0",
"php": "^8.0 || ^7.4",
- "symfony/console": "^7.0 || ^6.0 || ^5.0 || ^4.0 || ^3.4",
- "symfony/var-dumper": "^7.0 || ^6.0 || ^5.0 || ^4.0 || ^3.4"
+ "symfony/console": "^8.0 || ^7.0 || ^6.0 || ^5.0 || ^4.0 || ^3.4",
+ "symfony/var-dumper": "^8.0 || ^7.0 || ^6.0 || ^5.0 || ^4.0 || ^3.4"
},
"conflict": {
"symfony/console": "4.4.37 || 5.3.14 || 5.3.15 || 5.4.3 || 5.4.4 || 6.0.3 || 6.0.4"
@@ -3852,9 +3876,9 @@
],
"support": {
"issues": "https://github.com/bobthecow/psysh/issues",
- "source": "https://github.com/bobthecow/psysh/tree/v0.12.14"
+ "source": "https://github.com/bobthecow/psysh/tree/v0.12.18"
},
- "time": "2025-10-27T17:15:31+00:00"
+ "time": "2025-12-17T14:35:46+00:00"
},
{
"name": "ralouphie/getallheaders",
@@ -3978,20 +4002,20 @@
},
{
"name": "ramsey/uuid",
- "version": "4.9.1",
+ "version": "4.9.2",
"source": {
"type": "git",
"url": "https://github.com/ramsey/uuid.git",
- "reference": "81f941f6f729b1e3ceea61d9d014f8b6c6800440"
+ "reference": "8429c78ca35a09f27565311b98101e2826affde0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/ramsey/uuid/zipball/81f941f6f729b1e3ceea61d9d014f8b6c6800440",
- "reference": "81f941f6f729b1e3ceea61d9d014f8b6c6800440",
+ "url": "https://api.github.com/repos/ramsey/uuid/zipball/8429c78ca35a09f27565311b98101e2826affde0",
+ "reference": "8429c78ca35a09f27565311b98101e2826affde0",
"shasum": ""
},
"require": {
- "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13 || ^0.14",
+ "brick/math": "^0.8.16 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13 || ^0.14",
"php": "^8.0",
"ramsey/collection": "^1.2 || ^2.0"
},
@@ -4050,22 +4074,22 @@
],
"support": {
"issues": "https://github.com/ramsey/uuid/issues",
- "source": "https://github.com/ramsey/uuid/tree/4.9.1"
+ "source": "https://github.com/ramsey/uuid/tree/4.9.2"
},
- "time": "2025-09-04T20:59:21+00:00"
+ "time": "2025-12-14T04:43:48+00:00"
},
{
"name": "spatie/laravel-permission",
- "version": "6.23.0",
+ "version": "6.24.0",
"source": {
"type": "git",
"url": "https://github.com/spatie/laravel-permission.git",
- "reference": "9e41247bd512b1e6c229afbc1eb528f7565ae3bb"
+ "reference": "76adb1fc8d07c16a0721c35c4cc330b7a12598d7"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/spatie/laravel-permission/zipball/9e41247bd512b1e6c229afbc1eb528f7565ae3bb",
- "reference": "9e41247bd512b1e6c229afbc1eb528f7565ae3bb",
+ "url": "https://api.github.com/repos/spatie/laravel-permission/zipball/76adb1fc8d07c16a0721c35c4cc330b7a12598d7",
+ "reference": "76adb1fc8d07c16a0721c35c4cc330b7a12598d7",
"shasum": ""
},
"require": {
@@ -4127,7 +4151,7 @@
],
"support": {
"issues": "https://github.com/spatie/laravel-permission/issues",
- "source": "https://github.com/spatie/laravel-permission/tree/6.23.0"
+ "source": "https://github.com/spatie/laravel-permission/tree/6.24.0"
},
"funding": [
{
@@ -4135,26 +4159,25 @@
"type": "github"
}
],
- "time": "2025-11-03T20:16:13+00:00"
+ "time": "2025-12-13T21:45:21+00:00"
},
{
"name": "symfony/clock",
- "version": "v7.3.0",
+ "version": "v8.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/clock.git",
- "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24"
+ "reference": "832119f9b8dbc6c8e6f65f30c5969eca1e88764f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/clock/zipball/b81435fbd6648ea425d1ee96a2d8e68f4ceacd24",
- "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24",
+ "url": "https://api.github.com/repos/symfony/clock/zipball/832119f9b8dbc6c8e6f65f30c5969eca1e88764f",
+ "reference": "832119f9b8dbc6c8e6f65f30c5969eca1e88764f",
"shasum": ""
},
"require": {
- "php": ">=8.2",
- "psr/clock": "^1.0",
- "symfony/polyfill-php83": "^1.28"
+ "php": ">=8.4",
+ "psr/clock": "^1.0"
},
"provide": {
"psr/clock-implementation": "1.0"
@@ -4193,7 +4216,7 @@
"time"
],
"support": {
- "source": "https://github.com/symfony/clock/tree/v7.3.0"
+ "source": "https://github.com/symfony/clock/tree/v8.0.0"
},
"funding": [
{
@@ -4204,25 +4227,29 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2024-09-25T14:21:43+00:00"
+ "time": "2025-11-12T15:46:48+00:00"
},
{
"name": "symfony/console",
- "version": "v7.3.5",
+ "version": "v7.4.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
- "reference": "cdb80fa5869653c83cfe1a9084a673b6daf57ea7"
+ "reference": "6d9f0fbf2ec2e9785880096e3abd0ca0c88b506e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/cdb80fa5869653c83cfe1a9084a673b6daf57ea7",
- "reference": "cdb80fa5869653c83cfe1a9084a673b6daf57ea7",
+ "url": "https://api.github.com/repos/symfony/console/zipball/6d9f0fbf2ec2e9785880096e3abd0ca0c88b506e",
+ "reference": "6d9f0fbf2ec2e9785880096e3abd0ca0c88b506e",
"shasum": ""
},
"require": {
@@ -4230,7 +4257,7 @@
"symfony/deprecation-contracts": "^2.5|^3",
"symfony/polyfill-mbstring": "~1.0",
"symfony/service-contracts": "^2.5|^3",
- "symfony/string": "^7.2"
+ "symfony/string": "^7.2|^8.0"
},
"conflict": {
"symfony/dependency-injection": "<6.4",
@@ -4244,16 +4271,16 @@
},
"require-dev": {
"psr/log": "^1|^2|^3",
- "symfony/config": "^6.4|^7.0",
- "symfony/dependency-injection": "^6.4|^7.0",
- "symfony/event-dispatcher": "^6.4|^7.0",
- "symfony/http-foundation": "^6.4|^7.0",
- "symfony/http-kernel": "^6.4|^7.0",
- "symfony/lock": "^6.4|^7.0",
- "symfony/messenger": "^6.4|^7.0",
- "symfony/process": "^6.4|^7.0",
- "symfony/stopwatch": "^6.4|^7.0",
- "symfony/var-dumper": "^6.4|^7.0"
+ "symfony/config": "^6.4|^7.0|^8.0",
+ "symfony/dependency-injection": "^6.4|^7.0|^8.0",
+ "symfony/event-dispatcher": "^6.4|^7.0|^8.0",
+ "symfony/http-foundation": "^6.4|^7.0|^8.0",
+ "symfony/http-kernel": "^6.4|^7.0|^8.0",
+ "symfony/lock": "^6.4|^7.0|^8.0",
+ "symfony/messenger": "^6.4|^7.0|^8.0",
+ "symfony/process": "^6.4|^7.0|^8.0",
+ "symfony/stopwatch": "^6.4|^7.0|^8.0",
+ "symfony/var-dumper": "^6.4|^7.0|^8.0"
},
"type": "library",
"autoload": {
@@ -4287,7 +4314,7 @@
"terminal"
],
"support": {
- "source": "https://github.com/symfony/console/tree/v7.3.5"
+ "source": "https://github.com/symfony/console/tree/v7.4.1"
},
"funding": [
{
@@ -4307,24 +4334,24 @@
"type": "tidelift"
}
],
- "time": "2025-10-14T15:46:26+00:00"
+ "time": "2025-12-05T15:23:39+00:00"
},
{
"name": "symfony/css-selector",
- "version": "v7.3.0",
+ "version": "v8.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/css-selector.git",
- "reference": "601a5ce9aaad7bf10797e3663faefce9e26c24e2"
+ "reference": "6225bd458c53ecdee056214cb4a2ffaf58bd592b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/css-selector/zipball/601a5ce9aaad7bf10797e3663faefce9e26c24e2",
- "reference": "601a5ce9aaad7bf10797e3663faefce9e26c24e2",
+ "url": "https://api.github.com/repos/symfony/css-selector/zipball/6225bd458c53ecdee056214cb4a2ffaf58bd592b",
+ "reference": "6225bd458c53ecdee056214cb4a2ffaf58bd592b",
"shasum": ""
},
"require": {
- "php": ">=8.2"
+ "php": ">=8.4"
},
"type": "library",
"autoload": {
@@ -4356,7 +4383,7 @@
"description": "Converts CSS selectors to XPath expressions",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/css-selector/tree/v7.3.0"
+ "source": "https://github.com/symfony/css-selector/tree/v8.0.0"
},
"funding": [
{
@@ -4367,12 +4394,16 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2024-09-25T14:21:43+00:00"
+ "time": "2025-10-30T14:17:19+00:00"
},
{
"name": "symfony/deprecation-contracts",
@@ -4443,32 +4474,33 @@
},
{
"name": "symfony/error-handler",
- "version": "v7.3.4",
+ "version": "v7.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/error-handler.git",
- "reference": "99f81bc944ab8e5dae4f21b4ca9972698bbad0e4"
+ "reference": "48be2b0653594eea32dcef130cca1c811dcf25c2"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/error-handler/zipball/99f81bc944ab8e5dae4f21b4ca9972698bbad0e4",
- "reference": "99f81bc944ab8e5dae4f21b4ca9972698bbad0e4",
+ "url": "https://api.github.com/repos/symfony/error-handler/zipball/48be2b0653594eea32dcef130cca1c811dcf25c2",
+ "reference": "48be2b0653594eea32dcef130cca1c811dcf25c2",
"shasum": ""
},
"require": {
"php": ">=8.2",
"psr/log": "^1|^2|^3",
- "symfony/var-dumper": "^6.4|^7.0"
+ "symfony/polyfill-php85": "^1.32",
+ "symfony/var-dumper": "^6.4|^7.0|^8.0"
},
"conflict": {
"symfony/deprecation-contracts": "<2.5",
"symfony/http-kernel": "<6.4"
},
"require-dev": {
- "symfony/console": "^6.4|^7.0",
+ "symfony/console": "^6.4|^7.0|^8.0",
"symfony/deprecation-contracts": "^2.5|^3",
- "symfony/http-kernel": "^6.4|^7.0",
- "symfony/serializer": "^6.4|^7.0",
+ "symfony/http-kernel": "^6.4|^7.0|^8.0",
+ "symfony/serializer": "^6.4|^7.0|^8.0",
"symfony/webpack-encore-bundle": "^1.0|^2.0"
},
"bin": [
@@ -4500,7 +4532,7 @@
"description": "Provides tools to manage errors and ease debugging PHP code",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/error-handler/tree/v7.3.4"
+ "source": "https://github.com/symfony/error-handler/tree/v7.4.0"
},
"funding": [
{
@@ -4520,28 +4552,28 @@
"type": "tidelift"
}
],
- "time": "2025-09-11T10:12:26+00:00"
+ "time": "2025-11-05T14:29:59+00:00"
},
{
"name": "symfony/event-dispatcher",
- "version": "v7.3.3",
+ "version": "v8.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
- "reference": "b7dc69e71de420ac04bc9ab830cf3ffebba48191"
+ "reference": "573f95783a2ec6e38752979db139f09fec033f03"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b7dc69e71de420ac04bc9ab830cf3ffebba48191",
- "reference": "b7dc69e71de420ac04bc9ab830cf3ffebba48191",
+ "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/573f95783a2ec6e38752979db139f09fec033f03",
+ "reference": "573f95783a2ec6e38752979db139f09fec033f03",
"shasum": ""
},
"require": {
- "php": ">=8.2",
+ "php": ">=8.4",
"symfony/event-dispatcher-contracts": "^2.5|^3"
},
"conflict": {
- "symfony/dependency-injection": "<6.4",
+ "symfony/security-http": "<7.4",
"symfony/service-contracts": "<2.5"
},
"provide": {
@@ -4550,13 +4582,14 @@
},
"require-dev": {
"psr/log": "^1|^2|^3",
- "symfony/config": "^6.4|^7.0",
- "symfony/dependency-injection": "^6.4|^7.0",
- "symfony/error-handler": "^6.4|^7.0",
- "symfony/expression-language": "^6.4|^7.0",
- "symfony/http-foundation": "^6.4|^7.0",
+ "symfony/config": "^7.4|^8.0",
+ "symfony/dependency-injection": "^7.4|^8.0",
+ "symfony/error-handler": "^7.4|^8.0",
+ "symfony/expression-language": "^7.4|^8.0",
+ "symfony/framework-bundle": "^7.4|^8.0",
+ "symfony/http-foundation": "^7.4|^8.0",
"symfony/service-contracts": "^2.5|^3",
- "symfony/stopwatch": "^6.4|^7.0"
+ "symfony/stopwatch": "^7.4|^8.0"
},
"type": "library",
"autoload": {
@@ -4584,7 +4617,7 @@
"description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/event-dispatcher/tree/v7.3.3"
+ "source": "https://github.com/symfony/event-dispatcher/tree/v8.0.0"
},
"funding": [
{
@@ -4604,7 +4637,7 @@
"type": "tidelift"
}
],
- "time": "2025-08-13T11:49:31+00:00"
+ "time": "2025-10-30T14:17:19+00:00"
},
{
"name": "symfony/event-dispatcher-contracts",
@@ -4684,23 +4717,23 @@
},
{
"name": "symfony/finder",
- "version": "v7.3.5",
+ "version": "v7.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
- "reference": "9f696d2f1e340484b4683f7853b273abff94421f"
+ "reference": "340b9ed7320570f319028a2cbec46d40535e94bd"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/finder/zipball/9f696d2f1e340484b4683f7853b273abff94421f",
- "reference": "9f696d2f1e340484b4683f7853b273abff94421f",
+ "url": "https://api.github.com/repos/symfony/finder/zipball/340b9ed7320570f319028a2cbec46d40535e94bd",
+ "reference": "340b9ed7320570f319028a2cbec46d40535e94bd",
"shasum": ""
},
"require": {
"php": ">=8.2"
},
"require-dev": {
- "symfony/filesystem": "^6.4|^7.0"
+ "symfony/filesystem": "^6.4|^7.0|^8.0"
},
"type": "library",
"autoload": {
@@ -4728,7 +4761,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.5"
+ "source": "https://github.com/symfony/finder/tree/v7.4.0"
},
"funding": [
{
@@ -4748,27 +4781,26 @@
"type": "tidelift"
}
],
- "time": "2025-10-15T18:45:57+00:00"
+ "time": "2025-11-05T05:42:40+00:00"
},
{
"name": "symfony/http-foundation",
- "version": "v7.3.5",
+ "version": "v7.4.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-foundation.git",
- "reference": "ce31218c7cac92eab280762c4375fb70a6f4f897"
+ "reference": "bd1af1e425811d6f077db240c3a588bdb405cd27"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/http-foundation/zipball/ce31218c7cac92eab280762c4375fb70a6f4f897",
- "reference": "ce31218c7cac92eab280762c4375fb70a6f4f897",
+ "url": "https://api.github.com/repos/symfony/http-foundation/zipball/bd1af1e425811d6f077db240c3a588bdb405cd27",
+ "reference": "bd1af1e425811d6f077db240c3a588bdb405cd27",
"shasum": ""
},
"require": {
"php": ">=8.2",
- "symfony/deprecation-contracts": "^2.5|^3.0",
- "symfony/polyfill-mbstring": "~1.1",
- "symfony/polyfill-php83": "^1.27"
+ "symfony/deprecation-contracts": "^2.5|^3",
+ "symfony/polyfill-mbstring": "^1.1"
},
"conflict": {
"doctrine/dbal": "<3.6",
@@ -4777,13 +4809,13 @@
"require-dev": {
"doctrine/dbal": "^3.6|^4",
"predis/predis": "^1.1|^2.0",
- "symfony/cache": "^6.4.12|^7.1.5",
- "symfony/clock": "^6.4|^7.0",
- "symfony/dependency-injection": "^6.4|^7.0",
- "symfony/expression-language": "^6.4|^7.0",
- "symfony/http-kernel": "^6.4|^7.0",
- "symfony/mime": "^6.4|^7.0",
- "symfony/rate-limiter": "^6.4|^7.0"
+ "symfony/cache": "^6.4.12|^7.1.5|^8.0",
+ "symfony/clock": "^6.4|^7.0|^8.0",
+ "symfony/dependency-injection": "^6.4|^7.0|^8.0",
+ "symfony/expression-language": "^6.4|^7.0|^8.0",
+ "symfony/http-kernel": "^6.4|^7.0|^8.0",
+ "symfony/mime": "^6.4|^7.0|^8.0",
+ "symfony/rate-limiter": "^6.4|^7.0|^8.0"
},
"type": "library",
"autoload": {
@@ -4811,7 +4843,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.5"
+ "source": "https://github.com/symfony/http-foundation/tree/v7.4.1"
},
"funding": [
{
@@ -4831,29 +4863,29 @@
"type": "tidelift"
}
],
- "time": "2025-10-24T21:42:11+00:00"
+ "time": "2025-12-07T11:13:10+00:00"
},
{
"name": "symfony/http-kernel",
- "version": "v7.3.5",
+ "version": "v7.4.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-kernel.git",
- "reference": "24fd3f123532e26025f49f1abefcc01a69ef15ab"
+ "reference": "f6e6f0a5fa8763f75a504b930163785fb6dd055f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/http-kernel/zipball/24fd3f123532e26025f49f1abefcc01a69ef15ab",
- "reference": "24fd3f123532e26025f49f1abefcc01a69ef15ab",
+ "url": "https://api.github.com/repos/symfony/http-kernel/zipball/f6e6f0a5fa8763f75a504b930163785fb6dd055f",
+ "reference": "f6e6f0a5fa8763f75a504b930163785fb6dd055f",
"shasum": ""
},
"require": {
"php": ">=8.2",
"psr/log": "^1|^2|^3",
"symfony/deprecation-contracts": "^2.5|^3",
- "symfony/error-handler": "^6.4|^7.0",
- "symfony/event-dispatcher": "^7.3",
- "symfony/http-foundation": "^7.3",
+ "symfony/error-handler": "^6.4|^7.0|^8.0",
+ "symfony/event-dispatcher": "^7.3|^8.0",
+ "symfony/http-foundation": "^7.4|^8.0",
"symfony/polyfill-ctype": "^1.8"
},
"conflict": {
@@ -4863,6 +4895,7 @@
"symfony/console": "<6.4",
"symfony/dependency-injection": "<6.4",
"symfony/doctrine-bridge": "<6.4",
+ "symfony/flex": "<2.10",
"symfony/form": "<6.4",
"symfony/http-client": "<6.4",
"symfony/http-client-contracts": "<2.5",
@@ -4880,27 +4913,27 @@
},
"require-dev": {
"psr/cache": "^1.0|^2.0|^3.0",
- "symfony/browser-kit": "^6.4|^7.0",
- "symfony/clock": "^6.4|^7.0",
- "symfony/config": "^6.4|^7.0",
- "symfony/console": "^6.4|^7.0",
- "symfony/css-selector": "^6.4|^7.0",
- "symfony/dependency-injection": "^6.4|^7.0",
- "symfony/dom-crawler": "^6.4|^7.0",
- "symfony/expression-language": "^6.4|^7.0",
- "symfony/finder": "^6.4|^7.0",
+ "symfony/browser-kit": "^6.4|^7.0|^8.0",
+ "symfony/clock": "^6.4|^7.0|^8.0",
+ "symfony/config": "^6.4|^7.0|^8.0",
+ "symfony/console": "^6.4|^7.0|^8.0",
+ "symfony/css-selector": "^6.4|^7.0|^8.0",
+ "symfony/dependency-injection": "^6.4|^7.0|^8.0",
+ "symfony/dom-crawler": "^6.4|^7.0|^8.0",
+ "symfony/expression-language": "^6.4|^7.0|^8.0",
+ "symfony/finder": "^6.4|^7.0|^8.0",
"symfony/http-client-contracts": "^2.5|^3",
- "symfony/process": "^6.4|^7.0",
- "symfony/property-access": "^7.1",
- "symfony/routing": "^6.4|^7.0",
- "symfony/serializer": "^7.1",
- "symfony/stopwatch": "^6.4|^7.0",
- "symfony/translation": "^6.4|^7.0",
+ "symfony/process": "^6.4|^7.0|^8.0",
+ "symfony/property-access": "^7.1|^8.0",
+ "symfony/routing": "^6.4|^7.0|^8.0",
+ "symfony/serializer": "^7.1|^8.0",
+ "symfony/stopwatch": "^6.4|^7.0|^8.0",
+ "symfony/translation": "^6.4|^7.0|^8.0",
"symfony/translation-contracts": "^2.5|^3",
- "symfony/uid": "^6.4|^7.0",
- "symfony/validator": "^6.4|^7.0",
- "symfony/var-dumper": "^6.4|^7.0",
- "symfony/var-exporter": "^6.4|^7.0",
+ "symfony/uid": "^6.4|^7.0|^8.0",
+ "symfony/validator": "^6.4|^7.0|^8.0",
+ "symfony/var-dumper": "^6.4|^7.0|^8.0",
+ "symfony/var-exporter": "^6.4|^7.0|^8.0",
"twig/twig": "^3.12"
},
"type": "library",
@@ -4929,7 +4962,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.5"
+ "source": "https://github.com/symfony/http-kernel/tree/v7.4.2"
},
"funding": [
{
@@ -4949,20 +4982,20 @@
"type": "tidelift"
}
],
- "time": "2025-10-28T10:19:01+00:00"
+ "time": "2025-12-08T07:43:37+00:00"
},
{
"name": "symfony/mailer",
- "version": "v7.3.5",
+ "version": "v7.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/mailer.git",
- "reference": "fd497c45ba9c10c37864e19466b090dcb60a50ba"
+ "reference": "a3d9eea8cfa467ece41f0f54ba28185d74bd53fd"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/mailer/zipball/fd497c45ba9c10c37864e19466b090dcb60a50ba",
- "reference": "fd497c45ba9c10c37864e19466b090dcb60a50ba",
+ "url": "https://api.github.com/repos/symfony/mailer/zipball/a3d9eea8cfa467ece41f0f54ba28185d74bd53fd",
+ "reference": "a3d9eea8cfa467ece41f0f54ba28185d74bd53fd",
"shasum": ""
},
"require": {
@@ -4970,8 +5003,8 @@
"php": ">=8.2",
"psr/event-dispatcher": "^1",
"psr/log": "^1|^2|^3",
- "symfony/event-dispatcher": "^6.4|^7.0",
- "symfony/mime": "^7.2",
+ "symfony/event-dispatcher": "^6.4|^7.0|^8.0",
+ "symfony/mime": "^7.2|^8.0",
"symfony/service-contracts": "^2.5|^3"
},
"conflict": {
@@ -4982,10 +5015,10 @@
"symfony/twig-bridge": "<6.4"
},
"require-dev": {
- "symfony/console": "^6.4|^7.0",
- "symfony/http-client": "^6.4|^7.0",
- "symfony/messenger": "^6.4|^7.0",
- "symfony/twig-bridge": "^6.4|^7.0"
+ "symfony/console": "^6.4|^7.0|^8.0",
+ "symfony/http-client": "^6.4|^7.0|^8.0",
+ "symfony/messenger": "^6.4|^7.0|^8.0",
+ "symfony/twig-bridge": "^6.4|^7.0|^8.0"
},
"type": "library",
"autoload": {
@@ -5013,7 +5046,7 @@
"description": "Helps sending emails",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/mailer/tree/v7.3.5"
+ "source": "https://github.com/symfony/mailer/tree/v7.4.0"
},
"funding": [
{
@@ -5033,24 +5066,25 @@
"type": "tidelift"
}
],
- "time": "2025-10-24T14:27:20+00:00"
+ "time": "2025-11-21T15:26:00+00:00"
},
{
"name": "symfony/mime",
- "version": "v7.3.4",
+ "version": "v7.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/mime.git",
- "reference": "b1b828f69cbaf887fa835a091869e55df91d0e35"
+ "reference": "bdb02729471be5d047a3ac4a69068748f1a6be7a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/mime/zipball/b1b828f69cbaf887fa835a091869e55df91d0e35",
- "reference": "b1b828f69cbaf887fa835a091869e55df91d0e35",
+ "url": "https://api.github.com/repos/symfony/mime/zipball/bdb02729471be5d047a3ac4a69068748f1a6be7a",
+ "reference": "bdb02729471be5d047a3ac4a69068748f1a6be7a",
"shasum": ""
},
"require": {
"php": ">=8.2",
+ "symfony/deprecation-contracts": "^2.5|^3",
"symfony/polyfill-intl-idn": "^1.10",
"symfony/polyfill-mbstring": "^1.0"
},
@@ -5065,11 +5099,11 @@
"egulias/email-validator": "^2.1.10|^3.1|^4",
"league/html-to-markdown": "^5.0",
"phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0",
- "symfony/dependency-injection": "^6.4|^7.0",
- "symfony/process": "^6.4|^7.0",
- "symfony/property-access": "^6.4|^7.0",
- "symfony/property-info": "^6.4|^7.0",
- "symfony/serializer": "^6.4.3|^7.0.3"
+ "symfony/dependency-injection": "^6.4|^7.0|^8.0",
+ "symfony/process": "^6.4|^7.0|^8.0",
+ "symfony/property-access": "^6.4|^7.0|^8.0",
+ "symfony/property-info": "^6.4|^7.0|^8.0",
+ "symfony/serializer": "^6.4.3|^7.0.3|^8.0"
},
"type": "library",
"autoload": {
@@ -5101,7 +5135,7 @@
"mime-type"
],
"support": {
- "source": "https://github.com/symfony/mime/tree/v7.3.4"
+ "source": "https://github.com/symfony/mime/tree/v7.4.0"
},
"funding": [
{
@@ -5121,7 +5155,7 @@
"type": "tidelift"
}
],
- "time": "2025-09-16T08:38:17+00:00"
+ "time": "2025-11-16T10:14:42+00:00"
},
{
"name": "symfony/polyfill-ctype",
@@ -5954,16 +5988,16 @@
},
{
"name": "symfony/process",
- "version": "v7.3.4",
+ "version": "v7.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
- "reference": "f24f8f316367b30810810d4eb30c543d7003ff3b"
+ "reference": "7ca8dc2d0dcf4882658313aba8be5d9fd01026c8"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/process/zipball/f24f8f316367b30810810d4eb30c543d7003ff3b",
- "reference": "f24f8f316367b30810810d4eb30c543d7003ff3b",
+ "url": "https://api.github.com/repos/symfony/process/zipball/7ca8dc2d0dcf4882658313aba8be5d9fd01026c8",
+ "reference": "7ca8dc2d0dcf4882658313aba8be5d9fd01026c8",
"shasum": ""
},
"require": {
@@ -5995,7 +6029,7 @@
"description": "Executes commands in sub-processes",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/process/tree/v7.3.4"
+ "source": "https://github.com/symfony/process/tree/v7.4.0"
},
"funding": [
{
@@ -6015,20 +6049,20 @@
"type": "tidelift"
}
],
- "time": "2025-09-11T10:12:26+00:00"
+ "time": "2025-10-16T11:21:06+00:00"
},
{
"name": "symfony/routing",
- "version": "v7.3.4",
+ "version": "v7.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/routing.git",
- "reference": "8dc648e159e9bac02b703b9fbd937f19ba13d07c"
+ "reference": "4720254cb2644a0b876233d258a32bf017330db7"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/routing/zipball/8dc648e159e9bac02b703b9fbd937f19ba13d07c",
- "reference": "8dc648e159e9bac02b703b9fbd937f19ba13d07c",
+ "url": "https://api.github.com/repos/symfony/routing/zipball/4720254cb2644a0b876233d258a32bf017330db7",
+ "reference": "4720254cb2644a0b876233d258a32bf017330db7",
"shasum": ""
},
"require": {
@@ -6042,11 +6076,11 @@
},
"require-dev": {
"psr/log": "^1|^2|^3",
- "symfony/config": "^6.4|^7.0",
- "symfony/dependency-injection": "^6.4|^7.0",
- "symfony/expression-language": "^6.4|^7.0",
- "symfony/http-foundation": "^6.4|^7.0",
- "symfony/yaml": "^6.4|^7.0"
+ "symfony/config": "^6.4|^7.0|^8.0",
+ "symfony/dependency-injection": "^6.4|^7.0|^8.0",
+ "symfony/expression-language": "^6.4|^7.0|^8.0",
+ "symfony/http-foundation": "^6.4|^7.0|^8.0",
+ "symfony/yaml": "^6.4|^7.0|^8.0"
},
"type": "library",
"autoload": {
@@ -6080,7 +6114,7 @@
"url"
],
"support": {
- "source": "https://github.com/symfony/routing/tree/v7.3.4"
+ "source": "https://github.com/symfony/routing/tree/v7.4.0"
},
"funding": [
{
@@ -6100,20 +6134,20 @@
"type": "tidelift"
}
],
- "time": "2025-09-11T10:12:26+00:00"
+ "time": "2025-11-27T13:27:24+00:00"
},
{
"name": "symfony/service-contracts",
- "version": "v3.6.0",
+ "version": "v3.6.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
- "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4"
+ "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4",
- "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4",
+ "url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43",
+ "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43",
"shasum": ""
},
"require": {
@@ -6167,7 +6201,7 @@
"standards"
],
"support": {
- "source": "https://github.com/symfony/service-contracts/tree/v3.6.0"
+ "source": "https://github.com/symfony/service-contracts/tree/v3.6.1"
},
"funding": [
{
@@ -6178,43 +6212,47 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2025-04-25T09:37:31+00:00"
+ "time": "2025-07-15T11:30:57+00:00"
},
{
"name": "symfony/string",
- "version": "v7.3.4",
+ "version": "v8.0.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
- "reference": "f96476035142921000338bad71e5247fbc138872"
+ "reference": "ba65a969ac918ce0cc3edfac6cdde847eba231dc"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/string/zipball/f96476035142921000338bad71e5247fbc138872",
- "reference": "f96476035142921000338bad71e5247fbc138872",
+ "url": "https://api.github.com/repos/symfony/string/zipball/ba65a969ac918ce0cc3edfac6cdde847eba231dc",
+ "reference": "ba65a969ac918ce0cc3edfac6cdde847eba231dc",
"shasum": ""
},
"require": {
- "php": ">=8.2",
- "symfony/polyfill-ctype": "~1.8",
- "symfony/polyfill-intl-grapheme": "~1.0",
- "symfony/polyfill-intl-normalizer": "~1.0",
- "symfony/polyfill-mbstring": "~1.0"
+ "php": ">=8.4",
+ "symfony/polyfill-ctype": "^1.8",
+ "symfony/polyfill-intl-grapheme": "^1.33",
+ "symfony/polyfill-intl-normalizer": "^1.0",
+ "symfony/polyfill-mbstring": "^1.0"
},
"conflict": {
"symfony/translation-contracts": "<2.5"
},
"require-dev": {
- "symfony/emoji": "^7.1",
- "symfony/http-client": "^6.4|^7.0",
- "symfony/intl": "^6.4|^7.0",
+ "symfony/emoji": "^7.4|^8.0",
+ "symfony/http-client": "^7.4|^8.0",
+ "symfony/intl": "^7.4|^8.0",
"symfony/translation-contracts": "^2.5|^3.0",
- "symfony/var-exporter": "^6.4|^7.0"
+ "symfony/var-exporter": "^7.4|^8.0"
},
"type": "library",
"autoload": {
@@ -6253,7 +6291,7 @@
"utf8"
],
"support": {
- "source": "https://github.com/symfony/string/tree/v7.3.4"
+ "source": "https://github.com/symfony/string/tree/v8.0.1"
},
"funding": [
{
@@ -6273,38 +6311,31 @@
"type": "tidelift"
}
],
- "time": "2025-09-11T14:36:48+00:00"
+ "time": "2025-12-01T09:13:36+00:00"
},
{
"name": "symfony/translation",
- "version": "v7.3.4",
+ "version": "v8.0.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/translation.git",
- "reference": "ec25870502d0c7072d086e8ffba1420c85965174"
+ "reference": "770e3b8b0ba8360958abedcabacd4203467333ca"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/translation/zipball/ec25870502d0c7072d086e8ffba1420c85965174",
- "reference": "ec25870502d0c7072d086e8ffba1420c85965174",
+ "url": "https://api.github.com/repos/symfony/translation/zipball/770e3b8b0ba8360958abedcabacd4203467333ca",
+ "reference": "770e3b8b0ba8360958abedcabacd4203467333ca",
"shasum": ""
},
"require": {
- "php": ">=8.2",
- "symfony/deprecation-contracts": "^2.5|^3",
- "symfony/polyfill-mbstring": "~1.0",
- "symfony/translation-contracts": "^2.5|^3.0"
+ "php": ">=8.4",
+ "symfony/polyfill-mbstring": "^1.0",
+ "symfony/translation-contracts": "^3.6.1"
},
"conflict": {
"nikic/php-parser": "<5.0",
- "symfony/config": "<6.4",
- "symfony/console": "<6.4",
- "symfony/dependency-injection": "<6.4",
"symfony/http-client-contracts": "<2.5",
- "symfony/http-kernel": "<6.4",
- "symfony/service-contracts": "<2.5",
- "symfony/twig-bundle": "<6.4",
- "symfony/yaml": "<6.4"
+ "symfony/service-contracts": "<2.5"
},
"provide": {
"symfony/translation-implementation": "2.3|3.0"
@@ -6312,17 +6343,17 @@
"require-dev": {
"nikic/php-parser": "^5.0",
"psr/log": "^1|^2|^3",
- "symfony/config": "^6.4|^7.0",
- "symfony/console": "^6.4|^7.0",
- "symfony/dependency-injection": "^6.4|^7.0",
- "symfony/finder": "^6.4|^7.0",
+ "symfony/config": "^7.4|^8.0",
+ "symfony/console": "^7.4|^8.0",
+ "symfony/dependency-injection": "^7.4|^8.0",
+ "symfony/finder": "^7.4|^8.0",
"symfony/http-client-contracts": "^2.5|^3.0",
- "symfony/http-kernel": "^6.4|^7.0",
- "symfony/intl": "^6.4|^7.0",
+ "symfony/http-kernel": "^7.4|^8.0",
+ "symfony/intl": "^7.4|^8.0",
"symfony/polyfill-intl-icu": "^1.21",
- "symfony/routing": "^6.4|^7.0",
+ "symfony/routing": "^7.4|^8.0",
"symfony/service-contracts": "^2.5|^3",
- "symfony/yaml": "^6.4|^7.0"
+ "symfony/yaml": "^7.4|^8.0"
},
"type": "library",
"autoload": {
@@ -6353,7 +6384,7 @@
"description": "Provides tools to internationalize your application",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/translation/tree/v7.3.4"
+ "source": "https://github.com/symfony/translation/tree/v8.0.1"
},
"funding": [
{
@@ -6373,20 +6404,20 @@
"type": "tidelift"
}
],
- "time": "2025-09-07T11:39:36+00:00"
+ "time": "2025-12-01T09:13:36+00:00"
},
{
"name": "symfony/translation-contracts",
- "version": "v3.6.0",
+ "version": "v3.6.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/translation-contracts.git",
- "reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d"
+ "reference": "65a8bc82080447fae78373aa10f8d13b38338977"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/df210c7a2573f1913b2d17cc95f90f53a73d8f7d",
- "reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d",
+ "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/65a8bc82080447fae78373aa10f8d13b38338977",
+ "reference": "65a8bc82080447fae78373aa10f8d13b38338977",
"shasum": ""
},
"require": {
@@ -6435,7 +6466,7 @@
"standards"
],
"support": {
- "source": "https://github.com/symfony/translation-contracts/tree/v3.6.0"
+ "source": "https://github.com/symfony/translation-contracts/tree/v3.6.1"
},
"funding": [
{
@@ -6446,25 +6477,29 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2024-09-27T08:32:26+00:00"
+ "time": "2025-07-15T13:41:35+00:00"
},
{
"name": "symfony/uid",
- "version": "v7.3.1",
+ "version": "v7.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/uid.git",
- "reference": "a69f69f3159b852651a6bf45a9fdd149520525bb"
+ "reference": "2498e9f81b7baa206f44de583f2f48350b90142c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/uid/zipball/a69f69f3159b852651a6bf45a9fdd149520525bb",
- "reference": "a69f69f3159b852651a6bf45a9fdd149520525bb",
+ "url": "https://api.github.com/repos/symfony/uid/zipball/2498e9f81b7baa206f44de583f2f48350b90142c",
+ "reference": "2498e9f81b7baa206f44de583f2f48350b90142c",
"shasum": ""
},
"require": {
@@ -6472,7 +6507,7 @@
"symfony/polyfill-uuid": "^1.15"
},
"require-dev": {
- "symfony/console": "^6.4|^7.0"
+ "symfony/console": "^6.4|^7.0|^8.0"
},
"type": "library",
"autoload": {
@@ -6509,7 +6544,7 @@
"uuid"
],
"support": {
- "source": "https://github.com/symfony/uid/tree/v7.3.1"
+ "source": "https://github.com/symfony/uid/tree/v7.4.0"
},
"funding": [
{
@@ -6520,25 +6555,29 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2025-06-27T19:55:54+00:00"
+ "time": "2025-09-25T11:02:55+00:00"
},
{
"name": "symfony/var-dumper",
- "version": "v7.3.5",
+ "version": "v7.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-dumper.git",
- "reference": "476c4ae17f43a9a36650c69879dcf5b1e6ae724d"
+ "reference": "41fd6c4ae28c38b294b42af6db61446594a0dece"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/var-dumper/zipball/476c4ae17f43a9a36650c69879dcf5b1e6ae724d",
- "reference": "476c4ae17f43a9a36650c69879dcf5b1e6ae724d",
+ "url": "https://api.github.com/repos/symfony/var-dumper/zipball/41fd6c4ae28c38b294b42af6db61446594a0dece",
+ "reference": "41fd6c4ae28c38b294b42af6db61446594a0dece",
"shasum": ""
},
"require": {
@@ -6550,10 +6589,10 @@
"symfony/console": "<6.4"
},
"require-dev": {
- "symfony/console": "^6.4|^7.0",
- "symfony/http-kernel": "^6.4|^7.0",
- "symfony/process": "^6.4|^7.0",
- "symfony/uid": "^6.4|^7.0",
+ "symfony/console": "^6.4|^7.0|^8.0",
+ "symfony/http-kernel": "^6.4|^7.0|^8.0",
+ "symfony/process": "^6.4|^7.0|^8.0",
+ "symfony/uid": "^6.4|^7.0|^8.0",
"twig/twig": "^3.12"
},
"bin": [
@@ -6592,7 +6631,7 @@
"dump"
],
"support": {
- "source": "https://github.com/symfony/var-dumper/tree/v7.3.5"
+ "source": "https://github.com/symfony/var-dumper/tree/v7.4.0"
},
"funding": [
{
@@ -6612,27 +6651,27 @@
"type": "tidelift"
}
],
- "time": "2025-09-27T09:00:46+00:00"
+ "time": "2025-10-27T20:36:44+00:00"
},
{
"name": "tijsverkoyen/css-to-inline-styles",
- "version": "v2.3.0",
+ "version": "v2.4.0",
"source": {
"type": "git",
"url": "https://github.com/tijsverkoyen/CssToInlineStyles.git",
- "reference": "0d72ac1c00084279c1816675284073c5a337c20d"
+ "reference": "f0292ccf0ec75843d65027214426b6b163b48b41"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/0d72ac1c00084279c1816675284073c5a337c20d",
- "reference": "0d72ac1c00084279c1816675284073c5a337c20d",
+ "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/f0292ccf0ec75843d65027214426b6b163b48b41",
+ "reference": "f0292ccf0ec75843d65027214426b6b163b48b41",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-libxml": "*",
"php": "^7.4 || ^8.0",
- "symfony/css-selector": "^5.4 || ^6.0 || ^7.0"
+ "symfony/css-selector": "^5.4 || ^6.0 || ^7.0 || ^8.0"
},
"require-dev": {
"phpstan/phpstan": "^2.0",
@@ -6665,9 +6704,9 @@
"homepage": "https://github.com/tijsverkoyen/CssToInlineStyles",
"support": {
"issues": "https://github.com/tijsverkoyen/CssToInlineStyles/issues",
- "source": "https://github.com/tijsverkoyen/CssToInlineStyles/tree/v2.3.0"
+ "source": "https://github.com/tijsverkoyen/CssToInlineStyles/tree/v2.4.0"
},
- "time": "2024-12-21T16:25:41+00:00"
+ "time": "2025-12-02T11:56:42+00:00"
},
{
"name": "vlucas/phpdotenv",
@@ -6831,24 +6870,24 @@
"packages-dev": [
{
"name": "barryvdh/laravel-debugbar",
- "version": "v3.16.0",
+ "version": "v3.16.2",
"source": {
"type": "git",
"url": "https://github.com/barryvdh/laravel-debugbar.git",
- "reference": "f265cf5e38577d42311f1a90d619bcd3740bea23"
+ "reference": "730dbf8bf41f5691e026dd771e64dd54ad1b10b3"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/f265cf5e38577d42311f1a90d619bcd3740bea23",
- "reference": "f265cf5e38577d42311f1a90d619bcd3740bea23",
+ "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/730dbf8bf41f5691e026dd771e64dd54ad1b10b3",
+ "reference": "730dbf8bf41f5691e026dd771e64dd54ad1b10b3",
"shasum": ""
},
"require": {
- "illuminate/routing": "^9|^10|^11|^12",
- "illuminate/session": "^9|^10|^11|^12",
- "illuminate/support": "^9|^10|^11|^12",
+ "illuminate/routing": "^10|^11|^12",
+ "illuminate/session": "^10|^11|^12",
+ "illuminate/support": "^10|^11|^12",
"php": "^8.1",
- "php-debugbar/php-debugbar": "~2.2.0",
+ "php-debugbar/php-debugbar": "^2.2.4",
"symfony/finder": "^6|^7"
},
"require-dev": {
@@ -6900,7 +6939,7 @@
],
"support": {
"issues": "https://github.com/barryvdh/laravel-debugbar/issues",
- "source": "https://github.com/barryvdh/laravel-debugbar/tree/v3.16.0"
+ "source": "https://github.com/barryvdh/laravel-debugbar/tree/v3.16.2"
},
"funding": [
{
@@ -6912,7 +6951,7 @@
"type": "github"
}
],
- "time": "2025-07-14T11:56:43+00:00"
+ "time": "2025-12-03T14:52:46+00:00"
},
{
"name": "brianium/paratest",
@@ -7086,16 +7125,16 @@
},
{
"name": "doctrine/dbal",
- "version": "4.3.4",
+ "version": "4.4.1",
"source": {
"type": "git",
"url": "https://github.com/doctrine/dbal.git",
- "reference": "1a2fbd0e93b8dec7c3d1ac2b6396a7b929b130dc"
+ "reference": "3d544473fb93f5c25b483ea4f4ce99f8c4d9d44c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/doctrine/dbal/zipball/1a2fbd0e93b8dec7c3d1ac2b6396a7b929b130dc",
- "reference": "1a2fbd0e93b8dec7c3d1ac2b6396a7b929b130dc",
+ "url": "https://api.github.com/repos/doctrine/dbal/zipball/3d544473fb93f5c25b483ea4f4ce99f8c4d9d44c",
+ "reference": "3d544473fb93f5c25b483ea4f4ce99f8c4d9d44c",
"shasum": ""
},
"require": {
@@ -7114,8 +7153,8 @@
"phpunit/phpunit": "11.5.23",
"slevomat/coding-standard": "8.24.0",
"squizlabs/php_codesniffer": "4.0.0",
- "symfony/cache": "^6.3.8|^7.0",
- "symfony/console": "^5.4|^6.3|^7.0"
+ "symfony/cache": "^6.3.8|^7.0|^8.0",
+ "symfony/console": "^5.4|^6.3|^7.0|^8.0"
},
"suggest": {
"symfony/console": "For helpful console commands such as SQL execution and import of files."
@@ -7172,7 +7211,7 @@
],
"support": {
"issues": "https://github.com/doctrine/dbal/issues",
- "source": "https://github.com/doctrine/dbal/tree/4.3.4"
+ "source": "https://github.com/doctrine/dbal/tree/4.4.1"
},
"funding": [
{
@@ -7188,7 +7227,7 @@
"type": "tidelift"
}
],
- "time": "2025-10-09T09:11:36+00:00"
+ "time": "2025-12-04T10:11:03+00:00"
},
{
"name": "doctrine/deprecations",
@@ -7546,16 +7585,16 @@
},
{
"name": "laravel/dusk",
- "version": "v8.3.3",
+ "version": "v8.3.4",
"source": {
"type": "git",
"url": "https://github.com/laravel/dusk.git",
- "reference": "077d448cd993a08f97bfccf0ea3d6478b3908f7e"
+ "reference": "33a4211c7b63ffe430bf30ec3c014012dcb6dfa6"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/dusk/zipball/077d448cd993a08f97bfccf0ea3d6478b3908f7e",
- "reference": "077d448cd993a08f97bfccf0ea3d6478b3908f7e",
+ "url": "https://api.github.com/repos/laravel/dusk/zipball/33a4211c7b63ffe430bf30ec3c014012dcb6dfa6",
+ "reference": "33a4211c7b63ffe430bf30ec3c014012dcb6dfa6",
"shasum": ""
},
"require": {
@@ -7574,7 +7613,7 @@
"require-dev": {
"laravel/framework": "^10.0|^11.0|^12.0",
"mockery/mockery": "^1.6",
- "orchestra/testbench-core": "^8.19|^9.0|^10.0",
+ "orchestra/testbench-core": "^8.19|^9.17|^10.8",
"phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^10.1|^11.0|^12.0.1",
"psy/psysh": "^0.11.12|^0.12",
@@ -7614,22 +7653,22 @@
],
"support": {
"issues": "https://github.com/laravel/dusk/issues",
- "source": "https://github.com/laravel/dusk/tree/v8.3.3"
+ "source": "https://github.com/laravel/dusk/tree/v8.3.4"
},
- "time": "2025-06-10T13:59:27+00:00"
+ "time": "2025-11-20T16:26:16+00:00"
},
{
"name": "laravel/pail",
- "version": "v1.2.3",
+ "version": "v1.2.4",
"source": {
"type": "git",
"url": "https://github.com/laravel/pail.git",
- "reference": "8cc3d575c1f0e57eeb923f366a37528c50d2385a"
+ "reference": "49f92285ff5d6fc09816e976a004f8dec6a0ea30"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/pail/zipball/8cc3d575c1f0e57eeb923f366a37528c50d2385a",
- "reference": "8cc3d575c1f0e57eeb923f366a37528c50d2385a",
+ "url": "https://api.github.com/repos/laravel/pail/zipball/49f92285ff5d6fc09816e976a004f8dec6a0ea30",
+ "reference": "49f92285ff5d6fc09816e976a004f8dec6a0ea30",
"shasum": ""
},
"require": {
@@ -7646,9 +7685,9 @@
"require-dev": {
"laravel/framework": "^10.24|^11.0|^12.0",
"laravel/pint": "^1.13",
- "orchestra/testbench-core": "^8.13|^9.0|^10.0",
- "pestphp/pest": "^2.20|^3.0",
- "pestphp/pest-plugin-type-coverage": "^2.3|^3.0",
+ "orchestra/testbench-core": "^8.13|^9.17|^10.8",
+ "pestphp/pest": "^2.20|^3.0|^4.0",
+ "pestphp/pest-plugin-type-coverage": "^2.3|^3.0|^4.0",
"phpstan/phpstan": "^1.12.27",
"symfony/var-dumper": "^6.3|^7.0"
},
@@ -7695,20 +7734,20 @@
"issues": "https://github.com/laravel/pail/issues",
"source": "https://github.com/laravel/pail"
},
- "time": "2025-06-05T13:55:57+00:00"
+ "time": "2025-11-20T16:29:35+00:00"
},
{
"name": "laravel/pint",
- "version": "v1.25.1",
+ "version": "v1.26.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/pint.git",
- "reference": "5016e263f95d97670d71b9a987bd8996ade6d8d9"
+ "reference": "69dcca060ecb15e4b564af63d1f642c81a241d6f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/pint/zipball/5016e263f95d97670d71b9a987bd8996ade6d8d9",
- "reference": "5016e263f95d97670d71b9a987bd8996ade6d8d9",
+ "url": "https://api.github.com/repos/laravel/pint/zipball/69dcca060ecb15e4b564af63d1f642c81a241d6f",
+ "reference": "69dcca060ecb15e4b564af63d1f642c81a241d6f",
"shasum": ""
},
"require": {
@@ -7719,13 +7758,13 @@
"php": "^8.2.0"
},
"require-dev": {
- "friendsofphp/php-cs-fixer": "^3.87.2",
- "illuminate/view": "^11.46.0",
- "larastan/larastan": "^3.7.1",
- "laravel-zero/framework": "^11.45.0",
+ "friendsofphp/php-cs-fixer": "^3.90.0",
+ "illuminate/view": "^12.40.1",
+ "larastan/larastan": "^3.8.0",
+ "laravel-zero/framework": "^12.0.4",
"mockery/mockery": "^1.6.12",
- "nunomaduro/termwind": "^2.3.1",
- "pestphp/pest": "^2.36.0"
+ "nunomaduro/termwind": "^2.3.3",
+ "pestphp/pest": "^3.8.4"
},
"bin": [
"builds/pint"
@@ -7751,6 +7790,7 @@
"description": "An opinionated code formatter for PHP.",
"homepage": "https://laravel.com",
"keywords": [
+ "dev",
"format",
"formatter",
"lint",
@@ -7761,20 +7801,20 @@
"issues": "https://github.com/laravel/pint/issues",
"source": "https://github.com/laravel/pint"
},
- "time": "2025-09-19T02:57:12+00:00"
+ "time": "2025-11-25T21:15:52+00:00"
},
{
"name": "laravel/sail",
- "version": "v1.47.0",
+ "version": "v1.51.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/sail.git",
- "reference": "9a11e822238167ad8b791e4ea51155d25cf4d8f2"
+ "reference": "1c74357df034e869250b4365dd445c9f6ba5d068"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/sail/zipball/9a11e822238167ad8b791e4ea51155d25cf4d8f2",
- "reference": "9a11e822238167ad8b791e4ea51155d25cf4d8f2",
+ "url": "https://api.github.com/repos/laravel/sail/zipball/1c74357df034e869250b4365dd445c9f6ba5d068",
+ "reference": "1c74357df034e869250b4365dd445c9f6ba5d068",
"shasum": ""
},
"require": {
@@ -7824,7 +7864,7 @@
"issues": "https://github.com/laravel/sail/issues",
"source": "https://github.com/laravel/sail"
},
- "time": "2025-10-28T13:55:29+00:00"
+ "time": "2025-12-09T13:33:49+00:00"
},
{
"name": "mockery/mockery",
@@ -7971,16 +8011,16 @@
},
{
"name": "nunomaduro/collision",
- "version": "v8.8.2",
+ "version": "v8.8.3",
"source": {
"type": "git",
"url": "https://github.com/nunomaduro/collision.git",
- "reference": "60207965f9b7b7a4ce15a0f75d57f9dadb105bdb"
+ "reference": "1dc9e88d105699d0fee8bb18890f41b274f6b4c4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nunomaduro/collision/zipball/60207965f9b7b7a4ce15a0f75d57f9dadb105bdb",
- "reference": "60207965f9b7b7a4ce15a0f75d57f9dadb105bdb",
+ "url": "https://api.github.com/repos/nunomaduro/collision/zipball/1dc9e88d105699d0fee8bb18890f41b274f6b4c4",
+ "reference": "1dc9e88d105699d0fee8bb18890f41b274f6b4c4",
"shasum": ""
},
"require": {
@@ -8002,7 +8042,7 @@
"laravel/sanctum": "^4.1.1",
"laravel/tinker": "^2.10.1",
"orchestra/testbench-core": "^9.12.0 || ^10.4",
- "pestphp/pest": "^3.8.2",
+ "pestphp/pest": "^3.8.2 || ^4.0.0",
"sebastian/environment": "^7.2.1 || ^8.0"
},
"type": "library",
@@ -8066,43 +8106,46 @@
"type": "patreon"
}
],
- "time": "2025-06-25T02:12:12+00:00"
+ "time": "2025-11-20T02:55:25+00:00"
},
{
"name": "orchestra/canvas",
- "version": "v10.0.2",
+ "version": "v10.1.1",
"source": {
"type": "git",
"url": "https://github.com/orchestral/canvas.git",
- "reference": "94f732350e5c6d7136ff7b0fd05a90079dd77deb"
+ "reference": "6e63f56acd46b0ee842e922d0ebb18af8f7a60f6"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/orchestral/canvas/zipball/94f732350e5c6d7136ff7b0fd05a90079dd77deb",
- "reference": "94f732350e5c6d7136ff7b0fd05a90079dd77deb",
+ "url": "https://api.github.com/repos/orchestral/canvas/zipball/6e63f56acd46b0ee842e922d0ebb18af8f7a60f6",
+ "reference": "6e63f56acd46b0ee842e922d0ebb18af8f7a60f6",
"shasum": ""
},
"require": {
"composer-runtime-api": "^2.2",
"composer/semver": "^3.0",
- "illuminate/console": "^12.3.0",
- "illuminate/database": "^12.3.0",
- "illuminate/filesystem": "^12.3.0",
- "illuminate/support": "^12.3.0",
- "orchestra/canvas-core": "^10.0.1",
- "orchestra/sidekick": "^1.1.0",
- "orchestra/testbench-core": "^10.1.0",
+ "illuminate/console": "^12.40.0",
+ "illuminate/database": "^12.40.0",
+ "illuminate/filesystem": "^12.40.0",
+ "illuminate/support": "^12.40.0",
+ "orchestra/canvas-core": "^10.1.2",
+ "orchestra/sidekick": "^1.2.7",
+ "orchestra/testbench-core": "^10.8.0",
"php": "^8.2",
- "symfony/polyfill-php83": "^1.31",
+ "symfony/polyfill-php83": "^1.33",
"symfony/yaml": "^7.2.0"
},
+ "conflict": {
+ "laravel/framework": "<12.40.0|>=13.0.0"
+ },
"require-dev": {
- "laravel/framework": "^12.3.0",
- "laravel/pint": "^1.21",
+ "laravel/framework": "^12.40.0",
+ "laravel/pint": "^1.24",
"mockery/mockery": "^1.6.12",
- "phpstan/phpstan": "^2.1.8",
- "phpunit/phpunit": "^11.5.13",
- "spatie/laravel-ray": "^1.40.1"
+ "phpstan/phpstan": "^2.1.14",
+ "phpunit/phpunit": "^11.5.18|^12.0",
+ "spatie/laravel-ray": "^1.42.0"
},
"bin": [
"canvas"
@@ -8137,40 +8180,41 @@
"description": "Code Generators for Laravel Applications and Packages",
"support": {
"issues": "https://github.com/orchestral/canvas/issues",
- "source": "https://github.com/orchestral/canvas/tree/v10.0.2"
+ "source": "https://github.com/orchestral/canvas/tree/v10.1.1"
},
- "time": "2025-04-05T16:01:25+00:00"
+ "time": "2025-11-24T04:53:34+00:00"
},
{
"name": "orchestra/canvas-core",
- "version": "v10.0.1",
+ "version": "v10.1.2",
"source": {
"type": "git",
"url": "https://github.com/orchestral/canvas-core.git",
- "reference": "22b6515e7a070e1c45c8a3a9819f8b6cb0234173"
+ "reference": "af1ac73bb0e4f5a65eeb3aadc1030983c6ea0aea"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/orchestral/canvas-core/zipball/22b6515e7a070e1c45c8a3a9819f8b6cb0234173",
- "reference": "22b6515e7a070e1c45c8a3a9819f8b6cb0234173",
+ "url": "https://api.github.com/repos/orchestral/canvas-core/zipball/af1ac73bb0e4f5a65eeb3aadc1030983c6ea0aea",
+ "reference": "af1ac73bb0e4f5a65eeb3aadc1030983c6ea0aea",
"shasum": ""
},
"require": {
"composer-runtime-api": "^2.2",
"composer/semver": "^3.0",
- "illuminate/console": "^12.0",
- "illuminate/support": "^12.0",
- "orchestra/sidekick": "^1.0.2",
+ "illuminate/console": "^12.40.0",
+ "illuminate/support": "^12.40.0",
+ "orchestra/sidekick": "^1.2.0",
"php": "^8.2",
- "symfony/polyfill-php83": "^1.31"
+ "symfony/polyfill-php83": "^1.33"
},
"require-dev": {
- "laravel/framework": "^12.0",
- "laravel/pint": "^1.21",
+ "laravel/framework": "^12.40.0",
+ "laravel/pint": "^1.24",
"mockery/mockery": "^1.6.10",
- "orchestra/testbench-core": "^10.0",
- "phpstan/phpstan": "^2.1",
- "phpunit/phpunit": "^11.5.7",
+ "orchestra/testbench-core": "^10.8.0",
+ "phpstan/phpstan": "^2.1.14",
+ "phpunit/phpunit": "^11.5.12|^12.0.1",
+ "spatie/laravel-ray": "^1.40.2",
"symfony/yaml": "^7.2"
},
"type": "library",
@@ -8203,26 +8247,27 @@
"description": "Code Generators Builder for Laravel Applications and Packages",
"support": {
"issues": "https://github.com/orchestral/canvas/issues",
- "source": "https://github.com/orchestral/canvas-core/tree/v10.0.1"
+ "source": "https://github.com/orchestral/canvas-core/tree/v10.1.2"
},
- "time": "2025-02-19T04:17:05+00:00"
+ "time": "2025-11-24T04:41:15+00:00"
},
{
"name": "orchestra/sidekick",
- "version": "v1.2.17",
+ "version": "v1.2.18",
"source": {
"type": "git",
"url": "https://github.com/orchestral/sidekick.git",
- "reference": "371ce2882ee3f5bf826b36e75d461e51c9cd76c2"
+ "reference": "0e080ef62eed6c45aaea3619566a1fce02b62094"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/orchestral/sidekick/zipball/371ce2882ee3f5bf826b36e75d461e51c9cd76c2",
- "reference": "371ce2882ee3f5bf826b36e75d461e51c9cd76c2",
+ "url": "https://api.github.com/repos/orchestral/sidekick/zipball/0e080ef62eed6c45aaea3619566a1fce02b62094",
+ "reference": "0e080ef62eed6c45aaea3619566a1fce02b62094",
"shasum": ""
},
"require": {
"composer-runtime-api": "^2.2",
+ "composer/semver": "^3.0",
"php": "^8.1",
"symfony/polyfill-php83": "^1.32"
},
@@ -8260,31 +8305,31 @@
"description": "Packages Toolkit Utilities and Helpers for Laravel",
"support": {
"issues": "https://github.com/orchestral/sidekick/issues",
- "source": "https://github.com/orchestral/sidekick/tree/v1.2.17"
+ "source": "https://github.com/orchestral/sidekick/tree/v1.2.18"
},
- "time": "2025-10-02T11:02:26+00:00"
+ "time": "2025-11-29T15:16:23+00:00"
},
{
"name": "orchestra/testbench",
- "version": "v10.6.0",
+ "version": "v10.8.0",
"source": {
"type": "git",
"url": "https://github.com/orchestral/testbench.git",
- "reference": "87a7cb58edcfea9b1f26a63761c4d7ed5448f560"
+ "reference": "003922508c1d9f75bbe44f68364616d5ddee1939"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/orchestral/testbench/zipball/87a7cb58edcfea9b1f26a63761c4d7ed5448f560",
- "reference": "87a7cb58edcfea9b1f26a63761c4d7ed5448f560",
+ "url": "https://api.github.com/repos/orchestral/testbench/zipball/003922508c1d9f75bbe44f68364616d5ddee1939",
+ "reference": "003922508c1d9f75bbe44f68364616d5ddee1939",
"shasum": ""
},
"require": {
"composer-runtime-api": "^2.2",
"fakerphp/faker": "^1.23",
- "laravel/framework": "^12.24.0",
+ "laravel/framework": "^12.40.0",
"mockery/mockery": "^1.6.10",
- "orchestra/testbench-core": "^10.6.1",
- "orchestra/workbench": "^10.0.6",
+ "orchestra/testbench-core": "^10.8.0",
+ "orchestra/workbench": "^10.0.7",
"php": "^8.2",
"phpunit/phpunit": "^11.5.3|^12.0.1",
"symfony/process": "^7.2",
@@ -8315,47 +8360,47 @@
],
"support": {
"issues": "https://github.com/orchestral/testbench/issues",
- "source": "https://github.com/orchestral/testbench/tree/v10.6.0"
+ "source": "https://github.com/orchestral/testbench/tree/v10.8.0"
},
- "time": "2025-08-20T14:38:08+00:00"
+ "time": "2025-11-24T09:44:51+00:00"
},
{
"name": "orchestra/testbench-core",
- "version": "v10.7.0",
+ "version": "v10.8.1",
"source": {
"type": "git",
"url": "https://github.com/orchestral/testbench-core.git",
- "reference": "123ad189fcb1e49f95d87c3bc301b059e40edf05"
+ "reference": "f1da36cedc677d015d2a46d36abee54ffd5ba711"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/orchestral/testbench-core/zipball/123ad189fcb1e49f95d87c3bc301b059e40edf05",
- "reference": "123ad189fcb1e49f95d87c3bc301b059e40edf05",
+ "url": "https://api.github.com/repos/orchestral/testbench-core/zipball/f1da36cedc677d015d2a46d36abee54ffd5ba711",
+ "reference": "f1da36cedc677d015d2a46d36abee54ffd5ba711",
"shasum": ""
},
"require": {
"composer-runtime-api": "^2.2",
- "orchestra/sidekick": "~1.1.20|~1.2.17",
+ "orchestra/sidekick": "~1.1.21|~1.2.18",
"php": "^8.2",
"symfony/deprecation-contracts": "^2.5|^3.0",
"symfony/polyfill-php83": "^1.32"
},
"conflict": {
"brianium/paratest": "<7.3.0|>=8.0.0",
- "laravel/framework": "<12.28.0|>=13.0.0",
+ "laravel/framework": "<12.40.0|>=13.0.0",
"laravel/serializable-closure": "<1.3.0|>=2.0.0 <2.0.3|>=3.0.0",
"nunomaduro/collision": "<8.0.0|>=9.0.0",
- "phpunit/phpunit": "<10.5.35|>=11.0.0 <11.5.3|12.0.0|>=12.5.0"
+ "phpunit/phpunit": "<10.5.35|>=11.0.0 <11.5.3|12.0.0|>=12.6.0"
},
"require-dev": {
"fakerphp/faker": "^1.24",
- "laravel/framework": "^12.28.0",
+ "laravel/framework": "^12.40.0",
"laravel/pint": "^1.24",
"laravel/serializable-closure": "^1.3|^2.0.4",
"mockery/mockery": "^1.6.10",
"phpstan/phpstan": "^2.1.19",
"phpunit/phpunit": "^10.5.35|^11.5.3|^12.0.1",
- "spatie/laravel-ray": "^1.40.2",
+ "spatie/laravel-ray": "^1.42.0",
"symfony/process": "^7.2.0",
"symfony/yaml": "^7.2.0",
"vlucas/phpdotenv": "^5.6.1"
@@ -8364,7 +8409,7 @@
"brianium/paratest": "Allow using parallel testing (^7.3).",
"ext-pcntl": "Required to use all features of the console signal trapping.",
"fakerphp/faker": "Allow using Faker for testing (^1.23).",
- "laravel/framework": "Required for testing (^12.28.0).",
+ "laravel/framework": "Required for testing (^12.40.0).",
"mockery/mockery": "Allow using Mockery for testing (^1.6).",
"nunomaduro/collision": "Allow using Laravel style tests output and parallel testing (^8.0).",
"orchestra/testbench-dusk": "Allow using Laravel Dusk for testing (^10.0).",
@@ -8410,43 +8455,43 @@
"issues": "https://github.com/orchestral/testbench/issues",
"source": "https://github.com/orchestral/testbench-core"
},
- "time": "2025-10-14T12:16:46+00:00"
+ "time": "2025-12-08T08:07:27+00:00"
},
{
"name": "orchestra/workbench",
- "version": "v10.0.6",
+ "version": "v10.0.7",
"source": {
"type": "git",
"url": "https://github.com/orchestral/workbench.git",
- "reference": "4e8a5a68200971ddb9ce4abf26488838bf5c0812"
+ "reference": "7e41a6cbda2f553b725b4b0c104c684ae5d0f2b6"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/orchestral/workbench/zipball/4e8a5a68200971ddb9ce4abf26488838bf5c0812",
- "reference": "4e8a5a68200971ddb9ce4abf26488838bf5c0812",
+ "url": "https://api.github.com/repos/orchestral/workbench/zipball/7e41a6cbda2f553b725b4b0c104c684ae5d0f2b6",
+ "reference": "7e41a6cbda2f553b725b4b0c104c684ae5d0f2b6",
"shasum": ""
},
"require": {
"composer-runtime-api": "^2.2",
"fakerphp/faker": "^1.23",
- "laravel/framework": "^12.1.1",
+ "laravel/framework": "^12.40.0",
"laravel/pail": "^1.2.2",
"laravel/tinker": "^2.10.1",
"nunomaduro/collision": "^8.6",
- "orchestra/canvas": "^10.0.2",
- "orchestra/sidekick": "^1.1.0",
- "orchestra/testbench-core": "^10.2.1",
+ "orchestra/canvas": "^10.1.1",
+ "orchestra/sidekick": "^1.2.17",
+ "orchestra/testbench-core": "^10.8.0",
"php": "^8.2",
- "symfony/polyfill-php83": "^1.31",
+ "symfony/polyfill-php83": "^1.32",
"symfony/process": "^7.2",
"symfony/yaml": "^7.2"
},
"require-dev": {
- "laravel/pint": "^1.21.2",
+ "laravel/pint": "^1.22.0",
"mockery/mockery": "^1.6.12",
- "phpstan/phpstan": "^2.1.8",
+ "phpstan/phpstan": "^2.1.14",
"phpunit/phpunit": "^11.5.3|^12.0.1",
- "spatie/laravel-ray": "^1.40.1"
+ "spatie/laravel-ray": "^1.42.0"
},
"suggest": {
"ext-pcntl": "Required to use all features of the console signal trapping."
@@ -8476,9 +8521,9 @@
],
"support": {
"issues": "https://github.com/orchestral/workbench/issues",
- "source": "https://github.com/orchestral/workbench/tree/v10.0.6"
+ "source": "https://github.com/orchestral/workbench/tree/v10.0.7"
},
- "time": "2025-04-13T01:07:44+00:00"
+ "time": "2025-11-24T06:50:12+00:00"
},
{
"name": "pestphp/pest",
@@ -9190,16 +9235,16 @@
},
{
"name": "phpdocumentor/reflection-docblock",
- "version": "5.6.3",
+ "version": "5.6.5",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
- "reference": "94f8051919d1b0369a6bcc7931d679a511c03fe9"
+ "reference": "90614c73d3800e187615e2dd236ad0e2a01bf761"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94f8051919d1b0369a6bcc7931d679a511c03fe9",
- "reference": "94f8051919d1b0369a6bcc7931d679a511c03fe9",
+ "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/90614c73d3800e187615e2dd236ad0e2a01bf761",
+ "reference": "90614c73d3800e187615e2dd236ad0e2a01bf761",
"shasum": ""
},
"require": {
@@ -9248,22 +9293,22 @@
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
"support": {
"issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues",
- "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.3"
+ "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.5"
},
- "time": "2025-08-01T19:43:32+00:00"
+ "time": "2025-11-27T19:50:05+00:00"
},
{
"name": "phpdocumentor/type-resolver",
- "version": "1.10.0",
+ "version": "1.12.0",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/TypeResolver.git",
- "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a"
+ "reference": "92a98ada2b93d9b201a613cb5a33584dde25f195"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/679e3ce485b99e84c775d28e2e96fade9a7fb50a",
- "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a",
+ "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/92a98ada2b93d9b201a613cb5a33584dde25f195",
+ "reference": "92a98ada2b93d9b201a613cb5a33584dde25f195",
"shasum": ""
},
"require": {
@@ -9306,9 +9351,9 @@
"description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
"support": {
"issues": "https://github.com/phpDocumentor/TypeResolver/issues",
- "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.10.0"
+ "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.12.0"
},
- "time": "2024-11-09T15:12:26+00:00"
+ "time": "2025-11-21T15:09:14+00:00"
},
{
"name": "phpstan/phpdoc-parser",
@@ -10953,28 +10998,28 @@
},
{
"name": "symfony/yaml",
- "version": "v7.3.5",
+ "version": "v7.4.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
- "reference": "90208e2fc6f68f613eae7ca25a2458a931b1bacc"
+ "reference": "24dd4de28d2e3988b311751ac49e684d783e2345"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/yaml/zipball/90208e2fc6f68f613eae7ca25a2458a931b1bacc",
- "reference": "90208e2fc6f68f613eae7ca25a2458a931b1bacc",
+ "url": "https://api.github.com/repos/symfony/yaml/zipball/24dd4de28d2e3988b311751ac49e684d783e2345",
+ "reference": "24dd4de28d2e3988b311751ac49e684d783e2345",
"shasum": ""
},
"require": {
"php": ">=8.2",
- "symfony/deprecation-contracts": "^2.5|^3.0",
+ "symfony/deprecation-contracts": "^2.5|^3",
"symfony/polyfill-ctype": "^1.8"
},
"conflict": {
"symfony/console": "<6.4"
},
"require-dev": {
- "symfony/console": "^6.4|^7.0"
+ "symfony/console": "^6.4|^7.0|^8.0"
},
"bin": [
"Resources/bin/yaml-lint"
@@ -11005,7 +11050,7 @@
"description": "Loads and dumps YAML files",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/yaml/tree/v7.3.5"
+ "source": "https://github.com/symfony/yaml/tree/v7.4.1"
},
"funding": [
{
@@ -11025,7 +11070,7 @@
"type": "tidelift"
}
],
- "time": "2025-09-27T09:00:46+00:00"
+ "time": "2025-12-04T18:11:45+00:00"
},
{
"name": "ta-tikoma/phpunit-architecture-test",
@@ -11088,16 +11133,16 @@
},
{
"name": "theseer/tokenizer",
- "version": "1.2.3",
+ "version": "1.3.1",
"source": {
"type": "git",
"url": "https://github.com/theseer/tokenizer.git",
- "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2"
+ "reference": "b7489ce515e168639d17feec34b8847c326b0b3c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
- "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
+ "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b7489ce515e168639d17feec34b8847c326b0b3c",
+ "reference": "b7489ce515e168639d17feec34b8847c326b0b3c",
"shasum": ""
},
"require": {
@@ -11126,7 +11171,7 @@
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
"support": {
"issues": "https://github.com/theseer/tokenizer/issues",
- "source": "https://github.com/theseer/tokenizer/tree/1.2.3"
+ "source": "https://github.com/theseer/tokenizer/tree/1.3.1"
},
"funding": [
{
@@ -11134,7 +11179,7 @@
"type": "github"
}
],
- "time": "2024-03-03T12:36:25+00:00"
+ "time": "2025-11-17T20:03:58+00:00"
},
{
"name": "webmozart/assert",
diff --git a/config/app.php b/config/app.php
index 30d8e68..8e208bf 100644
--- a/config/app.php
+++ b/config/app.php
@@ -55,6 +55,19 @@ return [
'url' => env('APP_URL', 'https://localhost'),
'domain_name' => env('APP_DOMAIN_NAME', 'localhost'),
+ /*
+ |--------------------------------------------------------------------------
+ | Asset URL
+ |--------------------------------------------------------------------------
+ |
+ | This URL is used when generating asset URLs. By default, this is null
+ | which means assets will be served from the same domain. For multi-domain
+ | setups, this is dynamically overwritten by the ThemeServiceProvider.
+ |
+ */
+
+ 'asset_url' => env('ASSET_URL'),
+
/*
|--------------------------------------------------------------------------
| Application Timezone
diff --git a/config/cors.php b/config/cors.php
new file mode 100644
index 0000000..59cb236
--- /dev/null
+++ b/config/cors.php
@@ -0,0 +1,62 @@
+ ['api/*', 'sanctum/csrf-cookie', '@vite/*', '@fs/*', 'build/*'],
+
+ 'allowed_methods' => ['*'],
+
+ 'allowed_origins' => [
+ // Dynamisch alle konfigurierten Domains erlauben
+ env('DOMAIN_PORTAL_URL', 'https://portal.b2in.eu'),
+ env('DOMAIN_B2IN_URL', 'https://b2in.eu'),
+ env('DOMAIN_B2A_URL', 'https://bridges2america.online'),
+ env('DOMAIN_STILEIGENTUM_URL', 'https://stileigentum.de'),
+ env('DOMAIN_STYLE2OWN_URL', 'https://style2own.de'),
+ env('VITE_DEV_SERVER_URL', 'https://assets.b2in.eu'),
+ // HTTP-Varianten für Entwicklung
+ 'http://portal.b2in.test',
+ 'http://b2in.test',
+ 'http://b2a.test',
+ 'http://stileigentum.test',
+ 'http://style2own.test',
+ 'http://assets.b2in.test',
+ // Localhost für lokale Entwicklung
+ 'http://localhost:5174',
+ 'http://127.0.0.1:5174',
+ // Live Domains
+ 'https://portal.b2in.eu',
+ 'https://api.b2in.eu',
+ 'https://b2in.eu',
+ 'https://cabinet.b2in.eu', // Digital Signage Display
+ 'https://bridges2america.online',
+ 'https://stileigentum.de',
+ 'https://style2own.de',
+ ],
+
+ 'allowed_origins_patterns' => [
+ // Erlaube alle Subdomains von .b2in.eu für Produktion
+ '#^https?://.*\.b2in\.eu$#',
+ // Erlaube alle Subdomains von .test und .local für Entwicklung
+ '#^https?://.*\.b2in\.test$#',
+ '#^https?://.*\.test$#',
+ '#^https?://.*\.local$#',
+ ],
+
+ 'allowed_headers' => ['*'],
+
+ 'exposed_headers' => [],
+
+ 'max_age' => 0,
+
+ 'supports_credentials' => true,
+];
diff --git a/config/display.php b/config/display.php
new file mode 100644
index 0000000..9443e45
--- /dev/null
+++ b/config/display.php
@@ -0,0 +1,25 @@
+ env('DISPLAY_BASE_PATH', '_cabinet'),
+
+ // Subdomain für den Live-Server (optional)
+ // Wird verwendet, um die korrekte URL zu generieren
+ 'subdomain' => env('DISPLAY_SUBDOMAIN', null), // z.B. 'cabinet'
+
+ // Haupt-Domain
+ 'domain' => env('DISPLAY_DOMAIN', 'b2in.eu'),
+
+];
diff --git a/config/domains.php b/config/domains.php
index 395a29a..ee664ae 100644
--- a/config/domains.php
+++ b/config/domains.php
@@ -20,13 +20,25 @@ return [
*/
'protocol' => env('APP_PROTOCOL', 'https://'),
+ /*
+ |--------------------------------------------------------------------------
+ | Domain-Namen (ohne Protokoll)
+ |--------------------------------------------------------------------------
+ */
'domain_portal' => env('DOMAIN_PORTAL', 'portal.b2in.test'),
+ 'domain_api' => env('DOMAIN_API', 'api.b2in.test'),
'domain_b2in' => env('DOMAIN_B2IN', 'b2in.test'),
'domain_b2a' => env('DOMAIN_B2A', 'b2a.test'),
'domain_stileigentum' => env('DOMAIN_STILEIGENTUM', 'stileigentum.test'),
'domain_style2own' => env('DOMAIN_STYLE2OWN', 'style2own.test'),
+ /*
+ |--------------------------------------------------------------------------
+ | Vollständige Domain-URLs (mit Protokoll)
+ |--------------------------------------------------------------------------
+ */
'domain_portal_url' => env('DOMAIN_PORTAL_URL', 'https://portal.b2in.test'),
+ 'domain_api_url' => env('DOMAIN_API_URL', 'https://api.b2in.test'),
'domain_b2in_url' => env('DOMAIN_B2IN_URL', 'https://b2in.test'),
'domain_b2a_url' => env('DOMAIN_B2A_URL', 'https://b2a.test'),
'domain_stileigentum_url' => env('DOMAIN_STILEIGENTUM_URL', 'https://stileigentum.test'),
diff --git a/config/livewire.php b/config/livewire.php
index 8a4be98..294b7a4 100644
--- a/config/livewire.php
+++ b/config/livewire.php
@@ -69,22 +69,9 @@ return [
'directory' => null, // Example: 'tmp' | Default: 'livewire-tmp'
'middleware' => null, // Example: 'throttle:5,1' | Default: 'throttle:60,1'
'preview_mimes' => [ // Supported file types for temporary pre-signed file URLs...
- 'png',
- 'gif',
- 'bmp',
- 'svg',
- 'wav',
- 'mp4',
- 'mov',
- 'avi',
- 'wmv',
- 'mp3',
- 'm4a',
- 'jpg',
- 'jpeg',
- 'mpga',
- 'webp',
- 'wma',
+ 'png', 'gif', 'bmp', 'svg', 'wav', 'mp4',
+ 'mov', 'avi', 'wmv', 'mp3', 'm4a',
+ 'jpg', 'jpeg', 'mpga', 'webp', 'wma',
],
'max_upload_time' => 5, // Max duration (in minutes) before an upload is invalidated...
'cleanup' => true, // Should cleanup temporary uploads older than 24 hrs...
@@ -158,6 +145,19 @@ return [
'inject_morph_markers' => true,
+ /*
+ |---------------------------------------------------------------------------
+ | Smart Wire Keys
+ |---------------------------------------------------------------------------
+ |
+ | Livewire uses loops and keys used within loops to generate smart keys that
+ | are applied to nested components that don't have them. This makes using
+ | nested components more reliable by ensuring that they all have keys.
+ |
+ */
+
+ 'smart_wire_keys' => false,
+
/*
|---------------------------------------------------------------------------
| Pagination Theme
@@ -170,4 +170,17 @@ return [
*/
'pagination_theme' => 'tailwind',
+
+ /*
+ |---------------------------------------------------------------------------
+ | Release Token
+ |---------------------------------------------------------------------------
+ |
+ | This token is stored client-side and sent along with each request to check
+ | a users session to see if a new release has invalidated it. If there is
+ | a mismatch it will throw an error and prompt for a browser refresh.
+ |
+ */
+
+ 'release_token' => 'a',
];
diff --git a/database/migrations/2025_11_06_153241_create_brands_table.php b/database/migrations/2025_11_06_153241_create_brands_table.php
index 4820a9f..255469e 100644
--- a/database/migrations/2025_11_06_153241_create_brands_table.php
+++ b/database/migrations/2025_11_06_153241_create_brands_table.php
@@ -19,6 +19,7 @@ return new class extends Migration
$table->string('slug')->unique();
$table->string('logo_url')->nullable();
$table->text('description')->nullable();
+ $table->boolean('is_active')->default(true);
$table->timestamps();
});
}
diff --git a/database/migrations/2025_12_11_000001_create_registration_codes_table.php b/database/migrations/2025_12_11_000001_create_registration_codes_table.php
new file mode 100644
index 0000000..38019ce
--- /dev/null
+++ b/database/migrations/2025_12_11_000001_create_registration_codes_table.php
@@ -0,0 +1,33 @@
+id();
+ $table->string('code')->unique();
+ $table->string('role'); // broker|customer|retailer|manufacturer
+ $table->string('status')->default('available'); // available|used|expired
+ $table->foreignId('broker_partner_id')->nullable()->constrained('partners')->nullOnDelete();
+ $table->foreignId('partner_id')->nullable()->constrained('partners')->nullOnDelete();
+ $table->foreignId('used_by_user_id')->nullable()->constrained('users')->nullOnDelete();
+ $table->timestamp('used_at')->nullable();
+ $table->timestamp('expires_at')->nullable();
+ $table->json('metadata')->nullable();
+ $table->timestamps();
+
+ $table->index(['role', 'status']);
+ $table->index('broker_partner_id');
+ $table->index('partner_id');
+ });
+ }
+
+ public function down(): void
+ {
+ Schema::dropIfExists('registration_codes');
+ }
+};
diff --git a/database/migrations/2025_12_16_134959_add_name_and_assigned_to_code_id_to_registration_codes_table.php b/database/migrations/2025_12_16_134959_add_name_and_assigned_to_code_id_to_registration_codes_table.php
new file mode 100644
index 0000000..8a15790
--- /dev/null
+++ b/database/migrations/2025_12_16_134959_add_name_and_assigned_to_code_id_to_registration_codes_table.php
@@ -0,0 +1,30 @@
+string('name')->nullable()->after('role');
+ $table->foreignId('assigned_to_code_id')->nullable()->after('broker_partner_id')->constrained('registration_codes')->nullOnDelete();
+
+ // Indizes für bessere Performance
+ $table->index('name');
+ $table->index('assigned_to_code_id');
+ });
+ }
+
+ public function down(): void
+ {
+ Schema::table('registration_codes', function (Blueprint $table) {
+ $table->dropIndex(['name']);
+ $table->dropIndex(['assigned_to_code_id']);
+ $table->dropForeign(['assigned_to_code_id']);
+ $table->dropColumn(['name', 'assigned_to_code_id']);
+ });
+ }
+};
diff --git a/database/migrations/2025_12_16_135608_add_registration_fields_to_roles_table.php b/database/migrations/2025_12_16_135608_add_registration_fields_to_roles_table.php
new file mode 100644
index 0000000..9555da6
--- /dev/null
+++ b/database/migrations/2025_12_16_135608_add_registration_fields_to_roles_table.php
@@ -0,0 +1,28 @@
+string('reg_prefix', 1)->nullable()->after('can_be_invited');
+ $table->string('reg_description')->nullable()->after('reg_prefix');
+ $table->integer('reg_start_number')->nullable()->after('reg_description');
+
+ // Index für Prefix-Suche
+ $table->index('reg_prefix');
+ });
+ }
+
+ public function down(): void
+ {
+ Schema::table('roles', function (Blueprint $table) {
+ $table->dropIndex(['reg_prefix']);
+ $table->dropColumn(['reg_prefix', 'reg_description', 'reg_start_number']);
+ });
+ }
+};
diff --git a/database/migrations/2025_12_17_110248_add_display_name_to_users_table.php b/database/migrations/2025_12_17_110248_add_display_name_to_users_table.php
new file mode 100644
index 0000000..1fc736f
--- /dev/null
+++ b/database/migrations/2025_12_17_110248_add_display_name_to_users_table.php
@@ -0,0 +1,31 @@
+string('display_name')->nullable()->after('name');
+ $table->index('display_name');
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::table('users', function (Blueprint $table) {
+ $table->dropIndex(['display_name']);
+ $table->dropColumn('display_name');
+ });
+ }
+};
diff --git a/database/migrations/2025_12_17_123210_add_broker_partner_id_to_partners_table.php b/database/migrations/2025_12_17_123210_add_broker_partner_id_to_partners_table.php
new file mode 100644
index 0000000..47eaa8f
--- /dev/null
+++ b/database/migrations/2025_12_17_123210_add_broker_partner_id_to_partners_table.php
@@ -0,0 +1,41 @@
+foreignId('broker_partner_id')
+ ->nullable()
+ ->after('hub_id')
+ ->constrained('partners')
+ ->nullOnDelete();
+
+ $table->index('broker_partner_id');
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::table('partners', function (Blueprint $table) {
+ $table->dropIndex(['broker_partner_id']);
+ $table->dropForeign(['broker_partner_id']);
+ $table->dropColumn('broker_partner_id');
+ });
+ }
+};
diff --git a/database/migrations/2025_12_17_123422_rename_broker_partner_id_to_parent_partner_id_in_partners_table.php b/database/migrations/2025_12_17_123422_rename_broker_partner_id_to_parent_partner_id_in_partners_table.php
new file mode 100644
index 0000000..1870a92
--- /dev/null
+++ b/database/migrations/2025_12_17_123422_rename_broker_partner_id_to_parent_partner_id_in_partners_table.php
@@ -0,0 +1,30 @@
+renameColumn('broker_partner_id', 'parent_partner_id');
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::table('partners', function (Blueprint $table) {
+ $table->renameColumn('parent_partner_id', 'broker_partner_id');
+ });
+ }
+};
diff --git a/database/migrations/2025_12_17_132845_add_brand_to_partners_table.php b/database/migrations/2025_12_17_132845_add_brand_to_partners_table.php
new file mode 100644
index 0000000..97f756e
--- /dev/null
+++ b/database/migrations/2025_12_17_132845_add_brand_to_partners_table.php
@@ -0,0 +1,33 @@
+string('brand')->nullable()->after('type');
+
+ $table->index('brand');
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::table('partners', function (Blueprint $table) {
+ $table->dropIndex(['brand']);
+ $table->dropColumn('brand');
+ });
+ }
+};
diff --git a/database/migrations/2025_12_17_135808_add_address_fields_to_partners_table.php b/database/migrations/2025_12_17_135808_add_address_fields_to_partners_table.php
new file mode 100644
index 0000000..6b7837d
--- /dev/null
+++ b/database/migrations/2025_12_17_135808_add_address_fields_to_partners_table.php
@@ -0,0 +1,53 @@
+string('salutation')->nullable()->after('brand'); // Herr, Frau, Divers
+ $table->string('first_name')->nullable()->after('salutation');
+ $table->string('last_name')->nullable()->after('first_name');
+ $table->string('street')->nullable()->after('description');
+ $table->string('house_number')->nullable()->after('street');
+ $table->string('zip')->nullable()->after('house_number');
+ $table->string('city')->nullable()->after('zip');
+ $table->string('country')->default('Deutschland')->after('city');
+ $table->string('phone')->nullable()->after('country');
+ $table->string('website')->nullable()->after('phone');
+
+ // Display Name für Broker (kann vom Firmennamen abweichen)
+ $table->string('display_name')->nullable()->after('company_name');
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::table('partners', function (Blueprint $table) {
+ $table->dropColumn([
+ 'salutation',
+ 'first_name',
+ 'last_name',
+ 'street',
+ 'house_number',
+ 'zip',
+ 'city',
+ 'country',
+ 'phone',
+ 'website',
+ 'display_name',
+ ]);
+ });
+ }
+};
diff --git a/database/migrations/2025_12_18_080601_add_soft_deletes_to_users_table.php b/database/migrations/2025_12_18_080601_add_soft_deletes_to_users_table.php
new file mode 100644
index 0000000..a7bda58
--- /dev/null
+++ b/database/migrations/2025_12_18_080601_add_soft_deletes_to_users_table.php
@@ -0,0 +1,28 @@
+softDeletes();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::table('users', function (Blueprint $table) {
+ $table->dropSoftDeletes();
+ });
+ }
+};
diff --git a/database/migrations/2025_12_18_105009_add_partner_id_to_brands_table.php b/database/migrations/2025_12_18_105009_add_partner_id_to_brands_table.php
new file mode 100644
index 0000000..8b8713d
--- /dev/null
+++ b/database/migrations/2025_12_18_105009_add_partner_id_to_brands_table.php
@@ -0,0 +1,29 @@
+foreignId('partner_id')->after('id')->nullable()->constrained('partners')->nullOnDelete();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::table('brands', function (Blueprint $table) {
+ $table->dropForeign(['partner_id']);
+ $table->dropColumn('partner_id');
+ });
+ }
+};
diff --git a/database/migrations/2025_12_18_131551_create_display_videos_table.php b/database/migrations/2025_12_18_131551_create_display_videos_table.php
new file mode 100644
index 0000000..2273cb8
--- /dev/null
+++ b/database/migrations/2025_12_18_131551_create_display_videos_table.php
@@ -0,0 +1,32 @@
+id();
+ $table->string('filename'); // Dateiname des Videos (z.B. herbst_2025.mp4)
+ $table->string('title')->nullable(); // Optionaler Titel für bessere Verwaltung
+ $table->integer('position')->default(25); // Position in % (0-100)
+ $table->integer('sort_order')->default(0); // Reihenfolge der Wiedergabe
+ $table->boolean('is_active')->default(true); // Aktiv/Inaktiv
+ $table->timestamps();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::dropIfExists('display_videos');
+ }
+};
diff --git a/database/migrations/2025_12_18_131552_create_display_footer_contents_table.php b/database/migrations/2025_12_18_131552_create_display_footer_contents_table.php
new file mode 100644
index 0000000..550c56f
--- /dev/null
+++ b/database/migrations/2025_12_18_131552_create_display_footer_contents_table.php
@@ -0,0 +1,32 @@
+id();
+ $table->string('headline'); // Überschrift (z.B. "Beratung & Termin")
+ $table->string('subline'); // Unterzeile (z.B. "Jetzt Termin vereinbaren.")
+ $table->string('url'); // URL für den QR-Code
+ $table->integer('sort_order')->default(0); // Reihenfolge der Anzeige
+ $table->boolean('is_active')->default(true); // Aktiv/Inaktiv
+ $table->timestamps();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::dropIfExists('display_footer_contents');
+ }
+};
diff --git a/database/migrations/2025_12_18_134623_add_short_code_and_clicks_to_display_footer_contents.php b/database/migrations/2025_12_18_134623_add_short_code_and_clicks_to_display_footer_contents.php
new file mode 100644
index 0000000..1cfebec
--- /dev/null
+++ b/database/migrations/2025_12_18_134623_add_short_code_and_clicks_to_display_footer_contents.php
@@ -0,0 +1,29 @@
+string('short_code', 10)->unique()->nullable()->after('url');
+ $table->unsignedInteger('clicks')->default(0)->after('short_code');
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::table('display_footer_contents', function (Blueprint $table) {
+ $table->dropColumn(['short_code', 'clicks']);
+ });
+ }
+};
diff --git a/database/migrations/2025_12_18_140712_make_url_nullable_in_display_footer_contents.php b/database/migrations/2025_12_18_140712_make_url_nullable_in_display_footer_contents.php
new file mode 100644
index 0000000..399caf0
--- /dev/null
+++ b/database/migrations/2025_12_18_140712_make_url_nullable_in_display_footer_contents.php
@@ -0,0 +1,30 @@
+string('url')->nullable()->change();
+ $table->string('short_code', 10)->nullable()->change();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::table('display_footer_contents', function (Blueprint $table) {
+ $table->string('url')->nullable(false)->change();
+ $table->string('short_code', 10)->nullable(false)->change();
+ });
+ }
+};
diff --git a/database/seeders/DisplayContentSeeder.php b/database/seeders/DisplayContentSeeder.php
new file mode 100644
index 0000000..796d1ab
--- /dev/null
+++ b/database/seeders/DisplayContentSeeder.php
@@ -0,0 +1,68 @@
+ 'herbst_2025.mp4', 'title' => 'Herbst 2025', 'position' => 25, 'sort_order' => 0],
+ ['filename' => 'fruehjahr_2025.mp4', 'title' => 'Frühjahr 2025', 'position' => 10, 'sort_order' => 1],
+ ['filename' => 'fruehjahr_2024.mp4', 'title' => 'Frühjahr 2024', 'position' => 25, 'sort_order' => 2],
+ ['filename' => 'herbst_2024.mp4', 'title' => 'Herbst 2024', 'position' => 25, 'sort_order' => 3],
+ ];
+
+ foreach ($videos as $video) {
+ DisplayVideo::create($video);
+ }
+
+ // Footer-Inhalte aus der bestehenden Konfiguration
+ $footerContents = [
+ [
+ 'headline' => 'Beratung & Termin',
+ 'subline' => 'Jetzt Termin vereinbaren.',
+ 'url' => 'https://www.cabinet.de/bielefeld?utm_source=store_display&utm_medium=qr_code&utm_campaign=bielefeld_pos&utm_content=termin_buchung#c39393',
+ 'sort_order' => 0,
+ ],
+ [
+ 'headline' => 'Beratung vor Ort',
+ 'subline' => 'Einfach reinkommen.',
+ 'url' => 'https://www.cabinet.de/bielefeld?utm_source=store_display&utm_medium=qr_code&utm_campaign=bielefeld_pos&utm_content=termin_buchung#c39393',
+ 'sort_order' => 1,
+ ],
+ [
+ 'headline' => 'Pinterest',
+ 'subline' => 'Inspirationen entdecken.',
+ 'url' => 'https://de.pinterest.com/cabinet_AG/',
+ 'sort_order' => 2,
+ ],
+ [
+ 'headline' => 'Instagram',
+ 'subline' => 'Tägliche Einblicke & Design.',
+ 'url' => 'https://www.instagram.com/cabinet_schranksysteme/',
+ 'sort_order' => 3,
+ ],
+ [
+ 'headline' => 'Facebook',
+ 'subline' => 'News, Aktionen & Community.',
+ 'url' => 'https://de-de.facebook.com/cabinetschranksysteme/',
+ 'sort_order' => 4,
+ ],
+ ];
+
+ foreach ($footerContents as $content) {
+ DisplayFooterContent::create($content);
+ }
+
+ $this->command->info('Display-Inhalte erfolgreich eingefügt!');
+ }
+}
diff --git a/database/seeders/RoleSeeder.php b/database/seeders/RoleSeeder.php
index 1581007..fa6a729 100644
--- a/database/seeders/RoleSeeder.php
+++ b/database/seeders/RoleSeeder.php
@@ -65,7 +65,10 @@ class RoleSeeder extends Seeder
'display_name' => 'Customer (Kunde)',
'icon' => 'user',
'color' => 'indigo',
- 'can_be_invited' => true
+ 'can_be_invited' => true,
+ 'reg_prefix' => 'K',
+ 'reg_description' => 'Kundencodes werden Maklern oder Händlern zugeordnet',
+ 'reg_start_number' => 10000000,
]);
$customerRole->givePermissionTo([
'view products',
@@ -79,7 +82,10 @@ class RoleSeeder extends Seeder
'display_name' => 'Estate-Agent (Makler)',
'icon' => 'home',
'color' => 'lime',
- 'can_be_invited' => true
+ 'can_be_invited' => true,
+ 'reg_prefix' => 'M',
+ 'reg_description' => 'Maklercodes für die Registrierung von Maklern',
+ 'reg_start_number' => 10000000,
]);
$estateAgentRole->givePermissionTo([
'access dashboard',
@@ -94,7 +100,10 @@ class RoleSeeder extends Seeder
'display_name' => 'Retailer (Händler)',
'icon' => 'building-storefront',
'color' => 'teal',
- 'can_be_invited' => true
+ 'can_be_invited' => true,
+ 'reg_prefix' => 'H',
+ 'reg_description' => 'Händlercodes für die Registrierung von Händlern',
+ 'reg_start_number' => 10000000,
]);
$retailerRole->givePermissionTo([
'access dashboard',
@@ -113,7 +122,10 @@ class RoleSeeder extends Seeder
'display_name' => 'Manufacturer (Hersteller)',
'icon' => 'wrench-screwdriver',
'color' => 'orange',
- 'can_be_invited' => true
+ 'can_be_invited' => true,
+ 'reg_prefix' => 'P',
+ 'reg_description' => 'Herstellercodes für die Registrierung von Herstellern',
+ 'reg_start_number' => 10000000,
]);
$manufacturerRole->givePermissionTo([
'access dashboard',
diff --git a/COMPONENT-STRUCTURE.md b/dev/COMPONENT-STRUCTURE.md
similarity index 100%
rename from COMPONENT-STRUCTURE.md
rename to dev/COMPONENT-STRUCTURE.md
diff --git a/dev/DISPLAY_CMS_README.md b/dev/DISPLAY_CMS_README.md
new file mode 100644
index 0000000..7edb1dd
--- /dev/null
+++ b/dev/DISPLAY_CMS_README.md
@@ -0,0 +1,319 @@
+# Cabinet Display CMS - Dokumentation
+
+## Übersicht
+
+Das Display CMS ermöglicht die zentrale Verwaltung der Inhalte für die Digital Signage Display-Seite im Cabinet Showroom Bielefeld.
+
+**Einheitlicher Pfad:** Das System nutzt `public/_cabinet/` für Testserver und Live-Server.
+
+## Zugriff
+
+### Testserver
+- **Display:** `http://portal.b2in.test/_cabinet/`
+- **CMS:** `http://portal.b2in.test/admin/cms/cabinet`
+- **API:** `http://portal.b2in.test/api/display/config`
+
+### Live-Server
+- **Display:** `https://cabinet.b2in.eu/` (Subdomain zeigt auf `/_cabinet/`)
+- **CMS:** `https://b2in.eu/admin/cms/cabinet`
+- **API:** `https://b2in.eu/api/display/config`
+
+## Funktionen
+
+### 1. Video-Verwaltung
+- ✅ Videos aus dem `public/_cabinet/assets/` Ordner verwalten
+- ✅ Reihenfolge per Pfeiltasten ändern
+- ✅ Video-Position (0-100%) für optimalen Bildausschnitt einstellen
+- ✅ Videos aktivieren/deaktivieren
+- ✅ Titel für bessere Übersicht vergeben
+
+### 2. Footer-Content-Verwaltung mit Tracking
+- ✅ Überschrift, Unterzeile und **optional** Ziel-URL eingeben
+- ✅ **Automatische Short-Link-Generierung** (nur wenn URL angegeben)
+- ✅ **Echtzeit-Klick-Tracking** über Short-Links
+- ✅ **Klick-Statistiken** direkt im CMS
+- ✅ **Ohne URL:** Nur Text wird angezeigt, kein QR-Code
+- ✅ **Mit URL:** QR-Code mit Short-Link wird automatisch generiert
+- ✅ Reihenfolge ändern (werden alle 30 Sekunden rotiert)
+- ✅ Inhalte aktivieren/deaktivieren
+- ✅ Short-Code neu generieren
+- ✅ Klick-Zähler zurücksetzen
+
+### 3. Short-Link-System
+
+#### Wie funktioniert es?
+
+**Mit URL (QR-Code wird angezeigt):**
+1. **Beim Erstellen** mit URL wird automatisch ein 6-stelliger Short-Code generiert (z.B. `c59kjb`)
+2. **Short-URL** wird automatisch erstellt:
+ - Testserver: `http://portal.b2in.test/_cabinet/go.php?z=c59kjb`
+ - Live-Server: `https://cabinet.b2in.eu/go.php?z=c59kjb`
+3. **QR-Code** auf dem Display zeigt die Short-URL
+4. **Bei Klick** wird der User zur Original-URL weitergeleitet
+5. **Klicks werden gezählt** und im CMS angezeigt
+
+**Ohne URL (nur Text):**
+1. **Beim Erstellen** ohne URL wird kein Short-Code generiert
+2. **Nur Text** wird im Footer angezeigt (Überschrift + Unterzeile)
+3. **Kein QR-Code** wird angezeigt
+4. **Text-Bereich** nutzt die volle Breite des Footers
+
+#### Vorteile
+
+- ✅ Kürzere URLs für bessere QR-Codes
+- ✅ Automatisches Tracking aller Scans
+- ✅ Zentrale Verwaltung aller Links
+- ✅ Statistiken direkt im CMS
+- ✅ Links können geändert werden ohne QR-Code neu zu generieren
+- ✅ Funktioniert identisch auf Test- und Live-Server
+
+## CMS-Interface
+
+### Video-Playlist
+
+```
+┌─────────────────────────────────────────────┐
+│ Video-Playlist [+] │
+├─────────────────────────────────────────────┤
+│ ↑↓ [Aktiv] Herbst 2025 │
+│ 📁 herbst_2025.mp4 📍 Position: 25% │
+│ [👁] [✏] [🗑] │
+├─────────────────────────────────────────────┤
+│ ↑↓ [Aktiv] Frühjahr 2025 │
+│ 📁 fruehjahr_2025.mp4 📍 Position: 10% │
+│ [👁] [✏] [🗑] │
+└─────────────────────────────────────────────┘
+```
+
+### Footer-Inhalte
+
+```
+┌─────────────────────────────────────────────┐
+│ Footer-Inhalte [+] │
+│ 📊 Gesamt-Klicks: 47 │
+├─────────────────────────────────────────────┤
+│ ↑↓ [Aktiv] Beratung & Termin [🔵 23 Klicks]│
+│ Jetzt Termin vereinbaren. │
+│ 🔗 c59kjb [📋 Short-Link] │
+│ 🔗 https://www.cabinet.de/bielefeld... │
+│ [👁] [⋮] │
+│ ├─ Bearbeiten │
+│ ├─ Short-Code neu generieren │
+│ ├─ Klicks zurücksetzen │
+│ └─ Löschen │
+└─────────────────────────────────────────────┘
+```
+
+## Technische Details
+
+### Ordnerstruktur
+
+```
+public/_cabinet/
+├── index.html # Display-Seite (lädt dynamisch via API)
+├── go.php # Short-Link-Handler mit Tracking
+├── assets/ # Video-Dateien
+│ ├── herbst_2025.mp4
+│ ├── fruehjahr_2025.mp4
+│ └── ...
+└── clicks.log # Tracking-Log (wird automatisch erstellt)
+```
+
+### Datenbank-Tabellen
+
+#### `display_videos`
+```sql
+- id (PK)
+- filename -- Dateiname des Videos
+- title -- Optionaler Titel
+- position -- Vertikale Position (0-100%)
+- sort_order -- Reihenfolge der Wiedergabe
+- is_active -- Aktiv/Inaktiv
+- created_at, updated_at
+```
+
+#### `display_footer_contents`
+```sql
+- id (PK)
+- headline -- Überschrift
+- subline -- Unterzeile
+- url -- Original-Ziel-URL
+- short_code -- 6-stelliger eindeutiger Code
+- clicks -- Anzahl der Klicks
+- sort_order -- Reihenfolge der Anzeige
+- is_active -- Aktiv/Inaktiv
+- created_at, updated_at
+```
+
+### Konfiguration
+
+**Datei:** `config/display.php`
+
+```php
+'base_path' => env('DISPLAY_BASE_PATH', '_cabinet'),
+'subdomain' => env('DISPLAY_SUBDOMAIN', null),
+'domain' => env('DISPLAY_DOMAIN', 'b2in.eu'),
+```
+
+**Umgebungsvariablen (.env):**
+
+```env
+# Testserver
+DISPLAY_BASE_PATH=_cabinet
+DISPLAY_SUBDOMAIN=
+DISPLAY_DOMAIN=b2in.test
+
+# Live-Server
+DISPLAY_BASE_PATH=_cabinet
+DISPLAY_SUBDOMAIN=cabinet
+DISPLAY_DOMAIN=b2in.eu
+APP_ENV=production
+```
+
+### API-Response-Format
+
+**Endpunkt:** `/api/display/config`
+
+```json
+{
+ "videoPlaylist": [
+ {
+ "src": "assets/herbst_2025.mp4",
+ "position": 25
+ }
+ ],
+ "footerContent": [
+ {
+ "headline": "Beratung & Termin",
+ "subline": "Jetzt Termin vereinbaren.",
+ "url": "https://cabinet.b2in.eu/go.php?z=c59kjb"
+ }
+ ]
+}
+```
+
+## Workflow-Beispiele
+
+### Neuen Footer-Inhalt hinzufügen
+
+1. Im CMS auf **"Inhalt hinzufügen"** klicken
+2. Formular ausfüllen:
+ - Überschrift: "Beratung & Termin"
+ - Unterzeile: "Jetzt Termin vereinbaren."
+ - URL: `https://www.cabinet.de/bielefeld?utm_source=...`
+3. **Speichern**
+4. ✅ Short-Code wird automatisch generiert (z.B. `c59kjb`)
+5. ✅ Short-URL wird erstellt: `https://cabinet.b2in.eu/go.php?z=c59kjb`
+6. ✅ Display lädt neue Konfiguration (max. 5 Minuten)
+7. ✅ QR-Code zeigt automatisch den Short-Link
+8. ✅ Klicks werden gezählt und angezeigt
+
+### Video hinzufügen
+
+1. Video-Datei in `public/_cabinet/assets/` hochladen
+2. Im CMS auf **"Video hinzufügen"** klicken
+3. Video aus Dropdown auswählen
+4. Titel vergeben (optional)
+5. Position einstellen (0-100%)
+6. **Speichern**
+7. ✅ Video wird zur Playlist hinzugefügt
+8. ✅ Display spielt Video ab
+
+### Klick-Statistiken ansehen
+
+1. Im CMS unter **"Footer-Inhalte"** öffnen
+2. Bei jedem Inhalt wird die Anzahl der Klicks angezeigt
+3. **Gesamt-Klicks** werden oben summiert angezeigt
+4. Zum Zurücksetzen: **⋮ → Klicks zurücksetzen**
+
+### Short-Code neu generieren
+
+1. Bei gewünschtem Footer-Inhalt auf **⋮** klicken
+2. **"Short-Code neu generieren"** wählen
+3. ✅ Neuer Code wird erstellt
+4. ⚠️ Alter Code funktioniert nicht mehr
+5. ✅ QR-Code aktualisiert sich automatisch beim nächsten Reload
+
+## Logging
+
+### Datenbank-Tracking (Primär)
+- Alle Klicks werden in der Datenbank gezählt
+- Echtzeit-Statistiken im CMS
+- Auswertungen nach Inhalt möglich
+
+### Datei-Logging (Backup)
+- Zusätzliches Log: `public/_cabinet/clicks.log`
+- Format: `YYYY-MM-DD HH:MM:SS - Code: c59kjb - Headline: ... - URL: ...`
+- Nützlich für detaillierte Analysen
+
+**Log ansehen:**
+```bash
+tail -f public/_cabinet/clicks.log
+```
+
+## Wartung & Backup
+
+### Wichtige Daten für Backup
+- **Datenbank:** `display_videos`, `display_footer_contents`
+- **Video-Dateien:** `public/_cabinet/assets/`
+- **Tracking-Log:** `public/_cabinet/clicks.log`
+
+### Videos hinzufügen
+```bash
+# Upload via SCP
+scp video.mp4 user@server:/var/www/html/public/_cabinet/assets/
+
+# Oder via FTP/SFTP
+# Dann im CMS hinzufügen
+```
+
+### Cache leeren
+```bash
+php artisan config:clear
+php artisan cache:clear
+php artisan route:clear
+```
+
+## Troubleshooting
+
+### Display zeigt "LADEN..."
+**Problem:** API nicht erreichbar
+**Lösung:** Browser-Console (F12) prüfen, API-URL testen
+
+### Short-Links funktionieren nicht
+**Problem:** Datenbankverbindung oder Berechtigungen
+**Lösung:** `go.php` Berechtigungen prüfen, Logs prüfen
+
+### Klicks werden nicht gezählt
+**Problem:** Datenbankupdate fehlgeschlagen
+**Lösung:** `clicks.log` prüfen, Datenbank-Logs prüfen
+
+### Videos werden nicht abgespielt
+**Problem:** Falsches Format oder Pfad
+**Lösung:** Browser-Console prüfen, `.mp4` mit H.264 verwenden
+
+## Performance-Tipps
+
+### Video-Optimierung
+```bash
+# FFmpeg für kleinere Dateien
+ffmpeg -i input.mp4 -c:v libx264 -crf 23 \
+ -preset medium -c:a aac -b:a 128k output.mp4
+```
+
+### Auto-Reload
+- Display lädt alle 5 Minuten neue Konfiguration
+- Für sofortiges Update: Display-Seite neu laden
+
+## Support & Dokumentation
+
+- **Setup-Guide:** `DISPLAY_SETUP_LIVE.md`
+- **ENV-Variablen:** `ENV_VARIABLES_DISPLAY.md`
+- **Laravel-Logs:** `storage/logs/laravel.log`
+- **Tracking-Log:** `public/_cabinet/clicks.log`
+
+Bei Problemen:
+1. Logs prüfen
+2. Browser-Console prüfen
+3. API manuell testen
+4. Cache leeren
diff --git a/dev/DISPLAY_SETUP_LIVE.md b/dev/DISPLAY_SETUP_LIVE.md
new file mode 100644
index 0000000..790c53e
--- /dev/null
+++ b/dev/DISPLAY_SETUP_LIVE.md
@@ -0,0 +1,295 @@
+# Display Setup für Live-Server (cabinet.b2in.eu)
+
+## Übersicht
+
+Das Display-System nutzt den Ordner `public/_cabinet/` für beide Umgebungen:
+
+- **Testserver:** `portal.b2in.test/_cabinet/`
+- **Live-Server:** `cabinet.b2in.eu/` (Subdomain zeigt direkt auf `public/_cabinet/`)
+
+## Setup-Schritte für Live-Server
+
+### 1. Dateien vorbereiten
+
+Die Dateien sind bereits im Ordner `public/_cabinet/` vorhanden:
+
+```bash
+public/_cabinet/
+├── index.html # Display-Seite
+├── go.php # Short-Link-Handler
+├── assets/ # Video-Dateien
+│ ├── herbst_2025.mp4
+│ ├── fruehjahr_2025.mp4
+│ └── ...
+└── clicks.log # Tracking-Log (wird automatisch erstellt)
+```
+
+### 2. Subdomain konfigurieren
+
+Auf dem Live-Server die Subdomain `cabinet.b2in.eu` so einrichten, dass sie direkt auf `/public/_cabinet/` zeigt.
+
+**Apache VirtualHost Beispiel:**
+
+```apache
+
Bitte wähle eine Log-Datei aus dem Dropdown-Menü.
+ +⚠️ Keine Log-Dateien gefunden. Stelle sicher, dass das Logging aktiv ist und das Verzeichnis 'logs/' existiert.
+ +