﻿# Tasks: Agent Management & Investor Logic (SP-05)

**Input**: Design documents from `/specs/006-agent-investor/`

**Prerequisites**: plan.md (required), spec.md (required), research.md, data-model.md, contracts/agents.openapi.yaml, quickstart.md

**Tests**: Included â€” Constitution Â§III (Test-First) is NON-NEGOTIABLE. AC-036 mandates 100% unit coverage for computed fields; AC-037 mandates feature tests for every endpoint (happy + 2 error + 1 edge); AC-038 mandates â‰¥ 80% overall domain coverage. **Within every user story phase, test tasks are written BEFORE implementation tasks.**

**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

## Path Conventions

- **Laravel monolith**: `app/`, `tests/`, `lang/`, `database/` at repository root
- Domain code lives under `app/Domains/Agent/`
- Tests under `tests/Feature/Agent/` and `tests/Unit/Models/`

---

## Phase 1: Setup (Shared Infrastructure)

**Purpose**: Project scaffolding, translations, exception mapping, permissions

- [X] T001 Create domain directory structure `app/Domains/Agent/Http/Controllers/`, `app/Domains/Agent/Http/Requests/`, `app/Domains/Agent/Http/Resources/`, `app/Domains/Agent/Services/`, `app/Domains/Agent/Models/Scopes/`, `app/Domains/Agent/Routes/v1/`
- [X] T002 Create `AgentServiceProvider` in `app/Domains/Agent/AgentServiceProvider.php` with `loadRoutesFrom()` for domain routes
- [X] T003 Register `AgentServiceProvider` in `bootstrap/providers.php`
- [X] T004 Create route file `app/Domains/Agent/Routes/v1/api.php` with all 8 agent endpoints under `auth:sanctum` middleware and Spatie permission gates (no DELETE on `/agents/{id}`)
- [X] T005 [P] Create error translations `lang/ar/errors/agent.php` with keys: `not_found`, `phone_unique`, `immutable`
- [X] T006 [P] Create error translations `lang/ar/errors/shares.php` with keys: `not_latest`, `lock_period_expired`, `insufficient_balance`
- [X] T007 [P] Create success translations `lang/ar/success/agent.php` with keys: `created`, `updated`, `share_added`, `share_withdrawn`, `share_modified`, `share_deleted`
- [X] T008 [P] Create `InsufficientShareBalanceException` in `app/Exceptions/Business/InsufficientShareBalanceException.php` with default message via `__('errors/shares.insufficient_balance')` â€” business exception (message-level 422), NOT a field-level validation error
- [X] T009 Register `InsufficientShareBalanceException` mapping in `app/Exceptions/ExceptionMappings.php` returning 422 with `message = $e->getMessage()` and empty `errors` object (message-level, not field-level â€” balance check requires DB query, lives in Service not FormRequest)
- [X] T010 Add agent permissions (`agents.view`, `agents.create`, `agents.update`, `agents.manage_shares`, `agents.view_shares_log`) to `database/seeders/RolePermissionSeeder.php`

---

## Phase 2: Foundational (Blocking Prerequisites)

**Purpose**: Core model, scopes, shared resources, controller stubs, factory states, and aggregate scopes that ALL user stories depend on

**âš ï¸ CRITICAL**: No user story work can begin until this phase is complete

