Available for new projects
Book a Call
← Back to Portfolio

Customer Lifecycle Engine

ReactTypeScriptSupabasePostgreSQLPapaParseRecharts

The Challenge

A building materials company had thousands of POS transactions with no reliable way to connect orders to customers. Their point-of-sale system captured phone numbers inconsistently — sometimes with area codes, sometimes without, sometimes with dashes or spaces. Email addresses were optional and rarely collected. The result: thousands of orphaned orders that could not be attributed to any customer profile.

Without customer identity, there was no way to identify repeat buyers, recognize high-value accounts, detect churn risk, or measure customer lifetime value. Aggregate business metrics existed, but they told the story of the business, not of individual customer relationships. Marketing was spray-and-pray because there was no segmentation to target.

The Approach

We built a customer lifecycle engine that starts with the messiest part of the problem: identity resolution. The matching engine uses phone-first E.164 normalization — stripping all formatting, applying country codes, and matching against a canonical phone database. When phone matching fails, it falls back to email matching. Orders that still cannot be matched are queued for manual review with suggested matches ranked by confidence.

Once orders are linked to customer profiles, the enrichment engine calculates behavioral tags: repeat purchaser (2+ orders in 90 days), high-value (top 20% by spend), VIP (both repeat and high-value), and at-risk (no order in 60+ days after being active). These tags update automatically as new orders flow through the pipeline.

The Order Analytics Dashboard surfaces all of this through interactive visualizations — revenue trends, customer segment breakdowns, individual customer profiles with order history, and cohort analysis. Built with React, PapaParse for CSV ingestion, and Recharts for data visualization.

Architecture

Loading diagram...

Data pipeline from POS ingestion through identity matching, behavioral enrichment, and segmentation to the analytics dashboard.

Key Technical Decisions

  • Phone-first E.164 matching — phone numbers are more reliably captured at POS than email addresses. Normalizing to E.164 format before matching eliminates formatting-related false negatives.
  • Behavioral tagging as materialized views — segment tags are computed as database views that refresh on new data, avoiding the complexity of real-time event processing for a batch-oriented use case.
  • customer_type enum — a single enum column (new, repeat, high_value, vip, at_risk) enables simple query filtering across the application without joining to a separate segmentation table.
  • PapaParse for CSV ingestion — client-side CSV parsing keeps the data pipeline simple and avoids server-side file upload infrastructure for the initial import workflow.
  • Recharts over D3 — Recharts provides declarative React components for standard chart types. The dashboard needs bar charts, line charts, and pie charts — not custom visualizations that would justify D3 complexity.

Results

The identity matching engine successfully linked thousands of previously orphaned orders to customer profiles. The phone-first approach achieved a high match rate on first pass, with email fallback catching additional matches. The remaining unmatched orders were flagged for manual review with confidence-ranked suggestions.

For the first time, the business could see which customers were VIPs, which were at risk of churning, and which segments were growing or shrinking. The analytics dashboard became the daily operational tool for sales and management decisions — replacing gut-feel with data-driven customer intelligence.

Need to turn messy data into customer insights? Let's talk.

Start a Conversation
Get in Touch