Case study

A property raffle site with three ways to pay and a draw the site does not pick

People buy numbered tickets for a draw whose prize is a property. Card, bank transfer or crypto, with or without an account, in three languages.

My role

This one is a client's product, not mine, and I do not name the client here. The raffle, the prizes, the rules and the buyers are the client's. My part is the software: I am the only developer in its repository, 321 commits over seven months in 2026, and I still maintain it.

The situation

The client was already running these draws on a shop theme, with the payment sent out to an external link. A raffle for a property is not a shop, though. A buyer wants a numbered ticket and a proof that it exists, the organiser needs to know exactly how many tickets are out and who holds them, and on the day of the draw everybody needs to see that the winning number was a real, paid ticket.

The constraint

Money comes in through three doors and has to end in one counter. A card payment confirms itself in seconds. A bank transfer waits for a person to validate it. A crypto payment waits for the payment provider to call back. All three have to end in the same thing: a numbered ticket issued exactly once, and never one more ticket than the draw holds.

The draw has to be believable, so the site does not pick the winner. The draw is held outside the site, and the admin then records the winning number. The site's job is the boring half that matters: refusing a number that is not a real paid ticket, recording the winner and closing the draw in one single step, and publishing a proof page anyone can open.

A buyer does not need an account. That is good for sales and hard for everything else: the ticket has to reach a guest in a form they can keep, their purchases have to attach to an account if they create one later, and a public order form has to hold up against bots.

What I built

The site is in production and I still ship to it. What the site does:

  • A public site in three languages that opens in the visitor's language: the draws, a page per draw, winners, FAQ, a blog, the legal pages.
  • A three-step purchase: choose tickets or a pack, answer a timed skill question, pay. As a guest or from an account, for oneself or as a gift.
  • Card, bank transfer with a reference an admin validates and that expires by itself if the money never arrives, and crypto through a hosted provider whose callbacks are signature-checked.
  • One ticket allocator shared by all three: sequential six-digit numbers, a confirmation processed once only, and a refusal to sell past the size of the draw. The ticket arrives as a PDF by email, and a background job retries emails that did not go out.
  • Coupons, partner codes and referral links, with a free ticket after a set number of paid referrals.
  • The draw record: the site checks the winning number is a paid ticket, records the winner and locks the draw together, then shows a public proof page.
  • An admin console in two languages: draws, participants, transfers and crypto orders to validate, payments, refunds, coupons, payment links, exports and a newsletter tool with one-click unsubscribe.
  • The quiet parts: a bot check and rate limits on orders, a daily backup with a morning alert if it is missing, and a monitor that looks for stuck orders such as "paid but email not sent".

The numbers

  • 3payment methods (card, bank transfer, crypto)
  • 3languages on the public site
  • 10scheduled background jobs
  • 153automated test cases, in 16 files
  • 321commits over seven months in 2026

These are engineering counts, read from the project's own files and history. There is no ticket count, no revenue, no number of buyers, no partner name and no client name on this page. Those belong to the client, and they are the client's to publish.

What I did and did not do

This is somebody else's business. I did not design the raffle, choose the prizes, write the rules or hold the draw, and nothing on this page is a claim about how the draws went. What it shows is narrower: I can take a business that handles other people's money, replace the site under it, and keep it running alone for seven months.

I am the only person in the repository, and I work with an AI coding assistant every day. The other half of that habit is review: the payment code went through four review rounds on the day of its launch and in the two days after, and each finding was closed in its own commit.

What I would do differently: write the tests before the money. The three payment methods went live on 8 May 2026 and the first automated test file arrived on 25 May.

Want something like this?

Tell me what you are building, or what you are still doing by hand, and I will tell you how I would approach it. No commitment.