Echo 🎙️

Your life, in your own voice. A voice-first journaling social app.


💡 Inspiration

We kept hitting the same gap in our own lives: we mean to journal, but we rarely do. Opening an app and typing is just enough friction that the moment passes — and the moments most worth keeping arrive when our hands are busy: walking home, cooking dinner, rocking a baby at 3 a.m.

And even when we do write, a typed line flattens the memory. It can't hold the laugh, the pause, or the way we actually sounded that day, a voice note can.

The second spark was language. In multilingual families, a grandparent and a grandchild often don't fully share one, so the small daily stories never travel between them.

So we built Echo: tap, talk, done - and it handles the rest. Speak it · keep it · share it.


⚙️ How it works

$$ \text{🎙️ record} \rightarrow \text{S3} \rightarrow \text{Transcribe} \rightarrow \text{Translate} \rightarrow {\text{EN}, \text{ES}, \text{FR}} $$

You tap record and talk. The clip uploads to Amazon S3 with a presigned URL, Amazon Transcribe turns your voice into text, and Amazon Translate adds Spanish and French automatically. The entry saves to your journal, kept private or shared into a social feed. The UI shows a "Transcribing…" state and fills in the real text the moment it's ready.


🗄️ Two AWS databases, chosen by data shape

The data has two shapes, so we used two databases - each where it's strongest:

Amazon DynamoDB Amazon Aurora PostgreSQL Serverless v2
Type Serverless NoSQL (key-value) Relational, autoscaling
Holds echo-entries, echo-social users, follows, chapters, comments
Role Recordings, transcripts, likes Profiles + the social graph
Powers Your journal Feed, follow, people-search

DynamoDB takes the append-heavy entry data; Aurora handles everything that needs joins — like building your feed from who you followtheir public entries.

Rest of the stack: Next.js 16 · TypeScript · NextAuth (Google + email) · Amazon Bedrock (Claude Haiku) · AWS CDK · deployed on Vercel.


📚 What I learned

  • NoSQL vs. relational is a data-shape decision, not a preference. Entries are append-heavy and accessed by key → DynamoDB. The social graph is all relationships and joins → Aurora. Using both, each where it's strongest, made the whole app simpler.
  • The RDS Data API is the unlock for serverless databases. Aurora lives in a private VPC, so it's normally unreachable from a serverless host like Vercel. The RDS Data API exposes it over HTTPS — so the entire app runs serverless with no VPC tunnel, no connection pooling headaches.
  • Orchestrating an async ML pipeline. Transcription isn't instant, so we designed around it: optimistic UI, then poll. With interval $\Delta t = 5\text{s}$ and a cap of $n = 30$ attempts, the wait is bounded by $T_{\max} = n \cdot \Delta t = 150\text{s}$, after which we surface a graceful state.
  • Serverless economics are linear. Aurora Serverless v2 scales in the range $\text{ACU} \in [0.5,\, 4.0]$, and DynamoDB on-demand cost is essentially $C \propto \sum_i (r_i + w_i)$ over read/write requests — so an idle hackathon app costs almost nothing, and it still scales if usage spikes.

🧗 Challenges

Hit a wall Got past it
Aurora unreachable from localhost (private VPC) Switched to the RDS Data API (HTTPS)
CDK wouldn't bootstrap (root tsconfig is ESM) Separate tsconfig.infra.json (CommonJS)
Bedrock model id invalid for on-demand calls Cross-region inference profile
Hydration mismatch on load Move localStorage out of the useState initializer
Playback was a fake progress bar Real audio via presigned S3 GET URLs
Feed entries had no author names Batch profile lookup in Aurora to enrich them
A like wrote a phantom negative counter Found in end-to-end testing; removed the dead write
invalid_client on deploy Set env vars (+ redeploy) and the OAuth redirect URI

🚀 What's next

Co-authored "chapters," offline capture for moments without signal, more languages via Amazon Translate, and richer AI reflections with Bedrock - so Echo becomes a living, multilingual record of a life, in the voice that lived it.

Built With

Share this project:

Updates