task-d.5.3

This commit is contained in:
phaichayon
2026-06-24 14:23:15 +07:00
parent 350239b307
commit 0c28735c90
61 changed files with 11019 additions and 173 deletions

View File

@@ -0,0 +1,108 @@
# Task D.5.3: Lead Assignment -> Create Enquiry Foundation
## Objective
Establish the first production lead-assignment flow that preserves `crm_leads` as the
marketing-owned source record while creating or reusing a linked `crm_enquiries` record for the
sales execution workspace.
## Review Completed
- `AGENTS.md`
- `docs/standards/project-foundations.md`
- `docs/standards/task-catalog.md`
- `docs/adr/0018-lead-enquiry-domain-separation.md`
- `docs/implementation/task-d5-lead-enquiry-domain-separation.md`
- `docs/implementation/task-d52-lead-domain-service-api-foundation.md`
- `docs/security/crm-authorization-boundaries.md`
- `src/features/crm/leads/server/service.ts`
- `src/features/crm/enquiries/server/service.ts`
- `src/features/crm/customers/server/service.ts`
- `src/features/foundation/audit-log/service.ts`
- `src/features/foundation/document-sequence/service.ts`
## What Changed
- Added lead bootstrap and assignment fields to `crm_leads`:
- `description`
- `product_type`
- `priority`
- `estimated_value`
- `assigned_sales_owner_id`
- `assigned_at`
- `assigned_by`
- `assignment_remark`
- Added [assignment.service.ts](C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/features/crm/leads/server/assignment.service.ts)
with:
- `assignLead()`
- internal `createEnquiryFromLead()`
- Added [route.ts](C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/app/api/crm/leads/[id]/assign/route.ts)
for `POST /api/crm/leads/[id]/assign`
- Extended lead DTOs and schemas so new lead records can carry the data needed to bootstrap an
enquiry
- Added `assigned` to seeded `crm_lead_status`
- Tightened enquiry-owner validation so assignees must be sales-assignable members, not merely any
organization member
## Assignment Behavior
- route permission is `crm.lead.assign`
- service validates:
- lead exists and is active
- actor can access the lead through resolved CRM scope
- assignee belongs to the same organization and is a sales-assignable member
- if an active enquiry already exists for the lead:
- no second enquiry is created
- the existing enquiry is returned
- lead assignment metadata is synchronized
- if no active enquiry exists:
- enquiry code generation reuses `generateNextDocumentCode()` with `documentType = crm_enquiry`
- enquiry is created with `lead_id = crm_leads.id`
- enquiry owner compatibility fields use the existing enquiry model:
- `assigned_to_user_id`
- `assigned_at`
- `assigned_by`
- `assignment_remark`
## Lead -> Enquiry Bootstrap Mapping
When creating the enquiry from a lead, the flow copies:
- `customerId`
- `contactId`
- `description`
- `projectName`
- `projectLocation`
- `productType`
- `estimatedValue`
- `priority`
The enquiry title is derived from `lead.projectName` and falls back to `Lead <code>` when the
project name is empty.
## Audit Actions
This task records:
- `assign_lead` on `crm_lead`
- `create_enquiry_from_lead` on `crm_enquiry`
Captured linkage includes:
- `leadId`
- `enquiryId`
- `salesOwnerId`
## Compatibility Notes
This task intentionally does not change:
- quotation flows
- approval flows
- dashboard datasets
- reporting datasets
- won/lost lifecycle flows
- legacy enquiry list/detail APIs outside the stricter assignee validation
`crm_enquiries.pipeline_stage` remains in place for compatibility, but lead assignment now creates a
dedicated enquiry record instead of mutating a lead record in place.