Engineering & Architecture · 6 min read · Aug 21, 2026

Solving the Multi-Lifecycle CRM Lead Dilemma: Why Overwriting 'Won' Leads Destroys Analytics

How we solved the classic WhatsApp CRM conflict between active lead pipelines and historical conversion analytics using a multi-lifecycle ledger and 24h rollback protection.

AR
AR-Inbox Engineering Team
Core Architecture
Builds the lead pipeline, conversion ledger and inbox internals behind AR-Inbox.
Share:

Too Long? Read This in 10 Seconds

Executive bullet points for fast decision-making

  • Core Conflict: Moving a converted customer back to 'New' drops historical Won counts by 1 in snapshot-based CRMs.
  • Ledger Architecture: AR-Inbox logs every won milestone into an immutable lead_conversions table with is_repeat flags.
  • 24h Mistake Rollback: Accidental 'Won' clicks can be corrected within 24 hours to automatically void conversions and clean tags.
  • Auto-Triage & Badges: Returning won customers are auto-tagged #repeat_lead, moved to active pipeline, and badged in real-time.
  • Protected Insights: Lifetime Won metrics and Repeat Conversion Rates (%) remain 100% mathematically accurate across all date ranges.

1. The Classic CRM Dilemma: State vs. History#

In modern WhatsApp-first CRMs, customer communication is continuous and long-term. Unlike traditional email tickets that open and close in isolation, a single WhatsApp contact number represents a permanent relationship that evolves over months and years.

When a customer inquires about a service, negotiates, and completes a booking, the sales executive marks the lead stage as WON and closes the chat. The conversion is logged in the CRM’s analytics dashboard.

The Problem#

Three weeks later, the exact same customer sends a new message: "Hi, I want to book another test for my family."

This creates a fundamental architectural dilemma:

  1. If you change their stage from WonNew: The contact is moved to the top of the funnel so the sales team can work on the new inquiry. But because the contact is no longer in Won, your past monthly conversion numbers drop by 1. Historical insights are corrupted.
  2. If you KEEP their stage as Won: Past conversion analytics remain safe, but the contact stays trapped in the closed Won column. The sales executive never sees them in the active leads pipeline, and the new sale is lost.
  3. What if an executive accidentally marks someone Won?: Sales reps make mistakes. If an executive accidentally clicks Won and immediately moves them back to Proposal, the system must undo the conversion without permanently skewing business metrics.

2. The Architectural Solution: 3-Pillar Ledger Design#

To solve this permanently, we designed a Multi-Lifecycle Conversion System inspired by enterprise financial ledgers and event sourcing principles:

