A user uploads a photograph of a room, picks a design style and a room type, and gets back a redesigned photograph. The image is encoded client-side and posted to a serverless function that calls a Gemini image model with a long, specific prompt: preserve camera angle, room footprint, wall, window and door positions, and the real exterior view through the windows, while replacing every finish, fixture, appliance and furnishing to match the chosen aesthetic.
The generation path is shaped by a hard constraint. Netlify kills synchronous
functions at 26 seconds, so the function runs against a fixed internal budget —
most of it against gemini-2.5-flash-image, falling back to
gemini-3-pro-image-preview with whatever remains — deliberately leaving headroom
to run the credit-refund path if generation fails. Credit deduction uses an
optimistic-locking update guarded on the user’s current balance to avoid
double-spend, and a refund RPC fires from a finally block, which exists
specifically because a hard timeout would skip an ordinary catch.
Anonymous users get three free generations; creating an account adds ten credits. Paid tiers run through Stripe Checkout with a webhook granting credits on completion. Two anti-abuse layers sit on the free path: a per-identity daily cap and a global site-wide daily cap on zero-credit generations, the latter described in the code as a circuit breaker bounding worst-case daily model spend even if an attacker rotates anonymous identities.
Supabase provides Postgres, magic-link auth, and row-level security. Only the Supabase anon key reaches the client; the Gemini, service-role, and Stripe keys are server-side only.