- [X] T011 Create `AgentSharesLog` model in `app/Domains/Agent/Models/AgentSharesLog.php` with `$fillable = ['client_id', 'shares_count', 'transaction_type', 'status']`, `$table = 'agent_shares_logs'`, and `BelongsTo Client` relationship
- [X] T012 [P] Create `AgentSharesLogScopes` trait in `app/Domains/Agent/Models/Scopes/AgentSharesLogScopes.php` with scopes: `scopeActive`, `scopeForAgent`, `scopeRecentFirst`, `scopeMostRecentActive`
- [X] T013 [P] Create `BaseAgentResource` in `app/Domains/Agent/Http/Resources/BaseAgentResource.php` with `baseFields()` returning `id`, `name`, `phone`, `description`, `created_at`, `updated_at` (excludes `client_type_flags` and `reference_number` per SP-05-FR-030)
- [X] T014 Create `AgentController` in `app/Domains/Agent/Http/Controllers/AgentController.php` with empty `index`, `store`, `show`, `update` methods
- [X] T015 [P] Create `AgentSharesController` in `app/Domains/Agent/Http/Controllers/AgentSharesController.php` with empty `store`, `update`, `destroy`, `log` methods
- [X] T016 [P] Create `AgentService` skeleton in `app/Domains/Agent/Services/AgentService.php`
- [X] T017 [P] Create `AgentSharesService` skeleton in `app/Domains/Agent/Services/AgentSharesService.php`
- [X] T018 [P] Extend existing `ClientFactory` in `database/factories/ClientFactory.php` with three state methods using `fake('ar_SA')` Arabic locale: `asAgent()` (sets `client_type_flags` to `["agent"]`), `asInvestor()` (sets to `["agent", "investor"]`), `asAgentAndInvestor()` (alias of `asInvestor()` for test readability)
- [X] T019 [P] Create `AgentScopes` trait in `app/Domains/Agent/Models/Scopes/AgentScopes.php` with three scopes applied to `Client` queries: `scopeWithFinancialSummary` (JOINs `contracts`+`installments` selecting `total_installments_via_agent` / `total_collected_via_agent` / `total_remaining_via_agent` over active+completed), `scopeWithSharesBalance` (subquery on `agent_shares_logs` for signed sum over `status='active'`), `scopeWithInvestorProfit` (subquery on `contracts` for `SUM(total_after_profit - purchase_amount) * 0.05` over active+completed â€” `bcmath` done in SQL via `* 0.05` cast)

**Checkpoint**: Foundation ready â€” user story implementation can now begin in parallel

---

## Phase 3: User Story 1 â€” Agent Registration (Priority: P1) ðŸŽ¯ MVP

**Goal**: Admin can register a new agent and optionally seed initial shares; transactionally applies `agent` flag (and `investor` flag iff `shares_count > 0`)

**Independent Test**: `POST /api/v1/agents` with valid data returns 201; with `shares_count=5` creates one active share log row and sets investor flag; with `shares_count=0` creates no share log and no investor flag

### Tests for User Story 1

- [X] T020 [US1] Feature test for agent creation in `tests/Feature/Agent/CreateAgentTest.php` â€” covers: happy path (with and without shares), 422 duplicate phone, 422 missing fields, 422 negative shares_count, transactional flag update; uses `Bus::fake()` and asserts `Bus::assertDispatched(RefreshCustomerListingJob::class)` when `shares_count > 0` (AC-001..003, AC-013, AC-021, SP-05-FR-034)

### Implementation for User Story 1

- [X] T021 [P] [US1] Create `StoreAgentRequest` in `app/Domains/Agent/Http/Requests/StoreAgentRequest.php` with rules: `name` required|string|max:150, `phone` required|string|max:20|unique:clients,phone, `description` nullable|string, `shares_count` nullable|integer|min:0
- [X] T022 [P] [US1] Create `AgentCreatedResource` in `app/Domains/Agent/Http/Resources/AgentCreatedResource.php` extending `BaseAgentResource`, adding `shares_count` echo field
- [X] T023 [US1] Implement `AgentService::create` in `app/Domains/Agent/Services/AgentService.php` â€” wraps Client creation + `markAsAgent()` + optional share log insert + `markAsInvestor()` in `DB::transaction()`; dispatches `RefreshCustomerListingJob` after commit (SP-05-FR-004..008, BR-001-5/6)
- [X] T024 [US1] Implement `AgentController::store` in `app/Domains/Agent/Http/Controllers/AgentController.php` â€” delegates to `AgentService::create`, returns `AgentCreatedResource` with 201 (SP-05-FR-033, â‰¤5 lines)

**Checkpoint**: `POST /api/v1/agents` is fully functional and testable independently

---

## Phase 4: User Story 2 â€” Agent Listing with Financial Footprint (Priority: P1)

