Skip to content

Add localhost web console to BlackbookServer (KPI dashboard + safe actions) - #41

Merged
mayeack merged 1 commit into
mainfrom
claude/server-web-console
May 30, 2026
Merged

mayeack merged 1 commit into
mainfrom
claude/server-web-console

Conversation

@mayeack

@mayeack mayeack commented May 30, 2026

Copy link
Copy Markdown
Owner

Why

BlackbookServer was headless — an HTTP API plus a tiny menu-bar popover. There was no way to see operational health at a glance: sync status per device, storage, request errors, record counts, or iMessage-sync stats. This adds a localhost-only web console.

What

  • Second NWListener bound to 127.0.0.1:8766 (requiredLocalEndpoint). The Cloudflare tunnel forwards only 8765, so the console is never internet-exposed and needs no password. Reuses the existing receiveRequest/sendResponse plumbing; cancelled in stop()/scheduleRestart(). A loopback remote-endpoint check adds defense-in-depth.
  • Routes (no header auth; loopback only): GET / → bundled console.html; GET /api/stats → KPI JSON; POST /api/imessage/backfill + /api/imessage/toggle → safe actions (202/200).
  • /api/stats aggregates four sections from existing data: sync health (latest heartbeat per device), backups & storage (count/bytes/per-user), requests (today's access-log status histogram + recent tail), data (per-model fetchCount for all 10 models + iMessage stats).
  • console.html — one self-contained dark dashboard (inline CSS+JS, no CDN), polls every 5 s, with Sync Last 30 Days and Toggle iMessage Logging buttons. Auto-bundled by the sources: - BlackbookServer glob.
  • Wiring: BackupServer.init gains an imessage: param; ServerStatusModel passes it in; ServerMenuView gets an Open Web Console button.

Security

  • Loopback bind + remote-endpoint check ⇒ unreachable from the LAN or the tunnel. Safe actions only — no delete-backup / restart / log-prune.

Test plan

  • BlackbookServer builds clean (Debug + Release); console.html bundled in Contents/Resources/.
  • GET / → 200 text/html (12049 B); GET /api/stats → full JSON (Contacts 1288, backups 5/3.8 MB, 2 sync devices, 148 reqs today). Verified with curl + strict Python HTTP client.
  • Not exposed: LAN-IP:8766 → connection refused; https://sync.libersecretorum.com/api/stats → 401 (hits the 8765 sync server; console route absent). Backfill endpoint → 202.
  • 13 Swift Testing tests pass.
  • Open via the menu Open Web Console on the server Mac and click through the safe actions.

Deploy note

BlackbookServer is not in TestFlight. After merge, rebuild/reinstall locally (commands in docs/test-scenarios/TEST_SCENARIOS.md). Main Blackbook app is untouched.

🤖 Generated with Claude Code

…tions)

BlackbookServer was headless (HTTP API + menu-bar popover); there was no
way to see operational health at a glance. Adds a web console.

- Second NWListener bound to 127.0.0.1:8766 (requiredLocalEndpoint). The
  Cloudflare tunnel maps only 8765, so the console is never internet-
  exposed and needs no password. Reuses the existing receiveRequest/
  sendResponse plumbing; cancelled on stop()/scheduleRestart(); a loopback
  remote-endpoint check adds defense-in-depth.
- Routes (no header auth): GET / -> bundled console.html; GET /api/stats
  -> KPI JSON; POST /api/imessage/{backfill,toggle} -> safe actions.
- /api/stats aggregates: sync health (latest heartbeat per device),
  backups (count/bytes/per-user), requests (access-log status histogram +
  recent tail), data (per-model fetchCount + iMessage stats).
- console.html: single self-contained dark dashboard, polls every 5s,
  Sync-Last-30-Days + toggle buttons. Auto-bundled via the source glob.
- ServerStatusModel passes the iMessage service into BackupServer;
  ServerMenuView gains an "Open Web Console" button.

Localhost-only by design; safe actions only (no delete/restart). Verified:
GET / 200, /api/stats full JSON; LAN:8766 refused; tunnel /api/stats 401.
BlackbookServer is local-deploy (not TestFlight); rebuild/reinstall per
docs/test-scenarios/TEST_SCENARIOS.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@mayeack
mayeack merged commit 7007def into main May 30, 2026
2 checks passed
@mayeack
mayeack deleted the claude/server-web-console branch May 30, 2026 03:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant