Files
vmall/openspec/changes/archive/2026-09-18-replace-mock-api-wave-7/proposal.md
T
Chengdong Zhang c51e96ae41 feat(mall): address book wave 7 frontend, contract, and archive
Live addresses domain for the mall: shared contract (AddressBookEntry +
five client methods), mock adapter state v3, live domain pick, addresses
page CRUD, checkout saved-address picker with manual fallback, demo seed,
and the archived change plus address-book capability spec.
2026-09-18 16:00:05 +08:00

2.9 KiB

Proposal: replace-mock-api-wave-7

Why

The address book is the last piece of the core purchase chain still on fixed mock data: user/addresses.vue renders MOCK_ADDRESSES with local-only edits, and checkout picks from the same static list. A real address entity closes the chain end-to-end against the live API, following the established wave pattern (per-domain live pick in the mall's api plugin, mock adapter stays as fallback).

What Changes

  • New addresses table: user_id FK (cascade), recipient/phone/country/region/city/line1/postal_code, is_default, timestamps; partial unique index enforces one default per user.
  • New route module apps/api/src/routes/addresses.rs: GET/POST /api/addresses, PUT/DELETE /api/addresses/:id, POST /api/addresses/:id/default — customer role only, ownership via WHERE user_id = (cross-user → 404). Default management is transactional (unset siblings in the same statement/transaction); the first address becomes default automatically; deleting the default promotes the most recent remaining address.
  • packages/shared: AddressBookEntry type + listMyAddresses / createAddress / updateAddress / deleteAddress / setDefaultAddress on ApiClient.
  • Mall mock adapter implements the same methods against its persisted state (seeded from MOCK_ADDRESSES), so mock mode keeps working and the rollback flag stays meaningful.
  • Mall pages: user/addresses.vue switches to real CRUD (existing UiModal form pattern, plus delete + set-default); checkout/index.vue loads the address list from the API (falls back to an inline manual form when the list is empty) and submits the selected one; addresses joins LIVE_PICKS/DEFAULT_LIVE_DOMAINS.
  • scripts/seed-demo.mjs seeds two demo addresses for customer@vmall.local, idempotently.
  • Integration tests in apps/api/tests/addresses.rs (fixtures from tests/common/mod.rs): CRUD happy path, cross-user 404, single-default invariant, delete-default promotion, role guard.

Capabilities

New Capabilities

  • address-book: per-customer saved shipping addresses with a single default.

Modified Capabilities

  • frontend-mall: the buyer center address page and checkout address selection use the live address API.

Impact

apps/api/migrations/0009_addresses.sql, apps/api/src/routes/{addresses.rs,mod.rs}, router registration, packages/shared/src/{types.ts,api.ts}, apps/mall/{mock/api.ts,plugins/api.ts,pages/user/addresses.vue,pages/checkout/index.vue,locales/user.ts,locales/checkout.ts}, scripts/seed-demo.mjs, apps/api/tests/addresses.rs. The contract change rebuilds all three frontends.

Non-goals

  • No address auto-geocoding, no region cascader data (free-text region/city stays), no address selector inside the order-before flow beyond radio pick.
  • Coupons, favorites, wallet stats, marketing subsystems (seckill/collective/integral) and reviews remain mock/future work, unchanged.