**Goal**: Admin can view a paginated, alphabetically sorted list of all agents with their `total_remaining_via_agent` and `total_collected_via_agent` aggregates

**Independent Test**: Seed â‰¥ 50 agents with mixed contract states; verify alphabetical sort, draft exclusion, cursor pagination

### Tests for User Story 2

- [X] T025 [US2] Feature test for agent listing in `tests/Feature/Agent/ListAgentsTest.php` â€” covers: alphabetical sort, ILIKE search, empty list, cursor pagination, draft contract exclusion, zero-contract agents (AC-001, SP-05-FR-001..003)

### Implementation for User Story 2

- [X] T026 [P] [US2] Create `ListAgentsRequest` in `app/Domains/Agent/Http/Requests/ListAgentsRequest.php` with rules: `search` nullable|string, `per_page` nullable|integer|min:1|max:100, `cursor` nullable|string
- [X] T027 [P] [US2] Create `AgentListResource` in `app/Domains/Agent/Http/Resources/AgentListResource.php` extending `BaseAgentResource`, adding `total_remaining_via_agent` and `total_collected_via_agent` (read from `withFinancialSummary` scope) (SP-05-FR-038)
- [X] T028 [US2] Implement `AgentService::list` in `app/Domains/Agent/Services/AgentService.php` â€” query: `Client::whereJsonContains('client_type_flags', 'agent')->withFinancialSummary()`, apply ILIKE search, `orderBy('name')->orderBy('id')`, `cursorPaginate()` (SP-05-FR-001..003) â€” aggregation pushed to PostgreSQL via the scope, no PHP iteration
- [X] T029 [US2] Implement `AgentController::index` in `app/Domains/Agent/Http/Controllers/AgentController.php` â€” delegates to `AgentService::list`, returns `AgentListResource` collection with cursor meta (â‰¤5 lines)

**Checkpoint**: `GET /api/v1/agents` is fully functional and testable independently

---

## Phase 5: User Story 3 â€” Agent Detail with Computed Profit and Referred Customers (Priority: P1)

**Goal**: Admin can view a single agent with all 6 financial aggregates, computed profit (5% of company margin), and referred-customers list in one response

**Independent Test**: Seed agent with 2 referred customers, 3 contracts in mixed states, 8 active shares; verify `computed_profit = SUM(total_after_profit âˆ’ purchase_amount) Ã— 0.05` over active+completed only; draft contributes zero; `referred_customers` excludes unrelated customers

### Tests for User Story 3

- [X] T030 [US3] Unit test for `AgentScopes` SQL generation in `tests/Unit/Models/AgentScopesTest.php` â€” 100% coverage: `withFinancialSummary` produces correct JOIN+SUM, `withSharesBalance` produces correct subquery, `withInvestorProfit` produces correct multiplication (pure unit, no DB, AC-036)
- [X] T031 [US3] Feature test for agent detail in `tests/Feature/Agent/ViewAgentTest.php` â€” covers: happy path with all aggregates (using `withFinancialSummary` + `withSharesBalance` + `withInvestorProfit` scopes), zero-data agent, 404 non-existent, investor flag persists when balance is 0, referred_customers shape (AC-004..006, SP-05-FR-009..020)

### Implementation for User Story 3

- [X] T032 [P] [US3] Create `AgentDetailResource` in `app/Domains/Agent/Http/Resources/AgentDetailResource.php` extending `BaseAgentResource`, adding `total_shares`, `total_installments_via_agent`, `total_collected_via_agent`, `total_remaining_via_agent`, `computed_profit`, `referred_customers` (read from eager-loaded scope attributes) (SP-05-FR-009, SP-05-FR-030)
- [X] T033 [US3] Implement `AgentService::show` in `app/Domains/Agent/Services/AgentService.php` â€” find agent using composed query: `Client::whereJsonContains('client_type_flags', 'agent')->withFinancialSummary()->withSharesBalance()->withInvestorProfit()->findOrFail($id)` â€” all aggregation done in PostgreSQL via the `AgentScopes` trait, no separate service class needed (SP-05-FR-009..020, BR-005-3/4)
- [X] T034 [US3] Implement `AgentController::show` in `app/Domains/Agent/Http/Controllers/AgentController.php` â€” delegates to `AgentService::show`, returns `AgentDetailResource` (â‰¤5 lines)

