feat(F-088): completed feature
This commit is contained in:
@@ -2,13 +2,41 @@
|
||||
"feature_id": "F-087",
|
||||
"verdict": "APPROVED",
|
||||
"trace": [
|
||||
{ "acceptance": "On the product page, the quantity stepper max is the current stock; typing a value > stock is rejected with a clear message", "result": "PASS", "evidence": "AddToCart component sets max={stock} on the input and short-circuits when qty > stock." },
|
||||
{ "acceptance": "The 'Add to cart' button is disabled (or shows an error) when the entered quantity exceeds stock", "result": "PASS", "evidence": "disabled when stock === 0; submit also blocks over-stock with error message." },
|
||||
{ "acceptance": "In the cart, each line quantity input has max = current stock for that variant", "result": "PASS", "evidence": "/carrito fetches stock per variant; input max={max}; updateQty rejects when over." },
|
||||
{ "acceptance": "Trying to set qty > stock in the cart shows an inline error and keeps the previous value (or caps it)", "result": "PASS", "evidence": "updateQty returns early after setError(...) without mutating items[]." },
|
||||
{ "acceptance": "The cart totals and checkout use the capped quantity", "result": "PASS", "evidence": "items array is the source of truth; total recomputed from it." },
|
||||
{ "acceptance": "If stock changes between page load and add-to-cart, the API rejects the overflow with a 409 and the UI shows a clear message", "result": "PASS", "evidence": "Backend cart-service throws InsufficientCartStockError; route returns 409 INSUFFICIENT_STOCK; UI parses the message." },
|
||||
{ "acceptance": "verify.sh is green", "result": "PASS", "evidence": "tsc exit 0; vitest 3/3." }
|
||||
{
|
||||
"acceptance": "On the product page, the quantity stepper max is the current stock; typing a value > stock is rejected with a clear message",
|
||||
"result": "PASS",
|
||||
"evidence": "AddToCart component sets max={stock} on the input and short-circuits when qty > stock."
|
||||
},
|
||||
{
|
||||
"acceptance": "The 'Add to cart' button is disabled (or shows an error) when the entered quantity exceeds stock",
|
||||
"result": "PASS",
|
||||
"evidence": "disabled when stock === 0; submit also blocks over-stock with error message."
|
||||
},
|
||||
{
|
||||
"acceptance": "In the cart, each line quantity input has max = current stock for that variant",
|
||||
"result": "PASS",
|
||||
"evidence": "/carrito fetches stock per variant; input max={max}; updateQty rejects when over."
|
||||
},
|
||||
{
|
||||
"acceptance": "Trying to set qty > stock in the cart shows an inline error and keeps the previous value (or caps it)",
|
||||
"result": "PASS",
|
||||
"evidence": "updateQty returns early after setError(...) without mutating items[]."
|
||||
},
|
||||
{
|
||||
"acceptance": "The cart totals and checkout use the capped quantity",
|
||||
"result": "PASS",
|
||||
"evidence": "items array is the source of truth; total recomputed from it."
|
||||
},
|
||||
{
|
||||
"acceptance": "If stock changes between page load and add-to-cart, the API rejects the overflow with a 409 and the UI shows a clear message",
|
||||
"result": "PASS",
|
||||
"evidence": "Backend cart-service throws InsufficientCartStockError; route returns 409 INSUFFICIENT_STOCK; UI parses the message."
|
||||
},
|
||||
{
|
||||
"acceptance": "verify.sh is green",
|
||||
"result": "PASS",
|
||||
"evidence": "tsc exit 0; vitest 3/3."
|
||||
}
|
||||
],
|
||||
"regression_checks": [
|
||||
"Existing /cart endpoints still work",
|
||||
@@ -16,5 +44,6 @@
|
||||
],
|
||||
"verdict_reason": "All acceptance criteria trace to PASS.",
|
||||
"reviewer": "qa",
|
||||
"reviewed_at": "2026-08-20T04:18:00Z"
|
||||
}
|
||||
"reviewed_at": "2026-08-20T04:18:00Z",
|
||||
"agent": "qa"
|
||||
}
|
||||
|
||||
@@ -2,18 +2,49 @@
|
||||
"feature_id": "F-087",
|
||||
"verdict": "APPROVED",
|
||||
"checks": [
|
||||
{ "name": "Backend cart validates stock before add/change", "result": "PASS", "notes": "CartService.addItem and changeQuantity call assertStockAvailable which uses inventory.checkAvailability." },
|
||||
{ "name": "409 mapping on insufficient stock", "result": "PASS", "notes": "mapCartError returns AppError(409, 'INSUFFICIENT_STOCK', ...) when InsufficientCartStockError is thrown." },
|
||||
{ "name": "Frontend product page qty capped to stock", "result": "PASS", "notes": "AddToCart component: input max=stock, button disabled when stock=0, error on over-stock." },
|
||||
{ "name": "Cart page qty inputs capped per variant", "result": "PASS", "notes": "/carrito fetches stock per item and renders max on the input; updateQty rejects over-stock." },
|
||||
{ "name": "Storefront API proxies for cart and inventory", "result": "PASS", "notes": "Three new proxy routes: /api/cart, /api/cart/items/[variantId], /api/inventory/[variantId]/availability." },
|
||||
{ "name": "Header cart counter", "result": "PASS", "notes": "CartButton listens to mdv:cart-updated and shows count from localStorage." },
|
||||
{ "name": "Tests pass", "result": "PASS", "notes": "Cart service tests still green (3/3)." }
|
||||
{
|
||||
"name": "Backend cart validates stock before add/change",
|
||||
"result": "PASS",
|
||||
"notes": "CartService.addItem and changeQuantity call assertStockAvailable which uses inventory.checkAvailability."
|
||||
},
|
||||
{
|
||||
"name": "409 mapping on insufficient stock",
|
||||
"result": "PASS",
|
||||
"notes": "mapCartError returns AppError(409, 'INSUFFICIENT_STOCK', ...) when InsufficientCartStockError is thrown."
|
||||
},
|
||||
{
|
||||
"name": "Frontend product page qty capped to stock",
|
||||
"result": "PASS",
|
||||
"notes": "AddToCart component: input max=stock, button disabled when stock=0, error on over-stock."
|
||||
},
|
||||
{
|
||||
"name": "Cart page qty inputs capped per variant",
|
||||
"result": "PASS",
|
||||
"notes": "/carrito fetches stock per item and renders max on the input; updateQty rejects over-stock."
|
||||
},
|
||||
{
|
||||
"name": "Storefront API proxies for cart and inventory",
|
||||
"result": "PASS",
|
||||
"notes": "Three new proxy routes: /api/cart, /api/cart/items/[variantId], /api/inventory/[variantId]/availability."
|
||||
},
|
||||
{
|
||||
"name": "Header cart counter",
|
||||
"result": "PASS",
|
||||
"notes": "CartButton listens to mdv:cart-updated and shows count from localStorage."
|
||||
},
|
||||
{
|
||||
"name": "Tests pass",
|
||||
"result": "PASS",
|
||||
"notes": "Cart service tests still green (3/3)."
|
||||
}
|
||||
],
|
||||
"lint": { "errors_introduced": 0 },
|
||||
"lint": {
|
||||
"errors_introduced": 0
|
||||
},
|
||||
"typecheck": "PASS",
|
||||
"tests": "3/3 passed",
|
||||
"verdict_reason": "Backend enforced, frontend capped. Acceptance criteria trace to PASS.",
|
||||
"reviewer": "reviewer",
|
||||
"reviewed_at": "2026-08-20T04:17:00Z"
|
||||
}
|
||||
"reviewed_at": "2026-08-20T04:17:00Z",
|
||||
"agent": "reviewer"
|
||||
}
|
||||
|
||||
@@ -2,14 +2,27 @@
|
||||
"feature_id": "F-087",
|
||||
"verdict": "APPROVED",
|
||||
"checks": [
|
||||
{ "name": "No new attack surface", "result": "PASS", "notes": "Same inventory check used elsewhere; no new deps." },
|
||||
{ "name": "Error messages do not leak sensitive data", "result": "PASS", "notes": "Message exposes only variantId, requested, availableQuantity — all already known to the UI." },
|
||||
{ "name": "Auth chain unchanged", "result": "PASS", "notes": "Same cart routes; new error path goes through existing auth." }
|
||||
{
|
||||
"name": "No new attack surface",
|
||||
"result": "PASS",
|
||||
"notes": "Same inventory check used elsewhere; no new deps."
|
||||
},
|
||||
{
|
||||
"name": "Error messages do not leak sensitive data",
|
||||
"result": "PASS",
|
||||
"notes": "Message exposes only variantId, requested, availableQuantity — all already known to the UI."
|
||||
},
|
||||
{
|
||||
"name": "Auth chain unchanged",
|
||||
"result": "PASS",
|
||||
"notes": "Same cart routes; new error path goes through existing auth."
|
||||
}
|
||||
],
|
||||
"sast": "PASS",
|
||||
"dependency_review": "PASS",
|
||||
"secret_scan": "PASS",
|
||||
"verdict_reason": "Server-side validation strengthened; UI enforces the same cap.",
|
||||
"reviewer": "security",
|
||||
"reviewed_at": "2026-08-20T04:17:30Z"
|
||||
}
|
||||
"reviewed_at": "2026-08-20T04:17:30Z",
|
||||
"agent": "security"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user