Profile    Mohammed Shiroz Status   Loading  
Logo
Share This
Back to blog
Filter by:
Tags
//Article title

Designing a Maintenance Request System That Tenants Actually Use

24 Jul 2025Category : Blog

About Post

A leaking tap is a simple problem. Getting it fixed often isn't. The tenant calls the office, gets told to send a photo on a messaging app, explains the unit number twice, waits, calls again to ask if anyone is coming, and finally someone turns up when nobody is home.

When we built maintenance requests into Kate PMS, I realised the real competitor wasn't another software product. It was the phone call and the chat message. If reporting a problem in the tenant app is slower or less reassuring than calling someone, tenants will call. And then the system is just a database that staff have to fill in by hand.

So the design goal was simple to say and harder to do: make the app the easiest way to get something fixed. Here's how I think about each part of the flow.

1. Reporting: under a minute, photo first

A tenant reporting a problem is usually standing in front of it, slightly annoyed, with a phone in their hand. So the flow starts with what they can do fastest: take a photo.

  • Photo first, text optional. A picture of a water stain explains more than a paragraph, and it's easier than typing in a second language.
  • Categories with icons (plumbing, electrical, air conditioning, and so on) instead of a long dropdown. They also help route the request on the staff side.
  • Never ask for what we already know. The tenant is logged in and linked to their tenancy contract, so the unit is filled in automatically. Every field you remove is a reason not to pick up the phone instead.
  • Access details up front. When it's convenient to visit, and whether someone can enter if nobody is home. This is the question that otherwise causes the most back-and-forth later.

The app is React Native with Expo, and two small technical choices matter a lot here. Photos are resized and compressed on the device before upload, because a full-resolution phone photo over a weak signal is a great way to make the submit button feel broken. And submissions are safe to retry, so a tenant tapping "Send" twice on a bad connection doesn't create two requests.

2. Status: a state machine, not a free-text field

The backbone of the whole feature is the request's status. It's tempting to make it a simple string column that anyone can change to anything. That leads to requests that jump from "submitted" straight to "closed" with no record of what happened.

Instead, statuses and their allowed transitions are explicit. In simplified form, the idea looks like this:

enum RequestStatus: string
{
    case Submitted = 'submitted';
    case Assigned = 'assigned';
    case InProgress = 'in_progress';
    case Completed = 'completed';
    case Closed = 'closed';

    public function canMoveTo(self $next): bool
    {
        return in_array($next, match ($this) {
            self::Submitted => [self::Assigned],
            self::Assigned => [self::InProgress, self::Submitted],
            self::InProgress => [self::Completed],
            self::Completed => [self::Closed, self::InProgress], // confirm or reopen
            self::Closed => [],
        }, true);
    }
}

Every transition goes through one method that checks the rule, records who made the change and when, and fires an event. That history becomes the timeline the tenant sees, and it's also what makes it possible to see where requests tend to wait.

3. Assignment: the staff side matters just as much

A tenant app is only as good as what happens behind it. On the staff side, the goal is that nobody needs to pick up the phone to understand a request. Whoever assigns the work should be able to filter and sort the queue quickly, and the person doing the job should see the photos, the unit and the access details in the staff app before they arrive.

Role-based access does a lot of quiet work here. Different staff roles see and do different things: some assign, some update progress, some only view. Getting those boundaries right is less visible than a nice screen, but it's what keeps the data trustworthy.

4. Notifications: tell people what changed, not everything that happened

The number one reason tenants call about a request they've already submitted is uncertainty: "Did anyone see it? Is someone coming?" Push notifications answer that, but only if they're meaningful.

The rule I use: notify the tenant when something changes for them. Assigned, scheduled, completed. Not every internal note. That also means separating two kinds of comments in the data model: internal notes for staff ("waiting for a part from the supplier") and tenant-visible updates. Mixing them is a classic mistake, and an embarrassing one.

Technically, notifications belong in queued jobs, so a slow push service never slows down the staff member pressing the button.

The design rule behind all of this: every time a tenant has to ask "what's happening?", the system has failed to tell them. Status updates aren't a nice extra. They're the feature.

5. Closing the loop: the step most systems forget

In a lot of systems, the technician marks the job "done" and the request disappears. But "done" from the technician's point of view and "fixed" from the tenant's point of view aren't always the same thing.

So in the flow I design, completion isn't the end. The technician marks the work completed, ideally with an "after" photo. The tenant is then asked to confirm it's fixed, or to reopen it if it isn't, which sends it back to in progress with the history intact instead of starting a brand-new request. If the tenant doesn't respond, the request closes automatically after a while, so nothing stays open forever.

That small confirmation step changes the relationship. The tenant has the last word on whether their problem is solved, and staff get a clear signal when a fix didn't hold.

What I'd tell anyone building something similar

  • Your competitor is the phone call. Measure every screen against "is this easier than calling?"
  • Pre-fill everything you already know about the user.
  • Model statuses as a state machine with a history, not a string column.
  • Separate internal notes from customer-facing updates in the data model.
  • Notify on changes that matter to the person receiving them.
  • Let the person who reported the problem confirm it's actually fixed.

None of these ideas are specific to property management. Any app that handles requests (IT support, deliveries, repairs, internal approvals) has the same shape.

If you've built a request or ticketing flow, which part was harder than it looked? For me it was notifications: deciding what not to send took longer than building the sending.

Comments (0)
Leave your review

Thanks for your valuable comments. Your comments has been updated and appreciate your getting in touch...

01. About Shiroz

Mohammed Shiroz

Hi, I'm Mohammed Shiroz, a software engineer and AI enthusiast from Sri Lanka who turns ideas into intelligent, real-world solutions. With over 9 years of hands-on experience, I currently lead real estate ERP development at Kate Group, a...

03.My Projects

04. Categories

Ready To order Your Project ?

Get in Touch
Close