Files
ai-resume/content/assets/diagrams/04-edge-architecture.svg
Documenter da18ab2237 Phase 7: authored assets (diagrams, code exhibits, client wall, budget)
Phase 7 is mostly authored assets. This commit is the asset half; the
template half is a Builder child issue because this phase must not write
application code.

DoD items satisfied or advanced:

- [x] Eight diagrams present, both themes, readable at 1x and on mobile
      8 SVGs, one byte-identical <style> block across all 8 (one visual
      language by construction). Light and dark resolve from a single file
      via prefers-color-scheme, verified per file in Chrome: 8/8 return two
      distinct palettes. Geometry verified with getBBox(), not estimated:
      0 findings after fixing 74 (text overflow, partial overlap, empty
      text, out-of-viewBox). Mobile type at the 900px minimum is 14.1/12.2px.

- [x] Six code exhibits with a two-sentence rationale each
      212 verbatim lines across five eras, copied with cp/sed from the
      read-only archive. Every rationale is exactly two sentences about why
      the code is good; every exhibit also carries an honest_note, and where
      the code is not good the note says so (the 3,400-line procedural PHP
      script is presented for its operational judgement, not its structure).

- [~] Every image optimised; total page weight budgeted and recorded
      BUDGET.md records measured raw and gzip weights for all 15 served
      files: 63,802 B raw / 13,220 B gzipped. Zero rasters by design. Page
      weight of a real page is not measurable until Phase 2 templates and
      Phase 3 serving exist, and is recorded as open rather than asserted.

- [x] Archive never linked or exposed
      No mount paths or volume names under content/. Provenance recorded as
      "private archive, path withheld".

- [ ] Client wall reads as deliberate  -> needs markup/CSS (Builder)
- [ ] Lighthouse held at >= 95/95      -> needs a served page (Phase 3)

Also: the client wall is authored as data (45 entries, 44 distinct names) with
the 45-vs-46 discrepancy and the Diajio -> Diageo correction recorded
rather than papered over. No commercial marks are enabled: that is a
permission decision for Sam, so availability is recorded and permission is not
implied.
2026-10-26 17:35:15 +11:00

