I owned HymnDeck end to end: customer workflows, application architecture, AI orchestration, billing, infrastructure, deployment and production support. Every decision in this case study is one I made—and then had to live with.
- Role
- Founder and sole product engineer
- Timeline
- Core build: 1 March–1 April · WhatsApp added in August
- Users
- Two churches weekly at peak
- Status
- Live · near-zero running cost
The problem
The capable person gets every job
The person I built for is a worship leader at a church of 20–150 people who is already doing four other jobs on a Sunday. Worship, tech, rehearsals, song sheets, AV and slides often land with the same person because they are the most capable person available—which is exactly why nobody takes the work off them.
They write a song sheet, turn it into slides, then change the arrangement: a verse gets cut, a chorus gets doubled or the song is abridged the night before. Last week’s deck can no longer be reused. In a larger church the AV team absorbs the work in 15–20 minutes. In a small church it takes the worship leader about an hour, or two to three when the operator is less confident or the design is elaborate.
The cost was not only time. Someone who spent Saturday night fighting text boxes was not fully present when they led on Sunday morning.
Delegation did not work because teaching the slide system was another task for someone with no spare tasks. Existing worship presentation platforms were not short of features; migrating a decade-old workflow was simply a big, low-urgency project competing with things on fire that week. The intervention had to fit the workflow already in place: accept the song sheet they already write and return the PowerPoint they already use.
My first prototype was a deterministic parser. It worked for my church because users defined their own slide delimiters, then fell over at the second church. Lyric formatting is home-grown and inconsistent. A language model could absorb that variation without making users learn a new syntax, while a chat interface removed the last technical step.
Assumptions tested
Reality edited the roadmap
The useful discoveries were not all confirmations. Several wrong assumptions directly reshaped the product.
Slide preparation was the bottleneck
The repetitive formatting work, rather than choosing songs, was consuming the time.
Lyrics lived in one master document
Some churches used folders of old PowerPoints as their source of truth.
Users would trust the output unseen
They wanted to review everything, which made a full slide editor essential.
Difficulty stopped people switching
Workflow migration was a bigger obstacle than missing presentation features.
The worship leader was the buyer
The user and problem were clear; who would actually pay was not validated.
This was a paid product
Billing went live, but nobody converted from the free tier.
Product decisions
Automate the expensive part. Keep humans in control.
I started with song-sheet-to-PowerPoint because every user did it every week, it cost an hour on average and up to three at the tail, and it produced an artefact they already understood. Nothing else in their week had that shape.
Cut attractive distractions
I left out sermon slides despite demand. I did not have the domain knowledge or a validated buyer, and generic text-to-slides sat directly in the path of ChatGPT and Gemini. Song slides had libraries, recurring formatting and arrangement quirks that rewarded specialisation. I also cut agentic slide design because I did not yet trust models with unsupervised aesthetic decisions.
Follow the source of truth
I assumed every church kept one master Word document. After launch, I found churches that rehearsed from folders of old PowerPoints. That feedback created a PowerPoint-folder import path and the hardest engineering problem in the project.
Make review a feature
Users land in a block-based slide editor with control over lyrics, positioning and design. I was dogfooding HymnDeck for my own church and knew that silently changing a lyric was unacceptable. The model proposes; the user can inspect and correct.
Teach by getting out of the way
The first screen uses a familiar chat interface with an example of exactly what to paste. A 30-second explainer can expand or disappear. I repeatedly ran silent demos, watched where people hesitated and rewrote the opening flow around those moments.
After launch · WhatsApp
Distribution became a product constraint
The web product removed most of the slide-making work, but it still asked an overloaded worship leader to remember another product.
I took the original product principle—fit the workflow already in place—one step further and brought HymnDeck into WhatsApp. A user can send lyrics, images or documents, resolve ambiguous song matches in the conversation, choose a design and receive the finished PowerPoint without keeping a browser session open.
This is not a second generation engine. WhatsApp is a new control surface over the same source-grounded agent, deck model and organisation permissions. The web editor remains available when visual control matters; messaging makes the common path easier to start and delegate.
The integration is live, but it is too early to claim it solved distribution. It turns the lesson from the first launch into a testable product hypothesis.
Paste, upload or send it through WhatsApp
Structured AI tools with source constraints
Use the visual editor or reply in the conversation
Download it on the web or receive it in WhatsApp
Architecture
Serverless by constraint, not by slogan
A Next.js workspace and WhatsApp Cloud API webhook feed the same FastAPI service and shared agent state. Long AI work leaves both request paths through Cloud Tasks, runs in a private Cloud Run worker and returns through either the web application or a durable outbound-message queue.
- 01InputChurch teamLyrics, documents and design intentstart with what they already use
- 02Control surfacesWeb + WhatsAppNext.js workspace / Meta webhookssign in, message or review
- 03Public serviceFastAPICloud Run / Python / Uvicornvalidate, persist, respond
- 04QueueCloud TasksAuthenticated task deliverythe request can end here
- 05Private serviceAgent workerAI orchestration + document toolingno public ingress
- 06Delivery.pptx + previewweb download / WhatsApp documentdurable outbox + signed fallback
Explore the full technology stack
Frontend
Next.js 16, React 19, TypeScript, Turborepo, Bun workspaces, Tailwind CSS 4, Zustand, Framer Motion, Konva, React-Konva, dnd-kit, Firebase, next-themes, React Dropzone, React Markdown, Remark GFM, react-colorful and JSZip.
Backend and data
Python 3.14, FastAPI, Uvicorn, Pydantic, SQLAlchemy 2 async, asyncpg, Alembic, channel identities, agent sessions, a database-backed delivery outbox, Neon PostgreSQL and in-memory SQLite tests.
Infrastructure
Public and private Cloud Run services, Cloud Tasks, Cloud Storage, IAM service accounts, Secret Manager, Firebase Auth and Admin SDK, Google OAuth, Meta Graph and WhatsApp Cloud APIs, Docker multi-stage builds, uv and gcloud.
AI and documents
OpenRouter through the OpenAI Python SDK, configurable vision and tool-calling models, persisted agent activity, python-pptx, OOXML, LibreOffice, Poppler, Pillow, python-docx, pypdf, ZIP/XML inspection and bundled fonts.
Three engineering problems
The parts worth writing about
The difficult work was not producing a good demo. It was putting unreliable inputs and probabilistic models inside a workflow people could depend on every week.
Constrained AI
Make a probabilistic component behave predictably
The problem was never getting a good answer from a model. It was guaranteeing the model could not do something unacceptable.
Silently altering a lyric is unacceptable in worship software, so I treated hallucination as an authorisation problem. The model never touches the database or PowerPoint file. It selects typed tools whose Pydantic arguments become OpenRouter function schemas; unknown arguments are rejected before execution.
Server-side rules require an authorised source for lyric changes, flag wording absent from uploaded material, scope tools by organisation and design, and require confirmation for higher-impact or shared mutations. Draft and committed decks are separate objects, so proposing and persisting are distinct steps and users review ambiguous matches.
I compared GLM 5, Kimi K2.5, Gemini 2.5 Flash, Gemini 3 Flash and MiniMax M3 on representative HymnDeck tasks. That exposed a weakness in comparing models by token price and latency alone: less capable agents sometimes produced malformed tool calls or needed several attempts to complete one operation.
I reduced the initial tool surface to a small set of core capabilities, allowing the agent to activate additional tool groups only when the workflow requires them. I then moved the web and WhatsApp agent to GPT-5.6 Luna. Its lower price and better first-pass tool reliability made it cheaper per completed task—not merely cheaper per token. Gemini 3 Flash remains the constrained formatter.
Automated tests cover tool schemas, invalid arguments, permissions, source requirements, wording preservation, provenance, confirmation, failures and observability redaction. A scored model-evaluation dataset remains the clearest testing gap.
Real-world files
Ingest messy PowerPoint libraries in Cloud Run
A folder of old presentations turned a text-parsing feature into a file-infrastructure problem.
Formatting varied too widely for a deterministic lyric extractor, so the system reads PowerPoint XML with a language model. Older files are converted by headless LibreOffice. Parallel conversion was unreliable in the container, so I serialised that stage and accepted latency in exchange for dependable completion.
Uploads went through three versions: asking users to make ZIP files; packaging selected folders in the browser with JSZip and no compression; then, when larger libraries hit Cloud Run’s 32 MiB request limit, transferring files directly to Cloud Storage through signed URLs while the API handled metadata only.
Conversational reliability
Make slow AI feel native inside messaging
A webhook can be retried, a model can time out and the user can send another message while both are happening. The conversation still has to make sense.
Signed Meta webhooks are verified and normalised into durable records, then Cloud Tasks carries long-running work to a private worker. Provider message IDs, task-identity checks and commit-visibility retries make retried webhook delivery safe. Persisted agent sessions preserve reply context, while newer requests can supersede stale runs. Typing indicators and bounded working-status messages make progress visible without pretending generation is instantaneous.
Results leave through a database-backed delivery outbox with leases, retries and delivery receipts. The dispatcher respects WhatsApp’s customer-service window and can notify the user through a configured, approved template when direct delivery is blocked. Otherwise it waits for the next inbound message to reopen the window. A PowerPoint that is too large for direct media delivery falls back to a signed download. Model calls, tool calls and wall-clock duration are bounded so a stuck run can reach an honest terminal state.
Other people’s content
Hold little. Invent nothing.
The model only formats material supplied by the user; it never fills lyrics from training data. Transient source files are normally removed from active storage after about 48 hours and message content after about seven days; operational records retain only what is needed to recover and audit delivery. The generated deck structure persists for the life of the account because deleting somebody’s slides after 30 days would be hostile.
Customer content is scoped to the authenticated organisation. WhatsApp identities are connected through expiring, single-use tokens and relinking archives old conversational context before trust scope changes. Drive imports are restricted, URLs are allowlisted, and verbose model traces are off by default with unsafe values redacted during debugging.
Production work
The work nobody demos
Two Cloud Run services are deployed separately, with the worker private and reachable only through authenticated Cloud Tasks. Ordered Alembic migrations cover the initial schema, billing, multiple designs, background jobs, agent sessions, asset provenance, channel identities, delivery state, export snapshots and legacy data removal.
Secrets arrive through Secret Manager rather than the image. Warm-up logic covers Cloud Run, Neon, Firebase and the model client so the first request of the week is not the slow one. Persisted runs, model requests, tool calls and durations provide application-level observability; proper alerting would come before scale.
Results, honestly
Useful product. Real users. No commercial traction.
One church closed; the other still uses HymnDeck every week. A workflow that took about an hour—and up to three at the worst end—now takes minutes. The product has run in production since April without manual intervention to keep it alive. WhatsApp is now live as a second way into the same workflow; there is not yet enough usage to claim it changed adoption.
Billing was built, live and integrated, but nobody converted from the free tier. I under-tested willingness to pay and built a system whose engineering depth outran its distribution. Product risk, technical risk and distribution risk are different things; they need testing in a different order than the one I chose.
What I would do differently
Review the intent, not only the code
I built HymnDeck largely through agentic coding. The failure mode was rarely broken code; it was code that missed the intent. A chatbot bug would prompt a hyper-specific new tool instead of a better prompt using existing primitives. Architecture suggestions quietly depended on Cloud Run at min-instances: 1, discarding the serverless economics. Parsers handled the examples I supplied and nothing beyond them.
Reading a diff for product intent—not just correctness—was the highest-leverage habit I developed. Given another month, I would also make the system friendlier to newer agentic models. Worship leaders need slides that are consistent and pleasant, not bespoke; a fast agentic designer can now reasonably own more of that work.
Working alone made me quick and made me sloppy. I spent too little time on architecture up front, context-switched across product, frontend, backend, infrastructure and support, and let scope creep arrive without anyone asking why. On a team I would introduce lightweight design reviews early—especially around retries and tenant isolation—and go deeper in one area rather than shallow across all of them.
What this is evidence of
I know what shipping costs because I have owned what happened after launch.
I have done the messy end-to-end work of turning an AI product idea into functioning production software: product decisions, wrong assumptions, failure cases, deployment, users and ongoing responsibility. I am an early-career engineer who can contribute where product thinking, application engineering and AI-enabled systems meet.