Product Story
RevRent
UX/UI Audit & Design System — Directed Through AI
At a Glance
| Role | UX/UI Designer, directing AI-assisted implementation inside a live, multi-developer team |
|---|---|
| Timeline | August 2026 — this phase shipped and merged; next phase paused by mutual agreement pending real usage data |
| Stack | React · Tailwind · FastAPI · PostgreSQL · Git |
| Tools | Claude · Claude Code |
| Key Outcomes | Unified navigation and filtering vocabulary across five core product areas · replaced duplicated interaction patterns with reusable components · caught a cross-branch UX regression before it reached production · established a repeatable verification practice for AI-directed implementation |
Overview
RevRent is a live, multi-tenant SaaS platform for rental operators (golf carts, paddle boards, and similar equipment businesses), built rapidly and launched to its first real operator the same week this engagement began. The product was already functional and, in places, genuinely well designed — but it carried the normal scar tissue of software built fast under launch pressure: the same interaction pattern invented three or four different ways across the app, a single visual component quietly doing four unrelated jobs, and no written record of why any of it had been decided.
The mandate wasn't a redesign. It was an audit: find what's actually broken, fix it without disrupting real operators already relying on the product, and establish reusable patterns — with the reasoning behind them documented — so the next inconsistency doesn't get invented from scratch.
The Problem
For operators using the product
- The same kind of control — a filter, a view switch, a status toggle — looked and behaved differently depending on which page you were on.
- Some filters silently combined incorrectly; others couldn't combine at all when logically they should have.
- Zero-count badges rendered as a literal "0" in some places and were hidden entirely in others.
- A page's own sense of "where am I" was frequently reversed or missing — a navigational trail rendering above the page title it was supposed to support, or not existing at all.
For the team shipping the product
- No shared component existed for several patterns that had already been hand-rolled independently five or six times.
- Design decisions lived only in the head of whoever made them, with no record for the next session — human or AI — to inherit.
The core insight
The product had no shared vocabulary for its own interface — so every new page reinvented one, and every reinvention drifted a little further from the last.
Constraints
- Time: Sessions were compressed and self-contained — hours, not days — inside a product under continuous active development.
- Stack: An existing, working application already in production. No rebuilds, no framework changes — every fix had to compose with what real operators were already using.
- Team: Not a solo build. A small team was actively committing to the same repository throughout, several times a day, which meant every change had to be verified against a codebase that could have moved since the last sync.
- Audience: Real operators, mid-use, on a product whose long-term direction was itself still an open, evolving question.
How AI Fit Into the Work
The audit, taxonomy, UX decisions, scope, and implementation verification were my responsibility. Claude Code worked directly against the active repository to implement those decisions. Nothing was considered finished because a session reported success — every change was checked against the current repository, the rendered product, the test suite, and any upstream changes before it shipped. The concurrency issues below show why that verification discipline mattered.
Phase 1: Establishing the Taxonomy
Approach
Before fixing anything, the actual scope of the inconsistency had to be named precisely. A single visual pill component was found doing four structurally different jobs — navigation, filtering, multi-select input, and single-value selection — across sixteen separate files, with no visual distinction between them.
Key UX Decisions
Component Taxonomy
Split the shared visual language into purpose-specific components: a contained "segmented track" for navigation, a dismissible loose chip for filtering, a checkbox-affordance variant for selection. Same design language throughout — each now signals its actual function rather than relying on context alone.
Navigation & Breadcrumb Order
Corrected a reversed hierarchy: page title now always states the current location first; a breadcrumb trail sits below it as supporting context, appearing only once navigation genuinely goes deeper than a page's own tabs can express.
Badge Stability
Any count badge — on a navigation tab or a filter chip — must reflect a stable, unfiltered total, never whatever happens to be currently selected. A badge that changes while a user types into search reads as the data itself shifting, not as filter feedback.
A deliberate exception, not a rule: Settings kept its existing, denser layout rather than being folded into the new taxonomy — a product owner explicitly preferred seeing every option on one screen over a cleaner hierarchy that would have required drilling into buckets to find things. Consistency isn't the goal in itself; the goal is the right pattern for how the page actually gets used.
Phase 2: Scaling the Pattern
Approach
A second session extended the taxonomy from Phase 1 across the product's core operational modules — dispatch, bookings, fleet, service, customer records — proving the rules held up against real, varied backend shapes rather than just the one page they were invented on.
Key UX Decisions
Primary/Secondary Filter Layering
Where a page had one real filtering dimension, it stayed as chips. Where a page stacked multiple dimensions on the same table, the primary dimension stayed as chips and every additional dimension demoted to a dropdown — applied consistently across five separate pages, each with a different underlying data shape.
Shared View-Toggle Component
Extracted a single component for switching between display modes of the same data (list/calendar, timeline/map, table/diagram), replacing six independently hand-rolled implementations.
Managing Live Codebase Collisions
Two things surfaced while shipping this work that had nothing to do with visual design and everything to do with what "done" means on a product multiple people are changing at once.
A same-day data collision
While converting a location filter to a dropdown, verification surfaced that another engineer had fixed the exact same underlying data bug on the shared branch that same day — independently, with its own test coverage. Rather than overwrite it, the two changes were reconciled line-by-line against the actual upstream diff, reusing their parameter shape and porting their tests rather than duplicating weaker ones.
A mid-review regression
Code review caught that a new feature had landed on the main branch after this work was already built — a fourth view the shared toggle component had no knowledge of. A naive merge could have silently dropped that feature's entry point from the interface while its code kept running underneath, reachable only by hand-editing a URL. Nothing would have failed a test. It was a UX regression created by concurrent development, not a design mistake — and a colleague caught it, restored the entry point, and wrote a test that derives the interface's expected state from the page's own logic, so the same kind of drift can't go unnoticed again.
A third, smaller version of the same risk — two sessions independently claiming the same backlog-item number — was caught by CI before it reached review and resolved by renumbering.
The throughline: verify against the live repository, never against a session's own summary of itself — whether the session is yours or someone else's.
Results
- Unified navigation and filter patterns now live across Fleet, CRM, Bookings, Dispatch, and Service.
- A structural badge-counting bug caught and corrected on three separate pages, each with a different data model, before any of them shipped.
- Same-day overlapping work with another engineer reconciled without losing either side's shipped feature or test coverage.
- Merged after full frontend and backend verification, including tests run across multiple clock conditions; no known regressions reached production.
- Several additional real inconsistencies were found, fully documented, and deliberately left unbuilt — outside what had actually been agreed for that session.
What I'd Measure Next
- Whether filter- or navigation-related friction appears in support requests or operator feedback now that the patterns are consistent.
- Whether any of the documented-but-deferred findings show up as real friction in usage — component reuse alone won't tell us; drop-off or hesitation at specific steps would.
- Whether the badge-stability and filter-layering rules hold up as more modules get built, or a case emerges the rule doesn't cleanly cover.
Reflections
The clearest signal of judgment on this engagement wasn't any single fix. It was recognizing, mid-session, that the audit had surfaced more real problems than had actually been asked for that day — and choosing to stop anyway, document everything precisely, and close out exactly at the boundary of what was agreed. Formal design-system documentation was deferred the same way, for the same reason — worth writing down once the patterns have been tested against real usage, not before.
The backlog is documented and ready. The next move isn't to keep building against assumptions. It's to let the product run under sustained operator use, and let evidence decide which problems are actually worth solving next.