Files
alla-allaos-fullstack/docs/implementation/task-d53-lead-assignment-create-enquiry-foundation.md
phaichayon 0c28735c90 task-d.5.3
2026-06-24 14:23:15 +07:00

3.4 KiB

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 with:
    • assignLead()
    • internal createEnquiryFromLead()
  • Added 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.