flowchart TD
    %% Initial Lead Journey
    subgraph Lead_First_Cycle["1. First-Time Customer Journey"]
        A["New Inbound Lead (+919599110203)"] --> B["Stage: Proposal / Negotiation"]
        B -->|Executive closes booking| C["Executive marks WON"]
        C --> D["1. Create 'lead_conversions' Row
(is_repeat: false)"] D --> E["2. Stamp Tag: #won_customer"] E --> F["3. Close Conversation"] end %% Accidental Rollback subgraph Mistake_Rollback["Accidental Won Rollback (Within 24 Hours)"] C -.->|Accidental click within 24h| M["Executive moves Won to Proposal/Lost"] M --> M1["Soft-delete latest 'lead_conversions' row"] M1 --> M2["Remove #won_customer tag"] M2 --> M3["Insights & Stats 100% Cleaned"] end %% N-th Repeat Cycle subgraph Repeat_Cycle["2. N-th Repeat Inquiry (Customer Returns Later)"] F -->|Customer sends new WhatsApp msg| R1["Inbound Message Arrives"] R1 --> R2{"Has previous Won conversions?"} R2 -->|YES| R3["1. Keep #won_customer permanently"] R3 --> R4["2. Add Tag: #repeat_lead"] R4 --> R5["3. Move Active Stage: 'New'"] R5 --> R6["4. Reopen Conversation (unread: 1)"] end %% Second & N-th Conversion subgraph Nth_Won_Conversion["3. N-th Won Booking (Repeat Deal Closed)"] R6 -->|Executive closes 2nd/3rd booking| N1["Executive marks WON again"] N1 --> N2["Create new 'lead_conversions' Row
(is_repeat: true)"] N2 --> N3["Close Chat & Ready for next repeat!"] end %% Inbox & Insights State subgraph State_And_Insights["4. Real-Time Inbox State & Lead Insights"] R6 --> UI1["Left Rail Card:
New · Won · Repeat"] R6 --> UI2["Chat Header:
Won Customer (N deals) · Repeat Lead"] D --> DB[("Database Table:
lead_conversions")] N2 --> DB DB --> STATS["Lead Pipeline Insights Dashboard"] STATS --> K1["Won Deals: Total Lifetime Conversions"] STATS --> K2["Repeat Leads: Count of is_repeat = true"] STATS --> K3["Repeat Rate: (Repeat / Won) x 100"] end classDef primary fill:#e0f2fe,stroke:#0284c7,stroke-width:2px,color:#0f172a; classDef success fill:#dcfce7,stroke:#16a34a,stroke-width:2px,color:#0f172a; classDef warning fill:#fef3c7,stroke:#d97706,stroke-width:2px,color:#0f172a; classDef dark fill:#1e293b,stroke:#475569,stroke-width:2px,color:#f8fafc; class A,B,R1,R5,UI1,UI2 primary; class C,D,E,F,N1,N2,N3,K1,K2,K3 success; class M,M1,M2,M3 warning; class DB,STATS dark;

3. Deep-Dive: How Each Layer Works#

Layer 1: Dedicated Conversion Ledger (lead_conversions)#

Instead of calculating Won conversions from a snapshot of contacts.lead_stage_id, every won milestone is logged into a dedicated immutable conversion ledger:

LeadConversion::create([
    'merchant_id'   => $contact->merchant_id,
    'contact_id'    => $contact->id,
    'lead_stage_id' => $wonStage->id,
    'user_id'       => $actor?->id,
    'camp_id'       => $contact->latestMessage?->camp_id,
    'is_repeat'     => $existingConversionsCount > 0,
    'converted_at'  => now(),
]);
  • When a contact converts for the first time: is_repeat = false.
  • When the same contact converts for the 2nd, 3rd, or 10th time: is_repeat = true.
  • Analytics Guarantee: The conversion timestamp is permanently preserved. When the contact later moves to another stage, their historical conversion records remain intact.

Layer 2: 24-Hour Accidental Mistake Rollback#

Sales reps occasionally click the wrong stage. To prevent dirty analytics without requiring complex admin override tools, we implemented an automated 24-hour rollback rule:

  • If an executive moves a contact from WONProposal / Lost within 24 hours of marking them Won:
    1. The system detects an accidental click correction.
    2. It soft-deletes the recent lead_conversions record.
    3. If the contact has no other active conversions, it strips the #won_customer and #repeat_lead tags.
    4. Lead Insights are instantly corrected to their pristine state.

Layer 3: Automated Inbound Re-Engagement & Tagging#

When an existing won customer sends a new message weeks or months later:

  1. Permanent Customer Status: The #won_customer tag is retained.
  2. Re-engagement Tag: The #repeat_lead tag is added to contact.tags.
  3. Pipeline Activation: The active stage transitions from WonNew (or to the specific campaign stage if they clicked a WhatsApp quick reply button).
  4. Thread Re-opening: closed_at is cleared and unread_count increments to 1.

4. Customer Lifecycle State Matrix (1st to N-th Conversion)#

Event / Scenario Contact Stage Contact Tags Chat State lead_conversions Rows Insights Card
1. First Inbound New [] Open 0 rows In Play: +1
2. 1st Booking Won Won [#won_customer] Closed 1st Row (is_repeat: 0) Won: 1, Repeat: 0
3. Accidental Undo (<24h) Proposal [] Open Row Soft-Deleted Won: 0 (Clean Rollback)
4. Returns 1 month later New (re-opened) [#won_customer, #repeat_lead] Reopened (unread: 1) 1st Row Preserved Won: 1 (100% Safe)
5. 2nd Booking Won Won [#won_customer] Closed 2nd Row (is_repeat: 1) Won: 2, Repeat: 1
6. Returns 3rd time New (re-opened) [#won_customer, #repeat_lead] Reopened (unread: 1) 2 Rows Preserved Won: 2, Repeat: 1
7. 3rd Booking Won Won [#won_customer] Closed 3rd Row (is_repeat: 1) Won: 3, Repeat: 2

5. UI Impact for Sales Executives & Business Owners#

1. Left Rail Conversation List#

Executives scanning the inbox see visual pill indicators immediately:

  • [● New] Active inquiry status
  • [👑 Won] Converted customer milestone
  • [🔁 Repeat] Repeat buyer badge

2. Live Chat Header Bar#

When the thread is opened, the top action bar provides complete historical context:

  • 👑 Won Customer [2 deals]
  • 🔁 Repeat Lead

3. Lead Pipeline Analytics Dashboard#

The analytics view at /stats breaks down performance with mathematical precision:

  • 🏆 Won Deals: Total lifetime deals closed in the selected date range.
  • 🔁 Repeat Leads: Number of repeat deals won from existing customers.
  • 📈 Repeat Rate (%): Percentage of won deals that originated from returning buyers (repeat ÷ won × 100).

6. Key Takeaways#

  1. Never use active stage columns as historical records: Active stage represents current intent; conversions represent historical milestones. Separating them eliminates data corruption.

  2. Design for mistake tolerance: A simple 24-hour grace window prevents accidental clicks from permanently polluting analytics without adding cumbersome confirmation dialogs.

  3. Context is king in messaging CRMs: Visual badges (👑 Won Customer [N deals] and 🔁 Repeat Lead) empower sales executives to offer personalized VIP service to returning high-value customers.

Frequently asked questions

What happens to past conversion numbers when a won lead becomes active again? +

Nothing. Conversions live in a dedicated lead_conversions ledger with a permanent converted_at timestamp, so moving the contact back to an active stage never removes the historical row.

How does the 24-hour rollback work? +

If a contact is moved out of Won within 24 hours of being marked Won, the system treats it as a misclick: it soft-deletes the recent conversion row and, when no other active conversion remains, strips the #won_customer and #repeat_lead tags.

Does a returning customer create a duplicate contact? +

No. The existing contact is reopened, keeps #won_customer, gains #repeat_lead, and its stage moves back to New while every earlier conversion row is preserved.

How are repeat conversions counted separately? +

Each conversion row carries an is_repeat flag: false on the first conversion for that contact and true on every later one, so Won and Repeat can be reported independently.

WhatsApp policies, limits and pricing change often. This article was last reviewed on Aug 21, 2026 and is scheduled for its next review on Nov 21, 2026.

Related Articles