**Checkpoint**: `GET /api/v1/agents/{id}` is fully functional and testable independently

---

## Phase 6: User Story 5 â€” Share Movement Recording (Priority: P1)

**Goal**: Admin can record `add` or `withdraw` share movements; first `add` permanently marks client as investor; withdrawal that would yield negative balance is rejected with 422

**Independent Test**: First `add` â†’ investor flag set; subsequent `add`/`withdraw` â†’ new active log rows; withdrawal to zero balance â†’ investor flag remains; withdrawal exceeding balance â†’ 422 rejection with no log row created

### Tests for User Story 5

- [X] T035 [US5] Feature test for add shares in `tests/Feature/Agent/AddSharesTest.php` â€” covers: first-add sets investor flag, subsequent add keeps flag, 404 non-existent agent, 422 invalid action, 422 shares_count < 1; uses `Bus::fake()` and asserts `Bus::assertDispatched(RefreshCustomerListingJob::class)` on first add (AC-008, SP-05-FR-021..022, SP-05-FR-034)
- [X] T036 [US5] Feature test for withdraw shares in `tests/Feature/Agent/WithdrawSharesTest.php` â€” covers: successful withdrawal, withdrawal to exact-zero balance (AC-009b), 422 insufficient balance rejection with no log row created (AC-009a, BR-005-8), investor flag remains after zeroing balance (AC-022); uses `Bus::fake()` and asserts `Bus::assertDispatched(RefreshCustomerListingJob::class)` on successful withdraw (balance change affects MV)

### Implementation for User Story 5

- [X] T037 [P] [US5] Create `StoreAgentShareRequest` in `app/Domains/Agent/Http/Requests/StoreAgentShareRequest.php` with rules: `action` required|in:add,withdraw, `shares_count` required|integer|min:1 (NO `shares_count` min-balance check â€” that lives in the Service since it requires a DB query)
- [X] T038 [P] [US5] Create `AgentShareCreatedResource` in `app/Domains/Agent/Http/Resources/AgentShareCreatedResource.php` wrapping the share log row with success message
- [X] T039 [US5] Implement `AgentSharesService::store` in `app/Domains/Agent/Services/AgentSharesService.php` â€” guard order per SP-05-NFR-D-001a: (1) agent exists 404, (2) validation (FormRequest), (3) `action='withdraw'` â†’ projected balance â‰¥ 0 (throw `InsufficientShareBalanceException` 422), (4) first `add` â†’ `markAsInvestor()` in same `DB::transaction()`; dispatches `RefreshCustomerListingJob` after commit (SP-05-FR-021..022, BR-001-6, BR-005-8)
- [X] T040 [US5] Implement `AgentSharesController::store` in `app/Domains/Agent/Http/Controllers/AgentSharesController.php` â€” delegates to `AgentSharesService::store`, returns `AgentShareCreatedResource` with 201 (â‰¤5 lines)

**Checkpoint**: `POST /api/v1/agents/{id}/shares` is fully functional and testable independently

---

## Phase 7: User Story 6 â€” Share Log Modification within 30-Day Window (Priority: P1)

**Goal**: Admin can correct the most recent active share log row within 30 days; row is updated in place with `status='modified'`; rejects with 403 if not latest active or if 30 days elapsed

**Independent Test**: Modify most-recent active within 30 days â†’ row updated, `status='modified'`; modify non-latest â†’ 403; modify row > 30 days old â†’ 403; modify exactly on 30-day boundary â†’ succeeds (inclusive per Q3); two rows with identical `created_at` â†’ higher-id row is "most recent"

### Tests for User Story 6

