End-to-end laundromat management system with washing machine control

Stack: Claude Code · React 19 · Tailwind · Node.js + Express 5 · PostgreSQL · JWT · IoT (eWeLink/Sonoff) · Netlify · Fly.io · Supabase

Status: deployed to production, rolling out lavanderia-el-sol-demo.vercel.app

I rebuilt Lavandería El Sol's system from scratch: customers, orders, machines, inventory, cash register, reports and multi-branch support. The app switches the washing machines on and off through Sonoff relays, so a machine only gets power once its order has been paid.

Context

Lavandería El Sol was running on a system they had no source code for, with no way to fix bugs, adapt their processes or grow. Given those limits, we decided to rebuild the system from scratch while keeping the functionality the business depends on.

The project was handled end to end: business research and analysis of the previous system, wireframe definition, high-fidelity interface design, prototyping in Figma and software development.

Goal

Modernize the system, improve the architecture, leave room for future work and keep the functions the business runs on.

My role in the project

  • • Requirements gathering
  • • Analysis of the existing system
  • • Data model and architecture design: PostgreSQL, REST API, roles, multi-branch support and the device layer.
  • • Full backend (Node.js/Express) and frontend (React) development
  • • UX/UI architecture
  • • Hardware integration: registering the app with the manufacturer, OAuth, pairing the relays and testing against the physical machines.
  • • Deployment and operations: production pipeline, automated migrations.
  • • Automated backend and frontend tests, plus a security audit.
  • • Project documentation.

Designing before coding

After analyzing the product and its requirements

The process:

  • 1. Research — I interviewed the owner and studied the previous system to separate what genuinely worked for them from what they struggled with every day.

  • 2. Wireframes — I worked out structure, hierarchy and flows in low fidelity, with no color or styling, so we could discuss what comes first on screen without the conversation drifting to button colors.

  • 3. High-fidelity interface — I defined the palette, typography, iconography and the finished screens.

  • 4. Component library — I built the components in Figma with their variants, plus shared color and text styles.

  • 5. Clickable prototype — I linked the screens and walked through complete flows — taking an order, charging for it, assigning a machine, closing the register — to find the unnecessary steps before they cost code.

  • 6. Validation with the client — I walked them through the prototype and adjusted it before writing code.

The design decisions, and why:

  • Mobile first — The work happens standing up, phone in hand. I designed the mobile view first — bottom menu within thumb's reach, floating action button — and the desktop view alongside it for the admin screens, where the owner really is sitting down going over sales. On desktop the navigation becomes a sidebar that shows the links that fit and sends the rest to a menu, instead of shrinking everything until nothing is readable.

  • Color carries the state — Green means "done, come get me"; amber means "careful, this is a simulation or a warning"; red means money or danger. An employee should know which machine needs attention from across the counter, without reading a word. That is why every state color has its own light background tone: the whole card changes, not just a label.

  • Type sized by function — Text sizes aren't picked one by one: they're defined by their role — the big number in a KPI, the amount of a sale, a machine's timer, a card title — and that's what makes two screens built months apart look equally solid.

  • One screen, one task — Creating an order, charging for it, assigning a machine and closing the register are distinct moments with distinct levels of urgency. No giant form that does everything: the delicate steps (payment, register close-out, removing a load) happen in their own view or in a modal that forces a confirmation.

  • Immediate feedback on every action — The app confirms with movement: the checkmark draws itself, errors shake the field, notices slide in rather than appearing out of nowhere. When someone takes a payment or starts a washer, they need to know right away that it went through, instead of staring at the screen wondering.

  • Validation with the client — I walked them through the prototype and adjusted it before writing code.

System features

  • •

    Service orders — two services (self-service and drop-off) with counter-friendly order numbers, a per-load model (each load with its washer, dryer, garments and products), a lifecycle with transitions validated on the backend and an auditable history of every change.

  • •

    Customer receipt — a receipt laid out like a register ticket, sent over WhatsApp as an image: the receipt node is rasterized and handed off through the phone's share sheet.

  • •

    Machines and pickups — a catalog of washers and dryers by type and size, timers per load type, machine assignment at pickup time, and usage and revenue metrics per machine.

  • •

    IoT machine control — the app powers the washer on when a paid load starts and powers it off when the load ends, through Sonoff relays.

  • •

    Users and roles — JWT with a three-level hierarchy, a single session per account, check-in on the first login of the day, and permissions validated on the backend, not merely hidden in the interface.

  • •

    Cash register — opening, movements, close-out with "expected vs. counted" and history, automatic close at midnight and every payment tied to its register session. One open register per branch, enforced at the database level.

  • •

    Inventory — bulk and branded products (sold by bottle or by cap), bags by roll, supplies, minimum stock with alerts, movement history and a daily closing report. Stock is reserved when added to an order, deducted on payment and released on cancellation.

  • •

    Sales and reports — revenue per period attributed to the actual day of payment, breakdowns by line item and payment method, charts, performance per employee and export to PDF and CSV.

  • •

    End of day — an automatic job that, at the configured local time, releases forgotten machines, normalizes orders and closes sessions.

  • •

    Multi-branch — each employee works their own branch; admins switch branches from the header.

  • •

    Installable app (PWA) — installs on Android and iPhone straight from the browser.

Technical challenges

  • • Designing an architecture that works without internet
  • • Integrating physical control of the washing machines over IoT
  • • Keeping data in sync between the local system and the cloud

Technologies

AI

  • • Claude Code

Frontend

  • • React 19
  • • Vite 7
  • • Tailwind, CSS 3
  • • Recharts
  • • Progressive Web App (PWA)

Backend

  • • Node.js
  • • Express 5
  • • REST API
  • • JWT + bcrypt
  • • Helmet

Database

  • • PostgreSQL
  • • Triggers
  • • Partial unique indexes

Integrations

  • • IoT with Sonoff devices (relays over the eWeLink cloud)
  • • OAuth 2.0

Infrastructure

  • • Netlify
  • • Fly.io
  • • Supabase (managed PostgreSQL with session pooler)
  • • Git (continuous deployment)

Quality

  • • Vitest (backend and frontend)
  • • Testing Library
  • • Supertest
  • • ESLint
Claude Code React Vite Tailwind CSS PWA Node.js Express PostgreSQL JWT Sonoff / eWeLink OAuth 2.0 Netlify Fly.io Supabase Vitest

Impact

What the new system makes possible for the business:

  • •

    The business no longer depends on a system it couldn't modify: every counter process (taking in, charging, handing over, closing the register) runs on software built for them and open to change.

  • •

    A washing machine only gets power once the order has been paid: the counter rule that used to depend on nobody getting distracted is now enforced by the system.

  • •

    Register close-out went from being balanced by hand to being calculated automatically, with "expected vs. counted", a history of discrepancies and a split between cash and payments taken outside the drawer.

  • •

    Inventory no longer drifts out of balance from simultaneous sales, thanks to the transactional reservation system.

  • •

    Admins can see sales, performance per employee and usage per machine from their phone, across any of their branches.

Built with care & love ❤️   2026