Key takeaways
- The AI call is the smallest part of an AI image product. Most of Preloom's engineering went into what surrounds it: storage, billing, batch work and sharing.
- Batch design grids run several images at a time in the background, and their progress lives in the database, so a server restart costs minutes, not designs.
- Credits are charged at the last possible moment and refunded automatically when generation fails, so users never pay for an image they didn't get.
- Around 500 automated tests run with every outside service faked, so the whole product is checked in seconds without spending a single credit.
Preloom is an AI tool that turns a fabric photo into photoreal garment designs and model shots for textile brands. Making one good image was the easy part. The real engineering was making it dependable at volume: batches of designs that finish even when servers restart, billing that never charges for a failed image, and links buyers can review.
This post covers how Sprout engineered it. For what Preloom does and who it is for, see the Preloom case study.
The shape of the system
Preloom has two parts. A Next.js web app handles everything the user sees, and a Python (FastAPI) service does the heavy work: generating images, charging credits, and storing files. Records live in a managed database, and every image sits in private cloud storage. Nothing is publicly addressable. The app receives short-lived signed links that expire within the hour.
Users choose between several image quality tiers, each backed by a different AI model. Every generation request goes through the same path whichever tier it uses, so adding or swapping a model is a contained change rather than a rewrite. That mattered more than we expected: image models improve every few months, and a product tied to one vendor ages with it.
Fabric is the core object, not the image
Our first version treated each generation as a one-off: upload a photo, get a picture. Real users don't work that way. A textile brand has a set of fabrics it designs with again and again.
So fabric became its own record. A brand uploads a swatch once, adds details like its name and composition, and uses it in any number of designs. Saving a fabric is free, and only generation costs credits. Every design keeps a link back to the fabrics it was made from, so a brand can open a fabric and see every design it has produced.
Designs also have a family tree. When a user tweaks a design ("shorter sleeves", "deeper neckline"), the result records which version it came from. Versions form a tree of any depth, and the app can walk it to show a design's full history from first draft to final.
Batch grids that finish
The feature brands use most is the batch: pick several fabrics and several garment styles, and Preloom generates every combination as a grid. Twelve fabrics across four silhouettes is 48 designs, each a slow AI call.
Three decisions made this dependable:
- Submit returns at once, and the work runs in the background. The user watches the grid fill in, square by square, and can leave the page and come back to it from a list of running batches.
- Several designs generate at a time, not one after another. A 12-design batch used to be a 12-call queue. Running a few in parallel cut the wait sharply without overwhelming the image providers.
- Every square's progress is saved as it happens. If the server restarts mid-batch (it does, on every deploy), it picks up the unfinished squares when it boots. A restart costs a few minutes, not the designs.
One bug from this work is worth sharing. An early version of the grid page reloaded the user's entire design history each time a square finished. With a large account and a busy batch, that turned into a loop of full reloads and exhausted a database read quota. The fix was to have each finished square carry its own image link, so watching a batch now costs the same couple of reads whether a brand has ten designs or ten thousand. We added a test that counts reads, so it can't regress quietly.
Billing that's fair
Preloom sells credits, and an image's cost depends on the quality tier. AI calls fail sometimes, so the billing rules needed to be clear and enforced in code:
- Charge last. Credits come off only after every check has passed and the inputs are ready, immediately before the AI call. A bad upload or a missing permission never costs anything.
- Refund failures automatically. If the AI call fails, the credits go straight back, and the ledger records both the charge and the matching refund.
- Reserve for batches. A batch reserves its credits when submitted, using the settings in force at that moment, so changing a preference mid-run can't reprice it. Cancelling refunds only the designs that never ran.
- Keep an audit trail. Every charge and refund is written to an append-only history per account, so any balance can be explained line by line.
Getting this right meant guarding against double refunds as well as missed ones, since a retried request or a restart could otherwise refund the same failure twice. Each refund is recorded with a unique key, so repeating it has no effect.
Sharing with buyers
A brand's real goal is a buyer's yes. Preloom lets a brand group designs into a collection and send a link. The buyer needs no account: they can approve a design, request a change, or leave a comment, and the brand sees unread feedback on the collection.
Because the link grants access, it is treated like a key. Links can be rotated or revoked, revoking one actually cuts off the old link, and shared pages are hidden from search engines. It is the only part of Preloom that accepts input without a login, so it does the minimum and checks everything.
Never stall the server
AI image calls take seconds, and so do storage uploads. In a Python web server, one slow call made in the wrong place freezes every other request, including the health check the host uses to decide whether the server is alive. We found this the hard way and moved all slow work off the main request loop. A dedicated test runs two requests at once and fails if one has to wait for the other.
Testing without spending credits
Preloom has around 500 automated tests across the backend and the web app. Every outside service, including the AI models, storage, the database and payments, is replaced by a fake in tests. The full suite runs in about a second, never spends a credit, and can't touch real data. That speed is what lets us change billing or batch logic with confidence: the rules above are each pinned by tests, including the failure cases.
What carries over to your product
Preloom's lessons apply to most AI products:
- The model call is the easy part. Budget most of the engineering for what surrounds it.
- Make slow AI work resumable and visible, or users will retry it and pay twice.
- Design billing around failure from day one. Charge late, refund automatically, keep a ledger.
- Keep the model swappable. The best model next year probably isn't the one you start with.
If you have an AI product that needs to work this reliably, talk to us about building it.