← 返回文章列表

转班之后,历史学情究竟属于哪个班

从 Enrollment 时间线与 Learning Episode 出发,解释当前成员关系为什么不能改写历史教学证据。

返回 TeachFlow 项目总览

学生从 A 班转到 B 班之后,昨天在 A 班完成的作业应该出现在谁的班级轨迹里?如果系统每次都拿“当前班级”去关联历史作答,答案会变成 B 班。这在查询上很方便,在事实语义上却是错的。

TeachFlow 遇到的不是一个报表筛选问题,而是两个时间问题:

  • 现在谁属于哪个班;
  • 一条学习事件发生时属于哪个教学语境。

Current 不能倒推 History

Enrollment 表达当前和历史成员关系;Learning Episode、Publication、Assignment 与 Evidence 则保存一次教学活动发生时的上下文。学生转班只会关闭旧关系并打开新关系,不应该搬运已经发生的课堂和作业事实。

学生转班前后的当前关系与历史证据归属

图中的关键点是:T2 之后学生的当前班级变成 B,但 E1 和 E2 仍然属于 A 班当时的课程与作业;B 班只能拥有转班后发生的 E3。教师查看历史轨迹时,人数、覆盖率和掌握分布也应使用那个时间点的成员与事件,而不是今天的 Current。

为什么只保存 classroomId 还不够

一个 ID 能说明“属于哪个班”,却不能独立回答:

  • 当时的 Enrollment 是否有效;
  • 使用的是哪个课程 Publication 和图版本;
  • 这是课堂、作业、诊断还是迁移练习;
  • 后来是否发生纠正、撤销或重算;
  • 查询者现在是否仍有权限查看历史聚合。

因此,TeachFlow 把班级归属放进事件和 Episode 语境,并保留成员时间线。Current 只服务“现在该看什么”,历史查询则按发生时间和冻结引用重建。

外部标准为什么也保留开始与结束

1EdTech OneRoster 的 Enrollment 数据模型包含 user、class、school、role,并提供 beginDate 与 endDate;CSV Binding 1.2.1 又明确 endDate 是排他的结束日期。这个标准并不规定 TeachFlow 的全部实现,但证明“成员关系有有效期”不是项目特例。

类似地,事件溯源模式强调以不可变、按时间排序的事件保留状态变化历史,从而支持审计和过去状态分析。TeachFlow 不是把所有业务都实现成纯 Event Sourcing,但在学习事实与成员变化上采用了相同原则:后来的 Current 不覆盖早先发生的事实。

三种容易出错的实现

只在学生表保存 currentClassId。
转班更新一列后,所有历史查询都会跟着变化。

把转班做成删除旧 Enrollment。
当前查询变简单,但无法解释过去谁有权限、班级人数为何变化。

回填历史 Evidence 的新班级。
看似“数据统一”,实际破坏了原课程、教师和作业责任关系。

TeachFlow 的约束是:导入花名册是增量操作,文件中缺失的人不会被静默退班;退出或转班必须显式写入 inactive。班级轨迹再从成员事件与学习事实构建,不从当前列表倒推。

权限与归属不是一回事

历史证据属于 A 班,不代表所有现在的 A 班教师都天然有权查看学生个人详情。归属回答事实发生在哪里,授权回答当前请求者能看到什么。TeachFlow 的教师班级轨迹只返回聚合,学生个人轨迹保留自己的原始事实;跨班访问由服务端验证并拒绝。

当前证据边界

项目记录和源码包含转班、unknown 保留、班级历史、聚合隔离和轨迹回放检查;但本文固定快照未附带新的 PostgreSQL 与浏览器执行回执。现有范围也没有覆盖学期归档、跨校转学、合班拆班和法规留存,因此只能声明当前单校教学班模型下的时间归属设计。

常见问题与设计边界

学生转到 B 班后,B 班教师需要了解历史怎么办?
可以通过经过授权的学生纵向档案或摘要查看,但不能把历史事件改写成 B 班事实。共享视图和事实归属应分开。

为什么不把每次查询都按时间 join Enrollment?
可以,但要控制复杂度与一致性。冻结 Episode 上下文能减少歧义,成员时间线用于校验和历史聚合,两者职责不同。

学期结束后 Current 怎么办?
Current 可以归档或重建,但历史事件、冻结引用与当时成员关系不能丢失;具体保留周期仍需学校制度确定。

参考资料

结论

转班改变的是“从现在开始在哪里学习”,不是“过去在哪里发生”。把 Current 和 History 分开,把成员有效期与事件语境一起保存,系统才能在班级变化之后继续解释同一条学习证据,而不是让今天的一次更新改写昨天的课堂。

← 返回文章列表