# 技术调研:商家门店分管账号 ## 1. 账号存储方案 ### 决策 分管账号继续存放在 `info_user`,使用新的 `user_type=5` 表示“商家分管账号”,并通过 `merchant_owner_id` 关联唯一的商家主账号。 ### 依据 - 商家端登录、JWT、Redis 会话、CID、语言和消息归属都以 `InfoUser.userId` 为中心,复用 `info_user` 可以保持现有认证与推送链路。 - 平台商家页固定传 `userType=1`,Mapper 使用 `user_type = #{userType}`;类型 5 天然不会进入商家列表、导出和商家数量统计。 - `user_type=4` 已用于摊位商家,不能复用。 ### 否决方案 - **分管账号仍使用 `user_type=1`,另加角色字段**:所有按 `user_type=1` 统计、审核和导出的查询都必须额外排除分管账号,漏改一个入口就会污染平台商家管理。 - **单独建立完整账号表**:需要复制登录、Token、CID、语言和消息体系,认证链路复杂且容易产生两套用户主键。 ## 2. 双重停用状态 ### 决策 - 复用 `info_user.status` 作为平台控制状态:`0=正常`、`1=平台停用`。 - 新增 `subaccount_status` 作为主账号控制状态:`0=启用`、`1=主账号停用`,只对类型 5 生效。 - 分管账号可用条件为:自身未删除、平台状态正常、主账号控制状态正常、所属主账号未删除且平台状态正常。 ### 原因 如果主账号和平台共用一个可写状态,主账号可以重新启用平台强制停用的账号。两个状态必须独立,并由不同接口控制。 ## 3. 店铺授权模型 ### 决策 新增 `merchant_subaccount_store` 多对多关联表。授权保存时同时校验:分管账号的 `merchant_owner_id` 等于 `pos_store.user_id`。 ### 原因 一个分管账号可负责多个店铺,一个店铺也可配置多个分管账号;JSON、逗号字符串或 `info_user.store_id` 都不能可靠表达该关系。 ## 4. 权限校验边界 ### 决策 在 `ruoyi-system` 建立统一的 `MerchantStoreAccessService`,每次业务请求从数据库读取当前账号和目标数据的真实门店归属: - 主账号可访问 `pos_store.user_id = 当前账号` 的全部门店。 - 分管账号只可访问关联表中的有效门店。 - 订单以 `pos_order.md_id`、商品以 `pos_food.md_id`、分类和规格以其实际关联商品或门店为准。 - 新增店铺、分管账号管理、支付配置、结算和提现必须调用 `requireOwner`。 不把店铺集合写入 Token,也不依赖前端传入的主账号 ID,因此撤销授权后下一次请求立即生效。 ## 5. 平台呈现 ### 决策 不新增顶级“商家”行或独立商家审核流程。在平台 `sjuser.vue` 的主商家操作区增加“分管账号”入口,以对话框/抽屉展示该主账号的下属账号。 平台可以修改 `info_user.status` 以强制停用或恢复,但不能修改 `subaccount_status`、密码或店铺授权。 ## 6. 在线状态与通知资格 ### 决策 - 平台“在线”状态:Redis 中存在该账号的商家 App 或 PC 有效会话。 - 外部推送资格:账号满足全部启用条件、拥有目标店铺授权、存在商家 App 有效会话且 CID 非空。 - 任一可接收分管账号存在时,消息分别归属这些账号,主账号不重复接收。 - 没有可接收分管账号时,消息归属主账号并尝试主账号推送。 - 外部推送按 CID 去重;站内消息仍按账号分别入库。 商家登录成功时更新 `last_login_at`。停用账号时删除其商家 App/PC Redis 会话;分管账号的每次业务请求仍重新检查数据库状态,不能只依赖会话存在。 ## 7. 现有代码风险与兼容措施 - `InfoUserController.shanglodeing` 当前允许类型 1、3、4,且没有校验 `status`。实现时加入类型 5,并在签发 Token 前统一执行账号可用性检查。 - `PosStoreController.addmendian`、`PosFoodController.setposfood` 等有效商家端写入口存在未声明 token 或信任请求体归属字段的情况。实现时按 Controller 规范补充 `@RequestHeader String token`,并从 Token 解析操作者。 - 平台商家列表、导出、统计仍使用 `user_type=1`,新增回归测试证明类型 5 不会出现或计数。 - `user_type=4` 的摊位逻辑、类型 3 的夜市逻辑保持不变;不能把分管账号塞入现有单店 `store_id` 规则。 - 当前工作区已有订单状态和推送调整,实施时必须在其基础上接入通知路由,不能覆盖或回退这些未提交改动。 ## 8. 安全要求 - 新接口使用明确 DTO 和 `@RequestBody`,App token 使用 `@RequestHeader`,不使用 `Map` 接收请求。 - 手机号、名称、密码和店铺 ID 集合在 Controller/Service 中显式校验;错误使用现有国际化机制。 - 密码沿用现有商家端 RSA 传输与存储兼容方式,禁止记录明文、密文或 Token。 - 所有 Mapper 使用参数绑定,不拼接用户输入 SQL。 - 批量授权在事务内完成;任一店铺越权时整体回滚。 - 通过实体真实归属校验订单、商品和退款,防止 IDOR(越权直接对象访问)。