# Task D.3: Lead / Enquiry Ownership Refinement

## 1. Files Added

- `drizzle/0012_odd_fat_cobra.sql`
- `docs/adr/0011-lead-enquiry-ownership-model.md`
- `docs/implementation/task-d3-lead-enquiry-ownership-refinement.md`

## 2. Files Modified

- `src/db/schema.ts`
- `src/lib/auth/rbac.ts`
- `src/features/users/components/user-form-sheet.tsx`
- `src/features/crm/enquiries/api/types.ts`
- `src/features/crm/enquiries/server/service.ts`
- `src/features/crm/quotations/server/service.ts`
- `src/app/api/crm/enquiries/route.ts`
- `src/app/api/crm/enquiries/[id]/route.ts`
- `src/app/api/crm/enquiries/[id]/assign/route.ts`
- `src/app/api/crm/enquiries/[id]/reassign/route.ts`
- `src/app/api/crm/enquiries/[id]/customers/route.ts`
- `src/app/api/crm/enquiries/[id]/followups/route.ts`
- `src/app/api/crm/enquiries/[id]/followups/[followupId]/route.ts`
- `src/app/api/crm/dashboard/route.ts`
- `src/app/api/crm/dashboard/export/route.ts`
- `src/app/dashboard/crm/enquiries/page.tsx`
- `src/app/dashboard/crm/enquiries/[id]/page.tsx`
- `src/config/nav-config.ts`
- `src/features/crm/enquiries/components/enquiry-form-sheet.tsx`
- `src/features/crm/enquiries/components/enquiry-assignment-dialog.tsx`
- `src/features/crm/enquiries/components/enquiry-columns.tsx`
- `src/features/crm/enquiries/components/enquiry-detail.tsx`
- `src/features/crm/enquiries/components/enquiry-cell-action.tsx`
- `src/features/crm/dashboard/api/types.ts`
- `src/features/crm/dashboard/server/service.ts`
- `src/features/crm/dashboard/components/crm-dashboard.tsx`
- `src/features/crm/dashboard/components/dashboard-summary-cards.tsx`
- `src/features/crm/dashboard/components/dashboard-funnel.tsx`
- `src/features/crm/dashboard/components/dashboard-sales-ranking.tsx`
- `src/features/crm/dashboard/components/dashboard-followups.tsx`
- `src/features/crm/dashboard/components/dashboard-hot-projects.tsx`

## 3. Pipeline Changes

- Added `crm_enquiries.pipeline_stage`
- Allowed values:
  - `lead`
  - `enquiry`
  - `closed_won`
  - `closed_lost`
- Backfilled legacy enquiry rows:
  - assigned rows -> `enquiry`
  - unassigned rows -> `lead`
  - closed-lost/cancelled status rows -> `closed_lost`
- Assign flow now converts `lead -> enquiry`
- Quotation accepted/lost/rejected outcomes can synchronize linked enquiry lifecycle to won/lost stages

## 4. Ownership Changes

- Added business role `marketing`
- Marketing-created records default to `lead`
- Sales-created records default to `enquiry`
- `sales` and `sales_support` now use server-enforced own-or-assigned enquiry visibility
- managers, admins, and marketing retain broader monitoring visibility

## 5. Visibility Rules Added

- Marketing can read CRM lead/enquiry monitoring surfaces
- Marketing cannot see quotation pricing or approval analytics
- Enquiry detail hides related quotation links when the user lacks quotation read access
- CRM dashboard hides quotation, revenue, hot-enquiry, sales-ranking, and approval sections when the user lacks those permissions

## 6. KPI Changes

- Dashboard summary now uses `pipelineStage` for:
  - lead count
  - enquiry count
  - won count
  - lost count
- User-facing KPI language changed from `Opportunity` to `Enquiry`
- Funnel wording now follows lead -> enquiry -> quotation flow
- Follow-up and ownership labels now use `Enquiry Owner`

## 7. ADR Added

- Added `docs/adr/0011-lead-enquiry-ownership-model.md`
- This freezes:
  - lead ownership
  - enquiry ownership
  - assignment conversion behavior
  - marketing visibility restriction boundaries
  - won/lost lifecycle naming

## 8. Migration Notes

- Apply `drizzle/0012_odd_fat_cobra.sql`
- Existing `crm_enquiries` rows are backfilled in-place; no new lead table is introduced
- Existing forms and APIs remain shared across lead and enquiry flows
- Existing quotation routes remain intact; only linked enquiry lifecycle sync was added

## 9. Remaining Risks

- `closed_won` still has no dedicated timestamp field; lifecycle timing remains coarse
- dashboard/export visibility now follows permission boundaries, but any future custom report endpoints must preserve the same commercial-data guardrails
- quotation-to-enquiry lifecycle sync currently depends on quotation status transitions and does not yet model reopen scenarios explicitly

## Verification

- `npx tsc --noEmit`
