ADR-0017 rev 3: single switch — PE replaces the SG105E, CCTV rides a VLAN-30 trunk on the LAN1 cable

Viktor prefers not running two switches, so the TL-SG105PE takes over
all rack duties (apartment uplink, 4G, UPS, camera PoE) and the CCTV
segment moves onto a managed tagged trunk over the existing LAN1 cable:
pfSense net3 re-pointed from vmbr2 to vmbr0 tag=30 (applied live; same
MAC so vtnet3/dCCTV survived untouched). This is safe where the original
802.1Q rejection was not, because the managed switch is the only device
on eno1 and polices VLAN-30 membership. eno2/vmbr2 kept dormant as the
documented fallback. Old SG105E retires to cold spare; PE inherits
192.168.1.6. Glossary Segment term updated (all three segments are now
bridge-tags feeding untagged pfSense vNICs).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Viktor Barzin 2026-07-03 09:15:52 +00:00
parent 4082934bc1
commit be80ef23bb
4 changed files with 116 additions and 119 deletions

View file

@ -1,6 +1,6 @@
# CCTV segment on a dedicated pfSense leg, not an 802.1Q trunk
# CCTV segment: dedicated pfSense interface, VLAN-30 trunk on the LAN1 cable
Status: accepted (2026-07-02)
Status: accepted (2026-07-02, rev 3 — single-switch)
![Network topology — dCCTV segment, flows, and camera-day steps](./0017-cctv-segment-topology.svg)
@ -13,14 +13,22 @@ to pfSense" — but nothing in this network terminates dot1q on pfSense; the
site idiom is one vlan-aware Proxmox bridge → one tagged VM NIC → one clean
untagged pfSense interface per segment.
**Decision:** the CCTV segment (`dCCTV`, 10.0.30.1/24) rides a dedicated
physical leg — R730 `eno2` (spare) → new bridge `vmbr2` → pfSense `net3`
(vtnet3), untagged end-to-end. The new TL-SG105PE PoE switch is a **dedicated
CCTV island**: camera in a PoE port, one port patched to eno2, no VLAN table
at all, mgmt IP inside the segment (10.0.30.6 via Kea). The existing garage
TL-SG105E (192.168.1.6 — apartment uplink, R730 LAN1, 4G router 192.168.1.7,
UPS mgmt; exactly one free port) is untouched — it has no PoE and no spare
port pair, which is also why the two roles cannot share one switch.
**Decision (rev 3):** ONE switch — the new TL-SG105PE **replaces** the old
garage TL-SG105E (Viktor prefers not running two switches; retired unit
becomes a cold spare, its 192.168.1.6 mgmt IP passes to the PE). Five ports,
all used: apartment uplink, 4G router 192.168.1.7, UPS mgmt (all untagged
VLAN 1), the camera (untagged VLAN 30, PoE), and the **trunk to R730 `eno1`
carrying home LAN untagged + CCTV tagged 30** over the existing LAN1 cable.
pfSense `net3` (vtnet3) sits on `vmbr0` with `tag=30` — exactly the site
idiom used for dManagementsVms/dKubernetes (bridge-level tag → clean untagged
vNIC; pfSense still terminates no dot1q itself). The earlier dedicated
`eno2`/`vmbr2` leg is kept **dormant as a fallback** (rev 2 wired it; moving
net3 back to vmbr2 restores pure physical isolation in one `qm set`).
This narrows the earlier 802.1Q objection rather than contradicting it: the
rejection assumed *unmanaged* switches, where any LAN device could inject
tagged frames; with the managed PE as the only device on eno1, VLAN-30
membership is {camera port, trunk port} only, so tag-30 ingress from every
other port — and from the exposed camera cable — is dropped or contained.
Cameras are untrusted: default-deny on dCCTV with a single
NTP-to-gateway exception; Frigate (k8s) pulls RTSP in; ha-sofia (192.168.1.8)
may reach ISAPI/RTSP directly; home-LAN clients route in via an AX6000 static
@ -29,29 +37,35 @@ route (10.0.30.0/24 via 192.168.1.2). 10.0.30.0/24 is deliberately NOT in the
## Considered options
- **802.1Q tag over the existing LAN path (eno1/vmbr0)** — rejected: vmbr0 is
vlan-aware with `bridge-vids 2-4094`, so ANY device on the home LAN could
inject tagged frames straight into the camera segment (defeats the
cable-tap threat model); tag-passing through the unmanaged SW1 is
undefined; and it reconfigures the live bridge carrying the host IP and
pfSense WAN.
- **802.1Q over the LAN path behind an UNMANAGED switch** (the original plan
read this way) — rejected: any LAN device could inject tagged frames into
vmbr0 (`bridge-vids 2-4094`) and tag-passing through a dumb switch is
undefined. Rev 3 adopts the tagged path ONLY because the managed PE now
polices VLAN-30 membership at the single entry point to eno1; no bridge
reconfiguration was needed (vmbr0 was already vlan-aware).
- **Dedicated physical leg (eno2 → vmbr2 → net3), one switch per role**
(rev 1/2 as-built) — superseded by rev 3: it forced either a second switch
(6 connections vs 5 ports once the PE also replaced the old switch) or new
hardware. Strongest isolation of all options; kept dormant as the fallback.
- **AX6000 as the camera gateway** — rejected earlier in the design (consumer
router, no inter-VLAN firewall).
## Consequences
- eno2 is consumed; eno3/eno4 remain the last spare NICs on the R730.
- Two Easy Smart switches live in the rack: the OLD TL-SG105E at 192.168.1.6
remains the load-bearing shared one (apartment uplink, R730 LAN1, pfSense's
backup-WAN path via the 4G router, UPS mgmt — one port free); the NEW
TL-SG105PE carries only CCTV. The Easy Smart mgmt-answers-on-every-port
quirk is therefore contained: the PE's mgmt UI is only L2-adjacent to
cameras, and pfSense still gates all L3.
- Adding a future camera = one free PoE port on the PE + a Kea
reservation; no pfSense/PVE/VLAN work.
- 2026-07-02 correction: an earlier revision of this ADR described ONE shared
PE switch with a port-based VLAN split — written before discovering the
live 192.168.1.6 device is a separate, older non-PoE TL-SG105E. No VLAN
table exists anywhere in the final design.
- The switch is now single-point and load-bearing for everything in the rack
(apartment uplink, pfSense backup-WAN via 4G, UPS mgmt, CCTV) AND its VLAN
table + mgmt password are part of the isolation boundary — the Easy Smart
mgmt UI answers on every port, so the password is the gate between a
compromised camera and the switch config. All 5 ports are consumed: the
next camera forces an 8-port PoE upgrade (the wiring plan already fits it).
- `eno2`/`vmbr2` stay cabled-ready but dormant (fallback to rev 2's physical
leg); eno3/eno4 remain free.
- The old TL-SG105E is retired to cold spare; the PE inherits 192.168.1.6
(Kea reservation by MAC).
- Revision history (all 2026-07-02): rev 1 assumed one shared PE with a
port-VLAN split (conflated the two devices); rev 2 split into two switches
after inspecting 192.168.1.6 (old non-PoE SG105E, 4/5 ports used); rev 3
consolidated back to one switch — the PE replacing the SG105E — per
Viktor's preference, moving CCTV onto a managed tagged trunk.
- Frigate's ADR-0016 VRAM budget was bumped 2000 → 2300 MiB for the extra
NVDEC stream.

