Skip to content

About

FunnelLens: a data analyst case study on a messy e-commerce funnel (pandas, DuckDB SQL or tidyverse): data contract, confounder-adjusted tests, three-track parity, CI, a Dockerised dashboard with a guard-railed AI narrator, monitoring and a post-mortem. main = starter, solution = reference with per-phase tags.

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

FunnelLens: a data analyst case study on a messy e-commerce funnel, with AI as your pair analyst

CI CI (solution)

FunnelLens is a guided project from AiCanCode, the capstone of the Data Analyst track. Over 9 phases (about 32 hours) you carry one messy dataset the whole way, the way a professional analytics team does: requirements, a data contract and an analysis plan, a test-first implementation, data tests, CI, a containerised dashboard, monitoring after a data refresh, and a retrospective. AI assistants help at every step, and you verify every number they produce.

The situation. You are the first analyst at FunnelLens, a mid-sized Indian e-commerce company. Mobile is about 69 % of sessions but only about 61 % of revenue. The Head of Product is sure the mobile checkout is at fault and wants to rebuild it: a quarter of engineering time. Your job is not to agree or disagree. It is to find out what the data supports, and to say so clearly enough that a decision can be made.

The data. A six-month export (a 1-in-20 sample of sessions) in four deliberately imperfect CSVs, with the problems real exports have: duplicate and conflicting session ids, two date formats, amounts as text with rupee signs and thousands separators, inconsistent city spellings, missing signup channels, out-of-order funnel events and orders without a checkout.

Table Raw rows Known problems
sessions.csv 27,515 exact duplicates, conflicting ids, mixed date formats, out-of-period rows, unknown channels
events.csv 40,031 unknown event names, orphan events, repeated and out-of-order steps
orders.csv 2,522 amounts like ₹1,299.00 / Rs. 1,299 / -₹499, duplicates, orphan orders
users.csv 5,986 ~9 % missing signup channel, Bangalore / bengaluru / BENGALURU

What you deliver: an analysis that runs top to bottom from a clean checkout (a notebook, SQL report or R Markdown report), an answers.json that matches the shared contract, a one-page decision memo, and a dashboard. It is judged not on whether you agree with the Head of Product, but on whether the conclusion follows from the evidence and whether you were honest about what you could not establish.

Pick one track. The data, the contract, the golden answers and the dashboard are shared; only the analysis code differs, and the three tracks must produce the same numbers to 1e-9.

Track Stack Folder
Python Python 3.11+ · pandas · Jupyter · SciPy · statsmodels · pytest · ruff tracks/python
SQL DuckDB SQL (views you can query step by step) · sqlfluff · a thin Python runner · pytest tracks/sql
R R 4.3+ · tidyverse (dplyr, tidyr, readr, stringr) · base stats · R Markdown · testthat · covr · lintr tracks/r

The dashboard (dashboard/) is a small Streamlit app that reads any track's answers.json. Its optional AI narrator sees only numbered aggregate facts and is checked by guardrails; offline, it falls back to a deterministic template. Everything runs on your laptop, with no API key and no paid service.

Course repository: https://github.com/AICanCode-org/analyst-case-study (main = starter, solution = reference).


Repository layout

.
├── README.md                 ← you are here
├── AI_LOG.md                 ← your log of AI prompts, outputs and how you verified them
├── docs/                     ← the course: phase-0 … phase-8 + GitHub Actions explained
├── spec/                     ← requirements, analysis plan, ADRs (you write them in Phases 1-2)
├── contract/                 ← the shared contract: questions.md (every rule and formula), data-contract.yaml,
│                               answers.schema.json, the tiny fixture, stats cases and the golden answers
├── data/raw/2026-06/         ← the export (CSV + export.json), generated by scripts/generate_data.py
├── tracks/{python,sql,r}/    ← analysis code + tests (same Makefile targets in each)
├── dashboard/                ← the shared Streamlit dashboard + AI narrator
├── scripts/                  ← doctor.sh, check-all.sh, verify-tags.sh, build-cms.py, parity.py,
│                               generate_data.py (+ smoke-test.sh from Phase 6)
├── cms/                      ← machine-readable export of the course for the AiCanCode site
└── .github/                  ← CI workflows, issue/PR templates

Prerequisites (per operating system)

You need Git, make and Python 3.11+ (the scripts, the SQL runner and the dashboard use it) plus the toolchain of one track. Docker is needed from Phase 6. Run scripts/doctor.sh at any time.

