Client case study

Beaver Trap

Custom e-commerce platform for a local liquor and smoke shop

Beaver Trap storefront concept
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.

System at a glance

Framework
Next.js 16.1 · App Router · React 19.2 · TypeScript 5
Styling
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.

1 : n1 : 11 : n1 : n1 : nn : 1productsid (pk)branddepartmentprimary_subtypestorefront_statusis_featuredproduct_variantsid (pk)product_id (fk)price_centssize_mlactiveinventoryvariant_id (fk, pk)on_handlow_stock_thresholdproduct_imagesid (pk)product_id (fk)pathsortproduct_tagsproduct_id (fk)tagordersid (pk)customer_emailstatustotal_centsattention_neededorder_linesorder_id (fk)variant_id (fk)quantityprice_centsadmin_usersuser_id (pk, fk auth.users)
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.