screentinker/server/routes
Claude e3b01a5c7f Make a content-only schedule actually put that content on the screen
The schedule dialog offers "Content (single item, optional)". The value was cross-tenancy validated
and stored faithfully, and then read by nothing. services/scheduler.js acts on exactly two columns,
layout_id and playlist_id; content_id is consulted nowhere in the codebase. So picking a file and
saving produced a schedule that fired and changed nothing — while the calendar drew a block labelled
with that filename, as confirmation that it would.

Rather than thread a third override type through the engine and every player, the schedule now gets
a playlist containing that one item. That is the shape the entire pipeline already understands:
publish, assign, push, snapshot, offline cache and all four players work on it unchanged.

It is published through the shared publishPlaylist path rather than by hand-rolling the snapshot,
because players read denormalized fields out of published_snapshot (filename, mime_type, filepath,
remote_url, per-item schedules) and a second copy of that shape here would rot the first time it
changed.

An explicit playlist override still wins and no throwaway playlist is created; a schedule with
neither content nor playlist is untouched.

5 tests covering all of those, including that the generated playlist lands in the right workspace and
that its snapshot carries the fields the players need rather than just the id.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uaeo9MvzKoyXuN6ZsbhtkL
2026-07-30 22:26:58 -05:00
..
activity.js Phase 2.1: tenancy middleware, permission helpers, JWT workspace context, frontend + backend role-rename compat 2026-05-11 20:02:00 -05:00
admin.js Show every plan on the admin tab, with who is on each 2026-07-29 19:36:10 -05:00
agency.js fix(uploads): derive stored type from file content, and never serve uploads as documents 2026-07-25 11:47:09 -05:00
ai.js feat(ai): separate optional image API key (#41) 2026-06-09 13:47:47 -05:00
assignments.js fix(server): floor duration_sec to prevent widget zero-duration player loop (#199) 2026-07-17 13:41:52 -05:00
auth.js feat(auth): self-service password reset 2026-07-27 11:19:39 -05:00
billing.js feat(#146): billing:read scoped token — dual-path auth for the Usage Report (Option C) 2026-07-01 21:16:21 -05:00
contact.js fix(landing): replace broken Custom pricing card with enterprise contact form 2026-05-14 13:52:24 -05:00
content.js fix(uploads): derive stored type from file content, and never serve uploads as documents 2026-07-25 11:47:09 -05:00
device-groups.js Keep a workspace on schedules that outlive their device group 2026-07-30 20:53:21 -05:00
devices.js Let a display opt in to pre-release builds, so a test build is not reverted under the tester 2026-07-30 18:35:31 -05:00
folders.js Phase 2.2c: content_folders gets workspace_id (schema + backfill); folders.js scoped; content.js folder-move strict same-workspace 2026-05-11 21:04:03 -05:00
kiosk.js Validate kiosk style values as CSS rather than as HTML 2026-07-27 22:28:47 -05:00
layouts.js Save a layout by diffing its zones, not by deleting and re-inserting them 2026-07-30 20:51:28 -05:00
media.js feat: transition engine — GL wipes across web, Tizen & Android (+ image↔video) (#204) 2026-07-20 16:45:32 -05:00
pip.js Hold overlay pushes to the same write check as every other fleet action 2026-07-30 20:46:03 -05:00
player-debug.js Add player debug overlay and server-side error telemetry sink 2026-05-15 15:20:42 -05:00
playlists.js Tell the screens when the playlist they are showing is deleted 2026-07-30 21:50:50 -05:00
provisioning.js fix(api): consolidate device pairing to /pair, remove vestigial bare endpoint (#90) 2026-06-12 20:13:16 -05:00
reports.js Phase 2.2g: reports.js scoped to workspace_id; fixes pre-existing /export and /uptime cross-tenant leaks 2026-05-11 21:36:54 -05:00
schedules.js Make a content-only schedule actually put that content on the screen 2026-07-30 22:26:58 -05:00
status.js Merge branch 'fix/pin-generation-csprng' into release/auth-campaign 2026-07-26 16:22:59 -05:00
stripe.js feat(stripe): enable promotion codes on checkout sessions (#227) 2026-07-23 23:44:18 -05:00
subscription.js Initial open source release 2026-04-08 12:14:53 -05:00
teams.js feat(teams): temporarily disable Teams API while feature is redesigned 2026-05-12 13:30:55 -05:00
tokens.js feat(agency): per-token upload folder — auto-created, subtree-confined (#158) (#171) 2026-07-12 21:23:25 -05:00
video-walls.js feat(socket): delivery queue for offline-device emits 2026-05-14 13:06:43 -05:00
white-label.js fix(security): patch quick-win findings from the codebase review 2026-06-08 19:02:19 -05:00
widgets.js Stop shrinking hand-written text widgets into illegibility 2026-07-30 20:28:28 -05:00
workspaces.js fix(workspaces): use APP_URL env var for invite-accept URL generation 2026-05-17 15:26:07 -05:00