screentinker/server
ScreenTinker cbabbeb78c feat(preview): device-manager preview — second surface for #104 (combined)
Completes #104's two surfaces by reusing the now-generalized player preview
for devices, seam-safe (device-bound layout, NOT playlist-derived).

Server:
- GET /api/devices/:id/preview-payload returns buildPlaylistPayload(deviceId)
  — the device's OWN layout/orientation (device row) + its published items —
  with wall_config forced null (v1: wall members preview full-frame; a
  socket-free follower would otherwise freeze waiting for leader wall:sync).
  Device-READ gate (mirrors GET /:id, viewers allowed); NOT requirePlaylistRead.

Player (generalized, shared seam):
- Boot dispatch now accepts ?preview=1 with EITHER playlist=ID OR device=ID.
- bootPreview(qs) builds the right URL; shared body factored into
  renderPreviewFromUrl(url) used by both. Renderer still UNTOUCHED.
- derivePreviewLayout stays PLAYLIST-only; never touches the device path.

Dashboard:
- Device manager gets a Preview button -> /player?preview=1&device=ID
  (modal iframe, aspect from device orientation). Playlist-view button as-is.
- i18n x6 (device.preview_btn).

Validated (not just tests): 149 server tests green (generalization didn't
break the playlist path); device preview renders socket-free in headless
Chrome; layout proven device-bound on real data (device playlist has 0 zoned
items -> playlist-derivation would give NULL, but payload returns the device
row's "Vertical Full HD"); wall-member device previews full-frame (inWallMode
false) without freezing; auth gate outsider->403, no-token->401; playlist
path still renders the webpage note post-refactor.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 14:57:19 -05:00
..
config feat(api): agency-token security primitive - off-ladder scope + agencyGate (#73) 2026-06-13 21:30:38 -05:00
db revert: drop zone-binding, keep whole-playlist grants + size-guidance card (#73) 2026-06-14 15:52:11 -05:00
lib feat: full-screen-only guardrail for agency designations (#73) 2026-06-14 17:36:30 -05:00
middleware feat(api): per-agency-token auto-publish (#73) 2026-06-14 13:48:17 -05:00
player feat(preview): device-manager preview — second surface for #104 (combined) 2026-06-15 14:57:19 -05:00
routes feat(preview): device-manager preview — second surface for #104 (combined) 2026-06-15 14:57:19 -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 feat: full-screen-only guardrail for agency designations (#73) 2026-06-14 17:36:30 -05:00
ws feat(preview): draft-aware device-free playlist preview via player reuse (#104) 2026-06-15 14:11:05 -05:00
.gitignore feat(email): Microsoft Graph send + alert spam protection + preferences UI 2026-05-12 18:16:40 -05:00
config.js chore(version): single-source VERSION, env-configurable data paths, bump tooling 2026-06-10 12:56:03 -05:00
package-lock.json chore(release): v1.9.1-beta2 2026-06-14 20:34:21 -05:00
package.json chore(release): v1.9.1-beta2 2026-06-14 20:34:21 -05:00
server.js feat(api): batched email digest for agency uploads (#73) 2026-06-14 13:59:37 -05:00
version.js chore(version): single-source VERSION, env-configurable data paths, bump tooling 2026-06-10 12:56:03 -05:00