Apartment Maintenance Fails When WhatsApp Becomes the Ticketing System
A production-grade guide to turning resident WhatsApp complaints into structured maintenance tickets, technician workflows, SLA reminders, audit trails, and manager reporting.
The leak is not the real problem
A resident sends a photo of a leaking AC. The admin forwards it to a technician group. The unit number is incomplete. The technician asks for clarification. The resident follows up at night. The manager only hears about the issue after it becomes a complaint.
The broken part is not the AC. The broken part is the workflow. Apartment maintenance looks simple until request intake, assignment, status update, proof photo, SLA tracking, and reporting all happen inside informal chat threads.
Keep WhatsApp. Replace the chaos behind it.
Residents will not install a new app just to report a jammed door. Technicians will avoid a heavy system if WhatsApp is faster. The right architecture keeps WhatsApp as the interface and moves structure into the backend.
OpenClaw becomes the coordination layer: classify the message, validate unit data, ask for missing details, create a ticket, assign the right technician, remind the team, and update the resident. The database becomes the source of truth.
Ticket state is the product
“Open” and “done” are not enough. A serious maintenance system needs states: new, triaged, assigned, in progress, waiting resident, waiting parts, done pending review, closed, and cancelled.
Those states are not bureaucracy. They are the language the system uses to tell residents what is happening and to tell managers where work is stuck.
const ticketLifecycle = [
'new',
'triaged',
'assigned',
'in_progress',
'waiting_resident',
'waiting_parts',
'done_pending_review',
'closed',
'cancelled'
]AI intake needs guardrails
AI is useful for parsing natural language: “AC kamar utama bocor, Unit A-1708, air netes terus.” It can extract category, unit, urgency, issue summary, and attachment presence.
But the system should not blindly trust the model. Unit numbers must match the database. Emergency keywords must trigger a fast path. Duplicate issues must be detected. Missing photos or missing access information should trigger clarification.
async function intakeMaintenanceMessage(message) {
const extracted = await classifyMaintenanceIntent(message.text)
const unit = await db.units.findByCode(extracted.unitCode)
if (!unit) return ask('Please confirm your tower and unit number.')
if (await isDuplicate(unit.id, extracted.category)) return attachToExistingTicket()
return createTicket({
unitId: unit.id,
category: extracted.category,
priority: extracted.priority,
description: extracted.summary,
attachments: message.attachments
})
}SLA reminders should be honest
Do not create impossible SLAs. If a building has one technician, a ten-minute resolution promise is theater. Separate first response from resolution. Acknowledging a resident is not the same as fixing the issue.
The reminder worker should watch P1 tickets that were not acknowledged, P2 tickets not assigned, in-progress tickets with no update, waiting-parts tickets with no ETA, and completed tickets awaiting resident confirmation.
// sla-reminder.worker.ts
for (const ticket of await tickets.open()) {
if (ticket.priority === 'P1' && !ticket.acknowledgedAt) escalate(ticket)
if (ticket.priority === 'P2' && !ticket.assignedTo) remindManager(ticket)
if (ticket.status === 'in_progress' && stale(ticket.updatedAt)) remindTechnician(ticket)
}Technician workflow must be lightweight
The technician flow should be brutally simple: receive assignment, open ticket detail, start work, add note, upload proof photo, mark done. Every action writes an event to the audit trail.
Audit trail matters because maintenance creates disputes. If the resident says nobody came, the manager needs timestamps. If the technician says the part was replaced, the system needs a photo, note, and closure status.
type TicketEvent = {
ticketId: string
eventType: 'assigned' | 'started' | 'photo_uploaded' | 'status_changed' | 'resident_notified' | 'closed'
actorId: string
note?: string
createdAt: string
}The dashboard should answer operational questions
A manager dashboard should not exist to look modern. It should answer: how many tickets are open, which are overdue, which categories repeat, which technicians are overloaded, which units have recurring issues, and how long resolution takes.
Start with Today, Open, Overdue, and Closed. Once ticket data is reliable, add recurring issue analytics and monthly reporting. Data quality first. Dashboard sophistication second.
What NovaFlow would build
A NovaFlow implementation would map the building’s real categories, resident channels, technician roles, escalation rules, SLA expectations, proof requirements, and reporting format before writing the agent logic.
The deliverable is not a bot. It is a maintenance workflow system with WhatsApp intake, ticket database, technician action trail, SLA reminders, dashboard visibility, and management reports.