Case study · BillGill · built & shipped end to end

Two call providers. One truth.

Sales teams that live on the phone often run two telephony systems at once — SIM-based call tracking on field phones and a cloud dialer in the office. The numbers never agree, and managers reconcile them in spreadsheets. BillGill ingests both feeds, detects when they report the same physical call, and turns 90 days of raw call logs into leaderboards, scorecards and payroll-grade cost analysis.

2 providers, deduplicated
syncs every 5 minutes
on-device speech → sentiment
BillGill day-wise analysis: total versus connected calls per day over thirty days
30 days of calls vs connections — Sunday dips and one bad week, visible at a glance
01

Ninety seconds through the console

Recorded against a locally running instance seeded with 11,000+ fictional calls replayed through the real webhook receivers — every number on screen was computed by the production pipeline, not mocked.

Animated tour: dashboard, day-wise and hourly analytics, CBO scorecard with grades, employee leaderboard and per-rep drill-down

All employees, phone numbers and amounts are fictional demo data. Click any screenshot to enlarge it.

02

The screens managers live in

Click through the six screens managers actually live in — every number computed by the real pipeline from the seeded demo dataset. Click a screenshot to enlarge it.

03

Under the hood

87
API endpoints across analytics, admin, ingestion and a keyed public API
23k
lines of application code — FastAPI backend + Next.js frontend
12
dashboard screens from leaderboards to identity reconciliation
10s
time window used to catch the same call reported by both providers

Cross-source deduplication

The two providers report the same physical call with different client numbers. Matching on employee, date and a 10-second timestamp window flags duplicates, and every analytics query excludes them — so totals never double-count.

Identity resolution as a feature

A rep exists twice — once per provider, under different names. A dedicated Data Management screen links, merges and scores the mapping, with orphan-name detection and a data-quality percentage.

Self-healing ingestion

Pollers run every 5–10 minutes; a nightly reconciler compares local counts against the provider's own summary and automatically backfills whenever drift exceeds 5%. Backfills are checkpointed and resumable.

Speech intelligence at zero API cost

Call recordings run through on-device Whisper, Hindi/Kannada→English translation and sentiment/topic analysis — offloaded to worker threads after inline inference was found blocking the event loop on a 1-vCPU box.

Grades, not just numbers

The CBO scorecard composites effort (calls, connects, active days) and outcomes (registrations, fees, loans) normalised against the team's p95 into A–D grades — so a manager reads one letter, then argues with the detail.

A second, safer front door

External consumers get a separate read-only API with per-consumer static keys, constant-time comparison, per-resource field allowlists — and it fails closed with 503 when unconfigured.

Stack · Python · FastAPI · SQLAlchemy (async) · PostgreSQL 16 · APScheduler · faster-whisper · Next.js 16 · React 19 · Tailwind + shadcn/ui · Recharts · Docker Compose