Terry Henrard

portfolioTerry HenrardSeptember 12, 2024Updated November 24, 20256 minNext.jsBooking SystemSchedulingPrismaNeonPostgresVercelTailwind CSSTypeScriptServerlessWeb DevelopmentB2C

The "Excel" Exorcism

There is a specific kind of chaos that comes from running a successful mobile car wash business using only a WordPress landing page, a phone number, and a shared Excel spreadsheet.

"Car Wash From Home" (CWFH) was growing fast, but their backend operations were stuck in 2010. Double bookings were common, customers had to call to find an open slot, and the admins were spending their evenings manually reconciling paper notes with digital spreadsheets.

They needed to stop playing "Tetris" with appointments and start automating.

Contents

The Mission

I was brought in to perform a complete digital overhaul. The goal was simple but ambitious: kill the spreadsheet, modernize the brand, and build a booking brain that could handle the nuances of a real-world workforce.

Next.js 16Neon (Serverless Postgres)Vercel (Serverless Infra)Prisma ORMTailwind CSS

The Solution: More Than Just a Date Picker

A generic booking plugin wouldn't cut it. CWFH needed logic that understood that humans need lunch breaks, that Christmas exists, and that sometimes a van breaks down on a Tuesday.

I built a custom solution centered around granular availability control.

Admin Autonomy

Admins aren't locked into a rigid 9-to-5 structure. They can define standard opening hours, but easily override them for Ad Hoc events, set specific closing days, or block out time for equipment maintenance instantly.

Instant UX

By moving away from their sluggish WordPress theme to a bespoke Next.js frontend, we achieved near-instant page loads. The booking flow guides the user from service selection to confirmation in under 60 seconds.

The Technical Deep Dive

The UI was the fun part, but the database was the headache. Designing a schema that is performant enough to query availability in real-time, while being flexible enough to handle "Standard Tuesdays" vs "Christmas Eve Tuesday," required a complex relational structure.

I settled on a 5-table architecture (appointments, business-hours, recurring-time-slots, slot-exceptions, adhoc-time-slots) to decouple "Time" from "Availability."

A high-level view of the schema separating Business Rules from Actual Appointments.

The Schema Strategy

Structuring Complexity

We couldn't just have an appointments table. We needed to define the "Potential" for appointments first.

The Logic

Here is a simplified look at how we calculate slots. We don't store "free slots" in the DB; we calculate them on the fly to ensure atomic accuracy.

// Simplified logic for generating availability
async function getAvailableSlots(date: Date, serviceDuration: number) {
  // 1. Fetch Master Rules (business-hours), recurring time slots and slot-exceptions (Holidays or one-offs)
  const rules = await prisma.businessHours.findMany({ ... });
 
  // 2. Fetch existing appointments for that specific day
  const appointments = await prisma.appointment.findMany({
  where: { date: date }
  });
 
  // 3. Generate all possible time chunks (e.g., 09:00, 09:30...)
  const potentialSlots = generateTimeChunks(rules);
 
  // 4. Filter out collisions
  return potentialSlots.filter(slot => {
  return !isOverlapping(slot, appointments) && !isDuringBreak(slot);
  });
}

The Results

We launched the new platform just before the spring rush. The impact was immediate. The phone stopped ringing off the hook, not because customers left, but because they were happily booking online at 11 PM.

66%

Speed Increase

10k+

Happy Users

80%

Admin Time Saved

Conclusion

This project proved that for local businesses, a custom solution isn't vanity—it's necessary efficiency. Moving from WordPress to a Serverless Next.js architecture didn't just make the site look pretty; it fundamentally changed how the company operates.

And honestly? I don't miss migrating data from Excel one bit. 😴

Inspired by this project?

I can help you build something similar — let's chat about your idea and the next steps.

Subscribe to my newsletter

Get updates about new projects and occasional tips and tricks — just useful stuff.

Read another project

If you'd like to explore more, here's another project you might enjoy.