Available for projectsStockholm · CET

Work - Budkrig

Budkrig

A public pay-to-rank leaderboard for the Swedish market. Anyone can put a product link or an @handle on the board and pay to hold a spot - rank is decided by the amount paid, nothing else. Bids are cumulative, non-refundable, and never expire.

Role
Architecture · Development
Stack
Next.js · TypeScript · PostgreSQL · Drizzle · Redis · BullMQ · Stripe
The Budkrig landing page in Swedish - the headline "Ta förstaplatsen för" above a bid stepper set to 5 001 kr, with the public leaderboard below ranking two example listings by the amount each has paid.

“Budkrig” is Swedish for bidding war, and the site is exactly that: one public leaderboard where the only thing that sets your rank is how much you have paid to hold it. It is a Swedish-market take on outbid.lol (opens in a new tab) - anyone can add a product link or an @handle, pay to claim a position, and get bumped the moment someone pays more.

What it does

  • Claim a rank. Add a link or @handle, pick a category, and pay to take a spot. To pass the listing above you, you cover the difference over what they paid.
  • Cumulative, non-refundable bids. The amount you pay becomes the new floor for the next challenger. Nothing decays and nothing expires - a position holds until someone outbids it.
  • Swedish payment methods. Stripe Checkout with Swish, Klarna, and cards. The full claim -> Checkout -> webhook -> queued fulfilment loop is built and tested.
  • Categories, time windows, click tracking. The board filters by category and by “today” versus “all time”, and every listing counts the outbound clicks it has sent.

How it’s built

LayerChoice
FrameworkNext.js (App Router, TypeScript)
DatabasePostgreSQL with Drizzle ORM
QueueRedis + BullMQ for asynchronous payment fulfilment
PaymentsStripe Checkout - Swish, Klarna, cards - reconciled by webhook
UITailwind + shadcn/ui
HostingSelf-hosted on Coolify

The interesting part is the money model. Bids only ever go up, they are non-refundable, and ranks have to stay consistent while several people claim at once - so a payment that half-completes must never leave the board in a bad state. The flow is deliberately asynchronous: a claim writes a pending record, Stripe confirms out of band, and a BullMQ worker is what actually promotes the listing. It is documented the way I would hand it to a team - an architecture brief with C4 diagrams, a domain model that writes down every invariant, ADRs for the decisions, and a ranked risk register.

Status

Deployed at budkrig.viktordo.dev (opens in a new tab) with the board, the claim flow, the redirect handler, and the legal pages all live. The payment loop is built and tested end to end; taking real money is one Stripe key away.

← All work