task-d.5
task-d.5.1
This commit is contained in:
117
docs/adr/0018-lead-enquiry-domain-separation.md
Normal file
117
docs/adr/0018-lead-enquiry-domain-separation.md
Normal file
@@ -0,0 +1,117 @@
|
||||
# ADR 0018: Lead / Enquiry Domain Separation
|
||||
|
||||
## Status
|
||||
|
||||
Proposed
|
||||
|
||||
## Context
|
||||
|
||||
ADR-0011 froze the current CRM lifecycle around a single persisted entity:
|
||||
|
||||
- `crm_enquiries` stores both marketing-owned leads and sales-owned enquiries
|
||||
- `pipeline_stage` acts as the discriminator
|
||||
- navigation separation exists, but domain separation does not
|
||||
|
||||
That model was an intentional stabilization step for Tasks D.3 and D.3.1. It reduced UX ambiguity without forcing a schema split during the first production rollout.
|
||||
|
||||
Task D.5 introduces a stronger business requirement:
|
||||
|
||||
- Marketing owns `Lead` as a dedicated entity
|
||||
- Sales owns `Enquiry` as a dedicated entity
|
||||
- one lead may create many enquiries
|
||||
- sales may also create enquiries directly without a lead
|
||||
- marketing outcome must be derived from sales execution, not manually controlled
|
||||
|
||||
The current single-record model now creates structural ambiguity in at least these areas:
|
||||
|
||||
1. Assignment currently mutates one record from `lead -> enquiry`, which destroys the original lead as a stable marketing record.
|
||||
2. A true `1 Lead -> N Enquiries` relationship cannot be represented cleanly while the lead itself is also the enquiry record.
|
||||
3. Dashboard and report logic still infer lead analytics from `crm_enquiries.pipeline_stage`, which couples marketing and sales datasets.
|
||||
4. Outcome synchronization for marketing is harder to reason about because the source marketing entity does not exist independently.
|
||||
|
||||
## Decision
|
||||
|
||||
We will replace the single-record lead/enquiry persistence model with a split domain model:
|
||||
|
||||
- `crm_leads` becomes the dedicated marketing-owned lead table
|
||||
- `crm_enquiries` remains the dedicated sales-owned enquiry table
|
||||
- `crm_enquiries.lead_id` becomes nullable to support:
|
||||
- lead-origin enquiries
|
||||
- direct sales enquiries with `lead_id = null`
|
||||
|
||||
### Lifecycle
|
||||
|
||||
The target business flow is:
|
||||
|
||||
```txt
|
||||
Lead
|
||||
-> Enquiry
|
||||
-> Quotation
|
||||
-> Won / Lost
|
||||
```
|
||||
|
||||
### Relationship rules
|
||||
|
||||
- `crm_leads 1 -> N crm_enquiries`
|
||||
- `crm_enquiries 1 -> N crm_quotations`
|
||||
- `crm_quotations` remains the owning record for quotation revisions and child resources
|
||||
|
||||
### Ownership rules
|
||||
|
||||
- marketing owns lead creation and lead follow-up
|
||||
- sales owns enquiry creation, enquiry follow-up, quotation generation, and won/lost execution
|
||||
- managers and admins retain cross-workspace monitoring based on resolved CRM access
|
||||
|
||||
### Outcome rules
|
||||
|
||||
- lead outcome is derived, never manually updated
|
||||
- when any linked enquiry becomes won, the lead outcome becomes `won`
|
||||
- when all linked enquiries are lost, the lead outcome becomes `lost`
|
||||
- otherwise the lead outcome remains `open`
|
||||
|
||||
### Sequence rules
|
||||
|
||||
- lead codes use a dedicated lead document sequence
|
||||
- enquiry codes keep a separate enquiry document sequence
|
||||
|
||||
### Reporting and dashboard rules
|
||||
|
||||
- lead KPI and lead reports read from `crm_leads`
|
||||
- enquiry KPI and enquiry reports read from `crm_enquiries`
|
||||
- no report should continue to treat `pipeline_stage` as the marketing/sales entity boundary after migration
|
||||
|
||||
## Consequences
|
||||
|
||||
### Positive
|
||||
|
||||
- aligns persistence with the real marketing-to-sales handoff
|
||||
- supports true `1 Lead -> N Enquiries`
|
||||
- preserves lead identity after assignment
|
||||
- simplifies marketing analytics and awareness-source reporting
|
||||
- makes direct sales enquiries first-class without overloading lead semantics
|
||||
|
||||
### Tradeoffs
|
||||
|
||||
- supersedes a previously accepted ADR and requires broad migration across services, reports, dashboard, and permissions
|
||||
- requires data migration from existing `crm_enquiries.pipeline_stage`
|
||||
- increases temporary compatibility complexity during rollout
|
||||
|
||||
## Migration Strategy
|
||||
|
||||
The migration should be delivered in explicit phases:
|
||||
|
||||
1. Introduce ADR and governance freeze for split-domain direction.
|
||||
2. Add schema and seed support for `crm_leads`, `lead_id`, and lead master options.
|
||||
3. Introduce lead services and lead APIs without deleting enquiry flows.
|
||||
4. Migrate dashboard and reports to separated datasets.
|
||||
5. Remove old single-record assumptions from shared enquiry services and UI.
|
||||
|
||||
## Supersedes
|
||||
|
||||
This ADR is intended to supersede the following sections of ADR-0011 once implemented:
|
||||
|
||||
- `Single record model`
|
||||
- `Pipeline stage model` as the lead/enquiry persistence boundary
|
||||
- `Navigation Separation` as the primary separation mechanism
|
||||
|
||||
Until implementation is complete, ADR-0011 remains the description of current production behavior, while this ADR defines the approved target direction for Task D.5.
|
||||
Reference in New Issue
Block a user