Dev.to AI 🤖 Ai 👁 0 📖 3 min read

We built an AI design SaaS for small businesses in two months: Next.js, Supabase, Stripe as merchant of record, fal.ai

Case study from Weblevo, a two-person web studio in Madeira. Brifora is our own product, so this is the honest version. The problem My co-founder runs a print and embroidery shop. Every week someone brings a

Case study from Weblevo, a two-person web studio in Madeira. Brifora is our own product, so this is the honest version.

The problem

My co-founder runs a print and embroidery shop. Every week someone brings a phone photo of a logo and asks for it on a t-shirt. The file is a 400-px JPG; the embroidery machine needs a vector; the customer has no designer and no budget for one. We built Brifora to turn "what the customer already has" into files that print.

What it does

  • Create: logo from a 6-question brief (4 variants, SVG from the start), product images, short video from a still.
  • Fix: background removal, new scene, 4× upscale, outpaint to banner format, object removal, free captions.
  • Brand: logo mockups on 8 products with a free position/curve editor, "more in this style" series, raster → SVG, brand kit, cross-stitch pattern from any image (yes, really — the shop does embroidery).

Credits-based pricing from €9/month. Four interface languages: EN, PT, UK, RU.

Stack

  • Next.js 16 on Vercel (App Router, server actions, edge route for OG images)
  • Supabase — Postgres, auth by email code, storage, RLS everywhere
  • Stripe Managed Payments — Stripe is merchant of record, so EU VAT, invoices and disputes are theirs
  • fal.ai — one gateway to all generation models (image, vector, video, and a small text model for the assistant)
  • Resend for email, ElevenLabs for the assistant's recorded voice, Vercel Analytics (no cookies, no banner)

Five decisions worth stealing

1. Every generation is a job. The browser enqueues; fal.ai calls a signed webhook on completion; a one-minute cron sweeps stragglers and refunds credits on provider failure. The user can close the tab. Video made this mandatory, but it fixed image flows too.

2. The model draws the blank; code places the logo. Asking a model to "put this logo on a mug" mangles the logo. We render an empty product, then composite the user's actual file with sharp — crisp, editable, and the "nudge it 20 px left" editor is free because no model is involved.

3. Prices live in one table. Every card, every page, every FAQ answer reads credit costs from the same source. We changed prices three times before launch and never had a stale number.

4. Language in the URL, not in a cookie. We launched with cookie-based language and Google indexed only English. Moving to /pt/, /uk/, /ru/ prefixes with hreflang took a day and was the single most important SEO change.

5. Launch mode as an env var. LAUNCH_MODE=open flipped the "coming soon" banner off at launch without a redeploy. Boring, and exactly what you want on launch day.

Things that bit us

  • allow_promotion_codes and discounts are mutually exclusive in Stripe Checkout. We apply the code server-side when the user typed one, and let Stripe show the field when they didn't.
  • Satori (next/og) can't render a 50-path SVG character; our OG cards are typographic.
  • Headless browsers are filtered by Vercel Analytics as bots — test tracking with a real user agent or you'll think it's broken.
  • fal.ai's bria/expand wants absolute canvas dimensions, not a ratio.

Timeline

First commit to public launch: about two months, one product owner, AI-assisted development (Claude Code did most of the typing; we did the deciding). Roughly 40 screens, tools and integrations.

Links

Questions about the stack are welcome in the comments — happy to go deeper on the job queue or the Stripe MoR setup.

📰 Read the original article on Dev.to AI

Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.