For review · from White Oak Media
ProDeck is a production-booth hub I built for my church: one app that ties ProPresenter, Planning Center, the audio consoles, NFC "tap" discs, crew phones, and the livestream into dashboards for the booth, phones, and kiosk screens.
This guide is honest about what you'd be adopting. Part I is the evaluation — what it does, what it assumes, and what's tuned to my room. Part II is the adoption — everything your tech person needs to stand it up in your environment without me on the phone.
Part I — Evaluate
Not a product. ProDeck is one church's custom tool: no vendor, no support contract, no license fee, and one maintainer (me), whose priority is my own Sunday. You'd be adopting a codebase — a well-documented one, but a codebase. The realistic ways to hold it:
What it costs to run: a Mac in the booth, and if you want the phone/remote features, a Cloudflare account (free tier is enough) plus a domain (~$10/yr). That's the entire bill.
Every feature is independent — adopt the rows you want, ignore the rest. CORE needs only the booth Mac + ProPresenter + Planning Center. + X names the extra dependency.
| Feature | Needs | What it does |
|---|---|---|
| Dashboards | CORE | Drag-and-drop widget grids (rundown, now/next, slide grid, clocks, timers, readiness lights…), multiple named layouts, role templates. Same UI serves the booth screen, browsers, phones, kiosks. |
| Show flow | CORE | The PCO rundown with computed wall-clock start times, per-song key/leader/mic chips, live-item tracking that follows what's actually on the screens. |
| Service tracking & reports | CORE | Planned vs. actual timing per item, bucketed per service time; rehearsals kept out of Sunday stats; saved reports. |
| Clear dock | CORE | One-tap ProPresenter layer clears (slide/media/props/messages/…) pinned to every page. |
| SPL + RTA metering | + audio input | Calibrated house SPL, RTA, history graphs, per-service loudness records. Built for Dante Virtual Soundcard; any CoreAudio input works. |
| Console mirror | + a supported desk | Channel names/mutes/faders on dashboards, mic names pushed to the desk weekly. Allen & Heath Avantis, dLive and SQ (MIDI over TCP) and Behringer X32 / Midas M32 (OSC). Only the Avantis has been run against real hardware; the rest are built from the published protocols. Any other desk means new code. |
| Song-key MIDI send | + MIDI route | Sends the live song's key as a MIDI program change (I target Waves LV1 scenes). Generic PC/CC sender — usable against anything that takes MIDI. |
| Stage feed preview | + NDI | Any NDI source as a dashboard tile (LAN only, by design). |
| Crew phone app | + cloud | Installable web app: dashboards, plan, chat, push pages. Poster-QR signup with booth approval; names self-heal against PCO. |
| Paging & call times | + cloud | Page a person or team (phones buzz), scheduled call-time pages per PCO team, booth↔stage messages, confidence banner. |
| Check-in | + cloud | Crew auto-marked arrived when their phone joins your network (or by geofence); arrival board against call times. |
| Booth-off fallback | + cloud | When the booth Mac is off, your domain still serves a read-only plan + working chat + signup from Cloudflare's edge. |
| Kiosk mode | + cloud | URL-parameter kiosks: office screens, a "what's next" switcher dashboard for a touchscreen at the video position. |
| TapLink NFC discs | + cloud + NFC tags | The flagship trick: NFC discs in the lobby all open one link whose destination follows the service — a slide with tap: give in its ProPresenter notes retargets every disc to your giving page the moment it goes live. Manual override, auto-release, tap analytics. |
| Lobby TV auto-announcements | CORE | Drives a ProPresenter announcement playlist for lobby screens. |
| Live viewer count | + GA4 | Realtime "watching now" from the Google Analytics tag on your stream's watch page (matches GA4's own realtime screen). Works with Church Online Platform or any watch page you can tag. |
| Stream Deck | + Companion | Tap-disc keys with live state, dB and check-in readouts, page navigation, via Bitfocus Companion. |
| Component | Requirement |
|---|---|
| A Mac in the booth | REQUIRED Intel or Apple Silicon (macOS 10.15+), always on, always awake. This is the server for everything. There is no Windows or Linux build. |
| ProPresenter 7 | REQUIRED with the network API enabled (Preferences → Network). ProDeck reads slides/playlists/notes and triggers over it. |
| Planning Center Services | REQUIRED — plans, teams, and scheduling are the backbone. You press Connect and approve ProDeck on Planning Center's own page — it asks for Services and People, nothing else. (A Personal Access Token still works if you prefer one.) |
| Cloudflare + a domain | OPTIONAL — only for the crew/cloud/tap features. Free plan suffices; the domain is the only recurring cost. |
| Dante / audio interface | OPTIONAL — SPL features take any input the Mac can hear. |
| A supported sound console | OPTIONAL — A&H Avantis / dLive / SQ, or Behringer X32 / Midas M32. Anything else is unsupported. |
| OBS Studio | OPTIONAL — scene, stream/record state and dropped frames, via OBS's built-in WebSocket server. |
| NDI source, Stream Deck, NFC tags (NTAG213+), GA4 on your watch page | OPTIONAL — one feature each. |
The honest answer to "how personalized is this?" — in three tiers.
ProPresenter host, PCO credentials, all passwords and tokens, GA4 property/key, church coordinates, SPL calibration, MIDI ports and channels, Avantis host, audio channel routing, mic-position templates, checklists, call-time schedules, tap keyword→URL mappings, dashboard layouts. None of my values ship in the repo — a fresh install starts blank.
Everything site-specific is either a Setting or a gitignored local file, so your fork never carries your values in source:
| What | Where it lives |
|---|---|
| Your public domain (crew phones off-site, the edge fallback, the permanent /join QR) | Settings → Browser Access → Public URL. The edge push URL is derived from it. |
| Cloudflare Worker routes for your zone | crew-edge/wrangler.local.jsonc and taplink-edge/wrangler.local.jsonc (gitignored; copy the committed wrangler.jsonc and fill in your route) |
| Bundle identifier, signing identity, updater endpoint + public key | src-tauri/tauri.local.conf.json (gitignored overlay; scripts/setup.sh creates it). Leave the placeholder updater block in tauri.conf.json alone — if you never publish updates the check simply fails quietly in Settings. |
src-tauri/src/lib.rs and src/main.tsx.| Milestone | Time |
|---|---|
| Phase 0 — running on a spare Mac against Pro + PCO | an afternoon |
| Phase 1 — permanent booth install (signing, watchdog) | half a day |
| Phase 2 — your domain, workers, tunnel, crew phones | a day, mostly waiting on DNS |
| Phase 3 — discs, deck, kiosks, GA4 (each independent) | 1–3 hours each |
Part II — Adopt
Zero commitment: dev mode on any Mac (Intel or Apple Silicon) on your church network. No signing, no cloud, no install.
# prerequisites (one-time): Xcode command-line tools, Rust, Node 20+
xcode-select --install
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
brew install node # or nodejs.org installer
# get the code (after I've added you to the repo)
git clone https://github.com/whiteoakmedia/prodeck.git
cd prodeck
bash scripts/setup.sh # prereqs + config + dev mode, all guided
First run opens a setup wizard. Point it at ProPresenter (the ProPresenter machine's address (Find discovers it, or read the host and port from ProPresenter → Preferences → Network)) and press Connect for Planning Center, which signs you in on planningcenteronline.com itself — no password or token is typed into ProDeck. That's enough to evaluate everything tagged CORE in §2 — dashboards, show flow, slide grid, tracking, clear dock — plus SPL if you pick an audio input.
Evaluate against a real week
Load next Sunday's actual plan and leave a dashboard up through a midweek rehearsal. The value shows up in use, not in a demo click-through.
Makes it permanent: a signed build that survives crashes and reboots unattended.
Keychain Access → Certificate Assistant → Create a Certificate: name it (e.g. YourChurch ProDeck), identity type Self-Signed Root, certificate type Code Signing. macOS pins microphone/screen permissions to this identity — keep using the same one forever, and never re-sign with hardened runtime (the install script refuses it for you).
npm run tauri signer generate -- -w ~/.prodeck/updater.key
Put the printed public key and your fork's release feed into the gitignored overlay src-tauri/tauri.local.conf.json (plugins.updater.pubkey / endpoints, plus bundle.createUpdaterArtifacts: true) — not into the committed tauri.conf.json. If you never publish updates, skip this step entirely. Guard the private key like a password: whoever holds it can ship code to your booth.
TAURI_SIGNING_PRIVATE_KEY="$(cat ~/.prodeck/updater.key)" \
npm run tauri -- build --bundles app --config src-tauri/tauri.local.conf.json
codesign --force --deep --sign "YourChurch ProDeck" \
src-tauri/target/release/bundle/macos/ProDeck.app # no hardened runtime
bash scripts/install-local.sh # atomic swap into /Applications + watchdog handoff
Prefer a double-click installer? bash scripts/build-dmg.sh produces a drag-to-Applications ProDeck.dmg — hand it to anyone, no terminal needed to install (only to build). For an always-on booth, the script path below adds crash-relaunch and keep-alive that a plain drag-install does not.
scripts/install-local.sh refuses a bundle that isn't signed with your identity (or one signed with hardened runtime), and installs the watchdog LaunchAgent template from step 4 for you.
Ready-made templates live in deploy/launchagents/ — scripts/setup.sh --install installs and loads them for you. For reference:
| Plist | Purpose · ProgramArguments |
|---|---|
| com.prodeck.watchdog.plist | Relaunch on crash · /Applications/ProDeck.app/Contents/MacOS/prodeck, RunAtLoad true, KeepAlive.SuccessfulExit false, ThrottleInterval 10 |
| com.prodeck.caffeinate.plist | Never sleep · /usr/bin/caffeinate -s, KeepAlive true |
| com.prodeck.cloudflared.plist | Phase 2 only — the tunnel (§9). Not in the repo; you create it when you set up the tunnel. |
Finish by enabling Browser Access in Settings (pick your admin + member passwords) and giving the booth Mac a DHCP reservation — do the ProPresenter Mac too, and skip the single most recurring failure I ever had.
Unlocks: crew phones anywhere, booth-off fallback, tap discs, kiosks beyond the LAN. Needs a Cloudflare account (free) and a domain on it.
crew-edge/wrangler.local.jsonc (§4, Tier 2).crew-edge/ and taplink-edge/: npx wrangler login then npx wrangler deploy. Set each worker's secrets with npx wrangler secret put <NAME> — the names are listed at the top of each worker's src/index.ts (admin token, PCO pair for the edge fallback, tap tokens).brew install cloudflared, then cloudflared tunnel login, cloudflared tunnel create booth, and a config at ~/.cloudflared/config.yml routing your hostname → http://localhost:8088. Add the DNS route (cloudflared tunnel route dns booth yourdomain.com) and wrap it in the com.prodeck.cloudflared LaunchAgent. Tunnel only the gateway port — never video.install-local.sh keeps the edge's fallback copy in sync on every install.| Feature | Setup |
|---|---|
| Tap discs | Buy NTAG213+ stickers/discs, write each with your tap URL (any NFC-writer phone app), map keywords → URLs in the TapLink widget's editor, then put tap: keyword in ProPresenter slide notes. Discs are dumb pointers — all logic is server-side, so you can add discs forever without rewriting them. |
| Stream Deck | Install Bitfocus Companion on the booth Mac, add an HTTP connection pointed at localhost:8088 with your admin password as the prodeck_token variable. The gateway's deck endpoints (deck-state, tap actions, readouts) are documented in src-tauri/src/web.rs. |
| Kiosks | Any screen with a browser: https://yourdomain/?kiosk=<dashboard name>&token=<member password>. Windows auto-boot recipe is in OFFICE_KIOSK.md in the repo. |
| Live viewers | Make a GA4 property for your watch page, put its tag on the page (Church Online has a built-in GA4 integration), create a Google Cloud service account with the Analytics Data API enabled, grant it Viewer on the property, drop its JSON key on the booth Mac, fill in Settings → Live Viewers. Full recipe with the exact error messages you'll hit is in the repo's ga4.rs header comments. |
| SPL calibration | Play pink noise, read a real SPL meter at FOH, and adjust the calibration offset in Settings until they agree. Mine is meaningless in your room. |
~/Library/Application Support/ProDeck/ (all settings, layouts, reports, crew accounts — settings.json inside it holds every secret) and your updater key. Your fork covers the code.Where I land on it
If the tap discs, crew phones, or one-glance dashboards solve a real problem for your team, the adoption cost is a few honest days and a codebase to own. If they don't, skip it without guilt — everything underneath (Pro, PCO, your consoles, your stream) already works without it. Questions to zach@whiteoakmedia.io.