TryWordy

Rails 8 + Nuxt 4 · Claude · ElevenLabs

A calm vocabulary tool built solo, from design to deploy — Claude generates the cards, ElevenLabs speaks them, and a Rails API keeps the cost of both under control.

Visit trywordy.com
Role
Solo — product, design, frontend, backend, ops
Frontend
Nuxt 4 · Vue 3 · TypeScript on Vercel
Backend
Rails 8 API-only · PostgreSQL · Puma
AI
Claude Sonnet 4.5 (tool-use JSON) · ElevenLabs Multilingual v2
Billing & auth
Stripe Checkout · JWT multi-device sessions
Deploy
Kamal 2 to DigitalOcean · managed Postgres · zero-downtime

What it does

Paste a batch of words or phrases in any language and TryWordy returns clean vocabulary cards — definitions in both your target and native language, part of speech, register, synonyms and antonyms you would actually use, real example sentences, and natural pronunciation you can play back.

The whole product is built to feel like a well-made tool rather than a consumer app: no gamification, no mascots, no aggressive prompts. Just the lookup, done well.

Definitions: Claude, made reliable

The cards are generated by Claude Sonnet 4.5. Rather than parse free-form text, I have the model return its answer through a tool with a strict JSON schema, so every card has the same shape and a malformed response fails loudly instead of silently corrupting a card.

A single request covers up to twenty-five words and resolves every supported native language at once. The shared system prompt is marked for ephemeral caching, so repeated lookups within a short window reuse it at a heavy input-token discount — the kind of saving that only matters when one person is paying the bill.

Keeping a solo AI product affordable

An AI tool that anyone can hit is also a tool anyone can run up a bill on, so cost control is a first-class feature, not an afterthought.

Looked-up words are cached as dictionary entries; when several people request the same word at once, a Postgres advisory lock per word-and-language-pair lets exactly one request reach Claude while the rest wait for the result. On top of per-user quotas there is a global daily spend ceiling that scales with the number of paying users, so a bad day can't outrun the revenue. Email verification is required before any lookup runs, which closes the obvious abuse vector of farming disposable accounts to burn credits.

Pronunciation and the rest of the stack

Pronunciation audio comes from ElevenLabs' multilingual model, cached per word and voice so each clip is generated once and reused forever; the free tier falls back to the browser's built-in speech. Auth is JWT with per-device sessions so a logout or password change can revoke a single device. Billing runs through Stripe Checkout and the Customer Portal, with webhooks as the source of truth for which tier a user is on.

The Rails API ships to a DigitalOcean droplet with Kamal 2 for zero-downtime deploys, backed by a managed Postgres instance and Amazon SES for mail — with SES bounce and complaint notifications flowing back through an SNS webhook to suppress dead addresses automatically.

Why it matters

TryWordy is my proof of what zero-to-one-hundred looks like when I run the whole thing: the product decisions, the design, both halves of the codebase, and the operational details that decide whether an AI product is sustainable or just a demo.

Stack

Rails 8Nuxt 4PostgreSQLClaude APIElevenLabs TTS

← All selected work