# Setup — files to MERGE into your existing project

These files already exist in a fresh Laravel 11 install. Don't overwrite them —
add the marked sections into your own copy.

---

## 1. `bootstrap/app.php` — register middleware

```php
->withMiddleware(function (Middleware $middleware) {
    // Runs on every request — sets defensive headers (see SECURITY.md)
    $middleware->append(\App\Http\Middleware\SecurityHeaders::class);

    // Required by spatie/laravel-permission for the `role:` / `permission:` middleware
    $middleware->alias([
        'role' => \Spatie\Permission\Middleware\RoleMiddleware::class,
        'permission' => \Spatie\Permission\Middleware\PermissionMiddleware::class,
        'role_or_permission' => \Spatie\Permission\Middleware\RoleOrPermissionMiddleware::class,
    ]);
})
```

---

## 2. `app/Providers/AppServiceProvider.php` — login rate limiter

```php
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Support\Facades\RateLimiter;

public function boot(): void
{
    // Global API/route-level throttle as a second layer under the Livewire-level
    // RateLimiter check already inside app/Livewire/Auth/Login.php.
    RateLimiter::for('login', function ($request) {
        return Limit::perMinute(10)->by($request->ip());
    });
}
```

---

## 3. `routes/web.php` — role-scoped route groups

```php
use App\Livewire\Auth\Login;
use App\Livewire\Auth\Register;

Route::middleware('guest')->group(function () {
    Route::get('login', Login::class)->name('login');
    Route::get('register', Register::class)->name('register');
});

Route::middleware(['auth', 'verified'])->group(function () {
    Route::get('dashboard', function () {
        // Route to the correct dashboard by role — never let a controller assume
        // "logged in" means "admin". Each of these routes below must ALSO be
        // wrapped in their own role middleware (defense in depth).
        return match (true) {
            auth()->user()->hasRole('admin') => redirect()->route('admin.dashboard'),
            auth()->user()->hasRole('teacher') => redirect()->route('teacher.dashboard'),
            auth()->user()->hasRole('invigilator') => redirect()->route('invigilator.dashboard'),
            default => redirect()->route('student.dashboard'),
        };
    })->name('dashboard');
});

Route::middleware(['auth', 'verified', 'role:admin'])
    ->prefix('admin')->as('admin.')
    ->group(function () {
        Route::view('/', 'admin.dashboard')->name('dashboard');
        // Phase 2: user management, course/subject management, exam oversight
    });

Route::middleware(['auth', 'verified', 'role:teacher'])
    ->prefix('teacher')->as('teacher.')
    ->group(function () {
        Route::view('/', 'teacher.dashboard')->name('dashboard');
        // Phase 2: question bank, exam builder, grading queue
    });

Route::middleware(['auth', 'verified', 'role:invigilator|admin'])
    ->prefix('invigilator')->as('invigilator.')
    ->group(function () {
        Route::view('/', 'invigilator.dashboard')->name('dashboard');
        // Phase 2: live proctoring dashboard
    });

Route::middleware(['auth', 'verified', 'role:student'])
    ->prefix('student')->as('student.')
    ->group(function () {
        Route::view('/', 'student.dashboard')->name('dashboard');
        // Phase 2: exam list, exam taker, results
    });
```

> **Why the double-check (route middleware + Policy later)?** A route group protects
> the *entry point*. Once you add nested resources in Phase 2+ (e.g. a teacher editing
> `exams/{exam}`), you must also verify **that specific exam belongs to that teacher**
> via a Policy — otherwise Teacher A could edit `/teacher/exams/7` even if exam 7
> belongs to Teacher B, just by guessing the URL. Route middleware alone never
> catches this class of bug (IDOR — Insecure Direct Object Reference).

---

## 4. `tailwind.config.js` — content paths

Make sure Livewire view paths are included so Tailwind doesn't purge classes used
only inside Livewire components:

```js
content: [
    './resources/**/*.blade.php',
    './resources/**/*.js',
    './app/Livewire/**/*.php',
],
```

Import the design system in `resources/css/app.css`:

```css
@import './glass.css';
```

---

## 5. `.env` additions

```
ADMIN_SEED_EMAIL=admin@yourdomain.com
SESSION_SECURE_COOKIE=true
SESSION_HTTP_ONLY=true
SESSION_SAME_SITE=lax
```

Set `SESSION_SECURE_COOKIE=true` only once you're serving over HTTPS (required in
production; can stay `false` for local http development).
