Morning Maintenance Triage Board
What you'll learn
~30 min- Parse PMS-style CSV exports of maintenance work orders in Node.js
- Implement transparent priority-scoring rules (keyword matching + age + safety flags)
- Visualize backlog by urgency, category, and building location
- Generate a 'first 10 actions' daily queue and printable standup summary
What you’re building
It is 6:45 AM. You walk into the maintenance office at The Concord Crystal City. Overnight, 14 new work orders came in through the resident portal. Three are about a leak on the 12th floor. Two are noise complaints. One says “no hot water” with three exclamation marks. The rest are routine — a squeaky closet door, a dishwasher that smells, a request to re-caulk a bathtub. Your two maintenance techs arrive at 7:30 and need to know exactly where to go first.
Right now you open Yardi, scroll through the list, try to mentally sort by urgency, and scribble a priority list on a whiteboard. By the time you are done, it is 7:20 and you have not had coffee. What if you could export last night’s work orders as a CSV, run one command, and have a priority-scored action queue with a printable standup summary ready before your techs walk in the door?
That is what you will build in the next 25 minutes.
You will use this tool every single morning. It takes the most stressful 30 minutes of your day — the triage scramble — and compresses it into 30 seconds. Build it once, use it 250 times a year. That is not a practice exercise. That is an operational upgrade.
By the end of this lesson you will have a Node.js CLI tool that reads a CSV of maintenance work orders, applies a transparent priority-scoring algorithm (keyword detection, age-based urgency, safety flags), generates a sorted action queue, and outputs both a terminal summary and a printable HTML dashboard with Chart.js visualizations. No server. No subscription. Just a command you run before your morning standup.
Import CSV + apply rules + rank + visualize. This pattern works for helpdesk tickets, customer support queues, inspection checklists — any prioritized backlog. The techniques in this lesson transfer directly to non-property contexts.
🔍Domain Primer: Maintenance operations terms you'll see in this lesson
New to maintenance operations? Here are the key terms:
- Work order — A formal request for maintenance work. When a resident submits a request through the portal (“my dishwasher is leaking”), the PMS creates a work order with a unique ID, timestamp, unit number, description, category, and status. Think of it like a support ticket, but for physical building issues.
- SLA (Service Level Agreement) — The maximum response and completion time for different priority levels. At a property like The Concord, typical SLAs are: Emergency (life safety, major leak, no heat in winter) = 4-hour response, 24-hour resolution. Urgent (no hot water, broken AC in summer, elevator down) = 24-hour response, 48-hour resolution. Routine (cosmetic, minor repair, appliance issue) = 48-hour response, 5-business-day resolution. SLA breaches are tracked by regional managers and affect property performance scores.
- Morning standup — A brief daily meeting (5-10 minutes) where the maintenance supervisor reviews the day’s priorities with the techs. Typically done at 7:30 or 8:00 AM. The standup covers: what was completed yesterday, what is on deck today, and any blockers (parts on order, vendor scheduling, access issues). A good standup board makes this meeting crisp and efficient.
- Make-ready — The process of preparing a vacant unit for the next resident. Includes cleaning, painting, repairs, appliance checks, and final inspection. Make-ready work orders compete with resident requests for tech time, so they need to be factored into daily scheduling.
- Vendor/tech assignment — Matching work orders to the right person. A general maintenance tech handles most issues (plumbing, electrical, HVAC basics), but specialized work (elevator repair, fire alarm panel, roof leak) requires an outside vendor. The triage board suggests assignments based on work order category.
You don’t need to memorize these — the tool will use them in context. Knowing what they mean helps you understand why the scoring rules work the way they do.
Who this is for
- Maintenance supervisors who run the morning standup and need a prioritized queue before their team arrives.
- Community managers who want visibility into the maintenance backlog without digging through the PMS.
- Regional property managers who want consistent triage logic across every property in their portfolio.
Every PMS (Yardi, RealPage, Entrata, AppFolio) has a CSV export function for work orders. Starting with CSV means this tool works with any system, today, with zero IT involvement. You do not need API access, vendor approval, or a developer to build an integration. Export the CSV, run the tool, get your board. If you want a direct integration later, that is a follow-up prompt — but the CSV approach works on day one.
The showcase
Here is what the finished tool produces:
- Terminal output: A color-coded priority queue showing the top 10 actions, each with work order ID, unit, issue summary, priority score, SLA status, and suggested assignment
- HTML dashboard (
output/triage-board.html): A printable single-page board with:- Priority queue table — all work orders sorted by score, color-coded by urgency tier (red/orange/yellow/green)
- Urgency breakdown pie chart — how many emergency, urgent, routine, and make-ready orders
- Category bar chart — plumbing, HVAC, electrical, appliance, general, exterior
- Building location heatmap — work orders by floor (floors 1-18), showing which floors have the most open issues
- SLA breach warnings — highlighted rows for any work order that has exceeded or is approaching its SLA deadline
- Standup summary — a clean, printable block with today’s date, total open orders, top priorities, and tech assignments
Everything runs locally. The HTML dashboard uses Chart.js from CDN for charts and can be printed directly or saved as PDF from the browser.
The prompt
Open your terminal, navigate to a project folder, start your AI CLI tool (e.g., by typing claude), and paste this prompt:
Build a Node.js CLI tool called maintenance-triage-board that parsesmaintenance work order CSVs and generates a prioritized daily action queuewith a printable HTML dashboard. The property is The Concord Crystal City,a 413-unit, 18-story luxury apartment community.
PROJECT STRUCTURE:maintenance-triage-board/ package.json src/ index.js (CLI entry point) csv-parser.js (CSV ingestion and validation) scorer.js (priority scoring engine) dashboard.js (HTML dashboard generator) templates/ board.hbs (Handlebars template for the HTML dashboard) sample-data/ work-orders.csv (realistic sample data, 25 work orders) output/ (generated files go here)
REQUIREMENTS:
1. CLI INTERFACE (src/index.js) - Usage: node src/index.js <csv-file> [options] - Options: --top <n> Show top N priority items (default: 10) --techs <names> Comma-separated tech names for assignment (default: "Marco,Daniela") --date <date> Override today's date for SLA calculations (default: today, format YYYY-MM-DD) --html Generate HTML dashboard (default: true) --no-html Skip HTML generation, terminal output only --print Open the HTML file in the default browser after generating - Terminal output: color-coded table with columns: Priority | WO# | Unit | Floor | Category | Summary | Score | SLA Status | Assigned To - Colors: red for emergency, orange for urgent, yellow for routine, green for make-ready/low
2. CSV PARSER (src/csv-parser.js) - Expected CSV columns (matching common PMS exports): work_order_id, created_date, unit_number, floor, resident_name, category, description, status, priority_pms (the PMS-assigned priority, which we'll re-score), assigned_to, notes - Handle common CSV issues: quoted fields with commas, empty fields, date format variations (MM/DD/YYYY, YYYY-MM-DD, M/D/YY) - Validate required fields (work_order_id, created_date, unit_number, description). Log warnings for incomplete rows but don't skip them. - Filter to only "open" and "in-progress" status (skip "completed", "cancelled")
3. PRIORITY SCORING ENGINE (src/scorer.js) Score each work order on a 0-100 scale using these transparent rules:
a. KEYWORD EMERGENCY DETECTION (0-40 points) - Immediate life-safety keywords (40 pts): "fire", "fire alarm", "smoke", "gas leak", "gas smell", "carbon monoxide", "flood", "flooding", "ceiling collapse", "electrical fire" - Critical comfort keywords (30 pts): "no hot water", "no heat", "no AC", "no air conditioning", "no electricity", "power out", "elevator stuck", "elevator down", "sewage", "backed up" - Urgent keywords (20 pts): "leak", "leaking", "water damage", "mold", "pest", "roach", "mice", "broken lock", "door won't lock", "window broken", "toilet won't flush" - Standard keywords (10 pts): "dishwasher", "disposal", "squeaky", "cosmetic", "paint", "caulk", "screen", "lightbulb" - Match against description + notes fields, case-insensitive
b. AGE-BASED URGENCY (0-25 points) - Calculate days since created_date - 0-1 days: 5 pts - 2-3 days: 10 pts - 4-7 days: 15 pts - 8-14 days: 20 pts - 15+ days: 25 pts (approaching or past SLA breach)
c. SLA BREACH PROXIMITY (0-20 points) - Calculate hours/days until SLA deadline based on category: Emergency = 24 hrs, Urgent = 48 hrs, Routine = 5 business days - Already breached: 20 pts - Within 25% of deadline: 15 pts - Within 50% of deadline: 10 pts - Within 75% of deadline: 5 pts - Plenty of time: 0 pts
d. REPEAT/ESCALATION BONUS (0-15 points) - If the description or notes contain "again", "still", "second time", "recurring", "called again", "not fixed": +15 pts - If resident name appears in more than one open work order: +10 pts (multiple issues = frustrated resident)
- Final score = sum of all components, capped at 100 - Tier assignment: 80-100 = EMERGENCY (red), 60-79 = URGENT (orange), 30-59 = ROUTINE (yellow), 0-29 = LOW (green) - Export the scoring breakdown for each work order (not just the final score) so the dashboard can show WHY each order is ranked where it is
4. TECH ASSIGNMENT SUGGESTIONS - Round-robin assignment across the provided tech names - Emergency items: assign to the first available tech (don't round-robin) - Category-based hints: if the category is "HVAC" or "Elevator", add a note "Consider vendor dispatch" instead of assigning a tech - Output the suggested assignment but make it clear these are suggestions, not dispatched orders
5. HTML DASHBOARD (src/dashboard.js + templates/board.hbs) Generate output/triage-board.html with:
a. HEADER - Title: "Morning Triage Board -- The Concord Crystal City" - Date: today's date (or --date override) - Summary stats: Total open WOs, Emergency count, Urgent count, SLA breaches, Oldest open WO age
b. PRIORITY QUEUE TABLE - All work orders sorted by score (highest first) - Columns: Rank, WO#, Unit, Floor, Category, Description (first 60 chars), Score, Score Breakdown (tooltip or expandable), Tier, SLA Status, Suggested Tech - Row background color by tier: red #fecaca, orange #fed7aa, yellow #fef08a, green #bbf7d0 - SLA breached rows get a red left border and bold "BREACHED" tag
c. CHARTS (Chart.js from CDN) - Urgency breakdown: doughnut chart showing count by tier - Category distribution: horizontal bar chart showing count by category (Plumbing, HVAC, Electrical, Appliance, General, Exterior, Make-Ready) - Floor heatmap: vertical bar chart, one bar per floor (1-18), bar height = number of open WOs on that floor, color-coded by highest-severity WO on that floor
d. STANDUP SUMMARY (print-friendly section) - "TOP 10 PRIORITIES" list with WO#, unit, one-line summary, tech - "SLA ALERTS" list of any breached or near-breach items - "PARTS/VENDOR NEEDED" list if any notes mention "parts", "order", "vendor", "backordered", "scheduled" - "YESTERDAY'S COMPLETIONS" placeholder (to be filled manually or from a separate CSV) - Formatted for printing on a single sheet of paper (A4/Letter)
e. DESIGN - Dark theme for screen: background #09090b, cards #141414, borders #262626, text #e5e5e5 - Print stylesheet: white background, black text, no dark theme, Chart.js charts hidden (replaced by text summaries), single page layout - Font: system sans-serif stack - Responsive: works on laptop screens and tablets
6. SAMPLE DATA (sample-data/work-orders.csv) Include 25 realistic work orders with a mix of: - 2 emergency items (12th floor leak affecting multiple units, fire alarm panel fault on L3) - 4 urgent items (no hot water in 14B, elevator intermittent on east bank, backed-up drain in 6A, broken window lock in 9D) - 12 routine items (dishwasher issues, garbage disposal, paint touch- up, caulking, squeaky doors, HVAC filter changes, lightbulb replacements) - 4 make-ready items (units 4C, 7B, 11A, 15E -- turns happening this month) - 3 items with SLA breach potential (created 5+ days ago, still open) - 2 items with "recurring" or "again" in notes - Spread across floors 1-18 with realistic unit numbers - Mix of categories: Plumbing, HVAC, Electrical, Appliance, General, Exterior, Make-Ready - Dates ranging from today back to 16 days ago
DEPENDENCIES: commander, csv-parse (or csv-parser), handlebars, chalk,open (to open HTML in browser with --print flag)That entire block is the prompt. Paste it as-is. The scoring rules are spelled out explicitly because you need to be able to explain to your regional manager exactly why work order #4521 is ranked above #4518. Transparent, auditable logic beats a black box every time.
What you get
After the LLM finishes (typically 60-120 seconds), you will have the project:
maintenance-triage-board/ package.json src/ index.js csv-parser.js scorer.js dashboard.js templates/ board.hbs sample-data/ work-orders.csvSet it up and run
cd maintenance-triage-boardnpm installnode src/index.js sample-data/work-orders.csvYou should see terminal output like:
Morning Triage Board -- The Concord Crystal CityDate: 2026-03-06 | Open WOs: 22 | Emergency: 2 | Urgent: 4 | SLA Breaches: 3
# | WO# | Unit | Fl | Category | Summary | Score | Tier | SLA | Tech 1 | WO-4501| 12F | 12 | Plumbing | Active leak from ceiling, affe...| 92 | EMERGENCY | BREACHED | Marco 2 | WO-4503| L3 | 3 | Electrical | Fire alarm panel showing fault...| 88 | EMERGENCY | -22h left | Marco 3 | WO-4507| 14B | 14 | Plumbing | No hot water since yesterday m...| 71 | URGENT | -18h left | Daniela 4 | WO-4512| East | - | Elevator | Elevator intermittent, traps o...| 68 | URGENT | Vendor | *Vendor* 5 | WO-4509| 6A | 6 | Plumbing | Kitchen drain backed up, water...| 63 | URGENT | -36h left | Marco ...
Dashboard generated: output/triage-board.htmlOpen output/triage-board.html in your browser. You should see:
- Header with today’s date and summary statistics.
- Priority queue table with all 22 open work orders, color-coded by tier.
- Doughnut chart showing 2 emergency, 4 urgent, 12 routine, 4 make-ready.
- Category bar chart showing plumbing as the largest category.
- Floor chart with floor 12 highlighted red (the active leak).
- Standup summary section at the bottom, ready to print.
If something is off
| Problem | Follow-up prompt |
|---|---|
| CSV parsing fails on date formats | The date parser is failing on MM/DD/YYYY dates. Use a flexible date parsing approach: try YYYY-MM-DD first, then MM/DD/YYYY, then M/D/YY. Use new Date() with manual parsing, not Date.parse() which is inconsistent across environments. |
| Chart.js charts are blank | The Chart.js charts aren't rendering. Make sure Chart.js is loaded from CDN before the chart code runs. Add the script tag in the <head> with defer, and wrap chart creation in a DOMContentLoaded event listener. |
| Score breakdown is not visible | I can see the final score but not how it was calculated. Add a tooltip or expandable row in the HTML table that shows the scoring breakdown: keyword points, age points, SLA points, and escalation bonus. This is critical for transparency. |
| Print layout is broken | When I print the HTML dashboard, the dark background prints and the charts overlap the table. Add a @media print stylesheet that sets white background, hides Chart.js canvases, and uses the text-based standup summary instead. Make sure the priority table fits on one page. |
When Things Go Wrong
Use the Symptom → Evidence → Request pattern: describe what you see, paste the error, then ask for a fix.
How it works (the 2-minute explanation)
You do not need to understand every line of the generated code, but here is the mental model:
- CSV parsing reads each row into a JavaScript object. The parser handles date format variations and quoted fields. It filters out completed and cancelled work orders so you only see what needs attention.
- Priority scoring is a points-based system with four components: keyword detection (what is the problem?), age (how long has it been open?), SLA proximity (are we about to breach?), and escalation signals (is this a repeat issue?). Each component has a maximum, and the total is capped at 100. The breakdown is stored with each work order so you can explain any ranking.
- Tech assignment uses round-robin for routine items and first-available for emergencies. Specialized categories (HVAC, elevator) get flagged for vendor dispatch instead. These are suggestions, not dispatched orders — your techs know the building better than any algorithm.
- Chart.js renders three charts: a doughnut for urgency tiers, a horizontal bar for categories, and a vertical bar for floors. These give you a visual overview that is faster to read than a table.
- The print stylesheet strips the dark theme and charts for paper output, leaving a clean priority list and standup summary that fits on one page.
🔍Why transparent scoring matters
A black-box algorithm that says “this work order is priority 1” is useless if your regional manager asks why. Transparent scoring — where you can say “it scored 71 because: 30 points for ‘no hot water’ keyword, 15 points for being 4 days old, 16 points for approaching SLA breach, and 10 points because the resident has two open work orders” — is defensible. It is auditable. And when the scoring is wrong (and it will be sometimes), you can adjust the rules and re-run. You cannot do that with a gut feeling written on a whiteboard.
Customize it
The base tool handles daily triage, but here are follow-up prompts for specific operational needs:
Add vendor dispatch tracking
Add a --vendors flag that accepts a JSON file mapping categories to vendorcontacts. Example: {"HVAC": {"name": "AirTech Services", "phone":"703-555-0188", "contract": "monthly"}, "Elevator": {"name": "ThyssenKrupp","phone": "800-555-0199", "contract": "on-call"}}. When a work order isflagged for vendor dispatch, include the vendor name and phone in thedashboard. Add a "Vendor Dispatch" section to the standup summary listingall vendor-required items with contact info.Add week-over-week trend tracking
Add a --history flag that appends today's triage summary to atriage-history.json file. Track: date, total open WOs, emergency count,average score, SLA breach count, oldest open WO age. After 7+ days ofdata, add a "Trends" section to the dashboard showing a line chart ofopen WO count over time and a bar chart of SLA breaches per day. Thishelps identify whether the backlog is growing or shrinking.Add resident impact scoring
Add a "resident impact" component to the scoring engine. If a single unithas multiple open work orders, boost all of that unit's WOs by 10 points.If multiple units on the same floor report the same category (e.g., threeplumbing WOs on floor 12), flag it as a potential building-wide issue andadd a "BUILDING ISSUE" tag. Add a "Resident Impact" section to thedashboard showing which residents have the most open issues and whichfloors have clustered problems.Add make-ready tracking
Add a separate "Make-Ready Board" section to the dashboard. Filter workorders with category "Make-Ready" and group them by unit. For each unit,show: unit number, move-in date (add a move_in_date column to the CSV),days until move-in, completion percentage (completed make-ready WOs /total make-ready WOs for that unit), and a progress bar. Color-code byurgency: red if move-in is within 3 days and not 100% complete, yellowif within 7 days, green otherwise.Start with the base triage board. Use it for a week. You will immediately notice what is missing for your specific property — maybe you need vendor tracking, maybe you need make-ready progress bars, maybe you need a different SLA schedule. Each missing feature is one follow-up prompt. The tool grows to fit your operation, not the other way around.
Try it yourself
- Open your CLI tool in an empty folder.
- Paste the main prompt from above.
- Run
npm installand test with the sample data. - Open the HTML dashboard and review the priority queue. Does the scoring make sense?
- Try the print view (Ctrl+P or Cmd+P in the browser). Does the standup summary fit on one page?
- If you have access to a real work order export from your PMS, run it through the tool. Adjust column names in the CSV parser if your PMS uses different headers.
- Pick one customization from the list above and add it.
Key takeaways
- CSV is the universal export format — every PMS supports it. Building on CSV means your tool works with Yardi, RealPage, Entrata, AppFolio, or any system, today, without IT involvement.
- Transparent scoring beats gut-feel triage — when every point is traceable to a rule (keyword match, age, SLA proximity, repeat flag), you can explain and defend your priorities to anyone. Adjust the rules when they are wrong.
- SLA awareness prevents breaches before they happen — the breach proximity score pushes aging work orders up the queue before they actually breach, not after. Prevention is better than a breach report from your regional.
- Print-friendly output bridges the digital-analog gap — your maintenance techs may not have tablets. A printed standup sheet taped to the office wall is the interface that actually gets used every morning.
- The tool gets better with customization — vendor dispatch, trend tracking, and make-ready boards are all one prompt away. Start with the base, iterate to fit your property.
A work order for 'kitchen faucet leaking slowly' was created 6 days ago and is still open. The property's SLA for routine plumbing is 5 business days. The scoring engine gives it 62 points: 20 (keyword 'leak') + 15 (6 days old) + 20 (SLA breached) + 7 (no escalation signals). What tier does this work order land in?
What’s next
In the next lesson, you will build a tool that goes beyond daily operations into financial visibility: a Rent Roll Analyzer that parses your monthly rent roll export, calculates occupancy metrics, flags lease expirations, and produces a portfolio health dashboard. Same pattern — showcase, prompt, output, customize — but with financial data and KPI calculations instead of work order scoring.