Case study · Product engineering

Live in production

HymnDeck

Building an AI workflow that meets church teams where they already work.

Slide generation for people running on empty. HymnDeck turns a song sheet, document or WhatsApp message into the PowerPoint deck a small church already uses.

From a plain-language request to an editable, downloadable PowerPoint deck.

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 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.

Reality edited the roadmap

The useful discoveries were not all confirmations. Several wrong assumptions directly reshaped the product.

01Held up

Slide preparation was the bottleneck

The repetitive formatting work, rather than choosing songs, was consuming the time.

02Wrong

Lyrics lived in one master document

Some churches used folders of old PowerPoints as their source of truth.

03Wrong

Users would trust the output unseen

They wanted to review everything, which made a full slide editor essential.

04Broadly held

Difficulty stopped people switching

Workflow migration was a bigger obstacle than missing presentation features.

05Partly held

The worship leader was the buyer

The user and problem were clear; who would actually pay was not validated.

06Unproven

This was a paid product

Billing went live, but nobody converted from the free tier.

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.

01

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.

02

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.

03

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.

04

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.

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.

A request, progress updates and the finished PowerPoint delivered in the conversation.
01Bring the source

Paste, upload or send it through WhatsApp

02Generate safely

Structured AI tools with source constraints

03Resolve ambiguity

Use the visual editor or reply in the conversation

04Receive the deck

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.

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.

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.

01

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.

02

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.

03

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.

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.

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.

2churches using it weekly at peak
1still using it every week
Near £0running cost at current serverless usage
0customers converted from free to paid

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.

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.