Skip to main content

Case Study

Draft Slot

Draft Slot brand splash — 'Predict the Draft Like a Pro'

Role

  • Founder
  • Full-Stack Engineer
  • Product Designer
  • Infrastructure

Stack

  • Laravel
  • PHP
  • Alpine.js
  • Tailwind CSS
  • Laravel Reverb
  • Laravel Echo
  • Laravel Vapor
  • MySQL
  • Redis
  • Pest
  • PHPStan
  • WebAuthn
  • Sentry
  • Postmark
  • Service Worker
  • PWA

Six Years, One Idea

A side project I keep coming back to

In 2019, as a thesis for my first graduate program, I built a fantasy draft game. It was split across two repos — a Laravel 6 GraphQL API and a React 16 SPA — and when I turned it in, it worked. It also never shipped to a single real user.

Six years later, that thesis has become Draft Slot. It runs live drafts across the NFL, NBA, MLB, and NHL. It has real users and infrastructure that scales up for draft night and back down for the offseason. It's the project I keep teaching myself new things on — and the one I've never once paid to market.

Draft Slot homepage — 'Dominate Your Draft Room' with a sample Pick #1 card

The Thesis

Built On Hype Stacks

Draft Slot brand mark

The original version was two repos, both dated early 2019. The API was Laravel 6 with Lighthouse GraphQL and Passport for OAuth. The frontend was React 16 with Apollo Client for data and Redux for local UI state, bundled with a hand-rolled Webpack config.

I picked every piece for a reason: GraphQL was new, Apollo was new, and picking them meant I'd learn them. That was the entire point of a thesis project.

  • Laravel 6 + Lighthouse GraphQL on the backend
  • React 16 + Apollo + Redux on the frontend
  • Laravel Passport for OAuth2
  • Hand-rolled Webpack config — no create-react-app
  • Minimal tests, no deployment pipeline, no users

It delivered the thesis. It did not deliver a product. I submitted the work, graduated, and the repos went quiet for almost two years.

The Reset

One Codebase, Server-Rendered Again

One codebase covering NFL, NBA, MLB, and NHL — the multi-sport reach the rewrite made possible

When I came back to it, I didn't port the old code. I rebuilt the whole thing in a single Laravel monolith with Blade templates, Alpine.js for interactivity, and Tailwind for styling. The GraphQL layer was gone. The SPA was gone.

The choice looked unfashionable on paper. In practice, it was the only one that made sense. I had no team, no budget, no investors, and a full-time job. Every hour I spent tuning a bundler or fighting hydration was an hour I wasn't spending on features my users could actually see.

  • Laravel + Blade for server-rendered HTML, no hydration tax
  • Alpine.js progressively enhances specific components
  • Tailwind keeps CSS out of the critical path
  • One repo, one deploy, one mental model

This was the version that actually shipped. Real users, a real database, a real draft night — the baseline the rest of this story is built on top of. The tradeoff was real too: I gave up some of the polish a proper SPA offers. What I got back was velocity. Shipping something on a Sunday night became normal again.

The Agentic Era

Rebuilding The Shipped App Through An Agentic Loop

Draft Slot's tiered scoring breakdown — production UI from a Laravel codebase rewritten entirely with Claude

The Reset shipped, but it didn't do everything I wanted. I took the app that was already live and rebuilt its frontend and backend through an agentic engineering loop — requirements first, agent build, validation before merge. The product never restarted; the codebase did. Today the Laravel codebase is 100% built with Claude.

The goal of the rebuild was concrete: take the single-sport, server-rendered baseline and build the draft out into a real multi-sport, real-time product that scales. I got there by combining three threads, run through the same loop over and over.

  • A full test suite written with TDD — the spec came first, the agent wrote to it, validation gated the merge
  • Infrastructure that scales up and down per season — Laravel Vapor with three scaling profiles (offseason, pre-draft, draft week)
  • An interface of modular components built in atomic fashion (Atomic Design), each one run through requirements to validated build

The numbers are the shape of a codebase someone has actually lived with through an agentic loop: 1,800+ commits, 347 Pest tests, and not a single missed draft night since the rebuild. The product predates this era. The code that runs it doesn't.

The Product Today

What Shipped

Draft Slot's live draft board showing real-time picks in a 32-pick round

What the rebuild produced is a real product running across the NFL, NBA, MLB, and NHL. The work splits into three jobs that all have to hold at once: keep draft night live, treat the unglamorous plumbing seriously, and keep the bill sane in the months nobody is here.

Live drafts, in real time. On draft night every user watches the same board, and every pick has to reach every connected browser in seconds.

  • Laravel Reverb for WebSocket broadcasting, with public channels per draft (draft.nfl.2026)
  • Laravel Echo on the client subscribes; each pick is a broadcast event
  • ESPN API polling as the source of truth
  • Admin CSV override when the feed lags or breaks — the scoring engine replays from the upload
  • A 50-pick memory cap in the live store keeps long drafts light on mobile

Built like a real product. The plumbing users never see is the plumbing that decides whether this thing survives.

  • 347 Pest feature and unit tests, plus 24 Vitest tests on the JavaScript stores and offline storage
  • PHPStan static analysis at a meaningful level, not level 0
  • Sentry error tracking on both the Laravel and client sides
  • Passkeys and TOTP for two-factor, plus Google and Apple OAuth
  • Postmark with RFC 8058 one-click unsubscribe and plain-text fallbacks
  • A service worker, IndexedDB storage, and PWA install flow

Paying for the quiet months. A draft game has a brutal traffic shape — dead most of the year, mobbed for a few days in April, June, July, and October. I encoded the calendar into the deployment itself.

  • Offseason: zero warm Lambdas, scheduler every 15 minutes
  • Pre-draft: two warm instances, scheduler every five minutes
  • Draft week: 10 warm instances, scheduler every minute

It's the kind of cost optimization a small company would do for real money. For me, it's what keeps the project inside the budget of a personal side project.

What's Next

Microservices, FastAPI, And A Business Split

The next chapter moves off a single Laravel monolith and toward microservices that scale independently — the parts that spike on draft night decoupled from the parts that don't. Alongside that, I'm planning a transition to FastAPI, pulling the heavier service work into Python where the async story and the typing fit the direction the platform is headed.

The product splits in two as well. One side becomes a focused mock-draft app — the prediction game at its core. The other becomes a contest app called draftrm, where the competition and the sponsorship live: prize pools, sponsor configuration, and the Draft for a Cause rooms that let brands fund the payout.

The best thing about a side project is that it moves on your schedule. The scary thing about a side project is that it moves on your schedule. The work now is keeping the craft intact while finally letting more people in.