已实现
会员资料与账户
会员档案和登录账户分开绑定。会员请求从当前登录用户重新取得绑定,只能在服务层访问自己的预约;职员不能混入会员入口。
studio/portal_access.py:6–15 · portal_services.py:_ownedPROJECT CASE STUDY / WEB APPLICATION
已上线
围绕朋友的真实工作室需求,连接会员、预约与课时管理,让业务规则在软件中可靠落地。
BUSINESS RULES · TRACEABLE LEDGER · CLOUD DELIVERY
01 / PROJECT OVERVIEW
把工作室的预约、课时余额和操作原因连起来。每一个状态变化都应有业务含义,每一次扣课都应能解释,而不只是让一个余额数字变小。
02 / BACKGROUND
朋友经营小型健身工作室,需要管理会员、课程套餐、购课、可预约时段、余额与上课记录。手机上完成这些日常操作,比维护零散人工记录更方便。
项目围绕真实规则持续迭代:什么时候占用课时、取消何时扣课、教练取消如何补课、误扣后怎样保留证据。它是服务具体工作室的系统,不是已实现多租户的商业 SaaS。
THE PROBLEM
预约不能提前耗掉实际余额,又不能重复承诺同一份可用课时。取消、爽约、改期和冲正还会改变预约状态,需要与余额、流水及会员权限同时保持一致。
03 / MY ROLE
在 AI 辅助下参与需求梳理、业务规则制定、功能迭代与验收,并实践 Linux 生产部署。
项目在 AI 辅助下完成迭代。这里展示实际参与的需求、业务判断、实现与验收,不把辅助生成等同于独立精通。
MY DECISIONS / 个人贡献与取舍
我的工作从工作室的日常流程开始:会员购课后能预约多少次,哪些取消会扣课,误操作怎样恢复。这些问题必须先有统一规则,页面和数据库才能围绕同一种含义实现。开发中使用 AI 辅助,我承担需求与规则判断、功能迭代、测试验收和部署维护,而不是声称每行代码都由我独立手写。
预约只占用可用课时,不立即扣余额。规则演示(非真实会员数据):余额为 10、待上课占用 1 时,可用为 9;正常完成后增加一笔 -1 流水,余额汇总为 9,待上课占用释放。迟取消和爽约也扣一次;教练取消只释放占用、不产生扣课流水,另安排补课。余额来自流水汇总,不是额外维护一份随时可能失配的数字。
完整链路是会员选择时段 → 身份与可用课时校验 → 创建预约并占用 → 按完成/取消/爽约结果分支 → 必要时写扣课流水并汇总余额 → 记录状态与操作事件。重复完成先返回已有状态;其他非法状态明确拒绝。改期生成替代预约,取消判断用新时间,会员成功自行改期后锁定再次自主取消/改期。每次操作仍要确认当次规则。
权限隔离需要在服务端重新确认会员绑定,不能信任前端传来的会员编号;身份、规则、状态变更在事务中处理。SQLite 使用 IMMEDIATE 事务与锁忙重试提示,不把 select_for_update 描述成 SQLite 行锁,也不据此宣称已经证明高并发能力。
部署上,浏览器经 HTTPS/Caddy 到 Gunicorn、Django 和 SQLite,应用使用 Docker。持久化、迁移、静态资源检查和发布前备份有历史记录;回滚需兼顾新业务账目,不能拿旧库直接覆盖。教练端与会员端已上线;历史多阶段测试记录存在,但最新完整会员手机流程、流水联调及恢复演练仍需补齐签字。
依据:RC1 studio/services.py:161–163,306–372;portal_services.py:19–35,100–111,134–192;portal_access.py:6–15;已有脱敏部署记录。
04 / TECH STACK
05 / SYSTEM ARCHITECTURE
访问链路为浏览器 → HTTPS → Caddy → Gunicorn → Django → SQLite。上线依据后续 RC1 部署记录;本轮仅核验本地源码与记录,不重新连接生产或验证恢复演练。
06 / CORE FEATURES
已实现
会员档案和登录账户分开绑定。会员请求从当前登录用户重新取得绑定,只能在服务层访问自己的预约;职员不能混入会员入口。
studio/portal_access.py:6–15 · portal_services.py:_owned已实现
教练、课程套餐、购课与课时关联。余额以流水汇总为依据,可用课时扣除待上课占用,避免把显示余额当作可自由预约额度。
studio/services.py:credit_snapshot / register_purchase已实现
提供可预约时段与会员预约。改期新建有前后继关系的预约并重新计算截止;教练取消不扣课,补课保留来源。
studio/portal_services.py:member_reschedule · services.py:create_makeup_booking已实现
会员每次取消或改期必须明确确认当前规则版本。成功自主改期一次后,预约链保持自主操作锁定,不能再次自行取消或改期;授权职员仍可处理。
studio/portal_services.py:85–111,135–192已实现
具备相应会员权限的职员可以开户。表单把新账户固定为普通用户,会员、账户、绑定与审计共同置于事务内,阻止重复绑定。
studio/forms.py:MemberAccountOpeningForm · views.py:MemberAccountCreateView已实现
完成、迟取消与爽约按规则记一次负流水;授权冲正新增反向流水,不抹去原扣课,并记录原因和操作者。
studio/services.py:complete_booking / restore_booking · models.py:LessonEntry| 业务操作 | 课时与状态处理 |
|---|---|
| 预约成功 | 只占用可用课时,不立即扣实际余额。 |
| 正常完成 | 课程结束后确认完成,按预约成本扣一次;重复提交不再扣。 |
| 迟取消 / 爽约 | 按规则扣一次,保留独立状态与原因。 |
| 教练取消 / 补课 | 原课不扣,释放占用并建立关联补课;补课按自身结果记账。 |
| 误扣冲正 | 新增正向流水并关联原扣课,原记录保留;不重复恢复。 |
| 改期截止 | 依据新预约的上课日期重新判断取消截止,不沿用旧日期。 |
| 会员自主改期一次 | 成功后沿预约前序链保持锁定,禁止再次自行改期或取消。 |
| 逐次确认 | 每次取消或改期要求当前规则版本与明确确认,并保存规则快照。 |
| 余额一致性 | 实际余额来自流水,可用课时扣除待上课占用;状态、流水和事件在事务内一起提交。 |
07 / TECHNICAL CHALLENGES
规则之间存在依赖:只在页面上隐藏按钮不够,只给扣课函数加一个判断也不够。约束必须进入服务层、数据模型和可核对的记录。
08 / SOLUTIONS
同样叫“取消”,会员、教练、迟取消和改期后的取消可能产生不同结果。
服务层按当前预约状态和上课日期计算结果;改期创建关联后继。会员端额外记录规则版本、文本快照与确认时间,自主改期锁定沿前序链传递。
代码依据 studio/services.py:cancel_outcome / reschedule_booking · portal_services.py:member_locked
重复点击、请求重试或并发状态变更可能争用同一预约和可用课时。
状态终态检查、请求 UUID 与内容摘要、唯一/检查约束共同兜底。SQLite 采用 IMMEDIATE 事务和有限等待,写入前取得数据库级写保留锁;失败回滚或返回可重试错误。
代码依据 studio/services.py:operation / _consume · config/settings.py:transaction_mode
实现边界:SQLite 不是行级锁。该机制和已有测试不等于生产高并发、跨进程压力或断电恢复已全面验证。
只改余额会丢失原因;写了扣课却没更新预约,会让下一次处理含义不清。
以 LessonEntry 汇总余额,credit_snapshot 同时读取占用。统一业务事务处理预约状态、流水与 BookingEvent;冲正记录关联原流水,保留审计轨迹。
代码依据 studio/services.py:credit_snapshot / complete_booking / restore_booking · models.py:LessonEntry
登录成功或前端按钮限制,不能阻止用户伪造他人的预约编号或权限参数。
portal_access 每次根据当前用户重新绑定会员;_owned 用预约主键与会员同时筛选。开户表单固定普通用户标志,服务层再次校验归属与规则确认。
代码依据 studio/portal_access.py · portal_services.py:_owned / _rule · forms.py:MemberAccountOpeningForm
实现边界:这是会员资料归属与角色权限隔离,不把它称作已完成的多租户平台。
本地能打开页面,不意味着升级不会丢数据,或 HTTPS 与后端暴露方式正确。
使用 Docker、Gunicorn、Caddy 和持久化配置。后续部署记录保留迁移、健康状态及 HTTPS/静态资源验证结果;版本切换前考虑备份与回滚。
代码依据 Dockerfile · compose.yaml · RC1 部署记录(脱敏摘要)
实现边界:本轮未运行服务器命令;持续运行、完整实机业务验收与恢复责任仍需后续确认。
SOURCE EXCERPT
完成操作对已完成预约直接返回,拒绝不合适状态和提前完成,再调用统一扣课并写事件。并发保护还依赖 operation 装饰器和数据库约束,不能只从这一个判断推断全部保证。
RC1 · studio/services.py:306–320 · complete_booking@operation("complete_booking")
def complete_booking(booking_id, *, actor, reason="确认课程完成"):
reason = _reason(reason)
booking = _get(Booking, booking_id)
if booking.status == Booking.Status.COMPLETED:
return booking
if booking.status != Booking.Status.PENDING:
raise BusinessError("仅待上课预约可以确认完成。")
if booking.ends_at > timezone.now():
raise BusinessError("课程尚未结束,不能提前确认完成。")
_consume(booking, LessonEntry.Kind.COMPLETE, actor, reason, booking.ends_at)
booking.status = Booking.Status.COMPLETED
booking.save(update_fields=["status", "updated_at"])
_event(booking, "complete", actor, reason, before="pending", after="completed")
return booking来自已核验的本地源码节选;为便于阅读保留原有实现片段,不是完整可运行模块。
DEVELOPMENT PROCESS
按现有实现与版本资料整理阶段,不推断未经确认的具体开发日期。
围绕工作室真实日常确认预约占用、取消时限、补课和冲正,逐步形成可说明的状态流转。
在管理端基础上增加会员账户、可用时段、预约与记录,并把归属检查、规则确认和自主改期锁定落到服务层。
保留关键规则、重复操作和竞争场景的回归设计;后续 RC1 记录包含迁移、容器健康与 HTTPS 验证,不把早期部署准备文档当作最终状态。
09 / TESTING & VALIDATION
早期源码保存了扣课、改期和 SQLite 竞争等回归测试;较新交付包提供会员端实现,但该包未附完整测试源码。下面区分已有测试依据与应继续执行的验收设计。
已有早期测试检查余额与可用课时区别,并验证重复完成不重复记账。
早期回归:studio/tests/test_bookings.py:test_booking_reserves_available_but_does_not_deduct_ledger / test_complete_deducts_once_and_records_event已有早期测试检查新日期的取消规则、冲突回滚、补课来源以及一次扣课。
早期回归:studio/tests/test_m5_confirmed_rules.py · test_m4_rules.py已有文件 SQLite + 独立连接的竞争测试,检查同时完成、时段争用、锁等待和回滚。
早期回归:studio/tests/test_concurrency.py · test_bookings.py:test_failure_between_ledger_and_state_rolls_back已核验 _owned、_rule、member_locked 等实现。验收设计:伪造他人预约应拒绝;旧规则需重确认;一次自主改期后再次取消/改期应拒绝。
RC1 源码核验 / 后续验收设计:studio/portal_services.py:38–192历史 RC1 记录包含迁移、健康状态和 HTTPS/静态资源检查;完整正式版身份隔离与扣课联调、长期运行和恢复演练仍需明确。
后续部署记录:DEPLOYMENT_RESULT.md(已脱敏核对)以上为业务项目源码中的验证设计与测试依据。本轮验证的是作品集网站,没有重新运行这些业务项目的完整测试,也没有对线上系统做操作。
10 / RESULTS
教练端与会员端已完成上线,后续记录包含迁移成功、容器健康以及 HTTPS 和静态资源验证。这证明项目经历了部署交付,不代表已拥有大量用户、长期稳定运营或完整恢复验收。
11 / FUTURE IMPROVEMENTS
以下是后续改进方向,不是已完成能力。
PROJECT GALLERY

