Consumer / Music

3693: a private music app in Flutter and Firebase

A private music app built with Flutter: search, a now-playing screen with lyrics, a queue, playlists, liked songs, a cloud library, listening stats and light and dark themes, on a typed Firebase backend.

Our role: Our own product, designed and built by App369 founder Simon Dziak, who made every commit in the repository. It is a private app for its owner and friends.

The Problem

What 3693 Needed to Solve

The repository's own QA report calls 3693 "a small private app (owner plus friends)". That changes the brief. There is no store growth target, so the work goes into the parts a listener feels: audio that keeps playing in the background, a queue that stays correct when someone taps next five times in a second, and a library that follows the account from one device to the next. The commit history shows two phases: a burst of features in February, then correctness and polish in August. A 103-finding multi-agent QA review in between shaped the August hardening, and the lessons below come from it.

The Build

How We Built It

A Flutter app plays audio with just_audio and audio_service, so playback continues in the background and shows on the lock screen. GetX handles sign-in and routing, and a Provider-based player controller holds the queue and playback state. Hive keeps liked songs, recent searches, recently played tracks, playlists and settings on the device. Firebase Auth signs people in, and the cloud library and playlists live behind callable Cloud Functions written in TypeScript. Every function sits behind one auth wrapper that checks the caller before any code runs.

Features

What the Product Does

Search and playback

Search with recent searches and trending chips, a mini player, and background playback with lock-screen controls and a working scrubber.

Now playing

A waveform seek bar, lyrics with the current line highlighted, shuffle, repeat, a sleep timer, a shader-based visualizer and haptic feedback.

Queue

A queue screen where tracks can be reordered or swiped away, and a retry that skips to the next track when one fails to load.

Library

Playlists, liked songs, recently played and a cloud library saved to the account.

Listening stats

A stats screen with top songs, top artists and an hour-of-day heatmap, plus a card that can be shared.

Light and dark themes

One palette object defines both themes, and the interface takes accent colors from the current artwork.

Accessibility

Screen-reader labels, reduced-motion handling (with a test) and a layout for tablets.

Architecture

The Stack, Layer by Layer

Client app
Flutter and Dart. GetX for auth and routing, Provider for the audio controller, just_audio and audio_service for playback, Hive for local storage. The repository has about 18 screen files.
Backend
Cloud Functions (2nd gen) on Node.js 22 in TypeScript. Callable functions for account and profile, library and playlists, each with typed request and response interfaces and input validation.
Auth middleware
A requireAuth wrapper rejects unauthenticated calls and can also require a verified email or an admin flag. Handlers receive the verified user id rather than reading one from the request body.
Security rules
Firestore and Storage rules are kept in the same repository as the functions.
Testing
52 Flutter test files cover controllers, services, screens and widgets. A separate device walkthrough signs in, visits every screen in both themes and saves a screenshot of each.
Release
A preflight script gates TestFlight archives (see the lessons below).
By the Numbers

Verifiable Facts

Feb 2026
First commit to the repository
Aug 2026
Most recent commit (August 15)
42
Commits, all by one author
52
Flutter test files, plus a device walkthrough
103
Findings confirmed by the multi-agent QA pass

Counted from the private source repository on October 13, 2026. This page makes no claims about listeners, installs or revenue.

Lessons

What We Learned Shipping It

A test run can end up inside your release build

The device walkthrough runs with flutter drive, which rewrites the gitignored ios/Flutter/Generated.xcconfig so FLUTTER_TARGET points at the test file. An Xcode archive taken afterwards would ship the test as the app: it would sign in, flip themes and tap through tabs on its own. Nothing in the repository showed it. The fix is tool/release_preflight.sh, which regenerates the config from lib/main.dart, fails unless FLUTTER_TARGET is lib/main.dart, checks the analyzer and the tests, and prints the build number to bump.

Key things by id, never by title

The QA pass found song identity derived from the display title in many places: the now-playing highlight, the like button, the queue keys. Same-title songs collided. The worst case was listening stats, which were built on a box keyed by title, so a replay overwrote the earlier play and the counts were wrong. The report ranked it as the one critical finding.

Do not rebuild the tree on every position tick

The player was a single app-wide ChangeNotifier that notified listeners on each position update, about five times a second, so large parts of the interface rebuilt continuously while music played. The report also found animations and timers that never stopped when paused. The August commits worked through these in batches.

Have the polish reviewed by someone else

The QA pass was run by several AI agents across 12 areas, and every finding was re-checked against the code before it counted: 103 confirmed (1 critical, 7 high, 24 medium, 71 low). It also caught a build break, where the app's own RepeatMode enum collided with one newly exported by the Flutter SDK.

Replace a half-built feature with a real one

A high-contrast toggle saved its setting but no screen read it. The review caught it, and the August theme work replaced it with a single light/dark palette used by every screen.

Technologies Used
Flutter•Dart•just_audio•GetX•Provider•Hive•Firebase Auth•Cloud Functions•TypeScript
Timeline
February to August 2026 (commits from February 11 to August 15)

Planning Something Similar?

We build Flutter and Firebase apps for startups and small businesses. Get a ballpark with our app cost calculator, see Flutter development, or tell us about your project.

More Case Studies

SaaS / Business software

Workspace369: a Flutter and Firebase SaaS for client work

An all-in-one workspace for freelancers and small service businesses: CRM, proposals, invoicing and payments, scheduling, a shared email/SMS/voice inbox, accounting and AI, in one Flutter app on iOS and the web.

Read Case Study →
AI / Image processing

Deep Dream: a Flutter app and a PyTorch queue behind it

A Flutter app sends a photo to a Python API. A Redis queue hands the job to a PyTorch worker that runs DeepDream on a convolutional neural network, and the dreamed image comes back to save to the gallery.

Read Case Study →
Consumer / Collectibles

DG Card: scan a trading card and match it on the device

A Flutter app for trading card players. Point the camera at a card, on-device text recognition reads it, and the app matches it against a synced card database. From there you track a collection, build decks and trade with other players.

Read Case Study →
Automotive / Security hardware

Bull Horn GPS Alarm: one-tap SMS commands for an alarm

A Flutter app that works as a remote control for GPS vehicle and asset alarms. Each alarm is saved once with its phone number and password, and every command after that is one tap.

Read Case Study →
Landscaping / Field sales

Artificial Grass Masters: a field estimator and job sign-off app

A Flutter app for an artificial-turf installer. A rep measures a yard on a map, prices the grass, delivery and dumpster on the spot, and closes the job with photos, a customer signature and a rating. The company gets a text message when a new rating comes in.

Read Case Study →
AI integration / Open source

saas-mcp-connector: a safe MCP server for a SaaS API

An MCP server that lets Claude Desktop, Claude Code and other MCP clients use a SaaS product's API safely. Every call is scoped to one user's workspace, writes need explicit confirmation, and the HTTP transport is rate limited.

Read Case Study →