# Quickstart: Customer Management (SP-04)

**Created**: 2026-06-04
**Feature**: [spec.md](./spec.md)

## Prerequisites

- SP-01 (Authentication & RBAC) - Admin authentication via Sanctum
- SP-02 (Database Foundation) - Users, contracts, installments tables with indexes
- SP-03 (Base Architecture) - Repositories, Helpers, Domain routing pattern

## File Structure to Create

```
src/app/Domains/Customer/
├── CustomerServiceProvider.php
├── Repositories/
│   ├── Contracts/
│   │   └── CustomerRepositoryInterface.php
│   └── Eloquent/
│       └── EloquentCustomerRepository.php
├── Services/
│   ├── CustomerService.php
│   └── CustomerExportService.php
├── Http/
│   ├── Controllers/
│   │   └── CustomerController.php
│   ├── Requests/
│   │   ├── CreateCustomerRequest.php
│   │   ├── UpdateCustomerRequest.php
│   │   ├── ListCustomersRequest.php
│   │   └── ExportCustomerRequest.php
│   └── Resources/
│       ├── CustomerResource.php
│       ├── CustomerDetailResource.php
│       └── CustomerExportResource.php
├── Jobs/
│   └── ExportCustomersJob.php
└── Routes/
    └── v1/
        └── api.php
```

## Step-by-Step Implementation

### Step 1: Create CustomerServiceProvider

```php
// src/app/Domains/Customer/CustomerServiceProvider.php
namespace App\Domains\Customer;

use Illuminate\Support\ServiceProvider;

class CustomerServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->app->bind(
            \App\Domains\Customer\Repositories\Contracts\CustomerRepositoryInterface::class,
            \App\Domains\Customer\Repositories\Eloquent\EloquentCustomerRepository::class
        );
    }

    public function boot(): void
    {
        Route::prefix('api/v1')
            ->group(__DIR__ . '/Routes/v1/api.php');
    }
}
```

### Step 2: Register Provider

Add to `src/bootstrap/providers.php`:
```php
use App\Domains\Customer\CustomerServiceProvider;
return [
    AppServiceProvider::class,
    AuthServiceProvider::class,
    CustomerServiceProvider::class, // ADD THIS
];
```

### Step 3: Create Repository Interface & Implementation

**CustomerRepositoryInterface.php**:
```php
namespace App\Domains\Customer\Repositories\Contracts;

use App\Shared\Repositories\Contracts\BaseRepositoryInterface;

interface CustomerRepositoryInterface extends BaseRepositoryInterface
{
    public function findWithFinancialSummary(int $id): array;
    public function paginateWithNearestDueDate(array $filters, int $perPage = 20);
    public function getExportData(array $filters): Collection;
}
```

**EloquentCustomerRepository.php**: Implement with SQL aggregation for financial summary.

### Step 4: Create Services

**CustomerService.php**: One method per use case:
- `createCustomer(CreateCustomerRequest $request): Model`
- `updateCustomer(int $id, UpdateCustomerRequest $request): Model`
- `getCustomerList(ListCustomersRequest $request): LengthAwarePaginator`
- `getCustomerDetail(int $id): array`
- `dispatchExportJob(ExportCustomerRequest $request): void`

**CustomerExportService.php**:
- `generateExcel(Collection $data, string $path): void`
- `generatePdf(Collection $data, string $path): void`

### Step 5: Create FormRequests

All validation per data-model.md validation rules.

### Step 6: Create Resources

Transform models to JSON responses with proper field selection.

### Step 7: Create Controller

Thin controller - delegate to CustomerService.

### Step 8: Create Routes

```php
Route::prefix('customers')->middleware(['auth:sanctum', 'permission:customers.view'])->group(function () {
    Route::get('/', [CustomerController::class, 'index']);
    Route::post('/', [CustomerController::class, 'store'])->middleware('permission:customers.create');
    Route::get('/{id}', [CustomerController::class, 'show']);
    Route::put('/{id}', [CustomerController::class, 'update'])->middleware('permission:customers.update');
    Route::post('/export', [CustomerController::class, 'export'])->middleware('permission:customers.export');
});
```

### Step 9: Create Export Job

```php
class ExportCustomersJob implements ShouldQueue
{
    use Dispatchable, Queueable, SerializesModels;

    public function __construct(
        public array $filters,
        public string $format,
        public int $adminId
    ) {}

    public function handle(CustomerExportService $exportService): void
    {
        // Query data, generate file, store to disk
    }
}
```

### Step 10: Add Permissions to Seeder

```php
// In permissions seeder
Permission::create(['name' => 'customers.view']);
Permission::create(['name' => 'customers.create']);
Permission::create(['name' => 'customers.update']);
Permission::create(['name' => 'customers.export']);
```

## Testing Commands

```bash
# Run customer feature tests
php artisan test --filter=Customer

# Test API endpoints manually
curl -X POST http://localhost/api/v1/customers \
  -H "Authorization: Bearer {token}" \
  -d "name=Ahmed&phone=0555123456"

curl -X GET http://localhost/api/v1/customers \
  -H "Authorization: Bearer {token}"

curl -X GET "http://localhost/api/v1/customers?search=Ahmed&from_date=2024-01-01&to_date=2024-12-31" \
  -H "Authorization: Bearer {token}"

curl -X POST http://localhost/api/v1/customers/export \
  -H "Authorization: Bearer {token}" \
  -d "from_date=2024-01-01&to_date=2024-12-31&format=excel"
```

## Key Implementation Notes

1. **No delete endpoint** - Constitution forbids user deletion
2. **SQL aggregation** - Financial summary via SQL, not PHP loops
3. **Cursor pagination** - Use `cursorPaginate()` for performance
4. **Database sorting** - Sort by MIN(due_date) at database level
5. **Async export** - Never generate files synchronously
6. **Response helpers** - Always use `ApiResponseHelper` functions