# Routes

This guide explains how to define API routes following our established patterns.

## Overview

Routes are defined in module-specific files and included in the main domain route files. They use:

1. **Middleware** for authentication and permissions
2. **Route groups** for organization
3. **Resource routes** for CRUD operations
4. **Named routes** for consistency

## Standard Route File Template

**Location:** `app/Domains/YourDomain/YourModule/Routes/api.php`

```php
<?php

use App\Domains\YourDomain\YourModule\Http\Controllers\V1\YourEntityController;
use Illuminate\Support\Facades\Route;

Route::middleware(['auth:sanctum'])->prefix('your-module')->name('your-module.')->group(function () {

    // Entity routes
    Route::prefix('your-entities')->name('your-entities.')->group(function () {
        // List all
        Route::get('/', [YourEntityController::class, 'index'])
            ->name('index')
            ->middleware('permission:your-entities.list');

        // Create new
        Route::post('/', [YourEntityController::class, 'store'])
            ->name('store')
            ->middleware('permission:your-entities.create');

        // Get single
        Route::get('/{yourEntity}', [YourEntityController::class, 'show'])
            ->name('show')
            ->middleware('permission:your-entities.show');

        // Update
        Route::put('/{yourEntity}', [YourEntityController::class, 'update'])
            ->name('update')
            ->middleware('permission:your-entities.edit');

        // Delete
        Route::delete('/{yourEntity}', [YourEntityController::class, 'destroy'])
            ->name('destroy')
            ->middleware('permission:your-entities.delete');

        // Custom actions
        Route::post('/{yourEntity}/approve', [YourEntityController::class, 'approve'])
            ->name('approve')
            ->middleware('permission:your-entities.approve');

        Route::post('/{yourEntity}/reject', [YourEntityController::class, 'reject'])
            ->name('reject')
            ->middleware('permission:your-entities.reject');

        // Bulk actions
        Route::post('/bulk-approve', [YourEntityController::class, 'bulkApprove'])
            ->name('bulk-approve')
            ->middleware('permission:your-entities.approve');

        // Export
        Route::get('/export', [YourEntityController::class, 'export'])
            ->name('export')
            ->middleware('permission:your-entities.export');
    });
});
```

## Route Registration

### Include in Domain Routes

**Location:** `routes/apis/{domain}.php` (e.g., `routes/apis/management.php`)

```php
<?php

// Include module routes
require base_path('app/Domains/Management/YourModule/Routes/api.php');
require base_path('app/Domains/Management/AnotherModule/Routes/api.php');
```

### Main API Routes File

**Location:** `routes/api.php`

```php
<?php

// Domain route files
require base_path('routes/apis/core.php');
require base_path('routes/apis/accounting.php');
require base_path('routes/apis/management.php');
require base_path('routes/apis/construction.php');
// ... other domains
```

## Route Patterns

### Basic CRUD Routes

```php
Route::middleware(['auth:sanctum'])->group(function () {
    Route::prefix('entities')->name('entities.')->group(function () {
        Route::get('/', [EntityController::class, 'index'])->name('index');
        Route::post('/', [EntityController::class, 'store'])->name('store');
        Route::get('/{entity}', [EntityController::class, 'show'])->name('show');
        Route::put('/{entity}', [EntityController::class, 'update'])->name('update');
        Route::delete('/{entity}', [EntityController::class, 'destroy'])->name('destroy');
    });
});
```

### Using Route Resource (Shorthand)

```php
Route::middleware(['auth:sanctum'])->group(function () {
    Route::apiResource('entities', EntityController::class);
});
```

**Note:** Using explicit routes (as shown in the template) is preferred for:
- Clear permission middleware per route
- Custom route naming
- Additional custom routes

### Nested Resources

```php
Route::middleware(['auth:sanctum'])->group(function () {
    Route::prefix('orders/{order}')->name('orders.')->group(function () {
        // Order items
        Route::prefix('items')->name('items.')->group(function () {
            Route::get('/', [OrderItemController::class, 'index'])->name('index');
            Route::post('/', [OrderItemController::class, 'store'])->name('store');
            Route::get('/{item}', [OrderItemController::class, 'show'])->name('show');
            Route::put('/{item}', [OrderItemController::class, 'update'])->name('update');
            Route::delete('/{item}', [OrderItemController::class, 'destroy'])->name('destroy');
        });

        // Order attachments
        Route::prefix('attachments')->name('attachments.')->group(function () {
            Route::get('/', [OrderAttachmentController::class, 'index'])->name('index');
            Route::post('/', [OrderAttachmentController::class, 'store'])->name('store');
            Route::delete('/{attachment}', [OrderAttachmentController::class, 'destroy'])->name('destroy');
        });
    });
});
```

