I'm a solo founder with zero formal coding background. Yet, I built LapScore — a free sports analytics platform tracking 14,000+ daily matches in 10 languages — in about 3 weeks using Claude AI as my primary development tool.
This post is a transparent technical breakdown of the stack, key decisions, and surprising lessons.
The Stack (Simpler Than You'd Think)Backend: FastAPI (Python)
Database: SQLite (WAL mode)
Templates: Jinja2 + lightweight SPA
Server: Vultr VPS (Seoul)
AI: Anthropic Claude
Sports API: api-sports.io
That's it. No Postgres, no Redis, no microservices, no Kubernetes. One Python process serving 14K+ matches across 122,170 SEO pages.
Why FastAPI + SQLite (and not Postgres)?
The "scale at all costs" advice is mostly wrong for early-stage products.
SQLite with WAL mode handles:
- 14,358 daily match records
- 122,170 server-rendered SEO pages
- Concurrent reads (essentially unlimited)
- Background jobs writing every minute
Single-file backups. No connection pool config. No "is the database down?" panics.
When LapScore actually needs Postgres (10K concurrent writes), I'll know. Until then, SQLite is a feature, not a limitation.
The Background Scheduler That Almost Broke
LapScore generates predictions twice daily via APScheduler:
_scheduled_lappick_morning,
'cron', hour=1, minute=0, id='lappick_morning' # KST 10:00
)
scheduler.add_job(
_scheduled_lappick_evening,
'cron', hour=13, minute=0, id='lappick_evening' # KST 22:00
)
Yesterday I noticed today's picks were missing. Diagnosis revealed the morning function had:
pythonBug
await generate_daily_lappick(hours_ahead=0, max_picks=3, job_name="morning")Fix (added hours_ahead_min=2)
await generate_daily_lappick(hours_ahead=0, max_picks=3,
job_name="morning", hours_ahead_min=2)
Default hours_ahead_min=4 meant "only consider matches starting 4+ hours from now." On a slow match day, every match got skipped.
Lesson: Default parameters in shared functions are silent bombs.
SEO: 122K Pages Without Writing 122K Pages
I generate one Jinja2 template, then render it for every match × every language:/match/lazio-vs-udinese-serie-a-1234 (English)
/match/lazio-vs-udinese-serie-a-1234?lang=de (German)
/match/lazio-vs-udinese-serie-a-1234?lang=pt (Portuguese)
... × 10 languages
Combined with proper hreflang tags and a 12,437-URL sitemap submitted to Google Search Console, this beats trying to compete for "livescore" (DR 90+ giants own that SERP).
Long-tail wins.
The LAP Prediction System
LAP picks are tracked publicly with a virtual $1,000 bankroll:
- Started: 2026-04-22
- Current: $1,103.72 (+10.37% ROI)
- Win rate: 60% (15/25)
Every pick. Every result. No deletions.
The Claude API analyzes 50-100 daily matches, looks for edge >8%, and publishes only when confident. Some days produce 6 picks, some days produce 2. That's the point.
What Working with Claude Actually Looks Like
I don't write code. I describe what I want, paste errors, paste logs, and iterate.
A typical exchange:
- Me: "The morning picks didn't generate today. Here's the log: [paste]"
- Claude: "The
hours_ahead_min=4default is filtering out everything. Fix: [code]" - Me: I SSH in, paste the fix, verify, redeploy.
This works because:
- I know my product cold (what should happen, what shouldn't)
- I can read code even though I can't write it from scratch
-
I keep extensive backups (
*.bak_YYYYMMDD_HHMMSSfor every change)
Non-technical doesn't mean uninvolved. It means I trade syntax knowledge for product clarity.
The Real Multipliers
After 3 weeks of building, the things that mattered most weren't technical:
- Public bankroll tracking — radical transparency beats marketing claims
- 10 languages from day one — most sports sites are English-only or single-locale
- Free, no signup — friction kills adoption faster than bad UX
- Long-tail SEO — 122K pages of low-competition match content
The stack barely matters. The decisions around it do.
Try It
LapScore — Free sports scores and predictions in 10 languages.
LAP Pick Bankroll — Public ROI tracker.
If you're a solo founder building something with AI assistance, I'd love to hear what stack you're using. Drop a comment.
Top comments (0)