S
COMPLETEFull-stack EngineerProfessional

LedgerTurf

Turf booking platform that lets players discover and reserve grounds on a Google Map while owners publish and manage slots with overlapping-time checks.

ReactExpressMongoDB AtlasRedux ToolkitGoogle Maps

[ 01 ] · Context

Problem

  • Turf owners in Dhaka booked slots over phone and WhatsApp: double-booking was routine, availability was never current, and players had no way to compare grounds.
  • Timezones and 24-hour clock confusion made 'is this slot free right now' a genuinely hard query to answer correctly.

[ 02 ] · Response

Solution

LedgerTurf is a monorepo (npm workspaces) with an Express REST API and a React SPA. Players discover turfs on Google Maps (owners pin their location with a map picker), locations carry a GeoJSON 2dsphere index (the radius geo search is currently disabled), owners publish and manage slots, and admins get full visibility, with JWT auth and role-based access at every layer.

Bookings are checked for overlapping slots before a Mongoose transaction writes them, and availability is computed in UTC with Bangladesh's UTC+6 offset handled explicitly, so 'available now' means the same thing to everyone.

SPA deep links are handled with Vercel rewrite rules so refreshing /turf/:id never 404s.

[ 03 ] · Structure

Architecture

  React SPA (Vite + Redux) ──► /api/v1 ──► Express (JWT bearer)
                                          │  asyncHandler pattern
                                          ├──► Mongo 2dsphere geo index
                                          ├──► Booking overlap check
                                          │    (before the txn write)
                                          ├──► Review avg-rating hooks
                                          └──► Cloudinary uploads
  Vercel: frontend + backend, SPA rewrite rules

[ 04 ] · Trade-offs

Key engineering decisions

  1. 01

    GeoJSON 2dsphere index

    Turf locations are stored as GeoJSON and indexed with MongoDB's 2dsphere index for radius-based discovery: the spatial query is commented out in production for Vercel stability but the index and model are in place.

  2. 02

    Explicit UTC+6 handling

    Past-date validation and 'availableNow' both compute against a single UTC clock offset, eliminating the midnight-rollover class of bugs common to BD booking apps.

  3. 03

    Npm workspaces monorepo

    frontend, backend, and an api-shim share the repo so type shapes stay in sync while each package deploys independently to Vercel.

[ 05 ] · Under the hood

Engineering highlights

Booking overlap check
const session = await mongoose.startSession();
session.startTransaction();
try {
  const clash = await Booking.findOne({
    turf, startTime: { $lt: end },
    endTime: { $gt: start },
  }).session(session);
  if (clash) throw new BookingConflictError();
  await Booking.create([{ turf, start, end }], { session });
  await session.commitTransaction();
} finally { session.endSession(); }
Honest note: the overlap check runs before the transaction, outside its session, so it isn't race-safe yet; a unique partial index is the planned hardening step.

[ 06 ] · Outcomes

Results

37
commits
3
roles (player / owner / admin)
2dsphere
geo index on locations
+6
UTC offset handled explicitly

[ 07 ] · Where it's going

Status & next steps

  • Unique partial index on (turf, startTime) to make double-booking impossible at the DB level.
  • Re-enable the geo-search path now that Vercel configuration is stable.

[ 08 ] · Keep exploring

More projects

InvoicePilot: AI-powered invoice processing platform that extracts, validates, and analyzes invoices while detecting duplicates and anomalies to streamline financial document workflows.
ProfessionalProduction
Featured

AI-powered invoice processing platform that extracts, validates, and analyzes invoices while detecting duplicates and anomalies to streamline financial document workflows.

FastAPIPythonMindee OCRPostgreSQLRedis StreamsCloudflare R2
Back to all projects