Draft Slot

Founder
Full-Stack Engineer
Product Designer
Infrastructure
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 IdeaA 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, paying sponsors, 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.

The Thesis
Built On Hype Stacks
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

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
The tradeoff was real. 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.
Live Drafts, In Real Time
When The Clock Starts Ticking

The hardest part of a draft prediction game is the draft itself. On draft night, every user is watching the same board and every pick needs to reach every connected browser in seconds.
I layered the real-time system in pieces. Laravel Reverb handles WebSocket broadcasting over public channels named after the draft (draft.nfl.2026). Laravel Echo on the client subscribes. Each pick is a broadcast event. The client-side store keeps only the last 50 picks in memory — the UI doesn't need more — which keeps long drafts light on mobile.
- Laravel Reverb for WebSocket broadcasting
- Laravel Echo client with public channels per draft
- ESPN API polling as the source of truth
- Admin CSV override when the feed lags or breaks
- 50-pick memory cap in the live store
There's an override system too. When the feed goes quiet — and it has, on several draft nights — I can upload a CSV and the scoring engine replays from there. The live experience stays intact even when the upstream doesn't.
Built Like A Real Product
No Shortcuts On The Unglamorous Parts

A side project is easy to treat like a side project. I've tried to do the opposite — you can see it in small things like the scoring panel above, polished down to the last cell. The plumbing that users never see is the plumbing that determines whether this thing survives.
- 347 Pest feature and unit tests covering auth, rooms, entries, scoring, and notifications
- 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
Over 1,800 commits and 115 database migrations, each one small and boring. That's the shape of a codebase someone has actually lived with.
Paying For The Quiet Months
Infrastructure That Respects The Calendar

A draft game has a brutal traffic shape. Most of the year, nobody is here. For a few days in April, July, October, and June, everyone is. Running at peak capacity year-round would eat the budget. Running too cold would break the nights that matter.
I encoded the calendar into the deployment itself. The Vapor config has three scaling profiles — offseason, pre-draft, and draft week — and I switch between them as the season approaches:
- 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
Sponsored rooms carry some of that cost now — brands funding prize pools inside the app — but the seasonal scaling is what keeps the fixed side sane on a personal budget. It's the kind of cost optimization a small company would do for real money. For me, it's what keeps this project inside the budget of a personal side project.

















What's Next
The 2026 Season
The next chapter is two moves. First, I'm migrating the platform off Laravel Vapor and onto Laravel Cloud. Vapor has served the project well, but Cloud is built around the way Laravel apps actually run, and the ergonomics — along with the ops cost — are a better fit for where the project is headed.
Second, for the first time, I'm giving this thing a real push. Next season I'm running my first paid experiments. The goal is meaningful engagement with real users — not vanity metrics — to see what this product looks like when people actually know it exists.
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.