- [X] T041 [US6] Feature test for modify share log in `tests/Feature/Agent/ModifyShareLogTest.php` â€” covers: happy path (same row updated, status='modified'), 403 not-latest, 403 30-day expired, 403 already modified/deleted, boundary at exactly 30 days (inclusive), 404 non-existent shareLogId, 422 shares_count < 1, concurrency (two parallel PATCHes â†’ one 200, one 403) (AC-010, AC-015, AC-016, AC-039, SP-05-NFR-D-006), edge case: two share log rows with identical `created_at` â†’ higher-id row is treated as "most recent" (per data-model Â§"Most-Recent-Active Tie-Breaker")

### Implementation for User Story 6

- [X] T042 [P] [US6] Create `UpdateAgentShareRequest` in `app/Domains/Agent/Http/Requests/UpdateAgentShareRequest.php` with rules: `shares_count` required|integer|min:1
- [X] T043 [P] [US6] Create `AgentShareLogResource` in `app/Domains/Agent/Http/Resources/AgentShareLogResource.php` returning `id`, `client_id`, `transaction_type`, `shares_count`, `status`, `created_at`, `updated_at` (moved here from Phase 9 â€” must exist before T045)
- [X] T044 [US6] Implement `AgentSharesService::update` in `app/Domains/Agent/Services/AgentSharesService.php` â€” calls shared private `validateShareLogModification($agentId, $shareLogId)` method (extracted for reuse with destroy), acquires `lockForUpdate()` on target row, updates same row: `shares_count` + `status='modified'` + `updated_at` (SP-05-FR-023..025, SP-05-NFR-D-003/004/006)
- [X] T045 [US6] Implement `AgentSharesController::update` in `app/Domains/Agent/Http/Controllers/AgentSharesController.php` â€” delegates to `AgentSharesService::update`, returns `AgentShareLogResource` with 200 (â‰¤5 lines)

**Checkpoint**: `PATCH /api/v1/agents/{id}/shares/{shareLogId}` is fully functional and testable independently

---

## Phase 8: User Story 7 â€” Share Log Logical Deletion within 30-Day Window (Priority: P1)

**Goal**: Admin can void the most recent active share log row within 30 days; row's `status` flips to `deleted` (never physically deleted)

**Independent Test**: Delete most-recent active within 30 days â†’ `status='deleted'`, row remains in table; delete non-latest â†’ 403; delete row > 30 days old â†’ 403; verify no physical DELETE SQL executes

### Tests for User Story 7

- [X] T046 [US7] Feature test for delete share log in `tests/Feature/Agent/DeleteShareLogTest.php` â€” covers: happy path (status='deleted', row still exists), 403 not-latest, 403 30-day expired, 403 already deleted, 404 non-existent, physical DELETE assertion (no `DELETE FROM agent_shares_logs` SQL) (AC-011, AC-017, AC-023, AC-025, SP-05-NFR-D-005)

### Implementation for User Story 7

- [X] T047 [US7] Implement `AgentSharesService::destroy` in `app/Domains/Agent/Services/AgentSharesService.php` â€” calls SAME shared private `validateShareLogModification($agentId, $shareLogId)` method (extracted from update to prevent logic drift), acquires `lockForUpdate()`, updates same row: `status='deleted'` + `updated_at` (no physical DELETE) (SP-05-FR-026..028, SP-05-NFR-D-005/006)
- [X] T048 [US7] Implement `AgentSharesController::destroy` in `app/Domains/Agent/Http/Controllers/AgentSharesController.php` â€” delegates to `AgentSharesService::destroy`, returns success response with 200 (â‰¤5 lines)

**Checkpoint**: `DELETE /api/v1/agents/{id}/shares/{shareLogId}` is fully functional and testable independently

---

## Phase 9: User Story 8 â€” Share Log History Read (Priority: P1)

**Goal**: Admin can view full reverse-chronological history of all share movements including `modified` and `deleted` rows

**Independent Test**: Seed agent with 5 share log rows (mix of statuses); verify reverse-chronological order, all statuses visible, cursor pagination

### Tests for User Story 8

- [X] T049 [US8] Feature test for view shares log in `tests/Feature/Agent/ViewSharesLogTest.php` â€” covers: reverse-chronological order, all statuses visible (active/modified/deleted), empty log, 404 non-existent agent, cursor pagination (AC-012, SP-05-FR-029)

