Project Details
The problem
A client portal needed the ability to record a real meeting directly from the browser and have that recording land somewhere a human could review and approve it, with a real deadline: the feature had to exist, work, and be testable before a specific meeting the next day.
The obvious risk with any “record now, upload later” design is the failure mode that’s easy to miss until it actually happens live: a 60-to-90-minute recording lost entirely because one upload at the very end failed. That risk shaped every design decision below.
What was built
Chunked capture from the first second, not one recording at the end. The browser records in short segments and uploads each one as it’s produced, rather than holding the whole recording in memory until the person clicks stop. If a network connection drops mid-meeting, even for several minutes, recording keeps running locally, already-captured segments stay queued, and the queue drains and catches up automatically the moment connectivity returns. There is no single “final upload” moment for the whole recording to depend on.
A durable, idempotent ingest path. Each segment is written to disk and confirmed durable before the browser is told it succeeded, so a segment the browser believes uploaded really is safe even if something crashes a moment later. A retried upload (the browser’s own safety response to an uncertain network response) overwrites the same segment cleanly rather than duplicating or corrupting the recording.
Gaps are surfaced, never hidden. If some segments genuinely never arrive (a real, sustained outage), the system assembles the best recording possible from what did arrive and logs exactly what’s missing, rather than either refusing to produce anything or silently pretending the recording is complete.
Technology choices, and why
Browser-native recording (MediaRecorder) over a native app or plugin. The deployment target is “anyone on the team, no install,” and the browser’s own audio-capture API is now reliable enough for this use case without adding a client to build and distribute.
A small, dedicated ingest service rather than routing raw audio through the same path as the rest of the platform’s API traffic. Audio chunks are a genuinely different shape of traffic (binary, streaming, size-variable) than the JSON API calls the rest of the platform handles, and isolating the capture path meant it could be built, tested, and reasoned about independently. It was also, deliberately, designed from day one to also carry a second, unrelated real-time feature the platform needed next, rather than being single-purpose.
Deliberately decoupled capture from processing. The service that receives and stores audio does exactly that and nothing else. Turning a finished recording into a transcript and a reviewable summary is a separate, later step. A slow or failed transcription run can never corrupt or lose the raw recording it’s working from, because the two are not the same system.
Outcome
Built and real-tested in one evening: the ingest path was exercised with real audio, including a deliberately introduced gap to confirm the missing-segment detection actually works and a repeated upload to confirm retries are handled cleanly, not just read through as code. One real bug was found this way, not by inspection: the audio-repair step worked correctly from an interactive shell but silently failed under the actual background service, because the service’s own environment didn’t share the shell’s configuration. Caught and fixed before it could matter, specifically because the pipeline was run for real rather than trusted on the strength of the code alone.