{ "schema_version": 1, "diagram_type": "architecture", "meta": { "title": "Internet Use Control", "output": "architecture-map.html", "quality_profile": "showcase", "views": [ { "id": "control-path", "label": "Control path", "focus": [ "sam", "caddy", "control", "broker", "phone" ], "note": "A change in the dashboard reaches the phone through retained MQTT config." }, { "id": "admin-and-hub", "label": "Admin app and Hub", "focus": [ "adminapp", "hub", "control" ], "note": "Both call the Control Service over HTTP with a bearer token." }, { "id": "two-planes", "label": "Two MQTT planes", "focus": [ "broker", "legacy", "control", "phone" ], "note": "8883 is TLS with ACLs. 1883 stays plain for legacy consumers." } ] }, "components": [ { "id": "sam", "type": "external", "label": "Sam", "sublabel": "browser dashboard", "pos": [ 40, 300 ], "size": [ 120, 60 ] }, { "id": "caddy", "type": "security", "label": "Caddy (.35)", "sublabel": "TLS + vhost", "pos": [ 240, 300 ], "size": [ 130, 60 ], "tag": "webrestrict.lab" }, { "id": "control", "type": "backend", "label": "Control Service", "sublabel": "Go + SQLite :8791", "pos": [ 450, 300 ], "size": [ 140, 60 ], "tag": "source of truth" }, { "id": "broker", "type": "messagebus", "label": "Mosquitto (.13)", "sublabel": "8883 TLS + topic ACLs", "pos": [ 670, 300 ], "size": [ 150, 60 ], "tag": "two planes" }, { "id": "phone", "type": "frontend", "label": "Kids' Android client", "sublabel": "Kotlin, Accessibility + overlay", "pos": [ 900, 300 ], "size": [ 150, 60 ] }, { "id": "adminapp", "type": "external", "label": "Admin app", "sublabel": "kotlin_phone_app_admin", "pos": [ 450, 130 ], "size": [ 140, 60 ] }, { "id": "hub", "type": "external", "label": "Hub", "sublabel": "read-only /ask :8788", "pos": [ 450, 470 ], "size": [ 140, 60 ] }, { "id": "apprise", "type": "cloud", "label": "Apprise (.35)", "sublabel": "alerts :8210", "pos": [ 670, 480 ], "size": [ 140, 60 ] }, { "id": "legacy", "type": "external", "label": "Legacy consumers", "sublabel": "1883 plain + anonymous", "pos": [ 900, 480 ], "size": [ 150, 60 ] } ], "boundaries": [ { "kind": "region", "label": "Home lab - Docker on .13, Caddy and Apprise on .35", "wraps": [ "caddy", "control", "broker", "apprise" ] } ], "connections": [ { "id": "sam-to-caddy", "from": "sam", "to": "caddy", "label": "HTTPS", "variant": "emphasis" }, { "id": "caddy-to-control", "from": "caddy", "to": "control" }, { "id": "admin-to-control", "from": "adminapp", "to": "control", "label": "Bearer token /api/v1", "variant": "dashed", "labelDy": 24 }, { "id": "hub-to-control", "from": "hub", "to": "control", "label": "Bearer token /ask", "variant": "dashed" }, { "id": "control-to-broker", "from": "control", "to": "broker", "label": "retained config" }, { "id": "broker-to-phone", "from": "broker", "to": "phone", "label": "own config topic", "labelDy": -22 }, { "id": "phone-to-broker", "from": "phone", "to": "broker", "label": "status + telemetry", "variant": "dashed", "fromSide": "top", "toSide": "top", "via": [ [ 975, 240 ], [ 745, 240 ] ] }, { "id": "control-to-apprise", "from": "control", "to": "apprise", "label": "alerts + tamper" }, { "id": "broker-to-legacy", "from": "broker", "to": "legacy", "label": "1883 plain", "variant": "dashed" } ], "cards": [ { "dot": "cyan", "title": "Control Service", "items": [ "Go and SQLite are the single source of truth", "Publishes each device config retained", "Serves dashboard, admin API and Hub API" ] }, { "dot": "amber", "title": "MQTT two planes", "items": [ "8883 is TLS with per-device credentials and ACLs", "A device reads only its own config topic", "1883 stays plain and anonymous for legacy use" ] }, { "dot": "rose", "title": "Enforcement and gap", "items": [ "Accessibility overlay blocks by interruption", "Tamper alert is the real enforcement, not Device Owner", "Phase 4 Windows client is deferred and not built" ] } ] }