Silver Lands Management Group
Studio 168 Productions · Asset Management Architecture
Dashboard
Internal · April 2026

How the asset management dashboard is built.

A short, plain-English walkthrough of the file structure, data pipeline, and update rules behind the Silver Lands AM dashboard system.

Contents
01Overview 02The Portfolio 03Design Principles 04File Structure 05The Data Pipeline 06Consistency Rules 07Live Ops & Refresh 08Per-Property Pages 09Migration Plan
01 · OVERVIEW

Why this exists.

The asset management dashboard started as one HTML file. It now spans roughly eighty files across fifty properties, twelve portfolio groups, and six upstream data sources. That growth is healthy — but the seams are starting to show.

Numbers occasionally drift between the master view and a property page. A typo in an embedded data block can blank the whole dashboard. Refreshing data is a multi-file ritual that gets done late on Friday afternoons. None of these are critical. All of them compound.

This document describes the architecture that fixes those problems without rebuilding what already works. It defines where data lives, who is allowed to write to it, and how every dashboard view stays in sync as new information arrives.

The test: Monday morning, after a CapEx drop on Friday and a Main Street pull on Sunday, can the dashboard render the same number for Lakeside LTD on the master view, the property detail page, and the portfolio rollup? Yes. That's the point.
02 · THE PORTFOLIO

What the system covers.

Fifty properties across three asset types and twelve portfolio groups, all reporting into one command center.

50
Properties tracked
12
Portfolio groups
~80
Files when complete
6
Upstream data sources

Asset types

Upstream data sources

03 · DESIGN PRINCIPLES

Four rules that anchor every decision.

These are not aesthetic preferences. Each one prevents a specific failure mode that has already happened in the system.

I · Isolated failures — broken Lakeside file never blanks Lone Starsurvives errors
II · Single source of truth — each metric lives in exactly one fileno drift
III · Pipeline-owned data flow — humans don't paste data, scripts dorepeatable
IV · Auto-update from Main Street — scheduled pulls keep numbers freshalways current

Every architectural choice that follows traces back to one of these four. When two principles conflict — for example, when adding a new property forces a tradeoff between repeatability and isolation — the order above is the tiebreaker.

04 · FILE STRUCTURE

One workspace. Five top-level folders.

Predictable shape. Every file has a single job and a name you can guess from its location.

Asset Management Master/ ├── asset-management-master.html ← command center (renders only) │ ├── _data/ ← single source of truth (JSON) │ ├── properties.json (master roster, IDs, groups) │ ├── capex-actuals.json (GL + cash flow, all properties) │ ├── capex-plan.json (per-property plan baselines) │ ├── rent-roll.json (Main Street snapshot) │ ├── debt.json (lender ledger) │ └── mainstreet.json (live ops pull) │ ├── _sources/ ← raw inputs, never edited by hand │ ├── gl/ cash-flow/ rent-roll/ │ ├── gp-master/ appfolio/ │ └── monday/ mainstreet/ │ ├── _scripts/ ← the pipeline │ ├── refresh.py (orchestrator: pulls + builds) │ ├── validate.py (cross-file reconciliation) │ ├── ingest_*.py (one per source system) │ └── build_*.py (one per output) │ └── Properties/ ← one folder per property └── <Group>/<Property>/ ├── <property>.html (detail page, reads JSON only) ├── <property>-homes.html └── <property>-dd.html

Each folder has one job.

_data/
JSON source of truth
~10 files · what dashboards read
_sources/
Raw export archive
Append-only · never edited
_scripts/
The pipeline
~12 Python scripts · repeatable
Properties/
Per-property HTML
50 detail pages · isolated
05 · THE DATA PIPELINE

Sources flow in. Scripts shape them. Pages render them.

The pipeline is the only writer to _data/. Views are read-only consumers. This is the single rule that makes the system survive growth.

Three stages, in order

The pipeline contract

// Every script in _scripts/ obeys these rules: Inputs: files in _sources/ (read-only) Outputs: files in _data/ (write, with backup of prior version) Logs: _scripts/logs/YYYY-MM-DD.txt Errors: exit code 1, no partial writes Idempotent: running twice produces the same result

The orchestrator refresh.py calls every ingest and build script in order. It accepts a flag to skip stages (--skip mainstreet) and a --dry-run mode that reports what would change without writing.

