Skip to content

后端架构概览

本页记录后端的跨模块设计。接口、字段和请求格式以 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.pywsgi.pyasgi.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,再读 token cookie。 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 查询。非管理员只能看自己的任务;superadminsecretary 可看全部任务。旧的 Redis task_owner:<task_id> 方案已废弃,避免任务归属分散在缓存状态里。

已知技术债

  • logs.permissions.IsLogAdmin 仍读取旧版 user.role 字段,尚未完全接入 roles 数组。
  • services/file_storage.py 已有本地/S3 抽象,但上传端点仍直接写本地文件系统。
  • 班牌设备尚未接入签到写入流程。
  • observations 已有模型和模板接口,但业务闭环仍很轻,扩展前应先明确权限和数据生命周期。