23-01-2026

This commit is contained in:
Kevin Adametz 2026-01-23 17:33:10 +01:00
parent 07959c0ba2
commit 854ce02bf6
166 changed files with 32909 additions and 1262 deletions

View file

@ -8,15 +8,13 @@ use Livewire\Volt\Volt;
// Admin-Dashboard
Route::get('/', function () {
return redirect()->route('dashboard');
})->name('home');
})->name('admin.home');
// Partner Setup Wizard (muss vor anderen auth-Routes sein, um keine Middleware zu bekommen)
Route::middleware(['auth'])->group(function () {
Volt::route('partner/setup', 'partner.setup-wizard')
->name('partner.setup.wizard');
});
// Partner Setup Wizard wird in routes/web.php definiert
Route::view('dashboard', 'admin.dashboard')->middleware(['auth', 'verified', 'partner.setup'])->name('dashboard');
Volt::route('/partner/my-data', 'partner.my-data')
->name('partner.my-data');
// Admin-Einstellungen
Route::middleware(['auth', 'partner.setup'])->group(function () {
@ -26,6 +24,24 @@ Route::middleware(['auth', 'partner.setup'])->group(function () {
Volt::route('settings/password', 'settings.password')->name('settings.password');
Volt::route('settings/appearance', 'settings.appearance')->name('settings.appearance');
// Impersonation
Route::post('admin/impersonate/leave', function () {
$adminUserId = session('impersonate_from');
if ($adminUserId) {
$adminUser = \App\Models\User::find($adminUserId);
if ($adminUser) {
session()->forget('impersonate_from');
\Illuminate\Support\Facades\Auth::login($adminUser);
return redirect()->route('admin.users')->with('message', __('Erfolgreich zurück zum Admin-Account.'));
}
}
return redirect()->route('dashboard');
})->name('admin.impersonate.leave');
// Weitere Admin-Routen hier...
// User Management
@ -35,6 +51,32 @@ Route::middleware(['auth', 'partner.setup'])->group(function () {
// Partner Management
Volt::route('admin/partners/invite', 'admin.partners.invite')->name('admin.partners.invite');
Volt::route('admin/partners/registration-codes', 'admin.partners.registration-codes')->name('admin.partners.registration-codes');
// Testing
Volt::route('testing/registration', 'admin.testing.registration-tester')->name('testing.landing');
// CMS Routes
Route::get('admin/cms/cabinet', \App\Livewire\Admin\CMS\CabinetDisplay::class)->name('admin.cms.cabinet');
// Product Routes
Volt::route('products', 'products.index')->name('products.index');
Volt::route('products/create', 'products.create')->name('products.create');
// Hub Management
Volt::route('admin/hubs', 'admin.hubs.index')->name('admin.hubs.index');
Volt::route('admin/hubs/create', 'admin.hubs.manage')->name('admin.hubs.create');
Volt::route('admin/hubs/{hubId}/edit', 'admin.hubs.manage')->name('admin.hubs.edit');
// Documentation
Volt::route('admin/documentation', 'admin.documentation')->name('admin.documentation');
Route::get('admin/documentation/download', function () {
$mdPath = base_path('dev/entwicklung.md');
if (!file_exists($mdPath)) {
abort(404);
}
return response()->download($mdPath, 'b2in-entwicklung.md');
})->name('admin.documentation.download');
});
// Admin-Authentication wird bereits in domains.php geladen

View file

@ -56,3 +56,6 @@ Route::post('/login', function (Request $request) {
'message' => 'Ungültige Anmeldedaten',
], 401);
});
// Display-Konfiguration für Cabinet Display
Route::get('/display/config', [\App\Http\Controllers\Api\DisplayConfigController::class, 'index']);

View file

@ -30,6 +30,45 @@ Route::group(['middleware' => config('fortify.middleware', ['web'])], function (
->middleware(['auth:' . config('fortify.guard')])
->name('verification.notice');
// E-Mail-Verifizierung durchführen (ohne Login - verifiziert und loggt User ein)
Route::get('/email/verify/{id}/{hash}', function (Illuminate\Http\Request $request, $id, $hash) {
// Ablaufzeit prüfen
$expires = $request->query('expires');
if ($expires && time() > $expires) {
return redirect()->route('login')
->withErrors(['email' => __('Der Verifizierungslink ist abgelaufen. Bitte fordern Sie einen neuen an.')]);
}
// User finden
$user = \App\Models\User::findOrFail($id);
// Hash überprüfen (E-Mail-Hash)
if (!hash_equals($hash, sha1($user->getEmailForVerification()))) {
abort(403, __('Ungültiger Verifizierungslink.'));
}
// E-Mail verifizieren (falls noch nicht verifiziert)
if (!$user->hasVerifiedEmail()) {
$user->markEmailAsVerified();
// Event auslösen (für Listeners)
event(new \Illuminate\Auth\Events\Verified($user));
}
// User einloggen
\Illuminate\Support\Facades\Auth::login($user);
return redirect()->route('partner.setup.wizard')
->with('message', __('E-Mail erfolgreich verifiziert! Willkommen! Bitte schließen Sie Ihr Setup ab.'));
})->name('verification.verify');
// E-Mail-Verifizierung erneut senden
Route::post('/email/verification-notification', function (Illuminate\Http\Request $request) {
$request->user()->sendEmailVerificationNotification();
return back()->with('message', __('Verifizierungslink wurde erneut gesendet!'));
})->middleware(['auth:' . config('fortify.guard'), 'throttle:6,1'])->name('verification.send');
// Passwort bestätigen mit Livewire
Volt::route('/confirm-password', 'auth.confirm-password')
->middleware(['auth:' . config('fortify.guard')])
@ -37,5 +76,5 @@ Route::group(['middleware' => config('fortify.middleware', ['web'])], function (
// Logout-Route
Route::post('/logout', [Laravel\Fortify\Http\Controllers\AuthenticatedSessionController::class, 'destroy'])
->name('logout');
->name('auth.logout');
});

View file

@ -3,8 +3,30 @@
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Vite;
// Admin-Bereich auf portal.b2in.local
Route::domain('portal.b2in.test')->group(function () {
/*
|--------------------------------------------------------------------------
| Domain-Konfiguration aus config/domains.php laden
|--------------------------------------------------------------------------
|
| Die Domains werden dynamisch aus der Konfiguration geladen.
| In .env können die Live-Domains definiert werden:
|
| DOMAIN_PORTAL=portal.beispiel.de
| DOMAIN_B2IN=b2in.de
| DOMAIN_B2A=b2a.de
| DOMAIN_STILEIGENTUM=stileigentum.de
| DOMAIN_STYLE2OWN=style2own.de
|
*/
$domainPortal = config('domains.domain_portal', 'portal.b2in.test');
$domainB2in = config('domains.domain_b2in', 'b2in.test');
$domainB2a = config('domains.domain_b2a', 'b2a.test');
$domainStileigentum = config('domains.domain_stileigentum', 'stileigentum.test');
$domainStyle2own = config('domains.domain_style2own', 'style2own.test');
// Admin-Bereich (Portal)
Route::domain($domainPortal)->group(function () {
// Auth-Routen laden
require __DIR__ . '/auth.php';
@ -14,48 +36,44 @@ Route::domain('portal.b2in.test')->group(function () {
// Test-Route laden
require __DIR__ . '/test.php';
// Display-API-Route (öffentlich zugänglich)
Route::get('/api/display/config', [\App\Http\Controllers\Api\DisplayConfigController::class, 'index']);
// FluxUI Asset-Routen explizit für Portal-Domain registrieren
// (Notwendig weil Route-Cache die globalen Flux-Routen nicht für alle Domains enthält)
Route::get('/flux/flux.js', [\Flux\AssetManager::class, 'fluxJs']);
Route::get('/flux/flux.min.js', [\Flux\AssetManager::class, 'fluxMinJs']);
Route::get('/flux/editor.css', [\Flux\AssetManager::class, 'editorCss']);
Route::get('/flux/editor.js', [\Flux\AssetManager::class, 'editorJs']);
Route::get('/flux/editor.min.js', [\Flux\AssetManager::class, 'editorMinJs']);
// Admin-Assets (Vite)
Vite::useBuildDirectory('build/admin');
Vite::useBuildDirectory('build/portal');
});
// API-Routen für alle Domains
Route::domain('api.b2in.test')->group(function () {
// API-Routen für alle Domains (optional: auch dynamisch machen)
Route::domain(config('domains.domain_api', 'api.b2in.test'))->group(function () {
require __DIR__ . '/api.php';
});
// B2IN Theme für b2in.test (Hauptwebsite)
Route::domain('b2in.test')->group(function () {
// Web-Routes laden
require __DIR__ . '/web.php';
// Web-Routes für alle Themes (werden außerhalb der Domain-Gruppen geladen, um Duplikate zu vermeiden)
// Das Theme wird automatisch basierend auf der Domain vom ThemeServiceProvider ausgewählt
require __DIR__ . '/web.php';
// B2IN Theme Assets (Vite)
// Domain-spezifische Vite Build-Verzeichnisse
Route::domain($domainB2in)->group(function () {
Vite::useBuildDirectory('build/b2in');
});
// B2A Theme für b2a.test
Route::domain('b2a.test')->group(function () {
// Web-Routes laden
require __DIR__ . '/web.php';
// B2A Theme Assets (Vite)
Route::domain($domainB2a)->group(function () {
Vite::useBuildDirectory('build/b2a');
});
// Stileigentum Theme für stileigentum.test
Route::domain('stileigentum.test')->group(function () {
// Web-Routes laden
require __DIR__ . '/web.php';
// Stileigentum Theme Assets (Vite)
Route::domain($domainStileigentum)->group(function () {
Vite::useBuildDirectory('build/stileigentum');
});
// Style2own Theme für style2own.test
Route::domain('style2own.test')->group(function () {
// Web-Routes laden
require __DIR__ . '/web.php';
// Style2own Theme Assets (Vite)
Route::domain($domainStyle2own)->group(function () {
Vite::useBuildDirectory('build/style2own');
});
@ -85,3 +103,6 @@ Route::domain('landing2.test')->group(function () {
Vite::useBuildDirectory('build/web');
});*/
// Fallback: Display-API für alle anderen Domains (z.B. localhost)
Route::get('/api/display/config', [\App\Http\Controllers\Api\DisplayConfigController::class, 'index']);

View file

@ -1,5 +1,10 @@
<?php
use App\Mail\PartnerInvitationMail;
use App\Models\PartnerInvitation;
use App\Models\User;
use App\Notifications\CustomResetPasswordNotification;
use App\Notifications\CustomVerifyEmailNotification;
use Illuminate\Support\Facades\Route;
use Livewire\Volt\Volt;
@ -22,3 +27,60 @@ Route::get('/debug-login', function () {
Route::get('/simple-test', function () {
return view('test-simple');
})->name('simple.test');
// E-Mail-Vorschau-Routen (nur für Entwicklung)
Route::prefix('test/emails')->group(function () {
// Partner-Einladung Vorschau
Route::get('/partner-invitation', function () {
$invitation = PartnerInvitation::first() ?? new PartnerInvitation([
'company_name' => 'Musterfirma GmbH',
'contact_first_name' => 'Max',
'contact_last_name' => 'Mustermann',
'email' => 'max@musterfirma.de',
'expires_at' => now()->addWeeks(2),
]);
// Mock role if not exists
if (!$invitation->role) {
$invitation->setRelation('role', (object)[
'display_name' => 'Premium Partner',
'name' => 'partner'
]);
}
$invitationUrl = 'https://portal.b2in.test/partner/invitation/accept/ABC123';
return new PartnerInvitationMail($invitation, $invitationUrl);
})->name('test.email.partner-invitation');
// Passwort-Reset Vorschau
Route::get('/password-reset', function () {
$user = User::first() ?? new User([
'name' => 'Max Mustermann',
'email' => 'max@example.com'
]);
$notification = new CustomResetPasswordNotification('test-token-123');
$mailMessage = $notification->toMail($user);
return $mailMessage->render();
})->name('test.email.password-reset');
// E-Mail-Verifizierung Vorschau
Route::get('/email-verification', function () {
$user = User::first() ?? new User([
'name' => 'Max Mustermann',
'email' => 'max@example.com'
]);
$notification = new CustomVerifyEmailNotification();
$mailMessage = $notification->toMail($user);
return $mailMessage->render();
})->name('test.email.verification');
// Übersicht aller E-Mail-Vorlagen
Route::get('/', function () {
return view('emails.test-overview');
})->name('test.emails');
});

View file

@ -64,12 +64,12 @@ Route::get('/theme-demo', function () {
return view('web.theme-demo');
})->name('theme-demo');
// Pfad-basierte Theme-Routen für lokale Entwicklung wurden entfernt
// Die Themensauswahl wird nun über den ThemeServiceProvider gesteuert (Domain oder ?theme=... GET-Parameter)
Volt::route('/partner/invitation/{token}', 'partner.invitation-accept')
->name('partner.invitation.accept');
Route::get('/partner/invitation/expired/{token}', function (string $token) {
$invitation = \App\Models\PartnerInvitation::with('role')->where('token', $token)->firstOrFail();
@ -81,8 +81,27 @@ Route::get('/partner/invitation/used/{token}', function (string $token) {
return view('partner.invitation-used', compact('invitation'));
})->name('partner.invitation.used');
// Partner Setup Wizard
Volt::route('/partner/invitation/{token}', 'partner.invitation-accept')
->name('partner.invitation.accept');
Volt::route('/partner/create-account', 'partner.create-account')
->name('partner.create.account');
// Öffentliche Registrierung per QR-/Code (Landing, code-check)
Volt::route('/reg/{role}', 'reg.landing')
->name('registration.landing');
Volt::route('/registration/thank-you', 'reg.thank-you')
->name('registration.thank-you');
// Partner Setup Wizard & Daten
Route::middleware('auth')->group(function () {
Volt::route('/partner/setup', 'partner.setup-wizard')
->name('partner.setup.wizard');
});
// Authentifizierungs-Routen werden in domains.php eingebunden
//require __DIR__ . '/auth.php';