LDBD
/
All posts

What I Built in Week One: 18 Bots in a Leaderboard with Zero Users

The spec was done. Time to write actual code. A non-developer who'd barely heard of Postgres, Supabase, or RLS — and what got built in seven days.

Last post I wrote about how the 1,600-line spec got made. This one is the next stretch — picking up that spec and writing actual code for the first time.

Honestly, I didn't expect anything to work in seven days. Postgres, Supabase, RLS, Edge Function, App Router — most of those were words I'd just barely seen, and when I searched them, the explanations brought five more unknown words along.

And yet by the end of the week LDBD had login, asset price collection, prediction submission, automatic scoring, and a leaderboard.

I'd hardly typed any code myself. The strange part: I was still the bottleneck the whole way. The code came out fast. The slow part was me — figuring out what to build, what to drop, what to put on screen first.

The vocabulary stopped me first

Reading the docs didn't help much; every page assumed five other concepts I didn't have. So whenever a new word showed up I just asked Claude for a one-line explanation.

Postgres vs. Supabase confused me at first. I eventually settled on this: Postgres is the database where the actual data lives, and Supabase is a service layered on top of Postgres that adds login, permissions, and serverless functions. I'd never used either, but that framing was enough to follow along.

Schema felt abstract until I reframed it as a blueprint for what shape the table is — the upfront agreement that says “a prediction has an asset ID, a direction, a timeframe, and a result.” Until that's decided, you don't know where the data is supposed to go.

RLS (Row Level Security) was new to me too. I ended up thinking of it as a doorman set up inside the database itself, so users can only touch their own rows. That said, the doorman has to be configured well — turning RLS on doesn't magically make everything safe.

Cron jobs sounded scary but the idea was simple — a trigger that runs a job (“score any predictions that just expired”) on a fixed schedule. The full definition is more complicated, but that take got me through the first week.

Once those words felt less alien, the files Claude Code generated stopped looking like gibberish. I still couldn't write them from scratch. But I could squint at one and say “ah, this is creating a database table” or “ah, this is the bit that stops users from reading other people's predictions.” That was enough.

What we started with

When I asked for a stack recommendation the answer was short: Next.js + Supabase + Tailwind + shadcn/ui. The reasoning was a 1-developer-with-no-budget pitch — auth and DB and free hosting all in one place.

Half the names were unfamiliar but I went with it. If something didn't fit later, I figured I'd swap it then.

A leaderboard with zero users

I built the leaderboard, opened it, and something felt off. With no users, the table was empty. I could already picture a new visitor seeing that empty table and thinking “ah, no one's here” before bouncing.

The fix wasn't elegant, but it was direct. If there are no people, put bots in.

Six assets — VOO, QQQ, GLD, BTC-USD, KODEX 200, KODEX KOSDAQ150 — each given three simple strategies (always up, always down, random) gives you eighteen bots. Then I backfilled price data going back to 2016 and asked: if these eighteen bots had been making daily predictions for the last ten years, what would the record look like? That synthetic record filled the leaderboard. A simulated leaderboard, basically.

So a zero-user leaderboard suddenly looked like a board where someone had actually been predicting and getting scored.

There was a side effect I didn't expect. The data spit out a number that became its own pitch — a bot that just clicks “up” every day hits 62% accuracy. That number is now the line on the LDBD landing page: “A bot that just clicks ‘up’ every day has a 62% accuracy. If you can't beat a bot that literally does nothing smart, what does that say about your predictions?”

The score didn't fit on screen

Skill Rating looked great inside the spec doc. Statistically clean, borrowed from chess Elo, very legitimate-feeling. Claude recommended it.

The problem appeared the moment it hit the screen.

Skill Rating 1500

What does someone seeing this for the first time think? Is 1500 good? Average? Is 1800 impressive? If your headline ranking metric needs a paragraph of explanation to land, it's the wrong choice for the front of a page.

I ended up promoting average score to the primary ranking and burying Skill Rating almost out of sight. Average score reads as “+0.3 per prediction on average” — instantly intuitive. The AI didn't make a wrong call. I had failed to tell the difference between “a good metric” and “a metric that looks good on screen.”

People come back if you tell them the result

Prediction services have a weird structural problem. Users predict today, but the result lands days later. If they don't come back to look at the result, every scoring system in the world is useless.

So as soon as a prediction gets auto-scored, the user gets an in-app notification — a red dot on the bell icon in the header. I also added a small “community sentiment” section to each asset page: “Here's what others think VOO will do in a week — 12 up, 5 down.” You can see whether you're with the crowd or against it.

Of course, at the time there were zero users. As I write this there are still approximately zero. There's no one for the notifications to reach. I built the plumbing anyway — adding it after users show up felt like it would be too late.

End of week one

What was sitting in LDBD when the week ended:

  • Email and Google login
  • About 600 stocks/ETFs/crypto with daily auto-fetched prices
  • A prediction form (asset / direction / timeframe)
  • An hourly cron job that scores any expired predictions
  • A leaderboard (average score primary, Skill Rating mostly hidden)
  • 18 baseline bots with 10 years of simulated history behind them
  • Notifications and community sentiment

I didn't write a line of code. What I did instead was keep asking. Is this feature actually needed right now? Does this number make sense to a user? What does someone think when they hit a blank screen? Which edge cases can I just ignore?

By the end of the week I think I started to see it.

Claude Code is fast. The faster it goes, the faster I have to decide. Which metric leads the page. Whether to leave the leaderboard empty or seed it with bots. What signals to send so people come back.

Not coding doesn't mean not building. The thing I did all week wasn't typing — it was choosing.

The next four posts

From here the angle shifts. The next four are not about building LDBD itself — they're about plugging other AIs into LDBD.

I've done this four ways: Claude Desktop + MCP, a local LLM, the ChatGPT Connector, and a direct OpenAI API bot. Same job, four different paths, with surprisingly different strengths and trade-offs. One per post starting next time.


Want to put your own predictions on the record? Start at the homepage. It's free, and you can browse the leaderboard without signing up.

vibe-codingclaude-codefirst-week