App Manager

← Dashboard

README.md · last modified 2026-05-10 16:43

SA App Manager

Web dashboard for managing all services on soundappraisal-dev-server (Mac Mini). Built with FastAPI and HTMX.

URL: https://soundappraisal-dev-server.tail184f99.ts.net/app-manager
Port: 5014
Launchd label: com.tjeerd.saappmanager

How it works

The app manager runs as a launchd daemon and provides a web UI to start, stop, restart, and monitor all services on the Mini. It reads the service registry from ~/SA_projects/report_pipeline_2026/apps/apps_registry.toml and uses launchctl to control services.

Stack

Service organization: Daemons vs Agents

All services on the Mini are managed through macOS launchd. They fall into two categories:

Daemons (type = "daemon")

Current daemons:

Service Label Port Funnel path
Node Inspector (DB) eu.soundappraisal.node-inspector 5011
Sound Annotator eu.soundappraisal.sa-annotator 5012 /sa-annotation
Template Management eu.soundappraisal.template-management 5013
Batch Downloader eu.soundappraisal.batch-downloader
Data Server com.sa.data-server 5016
Brabantzorg MoSART com.soundappraisal.brabantzorg 8002 /mosart_bz
Geluidmeetdag com.soundappraisal.geluidmeetdag 8003 /geluidmeetdag
App Manager com.tjeerd.saappmanager 5014 /app-manager
Mercouris HTTP Server dev.soundappraisal.mercouris-httpd 8073 /mercouris
Mercouris Downloader dev.soundappraisal.mercouris-audio
PostgreSQL (T9) dev.soundappraisal.postgresql-t9 5432

Agents (type = "agent")

Current agents:

Service Label Port
Ollama com.tjeerd.ollama 11434
Caddy (Ollama proxy) com.tjeerd.caddy-ollama
Open WebUI com.tjeerd.open-webui 3000

Launchd plist conventions

Each service has a plist with:
- RunAtLoad: true — starts automatically
- KeepAlive: true — restarts on crash
- UserName: tjeerd — (daemons only) runs as the tjeerd user
- StandardOutPath / StandardErrorPath — log locations

Daemon plists use sudo launchctl kickstart -k system/<label> to restart.
Agent plists use launchctl kickstart -k gui/<uid>/<label>.

Tailscale Funnel

Services are exposed to the internet via Tailscale Funnel on https://soundappraisal-dev-server.tail184f99.ts.net. The funnel routes are defined in the [funnel] section of apps_registry.toml and configured separately in Tailscale.

Additionally, port 8443 (tailnet only) proxies Open WebUI, and port 11443 (tailnet only) proxies Ollama.

Service registry

All services are defined in a single TOML file:

~/SA_projects/report_pipeline_2026/apps/apps_registry.toml

Each [services.<id>] entry has:
- name — display name
- launchd_label — macOS launchd label
- type"daemon" or "agent"
- port — listening port (0 for background workers)
- log_file — path to the stderr/log file
- url — web URL (if applicable)
- funnel_path — Tailscale Funnel route (if exposed)
- app_dir — (optional) path to the app directory, enables the Readme button

Files

~/Scripts/sa_app_manager/
├── main.py                  # FastAPI app, routes, HTMX endpoints
├── app_runner.py            # launchctl integration, status checks
├── config.py                # Registry loader, dataclasses
├── start_app_manager.sh     # Startup script (conda + uvicorn)
└── templates/
    ├── base.html            # Layout and CSS
    ├── dashboard.html       # Main dashboard
    ├── readme.html          # README viewer page
    ├── overview.html        # Pipeline overview page
    └── partials/
        ├── service_row.html     # Single service row
        ├── service_rows.html    # All rows (daemons + agents)
        ├── log_viewer.html      # Log tail panel
        └── readme_viewer.html   # (legacy, unused)

Adding a new service

  1. Create the launchd plist in /Library/LaunchDaemons/ (daemon) or ~/Library/LaunchAgents/ (agent)
  2. Load it: sudo launchctl load /Library/LaunchDaemons/<label>.plist
  3. Add a [services.<id>] entry to apps_registry.toml
  4. The dashboard picks it up automatically on next refresh
  5. (Optional) Add a Tailscale Funnel route if the service needs public access