112 lines
6.7 KiB
XML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 540" width="960" height="540" role="img" aria-labelledby="ttl dsc">
<title id="ttl">Edge architecture</title>
<desc id="dsc">Constrained devices publish over LoRa, Zigbee or WiFi to a single MQTT broker, which feeds one automation layer that drives actuation. Retained configuration, telemetry and last-will presence let devices recover unattended.</desc>
<style>
text{font-family:ui-sans-serif,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;fill:#1b222b;font-size:15px}
.hd{font-size:15px;font-weight:600}
.sub{font-size:13px;fill:#5b6673}
.cap{font-size:12px;fill:#5b6673;letter-spacing:.06em;text-transform:uppercase;font-weight:600}
.big{font-size:19px;font-weight:600}
.node{fill:#f4f6f8;stroke:#c3ccd6;stroke-width:1.4}
.node-a{fill:#e9f1fd;stroke:#1a6bc4;stroke-width:1.4}
.node-t{fill:#e6f4f2;stroke:#0f766e;stroke-width:1.4}
.node-w{fill:#fdf1e3;stroke:#b45309;stroke-width:1.4}
.zone{fill:none;stroke:#aab4c0;stroke-width:1.4;stroke-dasharray:7 6}
.rule{stroke:#d0d7df;stroke-width:1}
.ln{stroke:#6b7684;stroke-width:1.6;fill:none}
.ln.d{stroke-dasharray:6 5}
.ln.a{stroke:#1a6bc4}
.ln.t{stroke:#0f766e}
.ln.w{stroke:#b45309}
.mN{fill:#6b7684}
.mA{fill:#1a6bc4}
.mT{fill:#0f766e}
.mW{fill:#b45309}
.dot{fill:#6b7684}
.tick{stroke:#aab4c0;stroke-width:1.2}
@media (prefers-color-scheme: dark){
text{fill:#e7edf4}
.sub,.cap{fill:#98a4b3}
.node{fill:#182028;stroke:#35424f}
.node-a{fill:#11253d;stroke:#5aa2f0}
.node-t{fill:#0d2624;stroke:#38b3a6}
.node-w{fill:#2a1d10;stroke:#d98b3f}
.zone{stroke:#43525f}
.rule{stroke:#2c3743}
.ln{stroke:#8496a6}
.ln.a{stroke:#5aa2f0}
.ln.t{stroke:#38b3a6}
.ln.w{stroke:#d98b3f}
.mN{fill:#8496a6}
.mA{fill:#5aa2f0}
.mT{fill:#38b3a6}
.mW{fill:#d98b3f}
.dot{fill:#8496a6}
.tick{stroke:#43525f}
}
</style>
<defs>
<marker id="aN" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path class="mN" d="M0,0 L10,5 L0,10 z"/></marker>
<marker id="aA" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path class="mA" d="M0,0 L10,5 L0,10 z"/></marker>
<marker id="aT" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path class="mT" d="M0,0 L10,5 L0,10 z"/></marker>
<marker id="aW" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path class="mW" d="M0,0 L10,5 L0,10 z"/></marker>
</defs>
<text x="24" y="40" class="big">Edge architecture — devices, one broker, one automation layer</text>
<rect x="24" y="74" width="220" height="236" rx="7" class="node "/>
<text x="38" y="100" class="hd">Devices</text>
<text x="38" y="120" class="sub">20+ nodes · 9 zones</text>
<path d="M24,132 L244,132" class="rule"/>
<rect x="38" y="146" width="192" height="40" rx="7" class="node "/>
<text x="134.0" y="164.0" class="hd" text-anchor="middle">10 × ESP32</text>
<text x="134.0" y="182.0" class="sub" text-anchor="middle">sensors, relays, buttons</text>
<rect x="38" y="194" width="192" height="40" rx="7" class="node "/>
<text x="134.0" y="212.0" class="hd" text-anchor="middle">2 × Zigbee routers</text>
<text x="134.0" y="230.0" class="sub" text-anchor="middle">hand-built</text>
<rect x="38" y="242" width="192" height="40" rx="7" class="node "/>
<text x="134.0" y="260.0" class="hd" text-anchor="middle">8 × Pi audio endpoints</text>
<text x="134.0" y="278.0" class="sub" text-anchor="middle">Snapcast clients</text>
<text x="38" y="300" class="sub">radio: LoRa · Zigbee · WiFi</text>
<path d="M244,190 L288,190" class="ln a" marker-end="url(#aA)"/>
<rect x="288" y="74" width="210" height="236" rx="7" class="node "/>
<text x="302" y="100" class="hd">MQTT broker</text>
<text x="302" y="120" class="sub">the only shared state</text>
<path d="M288,132 L498,132" class="rule"/>
<rect x="302" y="146" width="182" height="40" rx="7" class="node "/>
<text x="393.0" y="171.0" class="hd" text-anchor="middle">retained config</text>
<rect x="302" y="194" width="182" height="40" rx="7" class="node "/>
<text x="393.0" y="219.0" class="hd" text-anchor="middle">status · telemetry</text>
<rect x="302" y="242" width="182" height="40" rx="7" class="node "/>
<text x="393.0" y="260.0" class="hd" text-anchor="middle">LWT presence</text>
<text x="393.0" y="278.0" class="sub" text-anchor="middle">last will = offline</text>
<text x="302" y="300" class="sub">reconnect + re-subscribe</text>
<path d="M498,190 L542,190" class="ln " marker-end="url(#aN)"/>
<rect x="542" y="74" width="194" height="236" rx="7" class="node "/>
<text x="556" y="100" class="hd">Automation</text>
<text x="556" y="120" class="sub">20 automations · 9 zones</text>
<path d="M542,132 L736,132" class="rule"/>
<text x="556" y="156" class="sub">trigger → rule → action</text>
<text x="556" y="182" class="sub">9 lighting zones</text>
<text x="556" y="208" class="sub">auditable in one place</text>
<text x="556" y="240" class="sub">rules live in config,</text>
<text x="556" y="258" class="sub">not in firmware</text>
<path d="M736,190 L780,190" class="ln t" marker-end="url(#aT)"/>
<rect x="780" y="74" width="156" height="236" rx="7" class="node "/>
<text x="794" y="100" class="hd">Actuation</text>
<path d="M780,132 L936,132" class="rule"/>
<text x="794" y="158" class="sub">lights · relays</text>
<text x="794" y="184" class="sub">speech out</text>
<text x="794" y="210" class="sub">displays</text>
<text x="794" y="236" class="sub">doors · gates</text>
<rect x="24" y="332" width="442" height="84" rx="7" class="node node-t"/>
<text x="38" y="358" class="hd">Power and duty cycle</text>
<text x="38" y="380" class="sub">solar where there is no mains · deep sleep between reports</text>
<text x="38" y="400" class="sub">the budget that gets designed first, not last</text>
<rect x="494" y="332" width="442" height="84" rx="7" class="node node-w"/>
<text x="508" y="358" class="hd">Failures kept in the record</text>
<text x="508" y="380" class="sub">lizard feeder destroyed by the lizard · cameras postponed</text>
<text x="508" y="400" class="sub">doorbell being rebuilt with a ToF sensor</text>
<text x="24" y="452" class="sub">Same shape at every size: device → one broker → one automation layer → actuation.</text>
<text x="24" y="472" class="sub">Devices never talk to each other, so a node that returns from a power cut re-announces itself and nothing else changes.</text>
<text x="936" y="500" class="sub" text-anchor="end">20+ nodes = 10 ESP32 · 2 Zigbee routers · 8 Pi · reference/content-map.md</text>
</svg>