Overflow Tap 1.0.0: switch Overflow Tap destinations from keywords in ProPresenter slide notes #47

Open
michael wants to merge 2 commits from claude/overflow-tap-module into main
Owner

What it is

A new module, modules/overflow-tap, that does what Overflow's "ProPresenter Integration" helper app does, inside ProdDash — speaking the same Overflow API the helper speaks — so the helper on AB-ProPresenter can be retired once this is configured there.

  • Reads the live slide's notes from ProPresenter: the presentation layer (GET /v1/status/slide) and the announcement layer (GET /v1/announcement/slide_index + /active), once a second each.
  • When a layer's set of keywords changes to a non-empty set, tells Overflow, which points those keywords' Tap groups at their destinations. A slide without a keyword changes nothing; the last destination stays. Matching is the helper's rule: a whole word of the notes, any case, punctuation around it ignored (give fires on "Give!" and "#give", not on "forgiveness").
  • One tile: the keyword Tap is on (and since when), its destination and the groups moved, a chip saying whether the slide on screen — or the announcement — carries a keyword, and the last four switches with their times. A failed switch turns the tile red with the reason, retries three times 10 s apart, and — if switched on in admin — flashes an alert channel. Four tile switches: Destination, Groups, Slide match, History. Title bar: one icon, Refresh keywords.
  • Admin config, in three groups: ProPresenter (endpoint + API password), Overflow (a Dashboard login: email + password, plus a Nonprofit ID only for an @overflow.co staff login), Alerts (toggle + channel). The keyword → destination → Tap groups mapping stays in the Overflow Dashboard (Integrations › ProPresenter › Keyword Mappings) and is read from there on start, every five minutes, on the tile's refresh button, and from every trigger's answer.
  • Health line (admin): Following host:port · Overflow: booth@church.org, 4 keywords. The tile's own status line carries no email.

The Overflow API, and where it came from

Overflow's public API documents only reads for Tap. The first cut of this PR guessed a write route; this version instead makes exactly the calls the helper app makes (Overflow ProPresenter Integration 1.2.3, bundle read 2026-10-11 with the user's approval), against the Dashboard's own backend at server.overflow.co:

Call What for
POST /nonprofit-dashboard/authentication/login/jwt { email, password } a Dashboard sign-in → JWT (payload: nonprofitId, permissions with subject TAP, exp)
GET /nonprofit-dashboard/propresenter/nonprofits/{id}/keywords the Keyword Mappings: [{ keyword, destinationName, tapGroups: [{ id, tapGroupName }] }]
POST …/nonprofits/{id}/keywords?syncNonprofit=true { keywords } the switch
GET …/propresenter/nonprofits, POST …/nonprofits/{id}/select staff logins only

All of it is in one file, overflow.js, with the provenance at the top. Session handling: the token is cached across re-inits for the same login (an admin saving config five times must not become five sign-ins — Overflow answers 429 "too many attempts"); a 401 signs in again once and retries; a refused sign-in is not retried within 20 s. Google sign-in has no password, so the account needs one set — the admin help says so, as Overflow's article does.

Testing

  • node modules/overflow-tap/keywords.selftest.js — 8 cases pinning the matching rule.
  • node tools/overflow-tap-mock.js — a ProPresenter cycling through keyworded slides on :1602 (announcement layer included; --no-announcements for an older one) plus the Overflow Dashboard API on :24720: any email/password signs in; --fail-switch refuses every switch, --expire=20 makes sessions expire, --login=<email>:<password> accepts one login only. Run ProdDash with OVERFLOW_TAP_API_BASE=http://127.0.0.1:24720.
  • Against the mock: sign-in, keyword load, triggers on both layers (connect + events when both change in one tick), token expiry → sign-in again with switching uninterrupted, 500 → red tile + alert Tap not switched: … on channel 1 + retries, wrong login → the reason on the tile and in the health line with three sign-in attempts in 45 s, and recovery once the mock is back.
  • Resilience checklist (from the first cut, same tile code): upstream killed and restored, ProdDash restarted with the tile open, two tiles with different settings (a joining tile backfills from /state), tile removed with a clean console, admin config change mid-run, page reload.

Not yet exercised: a real Overflow account. That needs the Dashboard login entered on AB; the helper app there should stay until the module is seen switching.