Windows 10/11 macOS Linux (Ubuntu/Debian)
Shell WSL2 with Ubuntu: wsl --install in an admin PowerShell, reboot Terminal (zsh) any
Git, make inside WSL: sudo apt install git make xcode-select --install sudo apt install git make
Python (all tracks) inside WSL: sudo apt install python3 python3-venv brew install python@3.12 sudo apt install python3 python3-venv
R track inside WSL: sudo apt install r-base pandoc (or R + RStudio on Windows) R from CRAN + RStudio (pandoc included) sudo apt install r-base pandoc
Docker (Phase 6+) Docker Desktop with the WSL 2 engine Docker Desktop (or Colima) Docker Engine + compose plugin

Windows, important: clone and work inside the WSL file system (~/code/analyst-case-study), not under /mnt/c/.... Hardware: 8 GB RAM is plenty; the export is small on purpose.

Quick start (5 minutes)

git clone https://github.com/<you>/analyst-case-study.git && cd analyst-case-study   # your fork (Phase 0)
scripts/doctor.sh                        # check your tools
cd tracks/python                         # or tracks/sql, tracks/r
make install                             # dependencies (Python/SQL: creates .venv)
make lint test                           # all tests are "pending" (skipped) until Phase 3
python3 ../../scripts/generate_data.py --check   # the export in data/raw is exactly the published one

Every track offers the same commands:

Command What it does
make install install dependencies
make lint linter + formatter check (ruff / ruff + sqlfluff / lintr)
make test unit tests on the tiny hand-made fixture (seconds)
make coverage unit + data tests on the real export, with an 85 % line-coverage gate
make run write out/answers.json for one export (DATA=../../data/raw/2026-06)
make report execute the notebook / SQL report / R Markdown report top to bottom

Compare two tracks (or yours with the golden file): python3 scripts/parity.py contract/golden/answers-2026-06.json tracks/python/out/answers.json.

How the phases work

Phase Topic You end at tag
0 Setup and the brief phase-0-end
1 Requirements: questions, decisions and acceptance criteria phase-1-end
2 Design: data contract, analysis plan and ADRs phase-2-end
3 Implementation in five milestones: load, clean, explore, test, decide phase-3-end
4 Testing the analysis: golden answers, invariants, parity, coverage phase-4-end
5 CI with GitHub Actions phase-5-end
6 Dashboard, AI narrator, Docker and delivery phase-6-end = v1.0.0
7 Data refresh, monitoring and a post-mortem phase-7-end = v1.1.0
8 Retrospective and portfolio phase-8-end

Each phase page has the same 8 blocks: Why it matters · Objectives · Step-by-step instructions · AI-assist prompts · Deliverables · Self-check quiz · What you learned · Catch-up git commands.

Branches and tags

  • main: the starter. Every track has its structure, the full (pending) test suite and a TODO with a hint in every function or SQL view; the notebook and the R Markdown report are skeletons with the questions and no answers.
  • solution: the reference, one or more commits per phase, an annotated tag at the end of every phase (phase-0-end … phase-8-end) and the releases v1.0.0 and v1.1.0. Every tag passes the checks of all three tracks.

Stuck or behind? Start the next phase from the reference end of the previous one:

git fetch upstream --tags
git switch -c my-phase-4 phase-3-end

Compare with the reference: git diff phase-3-end -- tracks/python. Try first, then compare.

Pending tests

The complete test suite is already on main but switched off in one list per track (tests/conftest.py for Python and SQL, tests/testthat/helper-funnellens.R for R). In Phase 3 you remove one entry at a time, watch the tests fail, and make them pass. Skipped is never reported as passed.

Working with AI

Use any assistant you like. Each phase has copy-paste prompts and a "Verify the output by" checklist; log what you asked and how you checked it in AI_LOG.md. Two rules matter most in analysis work: never paste row-level customer data or secrets into a prompt (aggregates and your own code are fine), and never accept a number, a formula or a statistical claim from an assistant without reproducing it: the golden answers, the stats cases and the other tracks are there to check it.

Coming from the old five-step guide?

The earlier version (Brief · Load and Clean · Explore · Test a Hypothesis · Present) had the right story but no data, no tests and no way to know if your numbers were right. This version ships the data, a contract with every rule written down, golden answers, three tracks that check each other, CI, a dashboard and a data refresh. The mapping of the old steps is in docs/README.md.

More

Questions or problems: open an issue using the templates, or contact us via https://www.aicancode.org/contact.

About

FunnelLens: a data analyst case study on a messy e-commerce funnel (pandas, DuckDB SQL or tidyverse): data contract, confounder-adjusted tests, three-track parity, CI, a Dockerised dashboard with a guard-railed AI narrator, monitoring and a post-mortem. main = starter, solution = reference with per-phase tags.

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages