feat: wave 2 migration (P3, P5, P7 openspec changes)

Implements, verifies, and archives the three remaining Wave 2 changes from
openspec/MIGRATION-PLAN.md.

- add-wallet-settlement (P3): demo recharge, guarded withdrawal freeze and
  one-time admin review, paginated own fund entries, idempotent per-shop
  weekly/monthly settlement statements with commission rate and one-time
  payout confirmation.
- add-merchant-onboarding (P5): personal/enterprise applications with one live
  application per user, guarded review with mandatory rejection reason, and
  transactional shop + owner provisioning returning one-time credentials;
  mall onboarding/status pages and an admin review console.
- add-membership-messaging (P7): platform member levels, append-only growth
  accrual on order completion with guarded one-way leveling, order/shipment/
  refund system messages with unread/read state and soft deletion, plus the
  mall header unread badge.

Backend: migrations 0019-0023, new wallet, settlement, merchant_onboarding,
membership and messaging modules, event hooks in order/fulfillment/aftersale,
and integration suites for each. Shared contract extended and all three
frontends updated; code indexes, domain docs, backend guidelines and the
migration tracker synced.

Verification: cargo test -p vmall-api green twice consecutively; mall, admin
and shop-admin builds pass; browser smoke on every new surface; openspec
validate --all --strict green (33 passed).

