petstore-docs/架构决策-门店开通与员工邀请-2026-08-02.md

5.5 KiB
Raw Blame History

架构决策:门店开通、一次性员工邀请与操作审计

日期2026-08-02
状态Accepted / Code Complete待生产迁移与微信真机验收
OwnerBackend Core + Store Miniapp FE + Store Admin FE
ReviewData Model / Architecture / Access & Privacy = Yes

1. 决策背景

旧流程把 Store.invite_code 当作永久共享凭证,公开员工注册只凭 8 位码和手填手机号即可创建 staff老板注册也接受未核验手机号和明文密码。Admin/小程序的“直接创建员工”还生成无法安全交付的初始密码。该模型不满足真实试点的身份核验、撤销、有效期、审计和离职失效要求。

本批目标不是扩展组织/权限系统,而是让 35 家独立单店能自行完成开通,并让受邀员工本人安全加入。

2. 已冻结决策

2.1 门店开通

  • 新老板只走 POST /api/onboarding/register-boss,服务端用微信 phoneCode 换取并核验手机号;不接受手填手机号或明文密码。
  • 新门店状态为 in_progress;历史门店无法可靠判断是否已完成开通,迁移统一写 unknown
  • 开通清单四步:门店资料、预约容量、服务项目为必填;邀请员工为选填,支持单人门店。
  • 只有 boss 可显式完成;完成回执保存 completed_at/by 并写 AuditLog。清单不阻断已有业务接口避免历史门店升级即停摆。

2.2 员工邀请

  • legacy invite_code 仅保留数据库兼容,不返回 Admin/小程序,不再参与查询或注册。
  • 老板创建 StaffInvitation姓名、本人微信手机号、130 天有效期。
  • token 使用 32 字节 SecureRandom256-bit原文只在创建响应返回一次数据库仅保存 SHA-256。
  • 邀请状态:pending → accepted,或 pending → revoked/expired;只能首次接受,已接受不能撤销。
  • 预览只返回门店名、受邀姓名、脱敏手机号、状态和有效期。
  • 接受时必须由微信换得的手机号与邀请绑定手机号精确匹配;成功后才创建 staff、消费邀请并签发 session。
  • 已存在 User/openid/unionid 冲突均拒绝。本期 User 仍是单角色模型,不把 customer 静默升级为 staff试点遇到冲突时使用独立工作手机号后续如有真实频次再引入 Account + StoreMembership。

2.3 会话与离职

HMAC 签名和过期校验之后,每次受保护请求继续读取活跃 User校验账号未删除且 role/storeId 与 token 一致boss/staff 还必须归属仍有效的 Store。删除员工、停用门店或权限范围变化后旧 token 立即 401无需等待 7 天到期。

2.4 AuditLog 与 BusinessEvent

  • BusinessEvent 记录可统计经营事实;本批补齐 store_registered
  • AuditLog 记录门店开通/设置与员工权限操作,只追加、不更新/软删。
  • Audit metadata 只允许服务端白名单标量禁止手机号、token/URL、openid/unionid、密码/密钥、IP、地址/坐标、备注/内容和原始请求体。

3. API 契约

方法 路径 权限 关键语义
POST /api/onboarding/register-boss public + 微信手机号核验 原子创建门店/老板,返回 session
GET /api/admin/onboarding boss/staff + 本店 计算开通清单
POST /api/admin/onboarding/complete boss + 本店 必填项齐全后显式完成
POST /api/admin/staff-invitations boss + 本店 原始 token 仅本响应一次
GET /api/admin/staff-invitations boss + 本店 脱敏列表,无 token/hash
DELETE /api/admin/staff-invitations boss + 本店 撤销 pending 邀请
GET /api/staff-invitations/preview public 脱敏预览
POST /api/staff-invitations/accept public + 微信手机号核验 手机号匹配才创建 staff

/api/user/register-boss/api/user/register-staff/api/user/create-staff/api/store/register/api/store/invite-code 保留兼容入口但只返回明确 410 业务码,不产生写入。

4. 数据迁移与不变量

迁移:backend/db/migrations/20260802_create_store_onboarding.sql,在前五个迁移之后第六个执行。

新增 6 项生产只读不变量,总数由 18 增至 24

  1. 门店开通状态枚举合法;
  2. completed 必须有完成回执;
  3. unknown/in_progress 不得带完成回执;
  4. 邀请状态枚举合法;
  5. accepted 与接受回执一致;
  6. revoked 与撤销回执一致。

5. 前端行为

  • Admin 设置页顶部显示开通清单,员工页改为邀请中心;创建后必须立即复制,之后只能撤销并重建。
  • 小程序老板可直接用 open-type=share 转发带受控 path 的邀请卡片。
  • 员工从卡片进入可先匿名预览,再点击微信手机号授权接受。
  • H5 允许预览,但不会提供绕过微信手机号核验的接受路径。

6. 明确不做

  • 不引入多门店组织、复杂 RBAC、StoreMembership、审批流或通用 IAM。
  • 不接入短信生产登录,不恢复明文密码交付。
  • 不调用微信 URL Link/小程序码后台 API试点先使用小程序原生分享卡片Admin 提供复制消息作为补充。
  • 不自动执行生产迁移、不改生产数据。

7. 回滚

应用回滚只切回前一 backend/Admin/H5/小程序版本;数据库新增列/表/索引保留,不执行 down migration不覆盖已经产生的邀请、审计或员工账号。旧应用会忽略新增结构但 legacy 注册仍应保持关闭,避免重新暴露永久凭证路径。