The merge creates the brand capability (two requirements) and extends the catalog browse requirement with the brand filter, the sales sort and a real sold count. openspec validate --all --strict stays green at 14 specs. With every box now checked, docs/TBD-migrate-wave.md is deleted, as its own instructions require. Its two durable notes move to the README instead of disappearing with it: - `nuxt build` does not typecheck, so a green build is not the type gate the verification section claimed. AGENTS.md told me to treat it as one, which is why waves 1-5 over-reported "builds pass" as evidence. - the list of what stays deliberately mock: addresses, coupons, favourites, account stats, the seckill/collective/integral pages, reviews, and the fixed-data adapter itself, which the adapter spec requires for rollback. The README's verification block also gains the real test count (29, not 16).
2.4 KiB
Spec Delta
MODIFIED Requirements
Requirement: Public product browse
Public GET /api/products SHALL return only published products whose shop is active, and SHALL remain readable without authentication. When category_id is supplied, the filter SHALL match that category and every category beneath it, so requesting a parent category returns products assigned to its child and grandchild categories. When brand_id is supplied the filter SHALL match that brand and compose with the other filters. The listing SHALL accept an optional sort of price or sales: price orders by each product's lowest active SKU price, and sales orders by units sold across orders that reached payment, which SHALL also be reported per product as sold_count. Any other sort value SHALL be rejected with a 400 ApiError rather than silently ignored. An unsorted listing SHALL order newest first. Paging SHALL keep returning page and per_page alongside the filtered total.
Scenario: parent category includes descendant products
- WHEN a shopper requests products for a category that has child categories holding published products
- THEN the response contains the products assigned to those descendant categories, not only those assigned directly to the requested category
Scenario: sort by lowest active SKU price
- WHEN a shopper requests the product list with
sort=priceandorder=asc - THEN products come back ordered by their lowest active SKU price ascending
Scenario: sort by units sold
- WHEN a shopper requests the product list with
sort=salesandorder=desc - THEN products come back ordered by their
sold_countdescending, and a product with no paid orders reports zero rather than being omitted
Scenario: filter by brand
- WHEN a shopper requests products with a
brand_idalongside acategory_id - THEN only products matching both filters are returned, and
totalreflects the combined filter
Scenario: unsupported sort is rejected
- WHEN a client requests a
sortvalue that is neitherpricenorsales - THEN the API responds 400 with an
ApiErrorbody instead of ignoring the parameter
Scenario: unpublished products never appear
- WHEN any public listing or filter is applied
- THEN products that are not
published, or whose shop is not active, are absent from bothitemsandtotal