Applied Module 12 · The Nick E. Playbook

The Daily Ops Command Center

What you'll learn

~60 min
  • Orchestrate multiple AI-generated tools into a single unified workflow
  • Build a local Express.js dashboard with sidebar navigation linking all tools
  • Create a 'Morning Run' trigger that sequences triage, renewals, and reporting automatically
  • Deliver a unified 'Today's Top 15' action list combining all operational priorities

What you’re building

Over the last five lessons, Nick built five tools that each solve a real problem at the Concord Crystal City. A resident communication studio for polished response drafting. A maintenance triage board for prioritizing the overnight work orders. A renewal risk planner for keeping occupancy stable. A vendor and make-ready orchestrator for turning units on time. A pulse reporter for the weekly numbers. They all work. They all save time.

But right now, Nick’s morning routine looks like this: open the maintenance triage tool, review the queue, switch to the renewal planner, check who is expiring, switch to the vendor orchestrator, see if any turns are delayed, open the pulse reporter output from last Friday, and mentally assemble a picture of what the building needs today. Five tools, five tabs, five mental context switches before his first cup of coffee is done.

This lesson builds the thing that ties it all together. A local web dashboard — running on Nick’s laptop — that integrates every tool into a single interface with sidebar navigation, a unified action queue, and a “Morning Run” button that triggers the daily sequence automatically. One click at 7 AM, and Nick has a prioritized list of the 15 most important things to do today. No context switching. No tab juggling. One screen, one workflow.

💬This is how operators actually work

Property managers do not think in tools. They think in priorities. “What is the most urgent thing right now?” is the question that drives every morning. A command center does not add new capabilities — it rearranges the capabilities you already built into the shape of how Nick actually thinks. The integration is the product.

Software pattern: Unified operations dashboard with automated orchestration

Aggregate outputs from multiple independent tools into a single interface. Provide one-click workflow automation that sequences tool runs in the correct order. Surface a unified priority queue from heterogeneous data sources. This pattern powers mission control centers, DevOps dashboards (Grafana, Datadog), hospital charge nurse stations, and logistics dispatch systems. The tools are different; the need to see everything in one place is universal.

🔍Property management primer: what a command center replaces

If you have never managed a property, here is what Nick’s morning looks like without this tool — and why unifying it matters:

  • Command center / ops dashboard: A single screen that shows the operational state of the property. In property management, this does not exist as a standard product. Most GMs assemble their morning picture from Yardi reports, email, a printed work order stack, and a spreadsheet. The command center replaces that assembly process.
  • Morning Run: Every GM has a morning routine. Walk the property, check the overnight maintenance log, review the leasing traffic from yesterday, check which leases expire this month, see if any unit turns are on schedule. The “Morning Run” in this tool automates the data-gathering part of that routine so Nick can focus on the decision-making part.
  • Today’s Top 15: Property management is interrupt-driven. The phone rings, a resident stops you in the lobby, a vendor is late, a pipe bursts. Without a prioritized list, the loudest problem wins — not the most important one. The Top 15 list is Nick’s anchor. It is the answer to “what should I be doing right now?” when five things are competing for attention.
  • Exception center: Most of the building runs fine on any given day. The command center highlights only what is broken or at risk — SLA breaches on maintenance tickets, delayed unit turns, renewal risk spikes, KPI drops. If nothing is flagged, the building is healthy. Nick does not need to dig through 413 units of data to find that out.
  • Weekly owner packet: The Concord’s ownership group expects a weekly summary. The command center generates it from the same data that powers the daily dashboard — no separate report-building process. One click, one PDF, one email.

Who this is for

Nick, General Manager of the Concord Crystal City. He has built all five tools from Lessons 1-5. He runs them individually and they save him time. But he wants one place to see everything, one button to start his day, and one list that tells him what matters most. He is not a developer. He does not want to maintain five separate terminals. He wants a dashboard he can open in his browser at 7 AM, click “Morning Run,” and have his day organized by 7:02 AM.


The showcase

