The server delivers the browser interface and API from the same local address while each TV keeps a durable manifest, verified media, and future playback transitions.
ADMINISTRATIONReact + TypeScript
npm ci
npm run build:admin
dotnet run --project server/LessonCue.Server
The local browser experience manages accounts, classes, dated lessons, playlists, media previews, screens, a phone controller, pre-roll, countdowns, settings, and audited bulk planning and media operations.
LOCAL SERVERASP.NET Core 10 + SQLite
dotnet run --project server/LessonCue.Server
dotnet test server/LessonCue.Server.Tests
Authentication, discovery, pairing, manifests, ordered playback commands, media ranges, status, audit events, and SignalR invalidation live behind /api/v1.
OPTIONAL REMOTE ACCESSRestricted Cloudflare Tunnel
A protected root helper installs a checksum-verified connector; a separate unprivileged systemd service reads a root-owned token file and reports localhost-only edge metrics. The credential never returns through the browser API.
ANDROID / FIRE TVKotlin + Compose for TV + Media3
gradle -p android-tv :app:testDebugUnitTest :app:assembleDebug
The native app implements remote focus, pairing, local identity, background caching, browser-controller commands, and ExoPlayer playback.
APPLE TVSwiftUI + AVKit
cd tvos
xcodegen generate
open LessonCueTV.xcodeproj
The independent tvOS client implements Bonjour, Keychain credentials, AVPlayer, browser-controller commands, and verified offline cache.
LOCAL COMMAND CHANNELPhone browser → server → paired TV
Authenticated phone controls are versioned and queued in SQLite. TV clients establish a startup cursor, poll with their device credential, and consume play, pause, resume, previous, next, stop, and seek commands in order.
SCHEDULE SEMANTICSPre-roll → countdown → lesson
At designatedStartAt - durationMs, the client leaves the repeating pre-roll and starts the countdown. If it wakes midway, it seeks by elapsed time so the countdown still finishes exactly at the designated start.