feat(ADM-018): completed feature

This commit is contained in:
chattie
2026-08-17 22:23:10 +02:00
parent cf1c69fc8b
commit d595b4871f
871 changed files with 47411 additions and 281 deletions

View 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.

View 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`

View 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.

View 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"
}

View 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"
}

View 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"
}

View 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"
}