Why this matters. Today, updating CapEx requires editing four files: an embedded const in the master HTML, a shared JS file, a JSON source, and one or more per-property pages. After this change, the same update is one command: refresh.py capex. The four downstream files always agree because they read from one upstream file.
06 · CONSISTENCY RULES

How we prove the numbers match.

A dashboard that shows different numbers in different views loses trust the first time it happens. The system enforces consistency through three mechanisms.

Mechanism one — single source

Each metric lives in exactly one JSON file. Lakeside LTD CapEx exists in capex-actuals.json. The master view, the Lakeside detail page, and the portfolio rollup all read that same file. There is no second copy to drift from.

Mechanism two — validate.py

After every pipeline run, validate.py walks the data files and asserts known relationships:

Failures print to console and write a flag file. The dashboard surfaces a small banner when validation has failed since the last successful run.

Mechanism three — append-only sources

Raw exports go into _sources/ with the export date in the filename. Nothing overwrites. If a number changes mysteriously, you can diff yesterday's GL against today's GL and find the difference in two minutes.

07 · LIVE OPS & REFRESH

What runs when.

Different upstream systems refresh on different cadences. The schedule below keeps the dashboard fresh without overwhelming any one source.

Refresh cadence

Live ops drives the top-line KPIs

The KPI cards at the top of the master dashboard read from mainstreet.json, not from static fields in the HTML. When the late-afternoon Main Street pull completes, the next page load reflects current portfolio occupancy, collections, and work-order status.

Late afternoon, not early morning. The Main Street pull runs after 4pm intentionally — that's when the PM team has finished reconciling moves, payments, and work orders for the day. An early-morning pull would capture stale overnight state.
08 · PER-PROPERTY PAGES

Command center plus fifty isolated detail pages.

The master HTML is the command center — portfolio rollups, KPIs, cross-property comparisons. Each property has its own detail page that loads independently.

The pattern

Tab pattern (Lakeside template)

09 · MIGRATION PLAN

Five phases. About six hours of focused work.

The current system already does most of this work — the migration is mostly extraction and orchestration, not rebuilding. Phases can be paused between, but should be done in order.

1
Extract data from master HTML DONE
11 data domains pulled from asset-management-master.html into _data/*.{json,js}. Master HTML shrank from 2.14 MB → 879 KB (59%). The HTML is now a renderer.
1.5 hrs
2
Build the pipeline orchestrator DONE
_scripts/refresh.py and _scripts/regenerate_wrappers.py are live. Per-domain extract scripts use a shared _domain_extract.py. argv interface supports --only, --skip, --dry-run.
2 hrs
3
Add validate.py DONE
8 cross-file reconciliation checks, 31 assertions total. Wrappers-match-JSON (C2), LTD reconciliation (C3), routing pages exist (C4), data freshness (C5), group membership sanity (C6, C7, C8). All passing.
0.5 hr
4
Stamp remaining property pages DONE
_scripts/stamp_property_pages.py reads properties.json + all _data/ sources and auto-stamps a detail page per property. Tabs render only when their data exists. 44 pages stamped, 4 protected (Lakeside/Miami/Montecarlo/Ford Homes), 48 total in routing.
1.5 hrs
5
Schedule auto-refresh DONE
Two scheduled tasks live: am-refresh-daily runs every afternoon at 4:30 PM (Main Street + validate), am-refresh-weekly runs Mondays at 4:30 PM (full refresh across GL, GP Master, rent roll, Monday, Main Street). Failures surface through the Scheduled tasks sidebar.
0.5 hr

Today vs after

ScenarioTodayAfter
New CapEx GL drops inEdit 4 files by hand. Hope nothing drifts.Run refresh.py. Validate confirms reconciliation.
Lakeside file has a typoWhole dashboard goes blank.Lakeside page errors. Everything else renders.
New property addedTouch master HTML, JS map, plan file, and copy a template.Add a row to properties.json. Pipeline stamps the page.
Live ops change at 2pmManual export, manual paste, refresh browser.Scheduled pull at 4pm. Dashboard reflects it.
Recommended starting point. Phase 1 alone delivers most of the consistency benefit. Once data lives in JSON, every other improvement becomes a one-evening project. Without Phase 1, nothing else is durable.
Silver Lands Management Group · Studio 168 Productions · AM Dashboard Architecture · April 2026