← Back to Work
006 / Case Study

Turning Raw Dev Data into Team Clarity

A founder managing eight nearshore contractors across three Jira projects had sprint data, time logs, and pull requests scattered across three platforms. The data existed. What didn't exist was a way to look at all of it at once and know what was actually happening.

Timeline
Q1 2026 (4 weeks)
Role
AI Implementation
Tools
Next.js, Supabase, Jira API, GitHub API, TMetric

The Brief

The ask was one sentence: "I want to see what my team is doing." No wireframes, no feature list, no acceptance criteria. Just a founder watching sprint after sprint close without a clear picture of velocity, blockers, or where work was getting stuck. Eight developers spread across Mexico and Colombia, three active Jira projects, hours logged in TMetric, code shipping through GitHub. The information was all there. Nobody had stitched it together.

That one sentence isn't a spec. It's a problem statement. The first week was spent translating it into something buildable: what does "see" mean, at what granularity, and which decisions does the answer need to support? The spec I wrote was the answer to those questions, documented so I could build against it and the founder could correct it.

The Real Problem

Jira had the tickets. TMetric had the hours. GitHub had the pull requests. Three separate systems, three separate logins, three separate mental models. The problem was never a lack of data. It was a lack of synthesis.

The three Jira projects ran on overlapping sprint cadences. One project used three-week sprints; the other two had their own rhythms. Sprint timelines didn't map cleanly to calendar weeks. Time entries in TMetric weren't always keyed to specific tickets. GitHub PRs had no link back to who reviewed them or how long they sat before someone picked them up. There was no way to distinguish "this ticket is stuck in code review because the reviewer is swamped" from "this was finished Friday and is waiting to deploy."

What the founder needed wasn't a report. It was a place where pattern recognition happens automatically and the things that need attention surface themselves.

The Data Pipeline

Before any interface work, the engagement started with plumbing. Four Python scripts pulling from Jira's REST API, TMetric's workspace API, and GitHub's GraphQL API, normalizing the data, and writing it to Supabase. One script synced sprint metadata, tickets, assignees, story points, and impediment flags. Another reconstructed each ticket's full stage history, calculating time spent in each phase: In Progress, Code Review, QA, Done. A third imported time entries per developer, linked back to ticket keys. The fourth pulled all PRs from the GitHub org and enriched them with lines changed, reviewer assignments, and merge times.

The schema was designed for temporal queries. Every metric is computable from a date range, not just aggregated all-time. This matters when the question is "what happened this sprint" rather than "what has ever happened."

Sprint Grouping

The trickiest design problem wasn't visual. Three projects running overlapping sprint cadences meant that treating sprints independently would fracture the view, and combining them naively would produce noise. Neither option gives the founder what he actually needs: a single coherent window into what the team is doing right now.

The solution was a sprint grouping algorithm. Anchor-based, with a four-day proximity threshold, it clusters concurrent sprints across projects into a single "sprint group." The sidebar exposes these groups as a selector. Navigating to a group scopes every view, the sprint table, the developer summary, the bottlenecks panel, to the correct cross-project ticket set. One click, one context.

A constraint I enforced early: never parse sprint name strings to infer dates. Always use the start and end date fields from Jira's API. Sprint names are inconsistent, sometimes translated, occasionally misspelled. They're a trap.

The Dashboard

The frontend is a Next.js application, dark-themed, role-gated for manager and developer views. The main sprint overview is a sortable, filterable ticket table with status badges normalized across all three projects' naming conventions ("Code Review," "code_review," and "CR" all resolve to the same badge), an impediment flag column surfacing tickets marked as blocked in Jira, and a carry-over indicator for tickets that survived a sprint boundary without completing.

Each ticket row includes a health indicator computed from time in code review, time in QA, review returns, and QA rejections. Click any row and a detail panel slides open showing the full stage timeline, hours logged, lines changed, and PR information.

Developer summary cards show one card per active team member: tickets closed, bugs filed, hours logged, lines changed, average code review turnaround, QA rejection rate, carry-over count, and last active date. All metrics are scoped to the selected sprint group. A bottlenecks view surfaces tickets that have been sitting in code review or QA longer than expected, flagged by configurable thresholds.

Where Design Decisions Mattered

The first version of the sprint table was technically correct and visually exhausting. Every row had a full-width background color: red for at-risk, amber for slow, blue for in-progress. It looked like a traffic accident. The fix was simple but important: color lives only in the status badge and the small health dot. The row stays neutral. The eye can scan quickly because the signal stands out against quiet surroundings.

Carry-over definition required careful thought. The early implementation marked a ticket as "carried over" if it appeared in multiple sprint records. That's wrong. Tickets get reassigned between sprints for legitimate reasons: reprioritization, scope splits. The correct definition: the sprint's end date passed and the ticket status is not Done or Released. Computed in SQL at query time, never stored. The distinction seems minor. To someone paying contractors by the sprint, it's the difference between accurate accountability data and noise.

Outcome

The dashboard went from zero to production in four weeks with real team data across three Jira projects, eight developers, and three APIs. The founder's post-demo feedback confirmed the core thesis: the bottlenecks view alone, which surfaces tickets stuck in code review by duration and by developer, was worth the engagement. The sprint grouping system turned three separate project contexts into one unified view without collapsing the per-project detail needed for reporting. The tool became the team's primary artifact for weekly developer syncs, replacing spreadsheets and manual Jira queries that took longer to prepare than the meetings themselves.