← Back Sweep — Case Study
Self-initiated concept · 0→1 SaaS · 2026

Three people share one job. They should not share one screen.

Sweep is a self-initiated concept for a SaaS operations platform for commercial cleaning and facilities companies. I designed one system and three doors into it — an ops command center, a frontline mobile app, and a client portal — then the marketing site that sells it.

My role

Product Designer — end to end

Scope

Design system · 3 product surfaces · marketing site

Domain

B2B SaaS · Field operations

Built in

Claude Design · 2026

The industry runs on group texts and clipboards

01 — The problem

Commercial cleaning is a coordination business wearing the costume of a labour business. The actual product a cleaning company sells is not mopping — it is the promise that a building will be covered, every night, and that someone can prove it was.

Almost none of that promise is instrumented. A no-show at 10pm becomes a phone tree. A client asking "did anyone come Tuesday?" becomes a search through someone's messages. An extra job the client asked for in a hallway conversation becomes an invoice line nobody remembers agreeing to. The failure mode is never one big breakdown — it is a hundred small unrecorded handoffs.

Symptom

Coverage is discovered late

Nobody knows a shift is uncovered until the cleaner has already failed to show. By then the only lever left is an apology to the client.

Symptom

Proof lives in someone's camera roll

Work gets photographed, then buried in a personal phone. When a dispute arrives weeks later, the evidence is unreachable.

Symptom

Extra work has no paper trail

"Can you also do the carpets?" gets agreed verbally and argued about at invoice time. The money conversation happens after the work, not before.

How might we

"How might we give an ops manager, a cleaner and a client one shared record of the night's work — without showing any of them things they shouldn't see?"

One job, three completely different jobs-to-be-done

02 — The users

The temptation in a multi-sided product is to build one flexible interface and hand everyone a different permission set. I ruled that out early. These three people are not doing the same task at different zoom levels — they are doing genuinely different work, in different physical conditions, with different failure costs.

Ops manager

Desktop · dense · triage

Sits at a 1440px screen, watches many sites at once, and needs to spot the one thing going wrong across all of them. Optimises for scanning and speed of action. Reads like a well-run clipboard, not a consumer app.

Frontline cleaner

Mobile · one-handed · on-site

390px, in a stairwell, in poor light, often on bad signal, sometimes not in English. Needs three things and nothing else: where am I, what do I do, how do I prove I did it. Every tap target is 44px minimum.

Property manager

Responsive · occasional · trust

Opens the product a few times a week, usually because something is wrong or something extra is needed. The design job here is reassurance and a clean paper trail, not efficiency.

The constraint that shaped everything

Each surface is a deliberate subtraction, not a filtered view. The cleaner app does not contain client contacts or other crews' sites. The client portal does not contain cleaner personal details, pay, or leave. Both state this in plain language at the bottom of the screen, so the boundary is a visible feature rather than an invisible permission.

The two-lane model for client requests

03 — The core product decision

The hardest decision in this project had nothing to do with layout. When a client wants something done, there are two completely different things they could mean — and collapsing them into one "request" button is where the trust in this industry actually breaks.

Either the work was already paid for and it wasn't done properly, or the work is new and someone has to agree on a price. One of those is a complaint the vendor owes you for free. The other is a purchase. If a client fires off a "request" without knowing which lane they're in, they either get billed for something they thought was covered, or they sit waiting for a fix that was actually a quote.

So I split them at the navigation level, gave them different colours, different language, and a cross-link on each page pointing at the other one.

Lane 1 · covered by contract

Report a service issue

Contracted work was missed or done poorly. Never generates a charge.

  • Client picks which contracted service failed, from their actual contract
  • Outcome states are Under review → Rework scheduled → Resolved
  • Every card repeats "No charge — covered by your contract"
Sweep client portal — report a service issue form, with a banner stating the report is covered by the contract at no cost
Lane 1 — the form leads with "no charge"
Sweep client portal — submit an additional request form, with trade, urgency and preferred window
Lane 2 — the form leads with "you'll get a quote"
Sweep client portal — list of reported service issues in rework scheduled, under review and resolved states
Issue states — under review, rework scheduled, resolved
Sweep client portal — list of additional requests showing quoted with a countdown, approved, new and declined states
Request states — quoted with a countdown, approved, declined
Why this is the spine of the product

Everything downstream inherits this split. The ops dashboard has two separate inboxes rather than one queue. The invoice screen lets a client dispute a single line item instead of the whole invoice. A billing model turned out to be an information architecture problem.

"Hi-vis navy" — a system built for bad lighting

04 — The design system

I built the system before any screens, because three surfaces at three densities only stay coherent if the tokens decide it rather than my memory. The visual brief I wrote for myself was a well-run clipboard: cream paper, deep navy ink, and exactly one hi-vis colour that does all the pointing.

Cream#F6F4EF
Navy#1E2A3A
Amber#E8A23D
Success#2F8577
Danger#C24F3D
Ad-hoc#7A5EA6

