Zemeromo
A gospel music platform I designed and built end to end: private streaming, encrypted offline downloads, prepaid album cards and artist payouts. Pre-launch.
Founder & Full-Stack Engineer · Feb 2026 — now · Flutter, Node.js, MongoDB, Cloudflare R2 · Visit
Pre-launchAndroid app in device testing
Status: pre-launch. The Android app, API and worker are built and in device testing. There are no public users yet, and a launch date isn't set.
The problem
Ethiopian gospel music mostly spreads through Telegram forwards, YouTube re-uploads and memory cards. Artists rarely get paid for it, and listeners can't easily find full albums or lyrics. The global streaming services don't help much: they assume cards and fast, cheap data, and they pay out in ways local artists can't use.
Choirs have their own problem. Whole church teams rehearse the same songs every week, but they share them by forwarding files and printed lyric sheets.
Zemeromo is built to change that, with local payments, payouts artists can actually receive, and listening that still works on expensive or unreliable data.
What I built
A three-sided platform for listeners, verified artists and choir teams:
- Listeners browse and stream free music, buy albums or singles, read lyrics, build playlists, follow artists and download music for offline listening.
- Artists apply for verification, then use an in-app Studio to upload songs and albums with lyrics and artwork, set prices, publish drafts, mint prepaid album cards, track 28-day numbers and request payouts.
- Choir teams create or join a team, share a library, and plan dated service setlists. A rehearsal mode shows large, scalable lyrics so a choir can sing from one phone.
- Admins handle artist verification, editorial and sponsored placements, announcements and payout completion.

My role: I designed and built the whole platform: product and UI design, the Express API and background worker, the Flutter Android app, and the Next.js public site and admin.
Architecture
- Mobile: a Flutter Android app (Riverpod, go_router, Dio). Playback uses just_audio and audio_service, with background controls, a queue with shuffle and repeat, session restore, sleep timers and playback speed.
- API: Node.js, Express 5 and TypeScript over MongoDB. It runs with helmet, request validation and rate limiting, and has 57 integration test files run on mongodb-memory-server in CI.
- Worker: a separate background process for media transcoding, payment recovery, personalisation and event delivery, so slow work never blocks an HTTP request.
- Media: audio files are private. Production uses Cloudflare R2 for audio and Cloudinary for images, and clients only ever get short-lived signed links: 30 minutes for streaming, 15 for downloads.
- Web: Next.js 16 and React 19 for the public site and admin portal.
Publishing pipeline
When an artist uploads a song, the API stores the original privately, saves a draft marked processing, and queues a media job. The worker claims the job atomically, checks the audio with ffprobe, and uses ffmpeg to produce a 128 kbps AAC stream and a 256 kbps high-quality download. Failed jobs retry with backoff, up to five attempts, and jobs stuck on a crashed worker are picked up again. A song only goes live once its audio is ready.

Hard parts
1. Getting money right
Payments are where a platform for artists earns or loses trust, so the money path is built defensively:
- Never trust the browser redirect. Chapa checkouts for albums and singles are confirmed only by a signed webhook or a server-side check with Chapa.
- Recovering missed webhooks. Every 10 minutes the worker re-checks pending checkouts between 15 minutes and 7 days old, backing off as they age, so a buyer who closed the app still gets their album.
- Transactions all the way through. Sales, card redemptions and payouts run as MongoDB transactions, so a half-finished sale can't grant access without recording revenue, or the other way round.
- Idempotency keys on checkout, card redemption, card minting and upload, so a retry on a flaky connection replays the original response instead of charging or minting twice.
- Payouts artists can receive: Telebirr, CBE Birr or bank transfer. The available balance subtracts both completed and pending payouts, and only one request can be pending at a time, so an artist can't withdraw the same money twice.
2. Selling music without cards
Most listeners don't have a way to pay online, so artists can mint batches of prepaid album cards (ZMR-XXXX-XXXX, with a QR code) to sell in person, for example at concerts and churches. Each card is redeemed once, checked for expiry and existing ownership, and records revenue against the album. Unsold cards can be revoked.
3. Listening on costly, unreliable data
- Stream cache: recently played audio is cached (500 MB by default), and the player prefers a local file over the network.
- Offline downloads: the server issues download grants that are renewed every seven days, and files are stored encrypted with AES-256 using a per-install key. The download engine runs in the background and keeps records per account.
- Resilient playback: the player renews expiring links in the middle of a session and restores the last session after a restart.
4. Protecting artists' work
Audio is never public. Stream and download links are signed and short-lived, other apps can't capture playback, downloads are encrypted, and a purchased album can't be passed along by forwarding a file. That is the problem artists face today.
Where it stands
All of the core flows are implemented in the codebase: publishing, the player, purchases, prepaid cards, payouts, teams, setlists and offline downloads. The Android app is at version 0.1.1 and in device testing.
The work left before launch is mostly setup and verification, not new features:
- verifying payments, push notifications and downloads with live providers on real phones
- production deployment, monitoring and release signing
- finishing the admin website and public share pages
- full Amharic interface translation (the UI is in English today)
What I learned
Building a marketplace taught me that the hard engineering is in trust. Artists need to believe the numbers, and buyers need to get what they paid for even when the network drops in the middle of a checkout. Most of the backend's complexity — transactions, idempotency, payment recovery, signed media — exists for that reason.