A direct-to-consumer storefront platform for independent creators to sell digital and physical products without a marketplace middleman.
cd prototype
npm installCreate prototype/.env.local (gitignored, not included in the repo) with:
STRIPE_SECRET_KEY= # test-mode secret key from https://dashboard.stripe.com/test/apikeys
STRIPE_WEBHOOK_SECRET= # from `stripe listen --forward-to localhost:3000/api/webhooks/stripe`
NEXT_PUBLIC_SITE_URL=http://localhost:3000
DATABASE_URL= # Postgres (Neon via Vercel Marketplace) — see prototype/README.md
ORDERS_VIEW_PASSWORD= # Basic Auth password for the /orders view — see prototype/README.md
STRIPE_SECRET_KEY and DATABASE_URL are required — the app throws on startup without
STRIPE_SECRET_KEY (lib/stripe.ts), and the storefront/checkout/webhook all read from
Postgres now (lib/db/). STRIPE_WEBHOOK_SECRET is only needed to receive webhook
events locally via the Stripe CLI; the buy →
checkout → confirmation flow works without it, but order persistence does not.
npm run devOpen http://localhost:3000. Buy a product with Stripe's test
card 4242 4242 4242 4242 (any future expiry, any CVC, any ZIP).
See prototype/README.md for the automated test suite and more
detail on the environment variables.
author: hnakae@uoregon.edu
This course uses a five-sprint sequence. Each sprint adds project evidence and gives you another opportunity to practice the engineering cycle: Define, Generate, Analyze, Revise, Verify, and Explain.
DropShelf lets individual creators set up a public profile page, list products for sale, and accept payments directly from buyers via Stripe. The goal is a lightweight alternative to large marketplaces — creators own their storefront, keep more revenue, and sell on their own terms.
Sprint 1 deliverables — project definition:
- Repository initialized with commit history on
sprint-1branch - Project vision drafted (
docs/sprint-1-definition/project-vision.md) - Requirements defined (
docs/sprint-1-definition/requirements.md) - Initial architecture sketched (
docs/sprint-1-definition/architecture.md) - AI contribution documented (
docs/sprint-1-definition/AI_Contribution.md)
No working code yet — prototype begins in Sprint 2.
Sprint 2 deliverables — working prototype:
- Next.js app scaffolded (
prototype/) - Creator profile + product listing UI
- Stripe Checkout (buy flow) and webhook handler
- Automated test suite (Vitest + React Testing Library) — 25 tests passing, covers checkout action, webhook signature verification, and success-page confirmation
- Architecture updated to reflect the actual build (
docs/sprint-2-prototype/architecture.md) - Manual verification pass, including a real Stripe test payment (
docs/sprint-2-prototype/manual-verification.md) - AI review of the Stripe feature documented (below and in
docs/sprint-2-prototype/ai-implementation-review.md)
Completed feature slice: a buyer can browse a single creator's storefront, buy a product through a real Stripe Checkout session, and land on a confirmation page that re-verifies the payment with Stripe rather than trusting the redirect.
Sprint 3 deliverables — persistence and integration:
- Postgres database provisioned (Neon, via the Vercel Marketplace) and linked to the project
- Drizzle ORM schema (
products,orders,order_items) replacing the hardcodedlib/data.tsarray - Storefront and checkout action read the product catalog from the database
- Stripe webhook persists an order + order line item on
checkout.session.completed, instead of only logging it - Automated test suite updated for the database-backed data layer and webhook persistence — 27 tests passing
- Manual, end-to-end verification with a real Stripe test payment forwarded through the Stripe CLI, confirmed by querying the resulting rows in Postgres (
docs/sprint-3-persistence/manual-verification.md) - Architecture updated to reflect the persistence layer (
docs/sprint-3-persistence/architecture.md) - AI review of the persistence work documented (
docs/sprint-3-persistence/ai-implementation-review.md) - Webhook order write made atomic — a single SQL statement instead of two unguarded inserts (
docs/sprint-3-persistence/updates/webhook-atomic-write.md) - Order-history view (
/orders), reading live from Postgres, gated by a shared-secret Basic Auth check (docs/sprint-3-persistence/updates/orders-view.md,orders-view-auth-gate.md)
Completed feature slice: the product catalog and order history are now real,
durable data instead of a hardcoded module and a console.log. A completed Stripe
purchase leaves a permanent, queryable record — order and line item, written
atomically — in Postgres, and /orders makes that history visible and verifiable
without dropping into a database GUI.
Sprint 4 deliverables — quality and persistence completion:
- Kickoff scope, branch, and Canvas submission fields drafted (
docs/sprint-4-quality/kickoff.md) - Staged implementation plan written for Clerk auth, full product CRUD, order
cancel/refund, and test coverage, with per-item test annotations
(
docs/sprint-4-quality/plan.md) -
drizzle-zodschema validation added (lib/db/validation.ts) — Zod insert/select schemas derived directly from the Drizzle table definitions, so validation can't drift from the DB schema - Clerk authentication, replacing the shared-password Basic Auth gate on
/orders(also now gates/admin) — provisioned and live-verified: signed-out requests to/orders//admin/*redirect to/sign-in, the Stripe webhook is unaffected. Completing an actual sign-in still needs the admin account, which is created directly in the Clerk Dashboard rather than by an agent - Admin product management (create/edit/archive) with validated input
(
/admin/products) - Order cancel-and-refund action (Stripe refund + status update, with a guard against double-refunding)
- Automated test coverage for the above — 56 tests passing
- Sprint 4 Canvas submission fields finalized (
docs/sprint-4-quality/kickoff.md) -
/checkout/success500-on-invalid-session bug fixed — asession_idStripe can't retrieve/verify now shows "Session not found" instead of crashing (app/checkout/success/page.tsx)
Completed feature slice: signed-in admins can manage the product catalog
(create/edit/archive) and cancel an order for an automatic Stripe refund,
extending the persistence workflow from Create/Read to full CRUD plus a
compensating transaction — all gated by real Clerk authentication in place of
the Sprint 3 shared-password check. Remaining: creating the admin user
directly in the Clerk Dashboard (intentionally the student's own step, not
automated) is the one thing left before the signed-in admin flows can be
walked through manually — everything else, including the auth gating itself,
has been verified against a running app (see docs/sprint-4-quality/kickoff.md).