### Implementation for User Story 8

- [X] T050 [US8] Implement `AgentSharesService::log` in `app/Domains/Agent/Services/AgentSharesService.php` â€” queries `AgentSharesLog::forAgent($id)->recentFirst()->cursorPaginate()`, includes all statuses (SP-05-FR-029)
- [X] T051 [US8] Implement `AgentSharesController::log` in `app/Domains/Agent/Http/Controllers/AgentSharesController.php` â€” delegates to `AgentSharesService::log`, returns `AgentShareLogResource` collection with cursor meta (â‰¤5 lines)

**Checkpoint**: `GET /api/v1/agents/{id}/shares-log` is fully functional and testable independently

---

## Phase 10: User Story 4 â€” Agent Profile Update (Priority: P2)

**Goal**: Admin can update agent's name, phone, description; share-related fields are silently ignored

**Independent Test**: `PUT` with updated name â†’ 200, share log untouched; `PUT` with duplicate phone â†’ 422; `PUT` with `shares_count` in body â†’ silently ignored; non-existent agent â†’ 404

### Tests for User Story 4

- [X] T052 [US4] Feature test for update agent in `tests/Feature/Agent/UpdateAgentTest.php` â€” covers: happy path, 422 duplicate phone (ignore self), 404 non-existent, `shares_count` in body silently ignored (AC-007, SP-05-FR-010); does NOT assert `Bus::dispatched(RefreshCustomerListingJob)` since name/phone change does not affect MV (per SP-05-FR-034 implementation note)

### Implementation for User Story 4

- [X] T053 [P] [US4] Create `UpdateAgentRequest` in `app/Domains/Agent/Http/Requests/UpdateAgentRequest.php` with rules: `name` sometimes|string|max:150, `phone` sometimes|string|max:20|unique:clients,phone,{id}, `description` nullable|string
- [X] T054 [US4] Implement `AgentService::update` in `app/Domains/Agent/Services/AgentService.php` â€” finds agent, fills only `name`/`phone`/`description` (ignores share fields via `$request->only(['name','phone','description'])`), saves with full lifecycle (SP-05-FR-010)
- [X] T055 [US4] Implement `AgentController::update` in `app/Domains/Agent/Http/Controllers/AgentController.php` â€” delegates to `AgentService::update`, returns `BaseAgentResource` directly with 200 (NO separate `AgentUpdatedResource` â€” PUT response shape matches `BaseAgentResource`, per U2 resolution) (â‰¤5 lines)

**Checkpoint**: `PUT /api/v1/agents/{id}` is fully functional and testable independently

---

## Phase 11: User Story 9 â€” Agent Immutability (Priority: P1)

**Goal**: No `DELETE /api/v1/agents/{id}` route exists; any programmatic `delete()` throws `ClientImmutableException`

**Independent Test**: Programmatic `$agent->delete()` throws `ClientImmutableException`; route table has no DELETE for agents collection

### Tests for User Story 9

- [X] T056 [US9] Feature test for agent immutability in `tests/Feature/Agent/AgentImmutabilityTest.php` â€” covers: programmatic delete throws `ClientImmutableException` with zero DB mutation, no DELETE route registered for `/api/v1/agents/{id}` (AC-020, AC-024, SP-05-FR-011)

### Implementation for User Story 9

- [X] T057 [US9] Verify route file `app/Domains/Agent/Routes/v1/api.php` has no DELETE route on `/agents/{id}` â€” confirm existing `Client::delete()` and `Client::destroy()` overrides from SP-03 still enforce `ClientImmutableException` (no new code needed if SP-03 is correct)

**Checkpoint**: Agent immutability is verified and testable independently

---

## Phase 12: Polish & Cross-Cutting Concerns

**Purpose**: Coverage, data minimization verification, architecture compliance, localization audit