### Status Change Routes

```php
Route::prefix('entities')->name('entities.')->group(function () {
    // ... CRUD routes

    // Status transitions
    Route::post('/{entity}/submit', [EntityController::class, 'submit'])
        ->name('submit')
        ->middleware('permission:entities.submit');

    Route::post('/{entity}/approve', [EntityController::class, 'approve'])
        ->name('approve')
        ->middleware('permission:entities.approve');

    Route::post('/{entity}/reject', [EntityController::class, 'reject'])
        ->name('reject')
        ->middleware('permission:entities.reject');

    Route::post('/{entity}/cancel', [EntityController::class, 'cancel'])
        ->name('cancel')
        ->middleware('permission:entities.cancel');

    Route::post('/{entity}/complete', [EntityController::class, 'complete'])
        ->name('complete')
        ->middleware('permission:entities.complete');
});
```

### Bulk Action Routes

```php
Route::prefix('entities')->name('entities.')->group(function () {
    // ... CRUD routes

    // Bulk operations (no ID parameter)
    Route::post('/bulk-approve', [EntityController::class, 'bulkApprove'])
        ->name('bulk-approve')
        ->middleware('permission:entities.approve');

    Route::post('/bulk-delete', [EntityController::class, 'bulkDelete'])
        ->name('bulk-delete')
        ->middleware('permission:entities.delete');

    Route::post('/bulk-export', [EntityController::class, 'bulkExport'])
        ->name('bulk-export')
        ->middleware('permission:entities.export');
});
```

### Export/Import Routes

```php
Route::prefix('entities')->name('entities.')->group(function () {
    // Export - GET since it's retrieving data
    Route::get('/export', [EntityController::class, 'export'])
        ->name('export')
        ->middleware('permission:entities.export');

    // Import - POST since it's uploading data
    Route::post('/import', [EntityController::class, 'import'])
        ->name('import')
        ->middleware('permission:entities.import');

    // Download template
    Route::get('/template', [EntityController::class, 'downloadTemplate'])
        ->name('template');
});
```

### Lookup/Dropdown Routes

```php
Route::prefix('lookups')->name('lookups.')->group(function () {
    // Simple list for dropdowns (no pagination)
    Route::get('/categories', [LookupController::class, 'categories'])
        ->name('categories');

    Route::get('/statuses', [LookupController::class, 'statuses'])
        ->name('statuses');

    Route::get('/users', [LookupController::class, 'users'])
        ->name('users');
});
```

## Middleware

### Authentication

```php
// Require authentication
Route::middleware(['auth:sanctum'])->group(function () {
    // Protected routes
});

// Guest only
Route::middleware(['guest'])->group(function () {
    // Login, register routes
});
```

### Permission Middleware

```php
// Single permission
Route::get('/', [Controller::class, 'index'])
    ->middleware('permission:entities.list');

// Multiple permissions (any)
Route::get('/', [Controller::class, 'index'])
    ->middleware('permission:entities.list|entities.view');

// Role-based
Route::get('/', [Controller::class, 'index'])
    ->middleware('role:admin');
```

### Custom Middleware

```php
Route::middleware(['auth:sanctum', 'check.company.setup'])->group(function () {
    // Routes that require company setup
});

Route::middleware(['auth:sanctum', 'check.project.access'])->group(function () {
    // Routes that require project access
});
```

## Route Model Binding

Laravel automatically resolves route parameters to model instances:

```php
// Route definition
Route::get('/entities/{entity}', [EntityController::class, 'show']);

// Controller receives model instance
public function show(Entity $entity): JsonResponse
{
    // $entity is already loaded from database
    // 404 thrown automatically if not found
}
```

### Custom Key Binding

```php
// In Model
public function getRouteKeyName(): string
{
    return 'uuid'; // Use uuid instead of id
}

// Route
Route::get('/entities/{entity:uuid}', [EntityController::class, 'show']);
```

### Scoped Bindings

```php
// Ensure item belongs to order
Route::get('/orders/{order}/items/{item}', [OrderItemController::class, 'show'])
    ->scopeBindings();

// Controller
public function show(Order $order, OrderItem $item): JsonResponse
{
    // $item is automatically scoped to $order
}
```

## Route Naming Conventions

| Action | Route Name | URL Pattern |
|--------|------------|-------------|
| List | `entities.index` | `GET /entities` |
| Create | `entities.store` | `POST /entities` |
| Show | `entities.show` | `GET /entities/{id}` |
| Update | `entities.update` | `PUT /entities/{id}` |
| Delete | `entities.destroy` | `DELETE /entities/{id}` |
| Approve | `entities.approve` | `POST /entities/{id}/approve` |
| Export | `entities.export` | `GET /entities/export` |
| Bulk | `entities.bulk-approve` | `POST /entities/bulk-approve` |

