From 9dee4dc7de5c5e0d72e310d3419dfb5900051cf7 Mon Sep 17 00:00:00 2001 From: Sam Rolfe Date: Wed, 14 Oct 2026 12:21:28 +1100 Subject: [PATCH] sam-4screen-desktop 2026-10-14:12:21:28 --- .obsidian/workspace.json | 4 +- ... Use Control — Kids' Screen Time Limits.md | 151 ++++++++++++++++++ 010 inbox/_sort log.md | 3 + 3 files changed, 156 insertions(+), 2 deletions(-) create mode 100644 010 inbox/Internet Use Control — Kids' Screen Time Limits.md diff --git a/.obsidian/workspace.json b/.obsidian/workspace.json index 4217c33..3563f0e 100644 --- a/.obsidian/workspace.json +++ b/.obsidian/workspace.json @@ -210,8 +210,9 @@ "templater-obsidian:Templater": false } }, - "active": "7066c9273c6fb936", + "active": "26813e16e829b798", "lastOpenFiles": [ + "010 inbox/Internet Use Control — Kids' Screen Time Limits.md", "010 inbox/Email Agent — Family Inbox Triage.md", "100 inbox/Local LLM Infrastructure & Qwen2.5 Deployment.md", "010 inbox/Email & DNS Setup — Domains, Mailboxes & Records.md", @@ -239,7 +240,6 @@ "010 inbox/Alibaba Code Review AI Tool.md", "300 areas/395 AI Tools to try/Alibaba Code Review AI Tool.md", "Clippings/alibabaopen-code-review Secure, fast, efficient, battle-tested at Alibaba's scale. Hybrid architecture code review tool deterministic pipelines + LLM Agent, precise line-level comments, built-in multi-language ruleset (NPE, thread-safety, XSS, S.md", - "300 areas/395 AI Tools to try/Tools to try with AI.md", "010 inbox/_WATCHER", "300 areas/355 AI Research and Techniques", "300 areas/355 Ai Research and Techniques", diff --git a/010 inbox/Internet Use Control — Kids' Screen Time Limits.md b/010 inbox/Internet Use Control — Kids' Screen Time Limits.md new file mode 100644 index 0000000..a62c069 --- /dev/null +++ b/010 inbox/Internet Use Control — Kids' Screen Time Limits.md @@ -0,0 +1,151 @@ +--- +type: note +proposed_folder: 200 projects/Tools Software WebUI +proposed_toc: "100 Table of Contents/Projects.md → Tools & Software" +proposed_tags: + - project + - family + - architecture + - go + - kids + - time + - internet-control + - mqtt + - android + - sqlite + - htmx +confidence: 0.8 +approved: false +proposed_for: ca730e053cc5 +created: "2026-10-14 12:12" +tags: + - project + - family + - internet-control + - go + - mqtt + - android + - sqlite + - htmx +aliases: + - Internet Use Control + - Kids Screen Time +skills: + - Go backend development + - HTMX server-rendered dashboard UI + - SQLite data modelling and versioned migrations + - MQTT transport with TLS and per-device topic ACLs + - Android Accessibility Service and full-screen overlay (Kotlin) + - Android VpnService for device-local site filtering + - Versioned HTTP API design for a separate consumer + - Docker and Caddy deployment +tools: + - Go + - SQLite + - HTMX + - Mosquitto + - Docker + - Caddy + - Apprise + - Kotlin + - Android Accessibility Service + - Android VpnService +--- + +# [[Internet Use Control — Kids' Screen Time Limits]] + +## What is this project? + +This project limits screen time on the children's own devices. Harry's phone and +Finn's computer should follow their weekly schedule with nobody touching them. Sam +sees their usage on one page, and Sam changes a limit from his phone in seconds. + +The rules apply to the kids' devices only. Nothing changes for the rest of the +house. There is no router change, no Pi-hole and no DNS change. + +The main piece is the **Control Service**. It runs on `.13` in Docker. It holds the +schedules, the block lists, the allow lists and the usage in SQLite. It serves a +small web dashboard. It is the one place that writes the rules. + +A device gets its rules over **MQTT**. The Control Service publishes the wanted +state for each device as a *retained* message, so a phone that reconnects is +limited again at once. The device also sends its status and its usage back over +MQTT. If a device cannot reach the broker, it keeps its last rules. + +## What it does + +- **Weekly schedules.** A grid per device, Monday to Sunday. A window means the + rules are on. A window can cross midnight. +- **Block lists.** An app (Android package name) or a site (hostname). +- **Allow lists.** Spotify at night, school sites. The device blocks everything + on the block list **except** the allow list. +- **Usage.** The dashboard shows a week per device: the daily total, the top apps + and the top sites. +- **Overrides.** A versioned HTTP API for the admin app (`lock`, `unlock`, + `grant`), plus one shared keycode that a child can type on the device for a + short exemption. +- **Alerts.** Apprise tells Sam when a limit is reached or a device is offline + too long. +- **A Hub answer.** The family Hub can ask "how long have the kids been on + screens today?" and gets a real answer. That question path is read-only. + +## Why it matters (what it shows) + +This is a full home-lab product, not a script. It shows a Go service with no +heavy framework, an HTMX dashboard with no build step, a small SQLite store with +versioned migrations, real MQTT with TLS, per-device accounts and topic access +control, and a versioned API that another project consumes. + +The Android side is the interesting part. **Device Owner was rejected**, because +it needs a factory reset of the children's phones. Instead the phone blocks by +**interruption**: an Accessibility Service watches the foreground app, and a +full-screen overlay covers a blocked app. The child **can** disable it, and that +is accepted. The real enforcement is the **tamper alert**: when the Accessibility +Service stops, the app is force-stopped, or the overlay permission is removed, +the phone reports it and Sam gets an alert. Site filtering uses a device-local +`VpnService`. There is no wipe, no Device Owner and no managed profile. + +## Architecture + +```mermaid +flowchart LR + SAM["Sam
browser dashboard"] --> CADDY["Caddy on .35"] + CADDY --> CS["Control Service
Go + SQLite :8791"] + ADMIN["Admin app"] -->|"/api/v1"| CS + HUB["Hub"] -->|"read-only /ask"| CS + CS -->|"retained config"| MQ["Mosquitto on .13
8883 TLS + topic ACLs"] + MQ -->|"own config topic"| PHONE["Kids' Android client
Kotlin"] + PHONE -->|"status + telemetry"| MQ + MQ -->|reports| CS + CS --> APPRISE["Apprise
alerts + tamper"] +``` + +A picture of the two MQTT planes: port **1883** stays plain and anonymous for +legacy consumers, and port **8883** is TLS with per-device credentials and topic +ACLs. A device on 8883 may read only its own config topic and write only its own +status and telemetry topics. Without that rule a child could publish a fake +"unlocked". + +## What is still missing (state it plainly) + +**The Phase 4 Windows computer client is deliberately deferred and is not +built.** There is no Python client and no process blocking on a computer. The +project stands at **9 of 10** phases for that single reason. Everything else in +the build spec is done and running. + +## Where it lives + +- **Code**: Gitea repo `sam/internet_use_control`. +- **Live**: (container on `.13`, port + 8791, behind Caddy on `.35`). +- **Interactive map**: +- **AI context**: `docs/outline/` in the repo (00-index and four documents). +- **Tasks**: Vikunja project **Internet Use Control** (id 20). +- **Diagram source**: `docs/architecture.mmd`, rendered to + `docs/diagrams/architecture.png`. + +## Status + +Built and deployed. Phases 1, 2, 3, 5, 6, 7, 8, 9 and 10 are done. The phones +are limited by the Android client. Only the Windows client (Phase 4) remains, and +it is deferred on purpose. diff --git a/010 inbox/_sort log.md b/010 inbox/_sort log.md index 6fa5eb9..7414eeb 100644 --- a/010 inbox/_sort log.md +++ b/010 inbox/_sort log.md @@ -20062,3 +20062,6 @@ What the watcher did, newest last. ### 2026-10-13 10:44:03 - **proposed** `Email Agent — Family Inbox Triage.md` → `200 projects/Tools Software WebUI` (confidence 0.82) + +### 2026-10-14 12:12:45 +- **proposed** `Internet Use Control — Kids' Screen Time Limits.md` → `200 projects/Tools Software WebUI` (confidence 0.80)