Files
internet_use_control/SYSTEM_MAP.md

145 lines
4.8 KiB
Markdown

# Internet Use Control — system map
**Date:** 2026-10-10
**Purpose:** name every piece once, clearly. No more "Go service" or "admin app"
guessing.
---
## The pieces
| Name | What it is | Where it runs | Language |
|---|---|---|---|
| **Control Service** | The brain **and** the source of truth. Holds schedules, blocklists, per-device state, usage. Serves the web dashboard. | `.13`, Docker | Go + SQLite |
| **Web Dashboard** | Your setup screen in a browser. Schedules, blocklists, devices, usage. **This is the desktop admin.** | Served by the Control Service | HTMX |
| **Broker** | The message bus. Pushes state to devices. Collects their reports. | `.13`, Mosquitto (already running) | — |
| **Kids' phone app** | Enforces limits on a kid's phone. Shows what is blocked, and for how long. | Kids' phones | Kotlin |
| **Kids' computer client** | Same job on a kid's laptop or desktop. | Kids' computers | Python |
| **Admin app** | Your override and approval surface. | **Your phone** | Kotlin |
| **Hub** | A **peer**. Asks questions only. Never controls. | `.13` | separate project |
**There is no separate desktop admin app.** The dashboard in a browser *is* the
desktop admin. If you want a native desktop app later, that is a new decision.
---
## Where the truth lives
**SQLite inside the Control Service, on `.13`.** Not MQTT, not the devices, not the
Hub.
The broker is only a **delivery pipe**. It is fast and it remembers the last
message, but it is not the database.
---
## Who writes what
| Action | First goes to | Then |
|---|---|---|
| Change a schedule | Control Service (HTTP) | saved in SQLite → published to MQTT |
| Lock or unlock now | Control Service (HTTP) | same |
| You enter the device keycode | Control Service (HTTP) | same |
| Device reports usage | Broker (MQTT) | Control Service writes it to SQLite |
| Hub asks "screen time today?" | Control Service (HTTP) | reads SQLite, answers |
**Only the Control Service publishes config to devices.** Everything else writes
to the Control Service over HTTP.
That is the answer to "who publishes config": **the Control Service, and only the
Control Service.** One writer. One truth.
**"Config"** means the desired state for **one device**: locked or not, until
when, the allowed list, the blocked list.
---
## Data flow
```mermaid
flowchart LR
WD["Web Dashboard<br/>(browser)"]
AA["Admin app<br/>(your phone)"]
HUB["Hub<br/>(peer)"]
CS["Control Service<br/>Go + SQLite<br/>on .13"]
MQ["Broker<br/>Mosquitto on .13"]
KP["Kids' phone app<br/>(Kotlin)"]
KC["Kids' computer client<br/>(Python)"]
WD -->|HTTP| CS
AA -->|HTTP| CS
HUB -->|HTTP /ask| CS
CS -->|publish state| MQ
MQ -->|deliver state| KP
MQ -->|deliver state| KC
KP -->|status + usage| MQ
KC -->|status + usage| MQ
MQ -->|reports| CS
```
---
## Config carries per device
Each device has its own state. That is how "Harry's phone off, desktop on" works:
```
restrict/harry_phone/config {"locked": true, "until": "21:00", "allow": ["spotify"]}
restrict/harry_desktop/config {"locked": false}
```
The Control Service publishes each message, **retained**, so a device that
reconnects gets its current state at once.
---
## Fail state, and where the device is
The device must decide what to do when it **cannot reach the broker**. It also
needs to know whether it is **at home or away**, because the two cases differ.
| Situation | How the device knows | Behaviour |
|---|---|---|
| **At home, broker down** | On the home Wi-Fi, broker unreachable | **Keep last state** |
| **Away from home** | Not on the home Wi-Fi | **Keep last state** |
| **Long outage** | No contact for N hours | **Keep last state** |
**One rule: keep last state.** An outage changes nothing. The child cannot escape
by going offline, and a server restart does not lock them out.
The device **caches its last config on itself**, so the rule always has something
to follow.
### Overrides (two)
1. **On the device** — **one admin keycode, shared by every device**. For a broken
phone, a laptop, or when you are away. Stored hashed. Changeable in the
Control Service.
2. **Admin app** — remote lock, unlock, or grant time.
### Honest limit
A child can turn off Wi-Fi and use mobile data to look "away". Accepted. The goal
is **reasonable friction**, not a fortress.
---
## Kids' app interface
A simple screen on the kid's device:
- **What is blocked** right now.
- **How long** until it lifts.
- **Why** (schedule, limit reached).
- An **alert** when a block starts.
---
## Decisions (2026-10-10)
1. **No mobile profile.** Away from home behaves the same as at home: keep last state.
2. **One admin keycode**, shared by every device.
3. **Keep last state indefinitely.** The admin keycode overrides it.
These are settled. Do not re-open them unless something changes.