Commit graph

  • 12fe0e43eb fix(zones): frontend assignment-flow picker + missed devices.js zone_id projection main ScreenTinker 2026-05-14 21:26:58 -0500
  • 73f41c3288 fix(zone-id): restore zone-aware playlist_items wiring (issue #3 follow-up) ScreenTinker 2026-05-14 19:20:44 -0500
  • cdd29d5e3b Merge pull request #6 from ChrisChrome: web player auto-connect ScreenTinker 2026-05-14 16:12:58 -0500
  • f6ef75549b Fix possible race condition in player auto-connect Christopher Cookman 2026-05-14 14:54:17 -0600
  • 98e742c612
    Merge branch 'screentinker:main' into main Christopher Cookman 2026-05-14 13:46:40 -0600
  • d5e4e4d927 Feat: Web player auto connect Add a simple 5 second countdown to the web player to get a code without interacting (for systems where interaction is a hassle, or impossible) Christopher Cookman 2026-05-14 13:46:19 -0600
  • 8439f2bf18 fix(landing): replace broken Custom pricing card with enterprise contact form ScreenTinker 2026-05-14 13:52:24 -0500
  • f5ca26ae2d fix(socket): offline debounce + truthful single-device command feedback ScreenTinker 2026-05-14 13:11:40 -0500
  • 742d8c4b09 feat(socket): delivery queue for offline-device emits ScreenTinker 2026-05-14 13:06:43 -0500
  • 3da49ec79c chore(config): env-configurable heartbeat timing ScreenTinker 2026-05-14 13:03:02 -0500
  • 1aee4f2d5b fix(socket): raise Engine.IO ping/pong + prefer WebSocket transport ScreenTinker 2026-05-14 13:02:34 -0500
  • c4ac81c7a6 chore(discord): update Discord invite link ScreenTinker 2026-05-14 12:26:20 -0500
  • 1e23335356 fix(player): graceful handling when displayed content is removed ScreenTinker 2026-05-14 12:17:40 -0500
  • 3dfec5d2f9 feat(config): DISABLE_HOMEPAGE env var to redirect / to the app ScreenTinker 2026-05-14 12:03:29 -0500
  • 4b2a5c51ea docs(readme): comprehensive review - multi-tenancy, current features, tech stack, deployment, contribution ScreenTinker 2026-05-12 18:57:41 -0500
  • f4d2a0330b chore(email): log successful sends for observability ScreenTinker 2026-05-12 18:34:19 -0500
  • dddc48440b docs(readme): document Microsoft Graph email setup + dev restrict + spam protections ScreenTinker 2026-05-12 18:34:08 -0500
  • c71c4016ca feat(email): Microsoft Graph send + alert spam protection + preferences UI ScreenTinker 2026-05-12 18:16:40 -0500
  • f115cb454f style(switcher): widen dropdown, tighten rows, prevent org-line wrap ScreenTinker 2026-05-12 14:04:56 -0500
  • ce332ead67 feat(switcher): per-workspace device count in dropdown rows ScreenTinker 2026-05-12 14:04:21 -0500
  • 42966da973 feat(teams): temporarily disable Teams API while feature is redesigned ScreenTinker 2026-05-12 13:30:55 -0500
  • 766f02ae5d docs(upload): correct misleading defParamCharset comment ScreenTinker 2026-05-12 11:57:54 -0500
  • d679ca8d14 fix(upload): re-decode multipart filename header from latin1 to utf8 in multer storage callback ScreenTinker 2026-05-12 11:55:55 -0500
  • b67775283b fix(server): NFC normalize user-facing filenames in safeFilename ScreenTinker 2026-05-12 11:51:34 -0500
  • 1e142d9644 fix(frontend): playlists.js thumbnail path uses API endpoint instead of legacy direct path ScreenTinker 2026-05-12 11:44:30 -0500
  • fc29843035 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. ScreenTinker 2026-05-12 11:34:24 -0500
  • 56da64d0cd feat(workspaces): rename via switcher dropdown - new PATCH /api/workspaces/:id route, per-row pencil affordance in switcher (visible only when caller can_admin), small rename modal with name + slug fields, validation (name <=80 chars, slug ^[a-z0-9]+(?:-[a-z0-9]+)*$ <=60 chars, blank slug -> NULL), 409 on per-org slug collision. Permission gating via new canAdminWorkspace(db, user, ws) helper in lib/permissions.js - reused-ready for future Phase 3 admin actions. /me query now joins organization_members to compute can_admin per accessible_workspaces entry. Drive-by fixes surfaced: (1) activityLogger method filter was missing PATCH, added; (2) routes that operate on a target workspace by URL param need to stamp req.workspaceId from the param so activityLogger captures the right tenant attribution - documented in the route. Smoke fixture: switcher-test@local.test is workspace_admin of Studio A and workspace_editor of Field Crew (no org_owner) so the can_admin true/false split is exercised in one login. ScreenTinker 2026-05-12 11:06:55 -0500
  • 0c91390e56 fix(frontend): workspace switcher (Phase 3 MVP) + SW network-first migration + platform_admin accessible_workspaces expansion + static render CSS cleanup. The switcher adds a sidebar dropdown for users who are members of multiple workspaces, renders as static text with a 'Workspace' label for single-workspace users, and muted 'No workspace' for zero. Uses existing /api/auth/me's accessible_workspaces and POST /api/auth/switch-workspace endpoints. Platform admin / superadmin users now see all workspaces in accessible_workspaces (closing the known regression from 88d91b1) via a LEFT JOIN that preserves workspace_role semantics (null = acting-as, role string = direct member). No cap on the list - deliberate for now, revisit at 50+ workspaces. SW fix bumps rd-admin-v1 -> rd-admin-v2 and switches fetch strategy from cache-first to network-first so the server's existing Cache-Control: no-cache + ETag headers actually get respected; preserves offline fallback. Static render CSS drops the bordered-box chrome that was making single-workspace users think the static text was clickable. Includes test fixture user switcher-test@local.test (credentials in fixture SQL header). Surfaced by semetra22 / Discord report about 'screens jumbled up' post-migration; root cause was the missing workspace switcher UI making devices in non-active workspaces appear missing. ScreenTinker 2026-05-12 10:55:09 -0500
  • bc445a0a7c fix(boot): auto-apply Phase 1 multi-tenancy migration on startup if not yet applied; refactor scripts/migrate-multitenancy.js to expose runMigration() with CLI wrapper preserved; pre-migration snapshot to db/remote_display.pre-migration-<timestamp>.db; belt-and-suspenders guards on migrateFolderWorkspaceIds + backfillActivityLogWorkspace so the inline backfills skip cleanly if workspaces table absent. Fixes startup crash on pre-multi-tenancy installs (semetra22 / Discord report) where 'npm start' after pulling latest hit migrateFolderWorkspaceIds and crashed with 'no such table: workspaces'. Self-hosters now get an automatic upgrade path without needing to run 'node scripts/migrate-multitenancy.js' manually. ScreenTinker 2026-05-12 08:22:47 -0500
  • 92e26aafcb fix(server): mount activityLogger middleware before workspace routes so POST/PUT/DELETE actually get logged - pre-existing bug, the middleware was a no-op for every API route because route mounts came first in server.js (L305 routes vs L368 middleware). Zero double-log risk: the one inline logActivity caller at routes/auth.js:452 is on /api/auth which mounts before the new middleware position. activity_log row growth will pick up significantly going forward (pruneActivityLog 90-day retention already handles the bound). Surfaced by Phase 2.2 migration discipline. ScreenTinker 2026-05-11 23:17:28 -0500
  • 88d91b10af activity_log: stop the bleeding - writer-leak fix on 3 sites (activityLogger middleware, alert service, login route) + one-time backfill of 548 NULL-workspace rows via device.workspace_id or workspace_members lookup; activity.js route migration deferred to its own slice tomorrow. ScreenTinker 2026-05-11 23:14:06 -0500
  • f88805f36d fix(schedule): add delete button to schedule edit modal so schedules can be removed from the UI (DELETE /api/schedules/:id already existed) ScreenTinker 2026-05-11 23:05:03 -0500
  • 0b9aa56e75 Phase 2.2m: schedules.js scoped to workspace_id; schedule.workspace_id inherited from target (device/group); fixes 6 pre-existing cross-tenant leaks (POST content/widget/layout/playlist accepted with no check, PUT verifyOwnership rewrite across all 6 polymorphic targets) ScreenTinker 2026-05-11 23:03:54 -0500
  • a77ab365dd fix(dashboard): selection bar surfaces 'pick 1 more' hint when 1 display selected so the disabled Create Video Wall button isn't silently unresponsive ScreenTinker 2026-05-11 22:56:15 -0500
  • b6c90d3421 Phase 2.2l: video-walls.js scoped to workspace_id; fixes 4 pre-existing cross-tenant leaks (POST playlist_id, PUT playlist/content/leader_device, PUT /devices, PUT /content); drops dead admin/team_members code paths left over from Phase 2.1 role rename; team_id column noted for future cleanup ScreenTinker 2026-05-11 22:56:08 -0500
  • 52e68ac490 fix(playlists): POST /publish returns items with pi.id so post-publish delete works without refresh; future refactor candidate to share SELECT shape with GET /:id ScreenTinker 2026-05-11 22:28:59 -0500
  • 833e84578e Phase 2.2k: playlists.js scoped to workspace_id; fixes 3 pre-existing cross-tenant leaks (content add, widget add with NO existing check, device assign); content.js snapshot-scrub bundle; status.js export endpoint deferred to dedicated slice ScreenTinker 2026-05-11 22:22:18 -0500
  • 90fe6e0f9a Phase 2.2j: assignments.js scoped to workspace_id via playlist.workspace_id; fixes 3 pre-existing cross-tenant leaks (content add, widget add with NO existing check, copy-to cross-workspace); ensureDevicePlaylist loop-closer; status.js playlist INSERT bundle ScreenTinker 2026-05-11 22:12:13 -0500
  • e17538b186 Phase 2.2i: device-groups.js scoped to workspace_id; fixes 3 pre-existing cross-tenant leaks (group device add, bulk content assign, bulk playlist assign); pre-emptive workspace_id stamp on ensureDevicePlaylist helper ScreenTinker 2026-05-11 21:58:13 -0500
  • c7f9d014ca Phase 2.2h: layouts.js scoped to workspace_id; templates via is_template path; fixes pre-existing PUT /device/:deviceId cross-tenant layout-assignment leak ScreenTinker 2026-05-11 21:45:28 -0500
  • f17d757ba0 Phase 2.2g: reports.js scoped to workspace_id; fixes pre-existing /export and /uptime cross-tenant leaks ScreenTinker 2026-05-11 21:36:54 -0500
  • 0d642e4d80 Phase 2.2f: white-label.js scoped to workspace_id; requireWorkspaceAdmin gate; status.js bundle ScreenTinker 2026-05-11 21:30:22 -0500
  • 806c931e43 Phase 2.2e: kiosk.js scoped to workspace_id; import kiosk INSERT bundled ScreenTinker 2026-05-11 21:20:18 -0500
  • efce13e05d Phase 2.2d: widgets.js scoped to workspace_id; import + widget-reference defense bundled ScreenTinker 2026-05-11 21:13:51 -0500
  • a4610e8d0d Phase 2.2c: content_folders gets workspace_id (schema + backfill); folders.js scoped; content.js folder-move strict same-workspace ScreenTinker 2026-05-11 21:04:03 -0500
  • a5dbc5d665 Phase 2.2b: content.js + status.js import scoped to workspace_id; uploads stamp workspace_id ScreenTinker 2026-05-11 20:50:25 -0500
  • afd2a10df2 Phase 2.2a: devices.js scoped to workspace_id; pair flow stamps workspace_id on claim ScreenTinker 2026-05-11 20:33:58 -0500
  • ac3eb74122 i18n: register Italian locale in language registry (followup to PR #2) ScreenTinker 2026-05-11 20:05:09 -0500
  • 2954fd1a84 Phase 2.1: tenancy middleware, permission helpers, JWT workspace context, frontend + backend role-rename compat ScreenTinker 2026-05-11 20:02:00 -0500
  • d8492f3720 Phase 1: multi-tenancy design doc + migration scripts ScreenTinker 2026-05-11 19:12:03 -0500
  • fc84ab8d8b
    Merge pull request #2 from albanobattistella/patch-1 screentinker 2026-05-11 19:24:07 -0500
  • 9f1ca2e177
    Add Italian Translation albanobattistella 2026-05-09 15:58:48 +0200
  • 45a6800621 fix: log real client IPs through Cloudflare instead of CF edge ScreenTinker 2026-05-07 15:26:37 -0500
  • 2068bc8833 Video walls: free-form canvas editor, leader-driven sync, group dissolve, progress bars ScreenTinker 2026-04-29 23:11:16 -0500
  • 388e9e6ab8 Admin password reset + widget visibility fix ScreenTinker 2026-04-29 20:45:25 -0500
  • dec56506f9 i18n: add Android localized string resources ScreenTinker 2026-04-29 20:20:14 -0500
  • aebaacf2c1 i18n batch 7: index.html modal + player overlay ScreenTinker 2026-04-29 20:19:06 -0500
  • 6d6f901ef4 i18n batch 6: wire teams + activity + help (~62 keys) ScreenTinker 2026-04-29 20:16:21 -0500
  • 7a17bb5079 i18n batch 5: wire layout-editor + video-wall + billing (~85 keys) ScreenTinker 2026-04-29 20:13:38 -0500
  • f4a81d7be2 i18n batch 4: wire schedule + reports + kiosk (~95 keys) ScreenTinker 2026-04-29 20:09:32 -0500
  • 457a2e4dd4 i18n batch 3b: wire onboarding.js + admin.js (~84 keys) ScreenTinker 2026-04-29 20:04:23 -0500
  • 04891bccee i18n batch 3a: wire playlists.js (~65 keys) ScreenTinker 2026-04-29 20:00:52 -0500
  • 103803fb92 i18n batch 2b: wire designer.js (~80 keys) ScreenTinker 2026-04-29 19:57:12 -0500
  • 0743901e48 i18n batch 2a: wire widgets.js (~107 keys) ScreenTinker 2026-04-29 19:52:31 -0500
  • eccf4b7af1 i18n batch 1/6: wire device-detail + settings (~242 keys) ScreenTinker 2026-04-29 19:47:17 -0500
  • 8e7a093150 i18n: extract all strings, add 6 language translations, restructure i18n module ScreenTinker 2026-04-29 19:25:22 -0500
  • a2c8ab4336 Match YouTube oEmbed embed format (revert nocookie, add referrerpolicy) to fix Error 153 ScreenTinker 2026-04-29 11:32:57 -0500
  • a273e5b2b6 Switch YouTube embed to youtube-nocookie.com to avoid Error 153 from tracking blockers ScreenTinker 2026-04-29 11:28:49 -0500
  • 8bfb4584a1 Ignore local video/ directory ScreenTinker 2026-04-29 11:26:24 -0500
  • a27738120a Add YouTube video embed to landing page ScreenTinker 2026-04-29 11:25:29 -0500
  • 19b62fdc1b Fix landing-page comparison: ScreenTinker 15-device price is \$1,188 not \$989 ScreenTinker 2026-04-28 23:23:58 -0500
  • 25ab1c485b SEO: add meta tags, sitemap, robots.txt, comparison pages, guides, internal linking ScreenTinker 2026-04-28 20:54:32 -0500
  • b2aa7fab54 Player: keep video playing if unmute is blocked ScreenTinker 2026-04-28 16:18:32 -0500
  • a3551a2654 Player: only request fullscreen on real user clicks ScreenTinker 2026-04-28 16:13:58 -0500
  • 63dcc2b656 Drag-and-drop devices into groups on the dashboard ScreenTinker 2026-04-28 15:54:33 -0500
  • 9b26b4930b Make breadcrumb a drop target for moving content out of folders ScreenTinker 2026-04-28 15:51:02 -0500
  • 66a137cffe Android: bump to 1.7.8 + fix safeOn return type ScreenTinker 2026-04-28 15:45:18 -0500
  • a4c85eaabc Remove playerContainer position:relative override that nuked YT iframe ScreenTinker 2026-04-28 15:36:39 -0500
  • fb0a7f48dd Force YouTube iframe fullscreen with absolute positioning ScreenTinker 2026-04-28 15:34:40 -0500
  • ed46011ae4 Pin YouTube iframe to fill the player container ScreenTinker 2026-04-28 14:59:23 -0500
  • fb58256b1c Fix YouTube autoplay block from stale localStorage gesture flag ScreenTinker 2026-04-28 14:56:49 -0500
  • f951d51214 Always show tap overlay on player cold load ScreenTinker 2026-04-28 14:54:19 -0500
  • 06ba054898 Fix web player TDZ crash on cached-playlist startup ScreenTinker 2026-04-28 14:51:35 -0500
  • f8cc62308f Fix screenshot fallback query and API 404 hang ScreenTinker 2026-04-28 14:49:10 -0500
  • 8ec33721f7 Security: sanitize notes, add CSP headers, tighten CORS ScreenTinker 2026-04-28 14:37:31 -0500
  • c105a5941e Security: fix IDORs, XSS, rate limits, SSRF validation ScreenTinker 2026-04-28 14:37:18 -0500
  • 76a0076b65 Fix UTF-8 encoding for special characters in filenames ScreenTinker 2026-04-28 10:13:41 -0500
  • fcecf805ed Add media folder organization to content library ScreenTinker 2026-04-28 10:13:36 -0500
  • 8866e305f0 Fix Android app crash on WebSocket connection loss ScreenTinker 2026-04-28 10:13:26 -0500
  • cd6e39a4a7 Fix Android app OOM crash on 4K images and crash loop recovery ScreenTinker 2026-04-28 10:13:10 -0500
  • ee6888e737 Fix display duplication on WebSocket reconnect ScreenTinker 2026-04-28 10:13:00 -0500
  • 05f70b7910 Update ToS: add CSAM policy, fix MIT license conflict, add governing law ScreenTinker 2026-04-24 11:26:32 -0500
  • c2b1bb20ae Fix stale setup.sh references in Pi installer ScreenTinker 2026-04-23 18:28:26 -0500
  • 261f74e1e4 Rewrite Pi setup script as all-in-one installer ScreenTinker 2026-04-23 18:26:49 -0500
  • 846d61a1b0 Add Discord link and refresh feature copy ScreenTinker 2026-04-23 17:47:00 -0500
  • 2959eaa149 Refresh cached user so admin plan/role changes propagate ScreenTinker 2026-04-22 19:38:46 -0500
  • 281a735e84 Fix white-label settings not applying on page load ScreenTinker 2026-04-22 19:36:20 -0500
  • 4392bb460a Add DISABLE_REGISTRATION env var to block public sign-ups ScreenTinker 2026-04-22 19:35:32 -0500
  • ea86d70475 README: update feature list to reflect current capabilities ScreenTinker 2026-04-21 22:39:07 -0500
  • 6a0e5a28a9 Fix content file access gate for widget references ScreenTinker 2026-04-21 22:28:55 -0500