Stage M5 and Stage M6
This commit is contained in:
@@ -141,7 +141,7 @@ sport-store/
|
||||
│ ├── common/ decorators · filters · guards · interceptors
|
||||
│ │ middleware · pipes · errors
|
||||
│ ├── infrastructure/ prisma · redis · storage · events · logging
|
||||
│ └── modules/ 20 bounded contexts
|
||||
│ └── modules/ 21 bounded contexts
|
||||
│
|
||||
├── packages/
|
||||
│ ├── types/ Framework-free domain + API contracts (zero deps)
|
||||
@@ -158,7 +158,7 @@ sport-store/
|
||||
│
|
||||
├── docs/
|
||||
│ ├── architecture.md Boundaries, conventions, risks — read this first
|
||||
│ └── adr/ 17 decision records
|
||||
│ └── adr/ 18 decision records
|
||||
│
|
||||
├── docker-compose.yml Backing services; `--profile full` runs everything
|
||||
├── turbo.json pnpm-workspace.yaml package.json
|
||||
@@ -251,17 +251,16 @@ locale-in-path would buy nothing.
|
||||
| **M2** ✅ | Auth: login, refresh rotation with reuse detection, RBAC admin, user & role management |
|
||||
| **M3** ✅ | Admin catalog: write API, variant matrix, media uploads, inventory ledger, product editor (option builder + per-locale tabs) |
|
||||
| **M4** ✅ | Storefront catalog — listings, PDP, variant selector, filters, sort control, load-more pagination and a mobile filter sheet |
|
||||
| **M5** | Cart, checkout, orders |
|
||||
| **M6** | Search + faceting |
|
||||
| **M5** ✅ | Cart (Redis), guest checkout, orders with stock reservation and an admin order lifecycle |
|
||||
| **M6** ✅ | Search: PostgreSQL full-text + trigram, diacritic-folded, ranked, with type-ahead and refinable results |
|
||||
| **M7** | Promotions, coupons, reviews, CMS |
|
||||
| **M8** | Customer account |
|
||||
| **M9** | Payments (VNPay, MoMo, ZaloPay, COD), shipping, notifications |
|
||||
|
||||
**Recommended next step: M5 (cart & checkout).** M3 now closes the loop end to end: an operator
|
||||
creates a product with per-locale content, defines the option axes, gets a generated variant matrix,
|
||||
prices it, attaches imagery per colourway, receives stock through the ledger and publishes — and the
|
||||
result renders on the storefront in both languages. Cart and checkout are the first flows that put
|
||||
the variant model under real concurrency.
|
||||
**Recommended next step: M7 (promotions, coupons, reviews, CMS) or M9 (payments).** The store can
|
||||
now be browsed, searched, filled into a bag and checked out, and every order moves stock through a
|
||||
ledger. What it still cannot do is take money — which is the one gap between this and a shop that
|
||||
trades.
|
||||
|
||||
---
|
||||
|
||||
@@ -271,11 +270,12 @@ Everything below was run, not assumed:
|
||||
|
||||
- `pnpm lint` · `pnpm typecheck` · `pnpm test` · `pnpm build` — 27/27 Turborepo tasks pass;
|
||||
`pnpm format:check` clean
|
||||
- 6 migrations, 32 tables; seed loads 36 permissions, 6 roles, 3 brands, 8 categories,
|
||||
- 7 migrations, 35 tables; seed loads 36 permissions, 6 roles, 3 brands, 8 categories,
|
||||
3 collections, 12 products, **155 variants**, 64 uploaded images and 3 dev accounts
|
||||
- **48 tests** — RBAC guards, password hashing, translation fallback, `Accept-Language`, the
|
||||
- **57 tests** — RBAC guards, password hashing, translation fallback, `Accept-Language`, the
|
||||
variant matrix planner, the HTTP client's fetch receiver and retry recursion, the inventory
|
||||
list's variant-driven projection, and the two admin-schema defects that caused silent data loss
|
||||
list's variant-driven projection, the two admin-schema defects that caused silent data loss, and
|
||||
order-number round-tripping
|
||||
- Catalog: listings with filters/facets/cursor paging, PDP, navigation — correctly localised in
|
||||
both `vi` and `en`; money formats per locale from one integer (`690.000 ₫` / `₫690,000`)
|
||||
- Storefront: every route 200 in both locales; `/en/products/<vi-slug>` → 307 →
|
||||
@@ -303,6 +303,23 @@ through Chrome with the console and network panel open:
|
||||
media library upload driven from the browser (presign → PUT to MinIO → register, 400×500 PNG
|
||||
landed at 10,962 bytes with a date-partitioned UUID key); inventory adjustment from the table
|
||||
wrote a ledger entry and the storefront went `OUT_OF_STOCK` → `IN_STOCK` on the next request
|
||||
- **Search (M6):** `nocturne` and `running jacket` match exactly; `ao chay bo` finds _Áo Chạy Bộ
|
||||
Aero_ without diacritics; `nocturn`, `jaket` and `runing` survive their typos; `velocity`
|
||||
matches by brand, `crimson` by colourway, `VEL-NOC` by SKU; `zzzzqqq` correctly finds nothing.
|
||||
Type-ahead suggests from the product name only, and results stay refinable by the same facets
|
||||
as any listing with an honest sort control
|
||||
- **Concurrency:** three simultaneous checkouts for a single unit produce exactly one order and
|
||||
two clean rejections, with `reserved` landing on 1 — the read-then-write version created two
|
||||
orders and lost a reservation
|
||||
- **The purchase flow, end to end in a browser (M5):** added to bag from the PDP (badge updates),
|
||||
changed quantity in the bag, checked out as a guest and placed order **SP-000003**; the
|
||||
confirmation page is reachable from its bookmarkable URL; the admin confirmed then fulfilled it,
|
||||
which moved `onHand` 15→12, released `reserved` 3→0 and wrote a `SALE -3` ledger entry alongside
|
||||
`order.confirmed` / `order.fulfilled` audit records
|
||||
- **Commerce guard rails:** reserving does not touch `onHand`; cancelling returns the reservation;
|
||||
`PENDING→COMPLETED` is refused; cancelling without a reason is refused; a 20-unit request caps to
|
||||
available stock with a `QUANTITY_REDUCED` notice; guest order lookup needs number _and_ email and
|
||||
answers a wrong email with the same `NOT_FOUND` as a wrong number
|
||||
- **Catalog write correctness**, each reproduced before the fix and re-run after: a product
|
||||
authored in one language is accepted; renaming a product no longer clears its gender/sport
|
||||
targeting, collections or attributes; adding a size inherits the sibling price and the stored
|
||||
|
||||
Reference in New Issue
Block a user