Cream, not white

The page background is warm cream rather than white. It is softer under the fluorescent light of a service corridor and on the cheap Android handsets crews actually carry.

One accent, rationed

Amber is reserved for the single most important action or signal on a view — the hero CTA, an at-risk shift, the active tab. It is never decorative, and never used as text on cream because it fails AA there.

Status is never colour alone

Six job states, each carrying a colour, a dot and a written label. The system survives greyscale, colour-blindness, and a phone screen in direct sunlight.

Two density modes

Compact for the ops desktop — 32px controls, 40px rows. Comfortable for the cleaner's phone — 44px everything, which is the tap-target floor, not a preference.

Numbers are monospaced

Every time, hour count, shift code and dollar figure is IBM Plex Mono with tabular figures, so a live-updating dashboard does not jitter as digits change.

Motion only when functional

140ms for state changes, 220ms for entrances, 320ms for exits. No glassmorphism or backdrop blur — it degrades badly in poor light and on low-end devices. Everything collapses to 0ms under reduced motion.

Sweep design system specimen board — brand palette, six-state status system, type scale, status tints, motion durations, radii and elevation, and the two density modes
Specimen cards from the system — palette, status map, type scale, motion, elevation and density

The library that came out of it is thirteen components — Button, Input, Select, StatusBadge, SLAChip, ShiftCard, WorkerRow, ChecklistItem, Tabs, Toast, Modal, Skeleton and EmptyState — plus six token files. Two colours in the palette exist only because the status system needed them: info blue for in progress and plum for ad-hoc request, both added so those states could not be confused with amber at risk.

Surface one — the ops command center

05 — Ops manager

The ops manager's screen answers one question before any other: what is going wrong right now, across every building I am responsible for?

So the dashboard opens with an urgent band pinned above everything else, sorted by severity, before the user has picked a site. Only underneath that does the layout become per-site: live staff on shift, the two request lanes, contracted services with their last-completed times, and an editable financial summary.

Sweep ops manager dashboard — urgent band, site tabs, live staff on site with at-risk and late states, additional requests and financials
Ops dashboard — urgent first, then the site you chose

At-risk before no-show

A worker who has not checked in 18 minutes into their window is amber and "At-risk · LATE +18m", with an Assign button already on the card. The state exists so the manager acts during the window rather than after it.

Overtime shown at the moment of assigning

Worker cards carry a running weekly total — "41h this week · OT" — so the cost of a reassignment is visible at the point of the decision, not in a payroll report next month.

Overnight shifts written honestly

A 10:00pm–6:00am shift is labelled with both dates. Split shifts and shifts crossing midnight are the norm in this industry, and a calendar that silently truncates them is worse than no calendar.

Contracted work has a last-completed column

The recurring services table shows frequency, window and when it last actually happened — including "Missed Jul 16" in danger red. It is the vendor's own honest record before the client ever asks.

Surface two — the frontline app

06 — Cleaner mobile

This is the surface I was strictest with. It has three tabs — Today, Chats, You — and I rejected everything that did not survive the question: would a cleaner standing in a service corridor at 11pm need this in the next thirty seconds?

Sweep cleaner app — today's shifts with a task checklist and photo-required task
Today — one shift open, the rest collapsed
Sweep cleaner app in offline mode — offline banner and a photo queued for retry
Offline — work continues, the photo queues
Sweep cleaner app — group chats scoped to the sites the cleaner is assigned to
Chats — only this cleaner's own sites
01

Offline is the assumed state, not the error state

Basements and stairwells do not have signal. Going offline shows a calm amber band — "Changes save on this phone and sync when signal returns" — and the checklist keeps working. A photo that cannot upload becomes "Photo queued — 1 waiting, will retry when back online" with a manual retry. Nothing is lost and nothing is blocked.

02

Photo proof is a task property, not a separate step

Tasks that need evidence are marked "Photo required" with the camera affordance inline on the row. You cannot mark it done without it, and the error copy says what to do — "Add a photo before marking done" — rather than "Invalid input".

03

English and Spanish, switched in the header

EN/ES sits in the top bar of every screen rather than buried in settings, because the person who needs it needs it on their first launch, and may be handed the phone by someone else.

04

The escape hatch is on the shift card

"Can't reach site / report issue" sits directly under Check out. Locked door, wrong access code, no supplies — the most common real failure is one tap from where the cleaner already is.

05

Pay and leave are estimates, labelled as estimates

The pay screen shows earnings in progress with an explicit line: final pay is confirmed by the office before payout. A denied leave request carries the manager's reason and a "Request again" button, because a denial without a reason is how people stop using a tool.

Sweep cleaner app — monthly pay with weekly breakdown and next payout
Pay — in progress, with the caveat stated
Sweep cleaner app — leave requests with a denied request showing the manager's note
Leave — a denial carries its reason
Sweep cleaner app — account and preferences, with a visible statement of what the cleaner can and cannot see
You — the privacy boundary, written down

