screentinker/server
ScreenTinker a36880b147 fix: per-item mute round-trip + multi-zone orphan-zone fallback & warnings
Two independent multi-zone bugs, plus operator-facing warnings, i18n, and
regression tests guarding the data contracts.

Bug 1 — per-item mute was a no-op end to end:
- GET /api/devices/:id dropped the `muted` column from its assignments SELECT,
  so the dashboard toggle never reflected state (the muted=false case in
  particular). Column restored to the device payload.
- Android player now honours the per-item mute flag for YouTube (initial state
  + live via the IFrame JS API).

Bug 2 — items whose zone_id belongs to a different layout were silently dropped:
- Player fallback (web + Android): an orphaned zone_id is recovered into the
  largest zone instead of vanishing, with telemetry.
- server/lib/zone-validate.js is the single source of truth for the orphan rule
  (zone not in the device's active layout); used by the device payload
  (per-item `orphan` flag + `active_layout_zones`) and the device list
  (`orphan_count`).
- Assign-time hardening: a stale zone_id (not in the device's active layout) is
  cleared to null on POST/PUT rather than persisted as a new orphan.
- scripts/find-orphan-zone-items.js: read-only sweep for existing orphans.

Dashboard warnings (operator-facing, never on the live player):
- Per-item badge + reassign affordance, device-list glance, preview banner.
- Graceful degradation: the zone selector falls back to /api/layouts/:id so it
  can't vanish on a stale payload.

i18n: orphan-zone strings added to en/es/fr/de/pt/it (hi falls back by design;
count strings interpolate through tn()).

Tests: server/test/device-zone-contract.test.js adds 5 regression tests for the
data contracts above (muted true/false round-trip, active_layout_zones, orphan
flag + count, orphan-clears-on-reassign, assign-time clearing). 172/172 pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 23:16:29 -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 fix(#134): quiet false "reconnect" log + report HDMI output and UI render resolution (#136) 2026-06-19 15:32:11 -05:00
lib fix: per-item mute round-trip + multi-zone orphan-zone fallback & warnings 2026-06-22 23:16:29 -05:00
middleware feat(api): per-agency-token auto-publish (#73) 2026-06-14 13:48:17 -05:00
player fix: per-item mute round-trip + multi-zone orphan-zone fallback & warnings 2026-06-22 23:16:29 -05:00
routes fix: per-item mute round-trip + multi-zone orphan-zone fallback & warnings 2026-06-22 23:16:29 -05:00
scripts feat(scheduling): per-item schedule blocks (#74 dayparting, #75 auto-expire) 2026-06-11 15:46:41 -05:00
services feat(api): batched email digest for agency uploads (#73) 2026-06-14 13:59:37 -05:00
test fix: per-item mute round-trip + multi-zone orphan-zone fallback & warnings 2026-06-22 23:16:29 -05:00
ws fix(#134): quiet false "reconnect" log + report HDMI output and UI render resolution (#136) 2026-06-19 15:32:11 -05:00
.gitignore feat(email): Microsoft Graph send + alert spam protection + preferences UI 2026-05-12 18:16:40 -05:00
config.js feat(config): HIDE_BILLING flag to hide the Subscription/billing UI (#116) 2026-06-16 09:19:24 -05:00
package-lock.json chore(release): v1.9.1-beta5 2026-06-19 15:33:51 -05:00
package.json chore(release): v1.9.1-beta5 2026-06-19 15:33:51 -05:00
server.js fix(server): proxy remote YouTube thumbnails + real version in boot banner (#131) 2026-06-18 17:00:24 -05:00
version.js chore(version): single-source VERSION, env-configurable data paths, bump tooling 2026-06-10 12:56:03 -05:00