Selected work

Production engineering

Digital signage: one CMS, three device ecosystems

Getting the right media onto displays that run on hardware from three vendors, over networks nobody controls.

  • Java
  • Play Framework
  • MyBatis
  • SQL
  • Angular
  • TypeScript
  • Samsung Tizen
  • LG webOS
  • Android

Context

A digital signage platform is deceptively simple to describe: an operator uploads content, assigns it to displays, and the displays play it. The complexity is in every word of that sentence. The displays are televisions and media players from different manufacturers, sitting in shops and lobbies on whatever network the venue happens to have, running embedded browser engines that are often several years behind anything you would target on the desktop. They are expected to keep playing when the server is unreachable, and to be correct again when it comes back.

Written at the level a public case study can go: the shape of the problems and how I reasoned about them. No proprietary code, internal endpoints, schemas, customer details or unreleased work appears here.

How content reaches a display

Every arrow is a place where the two sides can disagree about state — which is where most of the interesting bugs live.

Operator
Management clientAngular · TypeScriptWhere content is uploaded, grouped, scheduled and assigned to displays.
Platform
Content & scheduling APIJava · PlayResolves what a given display should be showing right now, and why.
Device management APIcommands · stateRemote control, snapshots and live view — each an acknowledged command, not fire-and-forget.
IdentityOAuth 2.0 · OIDCWho may operate which displays. Separate domain, separate trust boundary.
Storage
Relational storeSQL · MyBatisContent metadata, schedules, device records and state.
Media storefilesThe actual video and image assets the players download.
Device agent
Player applicationJavaScriptSyncs its playlist, caches media locally, and keeps playing when the network is gone.
Hardware
SamsungTizen / SSSPIts own browser engine, its own device API surface.
LGwebOSDifferent engine, different API, same application expected to run.
Androidplayers & displaysThe most conventional runtime of the three, and still not the same.

The engineering

  1. Three platforms, three definitions of "the web"

    Samsung Tizen (SSSP), LG webOS and Android devices each ship their own browser engine and their own device APIs. The same player application has to run on all of them. Feature detection beats user-agent sniffing almost every time, but device APIs — the ones that control power state, capture a snapshot, or read hardware info — have no common interface at all, so the honest answer is a thin platform abstraction with a genuinely separate implementation per vendor behind it.

  2. Media that plays on one device and silently fails on another

    The most common report is "the video does not play", and it almost never means one thing. A file is a container holding streams in particular codecs at a particular profile and level, and playback depends on the hardware decoder, not on whether the file is technically valid. A device can accept the container, report no error, and still show black. Debugging this means separating container from codec from profile from decoder — and then deciding, at the platform level, what the supported set actually is.

  3. Remote operations against devices you cannot reach

    Remote control, snapshots and live view all share the same hard part: the device, the network and the server have to agree on state that is constantly drifting. A command issued to a display that rebooted thirty seconds ago has to fail in a way the operator understands, rather than hanging. That pushes you toward acknowledged commands, explicit timeouts, and a device state model that admits "I do not currently know".

  4. Backward compatibility as a hard constraint

    A device in the field is not on the latest build and cannot be assumed to update on command. That makes the API between server and device the most conservative interface in the system: new fields are additive, old behaviour keeps working, and a change that requires every device to update at once is not a change you can make. Most of the design discipline in this work comes from that single constraint.

Three platforms, compared

Where the differences actually show up, and what each one costs in practice.

AspectSamsungTizen / SSSPLGwebOS SignageAndroidplayers & displays
RuntimeDecides which language and API features you can use without a polyfill.Vendor web engine, versioned with the firmwareVendor web engine, versioned with the firmwareSystem WebView or a native shell
Device APIsPower state, hardware info, capture. No cross-vendor equivalent exists.Vendor-specific JavaScript APIsVendor-specific JavaScript APIsAndroid APIs via the host application
Feature detectionUser-agent strings on these devices are unreliable and change with firmware.Detect capabilities, not the deviceDetect capabilities, not the deviceDetect capabilities, not the device
Media playbackSupport is a property of the hardware decoder, not of the file being valid.Hardware decoder limits by model and firmwareHardware decoder limits by model and firmwareVaries widely with the SoC
Failure modeThe reason “it does not play” is rarely a useful bug report on its own.Can fail silently — no error, black outputCan fail silently — no error, black outputMore likely to surface an error
DebuggingHow much you can see when something goes wrong on a device you cannot reach.Remote inspector, when the device allows itRemote inspector, when the device allows itRemote debugging over ADB
Update cadenceFirmware in the field sets the real floor for what you can ship.Firmware-bound; fleets run mixed versionsFirmware-bound; fleets run mixed versionsVaries by vendor and device policy