How Claude Code Helped Build a Web Application for my Fantasy Football League
This project began with a simple operational problem: our fantasy football league had years of historical data, but no durable system for understanding it at scale. The information existed across spreadsheets, scattered records, and memory, making it difficult to answer even basic questions about league history, manager performance, or season-to-season patterns.
The goal was not simply to build another scoreboard. The goal was to create a trustworthy, maintainable platform that could convert league history into insight. The result is a web application that combines historical records, performance analytics, season storytelling, and a live-season-ready architecture.
What made this project distinctive was the way it was built. Rather than treating the app as a one-off portfolio project, I designed it as a system with clean data boundaries, durable schema choices, and a clear separation between historical analytics and future live-season ingestion.
Claude Code played a central role in accelerating the design and implementation process without replacing the need for disciplined technical decisions. This was my first major project leveraging Claude Code as the perfect partner that handled the nuanced technical decisions during the developmental phase.
I wanted to create something that was useful to all the mangers in my fantasy football league. These other owners are my closest friends from college and having a tool to examine performance over an extended period of time would be a huge win.
Overall, I learned a very specific lesson: when source data is fragmented, identities are inconsistent, and the product needs to evolve over time, the foundation must be a well-designed data model—one that efficiently supports historical data while also allowing live data to be queried as the season unfolds.
The Business Problem
At a practical level, the league had all of the ingredients for my plan:
- Years of matchup history (2018 – 2026)
- Team and Owner identities over time
- Player-level statistics spread across seasons (when applicable)
- Significant opportunity for a better story to tell and league context
- The curiosity about performance beyond a season scope; over a period of time (and in this case, the last eight years where all twelve of us owners have competed in the same league on the same platform)
The challenge was not just collecting data. The challenge was turning fragmented league history into a dependable, reusable source of truth.
I needed a lesson in classic data architecture; I needed a system that preserves identity, normalizes records, and provides consistent key metrics over time.
The Strategic Objective
After some discernment it became clear; I wanted to create a league intelligence layer that could answer questions faster and more reliably than the league’s informal record-keeping could.
I wanted the web application to support use cases like:
- All-time manager comparisons
- Season-by-season trend analysis
- Playoff and championship storytelling
- Weekly and cumulative performance tracking
- Live-season readiness without premature assumptions
The plan evolved into more than just a dashboard; I wanted to build an information system that could support decision-making and storytelling at the same time.
The Core Strategic Decision: Stability over Seasons
One of the most important design choices in the project was choosing owner identity (name) as the stable business key rather than team name.
This is not a minor implementation detail. It is foundational.
Fantasy leagues often change team names, rebrands, and presentation styles over time. If the data model treats a team label as the primary identity, historical records become unstable, duplicate, and difficult to interpret.
By modeling owners as the primary key while keeping team names as seasonal context, the platform preserves meaningful historical continuity which is vital.
In the schema design, owner names is able to pull together all data schemas that will ultimately support a sound data model.
I Need a Disciplined Data Architecture
From back and forth with my Claude Code partner, I decided that I need multiple sound layers in this proposed system.
- Raw data collection
- Data normalization and schema mapping
- Storage in PostgreSQL
- Reporting/dashboards driven by queries
- Deployment through my new account on the Vercel application
The different thing here that I have done is the data itself is treated as a raw feed, not the underlying dataset for the dashboard. This distinction brings stability to the process if the data source changes or a new seasons worth of data dictates a different collection method.

