# Internet Use Control — Control Service The **Control Service** is the brain and the single source of truth for the Internet Use Control project (`SYSTEM_MAP.md`). It holds schedules, blocklists, per-device state and usage, and serves the web dashboard. Only it publishes device config. This repository currently contains **Phase 1 — Skeleton** (AGENTS.md §11): - Go service with its own image (`Dockerfile`) and compose file. - SQLite schema for the whole data model (§7), applied through versioned migrations. - Configuration from the process environment (`environment.d`); no secrets in the repo. - A separate session login for Sam. - `GET /health`. - HTMX + server-rendered dashboard styled with the Family Home Lab design system (`tokens.css` copied in). Enforcement, MQTT, devices, schedules and the clients arrive in later phases. Nothing here touches the router, Pi-hole, or DNS. ## Quick start (on `.13`) ```bash cd /home/sam/paseo/projects/internet_use_control # 1. Create the env file from the template and set real values. cp environment.d/control-service.env.example environment.d/control-service.env $EDITOR environment.d/control-service.env # 2. Build and start. Own image, own container, port 8791. docker compose up -d --build # 3. Prove it. curl -s http://127.0.0.1:8791/health # {"status":"ok","service":"control-service","version":"0.1.0-phase1",...} ``` Open in a browser. It redirects to `/login`. Sign in with `CONTROL_ADMIN_USERNAME` and `CONTROL_ADMIN_PASSWORD`. ## Configuration All configuration is environment variables. Docker Compose loads them from `environment.d/control-service.env` (gitignored). The variables can also be exported from `~/.config/environment.d/10-secrets.conf` instead; the service reads only the process environment. | Variable | Default | Purpose | |---|---|---| | `CONTROL_ADDR` | `:8791` | Listen address | | `CONTROL_DB_PATH` | `/data/control.db` | SQLite file | | `CONTROL_SESSION_SECRET` | — (required) | Signs the session cookie, ≥ 16 chars | | `CONTROL_SESSION_TTL` | `12h` | Session lifetime | | `CONTROL_COOKIE_SECURE` | `true` | Secure cookie flag; keep true behind HTTPS | | `CONTROL_ADMIN_USERNAME` | `sam` | Dashboard login | | `CONTROL_ADMIN_PASSWORD` | — | Plaintext password (option A) | | `CONTROL_ADMIN_PASSWORD_HASH` | — | bcrypt hash (option B, preferred) | | `CONTROL_APP_ENV` | `production` | Label shown in the footer | | `CONTROL_LOG_LEVEL` | `info` | `debug`/`info`/`warn`/`error` | Generate a bcrypt hash without host Go: ```bash docker run --rm --entrypoint /app/control webrestrict/control:0.1.0-phase1 \ hash-password 'your-password' ``` ## Endpoints (Phase 1) | Method | Path | Notes | |---|---|---| | `GET` | `/health` | JSON. `status: ok`, database check. No auth. | | `GET` | `/login` | Session login form. | | `POST` | `/login` | Verifies credentials, sets a signed session cookie. | | `POST` | `/logout` | Clears the session. | | `GET` | `/` | Dashboard. Redirects to `/login` when not signed in. | | `GET` | `/partials/status` | HTMX fragment, polled every 10 s. | ## Development There is no host Go toolchain on `.13`; use the cached builder image. ```bash make test # go test ./... in golang:1.25-alpine make vet # go vet ./... make build # build the container image make up # docker compose up -d --build make logs # follow container logs ``` ## Layout ``` cmd/control/ service entry point (+ hash-password helper) internal/config/ environment configuration internal/store/ SQLite open, migrations, audit internal/store/migrations/001_init.sql internal/auth/ signed-cookie session login + CSRF internal/web/ HTTP handlers, templates, static assets templates/ login, dashboard, HTMX partials static/ tokens.css (Family Home Lab), app.css, htmx, Inter fonts Dockerfile own image (multi-stage, CGO-free) docker-compose.yml own container, port 8791 environment.d/ control-service.env.example (real file gitignored) deploy/caddy/ Caddy vhost for webrestrict.lab.audasmedia.com.au ``` ## Caddy `deploy/caddy/webrestrict.caddy` holds the vhost for `webrestrict.lab.audasmedia.com.au`. The terminating Caddy runs on `.35` (sam-Ubuntu1); see that file for the two proxy patterns and the apply commands. ## Non-goals (Phase 1) - No MQTT publishing (Phase 3). - No device registry or lock/unlock UI (Phase 2). - No admin API (Phase 8). - No Hub contact (Phase 9).