Priestly
← All projects

Case study 03 / 03 · Vehicle Rental / Business App

Car Rental

A car rental booking site. Customers search for a car by dates and type, then book it by the day. Staff manage the cars and bookings from an admin panel.

Role
Solo · full-stack
Status
Working demo · real PostgreSQL database
Stack
Next.js · PostgreSQL · Prisma
Updated
Sept 2026
car-rental-xi-lemon.vercel.app
Car Rental homepage: “Rent the right car, right now”, with a search form for category, pick-up and return dates and driver's age

01

What the client needed, and what I built

A car rental business needs customers to see which cars are free for their dates and book them. The price shouldn't change after someone has booked. The minimum driver age has to be checked the same way everywhere. And staff need a simple way to manage cars and bookings.

01 · Availability

ProblemCustomers need to see which cars are free for their dates, and a car must never be booked twice.

BuiltSearch by dates, and the dates are checked again against existing bookings before a booking is saved.

The overlap check and the insert run in one transaction; a database exclusion constraint is the next step to make it airtight

Find my car wizard: picking a pick-up date on a calendar and the number of days

02 · Price

ProblemThe price shouldn't change after someone has booked.

BuiltThe total is calculated and saved at booking, so later rate changes don't affect it.

Booking sent: summary with the car, pick-up and return dates, duration, total price and pending status

03 · Rules

ProblemThe minimum driver age has to be checked the same way everywhere.

BuiltOne age rule is shared by the search, the car page and the booking.

The server re-checks it on every booking, since a direct request can skip the form

Booking a Volkswagen Golf, step 2 of 4: choosing the dates
All features (10)
  • Search cars by category, transmission and fuel type, or use the step-by-step "find my car" wizard
  • Book by the day with a date picker. The total price is saved when you book, so if the daily rate changes later, your booking stays the same
  • No double bookings: before a booking is saved, it's checked against the car's existing bookings for those dates, and the search hides cars that are already taken
  • Drivers must be 18 or older. This is checked in the search, the booking form and the admin view
  • Sign in with Google or with email and password (hashed with bcrypt), all through Auth.js
  • Only customers who completed a booking can leave a review, and only one per booking
  • Admin panel for cars and bookings. A car that has bookings can't be deleted, only archived, so the booking history is kept
  • A real confirmation screen after booking, not just a redirect to the homepage
  • Forms and admin pages work on mobile, including fixes for date fields breaking the layout on iOS Safari
  • Proper link previews: sharing the site on social media shows a card with the title and an image

02

How it's built

I built a Next.js app with a "find my car" search wizard, a page for each car with reviews, and a booking flow that checks the driver's age and books by the day. After booking, customers see a real confirmation screen. Staff get an admin panel for the cars and bookings.

Frontend
Next.js 16 (App Router) + TypeScript + Tailwind v4Server components for pages with lots of data, like car lists and bookings. Client components only where the user interacts.
Database
PostgreSQL (Supabase) + Prisma 7Cars, bookings and reviews are all linked, so a relational database fits. Prisma gives typed queries instead of raw SQL.
Auth
Auth.js (NextAuth v5)One system for Google sign-in and email/password. The Prisma adapter saves users and sessions in the database.
Animation
MotionUsed in the booking flow where it helps, not on every element.
Hosting
VercelMade for Next.js, with no server to manage.

03

What was hard

  • Keeping prices fair. The total price is calculated and saved when the booking is made, instead of being recalculated from the car's current rate.
  • Keeping booking history. A car with bookings can't be deleted (onDelete: Restrict). Archiving is the normal way to remove a car, so admins don't run into errors.
  • Mobile took several rounds of fixes: date fields overlapping the time dropdown, search fields that needed to stack full width, and an overflow bug that only showed up on iOS Safari.
  • Builds were failing on Vercel because the Prisma client wasn't generated. I fixed it by generating the client on install.
  • Auth.js only trusts the Host header automatically on Vercel and Cloudflare. On other hosts you have to allow it yourself, and that's a security decision, not a setting to switch on without thinking.

04

Result

It's live as a working demo on Vercel, with a real Postgres database. The full flow works: search, book, confirm, and manage cars and bookings as an admin. The site says clearly that it's a portfolio demo, not a real rental business.

05

Screens

8 screens · tap to enlarge

Need a booking system like this?

Availability by date, prices fixed at booking, and an admin for your team.

Talk on WhatsApp