# CRM Core Foundation Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Build a usable bounded CRM Core with manual leads, dashboard, stage tracking, tasks, activity timeline, and safe event listeners only for currently trusted lifecycle events.

**Architecture:** CRM lives in `app/Domain/CRM` and owns leads, tasks, activities, and stage history only. Livewire pages remain thin and call CRM queries/actions. Event integration is limited to `WhatsAppLeadCreated`, `B2bLeadConverted`, and `WhatsAppReplySent`, with listeners that mutate CRM state only.

**Tech Stack:** Laravel 12, Livewire 3, PostgreSQL/MySQL-compatible migrations, Spatie permissions, domain events/listeners, PHPUnit feature tests.

---

## File Map

- Create `database/migrations/*_create_crm_core_tables.php`
- Create `app/Models/CrmLead.php`, `CrmTask.php`, `CrmActivity.php`, `CrmStageHistory.php`
- Create `app/Domain/CRM/*` for enums/config, actions, queries, listeners, services, and data objects
- Create `app/Policies/CrmLeadPolicy.php` and `CrmTaskPolicy.php`
- Modify `app/Support/Rbac/PermissionCatalog.php`, `routes/web.php`, `bootstrap/providers.php`
- Create Livewire pages under `app/Livewire/Admin/Crm/`
- Create Blade views under `resources/views/livewire/admin/crm/`
- Create `lang/ar/crm.php` and `lang/fr/crm.php`
- Create tests under `tests/Feature/CRM/`
- Create `docs/crm_architecture.md`

### Task 1: CRM Schema, Models, Permissions

**Files:**
- Create: `tests/Feature/CRM/CrmCoreSchemaTest.php`
- Create: `database/migrations/2026_05_21_120000_create_crm_core_tables.php`
- Create: `app/Models/CrmLead.php`
- Create: `app/Models/CrmTask.php`
- Create: `app/Models/CrmActivity.php`
- Create: `app/Models/CrmStageHistory.php`
- Modify: `app/Support/Rbac/PermissionCatalog.php`
- Create: `app/Policies/CrmLeadPolicy.php`
- Create: `app/Policies/CrmTaskPolicy.php`
- Modify: `app/Providers/AppServiceProvider.php` or current policy registration location if needed

- [ ] **Step 1: Write failing schema and permission tests**

Add feature tests asserting:

- CRM tables exist after migrations.
- CRM permissions are exposed by `PermissionCatalog`.
- Core roles receive expected CRM permissions.

- [ ] **Step 2: Run test to verify it fails**

Run:

```bash
php artisan test tests/Feature/CRM/CrmCoreSchemaTest.php
```

Expected: FAIL because CRM tables/models/permissions do not exist yet.

- [ ] **Step 3: Add migration and minimal models**

Create the CRM tables:

- `crm_leads`
- `crm_tasks`
- `crm_activities`
- `crm_stage_history`

Add minimal relationships and casts in the four models only.

- [ ] **Step 4: Add CRM permissions and policies**

Add:

- `crm.view`
- `crm.manage`
- `crm.assign`
- `crm.tasks.manage`
- `crm.pipeline.manage`

Ensure admin and super admin receive them, and support receives only the bounded visibility intended for CRM use.

- [ ] **Step 5: Run test to verify it passes**

Run:

```bash
php artisan test tests/Feature/CRM/CrmCoreSchemaTest.php
```

Expected: PASS.

### Task 2: CRM Domain Config, Queries, Dashboard, Lead List

**Files:**
- Create: `tests/Feature/CRM/CrmDashboardTest.php`
- Create: `app/Domain/CRM/Support/CrmPipelineCatalog.php`
- Create: `app/Domain/CRM/Queries/CrmLeadListQuery.php`
- Create: `app/Domain/CRM/Queries/CrmDashboardQuery.php`
- Create: `app/Livewire/Admin/Crm/DashboardPage.php`
- Create: `app/Livewire/Admin/Crm/LeadsIndexPage.php`
- Create: `resources/views/livewire/admin/crm/dashboard-page.blade.php`
- Create: `resources/views/livewire/admin/crm/leads-index-page.blade.php`
- Create: `lang/ar/crm.php`
- Create: `lang/fr/crm.php`
- Modify: `routes/web.php`

- [ ] **Step 1: Write failing dashboard/list tests**

Add tests asserting:

- `/admin/crm` requires permission and loads for authorized admin.
- `/admin/crm/leads` loads and can show unassigned/my leads filters.
- dashboard returns lead count, stage count, tasks, overdue follow-ups from seeded CRM rows.

- [ ] **Step 2: Run test to verify it fails**

