538 lines
5.3 KiB
Markdown
538 lines
5.3 KiB
Markdown
# Task D.5.3: Lead Assignment → Create Enquiry Foundation
|
|
|
|
## Status
|
|
|
|
Planned
|
|
|
|
## Objective
|
|
|
|
Implement the first production transition from Lead into Enquiry.
|
|
|
|
This task establishes the business boundary between:
|
|
|
|
```txt
|
|
Marketing Domain
|
|
↓
|
|
Lead
|
|
|
|
Sales Domain
|
|
↓
|
|
Enquiry
|
|
```
|
|
|
|
A Lead remains the marketing-owned source record.
|
|
|
|
An Enquiry becomes the sales execution workspace.
|
|
|
|
This task introduces:
|
|
|
|
* Lead assignment workflow
|
|
* Enquiry creation from Lead
|
|
* Lead ↔ Enquiry relationship
|
|
* Initial ownership transfer
|
|
* Enquiry bootstrap generation
|
|
|
|
without changing quotation, dashboard, reporting, or approval behavior.
|
|
|
|
---
|
|
|
|
# Mandatory Review
|
|
|
|
Review:
|
|
|
|
* AGENTS.md
|
|
* Project Foundations Registry
|
|
* Task Catalog
|
|
* ADR-0018 Lead / Enquiry Domain Separation
|
|
* Task D.5
|
|
* Task D.5.1
|
|
* Task D.5.2
|
|
* Customer Ownership Foundation
|
|
* CRM Security Foundation
|
|
* Audit Foundation
|
|
* Document Sequence Foundation
|
|
|
|
---
|
|
|
|
# Existing Foundation
|
|
|
|
Verified available:
|
|
|
|
```txt
|
|
crm_leads
|
|
crm_enquiries
|
|
crm_enquiries.lead_id
|
|
|
|
crm_lead sequence
|
|
crm_enquiry sequence
|
|
|
|
Lead Service
|
|
Lead API
|
|
```
|
|
|
|
Do not recreate:
|
|
|
|
```txt
|
|
tables
|
|
migrations
|
|
seed data
|
|
master-option categories
|
|
```
|
|
|
|
---
|
|
|
|
# Business Model
|
|
|
|
## Before Assignment
|
|
|
|
Owner:
|
|
|
|
```txt
|
|
Marketing
|
|
```
|
|
|
|
Workspace:
|
|
|
|
```txt
|
|
Lead
|
|
```
|
|
|
|
---
|
|
|
|
## After Assignment
|
|
|
|
Owner:
|
|
|
|
```txt
|
|
Sales
|
|
```
|
|
|
|
Workspace:
|
|
|
|
```txt
|
|
Enquiry
|
|
```
|
|
|
|
---
|
|
|
|
## Relationship
|
|
|
|
```txt
|
|
1 Lead
|
|
↓
|
|
0..N Enquiries
|
|
```
|
|
|
|
Lead remains immutable historical source.
|
|
|
|
Enquiries become sales execution records.
|
|
|
|
---
|
|
|
|
# Scope D5.3.1 Lead Assignment Service
|
|
|
|
Create:
|
|
|
|
```txt
|
|
src/features/crm/leads/server/assignment.service.ts
|
|
```
|
|
|
|
Required operation:
|
|
|
|
```txt
|
|
assignLead()
|
|
```
|
|
|
|
---
|
|
|
|
Input:
|
|
|
|
```ts
|
|
AssignLeadInput
|
|
```
|
|
|
|
Fields:
|
|
|
|
```ts
|
|
leadId
|
|
salesOwnerId
|
|
assignmentRemark
|
|
```
|
|
|
|
---
|
|
|
|
Validation:
|
|
|
|
```txt
|
|
lead exists
|
|
lead active
|
|
salesOwnerId valid
|
|
same organization
|
|
```
|
|
|
|
---
|
|
|
|
# Scope D5.3.2 Create Enquiry From Lead
|
|
|
|
Create:
|
|
|
|
```txt
|
|
createEnquiryFromLead()
|
|
```
|
|
|
|
inside assignment service.
|
|
|
|
---
|
|
|
|
Rules
|
|
|
|
Assignment automatically creates:
|
|
|
|
```txt
|
|
crm_enquiry
|
|
```
|
|
|
|
linked to:
|
|
|
|
```txt
|
|
crm_leads.id
|
|
```
|
|
|
|
through:
|
|
|
|
```txt
|
|
crm_enquiries.lead_id
|
|
```
|
|
|
|
---
|
|
|
|
Reuse:
|
|
|
|
```txt
|
|
generateNextDocumentCode()
|
|
```
|
|
|
|
with:
|
|
|
|
```txt
|
|
crm_enquiry
|
|
```
|
|
|
|
---
|
|
|
|
Expected:
|
|
|
|
```txt
|
|
EN2606-001
|
|
```
|
|
|
|
or existing enquiry format.
|
|
|
|
No custom numbering logic.
|
|
|
|
---
|
|
|
|
# Scope D5.3.3 Enquiry Bootstrap Mapping
|
|
|
|
When enquiry is created:
|
|
|
|
Copy:
|
|
|
|
```txt
|
|
customerId
|
|
contactId
|
|
projectName
|
|
projectLocation
|
|
productType
|
|
description
|
|
estimatedValue
|
|
priority
|
|
```
|
|
|
|
from Lead.
|
|
|
|
---
|
|
|
|
Do NOT copy:
|
|
|
|
```txt
|
|
marketing-only notes
|
|
internal marketing activity history
|
|
audit events
|
|
```
|
|
|
|
---
|
|
|
|
Lead remains unchanged.
|
|
|
|
---
|
|
|
|
# Scope D5.3.4 Lead Assignment API
|
|
|
|
Create:
|
|
|
|
```txt
|
|
POST /api/crm/leads/[id]/assign
|
|
```
|
|
|
|
---
|
|
|
|
Handler must call:
|
|
|
|
```txt
|
|
Lead Assignment Service
|
|
```
|
|
|
|
No direct DB access.
|
|
|
|
---
|
|
|
|
Response:
|
|
|
|
```ts
|
|
{
|
|
leadId: string;
|
|
enquiryId: string;
|
|
enquiryCode: string;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
# Scope D5.3.5 Ownership Transfer
|
|
|
|
After assignment:
|
|
|
|
Lead:
|
|
|
|
```txt
|
|
status = assigned
|
|
```
|
|
|
|
---
|
|
|
|
Lead:
|
|
|
|
```txt
|
|
assigned_sales_owner_id
|
|
assigned_at
|
|
assigned_by
|
|
```
|
|
|
|
updated.
|
|
|
|
---
|
|
|
|
Enquiry:
|
|
|
|
```txt
|
|
owner_user_id
|
|
```
|
|
|
|
set to assigned salesperson.
|
|
|
|
---
|
|
|
|
Marketing remains able to:
|
|
|
|
```txt
|
|
view lead
|
|
view assignment result
|
|
```
|
|
|
|
but not manage enquiry.
|
|
|
|
---
|
|
|
|
# Scope D5.3.6 CRM Security
|
|
|
|
Reuse:
|
|
|
|
```txt
|
|
resolveCrmMembershipAccess()
|
|
```
|
|
|
|
Assignment permission:
|
|
|
|
```txt
|
|
lead.assign
|
|
```
|
|
|
|
Only:
|
|
|
|
```txt
|
|
Marketing Manager
|
|
CRM Manager
|
|
Admin
|
|
```
|
|
|
|
or equivalent resolved permission.
|
|
|
|
---
|
|
|
|
Do not check role strings directly.
|
|
|
|
---
|
|
|
|
# Scope D5.3.7 Duplicate Protection
|
|
|
|
Prevent:
|
|
|
|
```txt
|
|
multiple enquiry creation
|
|
```
|
|
|
|
for the same assignment action.
|
|
|
|
---
|
|
|
|
Rules:
|
|
|
|
If assignment already produced an active enquiry:
|
|
|
|
```txt
|
|
return existing enquiry
|
|
```
|
|
|
|
instead of creating a second one.
|
|
|
|
---
|
|
|
|
# Scope D5.3.8 Audit Logging
|
|
|
|
Reuse audit foundation.
|
|
|
|
Required actions:
|
|
|
|
```txt
|
|
assign_lead
|
|
create_enquiry_from_lead
|
|
```
|
|
|
|
---
|
|
|
|
Audit must capture:
|
|
|
|
```txt
|
|
leadId
|
|
enquiryId
|
|
salesOwnerId
|
|
```
|
|
|
|
---
|
|
|
|
# Scope D5.3.9 Legacy Compatibility
|
|
|
|
Do not modify:
|
|
|
|
```txt
|
|
quotation flow
|
|
approval flow
|
|
dashboard
|
|
reports
|
|
won/lost process
|
|
```
|
|
|
|
---
|
|
|
|
Current enquiry APIs must continue functioning.
|
|
|
|
---
|
|
|
|
# Deliverables
|
|
|
|
New:
|
|
|
|
```txt
|
|
src/features/crm/leads/server/assignment.service.ts
|
|
```
|
|
|
|
---
|
|
|
|
New API:
|
|
|
|
```txt
|
|
POST /api/crm/leads/[id]/assign
|
|
```
|
|
|
|
---
|
|
|
|
Documentation:
|
|
|
|
```txt
|
|
docs/implementation/task-d53-lead-assignment-create-enquiry-foundation.md
|
|
```
|
|
|
|
---
|
|
|
|
# Verification
|
|
|
|
Run:
|
|
|
|
```txt
|
|
npm exec tsc --noEmit
|
|
```
|
|
|
|
---
|
|
|
|
Verify:
|
|
|
|
```txt
|
|
Assign Lead
|
|
Create Enquiry
|
|
Reuse Existing Enquiry
|
|
Lead Status Update
|
|
Audit Logging
|
|
Security Enforcement
|
|
```
|
|
|
|
---
|
|
|
|
Verify:
|
|
|
|
```txt
|
|
Quotation APIs still work
|
|
Dashboard still works
|
|
Reports still work
|
|
```
|
|
|
|
---
|
|
|
|
# Explicit Non-Scope
|
|
|
|
Do not:
|
|
|
|
* create Lead UI
|
|
* create Opportunity UI
|
|
* create quotation conversion
|
|
* change approval workflow
|
|
* change reports
|
|
* change dashboard
|
|
* migrate historical data
|
|
* implement won/lost synchronization
|
|
|
|
These belong to later D.5 phases.
|
|
|
|
---
|
|
|
|
# Definition of Done
|
|
|
|
Task is complete when:
|
|
|
|
* Lead assignment API exists
|
|
* Assignment creates or reuses enquiry
|
|
* crm_enquiries.lead_id is populated
|
|
* Enquiry owner is assigned salesperson
|
|
* Lead assignment is audited
|
|
* Existing CRM functionality remains unchanged
|
|
|
|
Result:
|
|
|
|
```txt
|
|
Lead Assignment = Established
|
|
|
|
Lead → Enquiry Transition = Established
|
|
|
|
Ready for Opportunity Workspace Separation
|
|
```
|