这张是真实教练端首页:展示新增会员、查看会员、创建预约及今日课程入口。空状态不证明完整会员流程验收;会员端、预约过程与脱敏验收截图尚待补充。
已展示使用者提供的真实界面。脱敏报表和更多业务场景待补充;不以空数据截图证明识别准确率、运营规模或完整验收。
朋友经营小型健身工作室,需要方便地管理会员、课程、预约和课时。项目围绕实际经营者展开,不以商业化 SaaS 为目标。
我把业务中的例外情况整理为规则,在 AI 辅助下迭代功能,并通过验收检查规则是否被正确执行。
通过持续迭代自动化测试,覆盖预约、课时扣减、权限、并发及状态变更等关键业务流程。
此处不展示未经对应测试报告核实的精确数量、覆盖率或性能指标。测试与业务验收共同帮助发现规则遗漏。
采用 Python、Django、SQLite、Docker Compose、Gunicorn 和 Caddy,在 2 核 CPU、2GB RAM 的 Linux 云服务器上部署。2026 年 11 月初,教练端与会员端已上线。
实践涵盖数据库持久化、域名、HTTPS、健康检查、版本升级、备份与回滚准备及临时演示环境清理。上线状态依据项目经历陈述,不代表已经拥有大量用户。
真实业务的难点往往在状态与边界条件。把规则说清楚、用测试验证、留下可追溯记录,和写出页面一样重要。
AI 能帮助实现与排错,但业务判断、验收和持续理解代码仍需要自己承担。