Marketplace
Routes
| Route | Purpose |
|---|---|
/marketplace | Product grid |
/marketplace/[slug] | Product detail — dynamicParams = false |
/services | Service cards grid |
/services/[slug] | Service detail + order form |
Product data
Products are defined in data/products.ts (static). Each product has:
type:3d-asset|pluginpersonalPrice/commercialPricefeaturedflagpreviewUrlorpreviewImagestags,software
Cart (Zustand)
// store/cart.ts
type CartItem = {
productSlug: string;
title: string;
price: number;
licenseType: 'personal' | 'commercial';
quantity: number;
};
addItem increments quantity if the same slug + license already exists. openDrawer() is called after add so the cart slides open.
CartDrawer is rendered once in app/layout.tsx — never scope it to a sub-route.
Checkout
Stripe checkout is stubbed. Handler is in place; wire up when ready.
Stripe product metadata fields
Set these in the Stripe dashboard on each product:
| Field | Values |
|---|---|
slug | URL slug e.g. my-product |
type | 3d-asset | plugin |
collection | Scene Packs | Templates | Merch |
deliveryType | digital | physical |
featured | true | false |
tags | comma-separated |
software | comma-separated |
downloadPath | server path for digital delivery |
printfulProductId | numeric ID — required for physical products |
Services
Six services defined in data/services.ts. Each service detail page includes ServiceOrderForm (react-hook-form), which submits via app/actions/service-orders.ts → submitServiceOrder.
Admin manages service orders at /admin/service-orders.