silverfish

Book a football turf in Sylhet without calling anyone.

A frame from the Zenvy film: the Zenvy mark above the words Skip the call. Book the turf.
The call
Chapters8 · 1:00
  1. To book a turf, you call the manager. Often, nobody picks up. And when they do, it’s a notebook: two teams, one hour. Zenvy: Skip the call. Book the turf.

  2. See which hours are open. Turfs across Sylhet, with live slots and both prices up front.

  3. Take the hour. Pay a small advance: ৳200 an hour by default, by bKash, Nagad, Rocket, Upay or card. Your code comes by SMS. Show it at the gate.

  4. Two teams can’t get the same hour. The database itself refuses double bookings: fire 20 at one hour, and exactly one wins.

  5. Retire the notebook and the Facebook inbox. Bookings ping your phone and money lands in your bKash. No signal? It still works. Listing costs nothing.

  6. bKash, Nagad, Rocket, Upay, card. Pay the advance the way you already pay.

  7. মাঠ বুক করুন। Book the pitch. দল নিয়ে আসুন। Bring the team. Bangla by default, English at a tap.

  8. Skip the call. Book the turf. zenvy.com.bd, made in Sylhet.

Watch with sound?

This case study opens with a one-minute film. It’s made to be heard: music and small sounds for every tap.

I’ll remember your choice on this device.

Book a football turf in Sylhet without calling anyone.

At a glance

01The problem
In Sylhet, booking a turf means calling a manager who often doesn't answer.
02What I built
Online booking with a small advance by bKash or card, and an owner app that works offline.
03The result
Live in Bangla and English, and the database makes double bookings impossible.
My part
Co-founder and CTO: architecture, payments and the owner app, with the team [to confirm]

Built with

Next.js · next-intl · Express · PostgreSQL · Prisma · PayStation

The goal, in the live site's own words

“Live availability at turfs across the country. See which hours are open, take one, and get confirmed on the spot.”

zenvy.com.bd, 2026-09-30. For turf owners: “Retire the notebook and the Facebook inbox.”

1

The problem

Football in Sylhet happens on small artificial-grass turfs, rented by the hour. To book one, you call the manager. Often nobody picks up, and when they do, they're checking a notebook while another team is asking about the same hour.

That's the whole problem: you can't see what's free, and nobody can promise an hour is yours. Players waste evenings, and grounds lose money on empty hours they didn't know they had.

2

Who it's for

Player · illustrative

Rafi, 22

Books for his team of ten on Friday nights. Wants to see a free hour, pay the advance by bKash and get a code he can show at the gate.

Ground manager · illustrative

The person at the desk

Runs the ground from a phone all day, takes cash from walk-ins, and isn't a computer person. Needs big buttons, plain words, and a phone that still works when the signal drops.

3

Try it

Find a free hour on the real site, live in Sylhet.

Live Find a turf on Zenvy zenvy.com.bd
4

What I built

Two apps on one platform: a booking site for players, and a phone-first app for the people who run the grounds.

The redesigned Zenvy home on a phone: the headline Skip the call. Book the turf. and a search box.
Zenvy for turfs on a phone: Run your turf from your phone, with a big sign-in button and a list of what owners get.
New designPlayers search and book in a few taps. Owners run the day from their phone. Turfs and counts in the new design are sample data for now.
The live zenvy.com.bd home: Book the pitch. Bring the team., a search box, and real turf cards showing free slots.
LiveThe site players use today, with real turfs and live free slots.
5

How it works

  1. Find a free hourSee every open hour at every ground, day and night prices side by side.
  2. Pay a small advance৳200 an hour by default (each ground sets its own), by bKash, Nagad, Rocket, Upay or card.
  3. Get your code by SMSShow it at the gate. The rest is paid at the ground.
6

Decisions I made

Decision Live

Let the database refuse double bookings

Options
Check in the app, lock rows, or put a rule in the database itself.
Why
A Postgres exclusion constraint refuses any two bookings whose times overlap. It holds on every code path, even for overlapping time ranges where there's no single row to lock. A test fires 20 claims at the same hour at once, and exactly one wins.
Cost
Harder migrations, and database errors have to be turned into friendly messages.
For engineersTechnical
  • EXCLUDE USING gist (fieldId WITH =, tstzrange(startAt, endAt, '[)') WITH &&), with SQLSTATE 23P01 mapped to HTTP 409.
  • Full and half pitches share inventory through a parent field, so booking the full pitch blocks both halves.
