mirror of
https://github.com/screentinker/screentinker.git
synced 2026-08-13 22:03:13 -06:00
docs(readme): catch up on displays, OTA behaviour, plans and the public API
The README had drifted behind several shipped features and, worse, behind a few behaviours that surprise people in practice. Everything here was verified against the code rather than written from memory — three claims were wrong on the first pass and are corrected below. Added: - **Public REST API.** Scoped tokens, the OpenAPI contract and the browsable reference at /docs were not mentioned anywhere in the README despite being a shipped, documented surface. - **When a display will not update itself.** The three things to check in order, and the retry model spelled out because "nothing is happening" is indistinguishable from "it gave up" otherwise: flagged for attention after 3 failed installs, still retrying to 40 (cheap — the APK is cached, so later attempts pull no bytes), then about one a day indefinitely, cleared by a new version. Plus what Force update overrides (back-off, attempt count and the MDM stand-down) and what it cannot (invent install permissions). - **Deleting and re-pairing a display.** Settings are keyed to the hardware, so a re-paired panel returns configured — which reads as a bug when the old playlist reappears. Also documents that a block deliberately survives re-pair, and that Unblock is the way out (and that before 1.9.25 it only cleared half, so a display can still be stuck). - **Plans and comped accounts.** The platform-admin plan overview, and how an inactive plan runs a comped/beta/legacy tier without appearing on the pricing page. - **Optional location permission** for reporting the Wi-Fi network name, and that permission rows stay visible as Manage so grants can be reviewed or revoked. - **One playlist per display**, and that Scheduling is how you rotate several — the question a customer asked this week. - LAN and WAN addresses in the telemetry feature bullet; BrightSign in Supported Platforms. Corrected while verifying: - The API reference is served at /docs, not /api-docs. - Tizen does NOT self-update; only the Android APK does. The two were wrongly lumped together. - The admin section is labelled "Subscription Plans". - The retry description conflated the flag threshold (3) with the attempt cap (40) — different numbers doing different jobs. - BrightSign is listed with the caveat that its HTML widget may not survive the player's reload on deploy, rather than as unqualified support. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uaeo9MvzKoyXuN6ZsbhtkL
This commit is contained in:
parent
40035533e5
commit
0b9d9aff76
90
README.md
90
README.md
|
|
@ -32,7 +32,7 @@ ScreenTinker is a free, open-source **digital signage CMS** you can self-host on
|
||||||
- **Widgets** — clocks, weather, RSS tickers, text/HTML, webpages, social feeds, and Directory Board (scrolling lobby tenant/room/staff directories with dark/light themes, category management, and anti-burn-in motion)
|
- **Widgets** — clocks, weather, RSS tickers, text/HTML, webpages, social feeds, and Directory Board (scrolling lobby tenant/room/staff directories with dark/light themes, category management, and anti-burn-in motion)
|
||||||
- **Kiosk mode** — interactive touchscreen interfaces
|
- **Kiosk mode** — interactive touchscreen interfaces
|
||||||
- **Proof-of-play** — per-content and per-device analytics, hourly/daily breakdowns, CSV export for ad verification
|
- **Proof-of-play** — per-content and per-device analytics, hourly/daily breakdowns, CSV export for ad verification
|
||||||
- **Device telemetry** — battery, storage, RAM, CPU, WiFi signal strength, and uptime reported by Android players
|
- **Device telemetry** — battery, storage, RAM, CPU, Wi-Fi signal strength and uptime reported by the players, plus both of a display's addresses: its **local (LAN) IP** as the player sees itself, and the public/WAN address the server saw it connect from. Wi-Fi network name is included where the platform allows it (Android 10+ needs an opt-in location permission — see Device Setup)
|
||||||
- **Offline resilience** — both web and Android players keep displaying cached content during server or internet outages (Android ContentCache, web player Service Worker); state syncs when connectivity returns
|
- **Offline resilience** — both web and Android players keep displaying cached content during server or internet outages (Android ContentCache, web player Service Worker); state syncs when connectivity returns
|
||||||
- **Mobile-responsive** — full management dashboard and landing page work on phones and tablets
|
- **Mobile-responsive** — full management dashboard and landing page work on phones and tablets
|
||||||
- **Workspaces** — multi-tenant data model: organizations contain workspaces, workspaces contain devices/content/playlists/schedules; users can be members of multiple workspaces and switch via a dropdown in the sidebar
|
- **Workspaces** — multi-tenant data model: organizations contain workspaces, workspaces contain devices/content/playlists/schedules; users can be members of multiple workspaces and switch via a dropdown in the sidebar
|
||||||
|
|
@ -46,6 +46,7 @@ ScreenTinker is a free, open-source **digital signage CMS** you can self-host on
|
||||||
- **Security** — JWT auth, bcrypt hashing, parameterized SQL, rate-limited endpoints, per-user ownership checks on all resources, ongoing auth/IDOR/XSS audits
|
- **Security** — JWT auth, bcrypt hashing, parameterized SQL, rate-limited endpoints, per-user ownership checks on all resources, ongoing auth/IDOR/XSS audits
|
||||||
- **Built-in billing** — Stripe integration for SaaS subscriptions (optional)
|
- **Built-in billing** — Stripe integration for SaaS subscriptions (optional)
|
||||||
- **Auto-update** — OTA updates pushed to devices automatically
|
- **Auto-update** — OTA updates pushed to devices automatically
|
||||||
|
- **Public REST API** — scoped personal access tokens (`read` / `write` / `full`) over the same resources the dashboard uses, workspace-confined by construction. Documented as an OpenAPI 3.1 contract ([`docs/openapi.yaml`](docs/openapi.yaml)) and browsable on any instance at `/docs` (served locally, no CDN, so it works air-gapped)
|
||||||
- **Activity log** — full audit trail of user and system actions
|
- **Activity log** — full audit trail of user and system actions
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
@ -92,7 +93,19 @@ Schema migrations run automatically the first time the server starts after a git
|
||||||
|
|
||||||
## Supported Platforms
|
## Supported Platforms
|
||||||
|
|
||||||
Android TV, Fire TV, Raspberry Pi, Windows, ChromeOS, LG webOS, Samsung Tizen, and any device with a web browser.
|
Android TV, Fire TV, Raspberry Pi, Windows, ChromeOS, LG webOS, Samsung Tizen, BrightSign, and any
|
||||||
|
device with a web browser.
|
||||||
|
|
||||||
|
Anything with a reasonably modern browser can be a display without installing anything: point it at
|
||||||
|
`/player`. The native players add what a browser cannot: the **Android APK** gives you unattended boot,
|
||||||
|
OTA self-update, remote power and touch injection, and a content cache that survives a reboot; the
|
||||||
|
**Tizen `.wgt`** gives you an installed app that launches itself on the TV. Tizen does not
|
||||||
|
self-update — new versions are installed the same way the first one was.
|
||||||
|
|
||||||
|
> **BrightSign** runs the unmodified browser player (verified on Series 5 / Chromium 120) and needs
|
||||||
|
> no separate build. One caveat worth knowing before you rely on it: BrightSign's HTML widget does
|
||||||
|
> not always survive the page reload the player performs when you deploy new content, and may need a
|
||||||
|
> restart to come back. Treat it as working but less hands-off than the native players.
|
||||||
|
|
||||||
## Self-Hosting
|
## Self-Hosting
|
||||||
|
|
||||||
|
|
@ -161,6 +174,52 @@ Two things to know before enabling it:
|
||||||
- **It is read by the player, not the server**, so only players new enough to understand
|
- **It is read by the player, not the server**, so only players new enough to understand
|
||||||
`allow_managed` honour it. Older players keep standing down regardless.
|
`allow_managed` honour it. Older players keep standing down regardless.
|
||||||
|
|
||||||
|
#### When a display will not update itself
|
||||||
|
|
||||||
|
OTA is per-display and can be turned off per display. If one is not taking an update, the order to
|
||||||
|
check is:
|
||||||
|
|
||||||
|
1. **Is OTA enabled for it?** There is a per-display toggle; a display with it off will never
|
||||||
|
self-update, by design.
|
||||||
|
2. **Is it standing down for an MDM?** It reports `manual_update_required` if so — see above.
|
||||||
|
3. **Has it been retrying and failing?** Retrying and telling you about it are two separate
|
||||||
|
things, on purpose:
|
||||||
|
|
||||||
|
- After **3** failed installs the display **flags itself as needing attention** in the dashboard.
|
||||||
|
A human is demonstrably required by then, so it says so early rather than at the end.
|
||||||
|
- It **keeps retrying anyway**, up to 40 attempts. Attempts after the first are close to free —
|
||||||
|
the APK is downloaded and signature-checked once and then reused from cache, so retry number
|
||||||
|
twelve pulls no bytes.
|
||||||
|
- Past that it settles to about **one attempt a day**, indefinitely. It never gives up for good,
|
||||||
|
and a new version clears the count — so a display stuck for a week still picks up the next
|
||||||
|
release on its own.
|
||||||
|
|
||||||
|
The flag is what to watch for. Silence is not the signal.
|
||||||
|
|
||||||
|
**Force update** — per display, or as a group command — deliberately ignores the back-off, the
|
||||||
|
attempt count *and* the MDM stand-down, and tries straight away. It reports back either way,
|
||||||
|
including "already up to date", so the button never just appears to do nothing. What it cannot do is
|
||||||
|
invent permissions: if installs need a confirmation tap on that hardware, forcing still raises the
|
||||||
|
dialog. It is the right button once you have fixed whatever was breaking the update.
|
||||||
|
|
||||||
|
#### Deleting and re-pairing a display
|
||||||
|
|
||||||
|
A display's settings are keyed to the hardware, not to its row in the database. Delete a display and
|
||||||
|
pair the same panel again and it comes back with its previous **name, orientation, timezone, notes
|
||||||
|
and assigned playlist** already set — you do not have to configure it twice, and a panel that is
|
||||||
|
physically hard to reach does not need a visit. (The playlist only returns if it still exists; a
|
||||||
|
deleted one is not resurrected.)
|
||||||
|
|
||||||
|
Two consequences that are easy to misread:
|
||||||
|
|
||||||
|
- The old playlist reappearing is ScreenTinker restoring it, not a bug. If you deleted the display
|
||||||
|
in order to *clear* it, change the playlist after re-pairing rather than before.
|
||||||
|
- **A blocked display stays blocked**, deliberately. Blocking is a security control, so it must not
|
||||||
|
be defeatable by deleting the display and pairing again. Use **Unblock** — that clears the stored
|
||||||
|
block as well as the live one. (Before 1.9.25, Unblock only cleared the live one and the block came
|
||||||
|
back on the next re-pair; if you have a display that refuses to pair for no visible reason, unblock
|
||||||
|
it once on this version.)
|
||||||
|
|
||||||
#### Raising the upload limit
|
#### Raising the upload limit
|
||||||
|
|
||||||
`MAX_FILE_SIZE` sets what **the application** accepts. It is usually not the only limit, and it
|
`MAX_FILE_SIZE` sets what **the application** accepts. It is usually not the only limit, and it
|
||||||
|
|
@ -218,6 +277,19 @@ If you want to charge your users, plug in your own Stripe keys. Without them, al
|
||||||
|
|
||||||
The default plans are: Free (2 devices), Starter (8 devices), Pro (25 devices), and Enterprise (unlimited). Edit the `plans` table to change pricing, limits, or add/remove tiers. In self-hosted mode, the first user gets Enterprise automatically.
|
The default plans are: Free (2 devices), Starter (8 devices), Pro (25 devices), and Enterprise (unlimited). Edit the `plans` table to change pricing, limits, or add/remove tiers. In self-hosted mode, the first user gets Enterprise automatically.
|
||||||
|
|
||||||
|
#### Plans and comped accounts
|
||||||
|
|
||||||
|
Platform admins get a plan overview under **Admin → Subscription Plans**: every plan on the instance with how
|
||||||
|
many accounts, organizations and displays are on each, so you can see what people actually use
|
||||||
|
before changing a price or retiring a tier. It also flags accounts pointing at a plan that no longer
|
||||||
|
exists, which otherwise surfaces only as odd entitlement behaviour.
|
||||||
|
|
||||||
|
A plan marked **inactive** disappears from the customer-facing pricing page but keeps working
|
||||||
|
normally for anyone already on it. That is how you run a comped, beta or legacy tier without
|
||||||
|
advertising it — put the account on the hidden plan and it simply gets those limits. The overview
|
||||||
|
above deliberately lists hidden plans too (marked as such), because the previous behaviour was that
|
||||||
|
a hidden plan was invisible to the operator as well as the customer.
|
||||||
|
|
||||||
#### Google OAuth
|
#### Google OAuth
|
||||||
|
|
||||||
Let users sign in with Google.
|
Let users sign in with Google.
|
||||||
|
|
@ -528,6 +600,20 @@ keytool -genkey -v -keystore android/release-key.jks -keyalg RSA -keysize 2048 -
|
||||||
- **Any browser**: Open `https://your-instance/player` in kiosk/fullscreen mode
|
- **Any browser**: Open `https://your-instance/player` in kiosk/fullscreen mode
|
||||||
4. Enter the pairing code shown on the device
|
4. Enter the pairing code shown on the device
|
||||||
|
|
||||||
|
On the Android player, the setup screen lists the permissions it wants and lets you revisit any of
|
||||||
|
them later — each row stays visible once granted and turns into **Manage**, so you can check or
|
||||||
|
revoke what you gave it rather than having the option disappear.
|
||||||
|
|
||||||
|
One of those rows is **optional and off by default**: granting location lets the player report the
|
||||||
|
**Wi-Fi network name** for the display. Android 10 and later will not reveal the SSID without it.
|
||||||
|
Nothing else changes if you skip it — the display works identically and still reports signal
|
||||||
|
strength, and the dashboard says the network name needs that permission rather than showing a blank.
|
||||||
|
|
||||||
|
> **One playlist per display, and how to run more.** A display has a single playlist at a time.
|
||||||
|
> To rotate between several, use **Scheduling** — "Playlist A 9am-5pm, Playlist B evenings", or
|
||||||
|
> different playlists on different days — and the display switches on its own, offline included,
|
||||||
|
> once the schedule has reached it.
|
||||||
|
|
||||||
> **Troubleshooting a player** (stuck on "Connecting to server", re-pointing a
|
> **Troubleshooting a player** (stuck on "Connecting to server", re-pointing a
|
||||||
> device to a different server, or connecting adb over Wi-Fi): see
|
> device to a different server, or connecting adb over Wi-Fi): see
|
||||||
> [docs/android-troubleshooting.md](docs/android-troubleshooting.md).
|
> [docs/android-troubleshooting.md](docs/android-troubleshooting.md).
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue