// project · eveluna

eveluna

Personalized audio bedtime stories for kids. An LLM writes the story, a TTS model narrates it, and the whole thing ships as a single Cloudflare Worker — provisioned, deployed, and kept honest by SST.

AI · LLM + TTSCloudflareTanStack StartWaitlist

Note: this page is an AI-generated summary of the project. The product, the code, and the stories behind it are real — the prose isn't hand-written.

// why

Kids' bedtime stories are usually one-size-fits-all: a book, the same characters, the same arc. eveluna is the opposite — pick an age, describe what the kid loves, and a fresh short story with calm narration lands a minute later. The real experiment is the build shape: one TanStack Start app, one Cloudflare Worker, one sst deploy, and you get a live product at a custom domain with D1 for the data and R2 for the mp3s. AWS Lambda + Cognito + DynamoDB collapsed into a single binary.

// look

eveluna landing page — personalized bedtime stories for kids
Landing. Invite-only while the waitlist fills up.
eveluna waitlist signup
Signup is email-only — the whole funnel is parent-friendly.
eveluna signup on mobile
Mobile-first: this is a phone product, at bedtime.
Story library, logged in
Library. New stories arrive as the admin seeds them.
A full story — Fern and the Singing Moon
A whole story in one screen. 2–3 minutes of reading, calmer than a feed.
Story on mobile
One hand, dim screen, bedtime voice.
Admin — approve waitlist signups, promote to admin
Admin. Approve a waitlister and they get a magic link within seconds.

// the deploy shape

A single sst.config.ts declares everything: D1 database, R2 bucket, three SST secrets, and the TanStack Start app wired to all of them. sst deploy --stage prod provisions the lot, publishes the Worker, and flips DNS on the custom domain. The auth layer is hand-rolled on top of D1 — invite-only waitlist, admin approval, magic-link (Resend) plus password, sessions in an HTTP-only cookie. All of it uses Web Crypto only; no Node APIs leak into the Worker bundle.

  • sst.cloudflare.TanStackStart — the Worker
  • sst.cloudflare.D1 — users + stories
  • sst.cloudflare.Bucket — audio mp3s
  • sst.Secret × 3 — OpenAI, Resend, session
  • drizzle-kit migrate — applied via D1 HTTP
  • Web Crypto PBKDF2 — password hashing

// stack

how it's built
  • TanStack StartUI + server in one app, React 19
  • Cloudflare WorkersSingle Worker serves everything
  • SST v4 (Ion)One `sst deploy` provisions the lot
  • Cloudflare D1SQLite for users, sessions, stories
  • Cloudflare R2Audio mp3 storage, zero egress
  • Drizzle ORMsqlite-core against D1 over HTTP
  • OpenAI chat completionsgpt-4o-mini writes the story
  • OpenAI audio.speechtts-1 narrates it, voice: fable
  • ResendMagic-link + waitlist notifications
  • Tailwind v4 + shadcnradix-maia preset, mobile-first

Story generation is admin-triggered — runs as a local CLI that calls OpenAI, uploads the mp3 to R2, and inserts a row in D1. The Worker itself never spends on OpenAI, which keeps the latency and cost envelope tight while the product is small.

// status

  • Live at eveluna.davidbroza.dev — waitlist open, first admin seeded, first story narrated.
  • Audio playback UI and server-side generation are the next two slices — the data model already supports them.
  • Personalization: child profiles, recurring characters that age with the kid, and story series that continue night after night.

// work together

Like what you see? I build products like this end-to-end — idea to shipped, front-end to infra. Hiring, have an idea you want made, or just want to poke at what I built here? Drop me a line — I reply.