active

Murmur

A voice-first notes app designed for fast, calm thought capture. Press and hold to record, release to transcribe.

Web AppNext.jsAIVoiceProductivity

Overview

Murmur is a voice-first mobile app for capturing fleeting thoughts in under 5 seconds. The core experience: hold a button, speak, release. No typing, no menus, no setup. Recordings upload instantly and sync across devices via Clerk authentication.

Built as an Android-first Flutter client with a Node.js backend, private Cloudflare R2 audio storage, and async AI for semantic search.

One gesture capture: press-and-hold → recording starts in under 200ms → release → auto-upload → saved. The user remembers the thought, not the app.

Core Features

  • Ultra-low latency capture — Press-and-hold maps directly to the recorder; no countdown or confirmation
  • Invisible sync — Failed uploads retry with exponential backoff; local file retained until success
  • Future Capsules — Time-lock a memo to unlock later (1 hour to 50 years) with lazy unlock + notifications
  • Semantic search — OpenAI embeddings over voice memos; cosine similarity ranking without a separate vector DB
  • Private by default — R2 bucket is private; playback uses signed URLs with a 1-hour TTL

Architecture

Flutter App ──► Clerk SDK ──► Clerk (Auth)
     │
     └──► Dio API Client ──► Nginx (SSL) ──► Express API (EC2)
                                                      │
                                    ┌─────────────────┼─────────────────┐
                                    ▼                 ▼                 ▼
                              PostgreSQL          Cloudflare R2      Clerk API
                              (Prisma)           (Private Bucket)   (JWT Verify)
  • Client: Flutter + Riverpod + Clerk Flutter SDK; record for capture, just_audio for playback
  • API: Node.js + Express on AWS EC2 (PM2 + Nginx); Clerk session JWTs only — no app-issued tokens
  • Storage: Cloudflare R2 (private); server normalizes AAC/M4A/Opus to MP3 via ffmpeg
  • Data: PostgreSQL + Prisma; compound index (userId, createdAt DESC) for instant library loads
  • AI: Async Whisper + text-embedding-3-small; never blocks the upload response

Audio Pipeline

  1. Client starts recording on press (<200ms)
  2. On release, multipart upload to Express
  3. Server validates MIME/size, converts to MP3 (128kbps mono), PutObject to R2
  4. Memo row created only after R2 succeeds (atomic — no partial records)
  5. Library updates optimistically on the client; AI embedding runs fire-and-forget

Outcomes

  • Sub-5s end-to-end capture path from gesture to saved memo
  • Zero custom auth stack — Clerk owns session lifecycle end to end
  • Dual upload paths: server-mediated (MVP) and presigned client→R2 (implemented, behind flag)

Reliability first: failed uploads retry silently in the background — no data loss, no friction.