skip to content
stevengates.io
back to home
case study·lead·since 2025

Mila Gates

A growing-up site for my daughter.

visit live publicNext.jsFamilyStorytelling
Mila Gates landing carousel — family photo timeline

the project

Mila Gatesis a private family site for my daughter — a growing-up timeline of photos, milestones, and written memories, captured month by month. The front door is a calm, mobile-friendly blog. The interesting part is what's behind it.

The whole site is wrapped in an agentic AI surface. I can ask — or speak — in plain English: “Find the photos from her first birthday,” “Pull up the post about her first steps,” “What did I write about the trip to Galveston?” The model searches the memory corpus, returns the right entry, and cites the source post.

what makes it agentic

The chatbot isn't a sidekick — it's the navigation layer. Under the hood, every blog post is ingested into an OpenAI Vector Store, and the chat surface uses OpenAI ChatKit with File Search (RAG) turned on. Ask a natural-language question, the model retrieves the matching posts, and the response stream includes citations back to the original entries.

Every blog post also has a TTS endpoint (/api/blog/[slug]/audio) that streams a voiced version of the entry. Family members who don't want to read can listen.

the stack

  • Next.js 15 App Router + React 19 — server components for the blog tier, route handlers under src/app/api/** for the AI + TTS endpoints.
  • Supabase for auth and content — Postgres + Row Level Security, a whitelisted-email auth flow so only family can see the protected segment.
  • OpenAI ChatKit embedded widget — exchanges a workflow ID for a per-session client secret via /api/chatkit/session, then renders the chat bottom-right. The workflow itself lives in OpenAI Agent Builder.
  • OpenAI Vector Store + File Search — the RAG tier. The chat stream attaches tools: [{ type: "file_search", vector_store_ids: [...] }] when a store ID is configured. Citations come back in the event: done SSE payload.
  • Edge-runtime streaming — the legacy /api/chat-stream route runs on the edge with SSE for low-latency token streaming and proper cancellation handling.
  • Bootstrap 5 + SCSS for the front-end shell. Deployed on Vercel with Analytics.

architecture in one paragraph

Posts live in Supabase. Posts are ingested into an OpenAI Vector Store. ChatKit renders a widget that talks to a session route, which mints a per-session client secret from the OpenAI workflow. When a family member asks a question, the workflow agent uses File Search to retrieve the relevant posts from the vector store, generates an answer streamed back token-by-token, and returns citations on completion. Voice playback of any post is a separate route that streams audio from the TTS endpoint. Auth is whitelist-based via Supabase RLS, so the protected segment is invisible to anyone outside the family allowlist.

why i built it

I have a daughter. I take a lot of photos. The phone's camera roll is a terrible memory system — chronological, unsearchable, and useless if you ever want to find the one moment. Mila Gates is the “I build for the people I love” piece. It's also the project where I get to feel good about agentic AI: a tool whose job is to help me remember.

what this demonstrates

  • Modern AI primitives in production. ChatKit, Vector Store, File Search, edge streaming, SSE with citations — wired end-to-end, deployed, in use.
  • Full-stack ownership. Auth, RLS, server components, edge handlers, RAG ingestion, TTS, embedded widget — all of it.
  • Pragmatic auth. Supabase + email allowlist instead of building a full identity stack. Right tool, right scope.
  • Agentic UX done quietly.The chat surface isn't a gimmick — it's the navigation. No forms to fill, no filters to click. Just ask.