Run:

```bash
php artisan test tests/Feature/CRM/CrmDashboardTest.php
```

Expected: FAIL because routes/pages/queries do not exist yet.

- [ ] **Step 3: Create pipeline catalog and queries**

Implement one source of truth for:

- pipeline types
- stage lists
- validation helpers
- dashboard counter buckets

Then create query classes for:

- lead list with scope filters
- dashboard metrics

- [ ] **Step 4: Create dashboard and lead list pages**

Use Livewire pages that:

- authorize in `mount()`
- delegate list/math to CRM queries
- remain read-only at this stage

- [ ] **Step 5: Add routes and translations**

Add:

- `admin.crm.dashboard`
- `admin.crm.leads.index`

Both protected with explicit permissions.

- [ ] **Step 6: Run test to verify it passes**

Run:

```bash
php artisan test tests/Feature/CRM/CrmDashboardTest.php
```

Expected: PASS.

### Task 3: Manual Lead Creation

**Files:**
- Create: `tests/Feature/CRM/ManualCrmLeadCreationTest.php`
- Create: `app/Domain/Common/Data/CreateCrmLeadData.php`
- Create: `app/Domain/CRM/Actions/CreateCrmLeadAction.php`
- Create: `app/Livewire/Admin/Crm/LeadCreatePage.php`
- Create: `resources/views/livewire/admin/crm/lead-create-page.blade.php`
- Modify: `routes/web.php`

- [ ] **Step 1: Write failing manual creation test**

Assert:

- authorized user can create manual CRM lead
- unauthorized user gets 403
- at least one of `full_name`, `phone_e164`, or `email` is required
- activity and stage history first entries are created

- [ ] **Step 2: Run test to verify it fails**

Run:

```bash
php artisan test tests/Feature/CRM/ManualCrmLeadCreationTest.php
```

Expected: FAIL.

- [ ] **Step 3: Implement data object and creation action**

The Action should:

- create CRM lead
- set initial stage
- create first CRM activity
- create first stage history row
- wrap writes in `DB::transaction()`

- [ ] **Step 4: Add create page and route**

Add:

- `admin.crm.leads.create`

Keep page thin and validation-driven.

- [ ] **Step 5: Run test to verify it passes**

Run:

```bash
php artisan test tests/Feature/CRM/ManualCrmLeadCreationTest.php
```

Expected: PASS.

### Task 4: Assignment And Stage History

**Files:**
- Create: `tests/Feature/CRM/CrmAssignmentAndStageTest.php`
- Create: `app/Domain/Common/Data/AssignCrmLeadData.php`
- Create: `app/Domain/Common/Data/MoveCrmLeadStageData.php`
- Create: `app/Domain/CRM/Actions/AssignCrmLeadAction.php`
- Create: `app/Domain/CRM/Actions/MoveCrmLeadStageAction.php`
- Modify: `app/Livewire/Admin/Crm/LeadDetailPage.php` or create it if not yet present

- [ ] **Step 1: Write failing assignment/stage tests**

Assert:

- assignment updates owner and logs activity
- reassignment logs previous and new owner
- stage changes create stage history
- moving to `lost` stores reason when provided

- [ ] **Step 2: Run test to verify it fails**

Run:

```bash
php artisan test tests/Feature/CRM/CrmAssignmentAndStageTest.php
```

Expected: FAIL.

- [ ] **Step 3: Implement assignment and stage actions**

Actions must mutate CRM only and never external workflows.

- [ ] **Step 4: Wire lead detail commands or lightweight component handlers**

Lead detail page can now support assignment and stage movement.

- [ ] **Step 5: Run test to verify it passes**

Run:

```bash
php artisan test tests/Feature/CRM/CrmAssignmentAndStageTest.php
```

Expected: PASS.

### Task 5: Tasks And Follow-Ups

**Files:**
- Create: `tests/Feature/CRM/CrmTasksTest.php`
- Create: `app/Domain/Common/Data/CreateCrmTaskData.php`
- Create: `app/Domain/Common/Data/UpdateCrmTaskScheduleData.php`
- Create: `app/Domain/CRM/Actions/CreateCrmTaskAction.php`
- Create: `app/Domain/CRM/Actions/CompleteCrmTaskAction.php`
- Create: `app/Domain/CRM/Actions/SnoozeCrmTaskAction.php`
- Create: `app/Domain/CRM/Queries/MyCrmTasksQuery.php`

- [ ] **Step 1: Write failing task tests**

Assert:

- user can create follow-up task for CRM lead
- overdue tasks appear on dashboard/query
- complete/snooze/reschedule write CRM activities

