Inventory pipeline
How the wholesale seed becomes retail units, Supabase records, and storefront inventory.
Inventory pipeline
The prototype uses the public Smoke Empire / Skokie Wholesale catalog with the client's reported permission. The raw scrape remains the source record; retail naming and per-unit pricing are derived in a separate, reversible normalization step.
Current catalog
The checked-in seed contains 2,201 wholesale products and 6,868 source variants. The retail builder currently selects 1,323 available products and produces 3,003 shopper-facing variants.
Four supplier variants are marked available with a zero price. They remain in the audit report but are excluded from storefront and import-ready variants.
Retail-unit normalization
Wholesale package text is not treated as one universal count. For example:
4pk - 10ct Boxbecomes one retail 4-pack at one tenth of the box cost.20pk - 12ct Displaykeeps the consumer 20-pack and divides by the 12 display units.- A consumer
75ct Boxcan remain one retail package. - Parenthetical snack case text can remain unit-priced when Shopify already exposes the item price.
The normalizer records the original wholesale price, units per wholesale item, generated unit cost,
MSRP when supplied, confidence, and the reason for each decision. Explicit overrides are reviewed in
data/retail-unit-overrides.ts. The full report is data/retail-normalization-report.json; previous
local reports are copied to the ignored data/backups/ directory.
bun run inventory:normalize
bun run inventory:normalize:checkImages
All supplier image URLs and mirrored local fallback paths are retained. Shopify remains the primary
delivery source while it is available. The local apps/web/public/inventory/ mirror is ignored by
Git and remains available for the later hosted-storage migration.
Supabase import
The migration in supabase/migrations/ separates supplier package cost, generated unit cost, and
editable retail price. Products import as drafts, supplier availability does not pretend to be KOF
location stock, and stock changes use audited database functions.
bun run inventory:supabase:sync
bun run inventory:supabase:sync --apply
bun run inventory:supabase:checkThe apply command requires an explicit local safety flag and a server-only Supabase secret. The secret is used only by the importer. Storefront and dashboard browser code use a public key, user sessions, RLS, and the deliberately limited storefront RPC.
See supabase/README.md for the self-hosted schema exposure, owner membership, import, and smoke-test
runbook.