56 lines
2.5 KiB
Markdown
56 lines
2.5 KiB
Markdown
# Online Store — Next.js (templates2)
|
|
|
|
A **ready-to-run storefront** forked from `templates2.Base.Next`: catalog, cart, checkout with the
|
|
built-in mock payment provider, customer orders and a product/order admin — plus the whole base core
|
|
(auth, roles, mock email, Docker, CI).
|
|
|
|
## Quickstart
|
|
|
|
```bash
|
|
npm ci
|
|
cp .env.example .env # SQLite + mock providers by default — no keys needed
|
|
npm run db:setup # prisma db push + seed (3 categories, 12 products, 2 orders)
|
|
npm run dev # http://localhost:3000
|
|
```
|
|
|
|
Demo accounts (seeded): `admin@example.com` (admin) and `customer@example.com` (customer) — password
|
|
`password`.
|
|
|
|
## Flow
|
|
|
|
`/shop` (search, category filters, sort, pagination) → `/shop/[slug]` (variants, stock, JSON-LD
|
|
`Product`) → `/cart` (persists in `localStorage`) → `/checkout` (**mock payment, no keys**) → order
|
|
confirmation → `/orders`. Admin: `/admin/products` (CRUD, stock, hide/show) and `/admin/orders`
|
|
(status transitions).
|
|
|
|
## What this case adds over the base
|
|
|
|
- **Data model** — `Category`, `Product` (price in minor units, stock, JSON variants), `Order`,
|
|
`OrderItem`.
|
|
- **Server-side validation** — `lib/cart.ts` recomputes every line's price from the database (never
|
|
trusts the client total), matches variants, and rejects over-stock quantities; `POST /api/checkout`
|
|
creates the order, decrements inventory and (on the mock provider) marks it paid.
|
|
- **Cart** — a client `CartProvider` backed by `localStorage`, so it survives reloads.
|
|
- **Admin** — product CRUD and order status transitions, all role-gated.
|
|
- **SEO** — `Product`/`Offer` JSON-LD per product and a sitemap that includes every active product.
|
|
- **Artwork** — a cohesive set of generated product/editorial photos in `public/art/` (hero,
|
|
collection tiles, lookbook, CTA/OG and one shot per seeded product), rendered by `<ProductImage>`,
|
|
which falls back to the emoji placeholder when a product has no image. Prompts live in
|
|
`../tools/art/store.json`; regenerate the set with
|
|
`node ../tools/generate-images.mjs ../tools/art/store.json --out /tmp/store-art` (needs
|
|
`OPENROUTER_API_KEY`), then convert to WebP into `public/art/`.
|
|
|
|
## Tests
|
|
|
|
- Unit: `tests/unit/cart.test.ts` — totals, variant deltas, empty cart, unknown product/variant,
|
|
over-stock rejection.
|
|
- E2E smoke: `tests/e2e/smoke.mjs` — catalog, filters, checkout validation and a full mock checkout.
|
|
|
|
## Quality
|
|
|
|
```bash
|
|
node templates2/qa.mjs Store.Next
|
|
```
|
|
|
|
See [`../CONTRACT.md`](../CONTRACT.md) for the Definition of Done.
|