
Mirra
Turns a folder of designs into finished Etsy and Shopify listings in one batch.
Solo build, commissioned · Sep 2024 – present · Live
Next.js · TypeScript · Express · Supabase · Google Gemini · Stripe
In production for a paying client; ~88K lines of TypeScript, 79 migrations, 26 services
Listing apparel on a marketplace is repetitive work: render a mockup, write a title, guess at tags, repeat. Mirra does a whole folder of designs in one batch and pushes the results into a seller's Etsy and Shopify stores as drafts. I built it as a commissioned project for one client and kept full IP. It runs in production today.
The problem
A print-on-demand seller uploads a batch of designs and then spends several minutes per listing on the same three things: a mockup photo, a title and thirteen tags that satisfy the marketplace's rules, and a description. Twenty to fifty designs at a time is normal.
The obvious fix is to ask a language model for the copy, and the obvious fix is wrong. A model with no market context invents keywords nobody searches for and will write a trademarked brand name into a title. The work is not generating text. It is generating text that is grounded and compliant.
Constraints
One client, a flat monthly subscription, and a hard cap of a thousand listings per cycle. That means the unit economics have to work per listing and cannot be waved away: every vision call, every page scraped, and every image composited costs money on a batch.
The marketplace rules are not suggestions either. Title length, exactly thirteen tags each at most twenty characters, description shape, and a trademark blocklist where a hit has to abort rather than retry. All of it runs as background work, so a process restart cannot lose a job or charge for one twice.
What I built
The metadata pipeline grounds generation in real data. A vision model reads the design and proposes search queries, a scraper pulls about fifteen live competitor listings for those queries, and a single structured call writes the Etsy and Shopify copy against that corpus. A validation contract checks every rule and re-prompts with the specific violation when something fails.
Because scraped competitor text reaches a model, I sanitize it and wrap it in delimiter blocks first, so the corpus is data and never instructions. Under all of it is a Postgres job queue with heartbeat leasing, a reaper for stuck jobs, and an idempotent ledger so a retry never bills twice.
What I owned
I built it alone: the Express backend, the Next.js frontend, the schema and its 79 migrations, the AI pipeline, the mockup compositing, both marketplace integrations, and the Stripe billing.
The client is the domain expert, not a collaborator on the code. He told me what a listing has to look like to survive Etsy's rules, what a good tag set actually does, and which of my early outputs read like a robot wrote them. That feedback shaped the validation contract more than any spec I could have written from the outside. The commission was his. The implementation and the IP are mine.
Results
It is in production for one paying client on a flat monthly subscription, and I kept full IP so I can sell it to other sellers later. The code is about 88,000 lines of TypeScript across two deployed apps, 26 backend services, and 79 migrations. Two marketplace integrations sit behind one push ledger with per-listing retry, and a ZIP export covers sellers who have not connected a store.
What I would change
I would cut scope earlier. I built a mockup template editor, revision history for the listing editor, and a usage dashboard before the metadata pipeline was reliable, and the pipeline is the only part the client would miss if it vanished.
I would also start with one marketplace instead of two. Etsy and Shopify share a push ledger now, but that shared abstraction came after I had written both integrations and seen what they had in common, which is the expensive order to discover it in. Cheaper: ship Etsy, get the client publishing, then generalize.