The Data Model
The web application is built on a relational schema rather than a loose collection of xlsx file or json files.
Why I think relational modeling is the way to go:
- Historical data continuity
- Supports efficient comparisons across multiple seasons
- It allows for matchup-based analyses
- Prevents the reporting layer from carrying the complexity of the data model itself allowing for simpler querying/extraction
The database itself becomes the applications foundation layer. A well thought out data model reduces ambiguity and yields more understandable insights for owners.
Why This Is A Good Fit for an AI-Assisted Project
Claude Code accelerated the project in a way that is particularly relevant for modern product work. It was not just a code generator; it served as a structured design partner through the most important technical decisions.
Claude helped me in three domains:
- Clarifying architecture and tech questions avoiding implementation drift
- Reviewing schema tradeoffs and recommending more robust identity models
- A system to iterate quickly while maintaining a clear separation between raw data, transformation phase, and logic needed for the dashboard layer (via versioning in GitHub)
Claude AI was able to keep me honest to the underlying model and product goals we had decided during our planning and conceptual discussions. While speed was a great tool from Claude what proved to be a better gift was clarity of the goal.
The Historical Pipeline: Durable and Scalable
The pipeline was built to support long-term analysis. Raw data is normalized into a consistent schema and loaded into PostgreSQL, where the app reads the model instead of reconstructing state from scattered raw source files.
This enables important reporting layers such as:
- KPI cards for league-wide performance
- Leaderboard views for manager comparisons
- Points-over-time tracking
- Season story summaries
- Player network and team narratives
The Live-Season Challenge: Readiness Without False Certainty
A major design requirement was the ability to anticipate future live-season data without prematurely presenting incomplete data as if it were complete and historical.
The solution was a holding-state architecture for the current season. With that pre-work; the application is ready for a live-season data path. This is not just a UX consideration; it is a governance and data-quality rule.
The project includes a structured fallback pipeline for live-season ingestion:
- Browser automation via Playwright
- Session-based Yahoo access
- Weekly team page extraction
- Normalization into the application’s existing schema
- Upsert workflow to the database
The design is important because it keeps the architecture stable. It does not create a second model. Instead, it feeds the same normalized structure used by the historical dataset, which makes future live-season reporting consistent with the historical app. The system is designed to absorb future real-time data without breaking the historical data model.
Technology Choices and Why They Matter:
Next.js and TypeScript
The platform is built with both Next.js and TypeScript because it provides strong application structure while remaining flexible enough for analytics-driven UI work. TypeScript is particularly useful in a project with multiple layers of data transformation, query logic, and UI components.
PostgreSQL
This was the right fit for this project because league data is inherently relational: owners, teams, matchups, seasons, and player performance must be represented as connected records, not isolated seasons.
GitHub and version control
GitHub serves as both a deployment source and a decision history. This matters in a project that evolves through repeated architecture and schema adjustments. Version control makes the development process transparent and recoverable.
Vercel
Vercel is a clean hosting choice for the app because it aligns naturally with the Next.js build and deployment model. It reduces operational complexity and makes that product easier to maintain and iterate.
Playwright
Playwright is used where browser-driven data collection is necessary. This is the fallback for the process when the data source is available only through a dynamic web interface rather than a straightforward API.
What This Project Teaches About Data Products
The broader lesson here applies to any organization dealing with fragmented source systems, evolving identity records, and the need to transform raw info into a decision-support platform.
The main principles are straightforward:
- Normalize before you build the product layer
- Separate source collection from trusted reporting components
- Design for future data sources without breaking the present data model
- Treat analytics as a product layer and not a side effect
This is ultimately what gave my project real strategic value. It demonstrates that a well-designed data product is not just about charts; it’s about making the underlying system workable to support better data decisions.
Conclusion
I started with a problem; I had access to historical data for my fantasy football league. I just did not like the way it was presented in Yahoo. What I loved was the extensive data available but there was no structure to make it useful for me. Claude was able to help me see the durable foundation needed to build a versatile data product.
While the goal of creating an interactive web application was attained; I actually ended up creating good data model that supported historical questions and was built to support future data pipelines from future seasons. Claude Code helped accelerate the process, but the long-term value came from disciplined architecture decisions: stable identities (owner names), normalized schemas, robust ingestion, and a clear story to tell.
This project is a good example of how modern AI-assisted development can be used effectively: not to skip the hard conceptual work, but to sharpen it, accelerate it, and keep the focus on the design choices that matter the most.
Below are some screenshots of sections of the application:



