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>
This commit is contained in:
ScreenTinker 2026-06-10 14:12:29 -05:00
parent fb17b242ce
commit 5530d6cfcd
3 changed files with 95 additions and 17 deletions

View file

@ -314,31 +314,36 @@ To update a running instance to the latest version:
```bash
cd /opt/screentinker
# Back up the database first
sqlite3 server/db/remote_display.db ".backup server/db/backup-$(date +%F).db"
# Upgrade to the latest tagged release. Backs up the db (a .backup snapshot under
# ./backups), checks out the tag, runs npm ci --omit=dev, restarts the service,
# and reports the running version.
scripts/upgrade.sh
# Pull latest code
git pull origin main
# Install any new dependencies
cd server && npm install --production
# Restart the service
sudo systemctl restart screentinker
# ...or pin a specific release:
scripts/upgrade.sh v1.8.0
```
If you deployed without git, you can initialize it:
Set `SERVICE_NAME` if your systemd unit is not named `screentinker`.
If you deployed without git, initialize it once so `upgrade.sh` can resolve tags:
```bash
cd /opt/screentinker
git init
git remote add origin https://github.com/screentinker/screentinker.git
git fetch origin main
git checkout origin/main -- .
git fetch origin --tags
git checkout -f main
cd server && npm install --production
sudo systemctl restart screentinker
```
**Track bleeding edge (`main`)** instead of tagged releases - newest code, less tested:
```bash
cd /opt/screentinker && git checkout main && git pull origin main
cd server && npm install --production && sudo systemctl restart screentinker
```
Your database, uploads, and configuration are preserved — only code files are updated.
**Schema migrations run automatically.** No manual migration commands at any point. On detecting a database that hasn't been through Phase 1 multi-tenancy migration yet, the server takes a timestamped snapshot first (`server/db/remote_display.pre-migration-<timestamp>.db`) and only continues startup once migration commits cleanly. If migration fails, the server logs the snapshot's path and exits — restore it with `cp` and investigate before retrying.
@ -414,6 +419,7 @@ keytool -genkey -v -keystore android/release-key.jks -keyalg RSA -keysize 2048 -
- **Android TV / tablets**: Download the APK from your instance (`/download/apk`) or build it from source (see above)
- **Raspberry Pi**: `curl -sSL https://your-instance/scripts/raspberry-pi-setup.sh | bash`
- **Windows**: Run the setup script from `scripts/windows-setup.bat`
- **Samsung Tizen TV / signage**: point the TV's URL Launcher (or browser) at `https://your-instance/player` - no signing needed. For an installed native app, see [tizen/README.md](tizen/README.md)
- **Any browser**: Open `https://your-instance/player` in kiosk/fullscreen mode
4. Enter the pairing code shown on the device

64
scripts/upgrade.sh Executable file
View file

@ -0,0 +1,64 @@
#!/bin/bash
# Upgrade a self-hosted ScreenTinker to a tagged release (default: the latest).
#
# scripts/upgrade.sh # upgrade to the highest vX.Y.Z tag
# scripts/upgrade.sh v1.8.0 # upgrade to a specific tag
#
# Backs up the database first, checks out the tag (detached HEAD - you are now
# running a specific release, not a moving branch), installs production deps,
# restarts the service, and reports the running version. Schema migrations run
# automatically on the next boot.
#
# Env overrides: SERVICE_NAME (systemd unit, default screentinker), DB,
# BACKUP_DIR, STATUS_URL.
set -euo pipefail
cd "$(dirname "$0")/.."
APP_DIR="$(pwd)"
SERVICE_NAME="${SERVICE_NAME:-screentinker}"
DB="${DB:-$APP_DIR/server/db/remote_display.db}"
BACKUP_DIR="${BACKUP_DIR:-$APP_DIR/backups}"
echo "==> Fetching tags"
git fetch --tags origin
# Target tag: explicit arg, or the highest semver v* tag.
TARGET="${1:-$(git tag -l 'v*' | sort -V | tail -1)}"
if [ -z "$TARGET" ] || ! git rev-parse -q --verify "refs/tags/$TARGET^{commit}" >/dev/null; then
echo "ERROR: no such release tag: '${TARGET:-<none found>}'" >&2
exit 1
fi
echo "==> Target release: $TARGET"
# Back up the db first (reuses backup.sh's .backup - a consistent online copy).
if [ -f "$DB" ]; then
mkdir -p "$BACKUP_DIR"
BK="$BACKUP_DIR/remote_display-pre-${TARGET}-$(date +%Y%m%d-%H%M%S).db"
echo "==> Backing up db -> $BK"
sqlite3 "$DB" ".backup '$BK'"
else
echo "==> No db at $DB yet (fresh install) - skipping backup"
fi
echo "==> Checking out $TARGET"
git checkout -q "$TARGET"
echo "==> Installing server deps (npm ci --omit=dev)"
( cd server && npm ci --omit=dev )
echo "==> Restarting $SERVICE_NAME"
sudo systemctl restart "$SERVICE_NAME"
# Best-effort: report the running version. Tries HTTP :3001 then HTTPS :3443.
echo "==> Waiting for the service to answer..."
OUT=""
for i in $(seq 1 30); do
for URL in "${STATUS_URL:-}" http://localhost:3001/api/status https://localhost:3443/api/status; do
[ -z "$URL" ] && continue
OUT="$(curl -skf "$URL" 2>/dev/null || true)"
[ -n "$OUT" ] && break
done
[ -n "$OUT" ] && break
sleep 1
done
echo "==> /api/status: ${OUT:-<no response - check: journalctl -u $SERVICE_NAME>}"
echo "==> Upgrade to $TARGET complete. (Back to bleeding edge anytime: git checkout main)"

View file

@ -35,12 +35,20 @@ build-wgt.sh package (signed if Tizen CLI present, else unsigned)
```
Without the Tizen CLI this is an **unsigned** `.wgt`.
> **Why the released `.wgt` is unsigned:** Samsung **distributor** certificates
> are locked to the **DUID** of the signer's own TVs, so a `.wgt` we signed would
> not install on your TV anyway. Releases therefore ship it unsigned (for
> inspection only). To actually run it, use **path A** (no signing) or sign it
> yourself with your own certificate (**path B**).
## Deploy — two paths
### A) URL Launcher (easiest, no signing) — Samsung signage (SSSP)
No package needed. Host this folder on any web server (e.g. the ScreenTinker
server itself) and point the display's **URL Launcher** at `…/index.html`.
The TV runs it as a web app on boot. Best for Samsung B2B signage displays.
### A) URL Launcher / TV browser (easiest, no signing)
No package, no Tizen Studio. Point the TV's **URL Launcher** (or just its web
browser) at your server's built-in web player: `https://<your-instance>/player`.
The TV runs it as a web app on boot, pairs with a 6-digit code, and plays - best
for Samsung B2B signage (SSSP). (You can instead self-host this `tizen/` folder
and point the URL Launcher at `…/index.html` for the Tizen-specific build.)
### B) Signed `.wgt` (installed app)
A signing profile is already set up on the build box (Tizen Studio CLI 6.1):