Case study · Pickup and delivery laundry in South Tangerang, Indonesia

I Wish You Wash Here

A booking and operations system for a pickup and delivery laundry: a customer website, an Admin dashboard, and a Driver app. Prices are calculated on the server, weighed with evidence, and approved by the customer before anything is washed. Life's Too Short to Do Laundry.

Next.js · FastAPI · PostgreSQL Live since November 2026 Zero hosting cost
Visit the live website ↗

Admin dashboard

The owner sees bookings and revenue per day, active customers, average booking value, and the best-selling services. Revenue comes from verified payments, using the same formula as the daily report.

Admin dashboard: tiles for bookings, active customers, revenue, and average per booking, line charts of bookings and revenue per day, and a bar chart of top services
A 90-day trend with a 30 or 90 day toggle, per-day tooltips, and a data table for screen readers.

The dashboard in this screenshot uses sample data for a scale test: 1,345 bookings and 972 customers over 90 days.

Booking from a phone in four steps

The target customers are busy professionals who browse on their phones and are often away from home at pickup time. Booking needs no account, and the schedule is honest: full time slots cannot be selected.

  1. ServicePick a category first, then the service. Specialty services are routed to WhatsApp.
  2. ScheduleThe next 14 days, with the remaining slots for each pickup window.
  3. DetailsAddress, area, and who can hand over the laundry if the customer is out.
  4. SummaryA price estimate from the server, then a booking code and live status.
Service step on a phone: four category cards for Kiloan, Satuan, Premium Care, and Specialized Cleaning
Step 1, service categories.
Schedule step on a phone: pickup or self drop-off, a row of dates with remaining slots, and pickup windows
Step 2, dates and windows with remaining slots.
Home page on a phone with the headline Life's Too Short to Do Laundry and a Booking Sekarang button
Home page with the main booking button.

Weekly booking schedule

Admins see a whole week in seven columns: pickup, delivery, and self drop-off cards with their time and status. On a phone, the same view becomes a list per day.

Weekly booking schedule on desktop with seven day columns of pickup, delivery, and self drop-off cards
Desktop: filter by type, move between weeks, and open any card for the booking details.
Admin booking schedule on a phone: a row of days and the bookings for the selected day
Phone: pick a day, then see its bookings.

Rules the system enforces

Prices come only from the server

The frontend never sends a price. The backend calculates every quote from a versioned catalog and saves a new version whenever it changes.

History cannot be overwritten

PostgreSQL triggers reject changes to weight records, price quotes, approvals, status history, and the audit log.

Nothing is washed before approval

The database refuses the processing status until the customer approves the latest quote through their link.

A slot cannot be booked twice

The pickup window row is locked while a booking is checked, so two customers cannot both take the last slot.

Permissions are checked on the backend

Admins, staff, and drivers have different permissions. Hiding a menu on screen is never the only guard.

Tested in real browsers

Playwright end-to-end tests in Chromium and WebKit against the production build, backend tests with pytest, and checks at 375px and desktop widths.

Technology and infrastructure

Frontend
Next.js, TypeScript, Tailwind CSS, Zod. A static export on Cloudflare Pages.
Backend
Python, FastAPI, SQLAlchemy, Alembic, PostgreSQL 16.
Zero-cost hosting
Cloudflare Pages and a Worker, then a Cloudflare Tunnel to a Mac mini at the outlet. No ports are open to the internet.
Operations
Docker through Colima, launchd schedules, encrypted database and photo backups, and releases with automatic rollback.