The three changes share the @vmall/shared contract, the mall mock adapter and
per-app locale/nav files, so they are committed together to keep every commit
buildable.
This commit is contained in:
2026-09-25 15:25:29 +00:00
parent 772aafa3fb
commit 9904696e76
120 changed files with 14097 additions and 125 deletions
+158
View File
@@ -0,0 +1,158 @@
// Merchant onboarding: application form and applicant status page.
export default {
en: {
merchant: {
joinTitle: "Sell on VMall",
joinSubtitle:
"Submit a merchant onboarding application. The platform team reviews it and provisions your shop and owner account.",
stepKind: "Entity type",
stepEntity: "Entity & categories",
stepContact: "Contact & qualification",
kindPersonal: "Individual",
kindEnterprise: "Enterprise",
kindHint: "Choose the entity type that will own the shop. Required fields change with it.",
entityInfo: "Entity information",
realName: "Legal name",
realNamePlaceholder: "Name shown on the identity document",
companyName: "Company name",
companyNamePlaceholder: "Registered company name",
businessLicenseNo: "Business license number",
businessLicenseNoPlaceholder: "Unified social credit code",
categories: "Operating categories",
categoriesHint: "Select one or more categories from the published category tree.",
categoriesLoadFailed: "Unable to load the category tree.",
contactInfo: "Contact details",
contactName: "Contact name",
contactPhone: "Contact phone",
contactEmail: "Contact email",
contactAddress: "Contact address (optional)",
contactNamePlaceholder: "Who should we contact?",
contactPhonePlaceholder: "Phone number with area code",
contactEmailPlaceholder: "you{'@'}example.com",
contactAddressPlaceholder: "Street, city, region",
qualification: "Qualification materials",
qualificationHint: "Provide public http(s) URLs only; this MVP has no file upload.",
identityDocumentUrl: "Identity document URL",
identityDocumentUrlPlaceholder: "https://example.com/id.jpg",
businessLicenseUrl: "Business license URL",
businessLicenseUrlPlaceholder: "https://example.com/license.jpg",
extraMaterials: "Extra material URLs (optional)",
extraMaterialPlaceholder: "https://example.com/extra.jpg",
extraMaterialAdd: "Add material URL",
extraMaterialRemove: "Remove",
previous: "Back",
next: "Next",
submit: "Submit application",
submitting: "Submitting…",
signInToSubmit: "Sign in or create an account to submit — your answers are kept.",
restoredDraft: "Welcome back. Your saved answers were restored; review them and submit.",
successTitle: "Application submitted",
successBody:
"Your merchant application is now pending review. You can track its state at any time.",
viewStatus: "View application status",
conflict:
"You already have a pending or approved merchant application. Track it on the status page instead of submitting another.",
invalid: "Please check the highlighted fields and try again.",
submitFailed: "Unable to submit the application. Please try again.",
errorRequired: "This field is required.",
errorEmail: "Enter a valid email address.",
errorUrl: "Enter a valid http(s) URL.",
errorCategories: "Select at least one operating category.",
statusTitle: "Merchant application status",
statusSubtitle: "The latest merchant application submitted by your account.",
statusLoadFailed: "Unable to load your merchant applications.",
noApplication: "You have not submitted a merchant application yet.",
startApplication: "Start an application",
status_pending: "Pending review",
status_approved: "Approved",
status_rejected: "Rejected",
applicationId: "Application ID",
entityKind: "Entity type",
submittedAt: "Submitted",
updatedAt: "Last updated",
reviewedAt: "Reviewed",
rejectionReason: "Rejection reason",
createdShop: "Provisioned shop",
reapply: "Apply again",
historyTitle: "Application history",
historyHint: "Earlier applications from this account.",
backToJoin: "Back to the application form",
},
},
zh: {
merchant: {
joinTitle: "商家入驻",
joinSubtitle: "提交商家入驻申请,平台审核通过后将为您开通店铺和店主账号。",
stepKind: "主体类型",
stepEntity: "主体与经营类目",
stepContact: "联系人与资质",
kindPersonal: "个人",
kindEnterprise: "企业",
kindHint: "请选择店铺的经营主体类型,选择后需要填写的字段会随之变化。",
entityInfo: "主体信息",
realName: "真实姓名",
realNamePlaceholder: "证件上的姓名",
companyName: "企业名称",
companyNamePlaceholder: "营业执照上的企业名称",
businessLicenseNo: "营业执照号",
businessLicenseNoPlaceholder: "统一社会信用代码",
categories: "经营类目",
categoriesHint: "请从已发布的类目树中选择一个或多个类目。",
categoriesLoadFailed: "类目加载失败。",
contactInfo: "联系信息",
contactName: "联系人姓名",
contactPhone: "联系电话",
contactEmail: "联系邮箱",
contactAddress: "联系地址(选填)",
contactNamePlaceholder: "请填写联系人姓名",
contactPhonePlaceholder: "请填写含区号的电话号码",
contactEmailPlaceholder: "you{'@'}example.com",
contactAddressPlaceholder: "省/市/区详细地址",
qualification: "资质材料",
qualificationHint: "仅支持填写公开的 http(s) 链接,本版本不提供文件上传。",
identityDocumentUrl: "身份证件链接",
identityDocumentUrlPlaceholder: "https://example.com/id.jpg",
businessLicenseUrl: "营业执照链接",
businessLicenseUrlPlaceholder: "https://example.com/license.jpg",
extraMaterials: "其他材料链接(选填)",
extraMaterialPlaceholder: "https://example.com/extra.jpg",
extraMaterialAdd: "添加材料链接",
extraMaterialRemove: "删除",
previous: "上一步",
next: "下一步",
submit: "提交申请",
submitting: "提交中…",
signInToSubmit: "请先登录或注册后提交,已填写的内容会为您保留。",
restoredDraft: "欢迎回来,已恢复您填写的申请内容,请确认后提交。",
successTitle: "申请已提交",
successBody: "您的入驻申请已提交,正在等待平台审核。您可以随时查看审核状态。",
viewStatus: "查看申请状态",
conflict: "您已有一条待审核或已通过的入驻申请,请前往状态页查看,无需重复提交。",
invalid: "请检查标注的字段后重试。",
submitFailed: "申请提交失败,请稍后重试。",
errorRequired: "该项为必填。",
errorEmail: "请填写有效的邮箱地址。",
errorUrl: "请填写有效的 http(s) 链接。",
errorCategories: "请至少选择一个经营类目。",
statusTitle: "入驻申请状态",
statusSubtitle: "您账号下最新提交的入驻申请。",
statusLoadFailed: "入驻申请加载失败。",
noApplication: "您还没有提交过入驻申请。",
startApplication: "开始申请",
status_pending: "待审核",
status_approved: "已通过",
status_rejected: "已拒绝",
applicationId: "申请编号",
entityKind: "主体类型",
submittedAt: "提交时间",
updatedAt: "更新时间",
reviewedAt: "审核时间",
rejectionReason: "拒绝原因",
createdShop: "已开通店铺",
reapply: "重新申请",
historyTitle: "申请记录",
historyHint: "该账号更早的申请记录。",
backToJoin: "返回入驻申请",
},
},
};