feat(ADM-018): completed feature
This commit is contained in:
30
work/artifacts/F-020/architect.md
Normal file
30
work/artifacts/F-020/architect.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# Architect — F-020 Shipping module
|
||||
|
||||
## Feature
|
||||
F-020 adds server-side shipping quotation behind `ShippingService.calculate(cart, address)`.
|
||||
|
||||
## Design
|
||||
|
||||
### Module boundaries
|
||||
Create `project/src/modules/shipping/` with domain/application/infrastructure/api/tests. Shipping owns zones and methods; it does not own cart data. Callers pass a cart summary and destination address into the public service.
|
||||
|
||||
### Data model
|
||||
Add migration `015_shipping.js`:
|
||||
- `shipping_zones`: id, name, country, postal_code_prefix nullable, active.
|
||||
- `shipping_methods`: id, zone_id, name, base_cost_cents, free_shipping_threshold_cents nullable, active.
|
||||
|
||||
### Rules
|
||||
- Address matching uses country plus optional postal-code prefix. Prefer the most specific prefix.
|
||||
- `ShippingService.calculate(cart, address)` returns the cheapest active method in the matching zone.
|
||||
- If cart total is at or above method threshold, shipping cost is zero.
|
||||
- If no zone/method matches, throw a domain error mapped to HTTP 422.
|
||||
- Carrier adapter is an interface only; no real carrier API.
|
||||
|
||||
### API
|
||||
- Admin create/update can be minimal for test setup: `POST /shipping/zones`, `POST /shipping/methods`.
|
||||
- Public/authenticated calculation endpoint: `POST /shipping/calculate` with cart total/address payload.
|
||||
|
||||
## Acceptance trace
|
||||
- Known zone returns shipping cost.
|
||||
- Unknown zone returns HTTP 422 with clear code.
|
||||
- Cart above free shipping threshold returns zero cost.
|
||||
23
work/artifacts/F-020/documenter.md
Normal file
23
work/artifacts/F-020/documenter.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# Documenter — F-020 Shipping module
|
||||
|
||||
## Summary
|
||||
Shipping module exposes server-side shipping quotation behind `ShippingService.calculate(cartTotalCents, address)`. Selection uses country plus most specific postal code prefix and the cheapest active method wins.
|
||||
|
||||
## Public API notes
|
||||
|
||||
| Route | Access | Result |
|
||||
|---|---|---|
|
||||
| POST /shipping/zones | admin | Creates a zone with country and optional postal-code prefix |
|
||||
| POST /shipping/methods | admin | Creates a method under a zone with optional free-shipping threshold |
|
||||
| POST /shipping/calculate | public | Returns cheapest active method cost with free shipping applied when threshold met |
|
||||
|
||||
## Errors
|
||||
- `SHIPPING_ZONE_NOT_FOUND` — HTTP 422
|
||||
- `INVALID_SHIPPING_ADDRESS` — HTTP 400
|
||||
|
||||
## Evidence
|
||||
- `work/artifacts/F-020/architect.md`
|
||||
- `work/artifacts/F-020/implementer.md`
|
||||
- `work/artifacts/F-020/reviewer.json`
|
||||
- `work/artifacts/F-020/security.json`
|
||||
- `work/artifacts/F-020/qa.json`
|
||||
26
work/artifacts/F-020/implementer.md
Normal file
26
work/artifacts/F-020/implementer.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# Implementer — F-020 Shipping module
|
||||
|
||||
## Summary
|
||||
Implemented server-side shipping quotation with zones, methods and free-shipping threshold behind `ShippingService.calculate(cartTotalCents, address)`.
|
||||
|
||||
## Files changed
|
||||
- `project/migrations/015_shipping.js`
|
||||
- `project/src/modules/shipping/**`
|
||||
- `project/src/app/build-app.ts`
|
||||
- `project/src/app/tests/shipping.itest.ts`
|
||||
|
||||
## Acceptance evidence
|
||||
- AC1 known zone: `shipping.itest.ts` seeds ES/28 zone with 500 cents method; `/shipping/calculate` returns 500.
|
||||
- AC2 unknown zone: same test sends US/94101 and gets HTTP 422 with `SHIPPING_ZONE_NOT_FOUND`.
|
||||
- AC3 free shipping threshold: same test sends cart total above threshold and gets 0/freeApplied.
|
||||
- `verify.sh`: passed.
|
||||
|
||||
## Commands run
|
||||
- `cd project && npm run lint/typecheck/build/test` passed
|
||||
- `cd project && TEST_DATABASE_URL='postgres://mdv:mdv_dev_only@localhost:5432/mdv_test' npm run test:integration -- shipping.itest migrations.itest` passed; 12 files, 47 tests
|
||||
- `./scripts/verify.sh` passed
|
||||
|
||||
## Notes
|
||||
- No new runtime dependency.
|
||||
- Carrier adapter remains an interface; no real carrier integration.
|
||||
- Cheapest active method per zone wins. Postal code prefix matching is most specific first.
|
||||
15
work/artifacts/F-020/leader-close.json
Normal file
15
work/artifacts/F-020/leader-close.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"feature_id": "F-020",
|
||||
"agent": "leader",
|
||||
"verdict": "APPROVED",
|
||||
"summary": "F-020 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-020 status done and gates true",
|
||||
"work/current.md updated: no active feature, next suggested F-021"
|
||||
],
|
||||
"timestamp": "2026-08-15T18:03:20Z"
|
||||
}
|
||||
21
work/artifacts/F-020/qa.json
Normal file
21
work/artifacts/F-020/qa.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"feature_id": "F-020",
|
||||
"agent": "qa",
|
||||
"verdict": "APPROVED",
|
||||
"summary": "QA approved. All F-020 acceptance criteria are covered by executable tests and green checks: known zone cost, unknown zone 422, and free-shipping threshold.",
|
||||
"evidence": [
|
||||
"shipping.itest.ts covers known zone returning costCents=500",
|
||||
"shipping.itest.ts covers unknown zone returning HTTP 422 SHIPPING_ZONE_NOT_FOUND",
|
||||
"shipping.itest.ts covers free shipping when cart total above threshold returning costCents=0",
|
||||
"cd project && npm run lint/typecheck/build/test passed",
|
||||
"DB integration shipping/migrations suite passed: 12 files, 47 tests",
|
||||
"./scripts/verify.sh passed"
|
||||
],
|
||||
"acceptance": [
|
||||
{ "criterion": "Given address in known zone When calculate Then shipping cost returned", "status": "PASS", "evidence": "/shipping/calculate returns cheapest active method in zone" },
|
||||
{ "criterion": "Given address outside all zones When checkout Then HTTP 422 with clear reason", "status": "PASS", "evidence": "US/94101 returns 422 SHIPPING_ZONE_NOT_FOUND" },
|
||||
{ "criterion": "Given cart above free shipping threshold Then shipping cost is zero", "status": "PASS", "evidence": "Cart total 5000 above threshold returns costCents=0 freeApplied=true" },
|
||||
{ "criterion": "verify.sh green", "status": "PASS", "evidence": "./scripts/verify.sh PASS" }
|
||||
],
|
||||
"timestamp": "2026-08-15T18:02:56Z"
|
||||
}
|
||||
17
work/artifacts/F-020/reviewer.json
Normal file
17
work/artifacts/F-020/reviewer.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"feature_id": "F-020",
|
||||
"agent": "reviewer",
|
||||
"verdict": "APPROVED",
|
||||
"summary": "F-020 review approved. Shipping module is isolated, exposes ShippingService.calculate(cartTotalCents, address), chooses the cheapest active method, supports free-shipping threshold, and returns clear errors for unknown zones.",
|
||||
"evidence": [
|
||||
"Read work/current.md, architect.md and implementer.md",
|
||||
"Inspected shipping domain/application/infrastructure/API and migration 015_shipping.js",
|
||||
"Verified cheapest active method selection and free-shipping threshold logic",
|
||||
"Verified zone matching uses country plus most specific postal_code_prefix",
|
||||
"gentle-ai review mode status: receipt-driven development off globally, ordinary Orquestra gate used",
|
||||
"cd project && npm run lint/typecheck/build/test passed",
|
||||
"DB integration shipping/migrations suite passed: 12 files, 47 tests",
|
||||
"./scripts/verify.sh passed"
|
||||
],
|
||||
"timestamp": "2026-08-15T18:02:37Z"
|
||||
}
|
||||
15
work/artifacts/F-020/security.json
Normal file
15
work/artifacts/F-020/security.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"feature_id": "F-020",
|
||||
"agent": "security",
|
||||
"verdict": "APPROVED",
|
||||
"summary": "Security approved. No new dependencies or secrets were introduced. Admin operations are protected, calculate route strips unknown fields, SQL is parameterized, and DB constraints prevent negative costs.",
|
||||
"evidence": [
|
||||
"cd project && npm audit --audit-level=high --omit=dev: found 0 vulnerabilities",
|
||||
"Secret scan found only a test fixture password, no committed credentials",
|
||||
"Reviewed /shipping/zones and /shipping/methods: admin-only creation",
|
||||
"Reviewed /shipping/calculate: zod schema strips unknown fields and validates country/postal code",
|
||||
"Reviewed repository SQL: parameterized queries only",
|
||||
"Reviewed migration CHECK constraints for base cost and free shipping threshold"
|
||||
],
|
||||
"timestamp": "2026-08-15T18:02:47Z"
|
||||
}
|
||||
Reference in New Issue
Block a user