feat(ADM-018): completed feature
This commit is contained in:
41
work/artifacts/F-018/architect.md
Normal file
41
work/artifacts/F-018/architect.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# Architect — F-018 Cart module
|
||||
|
||||
## Feature
|
||||
F-018 adds authenticated customer carts that persist only product/variant/quantity and recalculate price and availability on every read.
|
||||
|
||||
## Design
|
||||
|
||||
### Module boundaries
|
||||
Create `project/src/modules/cart/` with domain, application, infrastructure, api and tests. Cart owns cart persistence only; it does not own price or stock truth.
|
||||
|
||||
Cart depends only on public `PricingServicePort` and `InventoryServicePort` contracts injected by the composition root. It must not import pricing/inventory internals and must not store price, tax, stock or discount columns.
|
||||
|
||||
### Data model
|
||||
Add migration `013_cart.js`:
|
||||
- `cart_carts`: `id`, `user_id unique`, timestamps.
|
||||
- `cart_items`: `id`, `cart_id`, `product_id`, `variant_id`, `quantity`, timestamps.
|
||||
- Unique `(cart_id, variant_id)` so adding the same variant increases quantity.
|
||||
- CHECK `quantity > 0`.
|
||||
|
||||
### Use cases
|
||||
- `addItem(userId, { productId, variantId, quantity })`
|
||||
- `changeQuantity(userId, variantId, quantity)`
|
||||
- `removeItem(userId, variantId)`
|
||||
- `getCart(userId)`
|
||||
|
||||
`getCart` always recalculates every item with `PricingService.calculate({ variantId, quantity })` and `InventoryService.checkAvailability(variantId, quantity)`. If price is missing, mark item as unavailable for pricing instead of trusting stale data.
|
||||
|
||||
### API
|
||||
Authenticated routes:
|
||||
- `GET /cart`
|
||||
- `POST /cart/items`
|
||||
- `PATCH /cart/items/:variantId`
|
||||
- `DELETE /cart/items/:variantId`
|
||||
|
||||
Request schemas strip unknown fields so client price payload is ignored.
|
||||
|
||||
## Acceptance trace
|
||||
- Price changed after add: cart stores no price, read recalculates through PricingService.
|
||||
- Out-of-stock: cart read calls InventoryService and flags unavailable.
|
||||
- Client price fields ignored: API schemas strip unknown fields and persistence has no price columns.
|
||||
- `verify.sh` green after gates.
|
||||
28
work/artifacts/F-018/documenter.md
Normal file
28
work/artifacts/F-018/documenter.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# Documenter — F-018 Cart module
|
||||
|
||||
## Summary
|
||||
Documented F-018 cart behavior in this evidence artifact. Project README updates are not applied during document stage because the active repository guard restricts `project/` edits to build/implementer state.
|
||||
|
||||
## Public API notes
|
||||
|
||||
Cart is authenticated-user scoped. It stores only `productId`, `variantId` and `quantity`; price, tax, discount and stock truth are recalculated through Pricing and Inventory services on every read.
|
||||
|
||||
| Route | Access | Result |
|
||||
| ---------------------------- | ------------- | --------------------------------------- |
|
||||
| GET /cart | authenticated | Current cart with recalculated totals |
|
||||
| POST /cart/items | authenticated | Adds item or increments existing item |
|
||||
| PATCH /cart/items/:variantId | authenticated | Changes item quantity |
|
||||
| DELETE /cart/items/:variantId| authenticated | Removes item and returns updated cart |
|
||||
|
||||
## Rules
|
||||
- Client-supplied price, tax, discount, total or stock fields are ignored.
|
||||
- Cart persistence has no price/stock columns.
|
||||
- `available=false` when either pricing is missing or inventory availability is insufficient.
|
||||
- Totals are based on currently persisted server-side prices, not add-time prices.
|
||||
|
||||
## Evidence
|
||||
- `work/artifacts/F-018/architect.md`
|
||||
- `work/artifacts/F-018/implementer.md`
|
||||
- `work/artifacts/F-018/reviewer.json`
|
||||
- `work/artifacts/F-018/security.json`
|
||||
- `work/artifacts/F-018/qa.json`
|
||||
31
work/artifacts/F-018/implementer.md
Normal file
31
work/artifacts/F-018/implementer.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# Implementer — F-018 Cart module
|
||||
|
||||
## Summary
|
||||
Implemented authenticated cart persistence that stores only product id, variant id and quantity, and recalculates totals/availability through injected `PricingService` and `InventoryService` on every read.
|
||||
|
||||
## Files changed
|
||||
- `project/migrations/013_cart.js`
|
||||
- `project/src/app/build-app.ts`
|
||||
- `project/src/app/tests/cart.itest.ts`
|
||||
- `project/src/modules/cart/**`
|
||||
- `project/src/modules/inventory/index.ts`
|
||||
- `project/src/modules/pricing/index.ts`
|
||||
|
||||
## Acceptance evidence
|
||||
- AC1 price changed after add: `cart.itest.ts` adds item at one price, changes server price, then `GET /cart` returns recalculated totals.
|
||||
- AC2 out of stock: `cart.itest.ts` sets stock to zero and verifies cart item is flagged unavailable.
|
||||
- AC3 client price ignored: `cart.itest.ts` sends bogus price fields; response uses server-side pricing and `cart_items` has no price/tax/stock columns.
|
||||
- `verify.sh`: passed.
|
||||
|
||||
## Commands run
|
||||
- `cd project && npm run lint` — passed
|
||||
- `cd project && npm run typecheck` — passed
|
||||
- `cd project && npm run build` — passed
|
||||
- `cd project && npm test` — passed; DB tests skipped without `TEST_DATABASE_URL`
|
||||
- `cd project && TEST_DATABASE_URL='postgres://mdv:mdv_dev_only@localhost:5432/mdv_test' npm run test:integration -- cart.itest migrations.itest` — passed; 10 files, 42 tests
|
||||
- `./scripts/verify.sh` — passed
|
||||
|
||||
## Notes
|
||||
- Cart routes require authentication; no guest cart persistence in this slice.
|
||||
- Cart imports only public pricing/inventory interfaces, not internals.
|
||||
- Added public service factories in inventory/pricing module indexes for composition-root injection.
|
||||
15
work/artifacts/F-018/leader-close.json
Normal file
15
work/artifacts/F-018/leader-close.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"feature_id": "F-018",
|
||||
"agent": "leader",
|
||||
"verdict": "APPROVED",
|
||||
"summary": "F-018 closed with reviewer, security and QA gates approved. Final verify.sh passed.",
|
||||
"evidence": [
|
||||
"reviewer.json verdict APPROVED",
|
||||
"security.json verdict APPROVED",
|
||||
"qa.json verdict APPROVED",
|
||||
"./scripts/verify.sh passed during close",
|
||||
"backlog/features.json updated: F-018 status done and gates true",
|
||||
"work/current.md updated: no active feature, next suggested F-019"
|
||||
],
|
||||
"timestamp": "2026-08-15T17:32:49Z"
|
||||
}
|
||||
24
work/artifacts/F-018/qa.json
Normal file
24
work/artifacts/F-018/qa.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"feature_id": "F-018",
|
||||
"agent": "qa",
|
||||
"verdict": "APPROVED",
|
||||
"summary": "QA approved. All F-018 acceptance criteria are covered by executable integration tests and green checks. Cart read recalculates price after price changes, flags out-of-stock items, and ignores client-supplied price fields.",
|
||||
"evidence": [
|
||||
"cart.itest.ts covers price change after add and recalculated totals",
|
||||
"cart.itest.ts covers out-of-stock item availability flag",
|
||||
"cart.itest.ts covers ignored client price fields and validates cart_items columns contain no price/tax/stock fields",
|
||||
"cd project && npm run lint passed",
|
||||
"cd project && npm run typecheck passed",
|
||||
"cd project && npm run build passed",
|
||||
"cd project && npm test passed: 23 passed, 10 skipped without TEST_DATABASE_URL",
|
||||
"cd project && TEST_DATABASE_URL='postgres://mdv:mdv_dev_only@localhost:5432/mdv_test' npm run test:integration -- cart.itest migrations.itest passed: 10 files, 42 tests",
|
||||
"./scripts/verify.sh passed"
|
||||
],
|
||||
"acceptance": [
|
||||
{ "criterion": "Given product price changed after add to cart When cart read Then new price shown", "status": "PASS", "evidence": "Integration test updates server price after add; GET /cart returns recalculated totals" },
|
||||
{ "criterion": "Given variant out of stock When cart read Then item flagged unavailable", "status": "PASS", "evidence": "Integration test sets inventory stock to zero and cart item available=false" },
|
||||
{ "criterion": "Cart payload from client containing price fields is ignored", "status": "PASS", "evidence": "Integration test sends bogus netUnitAmountCents/totalCents and response uses server price; DB columns have no price fields" },
|
||||
{ "criterion": "verify.sh green", "status": "PASS", "evidence": "./scripts/verify.sh PASS" }
|
||||
],
|
||||
"timestamp": "2026-08-15T17:32:06Z"
|
||||
}
|
||||
22
work/artifacts/F-018/reviewer.json
Normal file
22
work/artifacts/F-018/reviewer.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"feature_id": "F-018",
|
||||
"agent": "reviewer",
|
||||
"verdict": "APPROVED",
|
||||
"summary": "F-018 review approved. The cart module stores only product, variant and quantity, recalculates prices and availability through injected public PricingService/InventoryService contracts, and includes tests for price changes, out-of-stock flags and ignored client price fields.",
|
||||
"evidence": [
|
||||
"Read work/current.md, architect.md and implementer.md",
|
||||
"Inspected cart domain/application/infrastructure/API files and migration 013_cart.js",
|
||||
"Verified cart_items has no price, tax, VAT, discount or stock columns",
|
||||
"Verified CartService recalculates pricing and inventory availability on cart view construction",
|
||||
"Verified cart API schemas strip unknown client price fields",
|
||||
"Verified build-app.ts injects pricing and inventory public services into cart routes at composition root",
|
||||
"gentle-ai review mode status: receipt-driven development off globally, ordinary Orquestra gate used",
|
||||
"cd project && npm run lint passed",
|
||||
"cd project && npm run typecheck passed",
|
||||
"cd project && npm run build passed",
|
||||
"cd project && npm test passed",
|
||||
"DB integration cart/migrations suite passed with TEST_DATABASE_URL",
|
||||
"./scripts/verify.sh passed"
|
||||
],
|
||||
"timestamp": "2026-08-15T17:31:34Z"
|
||||
}
|
||||
17
work/artifacts/F-018/security.json
Normal file
17
work/artifacts/F-018/security.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"feature_id": "F-018",
|
||||
"agent": "security",
|
||||
"verdict": "APPROVED",
|
||||
"summary": "Security approved. No new dependencies or secrets were introduced. Cart routes require authentication, SQL is parameterized, request schemas strip client-supplied price fields, and persisted cart data contains no price, tax, discount or stock columns.",
|
||||
"evidence": [
|
||||
"cd project && npm audit --audit-level=high --omit=dev: found 0 vulnerabilities",
|
||||
"Secret scan over cart files found only a test fixture password, no committed credentials",
|
||||
"Reviewed cart routes: all routes authenticate user before cart access",
|
||||
"Reviewed validation: UUID params and positive quantities enforced with zod",
|
||||
"Reviewed schemas: item payload strips unknown client-supplied price/tax/total fields",
|
||||
"Reviewed repository SQL: all dynamic values are parameterized",
|
||||
"Reviewed migration: cart_items stores product_id, variant_id and quantity only with quantity > 0 CHECK",
|
||||
"No new runtime dependency added"
|
||||
],
|
||||
"timestamp": "2026-08-15T17:31:53Z"
|
||||
}
|
||||
Reference in New Issue
Block a user