Skip to content
Mmohtasim
All projects

FrameRent

A camera and lens rental shop. Customers check availability, book a date range and pay a deposit. Staff manage every physical unit from an admin console with an occupancy calendar.

Screenshots

frame-rent-web.vercel.app
FrameRent landing page: great glass, rented by the day
frame-rent-web.vercel.app
Product page for a DJI RS 4 Pro with daily and weekly rates, deposit and a rental date calendar

The problem

If two people book the last copy of a lens for overlapping dates at the same moment, a simple "check, then insert" lets both bookings through. One of them shows up to an empty shelf.

What I built

  • Per-unit inventory, so the shop tracks each physical camera instead of a stock count
  • Booking inside one database transaction that locks the candidate units before assigning one
  • Stripe deposits held as authorizations, with webhooks as the single source of truth for payment
  • Unpaid bookings that expire after 30 minutes, so nobody can hold gear forever
  • Zod schemas shared between the React client and the Express API
  • An admin console with an occupancy grid and calendar
  • 67 automated tests with Vitest

The hardest part

Two bookings, one lens

Checking availability and then inserting a booking leaves a gap where a second request can slip in. I run the whole booking in one transaction and lock the candidate units first, so a second request waits until the first one finishes and then sees the unit is taken.

-- inside the booking transaction (simplified)
SELECT id FROM "Unit"
WHERE "productId" = $1
FOR UPDATE;  -- a second booking waits here

Next project

Dispatch

Got an idea? Let's build it.

Tell me what you're making or what's broken, and I'll reply with how I'd approach it. Use the form, or reach me directly.