# V3.1 Schema 迁移清单 > 生成自 `init_v3.sql` → `schema.v31.prisma`(已通过 `prisma validate`) > 旧版备份:`schema.legacy-v21.prisma`(当前运行中的 `schema.prisma`) ## 激活步骤(P0) ```bash cd server/dukang-api # 1. 备份并切换 schema cp prisma/schema.prisma prisma/schema.legacy-v21.prisma # 若尚未备份 cp prisma/schema.v31.prisma prisma/schema.prisma # 2. 开发库建议删库重建 mysql -u root -p -e "DROP DATABASE IF EXISTS dukang_haoke; CREATE DATABASE dukang_haoke ..." # 或:mysql < prisma/init_v3.sql # 3. 生成 Client pnpm db:generate npx prisma db push # 或 prisma migrate dev --name v31_init # 4. 新 seed(待编写 seed-v31.ts) pnpm prisma:seed ``` --- ## 表对照(27 张 v3.1) | v3.1 物理表 | Prisma Model | 旧表/Model | 变化 | |-------------|--------------|------------|------| | `common_wx_app_config` | `CommonWxAppConfig` | `wx_app_configs` / `WxAppConfig` | 重命名 | | `common_resource` | `CommonResource` | — | **新增**(替代 `store_media`、裸 URL) | | `common_event` | `CommonEvent` | `benefit_ledgers`, `order_status_logs`, `store_audits`, `event_logs`, `operation_logs` | **合并** | | `common_ticket` | `CommonTicket` | `after_sale_tickets`, `refunds`, `delivery_intercepts`, `alerts` | **合并** | | `common_product_item` | `CommonProductItem` | `products` / `Product` | 重命名 + `cover_resource_id` | | `common_store_category` | `CommonStoreCategory` | `store_categories` / `StoreCategory` | 重命名 | | `common_promo_code` | `CommonPromoCode` | `promo_codes` / `PromoCode` | 重命名 + `qrcode_resource_id` | | `common_city` | `CommonCity` | `cities` / `City` | 重命名 | | `common_city_commission_rule` | `CommonCityCommissionRule` | `city_commission_rules` | 重命名 | | `partner_partner` | `Partner` | `partners` | 重命名 + 合同字段内联 | | `partner_account` | `PartnerAccount` | `partner_accounts` | 重命名 | | `partner_bill` | `PartnerBill` | `partner_bills` | 状态枚举精简 | | `hq_account` | `HqAccount` | `hq_accounts` | 重命名 | | `user_user` | `User` | `users` | 重命名;`phone` 可空;含 `deviceKey`/合并字段 | | `user_address` | `UserAddress` | `user_addresses` | 重命名 | | `user_city_preference` | `UserCityPreference` | `user_city_preferences` | 重命名 | | `user_promo_attribution` | `UserPromoAttribution` | `user_promo_attributions` | 重命名 | | `store_store` | `Store` | `stores` | `cover_url` → `cover_resource_id` | | `store_account` | `StoreAccount` | `store_accounts` | 重命名 | | `user_order` | `Order` | `orders` | **无 order_items**;商品快照内嵌 | | `user_order_delivery` | `OrderDelivery` | `order_deliveries` | 重命名 + `sign_photo_resource_id` | | `user_benefit_coupon` | `BenefitCoupon` | `benefit_coupons` | 重命名 | | `user_redeem_record` | `RedeemRecord` | `redeem_records` | 重命名 | | `user_store_rating` | `StoreRating` | `store_ratings` | 重命名 | | `store_payout` | `StorePayout` | `store_payouts` | 重命名 | | `log_third_party` | `LogThirdParty` | `payments`, `sms_logs` | **合并** | | `log_user_analytics` | `LogUserAnalytics` | `event_logs`(埋点部分) | **拆分** | ### 删除的表(v3.1 不再存在) | 旧表 | 替代方案 | |------|----------| | `store_media` | `common_resource`(`owner_type=STORE`) | | `partner_contracts` | `partner_partner.contract_*` + `common_resource` CONTRACT | | `order_items` | `user_order` 内嵌快照字段 | | `order_status_logs` | `common_event(ORDER_STATUS)` | | `payments` | `log_third_party` + `user_order.pay_*` | | `refunds` | `common_ticket(REFUND)` | | `delivery_intercepts` | `common_ticket(ALERT)` 或 RESHIPMENT | | `benefit_ledgers` | `common_event(BENEFIT_LEDGER)` | | `redeem_tokens` | **仅 Redis** | | `order_commissions` | `partner_bill` 汇总(无明细表) | | `partner_withdrawals` | 手册 v3.1 未包含(后续按需) | | `store_audits` | `common_event(STORE_AUDIT)` | | `after_sale_tickets` | `common_ticket` | | `alerts` | `common_ticket(ALERT)` | | `operation_logs` | `common_event(HQ_OPERATION)` | | `event_logs` | `common_event` + `log_user_analytics` | ### preV1 扩展字段(已并入 v3.1) | 字段 | 表 | 说明 | |------|-----|------| | `device_key` / `phone_verified_at` / `merged_into_user_id` | `user_user` | 访客 JWT + 验机 + 账号合并 | | `client_ip` / `ip_*` / `gps_*` | `user_order` | 下单位置快照 | ~~以下字段在切换后丢失~~ → **已保留** --- ## Prisma Client 调用变更速查 | 旧调用 | v3.1 调用 | |--------|-----------| | `prisma.product` | `prisma.commonProductItem` | | `prisma.city` | `prisma.commonCity` | | `prisma.cityCommissionRule` | `prisma.commonCityCommissionRule` | | `prisma.storeCategory` | `prisma.commonStoreCategory` | | `prisma.promoCode` | `prisma.commonPromoCode` | | `prisma.orderDelivery` | `prisma.orderDelivery`(表名变 `user_order_delivery`) | | `prisma.benefitCoupon` | `prisma.benefitCoupon`(表 `user_benefit_coupon`) | | `prisma.benefitLedger` | `prisma.commonEvent`(`eventType=BENEFIT_LEDGER`) | | `prisma.redeemToken` | **删除**,改 Redis | | `prisma.storeMedia` | `prisma.commonResource` | | `prisma.storeAudit` | `prisma.commonEvent`(`eventType=STORE_AUDIT`) | | `prisma.payment` | `prisma.logThirdParty` | | `prisma.orderStatusLog` | `prisma.commonEvent`(`eventType=ORDER_STATUS`) | | `prisma.orderItem` | **删除**,读写 `order` 快照字段 | > `Partner`、`Store`、`User`、`Order` 等 Model 名保留,仅 `@@map` 物理表名变化。 --- ## 后端模块影响面 ### P0 — 基础设施 | 路径 | 影响 | 工作量 | |------|------|--------| | `prisma/schema.prisma` | 已切换为 v3.1 | ✅ | | `prisma/schema.v31.prisma` | 与 `schema.prisma` 同步源 | ✅ | | `prisma/seed-prev1.ts` | 保留为 `seed-legacy`;主 seed 为 `seed-v31.ts` | ✅ | | `prisma/sync-benefit-to-price.ts` | `product` → `commonProductItem` | 低 | | `packages/shared-types` | `ClientApp` 去掉 `USER_H5` 等;新增 Resource/Event 枚举 | 中 | ### P1 — common 模块(新建) | 路径 | 说明 | |------|------| | `src/modules/common/common.module.ts` | **新建** | | `src/modules/common/resource.service.ts` | OSS 凭证、登记、CRUD | | `src/modules/common/resource.controller.ts` | `/common/resources/*` | | `src/modules/common/event.service.ts` | 事件写入/查询/时间线 | | `src/modules/common/ticket.service.ts` | 工单 CRUD | ### P2 — IAM | 路径 | 关键改动 | |------|----------| | `modules/iam/auth.service.ts` | 去掉访客 `deviceKey` 流程;`user.phone` 必填;`prisma.user` 字段变更 | | `modules/iam/user-address.service.ts` | 表名映射,逻辑基本不变 | | `common/guards/phone-verified.guard.ts` | 适配新 User 模型 | | `common/guards/super-admin.guard.ts` | 无大变 | ### P3 — catalog | 路径 | 关键改动 | |------|----------| | `modules/catalog/catalog.service.ts` | `city`→`commonCity`,`product`→`commonProductItem`;返回 `coverResource.url` | ### P4 — trade(改动最大) | 路径 | 关键改动 | |------|----------| | `modules/trade/trade.service.ts` | 下单写 `user_order` 快照(无 `orderItem`);支付写 `log_third_party`;状态变更写 `common_event`;去掉 IP/GPS 字段或扩展 | | `integrations/pay/*` | 回调改查 `log_third_party` | | `jobs/*`(配送 Mock) | `orderDelivery` 字段对齐 | ### P5 — benefit | 路径 | 关键改动 | |------|----------| | `modules/benefit/benefit.service.ts` | 发券逻辑保留;流水从 `benefitLedger.create` → `commonEvent.create(BENEFIT_LEDGER)`;读明细改查 `commonEvent` | ### P6 — redeem | 路径 | 关键改动 | |------|----------| | `modules/redeem/redeem.service.ts` | **删除** `redeemToken` DB 写入,仅 Redis;`cityCommissionRule`→`commonCityCommissionRule` | ### P7 — store | 路径 | 关键改动 | |------|----------| | `modules/store/store.service.ts` | `storeAudit`→`commonEvent`;封面改 `coverResourceId`;`city`→`commonCity` | ### P8 — settlement | 路径 | 关键改动 | |------|----------| | `modules/settlement/settlement.service.ts` | `partnerBill` 状态枚举变更;去掉 `orderCommission` 明细 | ### P9 — analytics | 路径 | 关键改动 | |------|----------| | `modules/analytics/analytics.service.ts` | `eventLog`→`logUserAnalytics` | ### P10 — ops(HQ 后台) | 路径 | 关键改动 | |------|----------| | `modules/ops/admin-stores.service.ts` | `storeMedia`→`commonResource`;`coverUrl`→`coverResourceId`;`city`→`commonCity` | | `modules/ops/admin-benefit.service.ts` | 流水列表改查 `commonEvent` | | `modules/ops/admin-orders.service.ts` | 订单含内嵌商品快照;无 `items` include | | `modules/ops/admin-dashboard.service.ts` | 统计字段:去掉 guest/merged 用户计数 | | `modules/ops/admin-cities.service.ts` | `city`→`commonCity` | | `modules/ops/admin-partners.service.ts` | 订单关联 `city.partnerId` 不变 | | `modules/ops/admin-redeem.service.ts` | 表名映射 | | `modules/ops/admin-users.service.ts` | 去掉 merged/guest 相关 | | `admin-stores.controller.ts` | `/admin/store-media` → `/admin/resources` 或复用 common API | --- ## 前端影响面 | 应用 | 影响 | |------|------| | `apps/h5-user` | 登录流(phone 必填);商品图 URL 来源;订单详情无 items 数组 | | `apps/h5-shop` | 门店详情封面 URL | | `apps/h5-partner` | 录店上传走 `/common/resources` | | `apps/admin-web` | 门店资源页改 `common_resource`;权益流水改 event;订单详情结构调整 | | `packages/shared-types` | 枚举与 DTO 同步 | --- ## P1 进度(common 模块) | 项 | 状态 | |----|------| | `modules/common/` Resource/Event/Ticket/ThirdPartyLog | ✅ | | `common/event/event.helpers.ts` 权益/订单事件 | ✅ | | 业务层改用 `commonEvent` / `commonResource` / `logThirdParty` | ✅ | | `pnpm run build` | ✅ | ## P2–P6 进度(业务层 + 兼容层 + 后台) | 项 | 状态 | |----|------| | P2 IAM + catalog 适配 v3.1 | ✅ | | P3 trade + benefit(下单/发券/支付日志/事件) | ✅ | | P4 redeem + store(Redis token + 封面资源) | ✅ | | P5 ops 后台(订单/门店/权益/城市/合伙人) | ✅ | | P6 兼容层 `v31-compat.ts`(订单 items、门店 coverUrl、流水/状态日志) | ✅ | | `admin/products` CRUD + HQ 商品页 | ✅ | | `sync-benefit-to-price.ts` → `commonProductItem` | ✅ | | `schema.prisma` ↔ `schema.v31.prisma` 同步 | ✅ | | smoke 脚本 `scripts/smoke-prev1.mjs` | ✅ | ### 新增 HQ API | 路径 | 说明 | |------|------| | `GET/POST /admin/products` | 商品列表/新建 | | `GET/PUT /admin/products/:id` | 商品详情/更新 | ### 新增 API(`/api/v1/common/*`) | 路径 | 说明 | |------|------| | `POST /common/resources/upload-token` | Mock OSS 直传凭证 | | `POST/GET/PUT/DELETE /common/resources` | 资源 CRUD | | `POST/GET /common/events` | 事件写入/查询 | | `GET /common/events/timeline` | 时间线 | | `POST/GET/PUT /common/tickets` | 工单 | | `GET /common/third-party-logs` | HQ 只读支付/第三方日志 | ## 建议实施顺序 ``` P0 schema 切换 + seed-v31 → P1 common 模块(resource + event) → P2 IAM + catalog(可登录、可看商品) → P3 trade + benefit(可下单发券) → P4 redeem + store(可核销) → P5 ops 后台 + settlement → P6 前端对齐 + smoke ``` **冻结规则**:P0~P1 期间不新增业务功能,只修迁移阻塞项。 --- ## 文件索引 | 文件 | 说明 | |------|------| | `prisma/init_v3.sql` | DDL 源 | | `prisma/schema.v31.prisma` | **新生成**,待激活 | | `prisma/schema.legacy-v21.prisma` | 旧版备份 | | `prisma/schema.prisma` | 当前运行版(**v3.1 已激活**) |