139 lines
6.2 KiB
Markdown
139 lines
6.2 KiB
Markdown
# ARCHITECTURE.md
|
|
|
|
本文是后端架构入口,说明 Django 项目内部模块边界和调用规则。具体业务需求看 `docs/specs/`,字段、接口和状态以 `docs/contracts/` 为准。
|
|
|
|
## 架构原则
|
|
|
|
1. 第一版采用 Django 模块化单体,不拆微服务。
|
|
2. app 负责边界和数据归属,复杂业务逻辑放 service 层。
|
|
3. view / serializer 只做请求响应、参数校验和呈现,不承载复杂流程。
|
|
4. 所有关键动作必须写操作日志或失败记录。
|
|
5. 飞书回调、AI 输出、定时触发必须幂等。
|
|
6. 权限必须在接口层和 service 层双重校验。
|
|
|
|
## 运行时与依赖版本
|
|
|
|
> 第一版新项目采用仍在官方扩展支持期内的 Django 5.2 LTS。Docker / 部署环境固定 Python 3.12.13;本地开发允许 Python 3.11 或 3.12,但提交前必须在部署基线 Python 3.12.13 上跑完整测试。
|
|
|
|
| 类别 | 版本约定 |
|
|
| --------------- | -------------------------------------------------------------------------------- |
|
|
| Python | 部署 `3.12.13`;本地开发 `>=3.11,<3.13` |
|
|
| Web 框架 | `Django==5.2.15` |
|
|
| API 框架 | `djangorestframework==3.17.1` |
|
|
| ORM / Migration | Django ORM + Django Migrations,跟随 `Django==5.2.15` |
|
|
| 数据库 | PostgreSQL `18.x`,作为唯一数据源;业务表、AI 对话记忆、上下文快照和日志都落同一套 PostgreSQL |
|
|
| PostgreSQL 驱动 | `psycopg[binary]`,具体 patch 版本以 `requirements.txt` 锁定为准 |
|
|
| 定时任务 | `APScheduler==3.11.2` + `django-apscheduler==0.7.0`,通过独立 management command 进程运行 |
|
|
| AI 接入 | `dashscope==1.25.23`;百炼管理类 OpenAPI 可选 `alibabacloud-bailian20231229==2.13.1` |
|
|
| 飞书接入 | `lark-oapi==1.6.8` |
|
|
| 登录态 / 加解密 | `PyJWT==2.13.0` + `cryptography==49.0.0` |
|
|
| HTTP / 配置 | `requests==2.34.2`、`httpx==0.28.1`、`python-dotenv==1.2.2` |
|
|
| WSGI | `gunicorn==26.0.0` |
|
|
| Docker 基础镜像 | `python:3.12.13-slim-bookworm`、`postgres:18`、`nginx:stable-alpine` |
|
|
|
|
Python 依赖基线:
|
|
|
|
```txt
|
|
Django==5.2.15
|
|
djangorestframework==3.17.1
|
|
psycopg[binary]
|
|
asgiref==3.11.1
|
|
sqlparse==0.5.5
|
|
tzdata==2026.2
|
|
python-dotenv==1.2.2
|
|
requests==2.34.2
|
|
httpx==0.28.1
|
|
APScheduler==3.11.2
|
|
django-apscheduler==0.7.0
|
|
dashscope==1.25.23
|
|
alibabacloud-bailian20231229==2.13.1
|
|
lark-oapi==1.6.8
|
|
PyJWT==2.13.0
|
|
cryptography==49.0.0
|
|
gunicorn==26.0.0
|
|
```
|
|
|
|
## 推荐 Django app
|
|
|
|
| app | 职责 |
|
|
| --- | --- |
|
|
| `accounts` | 自定义用户、角色、登录态、飞书身份绑定 |
|
|
| `people` | 人员映射、称呼匹配、第一批试用人员 |
|
|
| `drafts` | `AiSecretaryAgent`、AI 草稿、补充/重说、BotContext、对话消息和草稿状态流转 |
|
|
| `tasks` | 事项创建、程经理确认、事项状态流转 |
|
|
| `reminders` | 定时提醒、固定周期、触发记录 |
|
|
| `notifications` | 飞书通知、通知补发、通知状态 |
|
|
| `feedbacks` | 飞书卡片反馈、平台内反馈 |
|
|
| `feishu` | 飞书登录、机器人事件、卡片回调、验签 |
|
|
| `prompts` | 背景摘要、老板风格提示词、业务规则版本 |
|
|
| `audit` | 失败记录、操作日志、模型调用日志 |
|
|
|
|
## 分层约定
|
|
|
|
| 层 | 放什么 | 不放什么 |
|
|
| --- | --- | --- |
|
|
| `models` | 字段、索引、基础枚举、简单 model 方法 | 跨模块流程、外部 API 调用 |
|
|
| `serializers` | 入参出参结构、字段级校验、展示转换 | 状态机、权限决策、飞书调用 |
|
|
| `views` | DRF ViewSet/APIView、权限入口、调用 service | 复杂业务分支、事务主体 |
|
|
| `services` | 业务流程、状态流转、事务、幂等、日志 | HTTP 请求细节 |
|
|
| `clients` | 阿里百炼、飞书 API 等外部调用封装 | 业务状态修改 |
|
|
| `tasks/commands` | scheduler、补发、批处理命令 | Web 请求上下文依赖 |
|
|
|
|
## 核心调用方向
|
|
|
|
```text
|
|
views
|
|
-> serializers
|
|
-> services
|
|
-> models / clients
|
|
-> audit logs / failure records
|
|
```
|
|
|
|
允许:
|
|
|
|
1. `drafts` 通过 service 转换为 `tasks` 或 `reminders`。
|
|
2. `tasks` / `reminders` 通过 service 创建 `notifications`。
|
|
3. `notifications` 通过 `feishu` client 发送消息。
|
|
4. `feishu` 回调通过 service 更新 `drafts`、`feedbacks`、`tasks`、`reminders`。
|
|
5. 所有模块写入 `audit`。
|
|
6. `drafts` 中的 AI 对话记忆只辅助理解和草稿修订,不替代 `tasks`、`reminders`、`notifications` 等正式业务表。
|
|
|
|
避免:
|
|
|
|
1. app 之间直接互相改 model 状态。
|
|
2. 在 view 里直接调用飞书或模型 API。
|
|
3. 在 serializer 里做状态流转。
|
|
4. 在 scheduler 中绕过 service 直接改业务表。
|
|
|
|
## 必须写日志的动作
|
|
|
|
1. 飞书登录成功或失败。
|
|
2. 机器人收到老板消息。
|
|
3. 非老板私聊机器人。
|
|
4. AI 生成草稿、解析失败。
|
|
5. 人工确认、修改、取消草稿。
|
|
6. 老板点击补充/重说。
|
|
7. 程经理确认复杂事项。
|
|
8. 创建事项、创建提醒。
|
|
9. 发送通知、补发通知、通知失败。
|
|
10. 接收反馈,尤其是“有问题”反馈。
|
|
11. 定时提醒触发成功或失败。
|
|
12. 失败记录处理。
|
|
13. 背景摘要或老板风格提示词版本启用。
|
|
|
|
## 后台任务
|
|
|
|
定时提醒扫描使用独立进程,不放在 Gunicorn worker 内。生产和测试环境必须保证同一环境同一应用库同时只有一个 scheduler 进程在运行;如果未来多实例部署,需要先引入外部锁、leader election 或数据库级幂等锁。建议命令:
|
|
|
|
```bash
|
|
python manage.py run_reminder_scheduler
|
|
```
|
|
|
|
调度器每次触发前必须检查幂等键:
|
|
|
|
```text
|
|
reminder_id + trigger_time + receiver_id + notification_channel
|
|
```
|
|
|
|
同一个提醒、同一个触发时间、同一个接收人,只允许生成一条有效通知。
|