Building ChronoFlow: cross-platform digital signage engineering
How a small team builds and ships a digital signage product that runs on phones, tablets, TVs and the web. This page is the map: each section sums up one engineering decision and links to the guide that explains it in depth.
The product
ChronoFlow schedules images, videos and YouTube on screens from one place. The Controller is where you manage content, playlists and schedules; the Player is the screen that plays. Both live in one Flutter app, next to a Laravel API and a web Player for Samsung and LG TVs.
The architecture: one app, two modes
Why a single build is a console on a phone and a screen on a TV.
-
Controller and Player in one Flutter app: one mode per device
How a single ChronoFlow build is a console on a phone and a screen on a TV: a mode stored on the device, one shell per mode, Android TV detection, and a separate web Player for Samsung and LG.
Read the guide
Screens and identity
How a screen joins an account without a password, and how every client signs in without holding a secret.
-
Pairing screens with a short code and a QR, without typing a password on the TV
How a ChronoFlow screen joins an account: a six-character code that rotates every two minutes, a device secret, a claim inside one transaction, and a credential delivered exactly once.
Read the guide -
OAuth2 with Passport for web, mobile and TV: one identity, no secret in the client
How ChronoFlow serves the dashboard, the app and TVs with one Passport server: one client per channel, secrets only on the server, 1-day and 30-day sessions, and Google and Microsoft sign-in without blindly merging accounts.
Read the guide
Content that plays on its own
How the API decides what plays now, and where the files live for each plan.
-
Playlists, schedules and groups: how a signage API decides what plays now
How ChronoFlow models playlists, schedules and screen groups, picks the winner with source weights and priority, keeps the loop as screen state, and delivers a change in a second or two.
Read the guide -
Object storage by plan: moving files between R2 and B2 without stopping the screens
How ChronoFlow keeps Free files in Cloudflare R2 and Pro files in Backblaze B2: one disk per plan, each file remembers its own, quotas checked twice, and a move that deletes the source last.
Read the guide
Reaching every screen
What changes when the Player is a web app inside a TV instead of a native app.
-
CORS in digital signage: why it breaks on the TV and never in the native app
Why CORS breaks the ChronoFlow Samsung and LG apps but never the Flutter app: Origin null, preflights before authentication, every custom header on the list, bucket CORS, and one Vue codebase for web and TVs.
Read the guide
Costs and shipping to the stores
What our storage choices cost, how we automate iOS and Android releases, and what to have ready before a store review.
-
Why ChronoFlow stores files with two providers, and what each one costs
Free on Cloudflare R2 and Pro on Backblaze B2: what we compared at public list prices, why not Azure Blob, what it costs per 1,000 accounts, and what we gained and gave up by choosing two providers.
Read the guide -
Automating iOS and Android releases: what we gained over doing it by hand
How we ship ChronoFlow with GitHub Actions: two workflows per platform, the same commit rebuilt for the store, build numbers without collisions, iOS with no Mac in the way, and what stays manual.
Read the guide -
A checklist for submitting your first Flutter app to the App Store and Google Play
What a small team needs ready before submitting an app to the stores, in order: before the first build, the test track, the store build, the listing, legal URLs, review rules and notes for the reviewer.
Read the guide