## URL Structure Examples

```
# Module: PayrollPipeline
GET    /api/payroll/runs                    # List payroll runs
POST   /api/payroll/runs                    # Create payroll run
GET    /api/payroll/runs/{id}               # Get payroll run
PUT    /api/payroll/runs/{id}               # Update payroll run
DELETE /api/payroll/runs/{id}               # Delete payroll run

# Nested: Salary slips under payroll run
GET    /api/payroll/runs/{runId}/slips      # List slips for run
GET    /api/payroll/runs/{runId}/slips/{id} # Get specific slip

# Actions
POST   /api/payroll/runs/{id}/approve       # Approve run
POST   /api/payroll/runs/{id}/process       # Process run
GET    /api/payroll/runs/export             # Export runs
```

## Complete Module Route Example

```php
<?php

use App\Domains\Management\PayrollPipeline\Http\Controllers\V1\PayrollRunController;
use App\Domains\Management\PayrollPipeline\Http\Controllers\V1\SalarySlipController;
use Illuminate\Support\Facades\Route;

Route::middleware(['auth:sanctum'])->prefix('payroll')->name('payroll.')->group(function () {

    // Payroll Runs
    Route::prefix('runs')->name('runs.')->group(function () {
        // CRUD
        Route::get('/', [PayrollRunController::class, 'index'])
            ->name('index')
            ->middleware('permission:payroll.runs.list');

        Route::post('/', [PayrollRunController::class, 'store'])
            ->name('store')
            ->middleware('permission:payroll.runs.create');

        Route::get('/{payrollRun}', [PayrollRunController::class, 'show'])
            ->name('show')
            ->middleware('permission:payroll.runs.show');

        Route::put('/{payrollRun}', [PayrollRunController::class, 'update'])
            ->name('update')
            ->middleware('permission:payroll.runs.edit');

        Route::delete('/{payrollRun}', [PayrollRunController::class, 'destroy'])
            ->name('destroy')
            ->middleware('permission:payroll.runs.delete');

        // Actions
        Route::post('/{payrollRun}/approve', [PayrollRunController::class, 'approve'])
            ->name('approve')
            ->middleware('permission:payroll.runs.approve');

        Route::post('/{payrollRun}/process', [PayrollRunController::class, 'process'])
            ->name('process')
            ->middleware('permission:payroll.runs.process');

        // Export
        Route::get('/export', [PayrollRunController::class, 'export'])
            ->name('export')
            ->middleware('permission:payroll.runs.export');

        // Nested: Salary Slips
        Route::prefix('/{payrollRun}/slips')->name('slips.')->group(function () {
            Route::get('/', [SalarySlipController::class, 'index'])
                ->name('index')
                ->middleware('permission:payroll.slips.list');

            Route::get('/{salarySlip}', [SalarySlipController::class, 'show'])
                ->name('show')
                ->middleware('permission:payroll.slips.show');

            Route::put('/{salarySlip}', [SalarySlipController::class, 'update'])
                ->name('update')
                ->middleware('permission:payroll.slips.edit');
        });
    });

    // Standalone Salary Slips routes (if needed)
    Route::prefix('slips')->name('slips.')->group(function () {
        Route::post('/{salarySlip}/approve', [SalarySlipController::class, 'approve'])
            ->name('approve')
            ->middleware('permission:payroll.slips.approve');

        Route::post('/bulk-approve', [SalarySlipController::class, 'bulkApprove'])
            ->name('bulk-approve')
            ->middleware('permission:payroll.slips.approve');
    });
});
```

## Best Practices

### DO:

1. **Group related routes** - Use prefix and name groups
2. **Apply permission middleware** - Per route for clarity
3. **Use route model binding** - Let Laravel resolve models
4. **Follow REST conventions** - GET for read, POST for create, etc.
5. **Name all routes** - For easy URL generation

### DON'T:

1. **Don't skip middleware** - Always protect routes
2. **Don't use verbs in URLs** - Use `/entities/{id}/approve` not `/approve-entity/{id}`
3. **Don't mix concerns** - Keep module routes separate
4. **Don't hardcode URLs** - Use `route()` helper
5. **Don't forget trailing slashes** - Be consistent

## Testing Routes

```bash
# List all routes
php artisan route:list

# Filter by name
php artisan route:list --name=payroll

# Filter by path
php artisan route:list --path=api/payroll
```
