I moved playlist scheduling and interruption logic from the frontend into backend services. From there, my work covered preparing audio, controlling players remotely, and recording what actually played. Each part had to work with the devices and connections already in the venues.
Naistro provides music and scheduled audio for physical venues. A venue can have several players, its own local time, and announcements that need to interrupt the music.
01 / Scheduling & interruptions
I moved the scheduling decisions into the backend.
A song can still be playing when an advert or prayer is due. The player needs to know what takes priority, where to stop, and where to resume. Station changes and the venue’s local time add more boundaries to that same day.
MY CONTRIBUTION
I moved playlist and interruption logic from the frontend to backend services and extended the scheduler. I worked on the day’s timeline, overlapping events, and saved track positions, along with the tools used to program and arrange the music.
THE IDEA, ILLUSTRATED
Interrupt, then resume in the right place
ONE TIMELINE · THREE PRIORITIES
3 / Prayer2 / Advert1 / Music
0s30s60s90s120s150s
Track A
Resume 35s
Resume 55s
Ad
Prayer
Playback offset is retained across the interruption.
Prayer takes priority. Music resumes after the interruptions.
Watch the music lane split around the scheduled interruptions. The second music segment continues from the saved position rather than starting the song again.
THE DECISION
Start on time without losing the song.
Giving an interruption priority solves only half the problem. I also had to preserve how much of the track had played, resolve conflicts between interruptions, and align what came next. Time-zone handling kept those decisions tied to the venue’s day.
WHAT CHANGED
Scheduling errors fell, and interrupted tracks could continue from their saved position. Operators gained more control over when content played and how it fit into the rest of the schedule.
Scheduling errors
−80%After moving playlist and interruption logic from the frontend into backend services.
I built the processing step between an upload and playback.
Uploaded audio still needed preparation: its format and loudness had to suit playback, and some messages needed silence around them. That work took time and depended on tools beyond the application runtime.
MY CONTRIBUTION
I built background audio processing with SQS and FFmpeg, stored the prepared files in S3, and packaged the required tools with Docker. I also worked on compatibility so newer processing could supply audio to existing players.
Uploaded audio waits in a queue while a worker prepares it for playback.
Uploading a file is only the first step. It waits for a worker, goes through audio preparation, and becomes available to play once processing finishes.
THE DECISION
Background work needs a visible outcome.
Moving processing into a queue let the request finish sooner, but the file was not ready yet. I handled processing and failure states and temporary-file cleanup. Compatibility work also had to refresh cached files and metadata so older players received the updated audio.
WHAT CHANGED
Audio preparation became an automated background operation. Content could be normalized and encoded without holding the original request open, with status available when processing failed.
Venues supported
3,000+Scale served by the automated track-processing pipeline.
I connected dashboard controls to the players in each venue.
An operator might need to pause several players or change a venue’s volume. Some devices could be connected while another was unavailable. A dashboard needed to make that situation understandable.
MY CONTRIBUTION
I built remote playback controls and worked on device connection state, heartbeats, and access to venue resources. I also added player notifications and editable product guides for the people using those controls.
THE IDEA, ILLUSTRATED
Connect a control with the receiving device
VENUE CONTROL · DIRECT WEBSOCKET FAN-OUT
DashboardConnected devicesWebSockets
Entrance65% volume
Main floor65% volume
Lounge65% volume
Adjust the volume. Available targeted devices receive the command.
Sending a command does not mean the player received it. Connection feedback shows when playback can be controlled and when the device is unreachable.
THE DECISION
A group command can have mixed results.
One unavailable device should not erase successful sends to the others. I returned per-operation delivery results and worked on aging connection state so a disconnected player would not look active indefinitely. A sent command still needed to be distinguished from observed playback.
WHAT CHANGED
Operators could control players remotely and see more useful information about their availability. The backend supported venue-level actions without treating the entire fleet as one device.
Inactive-device detection
20 secTime to detect inactive devices through real-time health monitoring.
I kept playback records from disappearing with the connection.
The schedule said what should play. Reporting needed to know what did play, including when a device lost its connection or a prayer interrupted a track. Sending each record immediately was not always possible.
MY CONTRIBUTION
I worked on actual playback-time accounting and a file-backed queue for unsent records. I also built monitoring for missed scheduled events, alert delivery, and reporting so the team could compare the plan with device evidence.
THE IDEA, ILLUSTRATED
Keep the record through a lost connection
OFFLINE RESILIENCE · LOCAL QUEUE
On the device3 pending
Playback 130s
Playback 230s
Playback 330s
Offline
Last batch received0Acknowledged records
Playback evidence can wait locally until the network returns.
Records stay on the device during an outage. When the connection returns, delivery resumes. A failed attempt keeps the records available for another try.
THE DECISION
Keep the record until delivery succeeds.
Removing a record when sending started could lose it on failure. I retained unsent records on the device and removed the sent batch after success. Monitoring had a related timing problem: it needed to allow for delayed evidence before treating an expected event as missing.
WHAT CHANGED
Unsent playback records could survive a restart and travel when connectivity returned. Monitoring made missed activity easier to investigate, with alert outcomes recorded separately from the detection itself.
The services needed to run in development and production with their dependencies in place. Audio processing made that especially concrete: code could be correct while the deployed container lacked a required media tool.
MY CONTRIBUTION
I owned CI/CD work using containers and AWS deployment services. I worked on the build and release steps so checked changes could follow a repeatable path into each environment.
THE IDEA, ILLUSTRATED
Move a change through checks to release
01 / CHANGEA new version
+ a product improvement+ a behavior check
02 / CHECKReady to test
Validate the change before releasing it.
03 / RELEASECurrent version stays
An unchecked change does not replace it.
Check the change before releasing it.
A change passes through checks before release. If a check fails, the current version stays in place while the issue is fixed.
THE DECISION
The runtime was part of the change.
A successful application build did not prove that the deployed worker had everything it needed. Container configuration and environment-specific settings had to travel through the release process alongside the code.
WHAT CHANGED
Deployment issues decreased. The team had automated release steps and a more consistent runtime for operating the backend.
Naistro took my backend work all the way to the player. I worked on the schedule it received, the audio it used, the commands it followed, and the records it sent back when the connection returned.