后端架构概览
本页记录后端的跨模块设计。接口、字段和请求格式以 OpenAPI 与代码为准。
代码地图
text
backend/
├── apps/
│ ├── accounts/ # 用户、角色、认证、多因素登录
│ ├── courses/ # 课程主记录与 CourseOccurrence
│ ├── classrooms/ # 教室主数据、空闲教室、教室日程
│ ├── borrowings/ # 教室借用、审批、冲突检测
│ ├── checkins/ # 签到会话与签到记录
│ ├── signage/ # 班牌设备认证、激活、展示数据
│ ├── observations/ # 听课观察模板与记录模型
│ ├── repairs/ # 报修工单
│ ├── abuse/ # 违规举报
│ └── logs/ # 操作日志
├── classroom_manager/ # Django settings、URL、Celery 入口
├── common/ # 系统配置、上传、分页、任务状态
├── services/ # 跨模块服务
└── manage.py运行时形态
manage.py、wsgi.py和asgi.py默认指向classroom_manager.settings.base;生产容器可显式使用settings.prod。- 数据库是 PostgreSQL,Redis 用于 Celery broker/result backend 和 Django cache。
- REST Framework 默认要求认证;匿名端点在 view 上显式声明。
- 项目尚未完全统一响应格式。自定义动作常用
{code, message, data},默认 DRF viewset 行为可能返回原生结构。前端和 Agent 需要以具体接口为准。
认证与角色
- Web 登录通过 JWT cookie 工作;微信小程序登录直接在响应体返回 token。
CookieJWTAuthentication先读Authorization,再读tokencookie。current_role是请求级上下文。CurrentRoleMiddleware从 JWT 或X-Current-Role解析,并校验角色是否属于user.roles。这个设计避免把“当前身份”写成用户全局状态,也让同一账号在不同客户端中独立选择身份。
班牌设备使用 SignageDeviceAuthentication,只接受设备 token。设备身份与用户身份分开,是为了让教室终端长期在线而不依赖某个用户会话。
共享模型选择
- 课时:
CourseOccurrence是课程实例事实来源。新增课表来源时,优先考虑转换为课程实例,而不是新增第二套“实际课表”状态。 - 教室占用:教室日程和空闲教室由课程实例与手动借用叠加得出。
- 借用冲突:同时检查手动借用和课程占用。
- 签到:签到会话应锚定到课程实例,避免脱离课程体系的孤立签到。
- 班牌:当前只展示课程实例,不合并手动借用。
- 系统配置:季节作息和学期开始日期由
SystemConfig提供给课程服务。
为什么任务状态在 PostgreSQL
课程导入和用户导入会超过普通 HTTP 请求的可靠执行窗口,因此由 Celery 执行。view 负责校验输入、保存上传文件、创建 TaskRecord、投递任务;worker 负责更新任务状态。
任务状态以 common.models_task.TaskRecord 为事实来源,并通过 /api/v1/tasks/ 的只读 viewset 查询。非管理员只能看自己的任务;superadmin 和 secretary 可看全部任务。旧的 Redis task_owner:<task_id> 方案已废弃,避免任务归属分散在缓存状态里。
已知技术债
logs.permissions.IsLogAdmin仍读取旧版user.role字段,尚未完全接入roles数组。services/file_storage.py已有本地/S3 抽象,但上传端点仍直接写本地文件系统。- 班牌设备尚未接入签到写入流程。
observations已有模型和模板接口,但业务闭环仍很轻,扩展前应先明确权限和数据生命周期。