【架构实战】从业务逻辑到工程落地:私教预约系统的三大核心模型解析
目录
- 引言:设计与工程的分水岭
- 一、分层 ER 模型(系统的数据骨架)
- 1. 第一层:用户与角色层(Actor)
- 2. 第二层:交易与资产层(核心商业闭环)
- 3. 第三层:履约调度层(系统的真正枢纽)
- 二、状态机设计(系统的行为约束)
- 1. Booking(预约单)状态机
- 2. Order(交易单)状态机
- 3. CourseCard(课时卡)状态机
- 三、基于数据边界的权限矩阵(RBAC)
- 权限矩阵一览
- 💡 权限设计三大铁律:
- 四、一句话收束
摘要:在上一篇文章中,我们完成了私教健身管理系统的业务边界划分与领域模型推演。但“架构图”如何平滑过渡到“工程代码”?在进入具体的数据库建表(无论是使用原生 SQL 还是 Prisma 等现代 ORM 工具)之前,我们必须先交付系统设计真正落地的三张核心图纸:ER 实体关系模型、核心状态机、以及基于数据边界的 RBAC 权限矩阵。
引言:设计与工程的分水岭
很多开发者在拿到需求后,习惯性地凭借直觉去建表,这往往会导致后期业务扩展时牵一发而动全身。
一个高健壮性的 B 端交易与调度系统,其底层基建必须由三个维度共同支撑:
- ER 模型:决定了系统世界里“有什么”。
- 状态机设计:决定了系统世界“怎么动”。
- 权限模型:决定了“谁能推动这个世界”。
接下来,我们将把抽象的业务概念,直接展开为研发级、可直接用于数据库建模与低代码配置的结构。
一、分层 ER 模型(系统的数据骨架)
不要一上来就罗列几十张表,优秀的数据库设计必须是分层的。以下是经过业务提纯后的核心数据结构。
1. 第一层:用户与角色层(Actor)
核心思想:统一身份,分离职责。所有人员统一在User表中,通过role字段分化行为,避免多表关联带来的灾难。
- User(统一用户表)
id/role(STUDENT | TRAINER | ADMIN) /name/phone/email/status
2. 第二层:交易与资产层(核心商业闭环)
这一层负责记录“钱的流动”与“服务权利的确权”。商品是静态的,订单是一次性的,而课时资产(CourseCard)才是伴随用户整个生命周期的核心。
Course(课程商品 SKU)
id/title/type(如 1v1 / 1v2 等) /price/sessions_total(包含课时数) /statusOrder(交易流水单)
id/order_no/user_id/course_id/final_price/status/pay_timeCourseCard(课时资产本)
id/student_id/course_id/order_id/total_sessions(总额度) /used_sessions(已用) /remaining_sessions(余额) /status
3. 第三层:履约调度层(系统的真正枢纽)
这是整个系统最复杂、并发最高的区域。Booking表是毫无争议的核心枢纽,所有的状态流转都必须经过它。
TrainerSchedule(供给侧资源池)
id/trainer_id/date/start_time/end_time/capacity_total/capacity_booked/status设计意图:将教练的时间切割为标准化的“库存资源”。
Booking(预约履约单)
id/booking_no/student_id/course_card_id/schedule_id/status/check_in_time/is_deducted(是否已扣课标记)设计意图:绑定人(Student)、资产(CourseCard)与资源(Schedule)。
SessionRecord(课时流水账)
id/student_id/course_card_id/booking_id/type(RECHARGE | CONSUME) /sessions/remark设计意图:防篡改设计。任何课时余额的变化,必须在这里有确切的流水留痕。
二、状态机设计(系统的行为约束)
业务表绝不能随意UPDATE,核心业务实体的生命周期必须由严格的单向状态机驱动。这能从根源上杜绝“脏数据”与“非法操作”。
1. Booking(预约单)状态机
⚠️关键认知:Booking 不仅仅是一条记录,它是“状态驱动的引擎”。
流转路径:
UPCOMING(已预约未上课) → 学员签到/教练上课 →COMPLETED(正常完成)UPCOMING→ 提前主动取消 / 系统冲突强取 →CANCELLED(取消并释放资源)UPCOMING→ 约定时间未签到 →NO_SHOW(爽约/未到课)
2. Order(交易单)状态机
流转路径:
PENDING(待支付) →PAID(已支付成功)PENDING→CANCELLED(超时未支付/主动取消)PAID→REFUNDED(发起退款)- 强约束:只有当状态切为
PAID时,系统才能下发CourseCard(课时资产)。
3. CourseCard(课时卡)状态机
流转路径:
VALID(正常可用) → 余额扣减为 0 →EXHAUSTED(课时用尽)VALID→ 超过绝对有效期 →EXPIRED(过期作废)VALID/EXHAUSTED→ 发生退费 →REFUNDED(已冻结/退款完成)
三、基于数据边界的权限矩阵(RBAC)
在 B 端系统中,权限设计最容易踩坑的地方在于:混淆了“功能权限”与“数据权限”。
一个教练和一个老板都可以拥有“查看预约(View Booking)”的功能权限,但他们看到的数据范围(Scope)绝对是天壤之别。
核心公式:权限 = Role (角色) + Resource (资源) + Action (操作) + Scope (数据边界)
权限矩阵一览
| 模块 | STUDENT (学员) | TRAINER (教练) | ADMIN (管理员) |
|---|---|---|---|
| Course (课程库) | ✔ 仅查看上架商品 | ✔ 仅查看上架商品 | ✔ 增删改查全权限 |
| Booking (预约单) | ✔ 创建/取消本人预约✔ 查看本人记录 | ❌ 不可创建✔ 查看/处理关联自己的预约 | ✔ 代客预约✔ 全局查看与强制改单 |
| CourseCard (资产) | ✔ 查看本人余额与流水 | ❌ 无权访问 | ✔ 全局管理与手动调账 |
| Schedule (排班) | ✔ 查看公开可用时间 | ✔ 创建/修改本人排期 | ✔ 全局调度与统筹排班 |
| SessionRecord | ✔ 查看本人扣除流水 | ✔ 查看所授课程流水 | ✔ 全局审计与追溯 |
💡 权限设计三大铁律:
- 学员的隔离性:绝对的“孤岛”,只能看到与自己 ID 绑定的所有业务数据。
- 教练的局部域:基于关联关系(如
trainer_id)构建数据视图,能看自己的排班和上课学员,但绝不能看到同事的数据或门店的财务数据。 - 管理员的全局观:掌握绝对控制权,用于处理极端异常(如退费回滚、异常排课冲突处理)。
四、一句话收束
回到我们开篇的论调:
- ER 模型决定了“系统世界有什么”;
- 状态机决定了“世界里的元素怎么合理地互动”;
- 权限模型决定了“谁有资格去推动这个世界”。
下一步预告:
当这三套模型在图纸上彻底咬合后,我们距离真正的工程落地就只剩下一层薄纱了。在下一篇文章中,我们将直接进入代码层,演示如何将这些精心设计的架构,优雅地翻译成现代 ORM(如 Prisma)的 Schema 定义,并在此基础上构建全栈 Serverless API 接口。敬请期待!
