- 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
Hobbs' Family Organizer App — self-hosted package
This release moves the organizer off ChatGPT Sites and onto your own container host. The dashboard, API routes, calendar parser, weather, FRED market ticker, RSS headlines, QR handoff, and Shield wrapper are included.
The local deployment does not require ChatGPT, an OpenAI account, or an OpenAI API key. It is stateless and has no database or persistent application volume.
What still uses the Internet
The container needs outbound DNS and HTTPS for:
calendar.google.com— private Google Calendar ICS feedsapi.weather.gov— seven-day National Weather Service forecastfred.stlouisfed.org— public FRED series pages used by the ticker- the configured OpenAI, Google AI, DeepMind, NVIDIA, Ars Technica, and Wired RSS feeds
No inbound Internet access is required. Keep the service on your LAN, VPN, or behind your existing reverse proxy.
Package contents
Dockerfile— production Node 22 imagecompose.yaml— hardened Compose deployment on port 8080 by defaultapp/— complete Next.js dashboard and API sourcecontainer/start.mjs— validates secrets, then drops the app to uid/gid 10001scripts/configure.*— creates runtime secrets without printing themscripts/backup.*andscripts/restore.*— configuration backup and restoresecrets/— ignored runtime secret location and a calendar templateshield/— signed v1.4 APK, provisioning scripts, and Android sourceMIGRATION.md— ordered cutover and rollback procedure
Requirements
- A Linux, Windows, or macOS host with Docker Engine/Desktop and Docker Compose v2
- Outbound HTTPS from the container host
- One to ten private Google Calendar
basic.icsURLs - For Shield deployment: Android Platform Tools (
adb) and network debugging enabled on the Shield
The image builds for both linux/amd64 and linux/arm64 when the selected Node base image supports the host architecture.
Quick start
Linux or macOS
chmod +x scripts/*.sh
./scripts/configure.sh --mode trusted-lan
docker compose config --quiet
docker compose up -d --build --wait
curl -fsS http://127.0.0.1:8080/api/health
Windows PowerShell
Set-ExecutionPolicy -Scope Process Bypass
.\scripts\configure.ps1 -Mode trusted-lan
docker compose config --quiet
docker compose up -d --build --wait
Invoke-RestMethod http://127.0.0.1:8080/api/health
The configuration script:
- copies
.env.exampleto.envif needed; - prompts privately for each Google Calendar ICS URL;
- writes
secrets/calendar_ical_urls.jsonwith restrictive permissions; - creates
secrets/organizer_access_token.txt, empty for trusted-LAN mode or populated with a random token for bearer mode.
After startup, open http://SERVER-IP:8080/ or the HTTPS name provided by your reverse proxy.
Access modes
Trusted LAN
Use this when firewall/VLAN/VPN rules already restrict the dashboard:
./scripts/configure.sh --mode trusted-lan
.\scripts\configure.ps1 -Mode trusted-lan
The token file exists but is empty. Anyone who can reach the published port can view calendar details, so bind to the intended interface and enforce access in your network or reverse proxy.
Bearer token
Use this for the Shield or a reverse proxy that can inject an authorization header:
./scripts/configure.sh --mode bearer --rotate-token
.\scripts\configure.ps1 -Mode bearer -RotateToken
Every route except /api/health then requires:
Authorization: Bearer TOKEN
The Shield wrapper injects this header into every same-origin request. An ordinary browser address bar cannot add it, so browser access in bearer mode should go through an authenticated reverse proxy that injects the header. The configuration scripts intentionally do not print the token.
Configuration
Edit .env for nonsecret settings:
| Setting | Default | Purpose |
|---|---|---|
HOBBS_BIND_ADDRESS |
0.0.0.0 |
Host interface used by Docker |
HOBBS_HTTP_PORT |
8080 |
Published HTTP port |
ORGANIZER_TIMEZONE |
America/Chicago |
Clock and calendar timezone |
WEATHER_LOCATION |
Sapulpa, OK |
Display label |
WEATHER_LATITUDE |
35.9987 |
Sunrise/sunset latitude |
WEATHER_LONGITUDE |
-96.11417 |
Sunrise/sunset longitude |
NWS_FORECAST_URL |
https://api.weather.gov/gridpoints/TSA/37,98/forecast |
NWS grid forecast |
WEATHER_USER_AGENT |
example value | NWS client identifier; add a monitored contact |
Keep these secrets out of .env, Git, image layers, and tickets:
secrets/calendar_ical_urls.jsonsecrets/organizer_access_token.txt
Private Google Calendar URLs act like passwords. Because the current URLs were previously shared during development, reset/regenerate each private ICS URL in Google Calendar before the final production cutover, then run the configure script again.
Operations
Status and logs:
docker compose ps
docker compose logs --tail=200 organizer
curl -fsS http://127.0.0.1:8080/api/health
The health endpoint never calls Google, FRED, NWS, or RSS providers. It reports liveness plus booleans for calendar configuration and authentication, but no secret values.
Stop and start:
docker compose stop
docker compose start
Update after replacing the release files:
docker compose build --pull
docker compose up -d --wait
docker image prune
docker image prune is optional and removes only unused images after confirmation.
Backup and restore
The app has no database. Back up only .env and the two runtime secret files.
Linux/macOS:
./scripts/backup.sh
./scripts/restore.sh --force backups/hobbs-organizer-config-YYYYMMDD-HHMMSS.tar.gz
Windows:
.\scripts\backup.ps1
.\scripts\restore.ps1 -Archive .\backups\hobbs-organizer-config-YYYYMMDD-HHMMSS-XXXXXXXX.zip -Force
Backup archives contain private calendar URLs and possibly the bearer token. Store them in an encrypted or tightly access-controlled backup system.
Reverse proxy and HTTPS
HTTPS with a stable internal DNS name is recommended, for example organizer.home.arpa. Sample Caddy and Nginx configurations are in examples/.
If you use an internal certificate authority, install its root certificate in the Shield's user certificate store. The wrapper trusts system and user-installed CAs but always rejects certificate errors; it has no trust-all bypass.
For direct LAN HTTP, the Shield configuration script requires both an explicit -AllowInsecureHttp switch and a private IP, .local, .lan, or .home.arpa host.
NVIDIA Shield deployment
Install Android Platform Tools, enable network debugging, and authorize the computer on the Shield. Upgrading the existing package preserves the hosted rollback token and the per-device 6:30 AM schedule flag.
$adb = "C:\path\to\platform-tools\adb.exe"
& $adb connect 192.168.86.179:5555
& $adb -s 192.168.86.179:5555 install -r .\shield\Hobbs-Family-Organizer-Local-v1.4.apk
For HTTPS with bearer authentication:
.\shield\configure-shield.ps1 `
-Device 192.168.86.179:5555 `
-BaseUrl https://organizer.home.arpa/ `
-TokenFile .\secrets\organizer_access_token.txt `
-AdbPath $adb
For trusted-LAN HTTP:
.\shield\configure-shield.ps1 `
-Device 192.168.86.179:5555 `
-BaseUrl http://192.168.86.50:8080/ `
-AllowInsecureHttp `
-AdbPath $adb
The script streams the token through ADB standard input and never places it in the process arguments. Repeat for the second Shield using its address. Do not change the package ID: com.dayline.tv is intentionally preserved so existing app-private data survives adb install -r.
The wrapper is debuggable so the scripts can use Android run-as to provision private files. After the migration, disable network debugging on each Shield and enable it again only during controlled maintenance.
To return a Shield to the existing hosted Site:
.\shield\restore-hosted-site.ps1 -Device 192.168.86.179:5555 -AdbPath $adb
That removes only the local URL/token flags and keeps the old hosted service_token intact.
Build from source
Container application:
npm ci
npm run lint
npm run build
npm start
For local npm start, set CALENDAR_ICAL_URLS to a JSON array and optionally set ORGANIZER_ACCESS_TOKEN. The Compose path is preferred because it loads secrets from files and applies the security profile.
Android source is under shield/source/. It targets Android SDK 35, Java 17, and Gradle 8.9/Android Gradle Plugin 8.7.3. The included APK is already signed with the same certificate as the installed v1.3 app. The private signing key is deliberately not included in this package.
Troubleshooting
calendarConfigurationValid: false: rerunscripts/configure.*and confirm the secret contains a JSON array of Googlebasic.icsURLs.- Dashboard returns
401: token mode is enabled; provision the same token to the Shield or reverse proxy. - Weather is empty: verify the NWS grid URL, outbound HTTPS, DNS, and
WEATHER_USER_AGENT. - FRED shows demo data: allow outbound HTTPS to
fred.stlouisfed.org; the feed uses public pages and no API key. - Shield shows setup required: confirm the APK is installed and rerun
shield/configure-shield.ps1. - Shield rejects HTTPS: install the internal CA certificate or use a certificate trusted by Android; never bypass validation.
- Container does not become healthy: run
docker compose logs organizerand validate that both secret files exist.