screentinker/server
screentinker 1ebdb1f7a9
feat(ota): self-update kill switch — global, per-device, and MDM auto-detect (#166)
Lets an operator (or an MDM) own updates instead of the app self-installing, which
on managed panels shows a self-install confirm dialog over customer content
(#155). Three layered controls:

- GLOBAL (server): config.otaEnabled from OTA_ENABLED (default on). When off,
  /api/update/check returns update_available:false, reason:ota_disabled_global —
  the whole instance stops offering updates.
- PER-DEVICE (server + dashboard): new devices.ota_enabled column (default 1). When
  0, that device is never offered an update (reason:ota_disabled_device). A
  "Self-update (OTA)" toggle in the device settings flips it via PUT /api/devices/:id.
- AUTO-DETECT (Android): UpdateChecker stands down entirely when a foreign device
  owner (an MDM/DPC) manages the panel — detected via getActiveAdmins() + not being
  device owner ourselves. Pure client-side, errs safe, needs no server change.

The two server gates are enforced server-side so they cover EVERY client version,
not just ones with the client-side stand-down. When OTA is off the device still
reports its version (dashboard sees state); the MDM/operator owns the actual update.

For an MDM-managed fleet (e.g. Pivot/MAXHUB), turn OTA off and let the MDM push the
APK — the install-dialog race disappears from every angle.

Tests: +2 (per-device gate + a real OTA_ENABLED=false server for the global gate);
full server suite 393 pass; Android compiles.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-10 22:38:58 -05:00
..
config PiP overlay MVP: push image/web overlays to a device or group (#109) (#127) 2026-06-18 14:54:44 -05:00
db feat(ota): self-update kill switch — global, per-device, and MDM auto-detect (#166) 2026-07-10 22:38:58 -05:00
lib fix(ota): treat legacy -patchN as a released version so the old fleet is offered updates 2026-07-08 23:21:26 -05:00
middleware feat(#146): billing:read scoped token — dual-path auth for the Usage Report (Option C) 2026-07-01 21:16:21 -05:00
player fix(player): send device_id/token on reconnect before pairing (#164) 2026-07-10 13:04:18 -05:00
routes feat(ota): self-update kill switch — global, per-device, and MDM auto-detect (#166) 2026-07-10 22:38:58 -05:00
scripts feat(scheduling): per-item schedule blocks (#74 dayparting, #75 auto-expire) 2026-06-11 15:46:41 -05:00
services feat: app-ending signal (exit-signal contract v1) — server + APK + .wgt + /player 2026-07-08 15:32:40 -05:00
test feat(ota): self-update kill switch — global, per-device, and MDM auto-detect (#166) 2026-07-10 22:38:58 -05:00
ws Merge origin/main into feat/android-hidden-settings-menu 2026-07-09 20:09:58 -04:00
.gitignore feat(email): Microsoft Graph send + alert spam protection + preferences UI 2026-05-12 18:16:40 -05:00
config.js feat(ota): self-update kill switch — global, per-device, and MDM auto-detect (#166) 2026-07-10 22:38:58 -05:00
package-lock.json chore(release): v1.9.4 2026-07-10 11:57:43 -05:00
package.json chore(release): v1.9.4 2026-07-10 11:57:43 -05:00
server.js feat(ota): self-update kill switch — global, per-device, and MDM auto-detect (#166) 2026-07-10 22:38:58 -05:00
version.js chore(version): single-source VERSION, env-configurable data paths, bump tooling 2026-06-10 12:56:03 -05:00