Shell untouched. Requires ProdDash ≥ 1.11.0 (alerts). README and CLAUDE.md carry the module and the mock.

🤖 Generated with Claude Code

## What it is A new module, `modules/overflow-tap`, that does what Overflow's "ProPresenter Integration" helper app does, inside ProdDash — speaking the same Overflow API the helper speaks — so the helper on AB-ProPresenter can be retired once this is configured there. - Reads the live slide's notes from ProPresenter: the presentation layer (`GET /v1/status/slide`) and the announcement layer (`GET /v1/announcement/slide_index` + `/active`), once a second each. - When a layer's set of keywords changes to a non-empty set, tells Overflow, which points those keywords' Tap groups at their destinations. A slide without a keyword changes nothing; the last destination stays. Matching is the helper's rule: a whole word of the notes, any case, punctuation around it ignored (`give` fires on "Give!" and "#give", not on "forgiveness"). - One tile: the keyword Tap is on (and since when), its destination and the groups moved, a chip saying whether the slide on screen — or the announcement — carries a keyword, and the last four switches with their times. A failed switch turns the tile red with the reason, retries three times 10 s apart, and — if switched on in admin — flashes an alert channel. Four tile switches: Destination, Groups, Slide match, History. Title bar: one icon, Refresh keywords. - Admin config, in three groups: **ProPresenter** (endpoint + API password), **Overflow** (a Dashboard login: email + password, plus a Nonprofit ID only for an @overflow.co staff login), **Alerts** (toggle + channel). **The keyword → destination → Tap groups mapping stays in the Overflow Dashboard** (Integrations › ProPresenter › Keyword Mappings) and is read from there on start, every five minutes, on the tile's refresh button, and from every trigger's answer. - Health line (admin): `Following host:port · Overflow: booth@church.org, 4 keywords`. The tile's own status line carries no email. ## The Overflow API, and where it came from Overflow's public API documents only reads for Tap. The first cut of this PR guessed a write route; this version instead makes exactly the calls the helper app makes (Overflow ProPresenter Integration 1.2.3, bundle read 2026-10-11 with the user's approval), against the Dashboard's own backend at `server.overflow.co`: | Call | What for | | --- | --- | | `POST /nonprofit-dashboard/authentication/login/jwt` `{ email, password }` | a Dashboard sign-in → JWT (payload: nonprofitId, permissions with subject TAP, exp) | | `GET /nonprofit-dashboard/propresenter/nonprofits/{id}/keywords` | the Keyword Mappings: `[{ keyword, destinationName, tapGroups: [{ id, tapGroupName }] }]` | | `POST …/nonprofits/{id}/keywords?syncNonprofit=true` `{ keywords }` | the switch | | `GET …/propresenter/nonprofits`, `POST …/nonprofits/{id}/select` | staff logins only | All of it is in one file, `overflow.js`, with the provenance at the top. Session handling: the token is cached across re-inits for the same login (an admin saving config five times must not become five sign-ins — Overflow answers 429 "too many attempts"); a 401 signs in again once and retries; a refused sign-in is not retried within 20 s. Google sign-in has no password, so the account needs one set — the admin help says so, as Overflow's article does. ## Testing - `node modules/overflow-tap/keywords.selftest.js` — 8 cases pinning the matching rule. - `node tools/overflow-tap-mock.js` — a ProPresenter cycling through keyworded slides on `:1602` (announcement layer included; `--no-announcements` for an older one) plus the Overflow Dashboard API on `:24720`: any email/password signs in; `--fail-switch` refuses every switch, `--expire=20` makes sessions expire, `--login=<email>:<password>` accepts one login only. Run ProdDash with `OVERFLOW_TAP_API_BASE=http://127.0.0.1:24720`. - Against the mock: sign-in, keyword load, triggers on both layers (`connect + events` when both change in one tick), token expiry → sign-in again with switching uninterrupted, 500 → red tile + alert `Tap not switched: …` on channel 1 + retries, wrong login → the reason on the tile and in the health line with three sign-in attempts in 45 s, and recovery once the mock is back. - Resilience checklist (from the first cut, same tile code): upstream killed and restored, ProdDash restarted with the tile open, two tiles with different settings (a joining tile backfills from `/state`), tile removed with a clean console, admin config change mid-run, page reload. Not yet exercised: a real Overflow account. That needs the Dashboard login entered on AB; the helper app there should stay until the module is seen switching. Shell untouched. Requires ProdDash ≥ 1.11.0 (alerts). README and CLAUDE.md carry the module and the mock. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
michael added 1 commit 2026-10-07 14:01:06 -04:00
A new module that does what Overflow's "ProPresenter Integration" helper app
does, inside ProdDash: the live slide's notes are read from ProPresenter
(GET /v1/status/slide, twice a second) and when they carry one of the admin
page's keywords, the chosen Overflow Tap groups are pointed at that keyword's
destination. One tile: the keyword Tap is on (and since when), its
destination and the groups moved, a chip saying whether the slide on screen
carries a keyword, and the last four switches. A failed switch turns the tile
red with the reason, retries three times, and can flash an alert channel.