> **Note on Performance Tests (G1 deferral)**: AC-030 (10K agents load test) and AC-031 (50 contracts / 500 installments load test) are **deferred to SP-07 implementation phase** â€” both require contract and installment data that do not exist until the Contract Management spec is implemented. No performance test tasks are added in this spec.

- [X] T058 [P] Unit test for `AgentSharesLogScopes` in `tests/Unit/Models/AgentSharesLogScopesTest.php` â€” verifies scope SQL generation for `active`, `forAgent`, `recentFirst`, `mostRecentActive`
- [X] T059 [P] Unit test for `AgentSharesService` calculations in `tests/Unit/Services/Agent/AgentSharesServiceTest.php` â€” verifies projected balance calculation, 30-day boundary logic, `validateShareLogModification` guard logic
- [X] T060 Verify data minimization: no `client_type_flags` or `reference_number` in any agent API response â€” structural test across all 8 endpoints (AC-026, SP-05-FR-030)
- [X] T061 Verify all Controller methods are thin (â‰¤ 5 lines, no business logic) â€” architecture compliance (AC-033)
- [X] T062 Verify all Models declare explicit `$fillable` (no `$guarded = ['*']`) â€” architecture compliance (AC-034)
- [X] T063 Verify `routes/api.php` remains empty â€” all agent routes loaded by `AgentServiceProvider` (AC-032)
- [X] T064 Run full test suite with coverage report â€” verify â‰¥ 80% for agent domain (AC-038)
- [X] T065 Run quickstart.md validation steps from `specs/006-agent-investor/quickstart.md`
- [X] T066 [P] Localization audit â€” verify all translation keys used in agent domain exist in `lang/ar/errors/agent.php`, `lang/ar/errors/shares.php`, `lang/ar/success/agent.php`, `lang/ar/errors/general.php`; use assertion that `__()` does not return the key itself for every key used in `ExceptionMappings.php`, FormRequest messages, and Service error strings (AC-028, AC-029, SP-05-FR-039)

---

## 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..11)**: All depend on Foundational phase completion
  - US1 (Agent Registration) can start immediately after Foundational
  - US2 (Agent Listing) depends on US1 for `AgentService` class existence
  - US3 (Agent Detail) can start after Foundational (uses `AgentScopes` from Phase 2)
  - US5 (Share Movement) can start after Foundational (needs `AgentSharesService`)
  - US6 (Share Log Modification) depends on US5 for `AgentSharesService` class existence
  - US7 (Share Log Logical Deletion) depends on US5/US6 for `AgentSharesService` class existence (safety margin)
  - US8 (Share Log History) depends on US5 for `AgentSharesService` class existence
  - US4 (Agent Update) depends on US1 for `AgentService` class existence
  - US9 (Immutability) can start after Foundational (verification only)
- **Polish (Phase 12)**: Depends on all user stories being complete

### User Story Dependencies

- **US1 (P1)**: No dependencies on other stories â€” ðŸŽ¯ MVP entry point
- **US2 (P1)**: Soft dependency on US1 (same `AgentService` class)
- **US3 (P1)**: Independent of US1/US2 (uses `AgentScopes` trait, no service conflict)
- **US5 (P1)**: Independent of US1..US3 (different `AgentSharesService`)
- **US6 (P1)**: Depends on US5 (`AgentSharesService` class)
- **US7 (P1)**: Depends on US5/US6 (`AgentSharesService` class â€” safety margin)
- **US8 (P1)**: Depends on US5 (`AgentSharesService` class)
- **US4 (P2)**: Soft dependency on US1 (same `AgentService` class)
- **US9 (P1)**: Independent â€” verification only

### Within Each User Story

- Tests MUST be written and FAIL before implementation (Constitution Â§III â€” TEST-FIRST is NON-NEGOTIABLE)
- All test tasks are listed BEFORE implementation tasks in every story phase
- Requests before Services
- Services before Controllers
- Core implementation before integration

### Parallel Opportunities

- All Setup tasks T005..T010 marked [P] can run in parallel
- All Foundational tasks T012, T013, T015..T019 marked [P] can run in parallel
- US3 and US5 can be developed in parallel (different services, different controllers)
- US9 can be developed in parallel with any other story
- Within each story, [P] tasks can run in parallel

