This commit is contained in:
phaichayon
2026-06-23 22:13:08 +07:00
parent 99a4087099
commit c1ecd5ea50
32 changed files with 3503 additions and 150 deletions

766
plans/task-d.5.md Normal file
View File

@@ -0,0 +1,766 @@
# Task D.5: Lead / Enquiry Domain Separation
## Objective
Refactor CRM pipeline architecture by separating Lead and Enquiry into dedicated business entities.
Replace the current shared `crm_enquiries + pipelineStage` model with a true business flow:
```txt
Lead
→ Enquiry
→ Quotation
→ Won / Lost
```
The new model must support:
```txt
1 Lead
→ N Enquiries
1 Enquiry
→ N Quotations
1 Quotation
→ N Options
```
and remove the ambiguity caused by stage-based mutation.
---
# Business Discovery 3.1 (Frozen)
## Marketing Flow
```txt
Marketing
Create Lead
Follow Up
Assign Sales
Create Enquiry
```
Marketing owns Leads.
---
## Sales Flow
```txt
Sales
Create Enquiry Directly
```
Sales can create Enquiries without a Lead.
---
## Sales Execution Flow
```txt
Enquiry
Quotation
PO Received
Won
```
or
```txt
Enquiry
Lost
```
---
# Mandatory Review
Before implementation review:
* AGENTS.md
* Project Foundations Registry
* Task Catalog
* ADR 0011 Lead / Enquiry Ownership Model
* ADR 0016 Won / Lost Lifecycle Governance
* Customer Ownership Foundation
* Reporting Foundation
* Authorization Foundation
* Dashboard Foundation
---
# Required Skills
## Governance
* AGENTS.md
* Task Contract Template
* Architecture Rules
* Task Review Checklist
---
## CRM
* Lead / Enquiry Governance
* Won / Lost Governance
* Customer Ownership Governance
* Revenue Attribution Governance
---
## Security
* CRM Authorization Foundation
* Scope Enforcement Foundation
---
# Scope D5.1 Lead Table
Create:
```txt
crm_leads
```
Lead becomes a dedicated entity.
Core fields:
```txt
id
organizationId
branchId
code
customerId
contactId
projectName
projectLocation
awarenessId
status
followupStatus
lostReason
outcome
ownerMarketingUserId
createdBy
createdAt
updatedAt
deletedAt
```
---
# Scope D5.2 Lead Awareness
Master option category:
```txt
crm_lead_awareness
```
Seed:
```txt
Google Search / Website
Social Media
Email Marketing
Visit
Exhibition / Event
Brochure / Catalog
Word of Mouth
Corporate Car
Product Label
Re-purchasing
Introducing
BCI
```
Purpose:
```txt
ลูกค้ารู้จักเราจากช่องทางใด
```
Used in:
* Lead Form
* Lead Dashboard
* Lead Reports
* Marketing Analytics
---
# Scope D5.3 Lead Status
Master option:
```txt
crm_lead_status
```
Values:
```txt
new_job
follow_up
closed_lost
cancel
```
Display:
```txt
New Job
Follow Up
Closed Lost
Cancel
```
---
# Scope D5.4 Lead Follow-up Status
Master option:
```txt
crm_lead_followup_status
```
Values:
```txt
budget_pending
project_under_review
spec_clarification
site_survey_waiting
drawing_followup
quotation_preparation
waiting_po
```
Display:
```txt
รองบประมาณ
ระหว่างพิจารณาโครงการ
เคลียร์สเปค
รอสำรวจหน้างาน
ติดตามแบบงาน
ระหว่างการเสนอราคา
รอลูกค้าออก PO
```
Visible only when:
```txt
Lead Status = Follow Up
```
---
# Scope D5.5 Lead Lost Reason
Master option:
```txt
crm_lead_lost_reason
```
Values:
```txt
price
delivery_time
sales_person
service
customer
product_quality
other
transfer
```
Display:
```txt
ราคา
ระยะเวลาจัดส่ง
พนักงานขาย
การบริการ
ลูกค้า
คุณภาพสินค้า
อื่นๆ
Transfer
```
Visible only when:
```txt
Lead Status = Closed Lost
or
Lead Status = Cancel
```
---
# Scope D5.6 Lead Outcome
Add:
```txt
crm_leads.outcome
```
Values:
```txt
open
won
lost
```
Purpose:
Marketing KPI and reporting.
Marketing must not update manually.
---
# Scope D5.7 Enquiry Refactor
Refactor:
```txt
crm_enquiries
```
to become a pure Sales entity.
Remove Lead lifecycle responsibilities.
Add:
```txt
leadId nullable
```
Relationship:
```txt
crm_leads 1
→ N crm_enquiries
```
---
# Scope D5.8 Lead Assignment
Replace:
```txt
pipelineStage change
```
with:
```txt
Create Enquiry
```
Flow:
```txt
Lead
Assign Sales
Create Enquiry
```
Lead remains.
Enquiry is created.
---
# Scope D5.9 Direct Sales Enquiry
Support:
```txt
Sales
Create Enquiry Directly
```
Business Rule:
```txt
leadId = null
```
Allowed.
Examples:
```txt
Existing Customer
Walk-in Customer
Direct Referral
Sales Prospecting
```
---
# Scope D5.10 Multiple Product Types
Support:
```txt
1 Lead
→ N Enquiries
```
Example:
```txt
Lead LD2606-001
├─ EN2606-001 Crane
├─ EN2606-002 Dock Door
└─ EN2606-003 Solar
```
Each enquiry has:
```txt
productTypeId
salesmanId
assignedToUserId
```
independently.
---
# Scope D5.11 Outcome Synchronization
Marketing should never update outcomes manually.
When:
```txt
Enquiry = Won
```
Update:
```txt
Lead Outcome = Won
```
Automatically.
---
When:
```txt
All Enquiries linked to Lead = Lost
```
Update:
```txt
Lead Outcome = Lost
```
Automatically.
---
Lead Outcome is derived from Enquiry outcomes.
---
# Scope D5.12 Document Sequences
Create dedicated sequences.
Lead:
```txt
LD2606-001
```
Enquiry:
```txt
EN2606-001
```
Separate document types.
Separate counters.
---
# Scope D5.13 Dashboard Refactor
Lead KPI Source:
```txt
crm_leads
```
Enquiry KPI Source:
```txt
crm_enquiries
```
No stage filtering.
---
# Scope D5.14 Reporting Refactor
Update:
* Lead Pipeline
* Lead Aging
* Lead Conversion
* Enquiry Pipeline
* Enquiry Aging
* Funnel Reports
Reuse:
```txt
Reporting Foundation
```
No parallel reporting implementation.
---
# Scope D5.15 Security Refactor
Lead visibility:
```txt
Marketing
Managers
Admins
```
Enquiry visibility:
```txt
Assigned Sales
Managers
Admins
```
Use:
```txt
resolveCrmMembershipAccess()
```
No direct role checks.
---
# Scope D5.16 Data Migration
Migrate existing records.
Rules:
```txt
pipelineStage = lead
→ crm_leads
pipelineStage = enquiry
→ crm_enquiries
pipelineStage = closed_won
→ crm_enquiries
pipelineStage = closed_lost
→ crm_enquiries
```
Preserve:
* follow-ups
* customers
* attachments
* ownership
* audit history
---
# Deliverables
## New Tables
* crm_leads
---
## Modified Tables
* crm_enquiries
---
## New Master Options
* crm_lead_awareness
* crm_lead_status
* crm_lead_followup_status
* crm_lead_lost_reason
---
## New APIs
* `/api/crm/leads`
* `/api/crm/leads/[id]`
* `/api/crm/leads/[id]/assign`
* `/api/crm/leads/[id]/followups`
---
## Updated APIs
* `/api/crm/enquiries`
* `/api/crm/dashboard`
* `/api/crm/reports`
---
## Documentation
Create:
```txt
docs/adr/0018-lead-enquiry-domain-separation.md
docs/implementation/task-d5-lead-enquiry-domain-separation.md
```
---
# Explicit Non-Scope
Do NOT:
* redesign quotation workflow
* redesign approval workflow
* redesign PDF workflow
* redesign role model
Reuse existing foundations.
---
# Verification
Verify:
```txt
1 Lead
→ N Enquiries
```
Verify:
```txt
1 Enquiry
→ N Quotations
```
Verify:
```txt
Sales Direct Enquiry
(leadId = null)
```
Verify:
```txt
Lead Outcome Auto Sync
```
Verify:
```txt
Lead Sequence
Enquiry Sequence
```
Verify:
```txt
Dashboard
Reports
Security
```
continue functioning.
Run:
```txt
npm exec tsc --noEmit
```
---
# Definition of Done
Task is complete when:
* Lead and Enquiry are separate entities
* Sales can create Enquiries directly
* Marketing can create Leads
* 1 Lead → N Enquiries works
* 1 Enquiry → N Quotations works
* Lead outcomes are automatically derived from Enquiry outcomes
* Lead and Enquiry document sequences are independent
* Dashboard and Reports use separated datasets
* Security follows existing CRM authorization foundation
Result:
Lead Domain = Established
Enquiry Domain = Established
Marketing Pipeline = Clear
Sales Pipeline = Clear