From d6af71ec147e68e9026183461cd5d55e362a0e20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=98=BF=E7=B1=B3=E7=8B=97?= Date: Tue, 17 Feb 2026 19:29:09 +0800 Subject: [PATCH] feat: add Phase D - system design (functions + business flows + DB design) --- SYSTEM_DESIGN.md | 371 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 371 insertions(+) create mode 100644 SYSTEM_DESIGN.md diff --git a/SYSTEM_DESIGN.md b/SYSTEM_DESIGN.md new file mode 100644 index 0000000..014a611 --- /dev/null +++ b/SYSTEM_DESIGN.md @@ -0,0 +1,371 @@ +# iShare 系统设计文档 + +> 优先级:最高(先于所有开发任务) +> 版本:v1.0 +> 日期:2026-02-17 + +--- + +## 一、系统角色 + +| 角色 | 说明 | +|------|------| +| **普通用户** | 注册登录,购买合租商品,获取账号凭据 | +| **车主(发布者)** | 发布自己的合租位(个人拼车广场) | +| **平台运营(管理员)** | 管理平台数据、自营商品、用户、订单 | +| **超级管理员** | 全局配置,含财务、权限管理 | + +--- + +## 二、功能模块清单 + +### 2.1 用户端 H5 功能 + +| 模块 | 功能点 | +|------|--------| +| **账号** | 手机号注册/登录、邮箱注册/登录、找回密码(验证码)、微信/社交登录(二期) | +| **首页** | 平台分类Tab、推荐商品卡片、Banner 广告位、热门合租榜 | +| **商品列表** | 按平台类型筛选、按价格/评分排序、关键词搜索 | +| **商品详情** | 平台介绍、套餐选择(月/季/年)、评价列表、剩余席位数、立即购买 | +| **购买流程** | 选套餐 → 确认订单 → 支付(余额/在线支付)→ 获取账号凭据 | +| **我的订阅** | 当前有效订阅列表、账号凭据查看、续费、退订 | +| **广场/拼车** | 浏览他人发起的合租位、申请加入、发起自己的合租 | +| **推广中心** | 邀请码、邀请记录、返现奖励记录 | +| **钱包** | 余额查看、充值、提现(二期)、流水记录 | +| **通知** | 续费提醒、订单状态变更、系统公告 | +| **个人中心** | 基本信息编辑、头像、安全设置(改密)、退出登录 | + +### 2.2 管理后台功能 + +| 模块 | 功能点 | +|------|--------| +| **平台管理** | 平台CRUD、平台分类CRUD、图标上传 | +| **订阅计划管理** | 计划CRUD、付费方案CRUD(多地区/多货币) | +| **自营商品管理** | 商品CRUD、上下架、库存(账号)管理、绑定账号凭据 | +| **订单管理** | 订单列表、状态查看、人工审核、退款处理 | +| **用户管理** | 用户列表、封禁/解封、余额调整、查看订阅记录 | +| **评价管理** | 评价列表、违规删除 | +| **财务管理** | 收入统计、提现申请审核(二期)、优惠券管理(二期) | +| **通知配置** | 系统通知模板、续费提醒开关 | +| **系统配置** | 站点信息、支付配置、短信/邮件配置 | + +--- + +## 三、核心业务流程 + +### 3.1 用户注册/登录 + +``` +[用户] → 输入手机/邮箱 + → 获取验证码(短信/邮件) + → 验证 → 首次登录自动注册 app_user + → 生成 JWT Token(复用 pigx-auth) + → 进入首页 +``` + +### 3.2 购买合租商品(核心流程) + +``` +[用户] → 浏览商品列表(as_sub_product, status=上架) + → 商品详情页 + ├── 查看剩余席位 = capacity - capacity_loaded(来自 as_user_sub 聚合) + └── 选择付费方案(as_sub_payroll) + → 点击"立即购买" + → 创建订单(as_order, status=待支付) + → 支付 + ├── 余额支付 → 扣减 as_wallet.balance + └── 在线支付 → 支付宝/微信回调 → 更新订单状态 + → 支付成功 + ├── 订单状态 → 已支付 → 使用中 + ├── 创建 as_user_sub 记录(capacity_loaded +1) + ├── 返回账号凭据(as_sub_account 解密后展示) + └── 推送通知(订阅成功) +``` + +### 3.3 账号凭据查看 + +``` +[用户] → "我的订阅" → 选择订阅 + → 验证身份(二次密码/生物识别,可选) + → 从 as_sub_account 查询 account_name + account_passwd + → AES 解密 account_passwd(服务端解密,不返回明文密钥) + → 展示账号密码(可设置自动隐藏倒计时) +``` + +### 3.4 订阅到期/续费 + +``` +[定时任务(每日凌晨)] + → 扫描 as_user_sub.expire_time < now() + 7天 + → 发送续费提醒通知(as_notification) + → 到期当日:as_user_sub.status = expired + → capacity_loaded -1(释放席位) + +[用户续费] + → 进入"我的订阅" → 点击续费 + → 选择续费套餐 → 走购买流程(复用) + → 续费成功:as_user_sub.expire_time 延长 +``` + +### 3.5 广场拼车(个人发布) + +``` +[车主] + → 填写合租信息(平台、计划、价格、总席位数、说明) + → 创建 as_sub_product(product_type=2 个人) + → 提交审核 → 管理员审核通过 → 上架(status=active) + +[拼车者] + → 广场浏览 → 找到心仪的拼车 + → 申请加入 → 走购买流程 + → 成功后 → 车主将账号凭据录入 as_sub_account + → 拼车者可查看凭据 +``` + +### 3.6 推广/邀请 + +``` +[用户A] → 分享邀请码/链接 +[用户B] → 点击链接注册 + → as_invite 记录(inviter=A, invitee=B) +[用户B首次购买成功] + → 触发返现奖励 + → as_wallet_log 记录(用户A 获得返现) + → as_wallet.balance 增加 +``` + +--- + +## 四、数据库设计(完整版) + +### 4.1 现有表评审与修订 + +#### ⚠️ 现有设计问题 + +| 表 | 问题 | 修订方案 | +|----|------|----------| +| `as_sub_account` | `passwd_salt` 是 int,不够安全;缺加密字段标记 | 改为 varchar salt,加 `encrypt_type` 字段 | +| `as_sub_account` | 缺 `status` 字段(账号可能失效/被封) | 加 `status`: 0=正常,1=失效,2=异常 | +| `as_user_sub` | 缺 `status`、`start_time`、`expire_time` | 补充状态和时间字段 | +| `as_user_sub` | `remark` 字段类型是 int(应为 varchar) | 改为 varchar | +| `as_sub_product` | 缺 `status`(上架/下架/售完)、`available_seats` | 补充状态和实时剩余席位 | +| `as_sub_product` | `sub_plan_ids` 用逗号分隔(反范式) | 评估是否改为关联表(影响查询) | +| `as_sub_payroll` | 缺促销价/折扣字段 | 加 `original_price`、`discount_rate` | +| `as_platform_type` | `platform_type` 是 int,0=全部 含义混乱 | 改用独立 sort_order + is_all 标志位 | + +### 4.2 核心业务表(完整版) + +#### 保留现有(修订后) + +- `as_platform` +- `as_platform_type` +- `as_sub_plan` +- `as_sub_payroll`(加 original_price, discount_rate) +- `as_sub_account`(加 status, encrypt_type, 改 passwd_salt 为 varchar) +- `as_sub_product`(加 status, available_seats) +- `as_sub_product_comment` +- `as_user_sub`(加 status, start_time, expire_time, 改 remark 为 varchar) + +#### 新增表 + +--- + +### `as_order` — 订单表 + +| 字段 | 类型 | 说明 | +|------|------|------| +| `id` | bigint PK | 订单ID | +| `order_no` | varchar(32) | 订单号(唯一,业务用) | +| `user_id` | bigint | 购买用户 | +| `product_id` | bigint | 商品ID (as_sub_product) | +| `payroll_id` | bigint | 付费方案ID (as_sub_payroll) | +| `amount` | decimal(10,2) | 实付金额 | +| `original_amount` | decimal(10,2) | 原价 | +| `discount_amount` | decimal(10,2) | 优惠金额 | +| `pay_type` | tinyint | 支付方式: 1=余额, 2=支付宝, 3=微信 | +| `pay_no` | varchar(64) | 第三方支付单号 | +| `status` | tinyint | 0=待支付, 1=已支付, 2=已完成, 3=已退款, 4=已取消 | +| `user_sub_id` | bigint | 关联的用户订阅ID (创建后填充) | +| `remark` | varchar | 备注 | +| `expire_time` | datetime | 订单过期时间(未支付自动取消) | +| `pay_time` | datetime | 支付时间 | +| `create_time` | datetime | | +| `update_time` | datetime | | + +--- + +### `as_wallet` — 用户钱包 + +| 字段 | 类型 | 说明 | +|------|------|------| +| `id` | bigint PK | | +| `user_id` | bigint UNIQUE | 用户ID(一人一钱包) | +| `balance` | decimal(10,2) | 可用余额 | +| `frozen_amount` | decimal(10,2) | 冻结金额(待退款/提现) | +| `total_income` | decimal(10,2) | 累计收入 | +| `total_expense` | decimal(10,2) | 累计支出 | +| `create_time` | datetime | | +| `update_time` | datetime | | + +--- + +### `as_wallet_log` — 钱包流水 + +| 字段 | 类型 | 说明 | +|------|------|------| +| `id` | bigint PK | | +| `user_id` | bigint | 用户ID | +| `amount` | decimal(10,2) | 金额(正=收入,负=支出) | +| `type` | tinyint | 1=充值, 2=消费, 3=退款, 4=邀请返现, 5=提现 | +| `order_id` | bigint | 关联订单ID(可空) | +| `balance_after` | decimal(10,2) | 操作后余额(快照) | +| `remark` | varchar | 说明(如"订阅 Netflix 高级版") | +| `create_time` | datetime | | + +--- + +### `as_invite` — 邀请关系 + +| 字段 | 类型 | 说明 | +|------|------|------| +| `id` | bigint PK | | +| `inviter_id` | bigint | 邀请人用户ID | +| `invitee_id` | bigint | 被邀请人用户ID | +| `invite_code` | varchar(16) | 使用的邀请码 | +| `reward_amount` | decimal(10,2) | 返现金额 | +| `reward_status` | tinyint | 0=待发放, 1=已发放(首次购买后触发) | +| `create_time` | datetime | | +| `reward_time` | datetime | 返现时间 | + +--- + +### `as_notification` — 通知消息 + +| 字段 | 类型 | 说明 | +|------|------|------| +| `id` | bigint PK | | +| `user_id` | bigint | 目标用户ID(0=全部用户) | +| `title` | varchar | 通知标题 | +| `content` | varchar | 通知内容 | +| `type` | tinyint | 1=续费提醒, 2=订单通知, 3=系统公告, 4=邀请奖励 | +| `ref_id` | bigint | 关联业务ID(如订单ID、订阅ID) | +| `is_read` | tinyint | 0=未读, 1=已读 | +| `create_time` | datetime | | + +--- + +### `app_user` 字段补充 + +在现有 PigX 的 `app_user` 表上,补充以下字段(via ALTER): + +| 字段 | 类型 | 说明 | +|------|------|------| +| `invite_code` | varchar(16) UNIQUE | 用户的专属邀请码(注册时生成) | +| `inviter_id` | bigint | 邀请人用户ID(注册时记录) | + +--- + +### 4.3 完整 ER 关系图 + +``` +as_platform_type (1) ──< (N) as_platform [platform_type] +as_platform (1) ──< (N) as_sub_plan [platform_id] +as_sub_plan (1) ──< (N) as_sub_payroll [sub_plans] +as_sub_plan (N) >──< (N) as_sub_product [sub_plan_ids] +as_sub_product (1) ──< (N) as_sub_product_comment [product_id] +as_sub_product (1) ──< (N) as_sub_account [product_id] +as_sub_plan (1) ──< (N) as_sub_account [sub_plan_id] +as_sub_payroll (1) ──< (N) as_sub_account [sub_payroll_id] + +as_sub_product (1) ──< (N) as_order [product_id] +as_sub_payroll (1) ──< (N) as_order [payroll_id] +as_order (1) ──< (1) as_user_sub [user_sub_id] + +as_sub_plan (1) ──< (N) as_user_sub [plan_id] +as_sub_account (1) ──< (N) as_user_sub [main_account] + +app_user (1) ──< (1) as_wallet [user_id] +as_wallet (1) ──< (N) as_wallet_log [user_id] +as_order (1) ──< (N) as_wallet_log [order_id] + +app_user (1) ──< (N) as_order [user_id] +app_user (1) ──< (N) as_user_sub [user_id] +app_user (1) ──< (N) as_sub_product [user_id — 发布者] +app_user (1) ──< (N) as_sub_account [user_id — 账号持有者] +app_user (1) ──< (N) as_sub_product_comment [user_id] +app_user (1) ──< (N) as_notification [user_id] + +app_user (1) ──< (N) as_invite [as inviter] [inviter_id] +app_user (1) ──< (1) as_invite [as invitee] [invitee_id] +``` + +### 4.4 `as_user_sub` 状态机 + +``` + 购买成功 +[pending] ──────→ [active] ──→ 到期 ──→ [expired] + │ │ + │ 退款/申请退订 │ 续费 + ↓ ↓ + [cancelled] [active] +``` + +状态值:0=待激活, 1=使用中, 2=已到期, 3=已退订 + +### 4.5 `as_order` 状态机 + +``` +[pending] → 15分钟未支付 → [cancelled] +[pending] → 支付成功 → [paid] → 激活订阅成功 → [completed] +[paid/completed] → 退款申请 → 审核通过 → [refunded] +``` + +--- + +## 五、接口设计要点 + +### 5.1 账号凭据安全 + +- `account_passwd` 使用 **AES-256-GCM** 加密存储 +- 密钥由服务端持有(存配置中心/环境变量),不入库 +- `passwd_salt` 用于 AES 的 IV(改为 varchar(32),16字节随机) +- 凭据查看接口:仅限订阅状态为 `active` 的用户,且需校验 `as_user_sub.user_id == currentUser` +- 返回解密后的明文,但 **不记录日志**(防止泄露) + +### 5.2 席位并发控制 + +- 购买时使用 **数据库乐观锁** 或 **Redis 分布式锁** 防止超卖 +- `as_sub_product.available_seats` 在下单时 -1(乐观锁 version 字段) +- 订单取消/超时后 +1 回补 + +### 5.3 价格一致性 + +- 订单金额在创建时 **快照** 到 `as_order.amount` +- 不依赖付费方案的实时价格(防止价格变动导致差异) + +--- + +## 六、设计待决策项(需 Ami 确认) + +| # | 问题 | 选项 | +|---|------|------| +| 1 | 付费方式一期支持哪些? | A) 仅余额(人工充值)B) 余额+支付宝 C) 三种都支持 | +| 2 | 拼车广场是否需要审核流程? | A) 管理员审核 B) 自动上架 C) 仅自营,无拼车广场 | +| 3 | 账号凭据展示方式? | A) 直接明文 B) 需二次验证(短信/密码)C) 限时展示(30s后隐藏)| +| 4 | 邀请返现比例和条件? | 需定义:返现金额/比例,是否有上限 | +| 5 | `as_sub_product` 的多计划关联是否改为关联表? | A) 保持逗号分隔(简单)B) 改关联表(规范,便于查询)| +| 6 | 提现功能是否一期上线? | A) 一期上 B) 二期(一期只充值不提现)| + +--- + +## 七、调整后的项目阶段 + +| 阶段 | 内容 | 时间 | +|------|------|------| +| **Phase D(当前·最高优先)** | 系统设计:功能清单 + 业务流程 + 数据库设计 | 进行中 | +| **Phase 0** | 环境搭建:仓库 + Fork PigX + CI/CD + 建库 SQL | D 完成后 | +| **Phase 1** | 后端核心 CRUD API | 1-2周 | +| **Phase 2** | 管理后台前端 | 1周 | +| **Phase 3** | 用户端 H5 | 2-3周 | +| **Phase 4** | 支付集成 | 按需 | +| **Phase 5** | 测试 + 上线 | — |