chore(openspec): archive add-points-mall

Sync the points-mall capability plus the frontend-mall and frontend-admin
requirements into the main specs, and write the capability Purpose the archive
leaves as a placeholder.
This commit is contained in:
2026-09-18 12:43:18 +00:00
parent f70d1e506a
commit 82c1e8e4bb
10 changed files with 60 additions and 6 deletions
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-09-18
@@ -0,0 +1,33 @@
## Context
The Mall has a fixture-only points catalog and points balance. Customer accounts will provide an atomic, append-only points ledger. Cash orders, payment, and shipments have a separate lifecycle, so a redemption should not be represented as a zero-value normal order.
## Goals / Non-Goals
**Goals:**
- Offer live points products and a customer redemption flow.
- Atomically debit points, reserve product stock, and create an immutable redemption order.
- Give platform operators product and redemption-order management.
**Non-Goals:**
- Point earning, cash co-payment, normal SKU inventory sharing, coupons, withdrawals, or full shipping integration.
## Decisions
### Points catalog is platform-owned and distinct
`integral_products` holds localized name/subtitle/content, images, integer `points_price`, stock, publish state, and sort/recommend fields. It is not a SKU and never joins merchant catalog inventory. Platform admins own CRUD; customers can read published products only.
### Redemptions have their own order snapshot
`integral_orders` stores customer, order number, state, address JSON snapshot, total points, and timestamps. `integral_order_items` snapshots product identity, localized name, image, point price, and quantity. States are `pending_fulfillment`, `fulfilled`, and `cancelled`; cancellation policy is platform-only until a future refund flow defines customer-initiated returns.
### Redeem atomically against accounts and stock
The service begins one transaction, locks the published product, conditionally decrements stock, debits the points account through customer-accounts, appends its entry with the redemption order reference, then inserts the order and line. Failures leave no order, stock change, or ledger entry. Point price and stock are never accepted from the client.
### UI replaces fixture-only behavior
Mall loads points balance and catalog through the shared client, submits a product/quantity/address redemption, and lists the customers redemption history on the points mall (not a cash-order list). Admin manages products and updates fulfillment state. Seed/demo data credits enough points for at least one redemption via the customer-accounts service with reason `seed`; it never assigns `balance_minor` by absolute overwrite.
## Risks / Trade-offs
- Redemption fulfillment initially stores only an address snapshot and status; carrier tracking can be integrated later with a dedicated model.
- The prerequisite customer-accounts change must archive first. This preserves a small, testable accounting boundary rather than duplicating balance mutation here.
- Without a seed credit, live redemption cannot be demonstrated; seed is an operator fixture, not a customer earn API.
@@ -0,0 +1,28 @@
## Why
The mall exposes a fixed points-store page and a fixed points balance. A real points mall needs a dedicated redemption order lifecycle and must consume the customer-account ledger rather than treat points as an unguarded profile field.
## What Changes
- Add platform-managed points products with localized catalog content, integer point price, stock, availability, and images.
- Add points redemption orders and immutable redemption-line snapshots, separate from cash orders and payments.
- Debit points and decrement redemption stock atomically; reject insufficient points, inactive products, and unavailable stock.
- Seed demo spendable points only through the archived customer-accounts credit path (immutable entry); do not treat seed as an earning campaign.
- Add customer browsing, redemption, and redemption-history APIs; add platform product and redemption-order management; replace mall fixtures.
## Capabilities
### New Capabilities
- `points-mall`: Points product catalog and atomic customer redemption orders.
### Modified Capabilities
- `frontend-mall`: Points mall and balance surfaces use live APIs.
- `frontend-admin`: Platform operators manage points products and redemption fulfillment.
## Non-goals
This change does not grant points, accept cash co-payments, share normal SKU inventory, add coupons to redemptions, or add customer withdrawals.
## Impact
Depends on archived `customer-accounts`; adds Rust points module/migrations, shared contract/locales, mall and admin routes, and points-redemption integration tests.
@@ -0,0 +1,12 @@
## ADDED Requirements
### Requirement: Platform points mall management
Platform admins SHALL manage points products and inspect and fulfill redemption orders through the admin console using the shared API contract. Admin SHALL expose points-mall navigation beside existing platform operations.
#### Scenario: manage a redemption catalog item
- **WHEN** a platform admin publishes a configured points product
- **THEN** it becomes available in the customer points mall
#### Scenario: points mall appears in admin navigation
- **WHEN** an authenticated platform admin opens the admin console
- **THEN** points-product and redemption-order management are reachable from the console nav
@@ -0,0 +1,8 @@
## ADDED Requirements
### Requirement: Live points mall
The mall SHALL display live published points products and the signed-in customer's live points balance, allow redemption with a shipping address, and show the customer's redemption history on the points route. It SHALL replace `INTEGRAL_PRODUCTS` and `USER_STATS` imports on the points route.
#### Scenario: redeem available product
- **WHEN** a signed-in shopper with enough points redeems a published in-stock product
- **THEN** the mall shows the created redemption order and refreshed points balance
@@ -0,0 +1,30 @@
## ADDED Requirements
### Requirement: Platform points product catalog
Platform admins SHALL create, update, publish, unpublish, and list points products with localized user-facing content, integer points price, stock, images, and recommendation order. Customers SHALL discover only published products.
#### Scenario: unpublished product is unavailable
- **WHEN** an admin unpublishes a points product
- **THEN** customers cannot discover or redeem it
### Requirement: Atomic points redemption
An authenticated customer SHALL redeem a published points product using a quantity and shipping address. The server SHALL atomically validate stock, debit points through customer accounts, create a redemption order with immutable product and address snapshots, and decrement stock.
#### Scenario: insufficient points
- **WHEN** a customer redeems a product costing more points than available
- **THEN** the API returns 409 and creates no redemption order or stock change
#### Scenario: final stock contention
- **WHEN** concurrent redemptions request the final product stock
- **THEN** only requests covered by stock succeed and no negative stock is stored
### Requirement: Redemption history and fulfillment
Customers SHALL list only their redemption orders. Platform admins SHALL list redemption orders and transition pending fulfillment to fulfilled or cancelled with validated current status. Demo seed SHALL credit points through customer accounts so at least one published product can be redeemed in the live mall.
#### Scenario: fulfill redemption
- **WHEN** a platform admin fulfills a pending redemption order
- **THEN** its status becomes fulfilled and the customer sees that status in history
#### Scenario: seeded points are spendable
- **WHEN** a seeded demo customer with a seed ledger credit redeems an in-stock published product they can afford
- **THEN** the redemption succeeds and the points summary decreases by the product price
@@ -0,0 +1,21 @@
## 1. Prerequisite and persistence
- [x] 1.1 Confirm `customer-accounts` is archived and use its guarded internal points-debit service.
- [x] 1.2 Add additive migrations for platform points products, redemption orders, redemption items, status constraints, address snapshots, and indexes.
- [x] 1.3 Implement the Rust points module repositories and services for published catalog reads, admin product management, atomic redemption, history, and validated fulfillment transitions.
## 2. Contract and backend proof
- [x] 2.1 Register customer and platform routes with appropriate roles and add shared types, client methods, locales, and fixed-data adapter parity.
- [x] 2.2 Add integration tests for unpublished-product rejection, insufficient points rollback, concurrent final stock, ownership filtering, and fulfillment transition validation.
## 3. Application surfaces
- [x] 3.1 Add platform-admin points-product and redemption-order management screens and admin nav entries using the shared client.
- [x] 3.2 Replace mall points fixtures with live catalog, address-aware redemption, refreshed balance, and customer redemption history.
- [x] 3.3 Remove `INTEGRAL_PRODUCTS` and `USER_STATS` page imports without deleting fixed-data adapter support.
## 4. Verification and specification
- [x] 4.1 Seed deterministic points products and credit demo customer points through the archived customer-accounts credit path (append-only entry, never an absolute balance write). Browser-smoke admin publication and customer redemption.
- [x] 4.2 Run cargo test for vmall-api, builds for mall and admin, and strict validation for this OpenSpec change.