
An editorial e-commerce storefront for botanical hair care, with an AI hair chatbot, an "Angel" loyalty portal, and a live two-way inventory sync to the private engine.
View the product pageThe problem
Sell physical botanicals direct-to-consumer in ZAR with trustworthy local fulfilment, while keeping stock counts truthful against a single source-of-truth ops system, so the storefront never oversells.
.jpg&w=3840&q=75)
Architecture
A container-level view of the real system, the boundaries, the trust edges, and where intelligence and money actually flow.
The full order→inventory loop is documented as a sequence diagram on the handbook home. The manufacturing engine is ghosted: a separate, isolated system reached only over two signed webhooks (two different shared secrets, a 5-minute replay guard), so the store mirrors stock but can never author it.
.jpg&w=3840&q=75)
By the numbers
25
tables · 53 migrations
8
stored RPCs
2
signed webhooks (the loop)
≤60s
stock sync lag (ISR)
Stack
Intelligence
One fast model, Claude Haiku 4.5, runs the whole hair-care brain: a streaming conversational coach over a cached, ≥4096-token botanical knowledge base (marked ephemeral for cache hits), plus journal-history-aware daily tips and monthly reflections. Every call has a graceful fallback, so a mid-stream model hiccup surfaces as "Sanyu lost her thread," never a broken response.
Data model
25 tables · 53 migrations · 8 stored RPCs
Key decisions
Architecture Decision Records, the trade-offs made deliberately, in the open.
.jpg&w=3840&q=75)
The hard parts, solved
reserve / commit / release are SECURITY DEFINER RPCs over available = stock_count − reserved_count. reserve_stock does SELECT … FOR UPDATE, then a conditional UPDATE … WHERE stock_count − reserved_count >= qty, a row-locked compare-and-swap, so two simultaneous checkouts can never both claim the last jar (a NULL stock_count means untracked / unlimited).
A combo’s stock_count = MIN over its components of floor(component.stock_count / qty_per_combo), recomputed by an AFTER UPDATE trigger with a recursion guard. Base products stay the single source of truth, so a bundle can never show "in stock" while one of its components is sold out.
The ITN handler rejects any mismatched amount, bails early if the order is already paid, and flips to paid with a compare-and-swap UPDATE … .neq("status","paid") so a duplicate ITN returns already_processed instead of double-fulfilling. Side-effects run only after the guarded flip.
Sourced from sanyubotanicals, SUPPLY_CHAIN, supabase/migrations (25 tables), lib/inventory/stock.ts, app/api/payfast/notify, lib/shipping.ts.
.jpg&w=3840&q=75)
Keep exploring