View file

@ -1,8 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1600" height="880" viewBox="0 0 1600 880" font-family="system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif">
<!-- ADR-0017 dCCTV topology (two-switch revision). Colors: reference dataviz
palette (light mode). blue #2a78d6 = home LAN · violet #4a3aa7 = dCCTV ·
aqua #1baf7a = dKubernetes · yellow #eda100 = dManagementsVms ·
green #008300 = allowed flow · red #e34948 = denied flow -->
<!-- ADR-0017 rev 3 dCCTV topology (single switch, VLAN-30 trunk on LAN1).
Colors: reference dataviz palette (light mode). blue #2a78d6 = home LAN ·
violet #4a3aa7 = dCCTV · aqua #1baf7a = dKubernetes ·
yellow #eda100 = dManagementsVms · green #008300 allow · red #e34948 deny -->
<defs>
<marker id="arrGreen" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<path d="M0,0 L10,5 L0,10 z" fill="#008300"/>
@ -17,11 +17,10 @@
<rect width="1600" height="880" fill="#fcfcfb"/>
<!-- title -->
<text x="40" y="42" font-size="26" font-weight="700" fill="#0b0b0b">ADR-0017 — CCTV segment on a dedicated pfSense leg</text>
<text x="40" y="66" font-size="15" fill="#52514e">Sofia/Vermont · as-built 2026-07-02 · dashed = camera-day · no VLANs anywhere — isolation is physical</text>
<text x="40" y="42" font-size="26" font-weight="700" fill="#0b0b0b">ADR-0017 — CCTV segment behind pfSense, VLAN-30 trunk on the LAN1 cable</text>
<text x="40" y="66" font-size="15" fill="#52514e">Sofia/Vermont · rev 3 (single switch) 2026-07-02 · dashed = camera-day · the ONLY 802.1Q is the trunk between the switch and eno1</text>
<!-- camera -> everything else (denied): kept above the zones, below the subtitle -->
<!-- camera -> everything else (denied) -->
<path d="M240,168 C520,104 900,104 1148,140" fill="none" stroke="#e34948" stroke-width="3" marker-end="url(#arrRed)"/>
<g transform="translate(560,111)">
<circle r="11" fill="#fcfcfb" stroke="#e34948" stroke-width="2.5"/>
@ -29,7 +28,7 @@
</g>
<text x="588" y="100" font-size="13.5" font-weight="700" fill="#e34948">DENY · camera → LAN / other segments / internet (default deny on dCCTV)</text>
<!-- ═════════ GARAGE ENTRANCE zone ═════════ -->
<!-- GARAGE ENTRANCE -->
<rect x="40" y="128" width="240" height="180" rx="10" fill="#4a3aa7" fill-opacity="0.06" stroke="#4a3aa7" stroke-opacity="0.35"/>
<text x="56" y="154" font-size="13" font-weight="700" fill="#52514e" letter-spacing="1">GARAGE ENTRANCE</text>
<rect x="64" y="170" width="192" height="112" rx="8" fill="#ffffff" stroke="#4a3aa7" stroke-width="2"/>
@ -39,67 +38,57 @@
<text x="80" y="252" font-size="12.5" fill="#52514e">DNS: garage-cam.viktorbarzin.lan</text>
<text x="80" y="270" font-size="12.5" fill="#52514e">PoE from switch · cloud/P2P off</text>
<!-- camera cable to PE switch (camera day, dashed) -->
<path d="M160,308 L160,390" fill="none" stroke="#52514e" stroke-width="2" stroke-dasharray="6,5" marker-end="url(#arrGray)"/>
<text x="172" y="344" font-size="12" fill="#52514e">cat6 in conduit · PoE</text>
<path d="M256,284 C330,330 412,368 417,430" fill="none" stroke="#52514e" stroke-width="2" stroke-dasharray="6,5" marker-end="url(#arrGray)"/>
<text x="330" y="322" font-size="12" fill="#52514e">cat6 in conduit · PoE → P4</text>
<!-- ═════════ RACK zone ═════════ -->
<!-- RACK zone: single switch -->
<rect x="40" y="360" width="560" height="265" rx="10" fill="#0b0b0b" fill-opacity="0.03" stroke="#b9b8b2"/>
<text x="56" y="384" font-size="13" font-weight="700" fill="#52514e" letter-spacing="1">RACK — GARAGE · TWO SWITCHES</text>
<text x="56" y="384" font-size="13" font-weight="700" fill="#52514e" letter-spacing="1">RACK — GARAGE · ONE SWITCH</text>
<!-- TL-SG105PE: NEW, dedicated CCTV island -->
<rect x="64" y="396" width="512" height="88" rx="8" fill="#4a3aa7" fill-opacity="0.05" stroke="#4a3aa7" stroke-width="2"/>
<text x="80" y="420" font-size="15" font-weight="700" fill="#0b0b0b">TL-SG105PE <tspan font-size="12.5" font-weight="400" fill="#52514e">NEW · dedicated CCTV island · mgmt 10.0.30.6 (Kea) · no VLAN table</tspan></text>
<rect x="64" y="396" width="512" height="176" rx="8" fill="#4a3aa7" fill-opacity="0.04" stroke="#4a3aa7" stroke-width="2"/>
<text x="80" y="420" font-size="15" font-weight="700" fill="#0b0b0b">TL-SG105PE <tspan font-size="12.5" font-weight="400" fill="#52514e">replaces the SG105E · mgmt 192.168.1.6 (Kea) · all 5 ports used</tspan></text>
<g font-size="11.5" text-anchor="middle">
<rect x="80" y="432" width="120" height="40" rx="6" fill="#4a3aa7" fill-opacity="0.12" stroke="#4a3aa7"/>
<text x="140" y="449" font-weight="700" fill="#0b0b0b">camera · PoE</text>
<text x="140" y="465" fill="#52514e">any of P1P4</text>
<rect x="212" y="432" width="120" height="40" rx="6" fill="#4a3aa7" fill-opacity="0.12" stroke="#4a3aa7"/>
<text x="272" y="449" font-weight="700" fill="#0b0b0b">→ R730 eno2</text>
<text x="272" y="465" fill="#52514e">uplink (P5)</text>
<rect x="344" y="432" width="120" height="40" rx="6" fill="#ffffff" stroke="#8a8984" stroke-dasharray="4,3"/>
<text x="404" y="449" fill="#52514e">3 × spare PoE</text>
<text x="404" y="465" fill="#52514e">future cameras</text>
<rect x="80" y="436" width="88" height="56" rx="6" fill="#2a78d6" fill-opacity="0.12" stroke="#2a78d6"/>
<text x="124" y="454" font-weight="700" fill="#0b0b0b">P1 · V1</text>
<text x="124" y="470" fill="#52514e">apartment</text>
<text x="124" y="484" fill="#52514e">uplink</text>
<rect x="178" y="436" width="88" height="56" rx="6" fill="#2a78d6" fill-opacity="0.12" stroke="#2a78d6"/>
<text x="222" y="454" font-weight="700" fill="#0b0b0b">P2 · V1</text>
<text x="222" y="470" fill="#52514e">4G router</text>
<text x="222" y="484" fill="#52514e">192.168.1.7</text>
<rect x="276" y="436" width="88" height="56" rx="6" fill="#2a78d6" fill-opacity="0.12" stroke="#2a78d6"/>
<text x="320" y="454" font-weight="700" fill="#0b0b0b">P3 · V1</text>
<text x="320" y="470" fill="#52514e">UPS mgmt</text>
<rect x="374" y="436" width="88" height="56" rx="6" fill="#4a3aa7" fill-opacity="0.12" stroke="#4a3aa7" stroke-width="2"/>
<text x="418" y="454" font-weight="700" fill="#0b0b0b">P4 · V30</text>
<text x="418" y="470" fill="#52514e">camera</text>
<text x="418" y="484" fill="#52514e">PoE ON</text>
<rect x="472" y="436" width="88" height="56" rx="6" fill="#2a78d6" fill-opacity="0.10" stroke="#4a3aa7" stroke-width="2" stroke-dasharray="0"/>
<text x="516" y="454" font-weight="700" fill="#0b0b0b">P5 · trunk</text>
<text x="516" y="470" fill="#52514e">V1 untagged</text>
<text x="516" y="484" fill="#4a3aa7">+ V30 tagged</text>
</g>
<text x="80" y="516" font-size="12" fill="#52514e">802.1Q: VLAN 1 untagged {P1,P2,P3,P5} · VLAN 30 {P4 untagged/PVID 30, P5 tagged}</text>
<text x="80" y="534" font-size="12" fill="#52514e">tag-30 ingress on P1/P2/P3 is dropped (not members) — the trunk is the only tagged path</text>
<text x="80" y="558" font-size="12" fill="#8a8984">old TL-SG105E → retired, cold spare · backup-WAN (4G) + UPS keep their ports</text>
<!-- TL-SG105E: existing garage switch, untouched -->
<rect x="64" y="496" width="512" height="116" rx="8" fill="#ffffff" stroke="#8a8984"/>
<text x="80" y="520" font-size="15" font-weight="700" fill="#0b0b0b">TL-SG105E · 192.168.1.6 <tspan font-size="12.5" font-weight="400" fill="#52514e">existing · no PoE · UNTOUCHED by this design</tspan></text>
<g font-size="11.5" text-anchor="middle">
<rect x="80" y="532" width="88" height="34" rx="6" fill="#2a78d6" fill-opacity="0.12" stroke="#2a78d6"/>
<text x="124" y="553" fill="#0b0b0b">P1 · 1G</text>
<rect x="178" y="532" width="88" height="34" rx="6" fill="#2a78d6" fill-opacity="0.12" stroke="#2a78d6"/>
<text x="222" y="553" fill="#0b0b0b">P2 · 100M</text>
<rect x="276" y="532" width="88" height="34" rx="6" fill="#2a78d6" fill-opacity="0.12" stroke="#2a78d6"/>
<text x="320" y="553" fill="#0b0b0b">P3 · 100M</text>
<rect x="374" y="532" width="88" height="34" rx="6" fill="#ffffff" stroke="#8a8984" stroke-dasharray="4,3"/>
<text x="418" y="553" fill="#52514e">P4 · free</text>
<rect x="472" y="532" width="88" height="34" rx="6" fill="#2a78d6" fill-opacity="0.12" stroke="#2a78d6"/>
<text x="516" y="553" fill="#0b0b0b">P5 · 1G</text>
</g>
<text x="80" y="590" font-size="12" fill="#52514e">1G ports: apartment uplink + R730 LAN1 · 100M ports: 4G router .7 (pfSense backup-WAN) + UPS mgmt</text>
<!-- trunk: two parallel lines to eno1 -->
<path d="M560,458 C630,458 640,428 692,420" fill="none" stroke="#2a78d6" stroke-width="2.5"/>
<path d="M560,466 C632,466 644,436 692,428" fill="none" stroke="#4a3aa7" stroke-width="2.5"/>
<text x="588" y="404" font-size="12" font-weight="700" fill="#0b0b0b">LAN1 cable</text>
<!-- PE -> eno2 patch (camera day, dashed) -->
<path d="M576,452 C630,452 640,478 676,490" fill="none" stroke="#52514e" stroke-width="2" stroke-dasharray="6,5" marker-end="url(#arrGray)"/>
<text x="592" y="440" font-size="12" fill="#52514e">patch</text>
<!-- E -> eno1 (existing R730 LAN1) -->
<path d="M576,522 C630,522 650,470 696,432" fill="none" stroke="#2a78d6" stroke-width="2" opacity="0.6"/>
<text x="604" y="516" font-size="12" fill="#2a78d6">R730 LAN1</text>
<!-- ═════════ R730 / PVE zone ═════════ -->
<!-- R730 / PVE zone -->
<rect x="680" y="330" width="880" height="440" rx="10" fill="#0b0b0b" fill-opacity="0.03" stroke="#b9b8b2"/>
<text x="696" y="356" font-size="13" font-weight="700" fill="#52514e" letter-spacing="1">DELL R730 — PVE HOST 192.168.1.127 (IN THE RACK)</text>
<!-- NIC/bridge chips on left edge -->
<g font-size="12">
<rect x="700" y="400" width="150" height="46" rx="6" fill="#2a78d6" fill-opacity="0.12" stroke="#2a78d6"/>
<rect x="700" y="400" width="150" height="46" rx="6" fill="#2a78d6" fill-opacity="0.12" stroke="#4a3aa7" stroke-width="2"/>
<text x="712" y="419" font-weight="700" fill="#0b0b0b">eno1 → vmbr0</text>
<text x="712" y="436" fill="#52514e">LAN1 · vlan-aware</text>
<text x="712" y="436" fill="#52514e">untag V1 + tag 30</text>
<rect x="700" y="471" width="150" height="46" rx="6" fill="#4a3aa7" fill-opacity="0.12" stroke="#4a3aa7" stroke-width="2"/>
<text x="712" y="490" font-weight="700" fill="#0b0b0b">eno2 → vmbr2</text>
<text x="712" y="507" fill="#52514e">NEW · dedicated leg</text>
<rect x="700" y="471" width="150" height="46" rx="6" fill="#ffffff" stroke="#8a8984" stroke-dasharray="4,3"/>
<text x="712" y="490" font-weight="700" fill="#52514e">eno2 → vmbr2</text>
<text x="712" y="507" fill="#8a8984">dormant fallback leg</text>
<rect x="700" y="542" width="150" height="46" rx="6" fill="#0b0b0b" fill-opacity="0.04" stroke="#8a8984"/>
<text x="712" y="561" font-weight="700" fill="#0b0b0b">vmbr1</text>
@ -112,17 +101,16 @@
<text x="906" y="432" font-size="12" fill="#52514e">gateway + firewall for every segment</text>
<g font-size="12">
<rect x="906" y="444" width="268" height="34" rx="5" fill="#2a78d6" fill-opacity="0.12" stroke="#2a78d6"/>
<text x="916" y="465" fill="#0b0b0b">net0 · WAN <tspan fill="#52514e">192.168.1.2 (home LAN)</tspan></text>
<text x="916" y="465" fill="#0b0b0b">net0 · WAN <tspan fill="#52514e">192.168.1.2 · vmbr0 untagged</tspan></text>
<rect x="906" y="484" width="268" height="34" rx="5" fill="#eda100" fill-opacity="0.14" stroke="#eda100"/>
<text x="916" y="505" fill="#0b0b0b">net1 · dManagementsVms <tspan fill="#52514e">10.0.10.1</tspan></text>
<rect x="906" y="524" width="268" height="34" rx="5" fill="#1baf7a" fill-opacity="0.12" stroke="#1baf7a"/>
<text x="916" y="545" fill="#0b0b0b">net2 · dKubernetes <tspan fill="#52514e">10.0.20.1</tspan></text>
<rect x="906" y="564" width="268" height="34" rx="5" fill="#4a3aa7" fill-opacity="0.12" stroke="#4a3aa7" stroke-width="2"/>
<text x="916" y="585" fill="#0b0b0b">net3 · dCCTV <tspan fill="#52514e">10.0.30.1/24 · NEW</tspan></text>
<text x="916" y="585" fill="#0b0b0b">net3 · dCCTV <tspan fill="#52514e">10.0.30.1/24 · vmbr0 tag 30</tspan></text>
</g>
<!-- bridge attachments -->
<path d="M850,423 L890,458" fill="none" stroke="#2a78d6" stroke-width="1.6" opacity="0.6"/>
<path d="M850,494 L890,581" fill="none" stroke="#4a3aa7" stroke-width="2"/>
<path d="M850,415 L890,458" fill="none" stroke="#2a78d6" stroke-width="1.6" opacity="0.6"/>
<path d="M850,430 L890,581" fill="none" stroke="#4a3aa7" stroke-width="2"/>
<path d="M850,565 L890,501" fill="none" stroke="#8a8984" stroke-width="1.6" opacity="0.6"/>
<path d="M850,565 L890,541" fill="none" stroke="#8a8984" stroke-width="1.6" opacity="0.6"/>
@ -139,7 +127,7 @@
<text x="1268" y="562" font-size="13.5" font-weight="700" fill="#0b0b0b">go2rtc LB 10.0.20.204</text>
<text x="1268" y="580" font-size="12" fill="#52514e">restream → HA live view (MSE/HLS)</text>
<!-- ═════════ HOME LAN zone ═════════ -->
<!-- HOME LAN zone -->
<rect x="1148" y="128" width="412" height="180" rx="10" fill="#2a78d6" fill-opacity="0.06" stroke="#2a78d6" stroke-opacity="0.4"/>
<text x="1164" y="154" font-size="13" font-weight="700" fill="#52514e" letter-spacing="1">HOME LAN 192.168.1.0/24</text>
<rect x="1164" y="168" width="180" height="56" rx="6" fill="#ffffff" stroke="#2a78d6"/>
@ -151,45 +139,40 @@
<rect x="1360" y="168" width="184" height="56" rx="6" fill="#ffffff" stroke="#2a78d6"/>
<text x="1372" y="190" font-size="13.5" font-weight="700" fill="#0b0b0b">apartment clients</text>
<text x="1372" y="208" font-size="11.5" fill="#52514e">laptops, phones</text>
<!-- AX6000 route badge (camera day) -->
<rect x="1360" y="236" width="184" height="52" rx="6" fill="#ffffff" stroke="#52514e" stroke-dasharray="5,4"/>
<text x="1372" y="256" font-size="11.5" font-weight="700" fill="#52514e">CAMERA DAY: static route</text>
<text x="1372" y="272" font-size="11.5" fill="#52514e">10.0.30.0/24 via 192.168.1.2</text>
<!-- home LAN -> pfSense WAN (via apartment uplink path) -->
<path d="M1254,308 C1150,352 950,372 790,400" fill="none" stroke="#2a78d6" stroke-width="2" opacity="0.6"/>
<text x="1010" y="374" font-size="12" fill="#2a78d6">apartment uplink · SG105E · eno1</text>
<text x="1010" y="374" font-size="12" fill="#2a78d6">apartment uplink · switch P1 · trunk · eno1</text>
<!-- ═════════ FLOWS ═════════ -->
<!-- Frigate -> camera RTSP (allowed): sweeps under the rack, terminates at the camera box -->
<!-- FLOWS -->
<path d="M1256,497 C1010,690 330,730 120,650 C40,618 40,380 96,286" fill="none" stroke="#008300" stroke-width="3" marker-end="url(#arrGreen)"/>
<text x="620" y="700" font-size="13.5" font-weight="700" fill="#008300">ALLOW · Frigate → camera RTSP :554 (routed k8s → dCCTV; opt1 allow-all)</text>
<!-- HA -> camera (allowed, via AX6000 route + WAN rules): labels above, arc dips below them -->
<path d="M1164,262 C820,282 470,268 302,176 C286,167 278,166 270,172" fill="none" stroke="#008300" stroke-width="3" marker-end="url(#arrGreen)"/>
<text x="484" y="216" font-size="13.5" font-weight="700" fill="#008300">ALLOW · ha-sofia → camera :80 ISAPI + :554</text>
<text x="484" y="234" font-size="12" fill="#52514e">enters pfSense WAN · reply-to off · needs the AX6000 route</text>
<!-- camera -> NTP (allowed) -->
<path d="M280,232 C660,200 860,320 936,386" fill="none" stroke="#008300" stroke-width="2" opacity="0.85" marker-end="url(#arrGreen)"/>
<text x="740" y="322" font-size="12.5" font-weight="700" fill="#008300">ALLOW · camera → 10.0.30.1:123 (NTP)</text>
<!-- ═════════ LEGEND ═════════ -->
<!-- LEGEND -->
<g transform="translate(40,800)" font-size="12.5">
<rect x="0" y="0" width="18" height="18" rx="4" fill="#2a78d6" fill-opacity="0.12" stroke="#2a78d6"/>
<text x="26" y="14" fill="#0b0b0b">home LAN 192.168.1.0/24</text>
<rect x="230" y="0" width="18" height="18" rx="4" fill="#4a3aa7" fill-opacity="0.12" stroke="#4a3aa7" stroke-width="2"/>
<text x="256" y="14" fill="#0b0b0b">CCTV island / dCCTV 10.0.30.0/24</text>
<rect x="510" y="0" width="18" height="18" rx="4" fill="#1baf7a" fill-opacity="0.12" stroke="#1baf7a"/>
<text x="536" y="14" fill="#0b0b0b">dKubernetes</text>
<rect x="650" y="0" width="18" height="18" rx="4" fill="#eda100" fill-opacity="0.14" stroke="#eda100"/>
<text x="676" y="14" fill="#0b0b0b">dManagementsVms</text>
<line x1="830" y1="9" x2="870" y2="9" stroke="#008300" stroke-width="3" marker-end="url(#arrGreen)"/>
<text x="880" y="14" fill="#0b0b0b">allowed flow</text>
<line x1="990" y1="9" x2="1030" y2="9" stroke="#e34948" stroke-width="3" marker-end="url(#arrRed)"/>
<text x="1040" y="14" fill="#0b0b0b">denied</text>
<line x1="1110" y1="9" x2="1150" y2="9" stroke="#52514e" stroke-width="2" stroke-dasharray="6,5"/>
<text x="1160" y="14" fill="#0b0b0b">camera-day step</text>
<text x="1330" y="14" fill="#52514e">ADR-0017 · rev 2</text>
<text x="26" y="14" fill="#0b0b0b">home LAN / VLAN 1</text>
<rect x="200" y="0" width="18" height="18" rx="4" fill="#4a3aa7" fill-opacity="0.12" stroke="#4a3aa7" stroke-width="2"/>
<text x="226" y="14" fill="#0b0b0b">CCTV / VLAN 30 / dCCTV 10.0.30.0/24</text>
<rect x="500" y="0" width="18" height="18" rx="4" fill="#1baf7a" fill-opacity="0.12" stroke="#1baf7a"/>
<text x="526" y="14" fill="#0b0b0b">dKubernetes</text>
<rect x="640" y="0" width="18" height="18" rx="4" fill="#eda100" fill-opacity="0.14" stroke="#eda100"/>
<text x="666" y="14" fill="#0b0b0b">dManagementsVms</text>
<line x1="820" y1="9" x2="860" y2="9" stroke="#008300" stroke-width="3" marker-end="url(#arrGreen)"/>
<text x="870" y="14" fill="#0b0b0b">allowed flow</text>
<line x1="980" y1="9" x2="1020" y2="9" stroke="#e34948" stroke-width="3" marker-end="url(#arrRed)"/>
<text x="1030" y="14" fill="#0b0b0b">denied</text>
<line x1="1100" y1="9" x2="1140" y2="9" stroke="#52514e" stroke-width="2" stroke-dasharray="6,5"/>
<text x="1150" y="14" fill="#0b0b0b">camera-day step</text>
<text x="1320" y="14" fill="#52514e">ADR-0017 · rev 3</text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Before After
Before After