5.9 KiB
5.9 KiB
1. Persistence and shared contract
- 1.1 Add migration
0016_membership_messaging.sql:member_levels(bilingualnameJSONB{en, zh},icon, unique integergrowth_threshold, bilingualbenefitsJSONB{en, zh}),growth_logs(append-onlyuser_id,delta, runninggrowth_total,reason,reference_type/reference_idorder reference with a partial unique index per user and reference),messages(user_id,kind, bilingualtitle/bodyJSONB{en, zh},reference_type/reference_id,statusunread/read,deleted_atsoft delete, partial unique index per user/kind/reference), ausers.levelcolumn referencingmember_levels, and listing/counting indexes. - 1.2 Add shared types (
MemberLevel,MemberLevelInput,MembershipStatus,GrowthLogEntry,Message,MessageListQuery) and@vmall/sharedmethodsgetMembership,listGrowthLogs,listMessages,markMessageRead,markAllMessagesRead,deleteMessage,getUnreadCount, andadmin.listMemberLevels,admin.createMemberLevel,admin.updateMemberLevel,admin.deleteMemberLevelwith all amounts and growth values as integers and i18n content as{en, zh}JSONB. - 1.3 Implement
apps/api/src/modules/membership/repository, service, DTO, handlers, and module registration: admin-role-gated member-level CRUD routes and customer-scoped membership status and growth-ledger routes, services returningApiResult<Dto>. - 1.4 Implement
apps/api/src/modules/messaging/repository, service, DTO, handlers, and module registration: customer-scoped message list (paginated, optional unread-only filter), mark-read, mark-all-read, soft delete, and unread-count routes returningApiResult<Dto>.
2. Services and behavioral tests
- 2.1 Implement growth accrual on order completion (customer confirms receipt): convert the order's realized paid amount to the base currency with integer minor-unit arithmetic (truncated whole units, no floating point), append exactly one ledger entry per order, and update
users.levelin the same transaction with a guardedUPDATE ... WHEREthat only moves the customer to a strictly higher-threshold level. - 2.2 Wire idempotent message emission into the order, fulfillment, and refund (after-sale) transitions: order payment success emits
order_paid, shipment dispatch emitsorder_shipped, and refund completion emitsrefund_completed, each a guarded insert keyed by user, kind, and reference with bilingual{en, zh}title and body naming the order. - 2.3 Add behavioral coverage in
apps/api/tests/membership.rsandapps/api/tests/messaging.rs(fixtures fromtests/common/mod.rs) for upgrade boundaries: growth exactly at a threshold upgrades, growth below every threshold holds no level, one accrual jumping two thresholds lands on the highest qualifying level, and repeated completion events accrue and upgrade exactly once. - 2.4 Extend the behavioral coverage for event triggers and read semantics: each of the three events creates exactly one correctly referenced message, re-run handlers do not duplicate, mark-read touches only
unreadrows (idempotent single and all-read), soft delete is idempotent and excluded from lists and unread counts, and cross-user message access fails.
3. Mall member and message surfaces
- 3.1 Implement the
getMembership,listGrowthLogs,listMessages,markMessageRead,markAllMessagesRead,deleteMessage, andgetUnreadCountmethods inapps/mall/mock/api.tswith deterministic per-session fixture state and the same idempotent read/delete semantics. - 3.2 Add the
membershipandmessagingdomains with their exact shared-client method picks to the Mall API selection and enable them in the default live runtime configuration. - 3.3 Add or adjust bilingual level, growth, message, badge, and failure strings through the existing Mall locale source without per-page hard-coded copy.
- 3.4 Build
apps/mall/pages/user/membership.vue: current level name/icon/benefits, growth total, progress to the next threshold, and paginated growth history from the shared contract, with fixed-adapter parity and no fixture imports. - 3.5 Build
apps/mall/pages/user/messages.vue: paginated message list with unread-only filter, open/mark-read, mark-all-read, and delete actions that persist through the API and refresh list and counts. - 3.6 Add the top-bar unread badge on the shell message entry: unread count on page entry and after read/mark-all/delete actions, absent for anonymous shoppers, linking to the message center.
4. Admin member-level management
- 4.1 Build
apps/admin/pages/member-levels.vue: levels in threshold order with create/edit/delete forms over bilingual name, icon, growth threshold, and benefits through the sharedadminlevel methods, surfacing the delete rejection for levels in use. - 4.2 Register the member-levels entry in the authenticated admin console navigation beside existing platform operations.
5. Verification
- 5.1 Run the
apps/api/tests/integration suites with thetests/common/mod.rsfixtures — the newmembership.rsandmessaging.rsplus the affectedorders.rs,order_service.rs, andpoints.rssuites — proving upgrade boundaries, event triggers, and read semantics against the shared test database. - 5.2 Browser-smoke the running API, Mall, and admin console: confirm receipt upgrades the level and appends the growth entry, the three system events land one message each, message-center read/mark-all/delete update lists and counts, the top-bar badge tracks unread count, and admin level CRUD with in-use delete rejection works end to end.
- 5.3 Build the affected frontends because the shared API contract changes:
pnpm --filter @vmall/mall build,pnpm --filter @vmall/admin build, andpnpm --filter @vmall/shop-admin build. - 5.4 Run
openspec change validate add-membership-messaging --strictandopenspec validate --all --strictand fix findings until both pass.