This project was designed and built independently, using a realistic business scenario and sample data, not live client work. It's here to show how I think through a problem and build the solution end to end.
The Problem
One property manager had to read, judge, and route every request alone, often from memory: a warranty restriction here, a tenant's accessibility need there, details no system was tracking. A delayed emergency risks real property damage and liability, and without an audit trail, there was no record of what got handled or when.
The Solution
A Jotform captures each request and feeds it to an AI agent. The agent reads three reference documents, a vendor directory, unit notes, and an escalation policy, then classifies the category and urgency, picks the right vendor, and checks whether that unit's history should override the default call.
A separate keyword check runs in parallel and independently flags true emergencies, so a life-safety call never depends on the AI alone. Based on final urgency, the system dispatches automatically: an instant Slack alert for emergencies, an email plus Slack notice for urgent issues, or a standard email for routine ones.
The Result
Figures below are illustrative estimates based on typical small property management operations, not measured client data. This is a portfolio build, not a live deployment.
For a 20-unit property getting about 30 requests a month, this saves roughly 6 hours of manager time monthly, time previously spent on manual triage, vendor lookup, and dispatch at 10–15 minutes per request, using tools that run free.
The bigger win is speed on requests that matter most. A burst pipe or a gas smell dispatched in minutes instead of hours is the difference between a minor repair and a real damage claim, and a timestamped audit trail backs up the manager's position in insurance claims and tenant disputes.
In testing, all 11 scenarios resolved correctly, telling true emergencies apart from routine requests and applying unit-specific history where it mattered.
Architecture
Hover or tap a step to see what happens at that stage.
Tenant Request
IntakeTenant submits a maintenance request through Jotform, including issue details, location, urgency, and optional attachments.
How It Works
- 1
Tenant submits a maintenance request via Jotform (unit number, description, contact info).
- 2
n8n receives the submission instantly and validates required fields.
- 3
A keyword filter scans the description for emergency language (gas, flood, fire, sparking, no heat) as a parallel check on the AI.
- 4
The AI agent queries the knowledge base (vendor directory, unit notes, escalation policy) and returns a structured classification: category, urgency, vendor, SLA, and relevant unit history.
- 5
The two checks are reconciled: if the keyword filter flags an emergency, that wins regardless of what the AI decided.
- 6
Before dispatching, the system checks for a duplicate request from the same unit in the last 30 minutes.
- 7
Final urgency decides the channel: Emergency goes straight to Slack, Urgent gets email plus a Slack notice, Routine gets a standard email.
- 8
Every request, regardless of outcome, is logged to a Google Sheets audit trail: category, urgency, vendor, dispatch method and status, and the AI's reasoning.
- 9
A scheduled check runs every 30 minutes and alerts the manager if a vendor hasn't confirmed within its SLA window.
Engineering Decisions
The choices that mattered most, and the reasoning behind them.
AI + deterministic rules, not AI alone
The AI handles judgment calls, like which vendor fits or how urgent something sounds, but a keyword-based rule always overrides it for language like "gas" or "flood." A model can misjudge a wording it hasn't seen; a hardcoded rule can't.
RAG over a fine-tuned model
Vendor lists and escalation policies change often. Grounding the AI in three editable documents means a policy update takes effect on the next request, not a retraining cycle.
An audit trail on every outcome
Property management runs on liability. Every classification, dispatch, and failure gets a timestamped record, so a manager can answer what happened and when without relying on memory.
Vendor routing follows unit history, not just category
The same issue can mean different things depending on the unit. A recurring wiring problem or an accessibility need can override the default vendor or urgency, because two identical-sounding requests aren't always the same request.
Retries before escalation, not instead of it
A failed dispatch retries once automatically. If that fails too, it alerts the manager directly instead of disappearing into a queue. Automation should fail loudly, not silently.
Reliability, Security & Scale
Error Handling
Emergency classification never depends on the AI alone: the keyword check runs independently. A malformed or failed AI response falls back to a safe default (Urgent tier, general vendor) instead of blocking the request, and a failed dispatch retries once before alerting the manager directly. A few things broke during testing: the AI initially skipped RAG retrieval until the prompt got more specific, a Groq free-tier rate limit hit mid-call and got fixed by adjusting the retry config, and a trailing-space bug quietly broke duplicate detection until it was caught.
Logging & Monitoring
Every request, including failures and duplicates, goes to a structured audit log. The SLA Breach Checker verifies vendor response times independently, and a separate health check watches the AI and vector database so an infra failure doesn't degrade the system unnoticed.
Security & Data Handling
Tenant PII is limited to what's operationally necessary and stored in a private, access-controlled log. Credentials use scoped OAuth2/API keys in n8n's encrypted store. Only manager-approved documents get embedded into the knowledge base, so tenant-submitted content never reaches the RAG source and can't be used to manipulate what the system treats as ground truth.
Scalability
Each piece scales on its own. The audit log can move from Sheets to a real database as volume grows, the vendor directory can move to a structured source, and a property identifier built into the pipeline lets one workflow serve multiple properties.
Skills Demonstrated
The technical capabilities this build required, at a glance.
Why I Built It This Way
I didn't trust a single AI call with anything safety-related, so the system never relies on one. A keyword check runs independently of the model and always wins when it detects a true emergency, no matter what the AI concluded. The AI supplies judgment; the rule supplies certainty where certainty matters most, and that split is the core decision behind this build.
Appendix
Supporting reference material for this build.
Sample AI Prompt Used
You are a property maintenance triage assistant for [Property Name]. You
classify incoming tenant maintenance requests and determine the correct
vendor and response path.
You have access to a knowledge base tool containing three documents: the
Vendor Directory & SLA reference, Unit-Specific Notes, and the Escalation
Policy. Always query this knowledge base before making a classification
decision. Never rely on general assumptions about urgency or vendors.
Your process for every request:
1. Determine the category and urgency tier per the Escalation Policy.
2. Check Unit-Specific Notes for the given unit. This may override or
raise the urgency tier, or specify a required vendor.
3. Retrieve the correct vendor, contact, and SLA from the Vendor
Directory.
4. If ambiguous, always classify at the higher urgency tier. Never
downgrade based on assumption.
5. Gas-related language is always Emergency tier without exception.
Return your classification matching the required schema: category,
urgency, vendor_name, vendor_contact, sla, unit_notes_found, reasoning.Screenshots
Got a process like this?
If any of this sounds like a bottleneck you're living with, tell me about it. I'll be straight about whether automation is worth it.