---

## Parallel Example: User Story 1

```text
# Phase 3 â€” Test first, then launch in parallel:
Task T020: "Feature test for agent creation (with Bus::fake assertions)"
Task T021: "Create StoreAgentRequest in app/Domains/Agent/Http/Requests/StoreAgentRequest.php"
Task T022: "Create AgentCreatedResource in app/Domains/Agent/Http/Resources/AgentCreatedResource.php"
# Then sequential:
Task T023: "Implement AgentService::create in app/Domains/Agent/Services/AgentService.php"
Task T024: "Implement AgentController::store in app/Domains/Agent/Http/Controllers/AgentController.php"
```

## Parallel Example: User Story 5 + User Story 3

```text
# After Foundational, two developers can work in parallel:
Developer A: US3 (AgentScopes in use â†’ AgentService::show â†’ AgentController::show)
Developer B: US5 (StoreAgentShareRequest â†’ AgentSharesService::store â†’ AgentSharesController::store)
# No file conflicts â€” different services, different controllers
```

---

## 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 (Agent Registration)
4. **STOP and VALIDATE**: Test US1 independently â€” `POST /api/v1/agents` creates agent + optional shares
5. Deploy/demo if ready

### Incremental Delivery

1. Complete Setup + Foundational â†’ Foundation ready
2. Add US1 (Agent Registration) â†’ Test independently â†’ Deploy/Demo (MVP!)
3. Add US2 (Agent Listing) â†’ Test independently â†’ Deploy/Demo
4. Add US3 (Agent Detail + Computed Profit) â†’ Test independently â†’ Deploy/Demo
5. Add US5 (Share Movement) â†’ Test independently â†’ Deploy/Demo
6. Add US6 + US7 (Share Log Correction + Deletion) â†’ Test independently â†’ Deploy/Demo
7. Add US8 (Share Log History) â†’ Test independently â†’ Deploy/Demo
8. Add US4 (Agent Update) â†’ Test independently â†’ Deploy/Demo
9. Add US9 (Immutability Verification) â†’ Test independently
10. Complete Polish â†’ Full coverage verified

### Parallel Team Strategy

With multiple developers:

1. Team completes Setup + Foundational together
2. Once Foundational is done:
   - Developer A: US1 â†’ US2 â†’ US4 (AgentService path)
   - Developer B: US3 (AgentScopes + AgentService::show)
   - Developer C: US5 â†’ US6 â†’ US7 â†’ US8 (AgentSharesService path)
   - Developer D: US9 (immutability verification)
3. Stories complete and integrate independently

---

## Notes

- **[P] tasks** = different files, no dependencies
- **[Story] label** maps task to specific user story for traceability
- **Test-First ordering**: Within every user story phase, test tasks precede implementation tasks (Constitution Â§III)
- Each user story should be independently completable and testable
- All financial math MUST use `bcmath` â€” no `float`/`double` (BR-006-1/2, Constitution ALWAYS)
- `client_type_flags` and `reference_number` MUST NEVER appear in API responses (SP-05-FR-030)
- No `saveQuietly()` for flag updates (Constitution NEVER)
- No physical DELETE on `agent_shares_logs` (BR-005-7, SP-05-NFR-D-005)
- No `DELETE /api/v1/agents/{id}` route (BR-001-1, SP-05-FR-011)
- `investor` flag is permanent once set (BR-001-6, AC-022)
- All user-facing strings via `__()` translation keys (Constitution ALWAYS, SP-05-FR-039)
- PATCH/DELETE share log MUST use `lockForUpdate()` (SP-05-NFR-D-006, AC-039)
- PATCH and DELETE share log guard logic MUST be extracted into a shared private `validateShareLogModification($agentId, $shareLogId)` method to prevent logic drift (D2 decision)
- `InsufficientShareBalanceException` is a message-level 422 exception, NOT a field-level validation error â€” balance check requires DB query and lives in Service (U3 decision)
- Commit after each task or logical group
- Stop at any checkpoint to validate story independently
