Web · 2026
SnapShop — an AI-assisted fashion marketplace
A live fashion marketplace on plain PHP and MariaDB: a storefront, a JWT mobile API, and four Groq-backed services for conversational search, outfit styling, and turning a photo into buyable products.
SnapShop is an AI-assisted fashion marketplace. I am its lead developer: the website, the catalogue and order systems, the mobile API and all four AI services are mine. The project belongs to its founder — this write-up is about the engineering.
One application, three surfaces
It is plain PHP 8 on MariaDB, deliberately framework-free: a hand-rolled front controller, services and PDO repositories. One codebase and one database serve three different consumers, and keeping the boundaries between them sharp is most of the architecture.
- The server-rendered storefront — landing, product pages, search, cart and checkout.
- The site's own AJAX API, authenticated by session, used by the website's JavaScript.
- A JWT mobile API, deliberately isolated from the website's session machinery — bearer token in, structured envelope out. Auth, products, search, cart, checkout, orders, shipping and the AI endpoints all speak it.
That isolation is a rule rather than a convention. Web requests and app requests never share an authentication path, so a change to how the website signs someone in can never quietly become a security question about the app.
Payments run through Stripe, shipping through Shippo, transactional mail through SendGrid, and sign-in through Google OAuth — each behind a single service class, so the marketplace is never coupled directly to a vendor's SDK.
Four AI services, and the rules they live under
Everything intelligent runs on Groq: conversational search, a budget-aware stylist that assembles whole outfits, visual search that turns a photograph into buyable products, and a catalogue enrichment pass that tags inventory so the other three have something substantive to reason over.
All four share one component. It loads the live catalogue once per request, hands the model a slimmed projection of it, and resolves whatever the model picks back to real database rows. Three rules are structural rather than advisory:
The model is never trusted for facts about a product. Price, slug, image and stock are always re-attached from the database after the model has answered. The LLM decides which products are relevant; it never gets to say what one costs or whether it is in stock. This is the single most important rule in the system, and it is enforced by where the data comes from rather than by asking the model nicely.
Picks resolve by numeric id, never by the title the model types back. Language models reconstruct text rather than quoting it — a rephrase, a changed capital or an added full stop are all normal output. An id is the only stable join between what the model chose and what the catalogue holds. Normalised-title and unique-substring matching sit behind it as fallbacks, and the resolver refuses to guess when a fragment is ambiguous: showing a customer a product they did not ask for is worse than showing them nothing. The behaviour is pinned by a test suite that runs without a server.
Every AI path has a non-AI answer behind it. Rate limits are a normal operating condition on any hosted model, so a limited response retries with backoff and then falls back to ordinary keyword search. A customer gets results, not an error page.
Treating a hosted model as a moving dependency
No model id is hard-coded anywhere in the system; each is an environment key. Hosted providers retire models on a published schedule, and a retired id fails every request made against it — so a provider deprecation should cost a configuration edit, not a deploy, and checking the provider's deprecation calendar belongs in the release routine rather than in an incident.
It is a small piece of plumbing that reflects the larger point: a third-party model is an operational dependency with a lifecycle, not a library you pin once and forget.
Where it goes next
- The quality ceiling is the catalogue, not the model. Search and the stylist reason over the attributes the enrichment pass produces, so richer inventory data raises every AI surface at once — more of the remaining upside is in the data than in prompting.
- The catalogue projection has a natural scale limit. Handing a model a slimmed view of the live catalogue is the right design at current size; well before that view stops fitting comfortably in a request, the same interfaces would sit on top of retrieval and embeddings instead, with nothing above them needing to change.