Commit graph

11 commits

Author SHA1 Message Date
ScreenTinker 53e32d31e2 fix(bump-version): do not rewrite the tizen config.xml XML declaration (#77)
bump-version.sh matched `<?xml version="1.0" ...?>` - the XML format version,
which has a leading space before version= just like the widget attribute - and
rewrote it to the app version, producing invalid XML that breaks the Tizen .wgt
build: 'XML version "X.Y.Z" is not supported, only XML 1.0 is supported'. (CI did
not catch it because the no-Tizen-CLI build path just zips the files without
validating the XML.)

- bump-version.sh: skip the `<?xml` declaration line in the tizen version sed.
- tizen/config.xml: restore the declaration to version="1.0" (prior bumps had
  corrupted it to 1.8.2).

The widget version and tizen:application required_version are still updated /
left alone correctly (verified with a dummy bump + an XML parse).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-11 08:56:59 -05:00
ScreenTinker 5530d6cfcd docs: tag-based upgrade flow + upgrade.sh, Tizen install paths
- scripts/upgrade.sh: upgrade a self-hosted instance to a tagged release
  (default latest). Backs up the db (.backup), checks out the tag, npm ci
  --omit=dev, restarts the service (SERVICE_NAME override), reports the version.
- README: replace the git-pull update flow with scripts/upgrade.sh (latest or a
  pinned tag); keep main as the bleeding-edge option. Add a Samsung Tizen entry
  to device setup (URL Launcher -> /player).
- tizen/README: point path A at the server's built-in /player, and explain why
  the released .wgt is unsigned (Samsung distributor certs are DUID-locked).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 14:12:29 -05:00
ScreenTinker fb17b242ce release: bundle .wgt in the CI tarball + finalize-release.sh for the signed apk
- release.yml: build the Tizen .wgt before the source tarball and bundle it in
  (ScreenTinker.wgt at the tarball root). The signed Android APK is added by the
  local finalize step (the keystore stays off CI).
- scripts/finalize-release.sh: after the release workflow publishes a tag, build
  the signed APK locally, pull the CI-built unsigned .wgt from the release,
  assemble a complete tarball (source + apk + wgt at the root, where /download/apk
  resolves the apk after extraction), and upload the apk + complete tarball.
- .gitignore: ignore *.wgt and *.tar.gz so finalize temp files cannot be committed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 14:12:29 -05:00
ScreenTinker 52b10408be chore(version): single-source VERSION, env-configurable data paths, bump tooling
- server/version.js: shared version helper that reads the root VERSION file once
  (fallback 0.0.0). Replaces the stale hardcoded 1.2.0 / 1.5.1 / 1.0.0 fallbacks
  in /api/version, /api/update/check, and /api/status.
- config.js: DATA_DIR / DB_PATH / UPLOADS_DIR / CERTS_DIR env overrides for the
  db, uploads, and certs/jwt-secret locations. Unset resolves to exactly the
  legacy in-repo paths, so existing installs (including production) are
  byte-for-byte unchanged. Guarded by test/config-paths.test.js.
- package.json: rename remote-display-server -> screentinker (+ lockfile name).
- scripts/bump-version.sh: one-shot bump across VERSION, package.json (+lock),
  android (versionName and versionCode + 1), and the tizen widget version; makes
  one commit plus an annotated tag; prints the push command, never pushes.
- .gitignore: global *.db / *.db-wal / *.db-shm / *.db.* so no database file
  (including .db.devbak backups, at any path) can be committed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 12:56:03 -05:00
ScreenTinker 3ac81a4206 feat(ops): nightly backup script with point-in-time content history
Adds scripts/backup.sh — atomic SQLite .backup + hard-linked point-in-time
content snapshots, daily (7) + monthly (12) retention, and an error log.
Env-configurable (SCREENTINKER_DIR/BACKUP_DIR/DB/UPLOADS/*_KEEP*) so any
self-hoster can use it; defaults target a /opt/screentinker install.

Hardens two real failure modes found in production:
- Content snapshots EXCLUDE uploads/screenshots/ and use rsync --link-dest
  instead of cp -al. The per-device *_latest.jpg screenshots are rewritten
  24/7; cp -al aborts when a file mutates mid-copy and the prior script
  swallowed the error with 2>/dev/null, silently breaking content snapshots
  for ~8 weeks. rsync --link-dest hard-links unchanged files but tolerates
  in-flight changes; errors now go to backup.log.
- Retention sorts by NAME, not mtime: rsync -a / cp -al preserve the source
  dir's (frozen) mtime, so ls -dt treated fresh snapshots as oldest and pruned
  them. The timestamp is in the dir name, so name-sort is chronological.

README Backups section documents the cron setup + env knobs. Verified on prod.
2026-06-09 19:53:09 -05:00
ScreenTinker 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. 2026-05-12 08:22:47 -05:00
ScreenTinker d8492f3720 Phase 1: multi-tenancy design doc + migration scripts 2026-05-11 19:37:15 -05:00
ScreenTinker c2b1bb20ae Fix stale setup.sh references in Pi installer
Curl-pipe URLs, --help output, clone-and-run path, and the root-check
error message all referenced pi-setup.sh / setup.sh / screentinker/pi,
none of which exist. Point them all at the actual filename and path:
scripts/raspberry-pi-setup.sh.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-23 18:28:26 -05:00
ScreenTinker 261f74e1e4 Rewrite Pi setup script as all-in-one installer
Turns the Raspberry Pi script from a basic Chromium kiosk launcher
into a full installer with two modes:

- All-in-One: installs Node.js, clones the repo, runs the server
  on port 3001, and launches the kiosk pointing at localhost. One
  Pi does everything.
- Player-Only: connects to an existing server; same kiosk behavior
  as before but with better Chromium flags and crash-flag cleanup.

Other changes:
- Detects Pi OS Lite vs Desktop and adjusts strategy (startx + vt1
  for Lite, plain kiosk launcher for Desktop)
- Auto-login on tty1 for Lite installs
- GPU memory, overscan, console-blanking, and watchdog tweaks
- screentinker-{status,update,logs} management commands
- MOTD with command hints
- Cleans up the legacy remotedisplay.service / kiosk script on
  upgrade so old installs migrate cleanly
- set -euo pipefail, root check, architecture check, tee'd log at
  /var/log/screentinker-setup.log

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-23 18:26:49 -05:00
ScreenTinker 772ead28a2 Fix reset-admin.js: honor recovery token in requireAuth
scripts/reset-admin.js signed a JWT with a synthetic id ("recovery-XXX")
and instructed the operator to paste it into localStorage. But the
requireAuth middleware always SELECTs the user row by id, so every
authed API call under the recovery token returned 401 "User not found"
and the recovery flow was effectively dead.

Fix:
- reset-admin.js now sets a `recovery: true` claim on the JWT.
- requireAuth / optionalAuth short-circuit the DB lookup when
  decoded.recovery === true and synthesize a req.user record in
  memory (role: admin, plan_id: enterprise). The synthetic user is
  never persisted, so FK-constrained writes that expect a real
  user (creating devices, etc.) will still fail — which is fine,
  recovery is only meant to let the operator reset a password or
  create a fresh admin via the Settings UI.

Security: a recovery token still requires the jwtSecret to sign,
so only someone with filesystem access to the server can mint one.
Token TTL remains 1h.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-21 19:08:49 -05:00
ScreenTinker 1594a9d4a4 Initial open source release
ScreenTinker - open source digital signage management software.
MIT License, all features included, no license gates.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-08 12:14:53 -05:00