The finished command center provides:

  • Sidebar navigation with five sections: Comms (Lesson 1), Maintenance (Lesson 2), Renewals (Lesson 3), Turns (Lesson 4), Reports (Lesson 5), plus a Home dashboard.
  • Home dashboard with the “Morning Run” button, Today’s Top 15 action queue, exception center, and property health summary.
  • “Morning Run” one-click automation: triggers the maintenance triage, renewal risk assessment, turn status check, and pulse report generation in sequence. Displays a progress indicator as each step completes. Total runtime: under 30 seconds.
  • Today’s Top 15: a single, unified, prioritized list pulling from all five tool outputs. Each item shows the source tool (icon), priority level (critical/high/normal), a one-line description, and an action link. Examples: “Unit 1204 — water heater leak — SLA breach in 2 hours” (from maintenance), “Resident Chen — lease expires in 9 days, no response to outreach” (from renewals), “Unit 807 make-ready — paint vendor 2 days behind schedule” (from turns).
  • Exception center: a dedicated panel showing only things that are off-track. SLA breaches on open work orders. Turns that are delayed past their target move-in date. Residents with renewal risk scores above 80 who have not responded to outreach. KPIs that crossed a threshold since last week. If the exception center is empty, the building is running well.
  • Weekly owner packet generation: a button that compiles the pulse report, adds a cover page with the property photo and executive summary, and exports as a branded PDF ready to email to ownership.
  • Concord-branded luxury UI: dark theme with teal (#0F766E) accents, clean typography, the Concord property name prominent in the header. It looks like a tool that belongs at a luxury property, not a college homework project.

The prompt

Start your AI CLI tool in an empty directory and paste this prompt:

Build a Node.js + Express web application called concord-command-center that
serves as a unified daily operations dashboard for a 413-unit luxury apartment
community. The dashboard integrates outputs from five standalone tools
(resident comms, maintenance triage, renewal planning, vendor/turn scheduling,
and weekly KPI reporting) into a single interface with automated orchestration.
PROJECT STRUCTURE:
concord-command-center/
package.json
src/
server.js (Express server, routes, middleware)
orchestrator.js (Morning Run sequencing engine)
priority-engine.js (Today's Top 15 unified queue generator)
exception-scanner.js (SLA breach, delay, risk spike detection)
data-bridge.js (reads output files from L1-L5 tool directories)
owner-packet.js (weekly owner report PDF generator)
public/
css/
style.css (main dashboard styles)
js/
dashboard.js (client-side interactivity, Morning Run trigger)
charts.js (Chart.js dashboard widgets)
views/
layout.hbs (shared Handlebars layout with sidebar)
home.hbs (main dashboard: Morning Run, Top 15, exceptions)
comms.hbs (resident communications panel)
maintenance.hbs (maintenance triage board view)
renewals.hbs (renewal risk and outreach view)
turns.hbs (vendor & make-ready status view)
reports.hbs (KPI pulse report view)
owner-packet.hbs (owner report preview and export)
data/
sample/ (sample JSON files simulating L1-L5 outputs)
comms-queue.json
maintenance-queue.json
renewal-risks.json
turn-schedule.json
pulse-kpis.json
config.json (property config, thresholds, tool paths)
REQUIREMENTS:
1. EXPRESS SERVER (src/server.js)
- Runs on port 3000 (configurable via PORT env var)
- Uses Handlebars (express-handlebars) for server-side rendering
- Serves static files from public/
- Routes:
GET / -> home dashboard
GET /comms -> communications panel
GET /maintenance -> maintenance triage board
GET /renewals -> renewal risk planner
GET /turns -> vendor & make-ready status
GET /reports -> KPI pulse report
GET /owner-packet -> owner report preview
POST /api/morning-run -> trigger Morning Run sequence
GET /api/status -> current Morning Run status (polling endpoint)
POST /api/owner-packet -> generate and download owner packet PDF
- Middleware: request logging, error handling, JSON body parsing
2. DATA BRIDGE (src/data-bridge.js)
Reads output files from each tool's directory. In production, these
paths point to the actual L1-L5 tool output directories. For demo
purposes, read from data/sample/.
Expected data formats:
a. comms-queue.json:
Array of pending resident communications:
[{ id, unit, residentName, category, subject, urgency, draftStatus,
createdAt, responseDeadline }]
Categories: "complaint", "request", "inquiry", "emergency", "notice"
b. maintenance-queue.json:
Array of open work orders:
[{ id, unit, description, priority, category, reportedAt, slaDeadline,
assignedVendor, status, estimatedCompletion }]
Priorities: "emergency", "urgent", "standard", "low"
Statuses: "open", "assigned", "in-progress", "parts-ordered",
"completed", "overdue"
c. renewal-risks.json:
Array of upcoming lease expirations with risk scores:
[{ unit, residentName, leaseEnd, monthlyRent, riskScore,
riskFactors, outreachStatus, lastContactDate, renewalOffer }]
Risk scores: 0-100 (higher = more likely to leave)
Outreach statuses: "not-started", "email-sent", "call-scheduled",
"in-negotiation", "renewed", "notice-given"
d. turn-schedule.json:
Array of unit turns (make-ready projects):
[{ unit, moveOutDate, targetMoveInDate, currentPhase, phases,
delayDays, assignedVendors, totalBudget, spentToDate }]
Phases: ["inspection", "punch-list", "paint", "carpet", "clean",
"final-inspection", "ready"]
Each phase: { name, vendor, scheduledStart, scheduledEnd,
actualStart, actualEnd, status }
e. pulse-kpis.json:
KPI snapshot:
{ reportDate, occupancy, preLease, renewalRate, delinquency,
avgConcession, leasingVelocity, vacantUnits, trends }
Each KPI: { current, previous, delta, direction, status }
Trends: { occupancy12wk: [array], velocity8wk: [array] }
The data bridge loads all files, validates their structure (log warnings
for missing or malformed data, use empty defaults), and exposes a
getData() function that returns the unified dataset.
3. ORCHESTRATOR (src/orchestrator.js)
The "Morning Run" engine that sequences tool execution:
Steps (in order):
1. Refresh maintenance data (re-read maintenance-queue.json or trigger
the triage tool if configured)
2. Refresh renewal risk scores (re-read renewal-risks.json or trigger
the renewal planner)
3. Refresh turn status (re-read turn-schedule.json or trigger the
vendor orchestrator)
4. Refresh KPI data (re-read pulse-kpis.json or trigger the pulse
reporter)
5. Run the priority engine to generate Today's Top 15
6. Run the exception scanner to flag breaches
In demo mode (reading from sample JSON), steps 1-4 just reload the
files. In production mode, each step calls the corresponding CLI tool
via child_process.spawn and waits for completion.
Provide a status object that the frontend polls:
{ currentStep: 3, totalSteps: 6, stepName: "Refreshing turn status",
startedAt, stepsCompleted: ["maintenance", "renewals"],
errors: [], isComplete: false }
Total runtime target: under 30 seconds for the full sequence.
4. PRIORITY ENGINE (src/priority-engine.js)
Generate the "Today's Top 15" unified action list from all data sources:
Priority scoring rules:
- Maintenance emergency: 100 points
- Maintenance SLA breach (past deadline): 95 points
- Maintenance SLA warning (within 2 hours of deadline): 85 points
- Turn delayed past target move-in: 90 points
- Turn phase overdue by 2+ days: 80 points
- Renewal risk score > 80, lease expires within 14 days: 88 points
- Renewal risk score > 60, no outreach started: 75 points
- Delinquency > 60 days on a single unit: 70 points
- Resident communication marked urgent, response deadline today: 82 points
- KPI threshold breach (any KPI crossed red threshold): 65 points
- Resident communication standard, response deadline today: 50 points
- Turn phase starting today (vendor coordination needed): 45 points
- Renewal outreach follow-up due today: 40 points
For each item, generate:
{ rank, score, source, sourceIcon, priority, title, description,
actionUrl, unit, deadline }
Source icons: wrench (maintenance), key (renewals), truck (turns),
envelope (comms), chart-bar (reports)
Return the top 15 items sorted by score descending. If fewer than 15
items exist, return all of them.
5. EXCEPTION SCANNER (src/exception-scanner.js)
Scan all data for off-track items:
a. SLA BREACHES: maintenance work orders past their SLA deadline
and not yet completed. Show: unit, description, hours overdue,
assigned vendor.
b. DELAYED TURNS: units where any make-ready phase is behind schedule
and the delay pushes past the target move-in date. Show: unit,
delayed phase, delay days, impact on move-in.
c. RENEWAL RISK SPIKES: residents with risk score > 75 whose lease
expires within 21 days and outreach status is "not-started" or
"email-sent" (not actively engaged). Show: unit, resident name,
lease end, monthly rent at risk.
d. KPI DROPS: any KPI that moved from green/yellow to red since the
previous week. Show: KPI name, current value, threshold, direction.
Return: { totalExceptions, breaches: [], delays: [], riskSpikes: [],
kpiDrops: [], severity } where severity is "critical" if any
breaches exist, "warning" if only delays/spikes, "clear" if empty.
6. OWNER PACKET GENERATOR (src/owner-packet.js)
Generate a branded weekly owner report:
- Cover page: "Concord Crystal City" title, Bozzuto Management logo
placeholder, report period, property address
(1201 S Eads St, Arlington, VA 22202)
- Executive summary: 3-4 sentences auto-generated from KPI data
(similar to pulse reporter narrative)
- KPI dashboard: the same 6 KPI cards from the pulse reporter
- Occupancy detail: unit mix summary, vacant unit list, pre-lease pipeline
- Financial snapshot: delinquency summary, concession spend, renewal
economics (renewal vs turnover cost comparison)
- Maintenance summary: open work orders by priority, average resolution
time, SLA compliance rate
- Turn status: in-progress turns with timeline, upcoming turns, budget
vs actual
- Use Puppeteer for HTML-to-PDF conversion
- Filename: concord-owner-packet-YYYY-MM-DD.pdf
7. VIEWS (Handlebars templates):
a. layout.hbs — Shared layout:
- Left sidebar (240px): Concord Crystal City header with teal accent
bar, navigation links (Home, Comms, Maintenance, Renewals, Turns,
Reports), each with an icon. Active page highlighted with teal
background. "Morning Run" button at the bottom of the sidebar
with a play icon.
- Top bar: current date/time, property health indicator (green/yellow/
red dot), "Last Morning Run: [timestamp]" badge.
- Main content area: 100% of remaining width.
- Footer: "Concord Property Ops | Bozzuto Management | v1.0"
b. home.hbs — Dashboard home:
- "Morning Run" hero card at top: large button with status indicator.
When running, shows a progress bar with step names.
When complete, shows "Last run: [time] -- [N] actions generated"
- Property health summary: 6 mini KPI cards (same data as pulse
reporter but compact)
- Today's Top 15: numbered list with priority badges, source icons,
descriptions, and action links. Critical items have a red left
border. High items have yellow. Normal items have gray.
- Exception Center: grouped cards for SLA breaches, delayed turns,
risk spikes, and KPI drops. Each card expandable. Header shows
count badge. If no exceptions: green "All Clear" banner.
c. comms.hbs — Resident Communications:
- Queue of pending communications with urgency indicators
- Click to view draft text and resident details
- Filter by category and urgency
d. maintenance.hbs — Maintenance Triage:
- Work order cards sorted by priority
- SLA countdown timers on open tickets
- Status filter: open, assigned, in-progress, overdue
- Color-coded priority bands: red (emergency), orange (urgent),
blue (standard), gray (low)
e. renewals.hbs — Renewal Risk:
- Table of upcoming expirations sorted by risk score
- Risk score bar visualization (0-100, colored gradient)
- Outreach status badges
- Monthly rent at risk total
f. turns.hbs — Make-Ready Status:
- Gantt-style timeline for each turn showing phases
- Red highlight on delayed phases
- Days until target move-in countdown
- Budget vs actual spend bar
g. reports.hbs — KPI Pulse:
- Full pulse report embedded (or iframe to the pulse reporter HTML)
- "Generate Owner Packet" button
- Historical KPI trend charts
8. CLIENT-SIDE JAVASCRIPT:
a. dashboard.js:
- Morning Run button click handler: POST to /api/morning-run,
poll /api/status every 500ms, update progress bar, refresh
page sections when complete.
- Auto-refresh: poll /api/status every 60 seconds to keep
exception counts current.
- Collapsible exception cards with smooth animation.
b. charts.js:
- Mini occupancy sparkline for the health summary
- Priority distribution donut chart (critical/high/normal counts)
- Use Chart.js loaded via CDN
9. STYLING (public/css/style.css):
- Dark luxury theme:
Background: #09090b
Sidebar: #0d0d12 with #0F766E accent bar on the left edge
Cards: #141414 with 1px #1e1e2a borders
Text: #e5e5e5 (primary), #9ca3af (secondary)
Accent: #0F766E (teal) for active states, buttons, highlights
Critical: #ef4444, Warning: #f59e0b, Success: #10b981
- Sidebar navigation:
Items 44px tall, icon + label, hover: #1a1a24
Active: #0F766E/15 background, teal left border, white text
- KPI cards: subtle top border in status color (green/yellow/red)
- Morning Run button: large, teal gradient, pulse animation when idle,
progress bar overlay when running
- Top 15 list: numbered items with left border color by priority,
hover: slight background shift
- Responsive: sidebar collapses to icon-only on screens < 1024px
- Font: system sans-serif stack
10. SAMPLE DATA (data/sample/):
Generate realistic sample data for the Concord Crystal City:
comms-queue.json: 8 pending communications
- 1 emergency (water leak complaint, response deadline 2 hours)
- 2 urgent (noise complaint, package theft report)
- 3 standard (parking request, guest suite inquiry, pet policy question)
- 2 low priority (general feedback, move-out forwarding address)
maintenance-queue.json: 22 open work orders
- 2 emergency (water heater failure unit 1204, elevator malfunction)
- 4 urgent (HVAC not cooling x2, dishwasher leak, garage gate)
- 12 standard (garbage disposal, light fixture, faucet drip, etc.)
- 4 low (touch-up paint, caulking, cabinet adjustment, weatherstrip)
- 3 should be past SLA deadline (overdue)
- Vendors: "Arlington Plumbing Co", "DMV HVAC Services",
"Capital Elevator Inc", "Bozzuto Maintenance Team"
renewal-risks.json: 18 leases expiring within 60 days
- 4 with risk score > 80 (high risk of not renewing)
- 6 with risk score 40-79 (moderate)
- 8 with risk score < 40 (likely to renew)
- Mix of outreach statuses
- Monthly rents ranging $2,200-4,200
- Risk factors: "rent-increase-sensitivity", "maintenance-complaints",
"no-engagement", "competitor-touring", "life-event"
turn-schedule.json: 5 active unit turns
- 2 on schedule (progressing through phases normally)
- 2 delayed (paint vendor 2 days behind on one, carpet delayed
waiting on materials for another)
- 1 completed (final inspection done, ready for move-in)
- Realistic phase timelines: inspection (1 day), punch-list (2 days),
paint (2 days), carpet (1 day), clean (1 day), final (1 day)
pulse-kpis.json:
- occupancy: 96.1% (down 0.4pp WoW, yellow-trending)
- preLease: 97.1% (stable)
- renewalRate: 64.3% (healthy)
- delinquency: 1.4% (up 0.2pp WoW, within threshold)
- avgConcession: $340 (stable)
- leasingVelocity: 6/week (healthy)
- Include 12-week occupancy trend and 8-week velocity arrays
config.json:
- property: "Concord Crystal City"
- management: "Bozzuto Management"
- address: "1201 S Eads St, Arlington, VA 22202"
- totalUnits: 413
- thresholds: { occupancy: { green: 95, yellow: 94, red: 92 },
delinquency: { green: 1.5, yellow: 2.0, red: 3.0 },
renewalRate: { green: 60, yellow: 50, red: 40 },
slaHours: { emergency: 4, urgent: 24, standard: 72, low: 168 } }
- toolPaths: { comms: null, maintenance: null, renewals: null,
turns: null, reports: null }
(null means demo mode -- read from sample data)
DEPENDENCIES: express, express-handlebars, puppeteer, chalk, chart.js (CDN)
💡Demo mode vs production mode

The command center works in two modes. In demo mode (the default), it reads from the sample JSON files in data/sample/. In production mode, you set the tool paths in config.json to point to your actual L1-L5 tool directories, and the Morning Run triggers each tool’s CLI command. Start with demo mode to verify everything works, then wire up the real tools one at a time.


What you get

After your AI CLI tool finishes, set it up:

Terminal window
cd concord-command-center
npm install
node src/server.js

Open http://localhost:3000 in your browser. You should see:

First look checklist

  1. Sidebar: five navigation items plus Home, each with an icon. The Concord Crystal City name at the top with a teal accent. The Morning Run button at the bottom.
  2. Home dashboard: the Morning Run hero card, 6 mini KPI cards, the Top 15 list, and the exception center.
  3. Click “Morning Run”: the button should animate, a progress bar should appear stepping through “Refreshing maintenance… Refreshing renewals… Refreshing turns… Refreshing KPIs… Generating priorities… Scanning exceptions…” and complete in a few seconds (demo mode just reloads JSON files).
  4. Today’s Top 15: after the Morning Run completes, the list should populate with items from all five sources. The top items should be the maintenance emergencies and SLA breaches. Renewal risks and turn delays should appear in the middle. Routine items at the bottom.
  5. Exception center: should show 3 SLA breaches (the overdue work orders), 2 delayed turns, and any renewal risk spikes. If a KPI crossed a threshold, that appears too.
  6. Click each sidebar item: navigate to Comms, Maintenance, Renewals, Turns, Reports. Each page should show data from its respective sample JSON file.
  7. Reports page: should display the KPI summary and have a “Generate Owner Packet” button.

Expected project structure

concord-command-center/
package.json
src/
server.js (~120-160 lines)
orchestrator.js (~100-140 lines)
priority-engine.js (~120-160 lines)
exception-scanner.js (~80-120 lines)
data-bridge.js (~80-100 lines)
owner-packet.js (~100-140 lines)
public/
css/style.css (~300-400 lines)
js/dashboard.js (~80-120 lines)
js/charts.js (~60-80 lines)
views/
layout.hbs
home.hbs
comms.hbs
maintenance.hbs
renewals.hbs
turns.hbs
reports.hbs
owner-packet.hbs
data/
sample/ (5 JSON files + config.json)
config.json

Common issues and fixes

ProblemFollow-up prompt
Express server crashes on startupThe server fails with "Error: No default engine was specified." Make sure express-handlebars is configured correctly: import { engine } from 'express-handlebars', then app.engine('hbs', engine({ extname: '.hbs', defaultLayout: 'layout' })). Set app.set('view engine', 'hbs') and app.set('views', path.join(__dirname, '..', 'views')).
Morning Run button does nothingClicking the Morning Run button has no effect. Check that dashboard.js has an event listener on the button that POSTs to /api/morning-run. The fetch call should be: fetch('/api/morning-run', { method: 'POST' }). Then poll /api/status every 500ms and update the progress bar. Also check the browser console for CORS or JavaScript errors.
Sidebar navigation links are brokenClicking sidebar links goes to a 404 page. Make sure server.js has GET routes for /comms, /maintenance, /renewals, /turns, /reports, and /owner-packet. Each route should call res.render('comms', { data }) with the correct template name and data from the data bridge.
Sample data files not foundThe server logs "ENOENT: no such file or directory" when loading sample data. The data-bridge.js file paths might be relative to the wrong directory. Use path.resolve(__dirname, '..', 'data', 'sample', 'maintenance-queue.json') to build absolute paths from the src/ directory.

🔧

When Things Go Wrong

Use the Symptom → Evidence → Request pattern: describe what you see, paste the error, then ask for a fix.

Symptom
Today's Top 15 list is empty after Morning Run
Evidence
The Morning Run completes successfully (shows 6/6 steps done) but the Top 15 list shows 'No actions today' even though the sample data has plenty of items.
What to ask the AI
"The priority engine is not receiving the data from the data bridge, or its output is not being sent to the template. Check that orchestrator.js calls priorityEngine.generate(allData) after refreshing all data sources, and that the result is stored somewhere the home route can access it (e.g., a module-level variable or a simple in-memory store). The GET / route should pass the latest Top 15 list to the home.hbs template."
Symptom
Exception center shows wrong counts or missing categories
Evidence
The exception center shows 0 SLA breaches but the maintenance data has 3 overdue work orders. The delayed turns section does not appear at all.
What to ask the AI
"The exception scanner is not detecting SLA breaches correctly. Check that it compares the current time against the slaDeadline field in maintenance-queue.json. The slaDeadline might be stored as a string -- parse it with new Date() before comparing. For delayed turns, check that it looks at each phase's scheduledEnd vs actualEnd and calculates delay days. Make sure the scanner returns all four categories (breaches, delays, riskSpikes, kpiDrops) even if some are empty arrays."
Symptom
Owner packet PDF is blank or has unstyled content
Evidence
Clicking 'Generate Owner Packet' downloads a PDF but it is either blank or shows raw HTML without styling.
What to ask the AI
"The Puppeteer PDF export is not loading the CSS. When converting HTML to PDF, Puppeteer needs the CSS to be either inline or loaded from an absolute file path (not a relative URL like '/css/style.css'). In owner-packet.js, either inline the CSS into the HTML before passing to Puppeteer, or use page.goto with a file:// URL pointing to a temporary HTML file that has the correct CSS path. Set printBackground: true in the PDF options to preserve the dark theme colors."
Symptom
The Morning Run progress bar freezes at step 2
Evidence
The Morning Run starts and shows 'Refreshing renewals...' but never advances to step 3. The server console shows no errors.
What to ask the AI
"The orchestrator is hanging on step 2. This usually means the step is waiting for a child process that never exits (production mode) or a file read that never resolves (demo mode). In demo mode, file reads should be synchronous or use await with fs.promises.readFile. Check that each step in the orchestrator resolves its promise after reading the data. Add a timeout (10 seconds per step) so the orchestrator moves on if a step hangs."
Symptom
Sidebar active state does not update when navigating
Evidence
The sidebar always shows 'Home' as active regardless of which page I am on.
What to ask the AI
"The layout.hbs template needs to know which page is active. Pass a 'currentPage' variable from each route: res.render('maintenance', { data, currentPage: 'maintenance' }). In the sidebar template, add a conditional class: {{#if (eq currentPage 'maintenance')}}active{{/if}}. Register a Handlebars 'eq' helper: Handlebars.registerHelper('eq', (a, b) => a === b)."

How it works

The command center has six core modules:

  1. Express Server (server.js) sets up routes, configures Handlebars templating, and serves the static frontend assets. It is the backbone that connects the browser to the data and orchestration logic.

  2. Data Bridge (data-bridge.js) is the abstraction layer between the command center and the individual tools. In demo mode, it reads JSON files from the sample directory. In production mode, it reads output files from each tool’s directory. This separation means you can wire up real tools one at a time without changing the command center code.

  3. Orchestrator (orchestrator.js) sequences the Morning Run. It runs each step in order, tracks progress, and provides a status endpoint for the frontend to poll. In production mode, it spawns child processes to run each tool’s CLI command. In demo mode, it just reloads data files with a small delay for visual feedback.

  4. Priority Engine (priority-engine.js) is the brain. It scores every actionable item from every data source against the priority rules, sorts by score, and returns the top 15. The scoring rules encode property management expertise: a water heater emergency outranks a renewal follow-up, which outranks a routine communication.

  5. Exception Scanner (exception-scanner.js) is the alarm system. It scans all data for items that are off-track — SLA breaches, delayed turns, risk spikes, KPI drops — and packages them for the exception center. If the scanner returns an empty result, the building is running smoothly.

  6. Owner Packet Generator (owner-packet.js) compiles a branded PDF from the KPI data, maintenance summary, turn status, and renewal pipeline. It uses Puppeteer to convert a Handlebars template to PDF with the Concord branding.


Customize it

Add Slack integration for critical alerts

Add a --slack flag to config.json with a Slack webhook URL. When the exception
scanner detects a critical SLA breach (emergency work order overdue), send
a Slack message immediately -- do not wait for the Morning Run. The message
should include the unit number, work order description, hours overdue, and
assigned vendor. Format it with a red sidebar and "CRITICAL: SLA Breach"
header. Only send for emergency and urgent SLA breaches, not standard ones.

Add resident communication drafting directly in the dashboard

Add a "Draft Response" button to each item in the comms view. When clicked,
open a modal with the resident's issue summary and a pre-drafted response
(pulled from the comms tool output). Let Nick edit the text, then save
the draft back to the comms-queue.json with status "draft-ready". Add a
"Send All Ready Drafts" button that marks them as sent and logs the timestamp.

Add mobile-optimized view

Create a /mobile route that serves a simplified single-column view optimized
for Nick's phone. Show only: the Morning Run button, Today's Top 5 (not 15),
exception count badges, and quick-action buttons for the most urgent items.
No charts, no sidebar -- just the essentials. Use a 16px base font and
44px minimum touch targets. Auto-detect mobile via user-agent and redirect
from / to /mobile if on a phone.

Add historical trend dashboard

Add a /trends route that shows 12-week trend charts for all KPIs. Store
each Morning Run's KPI snapshot in a history.json file (appended daily).
Show line charts for occupancy, leasing velocity, delinquency, renewal
rate, and concessions over time. Add a "compare to portfolio" toggle that
overlays the regional average (entered manually in config.json) so Nick
can see how the Concord tracks against the portfolio benchmark.

Try it yourself

  1. Generate the command center with the prompt above.
  2. Run npm install and start the server with node src/server.js.
  3. Open http://localhost:3000 and click “Morning Run.” Watch the progress bar step through each phase.
  4. Review the Top 15 list. Do the priorities make sense? The most urgent maintenance items should be at the top.
  5. Click into the Exception Center. Are the SLA breaches correct based on the sample data?
  6. Navigate to each section using the sidebar. Does the data display correctly on each page?
  7. Go to Reports and click “Generate Owner Packet” (if Puppeteer is installed). Open the PDF.
  8. Edit data/sample/maintenance-queue.json to add a new emergency work order. Restart the server and run the Morning Run again. Does the new emergency appear at the top of the Top 15?

Key takeaways

  • Integration is the capstone skill. Building individual tools is valuable. Connecting them into a unified workflow that matches how the operator actually thinks and works is where the real productivity gain lives. The command center does not add new data — it reorganizes existing data into the shape of a property manager’s morning.
  • Unified priority queues eliminate context switching. Five tools means five mental models. One ranked list means one question: “What is the most important thing right now?” The priority engine encodes operational expertise into scoring rules so the answer is always ready.
  • Exception-based management scales. A 413-unit property generates hundreds of data points daily. Nick cannot review all of them. The exception scanner surfaces only what is off-track, which means Nick’s attention goes to the 5% that matters, not the 95% that is running fine.
  • One-click automation respects the operator’s time. The Morning Run takes 30 seconds. The manual equivalent — opening five tools, reviewing five outputs, mentally combining them — takes 20 minutes. That is 19.5 minutes back every morning, plus the cognitive load of not having to remember which tool to check first.
  • Demo mode makes the tool usable immediately. The sample data means Nick can see the dashboard working before wiring up his real tools. That builds confidence. He can connect tools one at a time — maintenance first, then renewals, then the others — without an all-or-nothing migration.

KNOWLEDGE CHECK

Nick's Morning Run completes and the Top 15 shows a maintenance emergency (water heater failure, SLA breach in 2 hours) at rank 1 and a renewal risk (risk score 85, lease expires in 10 days, no outreach) at rank 3. A new work order comes in: a resident reports their toilet is overflowing (urgent priority, SLA deadline 24 hours). Where should this new item appear in the Top 15?


The complete property ops toolkit

Across six lessons, you built the operational backbone of a 413-unit luxury apartment community:

LessonToolWhat it does
1Resident Response StudioConverts rough notes into polished, brand-appropriate resident communications
2Morning Maintenance Triage BoardParses overnight work orders, prioritizes by urgency, generates a daily action queue
3Renewal Risk & Outreach PlannerScores renewal risk, segments residents, drafts personalized outreach
4Vendor & Make-Ready OrchestratorSchedules unit turns with dependency logic, vendor calendars, and delay alerts
5Occupancy & Revenue Pulse ReporterOne-command weekly KPI report with trends, charts, and narrative
6The Daily Ops Command CenterUnifies all five tools into a single daily operating hub

These tools chain together. The maintenance triage output feeds the command center’s priority queue. The renewal risk scores drive the exception scanner. The vendor delays trigger alerts. The pulse reporter KPIs populate the health summary. The command center is the hub that ties every tool into Nick’s daily workflow.


What’s next

That wraps the property ops side of the playbook. Six tools, one unified workflow, and a building that practically manages itself — at least the data side of it.

But the playbook is not just about the Concord. Nick has a life outside the office — two daughters in futsal, soccer, and dance, overlapping practice schedules, and game-day logistics that rival a unit turn timeline. The next two lessons build personal tools that solve real problems at home.

In Lesson 7, you will build the Kids Sports Schedule Coordinator — a multi-kid activity calendar with conflict detection, carpool planning, and a weekly family view. Same AI CLI workflow, different domain. Same “one command, real output” philosophy.

In Lesson 8, you will build the Coaching Playbook Builder — a visual play diagramming tool for youth coaching with drag-and-drop formations, movement routes, and drill sequences. Nick played football at JMU and has a kinesiology degree. This is his wheelhouse, powered by AI tooling.