# Tasks: Customer Management (SP-04)

**Input**: Design documents from `/specs/004-customer-management/`

**Prerequisites**: plan.md (required), spec.md (required for user stories), research.md, data-model.md, quickstart.md

**Tests**: PHPUnit + Feature Tests per endpoint (per plan.md)

**Organization**: Tasks are grouped by user story to enable independent implementation and testing of each story.

## Format: `[ID] [P?] [Story] Description`

- **[P]**: Can run in parallel (different files, no dependencies)
- **[Story]**: Which user story this task belongs to (e.g., US1, US2, US3)
- Include exact file paths in descriptions

---

## Phase 1: Setup (Domain Structure Creation)

**Purpose**: Create the Customer domain folder structure following SP-03 pattern

- [X] T001 [P] Create domain directory structure `src/app/Domains/Customer/` with Repositories/Contracts/, Repositories/Eloquent/, Services/, Http/Controllers/, Http/Requests/, Http/Resources/, Jobs/, Routes/v1/
- [X] T002 [P] Create `.gitkeep` files in each empty directory for version control

---

## Phase 2: Foundational (Blocking Prerequisites) ⚠️ CRITICAL

**Purpose**: Core infrastructure that MUST be complete before ANY user story can be implemented

**⚠️ CRITICAL**: No user story work can begin until this phase is complete

- [X] T003 Create `CustomerServiceProvider.php` in `src/app/Domains/Customer/CustomerServiceProvider.php` with repository bindings and route loading in boot()
- [X] T004 Register CustomerServiceProvider in `src/bootstrap/providers.php` alongside AuthServiceProvider
- [ ] T004a [P] Verify CustomerServiceProvider is registered correctly: run `php artisan tinker` and execute `app()->getProviders(App\Domains\Customer\CustomerServiceProvider::class)` to confirm provider loads
- [ ] T004b [P] Verify database migrations are healthy: run `php artisan migrate:status` to confirm all SP-02 migrations have run
- [X] T005 [P] Create `CustomerRepositoryInterface.php` in `src/app/Domains/Customer/Repositories/Contracts/CustomerRepositoryInterface.php` extending BaseRepositoryInterface with methods: findWithFinancialSummary(int $id), paginateWithNearestDueDate(array $filters, int $perPage), getExportData(array $filters)
- [X] T006 [P] Create `EloquentCustomerRepository.php` in `src/app/Domains/Customer/Repositories/Eloquent/EloquentCustomerRepository.php` implementing CustomerRepositoryInterface with:
  - SQL aggregation queries for financial summary using SUM(CASE WHEN...) and COUNT(CASE WHEN...)
  - Customer list query using LEFT JOIN (not INNER JOIN) with contracts and installments
  - Sorting by COALESCE(MIN(due_date), '9999-12-31') ASC, customer_id ASC to push NULL nearest_due_date to end
  - WHERE clause for status IN ('pending', 'overdue') when computing MIN(due_date)

**Checkpoint**: Foundation ready - user story implementation can now begin

---

## Phase 3: User Story 1 - Customer Creation (Priority: P1) 🎯 MVP

**Goal**: Admin can create a new customer via POST `/api/v1/customers` with name, phone, optional description, and avatar

**Independent Test**: POST to `/api/v1/customers` with valid data returns 201 and customer record

### Tests for User Story 1

> Write tests FIRST, ensure they FAIL before implementation

- [X] T007 [P] [US1] Create `tests/Feature/Customer/CustomerCrudTest.php` with testCreateCustomerSuccess, testCreateCustomerValidationError, testCreateCustomerPhoneUnique tests
- [X] T008 [P] [US1] Run tests to verify they FAIL before implementation

### Implementation for User Story 1

- [X] T009 [P] [US1] Create `CreateCustomerRequest.php` in `src/app/Domains/Customer/Http/Requests/CreateCustomerRequest.php` with validation: name (required, string, max:150), phone (required, string, unique:users), description (nullable, string), avatar (nullable, image, max:2048KB)
- [X] T010 [P] [US1] Create `CustomerResource.php` in `src/app/Domains/Customer/Http/Resources/CustomerResource.php` to transform customer model to JSON
- [X] T011 [US1] Create `CustomerService.php` in `src/app/Domains/Customer/Services/CustomerService.php` with createCustomer method (depends on T009, T010)
- [X] T012 [US1] Create `CustomerController.php` in `src/app/Domains/Customer/Http/Controllers/CustomerController.php` with store method using CustomerService and ApiResponseHelper
- [X] T013 [US1] Create routes in `src/app/Domains/Customer/Routes/v1/api.php` with POST `/customers` route pointing to CustomerController@store with `auth:sanctum` and `permission:customers.create` middleware
- [X] T014 [US1] Add `customers.create` and `customers.view` permissions to database seeder

