Digital Signage

Under the bonnet

Boring technology, chosen deliberately

Screens outlive software fashions. Everything here was picked to still be maintainable, hostable and hirable-for in a decade.

LayerBuilt withWhy
ServerPHP 8.2 · LaravelRuns on anything, including the cheapest shared hosting. Fifteen years of hosting compatibility is a feature, not a compromise.
DatabaseSQLite, MySQL or PostgreSQLStart on SQLite with no server to install; move to MySQL with four lines of configuration when the fleet grows.
Admin panelReact · TypeScript · TailwindA single-page app served from the same origin as the API, so there is no cross-origin session to get wrong.
Android playerKotlin · Media3 · RoomA native app rather than a wrapped web view: it can hold a foreground service, survive a reboot, and draw over other applications.
Web playerReact · Cache API · PWAThe same layouts as the native player, sharing one set of rendering code so a card cannot look different on two screens.
RealtimeWebSocket, with polling as a first-class fallbackCorporate networks drop sockets. Polling is a supported delivery path here rather than a degraded one, which is why it works on hosting that has no socket at all.

Design decisions

Three choices worth explaining

Polling is not a fallback we are embarrassed by. A great many office networks drop WebSockets, and a great many cheap hosting plans cannot run one at all. So the polling path is tested, measured and documented rather than bolted on — which is why the product works properly on a five-dollar host.

One renderer, two players. The announcement layouts are written once and drawn by both the web and the Android player. It would have been faster to write them twice, and they would have drifted within a month.

Content is addressed by checksum. A screen downloads a given file exactly once, however many playlists reference it, and knows without asking whether it already holds what a new plan needs. That is what makes a plan change instant on a screen that already has the media.

Operationally

Things that matter at three in the morning

A health page that tells the truth

  • Database, cache, storage, queue, scheduler and broadcaster
  • Says which scheduling mode is actually in use
  • Warns about a missing broadcaster rather than reporting a healthy one

Failures that are visible

  • A delivery report per screen, per alert
  • Screens that cannot cover other apps are flagged
  • An offline screen is a state in the panel, not a discovery

Nothing dangerous exposed

  • No operating-system commands from the panel
  • Player tokens stored only as hashes
  • Configuration kept outside the web root

Want to see the architecture?

We are happy to walk a technical team through the whole thing before anyone signs anything.

No open demo, no sign-up wall — a person reads every request.