Custom e-commerce platform for a local liquor and smoke shop
Storefront + admin
A ground-up ecommerce build for a local business that needed brand, discovery, owner control, and technical durability in one system.
Business
Local retail / ecommerce
Focus
Storefront, guided discovery, admin systems
Stack
Next.js 16 · Supabase · Tailwind 4
Status
Live, iterating
Case study narrative
The relationship, the system, and the outcome matter together. This page stays on the case-study side of that line. The deeper technical archive lives on the linked project pages.
The relationship
Beaver Trap is the liquor and smoke shop next to my house. I started going in as a customer and kept ending up in long conversations with the owner about what he wished his online presence could do. Those conversations turned into a working relationship, and the working relationship turned into a build. The page you are reading now is the honest record of what that build actually is.
Operating constraints
Before any architecture decision, four constraints shaped the system. They are the reason it does not look like a Shopify store with a theme on top.
Local, pickup-only fulfillment. No shipping carriers, no card-not-present risk, no Stripe webhook dependency.
One operator. The owner runs the shop and the site. Every admin surface has to be usable without a support call.
A catalog that does not sit still. New subtypes, brand identities, and flavored expressions arrive every month.
No SaaS lock-in. Product data, promotions, and order history all stay in a database he could port if he ever needed to.
Tailwind 4 · CVA variants · Motion for transitions
Data
Supabase Postgres · @supabase/ssr for session-aware server components
Auth
Supabase Auth + admin_users gate enforced in RLS and server actions
Storage
Supabase Storage bucket product-images, served via public CDN URLs
Realtime
Realtime subscription on orders for the admin fulfillment queue
Payments
None online. Payment is collected in-store at pickup.
Inventory
CSV reconciliation with dry-run + SKU mapping (no external library)
Hosting
Vercel · serverless routes for /api/wizard and checkout actions
Mobile read
Products stay central
Brand, department, variants, and inventory branch from one durable product record.
Inventory is queryable
Shelf, warehouse, and compliance data can change without rewriting storefront logic.
Promos are separate
Pricing and merchandising rules attach to the model instead of living inside page code.
Scroll the detail view if you want the full map. The working set: products → variants → inventory on the catalog side; orders → order_lines linking back to variants on the operations side. product_images and product_tags hang off products; admin_users is the RLS gate.
How the pieces fit
Storefront and admin live in the same Next.js application and share the same Supabase database. The split is not physical. It is a security boundary enforced by Row-Level Security and an admin_users table. Anonymous traffic can read storefront-eligible rows. The owner, once signed in and present in admin_users, can see the full catalog, touch every write path, and manage the order queue.
Hard problems
Four decisions took real thought. Each of them shows up in the linked technical notes.
What is live, what is next
The storefront, the Flavor Wizard, the admin catalog, the order queue, the CSV import, and the contact inbox are all live. The next pass is around merchandising automation: scheduled promotions, event-driven fresh-shelf rotations, and a sharper mobile admin for back-of-shop phone use.