公共与共享服务
API 事实来源:Django 后端自动文档
为什么这些能力放在公共层
common 放置系统级能力:配置、上传、分页、任务状态和 OpenAPI 包装。services/ 放置跨 app 可复用但不拥有业务状态的服务。
代码入口:
backend/common/models.pybackend/common/models_task.pybackend/common/views.pybackend/common/views_task.pybackend/common/pagination.pybackend/common/middleware/backend/services/
系统配置
SystemConfig是单例配置,当前承载季节作息和学期开始日期。- 季节切换只能由
superadmin执行。 - 季节配置影响课程时间缓存;修改配置逻辑时要同时看课程服务。
任务状态为什么不用 Redis 归属键
- 后台任务状态以
TaskRecord为事实来源。 /api/v1/tasks/是只读 viewset,支持列表和详情。- 非管理员只看自己的任务;
superadmin和secretary可看全部任务。 - 状态值使用数据库枚举:
pending、started、success、failure。 - 旧的 Redis
task_owner:<task_id>归属方案已废弃。任务状态和归属放在数据库中,便于权限过滤、审计和进程重启后的恢复。
上传的当前状态
- 当前上传端点直接写
LOCAL_UPLOAD_DIR,返回 URL 由LOCAL_UPLOAD_URL_PREFIX拼接。 services/file_storage.py已有本地/S3 双后端抽象,但上传端点尚未接入。- 上传改造前先决定:继续保持本地上传语义,还是正式迁移到 storage abstraction。两条路径的部署、URL、权限和回滚方式不同。
分页与请求上下文
- 默认分页类是
DefaultPagination,最大页大小为 200。 RequestTimezoneMiddleware从X-Timezone激活请求时区。OperationLogContextMiddleware和CurrentRoleMiddleware虽不在common/,但属于系统级请求上下文能力。
共享代码的判断标准
- 公共层可以服务业务模块,但反向依赖具体业务模块会让系统边界变模糊。
- 单模块逻辑留在所属 app;只有稳定复用于多个模块的能力才放入
services/。 - OpenAPI envelope hook 会影响自动文档和前端生成类型,修改后需要同时验证这两端。