A new Apple-silicon app in viewer/macos (Swift, no dependencies, ~1 MB): one window showing a ProdDash dashboard in WebKit, and nothing else. It runs no server; it points at any ProdDash on the network. - Connections (name + address) in Settings; the add/edit sheet asks /api/modules whether ProdDash answers as you type. No port means 24500. - Two or more connections bring a slim tab bar of their names. In a window it floats over the dashboard and comes out while the pointer is on the title bar; it is not part of the title bar, because anything there makes WebKit push the page down. In full screen it is a titlebar accessory that comes down with the menu bar, and it flashes up after each switch. ⌃Tab / ⌃⇧Tab and ⌘1–9 switch from the keyboard. - Full screen, reopening in full screen if it quit there; window size and the selected tab are kept too. The dashboard's own full-screen button works as well. - Menus: View (Back, Forward, Reload Page, Enter Full Screen), Settings, Edit (copy/paste in the page's text fields), Window, Help (a guide that ships in the app). - Every installation keeps its own live web view. One that can't be reached says why and retries at 2, 4, 8, then every 15 s; a redirect off the installation is reported, not handed to the browser. JS alert, confirm and prompt show as sheets; links to other sites open in the browser. - General settings: open at login (SMAppService), keep the display awake while a dashboard is on screen (default on). build.sh signs with the Developer ID when one is installed and makes a notarised DMG with --notarize, as the launcher's does. It needs Xcode: with only the command line tools the macOS 27 SDK can't expand SwiftUI's @State. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
5.4 KiB
ProdDash
Modular production dashboard web app for Waters Church, developed in this repo.
The app lives at the repo root and is built: zero-dependency Node server
(server.js, Node 18+), dashboard shell client in public/, admin page at
/admin, modules in modules/ (the repo's copies — a packaged install ships
none and installs them from the admin page's catalog), a native macOS menu-bar launcher in
launcher/macos/ (Swift, no dependencies — the shipped macOS app: it carries
the server and its own Node runtime, supervises them, and owns the macOS
permissions modules declare; see its README), and ProdDash Viewer in
viewer/macos/ (Swift, no dependencies — a separate Apple-silicon app that
only displays one or more ProdDash installations in WebKit, with an
auto-hiding tab bar; it runs no server; see its README). Runtime state (module
config, named layouts) is written to a per-machine data directory outside the
checkout (PRODDASH_DATA_DIR overrides; see README "Where settings are
kept") — never add code that writes runtime state into the repo folder.
SPEC.md was the authority for the initial build;
README.md has run/configure/use instructions.
Building a new module — read docs/MODULE-GUIDE.md first
docs/MODULE-GUIDE.md is the authority on the module contract (manifest, client factory + moduleApi, optional server entry, title-bar controls). The rules that matter most:
- A module is one self-contained folder in
modules/— never modify the shell (server.js,public/) to add one. Installation = the admin page's Available modules (downloads from the repo into the data directory), or drop the folder and restart; configure in/admin. - All settings in the admin page (
configSchema/instanceSchema) — never a separate setup page, hand-edited file or env var. Dependencies ship inside the module folder (zero deps is the norm). Everything the module does runs inside its server entry — no helper scripts, companion programs or daemons the operator starts by hand; a listener or decoder is started ininit()and stopped instop(). A native helper ships prebuilt inside the module folder for Apple silicon macOS and 64-bit Windows (bin/<name>-macos-arm64,bin/<name>-win-x64.exe, source and build script undernative/); nothing is ever compiled on the machine running ProdDash, and a missing binary means the feature reports itself off, not a broken module. Declare"proddash": ">=x.y.z"and bump the module'sversionon every change. - Browsers never call upstream services directly; the module's server routes proxy everything (no CORS, secrets stay server-side).
- Keep the interface clean (guide rules 5-11): no
helpand no label over three words in a tile's gear; server-side settings inconfigSchemaonly; a tile setting changes that tile alone; hide-toggles ungrouped when there are four or fewer, in a folded Show group when there are five or more; title-bar controls are icons with tooltips, never labels, and never repeat something the gear already offers. - Style with the shell's CSS variables only, scoped under
[data-module="<id>"]; survive upstream loss (reconnect +setStatus). - Verify against the guide's testing section and resilience checklist. Mocks
for the existing upstreams:
node tools/prodcom-mock.js(ProdCom) andnode band-lineup-display/tmp/pp-mock.js 1599(ProPresenter).node tools/slack-mock.js 24716(Slack; run ProdDash withSLACK_API_BASE=http://127.0.0.1:24716/api).node tools/pco-band-mock.js 24710(Planning Center for Band Lineup; run ProdDash withBAND_LINEUP_API_BASE=http://127.0.0.1:24710).node tools/ableset-mock.js 39071(AbleSet over OSC/UDP; point the AbleSet module at127.0.0.1:39071;--stopped,--no-live,--speed 4).node tools/vista-midi-mock.js 5104(a network MIDI / RTP-MIDI session for Vista Cues; point its first sender at127.0.0.1:5104and paste the cue sheet it prints;--invite 127.0.0.1:5040joins from its side,--name,--channel,--every,--notes 2,23,8).
Reference code (read-only forks — don't develop these here)
prodcom-listener/— live ProdCom transcript web app. Zero-dependency Nodeserver.jsthat servespublic/and proxies/prodcom/*(including the SSE transcript stream) to the ProdCom API atconfig.json → prodcomUrl(set per site; each campus runs its own). Good reference for: SSE handling, reconnect logic, channel colors/filtering, PWA install.band-lineup-display/— backstage Electron app (stage lineup photos with mic/pack labels) plus ProPresenter Now/Next:band-lineup-display/propresenter-core/— shared ProPresenter 7/20 client, no deps, no Electron. All ProPresenter quirks live here (PP20 runtime route discovery, arrangement-expanded slide totals, uuid-then-name live-item matching). Reuse this rather than re-implementing ProPresenter access.band-lineup-display/propresenter-app/— standalone Now/Next web display.band-lineup-display/tmp/pp-mock.js— mock ProPresenter API for testing without the real thing:node tmp/pp-mock.js 1599, then point at127.0.0.1:1599.
Upstream sources: ProdCom Listener lives at
github.com/michaelmcgary2008/prodcom-listener; BandLineupDisplay exists only
on the production machine. These folders are snapshots, not submodules.