screentinker/server/lib
ScreenTinker 400a438fff revert: drop zone-binding, keep whole-playlist grants + size-guidance card (#73)
Investigation found zone placement is a DEVICE property (device.layout_id), not a playlist
property: a normal playlist has no derivable layout (zone_id is NULL unless set in the
device-assignment flow), so a playlist-scoped zone grant can't reach the normal flow. The
right model: placement belongs to the device (same playlist can be full-screen on one screen,
a zone on another); the agency just gets whole-playlist grants + size-guidance.

Removed the zone-grant machinery (security-adjacent dead surface is a liability, not dormant
convenience): api_token_target_zones (schema + a DROP migration for the dev DB where the
short-lived CREATE ran), resolveGrantedZone, grantableZoneIds, buildZoneGrantRows, the
create/PUT zone validation, GET /api/playlists/:id/zones, getPlaylistZones, the settings
zone-picker + its i18n, and the zone-grant bite-test.

KEPT (model-agnostic, good): the reactive per-playlist size-guidance card - GET
/api/agency/playlists/:playlistId/layout (router.param-confined) now reports the zones the
playlist actually feeds (where/what-size content lands), or full-screen when it has no layout.
Whole-playlist grants = today's working model. 147 suite green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 15:52:11 -05:00
..
agency-layouts.js feat: agency zone-grant issuance UI + reactive placement card (#73) 2026-06-14 15:12:55 -05:00
agency-targets.js revert: drop zone-binding, keep whole-playlist grants + size-guidance card (#73) 2026-06-14 15:52:11 -05:00
branding.js fix(security): patch quick-win findings from the codebase review 2026-06-08 19:02:19 -05:00
command-queue.js feat(socket): delivery queue for offline-device emits 2026-05-14 13:06:43 -05:00
content-ingest.js refactor(content): extract the upload ingest into a shared lib (#73) 2026-06-13 22:48:42 -05:00
device-sanitize.js fix(security): patch quick-win findings from the codebase review 2026-06-08 19:02:19 -05:00
image-gen.js feat(ai): generate background + foreground images for signs (#41 Phase 2) 2026-06-09 13:40:14 -05:00
pair-lockout.js fix(api): harden device pairing against brute-force (#87) 2026-06-12 20:16:12 -05:00
permissions.js feat(roles): add cross-org platform_operator staff role (#13) 2026-06-05 10:30:21 -05:00
schedule-eval.js feat(scheduling): per-item schedule blocks (#74 dayparting, #75 auto-expire) 2026-06-11 15:46:41 -05:00
schema-check.js fix(db): observable migrations + fail-fast schema verification (#37) 2026-06-09 09:31:52 -05:00
secretbox.js feat(ai): AI content design in the Designer, BYO endpoint (#41 Phase 1) 2026-06-09 12:23:55 -05:00
socket-rooms.js feat(socket): Phase 2.3 workspace-scoped dashboard socket rooms + per-command permission gates. Dashboard namespace was previously a flat broadcast - every connected dashboard received every device's status/screenshot/playback events platform-wide (foreign device names + IPs included). Inbound socket commands gated by a legacy admin/superadmin role check that was dead code post-Phase-1 rename. 2026-05-12 11:34:24 -05:00
tenancy.js feat(roles): add cross-org platform_operator staff role (#13) 2026-06-05 10:30:21 -05:00
tenant-cascade-migration.js fix(db): cascade tenant resources on workspace/org delete (#18 follow-up) 2026-06-08 16:01:52 -05:00
totp-lockout.js feat(server): TOTP primitives - encrypted secret, hashed recovery codes, verify lockout (#100) 2026-06-13 20:48:55 -05:00
totp.js feat(server): TOTP primitives - encrypted secret, hashed recovery codes, verify lockout (#100) 2026-06-13 20:48:55 -05:00
user-deletion.js feat(admin): Delete Organization + Workspace with cascade (#36) 2026-06-09 09:22:21 -05:00