767 lines
7.7 KiB
Markdown
767 lines
7.7 KiB
Markdown
# 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
|