← Back to Blog
Next.jsPostgreSQLLogisticsFull Stack

Building TrailerFlow: A Logistics App from the Ground Up

TwoTones DigitalMay 23, 20266 min read

The Brief

The client came to me with a straightforward problem: their trailer rental operation was being managed entirely through phone calls, a spreadsheet, and a lot of memory. Bookings would overlap, trucks would go out without paperwork, and there was no easy way to see what was available at any given time.

They needed a system. Not a generic one — something built around how they actually operate.

Starting Point: Mapping the Domain

Before writing a single line of code, I spent time understanding the business:

  • Trailers have different types (flatbed, refrigerated, enclosed) with different availability windows
  • Bookings can span multiple days and need buffer time between clients
  • The dispatcher needs a live view of the fleet — what's out, what's due back, what's damaged
  • Clients need confirmation receipts and can sometimes book recurring slots

This shaped the entire data model. The core entities ended up being: Trailer, Booking, Client, and MaintenanceLog.

Tech Stack Decisions

Next.js (App Router) — full-stack with API routes
PostgreSQL + Prisma — relational data with type safety
Tailwind CSS — rapid UI iteration
Vercel — deployment with edge functions

I chose Next.js specifically because the App Router made it simple to have both the client-facing booking interface and the internal dispatcher dashboard in the same codebase, with server components doing the heavy lifting on data fetching.

The Calendar Problem

The hardest part of the project wasn't the tech — it was the availability logic. A trailer can't just be "booked or not booked." You need to handle:

  • Multi-day bookings with start/end times (not just dates)
  • Turnaround time (minimum gap between bookings for cleaning/inspection)
  • Maintenance blocks that take a trailer offline
  • Timezone handling for clients in different regions

My first approach used a simple date overlap check. It worked, but edge cases started piling up — what if a booking ends at noon and another starts at 2pm? Is the turnaround buffer met?

I ended up writing a dedicated availability engine that generates time slots from a combination of bookings and maintenance windows, rather than trying to query for conflicts directly.

// Simplified version of the core availability check
function isAvailable(trailer: Trailer, start: Date, end: Date): boolean {
  const buffer = trailer.turnaroundHours * 60 * 60 * 1000;
  return !trailer.bookings.some(b => {
    const bStart = new Date(b.startAt).getTime() - buffer;
    const bEnd = new Date(b.endAt).getTime() + buffer;
    return start.getTime() < bEnd && end.getTime() > bStart;
  });
}

Key Commits Along the Way

Here's a rough narrative of how the project evolved through commits:

Week 1 — Foundation

  • init: scaffold Next.js app with Prisma and PostgreSQL
  • feat: Trailer and Client models with seed data
  • feat: basic booking API route with conflict detection

Week 2 — The Dashboard

  • feat: dispatcher dashboard with fleet status grid
  • feat: booking calendar view (week/month toggle)
  • fix: availability query not accounting for buffer time

Week 3 — Client-Facing Flow

  • feat: public booking form with real-time availability
  • feat: email confirmation on booking creation
  • feat: PDF receipt generation with booking details

Week 4 — Polish & Launch

  • fix: timezone handling for multi-region bookings
  • feat: maintenance log with photo upload
  • chore: performance audit — reduced dashboard load time by 60%

What I'd Do Differently

Over-engineered the PDF generation early. I spent half a day wiring up a PDF library before the client had even confirmed they wanted PDFs. Ship the basics first.

Database migrations mid-project are painful. The schema changed three times in week 2 as I understood the business better. Starting with a more flexible draft schema would have saved a few hours of migration headaches.

The dispatcher loved the dashboard more than I expected. The fleet grid view — showing each trailer as a card with status colour coding — became the feature they mentioned to everyone. I almost cut it to save time.

Result

The client went from "we manage everything in a spreadsheet" to having a system that:

  • Prevents double bookings automatically
  • Sends confirmation emails to clients
  • Gives the dispatcher a live view of the entire fleet
  • Logs maintenance history per trailer
  • Generates PDF receipts on demand

It's not the flashiest project, but it's the kind of software that makes a real difference in someone's day. That's what keeps me building.


More posts incoming — including a full breakdown of the security company website rebuild. If you have a project you'd like to discuss, get in touch.