Surface three — the client portal

07 — Property manager

The client's version of the product is not a smaller dashboard. It is a receipt. Its whole job is to let a property manager answer a question from their own boss without phoning the vendor.

Today's overview leads with who is physically in the building right now and when they checked in, then the day's scheduled work with photo proof attached to what is already done. The schedule marks recurring contract work, rework, and work that came from an additional request as three visibly different things, so the client can always trace a job back to the reason it exists.

Sweep client portal — today's overview showing who is on site now, check-in times and photo proof
Today's overview — live presence, then proof
Sweep client portal — weekly schedule distinguishing recurring contract work, rework and additional requests
Schedule — every job carries its origin
Sweep client portal — invoices with line items and a per-line dispute action
Invoices — dispute the line, not the invoice
A small decision I care about

The dispute control sits on the individual line item. Disputing a whole invoice is an adversarial act that stops a payment; disputing one $480 add-on is a question. The invoice keeps a separate "Under review" state so the rest of the balance stays payable — the design lets the relationship survive the disagreement.

The escalation loop that closes the triangle

08 — Cross-surface flow

The three surfaces are only worth building as one product if something can travel between them. The clearest case is an ad-hoc specialist job — a dead outlet, a flickering light — posted by the client into a per-trade group chat where individual contractors can claim it.

The interesting part is what happens when nobody claims it. Rather than letting the request rot in a chat thread, an unclaimed request is automatically handed to the vendor after a set window, and lands in the ops manager's urgent band as an escalation with its own provenance line — "From group chat · unclaimed 3h · auto-escalated". The client sees the same handoff explained in their own thread.

01 · Client

Posts an ad-hoc request into the trade channel — electrical, plumbing, lawn care.

Unclaimed
02 · Contractors

Members of that channel see it and one claims it, with their name attached.

Claimed
03 · Timer

Nobody claims it inside the window. The system does not wait for a human to notice.

Unclaimed 30m
04 · Vendor

Auto-escalated to the cleaning vendor and shown at the top of the ops dashboard.

Escalated
05 · Ops

Manager claims it and assigns a technician. Both sides see the same status.

Assigned
Sweep client portal — per-trade group chats showing claimed, unclaimed, escalated and done ad-hoc requests
Group chats — a request thread with claim, escalation and completion states
Design principle

An unanswered message is a state, not an absence. Most operational software treats "nobody replied" as nothing happening. Here it is a first-class status with a timer attached to it, which is the only reason the escalation can be automatic.

Selling it in the same voice

09 — Marketing site

The last piece was a five-page marketing site built from the same tokens, which is where I found out whether the system was actually flexible or just consistent. It needed a display scale the app never uses, a two-voice split in the copy, and none of the visual crutches — no gradient hero, no stock photography, no glass panels.

The app voice is plain verbs in sentence case: "Assign", "Mark done", "Start shift". The marketing voice is allowed to be warm and declarative — "Cover every shift. See every clean." — but it still cannot use a colour the status system needs, and it still has to explain the three-doors structure honestly rather than pretending the product is one thing.

Sweep marketing site home page — hero, the three-doors section, and stat band
Home — one product, three doors, stated as the structure it is
Sweep marketing site pricing page — two plans with a full feature comparison table
Pricing — per-site plans with a full comparison table
Sweep marketing site services page — a section per surface
Services — one section per surface

Pricing was the useful exercise. Writing a two-tier feature table forced me to decide which capabilities are the product and which are the upgrade — Coverage Finder, the escalation loop, leave approvals and the dispute queue ended up on the paid side, while photo proof, offline tolerance and the client portal stayed in the base plan. A pricing page is a product spec that has to be honest in public.

What I would put in front of users first

10 — Reflection

This is a concept, not a shipped product, and the honest thing to say about it is which parts are decisions and which parts are assumptions.

What I am confident in

The two-lane split between service issues and additional requests. It resolves a real money-and-trust ambiguity, and every downstream screen got simpler once it existed rather than more complicated.

What I would test tomorrow

The cleaner app in an actual stairwell, on an actual cheap handset, with someone who does the job. Offline behaviour, photo capture and the EN/ES switch are the three things a comfortable desk can lie to you about.

The system paid for itself at surface three

Building tokens before screens felt slow through the first surface and obviously right by the third. The client portal took a fraction of the time because almost nothing new had to be invented.

Writing the copy is designing the product

"No charge — covered by your contract" is not microcopy sitting on a feature. It is the feature. Most of the trust in this design is carried by sentences, not layout.

Constraints beat capabilities

The strongest decisions here are all subtractions — what the cleaner cannot see, what the client cannot see, the single rationed accent colour, the three tabs.

The product is not the dashboard. It is the shared record that three people who never meet can all point at.
Next project

MedScor AI