- [ ] **Step 2: Run test to verify it fails**

Run:

```bash
php artisan test tests/Feature/CRM/CrmTasksTest.php
```

Expected: FAIL.

- [ ] **Step 3: Implement task actions and task query**

All task writes remain CRM-owned only.

- [ ] **Step 4: Surface tasks in dashboard and lead detail**

Keep UI minimal but operational.

- [ ] **Step 5: Run test to verify it passes**

Run:

```bash
php artisan test tests/Feature/CRM/CrmTasksTest.php
```

Expected: PASS.

### Task 6: Lead Detail And Activity Timeline

**Files:**
- Create: `tests/Feature/CRM/CrmLeadDetailTest.php`
- Create: `app/Domain/CRM/Queries/CrmLeadDetailQuery.php`
- Create: `app/Livewire/Admin/Crm/LeadDetailPage.php`
- Create: `resources/views/livewire/admin/crm/lead-detail-page.blade.php`
- Modify: `routes/web.php`

- [ ] **Step 1: Write failing lead detail test**

Assert:

- authorized user can open CRM lead detail
- page shows linked entities, current stage, tasks, stage history, activities
- unauthorized user is blocked

- [ ] **Step 2: Run test to verify it fails**

Run:

```bash
php artisan test tests/Feature/CRM/CrmLeadDetailTest.php
```

Expected: FAIL.

- [ ] **Step 3: Implement detail query and page**

Add route:

- `admin.crm.leads.show`

Use one query object to build the page read model.

- [ ] **Step 4: Run test to verify it passes**

Run:

```bash
php artisan test tests/Feature/CRM/CrmLeadDetailTest.php
```

Expected: PASS.

### Task 7: Safe Event Listeners

**Files:**
- Create: `tests/Feature/CRM/CrmEventIntegrationTest.php`
- Create: `app/Domain/CRM/Listeners/CreateCrmLeadFromWhatsAppLead.php`
- Create: `app/Domain/CRM/Listeners/SyncCrmLeadOnB2bLeadConverted.php`
- Create: `app/Domain/CRM/Listeners/LogCrmActivityForWhatsAppReply.php`
- Modify: `app/Providers/DomainEventBusServiceProvider.php`
- Modify: `docs/event_catalog.md`

- [ ] **Step 1: Write failing CRM event integration tests**

Assert:

- `WhatsAppLeadCreated` creates CRM lead once
- `B2bLeadConverted` updates linked organization and appends CRM activity
- `WhatsAppReplySent` appends CRM activity only
- listeners are idempotent

- [ ] **Step 2: Run test to verify it fails**

Run:

```bash
php artisan test tests/Feature/CRM/CrmEventIntegrationTest.php
```

Expected: FAIL.

- [ ] **Step 3: Implement CRM listeners**

Use `ListenerIdempotency` and mutate CRM state only.

- [ ] **Step 4: Register listeners in the domain event bus provider**

Do not wire any planned lifecycle integrations yet.

- [ ] **Step 5: Update event docs**

Mark CRM listeners as active only for the safe events in this phase.

- [ ] **Step 6: Run test to verify it passes**

Run:

```bash
php artisan test tests/Feature/CRM/CrmEventIntegrationTest.php
```

Expected: PASS.

### Task 8: Architecture Checks, Routes, And Final Verification

**Files:**
- Create: `tests/Feature/CRM/CrmAccessTest.php`
- Modify: `app/Console/Commands/ArchitectureCheckCommand.php`
- Modify: `config/architecture-check.php`
- Create: `docs/crm_architecture.md`
- Optionally modify admin navigation views if CRM links are added in this slice

- [ ] **Step 1: Write failing CRM access and architecture tests**

Assert:

- unauthorized access to CRM routes is blocked
- architecture check can flag forbidden CRM direct mutations if we add dedicated scan rules

- [ ] **Step 2: Run test to verify it fails**

Run:

```bash
php artisan test tests/Feature/CRM/CrmAccessTest.php
```

Expected: FAIL.

- [ ] **Step 3: Extend architecture checks for CRM boundaries**

Detect:

- CRM listeners directly mutating enrollment/payment/attendance/whatsapp state
- CRM actions calling payment/enrollment mutation methods directly outside approved contracts

- [ ] **Step 4: Write CRM architecture doc**

Document:

- ownership
- pipelines
- tasks
- event integrations
- planned integrations
- security boundaries

- [ ] **Step 5: Run full CRM verification**

Run:

```bash
php artisan test tests/Feature/CRM
php artisan app:architecture-check
```

Expected:

- CRM tests PASS
- architecture check runs successfully and reports only baseline debt outside this slice

