v2 · Normalized SQLite schema, executable CRM logic, operational UI

A synthetic Lead → Revenue prototype: CRM lifecycle, funnel math, forecasting, attribution, an AI copilot, and a read-only CRM UI

Every number on this page is computed by Python reading a 2,080-lead synthetic dataset in a normalized 6-table SQLite database — not typed in by hand. v1 of this project was a flat CSV and three scripts; v2 rebuilt it as a real relational schema with executable routing/lifecycle/scoring logic, multi-touch attribution, an ICP engine, an AI RevOps copilot, and — newest — a full operational CRM UI styled in Salesforce Lightning's visual language, built on top of the signal-scoring logic from my Clay enrichment-waterfall project.

revenue-engine-demo— Python + SQLite + Streamlit, deterministic seed, zero paid infra
Synthetic data

100% synthetic — no real prior-employer or client data anywhere in this repo.

Try the operational CRM live

Salesforce Lightning-styled: global header, app tab bar, list views with filters/search/pagination, a Kanban pipeline board, record detail pages with a Path stepper and activity timeline. Read-only, seeded with the same 2,080-lead dataset as everything below.

Live demo →  ·  source: crm_app.py  ·  run it yourself: streamlit run crm_app.py

Why this, not a live CRM screenshot

I don't have a real book of business to show — the closest thing I ever ran was a prior role's pipeline, and that data isn't mine to publish post-termination. What I can show honestly is the actual competency underneath "CRM experience" on a job description: a normalized relational schema, a lead lifecycle with real stage gates and SLAs enforced as code (not just documented), routing logic that's tested to actually balance load, multi-touch attribution across four models, a forecast that's honest about its own uncertainty, and — because reporting alone isn't a CRM — an operational surface a rep would actually work in day to day. A synthetic dataset, built and disclosed as such, is the honest way to demonstrate all of it.

The funnel

Computed by src/analytics/funnel.py reading data/revenue_engine.db, 2,080 leads across 1,906 accounts.

Total leads
2,080
Lead → Won
1.01%
Synthetic won MRR
$36,050
Avg cycle
31.5d
Pipeline coverage
7.51×
stage-wise conversion & drop-off
transitionfromtoconversionvs. benchmark
Lead → MQL2,08099547.8%within (35–55%)
MQL → SQL99524124.2%within (20–25%)
SQL → Opportunity24110443.2%within (30–50%)
Opportunity → Closed Won1042120.2%below (25–35%)

Three of four transitions land inside the published 2025–2026 SMB benchmark range; Opportunity→Won runs below it (20.2% vs. a 25–35% range). That's flagged, not smoothed over — it's exactly the kind of signal the Home tab's "Needs Attention" panel and the AI Copilot's "which stage is underperforming" question are built to surface, and the forecast's win-rate bounds are widened to 15–35% specifically because this stage's real performance sits below the naive benchmark midpoint.

The CRM system behind the data

Design: crm-system-design.md. Enforcement: src/crm/lifecycle.py and src/crm/routing.py — this is executable code, not just a design doc.

stageexit criteria (raises if missing)SLA
LeadSignal score ≥ 3.0Scored within 1 hour (automated)
MQLRep confirms budget/authority/need/timingActioned within 6 business hours
SQLDiscovery call completed, deal shape documentedCall booked within 3 business days
Opportunitydeal_value_monthly_usd requiredFollow-up every 5 business days
Closed Won/LostHandoff to CS / lost_reason requiredHandoff within 24 hours

Lead routing is a weighted round-robin with a signal-score fast lane: leads scoring ≥8.0 skip the queue and route to whoever has the lowest open-SQL load. This isn't just asserted — tests/test_analytics.py checks it directly: rep-level lead counts land within 1.7% of an even three-way split across all 2,080 leads (683 / 692 / 705).

Segmentation that changes real behavior

Accounts score 0–100 on category + firmographic + signal fit (src/segmentation/icp.py), bucketing into Beachhead / Core ICP / Adjacent / Poor Fit. Beachhead accounts convert at 4.3× Core ICP's Lead→Won rate (1.62% vs. 0.38%, on 1,109 vs. 799 leads) — the segmentation actually moves the funnel numbers, it isn't just a label on a report.

Multi-touch attribution — the models disagree, on purpose

Full file: src/analytics/attribution.py — first-touch, last-touch, linear, and U-shaped (40/20/40) over ~8,400 timestamped multi-touch activities.

First-touch and linear both credit Outbound LinkedIn as the top channel ($14,050 / $11,498 attributed MRR), but last-touch credits Signal-scored inbound instead ($9,950) — which channel "wins" depends on which attribution model a RevOps team chooses to trust, a real strategy decision this demo makes visible instead of picking one model and hiding the disagreement.

The forecast — two methods, three scenarios

Full file: src/analytics/forecasting.py. Close probabilities come from this dataset's own SQL→Opportunity→Won history, not a generic industry assumption.

stage-weighted forecast — current open pipeline
scenariowin ratenew MRR
Worst15%$21,570
Expected20.2% (measured)$29,048
Best35%$50,330

Win-rate bounds are the published SMB high-velocity range (15–35%) — widened rather than centered on the benchmark midpoint, because this dataset's own measured Opportunity→Won rate (20.2%) already runs below the naive 25–35% benchmark range, per the funnel table above.

monthly cohort projection — Aug–Oct 2026
monthproj. leadsproj. oppnew MRR (worst/expected/best)
2026-0846723$5.0K / $8.3K / $13.3K
2026-0949625$6.7K / $8.3K / $15.0K
2026-1052726$6.7K / $8.3K / $15.0K

An AI copilot that never fabricates

The Einstein Copilot tab answers four canonical RevOps questions ("why is pipeline down," "which stage is underperforming," "where should sales focus," "which segment converts best") by reading the exact JSON payload above — a real Claude API call if a key is supplied in the sidebar (never persisted), or an honestly-labeled deterministic analyst engine if not. Same output schema either way; the "why is pipeline down" handler explicitly checks whether pipeline is actually declining before answering, so a low-volume partial month can't fool it into reporting a false decline. Full file: src/copilot/revops_copilot.py.

Dashboards

Two: an interactive Streamlit analytics dashboard (7 tabs — overview, funnel, forecast, attribution, ICP/segments, rep pipeline, AI copilot) and a self-contained static HTML fallback for no-install viewing. Both read the same computed JSON as the CRM UI, so nothing can ever disagree on a number.

Open the static dashboard →

What's not built (named, not hidden)

Sources

Funnel, pipeline-coverage, and forecasting benchmarks, 2025–2026:

2025 B2B SaaS Funnel Benchmarks — Digital Bloom
MQL→SQL Conversion Rates by Industry (2026) — Data-Mania
Lead Conversion Rate Benchmarks 2026 — Prospeo
B2B Sales Funnel Stages: 2026 Guide — Prospeo
Pipeline Coverage Ratio — Landbase
Healthy Pipeline Coverage — Salesmotion
Pipeline Coverage Ratio — Clari
Sales Pipeline Coverage: Formula, Ratios & Forecast Impact — Forecastio

Why I built this

Every other demo in this portfolio (signal-engine-demo, account-brief-demo, gtm-warehouse-demo) proves out one piece of a GTM system — scoring, briefing, warehousing. This is the piece that was missing: what happens after a signal becomes a lead, all the way through to the screen a rep actually works in every day. A CRM lifecycle it can move through, funnel math that tells you where it's dying, attribution that's honest about model disagreement, a forecast that's honest about its own uncertainty, and an operational UI on top of all of it.

Let's talk