Admin config: ProPresenter endpoint + password; Overflow client ID + API key
(x-client-id / x-api-key, the public API's two headers); Tap groups to switch
(multiselect read from the account over /groups); keywords as text, one per
line (`give = Give Online`, optionally `@ Lobby, Kids Wing`); match mode
(whole word / anywhere / own line); alerts switch + channel.

The one unverified piece: Overflow's public API documents only reads for Tap
(OpenAPI checked 2026-10-07), while Overflow's helper uses the Dashboard's
private API. The switch is sent as PATCH /api/v3/tap/groups/{id} with the new
destinationId — the natural shape for this API — and every switch is confirmed
by reading the group back, so a refusal shows on the tile instead of passing
silently. overflow.js is the one place to change if Overflow names a
different route.

Also: tools/overflow-tap-mock.js (a ProPresenter whose slide notes carry
keywords on :1602 plus the Overflow Tap API on :24720, --read-only to fail
every switch), keywords.selftest.js (14 cases), README + CLAUDE.md entries.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
michael added 1 commit 2026-10-11 10:25:07 -04:00
The first cut guessed a write route on Overflow's public API, which documents
only reads for Tap. With the helper app's bundle in hand (Overflow ProPresenter
Integration 1.2.3, read 2026-10-11) the module now makes exactly the calls the
helper makes, against the Dashboard's own backend:

  POST /nonprofit-dashboard/authentication/login/jwt      a Dashboard sign-in → JWT
  GET  /nonprofit-dashboard/propresenter/nonprofits/{id}/keywords
                                                          the Keyword Mappings
  POST …/nonprofits/{id}/keywords?syncNonprofit=true      { keywords } = the switch

So the keyword → destination → Tap groups mapping stays where Overflow keeps
it (Dashboard › Integrations › ProPresenter › Keyword Mappings) and is read
from there: on start, every five minutes, on the tile's refresh button, and
from every trigger's answer. Admin config shrinks to the ProPresenter endpoint,
the Overflow Dashboard login (plus a Nonprofit ID only for an @overflow.co
staff login) and the alert switch; the API-key, Tap-groups, keyword-text and
match-mode fields are gone.

Behaviour follows the helper: both the presentation layer (/v1/status/slide)
and the announcement layer (/v1/announcement/slide_index + /active) are
watched; when a layer's set of matched keywords changes to a non-empty set it
is sent; matching is per word, case-insensitive, punctuation around the word
ignored. The session token is cached across re-inits for the same login so an
admin saving config repeatedly cannot trip Overflow's "too many attempts";
a 401 signs in again once; a refused sign-in is not retried within 20 s.

tools/overflow-tap-mock.js now plays the Dashboard API (any email/password
signs in; --fail-switch, --expire=<s>, --login=<email>:<password>) and gives
the mock ProPresenter an announcement layer (--no-announcements for an older
one). Verified against it: sign-in, keyword load, triggers on both layers,
token expiry → re-login, 500 → NOT SWITCHED + alert + retries, wrong login →
the reason on the tile and in the health line, and recovery. keywords.selftest.js
pins the matching rule (8 cases).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Checking for merge conflicts…
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin claude/overflow-tap-module:claude/overflow-tap-module
git checkout claude/overflow-tap-module
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: michael/ProdDash#47