Decision Live

Don't trust the payment redirect

Why
The gateway's redirect back to the site isn't signed, so a booking is confirmed only after a server-to-server status check, and webhooks are verified with an HMAC signature.
Cost
One extra round trip at checkout.
For engineersTechnical
  • Idempotency keys on payment rows, so a retried webhook can't pay twice. Late payments are recorded first, then settled against the constraint.
Decision Live

An owner app that works without signal

Why
Cash taken at the ground goes into an outbox on the phone and syncs when the connection comes back, without being counted twice.
Cost
Risky actions, like blocking an hour, are refused while offline.
For engineersTechnical
  • An IndexedDB outbox with a client request ID for each write, so the server ignores replays. A month of data is pre-loaded for offline use.
Decision Live

Designed for managers who may not read easily

Why
Amounts and names can be read aloud in Bangla at the tap of a button. The day is picked by part (morning, evening, night) instead of a 24-hour list, payment types are icons, and every target is at least 44 px.
Decision Live

Bangla first

Why
Bangla is the default, English is at /en. English SMS writes 'Tk' instead of ৳, because one non-GSM character turns a 160-character message into a 70-character one and roughly doubles the cost.
Decision Live

A deposit people can remember

Why
The advance used to be 20 % of the price, which produced figures nobody chose, like ৳260 or ৳440. Now it's a flat amount per hour, the same number in the SMS, on the receipt and at the gate.
Cost
At cheap grounds, a flat per-hour deposit is a bigger share of the price.
Decision Live

Zero commission at launch

Why
It was 5 %. The first grounds are taking a risk on an unproven platform, and charging them is the wrong trade while supply is the constraint. Commission is saved on each booking, so changing it later never rewrites money already earned.
Cost
No platform revenue from bookings until demand justifies a cut.
For engineers: the rest of the stackTechnical
  • Asia/Dhaka timestamptz everywhere, and operating days that run past midnight.
  • Additive migrations deploy on their own. Destructive ones wait for a person.
  • GitHub Actions deploys over SSH, checks /health, and rolls back on failure.
  • The payout ledger query went from 426 ms to 54 ms on a synthetic 73,000-booking benchmark.
7

The redesign

The new design, rolling out at zenvy.silverfish.dev, puts search and free hours first.

Decision New design

A booking site, not a marketing page

Why
The first version read like a SaaS landing page. Now the first thing you see is a search box and the free hours.
Decision New design

Skip the call. Book the turf.

Why
Longer taglines were cut as wordy. The whole promise fits in five words.
Decision New design

Readable on a phone

Why
I darkened the text greys after finding them too light on my phone. Body text is now 6.0:1. Small meta text is 4.1:1, which I'd raise to 4.5:1 next.
Decision New design

Every colour also has a word

Why
Free, Due, Paid and Closed are never shown by colour alone, because colour fails in glare and for colour-blind managers.
The redesign's 404 page: a pitch drawn in thin lines with the ball rolling out of play, and the words Out of play.
New designEven the 404 page stays on theme: the ball rolls out of play.
8

Results

5turfs bookable nowSource: zenvy.com.bd trust band, 2026-09-30
15turfs listed across 4 areasSource: zenvy.com.bd, 2026-09-30
≈ 900automated testsSource: the production repo, Sep 2026
57turfs mapped across Sylhet district for the rolloutSource: market research, Aug 2026
9

What I'd do next

Fill the quiet hours with a forecast. With enough booking history, a model can predict which hours will stay empty, from the day, the time, the weather and holidays, so owners can discount them early. It's the first thing I'd build with the machine learning I'm studying.

Project receipt · Zenvy

Checked 30 Sep 2026against code and the live site
My part
Co-founder & CTO. Architecture, payments, the owner app [to confirm]
Built with
Next.js 15, Express 5, Prisma 6, PostgreSQL (Supabase), next-intl, ImageKit, Sentry
Shipped
Live at zenvy.com.bd. A new design is rolling out at zenvy.silverfish.dev
Tests
About 900, run against a real Postgres on every push
On the site
15 turfs listed · 4 areas · 5 bookable now (zenvy.com.bd, 2026-09-30)
Sources
zenvy.com.bd · the production repo · the redesign's handover notes