**Checkpoint**: User Story 1 should be fully functional - test POST /api/v1/customers returns 201

---

## Phase 4: User Story 2 - Customer Data Modification (Priority: P1)

**Goal**: Admin can update existing customer data via PUT `/api/v1/customers/{id}` even with active contracts

**Independent Test**: PUT to `/api/v1/customers/{id}` with valid data returns 200 and updated customer record

### Tests for User Story 2

> Write tests FIRST, ensure they FAIL before implementation

- [X] T015 [P] [US2] Add testUpdateCustomerSuccess, testUpdateCustomerWithActiveContract, testUpdateCustomerNotFound to `tests/Feature/Customer/CustomerCrudTest.php`
- [X] T016 [P] [US2] Run tests to verify they FAIL before implementation

### Implementation for User Story 2

- [X] T017 [P] [US2] Create `UpdateCustomerRequest.php` in `src/app/Domains/Customer/Http/Requests/UpdateCustomerRequest.php` with validation: name (sometimes, string, max:150), phone (sometimes, unique:users, ignore:{id}), description (nullable, string), avatar (nullable, image, max:2048KB)
- [X] T018 [US2] Add updateCustomer method to `CustomerService.php` in `src/app/Domains/Customer/Services/CustomerService.php` (depends on T017)
- [X] T019 [US2] Add update method to `CustomerController.php` in `src/app/Domains/Customer/Http/Controllers/CustomerController.php` using CustomerService and ApiResponseHelper
- [X] T020 [US2] Add PUT `/customers/{id}` route to `src/app/Domains/Customer/Routes/v1/api.php` pointing to CustomerController@update with `auth:sanctum` and `permission:customers.update` middleware

**Checkpoint**: User Story 2 should be fully functional - test PUT /api/v1/customers/{id} returns 200

---

## Phase 5: User Story 3 - Customer Listing with Intelligent Sorting (Priority: P1)

**Goal**: Admin can view paginated customer list sorted by nearest pending/overdue installment due date with search and time filtering

**Independent Test**: GET `/api/v1/customers` returns cursor-paginated list sorted by MIN(due_date) of pending/overdue installments

### Tests for User Story 3

> Write tests FIRST, ensure they FAIL before implementation

- [X] T021 [P] [US3] Create `tests/Feature/Customer/CustomerListTest.php` with testListCustomersSortedByNearestDueDate, testListCustomersWithSearch, testListCustomersWithDateFilter, testListCustomersPagination tests
- [X] T022 [P] [US3] Run tests to verify they FAIL before implementation

### Implementation for User Story 3

- [X] T023 [P] [US3] Create `ListCustomersRequest.php` in `src/app/Domains/Customer/Http/Requests/ListCustomersRequest.php` with validation: search (nullable, string), from_date (nullable, date), to_date (nullable, date, after:from_date), cursor (nullable, string)
- [X] T024 [P] [US3] Create `CustomerListResource.php` in `src/app/Domains/Customer/Http/Resources/CustomerListResource.php` to transform customer list items with nearest_due_date
- [X] T025 [US3] Add getCustomerList method to `CustomerService.php` using paginateWithNearestDueDate from repository with search, from_date, to_date filters
- [X] T026 [US3] Add index method to `CustomerController.php` using CustomerService and cursorPaginate response with ApiResponseHelper
- [X] T027 [US3] Add GET `/customers` route to `src/app/Domains/Customer/Routes/v1/api.php` pointing to CustomerController@index with `auth:sanctum` and `permission:customers.view` middleware

**Checkpoint**: User Story 3 should be fully functional - test GET /api/v1/customers returns cursor-paginated results sorted by nearest due date

---

## Phase 6: User Story 4 - Customer Details with Financial Summary (Priority: P1)

**Goal**: Admin can view customer details with computed financial summary (total_installment_amount, total_collected_amount, total_remaining_amount, total_pending_installments, total_overdue_installments) calculated via SQL aggregation

**Independent Test**: GET `/api/v1/customers/{id}` returns customer data plus computed financial metrics matching manual calculation

### Tests for User Story 4

> Write tests FIRST, ensure they FAIL before implementation

- [X] T028 [P] [US4] Create `tests/Feature/Customer/CustomerDetailTest.php` with testShowCustomerWithFinancialSummary (full endpoint integration test), testShowCustomerNotFound tests
- [X] T029 [P] [US4] Run tests to verify they FAIL before implementation

