feat: self-host Hobbs Family Organizer (Shield TV dashboard) on hf-pdocker-02:8340

- tv app/Hobbs-Family-Organizer-Self-Hosted-v1.0.0: release bundle (Next.js app + Shield APK v1.4 + source)
- compose/hf-pdocker-02/hobbs-organizer: override (local-disk secrets, watchtower off), .env (port 8340), Shield provisioning script
- CLAUDE.md: service tree + internal ports
Trusted-LAN mode. Secrets live only on .100 /var/lib/hobbs-organizer/secrets (not in git).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E9NnVEico3WvFxLyjy1iW3
This commit is contained in:
2026-11-04 18:27:22 -06:00
parent 122ea392d1
commit e9c7e9df1a
68 changed files with 12831 additions and 0 deletions
@@ -0,0 +1,21 @@
# Hobbs' Family Organizer - nonsecret runtime settings
# Copy this file to .env. Keep private calendar URLs and the access token in
# ./secrets; never put either value in this file.
# Docker publishes the app on this server address and port. Set the bind
# address to a specific LAN interface if you do not want to listen everywhere.
HOBBS_BIND_ADDRESS=0.0.0.0
HOBBS_HTTP_PORT=8340
# Display and calendar defaults.
ORGANIZER_TIMEZONE=America/Chicago
# Seven-day forecast defaults for Sapulpa, Oklahoma.
WEATHER_LOCATION="Sapulpa, OK"
WEATHER_LATITUDE=35.9987
WEATHER_LONGITUDE=-96.11417
NWS_FORECAST_URL=https://api.weather.gov/gridpoints/TSA/37,98/forecast
# The National Weather Service asks clients to identify themselves. Replace
# the example contact with an address monitored by the server operator.
WEATHER_USER_AGENT="Hobbs-Family-Organizer/1.0 (self-hosted)"
@@ -0,0 +1,15 @@
# Hobbs Family Organizer (Shield TV dashboard) — hf-pdocker-02
Deployed 2026-11-04. URL: http://192.168.86.100:8340/ (LAN only, trusted-LAN mode = no token).
- App source / release bundle: `tv app/Hobbs-Family-Organizer-Self-Hosted-v1.0.0/` (repo root).
- Deploy dir on NAS: `/mnt/docker-data/compose/hf-pdocker-02/hobbs-organizer/` = the release bundle
+ `compose.override.yaml` + `.env` from this folder. Image is built locally (`hobbs-family-organizer:1.0.0`).
- Secrets on LOCAL disk of .100 (root:root 600): `/var/lib/hobbs-organizer/secrets/`
- `calendar_ical_urls.json` — JSON array of private Google Calendar basic.ics URLs (treat as passwords; never commit)
- `organizer_access_token.txt` — empty = trusted-LAN mode. Put a 32+ char token here for bearer mode.
- Redeploy: `cd /mnt/docker-data/compose/hf-pdocker-02/hobbs-organizer && docker compose up -d --build --wait`
- Health: `curl http://192.168.86.100:8340/api/health`
- Shields (package `com.dayline.tv`, APK v1.4) read `files/base_url` + `files/allow_insecure_http`
provisioned over ADB `run-as`. adb client lives on .100 (`apt install adb`).
- Shield provisioning (bash port of configure-shield.ps1, run on .100): `provision-shield.sh <ip> <base_url>`
@@ -0,0 +1,12 @@
# Homelab overrides (hf-pdocker-02). Secrets live on LOCAL disk, not NFS:
# start.mjs reads them as root, and NFS root_squash would deny that.
# Mode: trusted-LAN (empty token file) per user 2026-11-04.
services:
organizer:
labels:
com.centurylinklabs.watchtower.enable: "false"
secrets:
calendar_ical_urls:
file: /var/lib/hobbs-organizer/secrets/calendar_ical_urls.json
organizer_access_token:
file: /var/lib/hobbs-organizer/secrets/organizer_access_token.txt
@@ -0,0 +1,17 @@
#!/usr/bin/env bash
# Usage: provision-shield.sh <ip> <base_url> (bash port of configure-shield.ps1, trusted-LAN http)
set -euo pipefail
D="$1:5555"; URL="$2"; PKG=com.dayline.tv; APK=/home/glyptic/hobbs-shield/Hobbs-Family-Organizer-Local-v1.4.apk
adb connect "$D" >/dev/null; [ "$(adb -s "$D" get-state)" = device ]
echo "before: $(adb -s "$D" shell dumpsys package $PKG | grep -m1 versionName)"
adb -s "$D" shell run-as $PKG ls files
adb -s "$D" install -r "$APK"
echo "after: $(adb -s "$D" shell dumpsys package $PKG | grep -m1 versionName)"
put() { printf '%s' "$2" | adb -s "$D" shell "run-as $PKG sh -c 'umask 077; cat > files/.$1.new && chmod 600 files/.$1.new && mv files/.$1.new files/$1'"; }
put base_url "$URL"
adb -s "$D" shell "run-as $PKG rm -f files/access_token"
put allow_insecure_http enabled
adb -s "$D" shell run-as $PKG ls -l files
FG=$(adb -s "$D" shell dumpsys activity activities | grep -m1 mResumedActivity); echo "foreground: $FG"; echo "$FG" | grep -q -E "com.dayline.tv|launcher|tvlauncher|projengmenu" || { echo SKIP-LAUNCH: TV in use; exit 0; }
adb -s "$D" shell am force-stop $PKG
adb -s "$D" shell am start -W -n $PKG/.MainActivity | grep -E 'Status|Activity'