### Implementation for User Story 4

- [X] T030 [P] [US4] Create `CustomerDetailResource.php` in `src/app/Domains/Customer/Http/Resources/CustomerDetailResource.php` to transform customer with financial summary fields
- [X] T031 [US4] Add getCustomerDetail method to `CustomerService.php` using findWithFinancialSummary from repository
- [X] T032 [US4] Add show method to `CustomerController.php` using CustomerService and ApiResponseHelper
- [X] T033 [US4] Add GET `/customers/{id}` route to `src/app/Domains/Customer/Routes/v1/api.php` pointing to CustomerController@show with `auth:sanctum` and `permission:customers.view` middleware

**Checkpoint**: User Story 4 should be fully functional - test GET /api/v1/customers/{id} returns customer with accurate financial summary

---

## Phase 7: User Story 5 - Asynchronous Customer Export (Priority: P2)

**Goal**: Admin can request customer export via POST `/api/v1/customers/export` which dispatches a queue job and returns immediate response

**Independent Test**: POST `/api/v1/customers/export` with valid params returns 200/202 immediately and job appears in jobs table

### Tests for User Story 5

> Write tests FIRST, ensure they FAIL before implementation

- [X] T034 [P] [US5] Create `tests/Feature/Customer/CustomerExportTest.php` with testExportCustomersDispatchJob, testExportCustomersValidationError tests
- [X] T035 [P] [US5] Run tests to verify they FAIL before implementation

### Implementation for User Story 5

- [X] T036 [P] [US5] Create `ExportCustomerRequest.php` in `src/app/Domains/Customer/Http/Requests/ExportCustomerRequest.php` with validation: from_date (required, date, before:to_date), to_date (required, date, after:from_date), format (required, enum:excel,pdf)
- [X] T037 [P] [US5] Create `CustomerExportResource.php` in `src/app/Domains/Customer/Http/Resources/CustomerExportResource.php` to transform customer data for export format
- [X] T038 [P] [US5] Create `CustomerExportService.php` in `src/app/Domains/Customer/Services/CustomerExportService.php` with generateExcel and generatePdf methods using Maatwebsite/Excel and DomPDF, storing to `storage/app/exports/` with naming pattern `customers_export_{YYYYMMDD}_{timestamp}.{format}`
- [X] T039 [US5] Create `ExportCustomersJob.php` in `src/app/Domains/Customer/Jobs/ExportCustomersJob.php` implementing ShouldQueue with database driver, constructor accepting filters array, format string, and adminId, handle method calling CustomerExportService
- [X] T040 [US5] Add dispatchExportJob method to `CustomerService.php` dispatching ExportCustomersJob to queue
- [X] T041 [US5] Add export method to `CustomerController.php` using CustomerService and returning immediate success response via ApiResponseHelper
- [X] T042 [US5] Add POST `/customers/export` route to `src/app/Domains/Customer/Routes/v1/api.php` pointing to CustomerController@export with `auth:sanctum` and `permission:customers.export` middleware

**Checkpoint**: User Story 5 should be fully functional - test POST /api/v1/customers/export returns immediately and job exists in jobs table

---

## Phase 8: Polish & Cross-Cutting Concerns

**Purpose**: Final integration, permissions, and verification

- [ ] T043 [P] Run all feature tests to verify complete integration: `php artisan test --filter=Customer`
- [ ] T044 [P] Verify all routes are properly registered: `php artisan route:list | grep customer`
- [ ] T045 Run `php artisan test` to ensure no regressions in existing tests
- [ ] T046 [P] Verify User model immutability still throws exception on delete attempt
- [ ] T047 Verify all API responses use ApiResponseHelper functions (success, resourceCreatedResponse, etc.)
- [ ] T048 Verify no delete routes exist for customers (Constitution enforcement)

---

## Phase 9: Performance Testing (SC-003 Enforcement)

**Purpose**: Verify that customer list endpoint performs within 1 second for 10,000 customers

- [ ] T049 [P] Create `tests/Feature/Customer/CustomerPerformanceTest.php` with:
  - A seeder/factory that creates exactly 10,000 users with distributed contracts and installments
  - A test `testListCustomersPerformanceUnderLoad` that calls GET `/api/v1/customers`
  - Assertion that response time is strictly < 1000ms (1 second)
- [ ] T050 Run performance test to verify LEFT JOIN and indexes work under load: `php artisan test --filter=CustomerPerformanceTest`

---

## Dependencies & Execution Order

### Phase Dependencies

- **Setup (Phase 1)**: No dependencies - can start immediately
- **Foundational (Phase 2)**: Depends on Setup completion - BLOCKS all user stories
- **User Stories (Phase 3-7)**: All depend on Foundational phase completion
  - User stories can proceed in parallel (if staffed) or sequentially in priority order
- **Polish (Phase 8)**: Depends on all user stories being complete

### User Story Dependencies

- **US1 (P1) - Creation**: Can start after Foundational (Phase 2) - No dependencies on other stories
- **US2 (P1) - Modification**: Can start after Foundational (Phase 2) - No dependencies on other stories
- **US3 (P1) - Listing**: Can start after Foundational (Phase 2) - No dependencies on other stories
- **US4 (P1) - Details**: Can start after Foundational (Phase 2) - No dependencies on other stories
- **US5 (P2) - Export**: Can start after Foundational (Phase 2) - No dependencies on other stories

### Within Each User Story

- Tests MUST be written and FAIL before implementation
- Models/Requests/Resources can be done in parallel
- Services depend on Requests/Resources
- Controller depends on Service
- Routes depend on Controller

### Parallel Opportunities

- All Setup tasks marked [P] can run in parallel
- All Foundational tasks marked [P] can run in parallel (within Phase 2)
- Once Foundational phase completes, all user stories can start in parallel (if team capacity allows)
- All tests for a user story marked [P] can run in parallel
- All Request/Resource creations within a story marked [P] can run in parallel

---

## Parallel Example: User Story 1

```bash
# Launch all tests for User Story 1 together:
Task: "Create tests/Feature/Customer/CustomerCrudTest.php with testCreateCustomerSuccess..."
Task: "Run tests to verify they FAIL before implementation"

# Launch all components for User Story 1 creation in parallel:
Task: "Create CreateCustomerRequest.php in src/app/Domains/Customer/Http/Requests/"
Task: "Create CustomerResource.php in src/app/Domains/Customer/Http/Resources/"
```

---

## Implementation Strategy

### MVP First (User Story 1 Only)

1. Complete Phase 1: Setup
2. Complete Phase 2: Foundational (CRITICAL - blocks all stories)
3. Complete Phase 3: User Story 1 (Customer Creation)
4. **STOP and VALIDATE**: Test User Story 1 independently
5. Deploy/demo if ready

### Incremental Delivery

1. Complete Setup + Foundational → Foundation ready
2. Add User Story 1 → Test independently → Deploy/Demo (MVP!)
3. Add User Story 2 → Test independently → Deploy/Demo
4. Add User Story 3 → Test independently → Deploy/Demo
5. Add User Story 4 → Test independently → Deploy/Demo
6. Add User Story 5 → Test independently → Deploy/Demo
7. Each story adds value without breaking previous stories

### Parallel Team Strategy

With multiple developers:

1. Team completes Phase 1 + Phase 2 together
2. Once Foundational is done:
   - Developer A: User Story 1 + US2 (both P1)
   - Developer B: User Story 3 + US4 (both P1)
   - Developer C: User Story 5 (P2 - Export)
3. Stories complete and integrate independently

---

## Summary

| Metric | Value |
|--------|-------|
| **Total Tasks** | 52 |
| **User Story 1 (Creation)** | 9 tasks |
| **User Story 2 (Modification)** | 7 tasks |
| **User Story 3 (Listing)** | 8 tasks |
| **User Story 4 (Details)** | 7 tasks |
| **User Story 5 (Export)** | 9 tasks |
| **Setup + Foundational** | 10 tasks (incl. T004a, T004b verification) |
| **Performance Testing** | 2 tasks |
| **Parallelizable Tasks** | 26 (marked with [P]) |
| **MVP Scope** | User Story 1 (Phase 3) |

**Independent Test Criteria per User Story**:
- **US1**: POST /api/v1/customers returns 201 with customer data
- **US2**: PUT /api/v1/customers/{id} returns 200 with updated data
- **US3**: GET /api/v1/customers returns cursor-paginated list sorted by nearest due date
- **US4**: GET /api/v1/customers/{id} returns customer with financial summary
- **US5**: POST /api/v1/customers/export returns immediately, job visible in jobs table

---

## Notes

- [P] tasks = different files, no dependencies
- [Story] label maps task to specific user story for traceability
- Each user story should be independently completable and testable
- Verify tests fail before implementing
- Commit after each task or logical group
- Stop at any checkpoint to validate story independently
- No delete endpoint for customers (Constitution forbids user deletion)
- SQL aggregation required for financial calculations (not PHP loops)