From fcbd72845783fe4dd234076a4661c8f1b6742545 Mon Sep 17 00:00:00 2001 From: talesofzes <1029017043@qq.com> Date: Mon, 22 Jun 2026 16:27:57 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=87=E6=A1=A3=EF=BC=9A=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E6=B3=BD=E6=BA=90=E5=90=8E=E7=AB=AF=E5=8D=8F=E4=BD=9C=E5=9F=BA?= =?UTF-8?q?=E7=BA=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 48 ++ AGENTS.md | 105 ++++ ARCHITECTURE.md | 136 ++++ README.md | 80 +++ docs/00_项目总览.md | 86 +++ docs/01_当前任务.md | 51 ++ docs/checklists/AI生成代码检查清单.md | 89 +++ docs/checklists/后端Review清单.md | 78 +++ docs/checklists/联调验收清单.md | 68 ++ docs/contracts/API接口约定.md | 183 ++++++ docs/contracts/数据对象约定.md | 291 +++++++++ docs/contracts/状态流转约定.md | 297 +++++++++ .../plans/active/01_老板一句话闭环实施计划.md | 580 ++++++++++++++++++ .../completed/02_飞书通知回调实施计划.md | 8 + docs/specs/01_老板AI秘书与AI草稿.md | 159 +++++ docs/specs/02_事项任务.md | 130 ++++ docs/specs/03_飞书通知与反馈.md | 145 +++++ docs/specs/04_定时提醒.md | 138 +++++ docs/specs/05_权限日志失败记录.md | 134 ++++ 19 files changed, 2806 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fc5c464 --- /dev/null +++ b/.gitignore @@ -0,0 +1,48 @@ +# Local editors and note tools +.obsidian/ +.agents/ +.vscode/ +.idea/ + +# Local environment and secrets +.env +.env.* +!.env.example +!.env.template + +# Python bytecode and caches +__pycache__/ +*.py[cod] +*$py.class +.python-version + +# Virtual environments +.venv/ +venv/ +env/ +ENV/ + +# Django/runtime generated files +db.sqlite3 +*.sqlite3 +media/ +staticfiles/ + +# Test, lint, and coverage caches +.pytest_cache/ +.mypy_cache/ +.ruff_cache/ +.coverage +.coverage.* +htmlcov/ + +# Logs and temporary files +*.log +logs/ +tmp/ +temp/ + +# OS files +.DS_Store +Thumbs.db +desktop.ini diff --git a/AGENTS.md b/AGENTS.md index 8b13789..5a24970 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1 +1,106 @@ +# AGENTS.md +本文件是给 AI 和开发者看的后端协作导航。开发任何后端功能前,先按本文件判断要读哪些 spec、contract、plan 和 checklist。 + +## 项目一句话 + +第一版要做一个公司内部 AI 协作最小闭环: + +```text +老板一句话 +-> AI 草稿 +-> 人工确认 +-> 创建事项或定时提醒 +-> 飞书通知 +-> 接收人反馈 +-> 页面看到结果和失败记录 +``` + +这不是完整任务系统、完整 AI 工作台、完整看板,也不是全自动 Agent。 + +## 当前技术栈 + +| 层级 | 约定 | +| ----- | ------------------------------------------- | +| 后端 | Python Django + Django REST Framework | +| ORM | Django ORM + Django Migrations | +| 数据库 | MySQL 8,使用平台自有应用库 | +| 定时任务 | Django management command + 独立 scheduler 进程 | +| 后台管理 | Django Admin | +| AI 接入 | 阿里百炼 API,后端封装薄 `ai_client` | +| 飞书 | 飞书身份登录、机器人私聊、个人消息、交互卡片和回调 | +| 部署 | Docker Compose + Nginx + Gunicorn | +| | | +## 渐进式阅读规则 + +普通任务只读: + +1. `AGENTS.md` +2. 当前相关 `docs/specs/*.md` +3. 当前 active plan + +涉及接口时再读: + +1. `docs/contracts/API接口约定.md` + +涉及数据库或字段时再读: + +1. `docs/contracts/数据对象约定.md` + +涉及状态流转时再读: + +1. `docs/contracts/状态流转约定.md` + +涉及飞书时再读: + +1. `docs/specs/03_飞书通知与反馈.md` +2. `docs/contracts/API接口约定.md` + +涉及 Review 或提交前检查时再读: + +1. `docs/checklists/AI生成代码检查清单.md` +2. `docs/checklists/后端Review清单.md` + +不要每次全量读取所有 docs,避免上下文过大、重点变散。 + +## 事实源优先级 + +1. `docs/contracts/` 是字段、接口、状态、错误码和全局约定的唯一事实源。 +2. `docs/specs/` 说明业务边界和模块目标,不复制完整字段表。 +3. `docs/plans/active/` 是当前施工依据,不用于偷偷改变业务边界。 +4. `docs/checklists/` 和测试是 Review 闸门。 + +如果 spec 和 contract 冲突,以 contract 为准,并提出文档修正建议。 + +## 生成代码禁止事项 + +1. 不允许 AI 未经人工确认直接创建事项、提醒或发送通知。 +2. 不允许普通员工给别人创建事项或提醒。 +3. 不允许绕过后端权限校验,只靠前端隐藏按钮。 +4. 不允许自动操作交易系统、公司历史数据库、后台管理系统或其他外部业务系统。 +5. 不允许把 API Key、App Secret、飞书 token、完整手机号、完整邮箱写进代码或普通日志。 +6. 不允许把老板解释中的游戏化表达写进事项标题、接收人、时间、反馈要求等结构化字段。 +7. 不允许把第一版明确不做的功能混入主线。 + +## AI 写代码推荐流程 + +```text +人确定任务 +-> AI 读 AGENTS.md +-> AI 读对应 spec +-> AI 检查 docs/plans/active/ 是否已有当前 plan +-> 没有 plan:读必要 contracts,生成 plan 给人确认 +-> 已有 plan:只按当前 plan 执行 +-> AI 读 checklists +-> AI 按 plan 写代码 +-> AI 自测 +-> 泽源跑测试 +-> 乔大卫 / 田宇 Review 关键代码 +-> 王一多验收闭环 +``` + +active plan 是当前施工依据。除非发现 plan 明确不符合 spec/contracts,否则不要重新生成新 plan。 + +## 第一版不做 + +AI 工作台、技能市场、文件上传、多模态处理、会议纪要、日报、文档摘要、复杂反馈看板、复杂 BI、成本驾驶舱、完整工作流、完整项目管理、多级子任务、甘特图、复杂审批流、复杂组织架构、cron 表达式、日历系统、自动操作交易系统、自动操作历史数据库、自动读取员工本地文件、手机端网页完整适配、把飞书机器人开放为程经理或普通员工通用派活入口。 diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 8b13789..e4fcad5 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -1 +1,137 @@ +# 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` | +| 数据库 | MySQL `8.4.10` LTS,使用平台自有应用库 | +| MySQL 驱动 | `mysqlclient==2.2.8` | +| 定时任务 | `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`、`mysql:8.4.10`、`nginx:stable-alpine` | + +Python 依赖基线: + +```txt +Django==5.2.15 +djangorestframework==3.17.1 +mysqlclient==2.2.8 +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` | AI 草稿、补充/重说、草稿状态流转 | +| `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`。 + +避免: + +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 +``` + +同一个提醒、同一个触发时间、同一个接收人,只允许生成一条有效通知。 diff --git a/README.md b/README.md index 8b13789..cc89956 100644 --- a/README.md +++ b/README.md @@ -1 +1,81 @@ +# 公司内部 AI 协作 MVP 后端 +本仓库用于实现第一版公司内部 AI 协作最小闭环: + +```text +老板一句话 +-> AI 草稿 +-> 人工确认 +-> 创建事项或定时提醒 +-> 飞书通知 +-> 接收人反馈 +-> 页面看到结果和失败记录 +``` + +第一版不是完整任务系统、AI 工作台、复杂看板或全自动 Agent。所有关键动作都必须经过人工确认,AI 只生成可确认草稿。 + +## 技术栈 + +| 层级 | 约定 | +| ----- | ------------------------------------------- | +| 后端 | Python Django + Django REST Framework | +| ORM | Django ORM + Django Migrations | +| 数据库 | MySQL 8,使用平台自有应用库 | +| 定时任务 | Django management command + 独立 scheduler 进程 | +| 后台管理 | Django Admin | +| AI 接入 | 阿里百炼 API,后端封装薄 `ai_client` | +| 飞书 | 飞书身份登录、机器人私聊、个人消息、交互卡片和回调 | +| 部署 | Docker Compose + Nginx + Gunicorn | + +## 当前施工基线 + +1. 后端框架使用 `Django==5.2.15` + `djangorestframework==3.17.1`。 +2. Docker / 部署环境固定 Python `3.12.13`;本地开发允许 Python 3.11 或 3.12,提交前必须在 Python 3.12.13 上跑完整测试。 +3. 后端开发先采用 mock-first:单元测试和最小闭环测试不得访问真实百炼、真实飞书或公网回调。 +4. 定时提醒 scheduler 独立于 Gunicorn worker,同一环境同一应用库同时只能运行一个 scheduler 进程。 + +## 文档入口 + +开发前先读: + +1. `AGENTS.md` +2. 当前相关 `docs/specs/*.md` +3. `docs/plans/active/01_老板一句话闭环实施计划.md` + +涉及接口、字段、状态时,再读: + +1. `docs/contracts/API接口约定.md` +2. `docs/contracts/数据对象约定.md` +3. `docs/contracts/状态流转约定.md` + +提交或 Review 前读: + +1. `docs/checklists/AI生成代码检查清单.md` +2. `docs/checklists/后端Review清单.md` + +## 本地启动 + +当前仓库还处在后端文档和施工计划阶段,Django 项目骨架尚未创建。代码落地后,本节应补充: + +1. Python 虚拟环境创建方式。 +2. 依赖安装命令。 +3. `.env` 示例和环境变量说明。 +4. 数据库迁移命令。 +5. 本地启动命令。 +6. 测试命令。 + +## 环境变量边界 + +这些值必须放在环境变量或服务器安全配置中,不能提交到仓库: + +1. 阿里百炼 API Key。 +2. 飞书 App ID。 +3. 飞书 App Secret。 +4. 飞书回调验签密钥。 +5. 数据库账号密码。 + +普通日志中不得打印 API Key、App Secret、飞书 token、完整手机号或完整邮箱。 + +## 第一版不做 + +第一版不做 AI 工作台、技能市场、文件上传、多模态处理、会议纪要、日报、文档摘要、复杂反馈看板、复杂 BI、成本驾驶舱、完整工作流、完整项目管理、多级子任务、甘特图、复杂审批流、复杂组织架构、cron 表达式、日历系统、自动操作交易系统、自动操作历史数据库、自动读取员工本地文件、手机端网页完整适配,也不把飞书机器人开放为程经理或普通员工通用派活入口。 diff --git a/docs/00_项目总览.md b/docs/00_项目总览.md index 8b13789..287100c 100644 --- a/docs/00_项目总览.md +++ b/docs/00_项目总览.md @@ -1 +1,87 @@ +# 项目总览 +## 第一版目标 + +第一版要跑通一个公司内部 AI 协作最小闭环: + +```text +老板一句话 +-> AI 草稿 +-> 人工确认 +-> 创建事项或定时提醒 +-> 飞书通知 +-> 接收人反馈 +-> 页面看到结果和失败记录 +``` + +AI 只负责整理、建议和生成草稿,不直接创建事项、不直接创建提醒、不直接通知别人。所有关键动作都必须经过人工确认。 + +## 角色 + +| 角色 | 第一版能力 | +| --- | --- | +| 老板 | 通过飞书机器人或平台输入一句话、确认草稿、创建事项或提醒、查看自己相关记录 | +| 程经理 | 接收复杂事项待确认提醒,在平台确认、修改和分发复杂事项 | +| 普通员工 | 接收事项和提醒,反馈已收到、处理中、已完成或有问题,创建自己的提醒 | +| 管理员 / AI 团队 | 维护人员映射、提示词版本、失败记录和必要日志 | + +## 核心模块 + +1. 老板 AI 秘书:一句话入口、意图分类、AI 草稿、补充/重说、普通问答兜底。 +2. 事项任务:承接确认后的事项、通知、反馈和状态查看。 +3. 定时提醒:承接一次性和固定周期提醒,到点通知并记录结果。 +4. 飞书集成:身份登录、老板机器人私聊、个人消息、交互卡片和回调。 +5. 权限日志失败记录:角色权限、操作日志、失败记录、敏感信息边界。 + +## 第一版闭环 + +老板一句话到事项: + +```text +老板在飞书机器人私聊或平台输入 +-> AI 生成事项草稿 +-> 老板确认 / 补充/重说 / 取消 +-> 简单事项直接创建,复杂事项转程经理确认 +-> 飞书通知接收人 +-> 接收人反馈 +-> 发起人或程经理查看结果 +``` + +老板一句话到提醒: + +```text +老板输入未来提醒 +-> AI 生成提醒草稿 +-> 老板确认 / 补充/重说 / 取消 +-> 创建提醒 +-> 到点飞书通知 +-> 按需反馈 +-> 查看通知结果和失败原因 +``` + +异常复盘: + +```text +AI 解析失败 / 通知失败 / 回调失败 / 定时触发失败 +-> 写入失败记录 +-> AI 团队处理 +-> 必要时补发、取消、重新处理或同步程经理 +-> 处理结果留痕 +``` + +## 技术栈 + +| 层级 | 约定 | +| --- | --- | +| 后端 | Python Django + Django REST Framework | +| ORM | Django ORM + Django Migrations | +| 数据库 | MySQL 8,使用平台自有应用库 | +| 定时任务 | Django management command + 独立 scheduler 进程 | +| 后台管理 | Django Admin | +| AI 接入 | 阿里百炼 API,后端封装薄 `ai_client` | +| 飞书 | 飞书身份登录、机器人私聊、个人消息、交互卡片和回调 | +| 部署 | Docker Compose + Nginx + Gunicorn | + +## 第一版不做 + +不做完整任务系统、完整 AI 工作台、技能市场、文件上传、多模态处理、会议纪要、日报、文档摘要、复杂反馈看板、复杂 BI、成本驾驶舱、完整工作流、完整项目管理、多级子任务、甘特图、复杂审批流、复杂组织架构、cron 表达式、日历系统、自动操作交易系统、自动操作历史数据库、自动读取员工本地文件、手机端网页完整适配,也不把飞书机器人开放为程经理或普通员工通用派活入口。 diff --git a/docs/01_当前任务.md b/docs/01_当前任务.md index 8b13789..d398bcc 100644 --- a/docs/01_当前任务.md +++ b/docs/01_当前任务.md @@ -1 +1,52 @@ +# 当前任务 +更新时间:2026-06-22 + +## 当前迭代目标 + +补齐后端协作文档和第一份 active plan,让后续 AI 与开发者可以按同一套 spec、contract、plan 和 checklist 写 Django 后端代码。 + +本轮不直接实现业务代码,因为当前仓库还没有 Django 项目骨架,且原 `docs/specs`、`docs/contracts`、`docs/checklists` 和 `docs/plans/active` 基本为空。 + +可行性审查后,active plan 已补充 mock-first、Django 5.2 LTS、Task 1 可执行顺序、自定义用户模型首次迁移前设置、周期提醒状态和 scheduler 单实例约束。 + +## 本周任务 + +| 事项 | 负责人 | 状态 | +| ---------------------------------- | ------------- | --- | +| 补齐 `README.md` 项目说明 | 泽源 | 进行中 | +| 补齐 `docs/00_项目总览.md` | 王一多 / 泽源协作 | 进行中 | +| 补齐 `docs/specs/01_老板AI秘书与AI草稿.md` | 王一多 / 泽源 / 焕然 | 进行中 | +| 补齐 `docs/specs/02_事项任务.md` | 乔大卫 / 泽源 | 进行中 | +| 补齐 `docs/specs/03_飞书通知与反馈.md` | 田宇 | 进行中 | +| 补齐 `docs/specs/04_定时提醒.md` | 田宇 / 乔大卫 | 进行中 | +| 补齐 `docs/specs/05_权限日志失败记录.md` | 乔大卫 | 进行中 | +| 补齐 `docs/contracts/API接口约定.md` | 田宇 / 泽源 | 进行中 | +| 补齐 `docs/contracts/数据对象约定.md` | 乔大卫 / 泽源 | 进行中 | +| 补齐 `docs/contracts/状态流转约定.md` | 乔大卫 | 进行中 | +| 补齐 `docs/checklists/AI生成代码检查清单.md` | 泽源 | 进行中 | +| 补齐 `docs/checklists/后端Review清单.md` | 乔大卫 / 田宇 | 进行中 | +| 补齐第一份 active plan | 泽源 / 焕然 | 进行中 | + +## 当前卡点 + +1. Django 项目骨架尚未创建。 +2. 飞书正式应用配置、回调地址、个人消息权限和第一批试用人员映射还需要联调确认。 +3. 阿里百炼 API Key、飞书 App Secret 等密钥不能写入仓库,需要后续通过环境变量配置。 +4. 第一批试用人员姓名、常见称呼、手机号或邮箱映射需要后续维护。 +5. 本地当前 Python 可能不是部署基线;提交前需要在 Python 3.12.13 环境跑完整测试。 + +## 待确认问题 + +1. 第一批试用人员名单和角色白名单。 +2. 老板飞书身份映射方式:手机号、邮箱或手工 open_id。 +3. 演示阶段是否先使用平台账号登录兜底,还是直接接飞书扫码登录。 +4. 飞书个人消息和交互卡片权限是否已开通。 +5. 演示环境域名和 HTTPS 回调地址。 + +## 下一步 + +1. 完成本轮文档补齐。 +2. 由泽源按修订后的 active plan 创建 Django 项目骨架、基础 app、模型和迁移。 +3. 先用 mock 百炼和 mock 飞书跑通后端最小闭环测试。 +4. 优先跑通 AI 草稿、人工确认、事项创建、飞书通知和反馈记录这条最小链路。 diff --git a/docs/checklists/AI生成代码检查清单.md b/docs/checklists/AI生成代码检查清单.md index 8b13789..805442a 100644 --- a/docs/checklists/AI生成代码检查清单.md +++ b/docs/checklists/AI生成代码检查清单.md @@ -1 +1,90 @@ +# AI 生成代码检查清单 +AI 生成或修改后端代码前后都要检查本清单。checklists 是 Review 闸门,不是写完后随手看一眼。 + +## 1. 文档读取 + +- [ ] 已读 `AGENTS.md`。 +- [ ] 已读当前相关 `docs/specs/*.md`。 +- [ ] 已读当前 active plan。 +- [ ] 涉及接口时已读 `docs/contracts/API接口约定.md`。 +- [ ] 涉及字段或数据库时已读 `docs/contracts/数据对象约定.md`。 +- [ ] 涉及状态流转时已读 `docs/contracts/状态流转约定.md`。 +- [ ] 涉及飞书时已读 `docs/specs/03_飞书通知与反馈.md`。 + +## 2. 范围控制 + +- [ ] 只实现 active plan 要求的范围。 +- [ ] 没有混入第一版明确不做的功能。 +- [ ] 没有把 AI 工作台、技能市场、复杂看板、复杂 BI、cron、自定义日历等能力带入主线。 +- [ ] 没有为了方便临时绕过权限、状态或日志要求。 + +## 3. 权限 + +- [ ] 普通员工不能给别人创建事项。 +- [ ] 普通员工不能给别人创建提醒。 +- [ ] 接收人之外的人不能反馈事项或提醒。 +- [ ] 飞书机器人私聊入口第一版只允许老板使用。 +- [ ] 程经理复杂事项确认走平台,不通过机器人对话处理。 +- [ ] 权限在后端校验,不只靠前端隐藏按钮。 + +## 4. AI 草稿 + +- [ ] AI 只生成草稿,不直接创建事项、提醒或通知。 +- [ ] AI 输出 JSON 已做结构校验。 +- [ ] `qa` 和 `realtime_qa` 不创建事项、提醒或通知。 +- [ ] 实时问答第一版只做暂不支持提示,不做交易判断。 +- [ ] 结构化字段没有写入游戏化表达。 +- [ ] 模型调用记录了背景摘要、老板风格和业务规则版本。 +- [ ] AI 解析失败会写 `model_call_logs` 和 `failure_records`。 + +## 5. 状态 + +- [ ] 草稿、事项、提醒、通知、反馈、失败记录的状态枚举来自 `状态流转约定.md`。 +- [ ] 非法状态跳转返回 `state_conflict`。 +- [ ] 已取消对象不能继续转换、通知或反馈。 +- [ ] `converted` 草稿不会重复转换。 +- [ ] 通知失败不会被标记为已通知。 +- [ ] 有问题反馈必须填写原因。 + +## 6. 飞书 + +- [ ] 飞书回调必须验签。 +- [ ] 飞书事件使用 `event_id` 幂等。 +- [ ] 卡片重复点击不会重复创建事项、提醒或反馈。 +- [ ] 飞书通知只发送摘要和链接。 +- [ ] 非老板机器人访问不会调用 AI。 +- [ ] 回调失败会写 `feishu_events` 和 `failure_records`。 + +## 7. 定时提醒 + +- [ ] scheduler 独立于 Gunicorn worker 运行。 +- [ ] 同一环境同一应用库同时只有一个 scheduler 进程运行。 +- [ ] 只有 `active` 提醒会触发。 +- [ ] `paused` 和 `cancelled` 不会触发。 +- [ ] 同一提醒、同一触发时间、同一接收人、同一渠道只生成一条有效通知。 +- [ ] 触发失败会写失败记录。 + +## 8. 事务和幂等 + +- [ ] 创建事项或提醒、创建通知、写日志在事务边界内处理。 +- [ ] 外部调用失败不会留下半截错误状态。 +- [ ] 补发保留原失败记录和新发送结果。 +- [ ] 重复请求不会重复执行业务动作。 + +## 9. 日志和敏感信息 + +- [ ] 关键动作写 `operation_logs`。 +- [ ] 失败写 `failure_records`。 +- [ ] 普通日志不包含 API Key、App Secret、飞书 token。 +- [ ] 普通日志不包含完整手机号或完整邮箱。 +- [ ] 原始错误摘要不包含密钥。 + +## 10. 测试 + +- [ ] 权限测试覆盖普通员工不能给别人创建事项或提醒。 +- [ ] 状态测试覆盖非法跳转。 +- [ ] 飞书测试覆盖验签失败、幂等重复事件和非接收人反馈。 +- [ ] 定时测试覆盖重复触发防护。 +- [ ] 事务测试覆盖通知失败不留下半截数据。 +- [ ] AI 测试覆盖解析失败、实时问答和人工确认边界。 diff --git a/docs/checklists/后端Review清单.md b/docs/checklists/后端Review清单.md index 8b13789..1229401 100644 --- a/docs/checklists/后端Review清单.md +++ b/docs/checklists/后端Review清单.md @@ -1 +1,79 @@ +# 后端 Review 清单 +后端 Review 优先找风险、权限漏洞、状态错误、事务问题、缺测试和敏感信息泄漏。 + +## 1. 权限 + +- [ ] DRF permission class 覆盖入口权限。 +- [ ] service 层覆盖业务权限。 +- [ ] 普通员工不能给别人创建事项或提醒。 +- [ ] 反馈人必须是事项或提醒接收人。 +- [ ] 飞书身份没有直接绕过平台角色权限。 +- [ ] 非老板机器人私聊不会触发 AI。 +- [ ] 失败记录仅管理员 / AI 团队和必要管理角色可见。 + +## 2. 状态流转 + +- [ ] 状态枚举与 `docs/contracts/状态流转约定.md` 一致。 +- [ ] 状态变化集中在 service 层。 +- [ ] 非法状态跳转返回明确错误。 +- [ ] 已取消、已转换、已完成等终态不会被重复处理。 +- [ ] 有问题反馈必须留下原因。 + +## 3. 事务和一致性 + +- [ ] 创建事项 / 提醒 / 通知 / 日志的事务边界清晰。 +- [ ] 外部 API 失败不会造成业务状态误判。 +- [ ] 通知失败不会标记已通知。 +- [ ] 补发不会覆盖历史失败记录。 +- [ ] scheduler 不绕过 service 直接改业务表。 + +## 4. 飞书 + +- [ ] 回调已验签。 +- [ ] `event_id` 幂等。 +- [ ] 卡片重复点击幂等。 +- [ ] 通知内容只包含摘要和链接。 +- [ ] 飞书 token、App Secret 不进入日志。 +- [ ] 找不到通知、草稿、事项、提醒时有失败记录。 + +## 5. AI + +- [ ] AI 输出只进入草稿。 +- [ ] 模型 JSON 有 validator。 +- [ ] `qa` / `realtime_qa` 不创建事项或提醒。 +- [ ] 实时问答不做交易判断。 +- [ ] prompt_contexts 版本被记录。 +- [ ] 游戏化表达没有进入结构化字段。 + +## 6. 定时提醒 + +- [ ] 只支持一次性、每天、每周、每月。 +- [ ] 不支持 cron 和复杂日历。 +- [ ] 同一环境同一应用库同时只有一个 scheduler 进程。 +- [ ] `paused`、`cancelled` 不触发。 +- [ ] 触发幂等键覆盖提醒、时间、接收人和渠道。 +- [ ] 触发失败可复盘。 + +## 7. 日志和失败 + +- [ ] 关键动作写 `operation_logs`。 +- [ ] 失败写 `failure_records`。 +- [ ] 失败记录包含类型、关联对象、原因、处理状态。 +- [ ] 失败处理必须有处理结果。 +- [ ] 日志包含操作人和渠道。 + +## 8. 测试 + +- [ ] 单元测试覆盖权限、状态、AI 输出校验、飞书回调、提醒幂等。 +- [ ] 失败路径有测试。 +- [ ] 测试没有依赖真实飞书或真实百炼网络调用。 +- [ ] 测试 fixture 不包含真实手机号、邮箱、token 或密钥。 + +## 9. 文档同步 + +- [ ] 改接口同步 `docs/contracts/API接口约定.md`。 +- [ ] 改字段同步 `docs/contracts/数据对象约定.md`。 +- [ ] 改状态同步 `docs/contracts/状态流转约定.md`。 +- [ ] 改飞书逻辑同步 `docs/specs/03_飞书通知与反馈.md`。 +- [ ] 改 AI 规则同步 `docs/specs/01_老板AI秘书与AI草稿.md`。 diff --git a/docs/checklists/联调验收清单.md b/docs/checklists/联调验收清单.md index 8b13789..c4eda7e 100644 --- a/docs/checklists/联调验收清单.md +++ b/docs/checklists/联调验收清单.md @@ -1 +1,69 @@ +# 联调验收清单 +联调验收看闭环是否真实可用,不看页面数量。 + +## 1. 身份和入口 + +- [ ] 用户可以通过飞书扫码登录 / 身份登录进入平台。 +- [ ] 飞书登录可以匹配到平台用户和角色。 +- [ ] 未匹配用户或停用用户不能进入平台,并有失败记录。 +- [ ] 老板可以通过飞书机器人私聊提交一句话。 +- [ ] 非老板私聊机器人不会触发 AI,并有未授权访问记录。 + +## 2. AI 草稿 + +- [ ] AI 可以把老板一句话解析为结构化草稿。 +- [ ] AI 草稿可以展示原始输入、类型、内容、接收人候选、时间、反馈要求和缺失字段。 +- [ ] 草稿必须人工确认后才创建事项或提醒。 +- [ ] 老板可以确认、补充/重说、取消草稿。 +- [ ] 补充/重说 30 分钟上下文可以生效并过期。 +- [ ] 实时问答不会创建事项、提醒或通知。 + +## 3. 事项闭环 + +- [ ] 简单事项可以从草稿生成。 +- [ ] 复杂事项可以转程经理确认。 +- [ ] 程经理收到飞书提醒后进入平台确认。 +- [ ] 事项可以飞书通知接收人。 +- [ ] 接收人可以反馈已收到、处理中、已完成、有问题。 +- [ ] 有问题反馈必须留下原因。 +- [ ] 发起人或程经理可以看到事项结果。 + +## 4. 定时提醒闭环 + +- [ ] 手动创建一次性提醒。 +- [ ] 从草稿创建提醒。 +- [ ] 支持每天、每周、每月固定周期提醒。 +- [ ] 到点触发飞书通知。 +- [ ] 自己提醒自己默认不需要反馈。 +- [ ] 老板 / 程经理给别人设置的提醒默认需要反馈。 +- [ ] 暂停、恢复、取消按状态约定生效。 +- [ ] 同一提醒不会重复触发同一通知。 +- [ ] 演示 / 联调环境同一应用库只启动一个 scheduler 进程。 + +## 5. 飞书通知和回调 + +- [ ] 飞书个人消息可以发送。 +- [ ] 飞书交互卡片可以发送。 +- [ ] 卡片按钮回调可以被平台接收。 +- [ ] 回调验签失败不会执行业务动作。 +- [ ] 重复点击卡片不会重复创建反馈或转换草稿。 +- [ ] 通知成功和失败都有记录。 + +## 6. 失败复盘 + +- [ ] AI 解析失败有记录。 +- [ ] 人员映射缺失有记录。 +- [ ] 飞书登录失败有记录。 +- [ ] 飞书通知失败有记录。 +- [ ] 回调失败有记录。 +- [ ] 定时提醒触发失败有记录。 +- [ ] 管理员 / AI 团队可以处理失败并留下处理结果。 + +## 7. 安全边界 + +- [ ] 飞书通知只发摘要和链接。 +- [ ] 普通日志不含 API Key、App Secret、飞书 token。 +- [ ] 普通日志不含完整手机号和完整邮箱。 +- [ ] 不自动操作交易系统、历史数据库、后台管理系统或其他外部业务系统。 +- [ ] 第一版明确不做的功能没有混入主线。 diff --git a/docs/contracts/API接口约定.md b/docs/contracts/API接口约定.md index 8b13789..46d433c 100644 --- a/docs/contracts/API接口约定.md +++ b/docs/contracts/API接口约定.md @@ -1 +1,184 @@ +# API 接口约定 +本文件是后端接口路径、请求响应格式、错误码和分页格式的唯一事实源。spec 只描述业务边界,不重复完整接口返回。 + +## 1. 通用规则 + +1. 所有业务接口使用 `/api` 前缀。 +2. 请求和响应使用 JSON。 +3. 时间字段使用 ISO 8601 字符串,并统一保存为服务器时区感知时间。 +4. 列表接口默认分页。 +5. 动作类接口使用 `POST /api/{resources}/{id}/{action}`。 +6. 飞书回调接口必须单独记录原始 payload。 +7. 后端必须做权限校验,不能只靠前端隐藏入口。 + +## 2. 统一响应格式 + +成功: + +```json +{ + "success": true, + "data": {}, + "error": null, + "request_id": "req_20260622_xxx" +} +``` + +失败: + +```json +{ + "success": false, + "data": null, + "error": { + "code": "permission_denied", + "message": "当前用户无权执行该操作", + "detail": {} + }, + "request_id": "req_20260622_xxx" +} +``` + +分页: + +```json +{ + "success": true, + "data": { + "items": [], + "page": 1, + "page_size": 20, + "total": 0 + }, + "error": null, + "request_id": "req_20260622_xxx" +} +``` + +## 3. 通用错误码 + +| code | HTTP | 含义 | +| --- | --- | --- | +| `validation_error` | 400 | 请求字段校验失败 | +| `unauthenticated` | 401 | 未登录或登录态失效 | +| `permission_denied` | 403 | 当前用户无权操作 | +| `not_found` | 404 | 对象不存在或不可见 | +| `state_conflict` | 409 | 当前状态不允许该操作 | +| `idempotency_conflict` | 409 | 幂等键冲突或重复请求 | +| `ai_parse_failed` | 422 | AI 输出无法解析或不符合结构 | +| `person_mapping_missing` | 422 | 缺少人员映射 | +| `feishu_signature_invalid` | 401 | 飞书回调验签失败 | +| `feishu_api_failed` | 502 | 飞书接口调用失败 | +| `scheduler_trigger_failed` | 500 | 定时提醒触发失败 | +| `internal_error` | 500 | 未分类服务端错误 | + +## 4. 用户与人员映射 + +| 方法 | 路径 | 作用 | 权限 | +| --- | --- | --- | --- | +| GET | `/api/users/me` | 获取当前用户 | 已登录 | +| GET | `/api/users` | 用户列表 | 管理员 / AI 团队 | +| GET | `/api/auth/feishu/login` | 发起飞书扫码登录 / 身份登录 | 公开 | +| GET | `/api/auth/feishu/callback` | 飞书登录回调 | 公开回调 | +| POST | `/api/auth/logout` | 退出登录 | 已登录 | +| GET | `/api/person-mappings` | 人员映射列表 | 管理员 / AI 团队 | +| POST | `/api/person-mappings` | 新增人员映射 | 管理员 / AI 团队 | +| PATCH | `/api/person-mappings/{id}` | 修改人员映射 | 管理员 / AI 团队 | +| POST | `/api/person-mappings/{id}/resolve-feishu` | 根据手机号或邮箱解析飞书身份 | 管理员 / AI 团队 | + +## 5. Prompt 上下文 + +| 方法 | 路径 | 作用 | 权限 | +| --- | --- | --- | --- | +| GET | `/api/prompt-contexts` | 查看提示词上下文配置 | 管理员 / AI 团队 | +| PATCH | `/api/prompt-contexts/{id}` | 修改提示词上下文配置 | 管理员 / AI 团队 | +| POST | `/api/prompt-contexts/{id}/activate` | 启用某个提示词上下文版本 | 管理员 / AI 团队 | + +## 6. AI 草稿 + +| 方法 | 路径 | 作用 | 权限 | +| --- | --- | --- | --- | +| POST | `/api/ai-drafts/parse` | 提交一句话并生成草稿 | 老板;平台兜底可允许管理员测试 | +| GET | `/api/ai-drafts` | 草稿列表 | 相关用户、程经理、管理员 | +| GET | `/api/ai-drafts/{id}` | 草稿详情 | 相关用户、程经理、管理员 | +| PATCH | `/api/ai-drafts/{id}` | 修改草稿字段 | 草稿发起人、待确认程经理 | +| POST | `/api/ai-drafts/{id}/confirm` | 确认草稿 | 草稿发起人、待确认程经理 | +| POST | `/api/ai-drafts/{id}/cancel` | 取消草稿 | 草稿发起人 | +| POST | `/api/ai-drafts/{id}/convert` | 转换为事项或提醒 | 草稿发起人、待确认程经理 | +| POST | `/api/ai-drafts/{id}/follow-up` | 根据补充/重说重新生成草稿 | 草稿发起人 | + +`POST /api/ai-drafts/parse` 请求示例: + +```json +{ + "input_text": "明天上午提醒东东给我订会议室", + "source": "platform", + "client_context": {} +} +``` + +响应 `data` 必须包含 `draft_id`、`draft_type`、`status`、`summary`、`missing_fields` 和 `follow_up_questions`。 + +## 7. 事项 + +| 方法 | 路径 | 作用 | 权限 | +| --- | --- | --- | --- | +| GET | `/api/tasks` | 事项列表 | 相关用户、程经理、管理员 | +| POST | `/api/tasks` | 手动创建事项 | 老板、程经理 | +| GET | `/api/tasks/{id}` | 事项详情 | 相关用户、程经理、管理员 | +| PATCH | `/api/tasks/{id}` | 修改事项 | 发起人、程经理 | +| POST | `/api/tasks/{id}/manager-confirm` | 程经理确认复杂事项 | 指定程经理 | +| POST | `/api/tasks/{id}/cancel` | 取消事项 | 发起人、程经理 | +| POST | `/api/tasks/{id}/notify` | 发送或补发通知 | 发起人、程经理、管理员 | +| POST | `/api/tasks/{id}/feedback` | 平台内反馈 | 接收人 | + +## 8. 定时提醒 + +| 方法 | 路径 | 作用 | 权限 | +| --- | --- | --- | --- | +| GET | `/api/reminders` | 提醒列表 | 相关用户、程经理、管理员 | +| POST | `/api/reminders` | 创建提醒 | 已登录;给别人创建需老板或程经理 | +| GET | `/api/reminders/{id}` | 提醒详情 | 相关用户、程经理、管理员 | +| PATCH | `/api/reminders/{id}` | 修改提醒 | 创建人、发起人、管理员 | +| POST | `/api/reminders/{id}/pause` | 暂停提醒 | 创建人、发起人、管理员 | +| POST | `/api/reminders/{id}/resume` | 恢复提醒 | 创建人、发起人、管理员 | +| POST | `/api/reminders/{id}/cancel` | 取消提醒 | 创建人、发起人、管理员 | +| POST | `/api/reminders/{id}/notify` | 手动补发提醒通知 | 创建人、发起人、管理员 | +| POST | `/api/reminders/{id}/feedback` | 平台内反馈 | 接收人 | + +## 9. 通知、反馈和失败 + +| 方法 | 路径 | 作用 | 权限 | +| --- | --- | --- | --- | +| GET | `/api/notifications` | 通知记录列表 | 相关用户、程经理、管理员 | +| GET | `/api/notifications/{id}` | 通知详情 | 相关用户、程经理、管理员 | +| POST | `/api/notifications/{id}/retry` | 通知补发 | 发起人、程经理、管理员 | +| GET | `/api/feedbacks` | 反馈列表 | 相关用户、程经理、管理员 | +| GET | `/api/failure-records` | 失败记录列表 | 管理员 / AI 团队;必要时程经理 | +| GET | `/api/failure-records/{id}` | 失败详情 | 管理员 / AI 团队;必要时程经理 | +| PATCH | `/api/failure-records/{id}` | 更新处理状态 | 管理员 / AI 团队 | +| POST | `/api/failure-records/{id}/resolve` | 填写处理结果并标记已处理 | 管理员 / AI 团队 | + +## 10. 飞书回调 + +| 方法 | 路径 | 作用 | 权限 | +| --- | --- | --- | --- | +| POST | `/api/feishu/events` | 飞书事件回调,包含机器人消息事件 | 飞书验签 | +| POST | `/api/feishu/bot/messages` | 可选:单独承接机器人私聊消息 | 飞书验签 | +| POST | `/api/feishu/card-callback` | 飞书卡片回调 | 飞书验签 | + +飞书回调要求: + +1. 必须验签。 +2. 必须记录原始 payload 到 `feishu_events`。 +3. 必须使用 `event_id` 幂等。 +4. 验签失败不得执行业务动作。 +5. 回调处理失败必须写入 `failure_records`。 + +## 11. 敏感信息返回边界 + +1. API 不返回 API Key、App Secret、飞书 token。 +2. 手机号和邮箱默认脱敏返回,除非管理员维护页确有需要。 +3. 飞书通知只发送摘要和链接,不发送敏感全文。 +4. 模型调用日志对外接口默认不返回完整 prompt 和原始大段上下文。 diff --git a/docs/contracts/数据对象约定.md b/docs/contracts/数据对象约定.md index 8b13789..1b7dd28 100644 --- a/docs/contracts/数据对象约定.md +++ b/docs/contracts/数据对象约定.md @@ -1 +1,292 @@ +# 数据对象约定 +本文件是核心表、字段、外键关系和状态字段的唯一事实源。Django model、serializer、接口返回和测试用例中的字段应与本文件一致。 + +## 1. 通用字段 + +多数业务表使用: + +| 字段 | 说明 | +| --- | --- | +| `id` | 主键,建议 bigint 或 uuid | +| `created_at` | 创建时间 | +| `updated_at` | 更新时间 | +| `created_by` | 创建人,可为空时必须说明来源 | +| `updated_by` | 最后修改人 | +| `deleted_at` | 软删除时间,可选 | +| `remark` | 备注,可选 | + +第一版建议使用软删除,避免误删过程记录。 + +## 2. users + +平台登录、角色判断和数据范围控制。Django 项目初始化时建议使用自定义用户模型。 + +| 字段 | 说明 | +| --- | --- | +| `id` | 用户 ID | +| `username` | 登录名或内部唯一标识 | +| `name` | 显示姓名 | +| `role` | `boss`、`manager`、`employee`、`admin` | +| `phone` | 手机号,可选,普通日志需脱敏 | +| `email` | 邮箱,可选,普通日志需脱敏 | +| `feishu_open_id` | 飞书 open_id,可选 | +| `feishu_user_id` | 飞书 user_id,可选 | +| `feishu_union_id` | 飞书 union_id,可选 | +| `auth_provider` | `local`、`feishu` | +| `last_login_channel` | `platform`、`feishu_scan`、`feishu_in_app` | +| `status` | `active`、`disabled` | +| `last_login_at` | 最后登录时间 | + +## 3. person_mappings + +把老板输入中的姓名、称呼、部门或角色映射到平台用户和飞书身份。 + +| 字段 | 说明 | +| --- | --- | +| `id` | 映射 ID | +| `user_id` | 关联平台用户,可选 | +| `display_name` | 标准姓名 | +| `aliases` | JSON 数组,例如 `["东东", "CJN"]` | +| `department` | 部门 | +| `business_role` | 业务角色,例如行政、程经理、下单员 | +| `phone` | 手机号,可选 | +| `email` | 邮箱,可选 | +| `feishu_open_id` | 飞书 open_id | +| `feishu_user_id` | 飞书 user_id,可选 | +| `feishu_union_id` | 飞书 union_id,可选 | +| `mapping_status` | `pending`、`resolved`、`failed` | +| `is_trial_user` | 是否第一批试用人员 | +| `note` | 备注 | + +## 4. feishu_auth_sessions + +记录飞书登录过程和平台用户绑定结果。 + +| 字段 | 说明 | +| --- | --- | +| `id` | 会话 ID | +| `state` | OAuth state 或登录状态标识 | +| `feishu_open_id` | 飞书 open_id | +| `feishu_user_id` | 飞书 user_id | +| `feishu_union_id` | 飞书 union_id,可选 | +| `matched_user_id` | 匹配到的平台用户 | +| `login_channel` | `feishu_scan`、`feishu_in_app` | +| `status` | `pending`、`success`、`failed` | +| `failure_reason` | 失败原因 | +| `completed_at` | 完成时间 | + +## 5. bot_contexts + +记录老板机器人私聊中的补充/重说上下文。 + +| 字段 | 说明 | +| --- | --- | +| `id` | 上下文 ID | +| `user_id` | 平台用户 ID,第一版应为老板 | +| `feishu_open_id` | 飞书发送人 open_id | +| `current_draft_id` | 等待补充的草稿 ID | +| `status` | `idle`、`awaiting_follow_up`、`expired`、`closed` | +| `expires_at` | 补充/重说有效期,默认 30 分钟 | +| `last_message_id` | 最近一条飞书消息 ID | +| `last_message_text` | 最近一条消息内容 | + +## 6. prompt_contexts + +维护 AI 秘书调用模型时加载的上下文版本。 + +| 字段 | 说明 | +| --- | --- | +| `id` | 上下文 ID | +| `context_type` | `company_background`、`boss_style`、`business_rules` | +| `version` | 版本号 | +| `title` | 标题 | +| `content` | 实际使用的摘要或规则文本 | +| `status` | `draft`、`active`、`archived` | +| `activated_at` | 启用时间 | +| `created_by` | 创建人 | + +模型调用日志只保存本次使用的摘要、版本号和必要规则,避免反复保存完整背景库全文。 + +## 7. ai_drafts + +保存 AI 从一句话整理出的可确认草稿。 + +| 字段 | 说明 | +| --- | --- | +| `id` | 草稿 ID | +| `source` | `platform`、`feishu_bot` | +| `created_by` | 发起人 | +| `raw_input` | 原始输入 | +| `draft_type` | `task`、`reminder`、`qa`、`realtime_qa`、`note`、`unknown` | +| `status` | 见状态流转约定 | +| `title` | 草稿标题 | +| `content` | 事项或提醒内容 | +| `receiver_candidates` | JSON,接收人候选和置信度 | +| `scheduled_time` | 提醒或期望处理时间,可为空 | +| `repeat_rule` | `none`、`daily`、`weekly`、`monthly` | +| `requires_feedback` | 是否需要反馈 | +| `route_type` | `direct_notify`、`manager_confirm`、`needs_clarification` | +| `missing_fields` | JSON 数组 | +| `follow_up_questions` | JSON 数组,最多 3 个 | +| `answer` | `qa` / `realtime_qa` 的回答 | +| `parent_draft_id` | 补充/重说生成的新草稿指向上一版 | +| `model_call_log_id` | 关联模型调用日志 | + +## 8. model_call_logs + +记录模型输入输出、模型名、耗时和结果。 + +| 字段 | 说明 | +| --- | --- | +| `id` | 日志 ID | +| `provider` | `bailian` | +| `model_name` | 模型名 | +| `prompt_context_snapshot` | 本次使用的上下文版本和摘要 | +| `request_payload` | 请求摘要,避免保存密钥 | +| `raw_response` | 模型原始响应 | +| `parsed_json` | 解析后的 JSON | +| `status` | `success`、`failed` | +| `failure_reason` | 失败原因 | +| `latency_ms` | 耗时 | +| `created_by` | 调用发起人 | + +## 9. tasks + +需要接收人处理并反馈的事情。 + +| 字段 | 说明 | +| --- | --- | +| `id` | 事项 ID | +| `source_draft_id` | 来源草稿,可选 | +| `title` | 标题 | +| `content` | 事项内容 | +| `initiator_id` | 发起人 | +| `receiver_id` | 接收人 | +| `manager_id` | 复杂事项确认人,可选 | +| `status` | 见状态流转约定 | +| `visible_feedback_status` | `received`、`in_progress`、`completed`、`problem` | +| `requires_feedback` | 是否需要反馈 | +| `due_at` | 截止或期望反馈时间,可选 | +| `confirmed_at` | 确认时间 | +| `notified_at` | 通知时间 | +| `completed_at` | 完成时间 | +| `problem_reason` | 有问题原因,可选 | + +## 10. reminders + +未来某个时间触发的提醒。 + +| 字段 | 说明 | +| --- | --- | +| `id` | 提醒 ID | +| `source_draft_id` | 来源草稿,可选 | +| `related_task_id` | 关联事项,可选 | +| `title` | 标题 | +| `content` | 提醒内容 | +| `initiator_id` | 发起人 | +| `receiver_id` | 接收人 | +| `status` | 见状态流转约定 | +| `remind_at` | 首次提醒时间 | +| `next_trigger_at` | 下一次触发时间 | +| `repeat_rule` | `none`、`daily`、`weekly`、`monthly` | +| `requires_feedback` | 是否需要反馈 | +| `last_triggered_at` | 最近触发时间 | +| `cancelled_at` | 取消时间 | + +## 11. notifications + +飞书或平台内通知发送记录。 + +| 字段 | 说明 | +| --- | --- | +| `id` | 通知 ID | +| `target_type` | `ai_draft`、`task`、`reminder`、`failure_record` | +| `target_id` | 关联对象 ID | +| `receiver_id` | 接收人 | +| `channel` | `feishu`、`platform` | +| `message_type` | `text`、`card` | +| `summary` | 通知摘要 | +| `link_url` | 平台详情链接 | +| `status` | `pending`、`sent`、`failed`、`retrying`、`cancelled` | +| `idempotency_key` | 幂等键 | +| `feishu_message_id` | 飞书消息 ID | +| `sent_at` | 发送时间 | +| `failure_reason` | 失败原因 | + +## 12. feedbacks + +接收人的反馈状态和问题原因。 + +| 字段 | 说明 | +| --- | --- | +| `id` | 反馈 ID | +| `target_type` | `task`、`reminder` | +| `target_id` | 关联对象 ID | +| `feedback_by` | 反馈人 | +| `status` | `received`、`in_progress`、`completed`、`problem` | +| `problem_reason` | 有问题原因,`problem` 时必填 | +| `source` | `feishu_card`、`platform` | +| `notification_id` | 关联通知 | +| `created_at` | 反馈时间 | + +## 13. failure_records + +AI、通知、回调、调度等失败原因。 + +| 字段 | 说明 | +| --- | --- | +| `id` | 失败记录 ID | +| `failure_type` | 见状态流转约定中的失败类型 | +| `target_type` | 关联对象类型 | +| `target_id` | 关联对象 ID | +| `status` | `pending`、`processing`、`resolved`、`cancelled` | +| `reason` | 失败原因 | +| `raw_error` | 原始错误摘要,不含密钥 | +| `need_manager_sync` | 是否需要同步程经理 | +| `handled_by` | 处理人 | +| `handled_at` | 处理时间 | +| `handle_result` | 处理结果 | + +## 14. operation_logs + +人工确认、修改、取消、补发等过程留痕。 + +| 字段 | 说明 | +| --- | --- | +| `id` | 日志 ID | +| `actor_id` | 操作人 | +| `action` | 动作 | +| `target_type` | 对象类型 | +| `target_id` | 对象 ID | +| `channel` | `platform`、`feishu_bot`、`feishu_card`、`scheduler`、`admin` | +| `result` | `success`、`failed` | +| `summary` | 操作摘要 | +| `metadata` | JSON,避免敏感明文 | +| `created_at` | 操作时间 | + +## 15. feishu_events + +飞书回调原始事件和处理结果。 + +| 字段 | 说明 | +| --- | --- | +| `id` | 事件 ID | +| `event_id` | 飞书事件 ID | +| `event_type` | 事件类型 | +| `operator_open_id` | 操作人 open_id | +| `action_value` | 按钮值 | +| `target_type` | `ai_draft`、`task`、`reminder`、`auth`、`bot` | +| `target_id` | 关联业务对象 | +| `notification_id` | 关联通知 | +| `raw_payload` | 原始事件 | +| `process_status` | `pending`、`processed`、`failed`、`ignored` | +| `process_result` | 处理结果 | +| `created_at` | 接收时间 | + +## 16. 敏感字段规则 + +1. `phone`、`email` 可入库,但普通日志和普通列表接口默认脱敏。 +2. API Key、App Secret、飞书 token 不得入库到业务表或普通日志。 +3. `raw_error`、`metadata`、`request_payload` 必须避免密钥和完整个人联系方式。 +4. 飞书通知内容只保存和发送摘要,不展开敏感全文。 diff --git a/docs/contracts/状态流转约定.md b/docs/contracts/状态流转约定.md index 8b13789..2d340ba 100644 --- a/docs/contracts/状态流转约定.md +++ b/docs/contracts/状态流转约定.md @@ -1 +1,298 @@ +# 状态流转约定 +本文件是状态枚举、允许流转、触发人和日志要求的唯一事实源。代码枚举、接口返回和测试用例应与本文件一致。 + +## 1. 通用原则 + +1. 状态统一使用英文枚举。 +2. 状态变化必须通过 service 层完成。 +3. 关键状态变化必须写 `operation_logs`。 +4. 非法状态跳转必须返回 `state_conflict`。 +5. 通知、回调、调度相关状态变化必须幂等。 + +## 2. AI 草稿状态 + +| 状态 | 含义 | +| --- | --- | +| `pending_confirmation` | 等待老板确认 | +| `awaiting_follow_up` | 等待老板补充/重说 | +| `pending_manager_confirm` | 等待程经理确认 | +| `confirmed` | 已人工确认 | +| `converted` | 已转换为事项或提醒 | +| `cancelled` | 已取消 | +| `parse_failed` | AI 输出解析失败 | +| `expired` | 补充/重说上下文过期 | + +允许流转: + +```text +pending_confirmation -> awaiting_follow_up +pending_confirmation -> pending_manager_confirm +pending_confirmation -> confirmed +pending_confirmation -> cancelled +pending_confirmation -> parse_failed +awaiting_follow_up -> pending_confirmation +awaiting_follow_up -> expired +pending_manager_confirm -> confirmed +pending_manager_confirm -> cancelled +confirmed -> converted +``` + +约束: + +1. `parse_failed`、`cancelled`、`converted` 为终态。 +2. 未进入 `confirmed` 的草稿不得转换。 +3. 补充/重说生成的新草稿应写 `parent_draft_id`。 + +## 3. 事项状态 + +| 状态 | 含义 | +| --- | --- | +| `pending_manager_confirm` | 等待程经理确认 | +| `pending_notify` | 待通知 | +| `notified` | 已通知 | +| `notify_failed` | 通知失败 | +| `feedback_received` | 已收到反馈 | +| `completed` | 已完成 | +| `problem` | 有问题 | +| `cancelled` | 已取消 | + +允许流转: + +```text +pending_manager_confirm -> pending_notify +pending_manager_confirm -> cancelled +pending_notify -> notified +pending_notify -> notify_failed +notify_failed -> pending_notify +notified -> feedback_received +notified -> completed +notified -> problem +feedback_received -> completed +feedback_received -> problem +problem -> pending_notify +``` + +约束: + +1. `cancelled` 为终态。 +2. 未通知事项不得接收飞书反馈。 +3. `problem` 必须有问题原因。 +4. 通知失败不得标记为 `notified`。 + +## 4. 事项用户可见反馈状态 + +| 状态 | 含义 | +| --- | --- | +| `received` | 已收到 | +| `in_progress` | 处理中 | +| `completed` | 已完成 | +| `problem` | 有问题 | + +约束: + +1. `problem` 必须填写 `problem_reason`。 +2. 反馈人必须是事项接收人。 +3. `received` 和 `in_progress` 反馈写入 `feedbacks.status`,并将 `tasks.status` 置为 `feedback_received`、`tasks.visible_feedback_status` 置为对应值。 +4. `completed` 反馈将 `tasks.status` 和 `tasks.visible_feedback_status` 都置为 `completed`。 +5. `problem` 反馈将 `tasks.status` 和 `tasks.visible_feedback_status` 都置为 `problem`,并写入 `problem_reason`。 + +## 5. 提醒状态 + +| 状态 | 含义 | +| --- | --- | +| `active` | 生效中 | +| `paused` | 已暂停 | +| `triggered` | 一次性提醒已触发 | +| `trigger_failed` | 触发失败 | +| `cancelled` | 已取消 | +| `expired` | 已过期 | + +允许流转: + +```text +active -> paused +paused -> active +active -> triggered +active -> trigger_failed +trigger_failed -> active +active -> cancelled +paused -> cancelled +trigger_failed -> cancelled +triggered -> expired +``` + +约束: + +1. 只有 `active` 可以被 scheduler 触发。 +2. `cancelled` 为终态。 +3. `paused` 不触发通知。 +4. `trigger_failed` 必须写失败记录。 +5. 一次性提醒成功触发后,状态从 `active` 变为 `triggered`,并可在后续清理或展示时变为 `expired`。 +6. `daily`、`weekly`、`monthly` 周期提醒成功触发后状态保持 `active`,只更新 `last_triggered_at` 和下一次 `next_trigger_at`。 +7. 提醒反馈不改变提醒调度状态;反馈结果保存在 `feedbacks`,提醒是否继续触发只由 `status`、`repeat_rule` 和 `next_trigger_at` 决定。 + +## 6. 重复规则 + +| 值 | 含义 | +| --- | --- | +| `none` | 一次性 | +| `daily` | 每天 | +| `weekly` | 每周 | +| `monthly` | 每月 | + +第一版不支持 cron 表达式和自定义复杂周期。 + +## 7. 通知状态 + +| 状态 | 含义 | +| --- | --- | +| `pending` | 待发送 | +| `sent` | 已发送 | +| `failed` | 发送失败 | +| `retrying` | 补发中 | +| `cancelled` | 已取消 | + +允许流转: + +```text +pending -> sent +pending -> failed +failed -> retrying +retrying -> sent +retrying -> failed +pending -> cancelled +failed -> cancelled +``` + +约束: + +1. `sent` 不得重复发送同一通知。 +2. 补发必须保留原失败记录和新发送结果。 +3. 飞书通知必须使用幂等键。 + +通知幂等键建议: + +```text +target_type + target_id + receiver_id + channel + trigger_time +``` + +提醒触发幂等键建议: + +```text +reminder_id + trigger_time + receiver_id + notification_channel +``` + +## 8. 反馈状态 + +| 状态 | 含义 | +| --- | --- | +| `received` | 已收到 | +| `in_progress` | 处理中 | +| `completed` | 已完成 | +| `problem` | 有问题 | + +约束: + +1. 反馈目标只能是 `task` 或 `reminder`。 +2. 反馈人必须是接收人。 +3. `problem` 必须填写一句原因。 +4. 重复点击卡片不得重复创建相同反馈。 + +## 9. 失败记录状态 + +| 状态 | 含义 | +| --- | --- | +| `pending` | 待处理 | +| `processing` | 处理中 | +| `resolved` | 已处理 | +| `cancelled` | 已取消 | + +允许流转: + +```text +pending -> processing +pending -> resolved +pending -> cancelled +processing -> resolved +processing -> cancelled +``` + +约束: + +1. `resolved` 必须填写处理结果。 +2. 状态变化必须写操作日志。 + +## 10. 失败类型 + +| 类型 | 含义 | +| --- | --- | +| `ai_parse_failed` | AI 输出解析失败 | +| `person_mapping_missing` | 缺少人员映射 | +| `feishu_auth_failed` | 飞书登录失败 | +| `feishu_notify_failed` | 飞书通知失败 | +| `feishu_callback_failed` | 飞书回调处理失败 | +| `feishu_signature_invalid` | 飞书验签失败 | +| `scheduler_trigger_failed` | 定时提醒触发失败 | +| `unauthorized_bot_access` | 非老板使用机器人入口 | +| `bot_context_expired` | 补充/重说上下文过期 | +| `user_feedback_problem` | 用户反馈有问题 | +| `permission_denied` | 权限拒绝 | +| `other` | 其他 | + +## 11. 飞书事件处理状态 + +| 状态 | 含义 | +| --- | --- | +| `pending` | 已接收待处理 | +| `processed` | 已处理 | +| `failed` | 处理失败 | +| `ignored` | 已忽略 | + +约束: + +1. 同一 `event_id` 只处理一次。 +2. 验签失败不得执行业务动作。 +3. 处理失败必须写失败记录。 + +## 12. 用户和配置状态 + +用户状态: + +| 状态 | 含义 | +| --- | --- | +| `active` | 启用 | +| `disabled` | 停用 | + +人员映射状态: + +| 状态 | 含义 | +| --- | --- | +| `pending` | 待解析 | +| `resolved` | 已解析 | +| `failed` | 解析失败 | + +Prompt 上下文状态: + +| 状态 | 含义 | +| --- | --- | +| `draft` | 草稿 | +| `active` | 启用 | +| `archived` | 已归档 | + +飞书登录会话状态: + +| 状态 | 含义 | +| --- | --- | +| `pending` | 登录处理中 | +| `success` | 登录成功 | +| `failed` | 登录失败 | + +机器人上下文状态: + +| 状态 | 含义 | +| --- | --- | +| `idle` | 空闲 | +| `awaiting_follow_up` | 等待补充/重说 | +| `expired` | 已过期 | +| `closed` | 已关闭 | diff --git a/docs/plans/active/01_老板一句话闭环实施计划.md b/docs/plans/active/01_老板一句话闭环实施计划.md index 8b13789..480ccad 100644 --- a/docs/plans/active/01_老板一句话闭环实施计划.md +++ b/docs/plans/active/01_老板一句话闭环实施计划.md @@ -1 +1,581 @@ +# 老板一句话闭环 Implementation Plan +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** 建立第一版后端最小闭环:老板一句话生成 AI 草稿,人工确认后创建事项或提醒,通过飞书通知接收人并记录反馈和失败。 + +**Architecture:** 使用 Django 模块化单体。DRF view 负责请求入口,serializer 负责入参出参校验,service 负责权限、状态流转、事务和幂等,client 负责阿里百炼和飞书外部调用,audit 负责操作日志和失败记录。 + +**Tech Stack:** 部署 Python 3.12.13、本地开发 Python 3.11/3.12、Django 5.2 LTS、Django REST Framework、Django ORM、MySQL 8、Django management command scheduler、阿里百炼 API、飞书开放平台。 + +--- + +## 施工前必须阅读 + +1. `AGENTS.md` +2. `ARCHITECTURE.md` +3. `docs/specs/01_老板AI秘书与AI草稿.md` +4. `docs/specs/02_事项任务.md` +5. `docs/specs/03_飞书通知与反馈.md` +6. `docs/specs/04_定时提醒.md` +7. `docs/specs/05_权限日志失败记录.md` +8. `docs/contracts/API接口约定.md` +9. `docs/contracts/数据对象约定.md` +10. `docs/contracts/状态流转约定.md` +11. `docs/checklists/AI生成代码检查清单.md` +12. `docs/checklists/后端Review清单.md` + +## 范围边界 + +本计划只做第一版最小闭环: + +```text +老板一句话 +-> AI 草稿 +-> 人工确认 +-> 创建事项或定时提醒 +-> 飞书通知 +-> 接收人反馈 +-> 页面/API/Admin 可看到结果和失败记录 +``` + +本计划不做 AI 工作台、技能市场、文件上传、多模态处理、会议纪要、日报、文档摘要、复杂反馈看板、复杂 BI、成本驾驶舱、完整工作流、完整项目管理、多级子任务、甘特图、复杂审批流、复杂组织架构、cron 表达式、日历系统、自动操作交易系统、自动操作历史数据库、自动读取员工本地文件、手机端网页完整适配,也不把飞书机器人开放为程经理或普通员工通用派活入口。 + +## 可执行性门禁 + +1. 本计划先跑通 mock-first 后端闭环;单元测试和最小闭环测试不得访问真实百炼、真实飞书或公网回调。 +2. 真实联调前必须确认飞书正式应用、HTTPS 回调地址、个人消息权限、交互卡片权限、老板 / 程经理 / 第一批试用人员映射,以及百炼 API Key 环境变量。 +3. Docker / 部署环境固定 Python 3.12.13;本地开发允许 Python 3.11 或 3.12,但提交前必须在 Python 3.12.13 环境跑完整测试。 +4. scheduler 必须作为独立进程运行,同一环境同一应用库同时只能启动一个 scheduler 进程。 + +## 文件结构 + +第一轮代码施工建议创建这些目录和文件: + +```text +requirements.txt +manage.py +config/ + __init__.py + settings.py + urls.py + wsgi.py +apps/ + accounts/ + people/ + prompts/ + audit/ + drafts/ + tasks/ + reminders/ + notifications/ + feedbacks/ + feishu/ +tests/ +``` + +每个 Django app 采用统一结构: + +```text +apps// + __init__.py + admin.py + apps.py + models.py + serializers.py + services.py + urls.py + views.py + tests/ +``` + +外部 API 封装放在: + +```text +apps/drafts/ai_client.py +apps/feishu/client.py +apps/feishu/signature.py +``` + +--- + +### Task 1: Django 项目骨架和依赖基线 + +**Files:** +- Create: `requirements.txt` +- Create: `manage.py` +- Create: `config/__init__.py` +- Create: `config/settings.py` +- Create: `config/urls.py` +- Create: `config/wsgi.py` +- Create: `apps/__init__.py` +- Create: `apps/accounts/__init__.py` +- Create: `apps/accounts/apps.py` +- Create: `apps/people/__init__.py` +- Create: `apps/people/apps.py` +- Create: `apps/prompts/__init__.py` +- Create: `apps/prompts/apps.py` +- Create: `apps/audit/__init__.py` +- Create: `apps/audit/apps.py` +- Create: `apps/drafts/__init__.py` +- Create: `apps/drafts/apps.py` +- Create: `apps/tasks/__init__.py` +- Create: `apps/tasks/apps.py` +- Create: `apps/reminders/__init__.py` +- Create: `apps/reminders/apps.py` +- Create: `apps/notifications/__init__.py` +- Create: `apps/notifications/apps.py` +- Create: `apps/feedbacks/__init__.py` +- Create: `apps/feedbacks/apps.py` +- Create: `apps/feishu/__init__.py` +- Create: `apps/feishu/apps.py` + +- [ ] **Step 1: 写依赖文件** + +`requirements.txt` 第一版固定包含: + +```txt +Django==5.2.15 +djangorestframework==3.17.1 +mysqlclient==2.2.8 +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 +``` + +- [ ] **Step 2: 创建 Django 项目骨架和 app 空壳** + +使用 `config` 作为项目配置包,`apps` 作为业务 app 根目录。Task 1 必须先创建所有业务 app 的 `__init__.py` 和 `apps.py`,保证后续加入 `INSTALLED_APPS` 时可导入。 + +- [ ] **Step 3: 配置 settings** + +`config/settings.py` 必须包含: + +1. `INSTALLED_APPS` 加入 Django contrib app、DRF,以及已创建且可导入的业务 app 空壳。 +2. Task 1 暂不设置 `AUTH_USER_MODEL`;Task 2 实现 `apps.accounts.models.User` 后、首次 `makemigrations` / `migrate` 前再设置 `AUTH_USER_MODEL = "accounts.User"`。 +3. 数据库配置读取环境变量。 +4. 飞书和百炼密钥只读取环境变量。 +5. 日志配置避免输出密钥。 + +- [ ] **Step 4: 运行 Django 检查** + +Run: + +```bash +python manage.py check +``` + +Expected: `System check identified no issues`。 + +--- + +### Task 2: 账号、人员映射、Prompt 和审计基础模型 + +**Files:** +- Modify: `config/settings.py` +- Create: `apps/accounts/models.py` +- Create: `apps/people/models.py` +- Create: `apps/prompts/models.py` +- Create: `apps/audit/models.py` +- Create: `apps/accounts/admin.py` +- Create: `apps/people/admin.py` +- Create: `apps/prompts/admin.py` +- Create: `apps/audit/admin.py` +- Test: `apps/accounts/tests/test_permissions.py` +- Test: `apps/audit/tests/test_sensitive_logging.py` + +- [ ] **Step 1: 实现自定义 User** + +字段必须覆盖 `docs/contracts/数据对象约定.md` 中的 `users`。实现后立刻在 `config/settings.py` 设置 `AUTH_USER_MODEL = "accounts.User"`,且必须发生在第一次迁移之前。 + +- [ ] **Step 2: 实现 PersonMapping** + +字段必须覆盖 `person_mappings`,并支持别名 JSON。 + +- [ ] **Step 3: 实现 PromptContext** + +支持 `company_background`、`boss_style`、`business_rules` 三类上下文,只允许同类一个 `active` 版本。 + +- [ ] **Step 4: 实现 FailureRecord、OperationLog、ModelCallLog** + +失败类型和状态必须来自 `docs/contracts/状态流转约定.md`。 + +- [ ] **Step 5: 写权限和脱敏测试** + +测试必须覆盖: + +1. 普通员工不能访问失败记录列表。 +2. 普通日志工具不会输出完整手机号。 +3. 普通日志工具不会输出完整邮箱。 +4. 日志元数据不会保存 API Key、App Secret 或飞书 token。 + +- [ ] **Step 6: 生成并运行迁移** + +Run: + +```bash +python manage.py makemigrations +python manage.py migrate +python manage.py test apps.accounts apps.audit +``` + +Expected: migrations 成功,测试通过。 + +--- + +### Task 3: AI 草稿模型、AI 输出校验和解析服务 + +**Files:** +- Create: `apps/drafts/models.py` +- Create: `apps/drafts/serializers.py` +- Create: `apps/drafts/ai_client.py` +- Create: `apps/drafts/services.py` +- Create: `apps/drafts/views.py` +- Create: `apps/drafts/urls.py` +- Test: `apps/drafts/tests/test_ai_output_validator.py` +- Test: `apps/drafts/tests/test_parse_service.py` + +- [ ] **Step 1: 实现 AiDraft 模型** + +字段必须覆盖 `ai_drafts`,状态必须来自 `状态流转约定.md`。 + +- [ ] **Step 2: 实现 AI 输出 validator** + +validator 必须校验: + +1. JSON 可解析。 +2. `draft_type` 在允许范围内。 +3. `task` / `reminder` 才允许 `should_create_draft = true`。 +4. `qa` / `realtime_qa` 必须有 `answer`,且不得创建事项、提醒或通知。 +5. `follow_up_questions` 最多 3 个。 +6. `route_type` 在允许范围内。 +7. 结构化字段不得包含明显游戏化表达。 + +- [ ] **Step 3: 实现可 mock 的 ai_client** + +`ai_client` 只封装阿里百炼调用,不修改业务表。测试中必须使用 mock,不访问真实网络。 + +- [ ] **Step 4: 实现 parse service** + +service 流程: + +```text +加载 active prompt_contexts +-> 调用 ai_client +-> 写 model_call_logs +-> 校验 JSON +-> 成功创建 ai_drafts +-> 失败创建 parse_failed 草稿和 failure_records +``` + +- [ ] **Step 5: 实现 API** + +实现: + +1. `POST /api/ai-drafts/parse` +2. `GET /api/ai-drafts` +3. `GET /api/ai-drafts/{id}` +4. `PATCH /api/ai-drafts/{id}` +5. `POST /api/ai-drafts/{id}/cancel` +6. `POST /api/ai-drafts/{id}/follow-up` + +- [ ] **Step 6: 跑测试** + +Run: + +```bash +python manage.py test apps.drafts +``` + +Expected: AI 输出校验、解析失败、实时问答、补充/重说测试全部通过。 + +--- + +### Task 4: 事项、提醒、通知和反馈模型与服务 + +**Files:** +- Create: `apps/tasks/models.py` +- Create: `apps/tasks/services.py` +- Create: `apps/tasks/views.py` +- Create: `apps/reminders/models.py` +- Create: `apps/reminders/services.py` +- Create: `apps/reminders/views.py` +- Create: `apps/notifications/models.py` +- Create: `apps/notifications/services.py` +- Create: `apps/feedbacks/models.py` +- Create: `apps/feedbacks/services.py` +- Test: `apps/tasks/tests/test_task_permissions.py` +- Test: `apps/reminders/tests/test_reminder_permissions.py` +- Test: `apps/feedbacks/tests/test_feedback_rules.py` + +- [ ] **Step 1: 实现模型** + +字段必须覆盖 `tasks`、`reminders`、`notifications`、`feedbacks`。 + +- [ ] **Step 2: 实现事项 service** + +必须支持: + +1. 老板和程经理创建事项。 +2. 普通员工不能给别人创建事项。 +3. 程经理确认复杂事项。 +4. 通知失败保留失败状态。 +5. 有问题反馈必须填写原因。 + +- [ ] **Step 3: 实现提醒 service** + +必须支持: + +1. 所有人创建自己的提醒。 +2. 老板和程经理给别人创建提醒。 +3. 普通员工不能给别人创建提醒。 +4. 一次性、每天、每周、每月重复规则。 +5. 暂停、恢复、取消。 + +- [ ] **Step 4: 实现通知和反馈 service** + +必须支持: + +1. 生成飞书通知记录。 +2. 使用幂等键避免重复通知。 +3. 接收人反馈。 +4. 非接收人反馈返回 `permission_denied`。 + +- [ ] **Step 5: 实现 API** + +按 `docs/contracts/API接口约定.md` 实现 tasks、reminders、notifications、feedbacks 相关接口。 + +- [ ] **Step 6: 跑测试** + +Run: + +```bash +python manage.py test apps.tasks apps.reminders apps.notifications apps.feedbacks +``` + +Expected: 权限、状态、反馈原因和通知失败测试通过。 + +--- + +### Task 5: 飞书登录、机器人事件和卡片回调 + +**Files:** +- Create: `apps/feishu/models.py` +- Create: `apps/feishu/client.py` +- Create: `apps/feishu/signature.py` +- Create: `apps/feishu/services.py` +- Create: `apps/feishu/views.py` +- Create: `apps/feishu/urls.py` +- Test: `apps/feishu/tests/test_signature.py` +- Test: `apps/feishu/tests/test_event_idempotency.py` +- Test: `apps/feishu/tests/test_bot_access.py` +- Test: `apps/feishu/tests/test_card_callback.py` + +- [ ] **Step 1: 实现 FeishuEvent 和 FeishuAuthSession** + +字段必须覆盖 `feishu_events` 和 `feishu_auth_sessions`。 + +本任务所有测试必须 mock 飞书 SDK / HTTP client,不依赖真实飞书应用、公网回调或个人消息权限。 + +- [ ] **Step 2: 实现验签** + +验签失败返回 `feishu_signature_invalid`,不得执行业务动作。 + +- [ ] **Step 3: 实现事件幂等** + +同一 `event_id` 重放时只返回已有处理结果,不重复创建草稿、事项、提醒或反馈。 + +- [ ] **Step 4: 实现老板机器人入口** + +非老板私聊机器人时: + +```text +不调用 AI +不生成草稿 +回复当前入口仅对老板开放 +写 unauthorized_bot_access 失败记录 +``` + +- [ ] **Step 5: 实现卡片回调** + +支持: + +1. 老板确认草稿。 +2. 老板补充/重说。 +3. 老板取消草稿。 +4. 接收人反馈事项或提醒。 +5. 程经理待确认提醒只跳转平台。 + +- [ ] **Step 6: 跑测试** + +Run: + +```bash +python manage.py test apps.feishu +``` + +Expected: 验签、幂等、非老板访问、卡片反馈测试通过。 + +--- + +### Task 6: 草稿转换、事项通知和提醒调度闭环 + +**Files:** +- Modify: `apps/drafts/services.py` +- Modify: `apps/tasks/services.py` +- Modify: `apps/reminders/services.py` +- Modify: `apps/notifications/services.py` +- Create: `apps/reminders/management/commands/run_reminder_scheduler.py` +- Test: `apps/drafts/tests/test_convert_draft.py` +- Test: `apps/reminders/tests/test_scheduler.py` +- Test: `apps/notifications/tests/test_notification_retry.py` + +- [ ] **Step 1: 实现草稿确认和转换** + +`confirmed -> converted` 只允许执行一次。`task` 草稿转换为事项,`reminder` 草稿转换为提醒。 + +- [ ] **Step 2: 实现复杂事项转程经理确认** + +`route_type = manager_confirm` 时创建程经理待确认记录,并生成给程经理的飞书提醒。 + +- [ ] **Step 3: 实现 scheduler command** + +命令名: + +```bash +python manage.py run_reminder_scheduler +``` + +scheduler 只扫描 `active` 且 `next_trigger_at <= now` 的提醒。一次性提醒成功触发后走 `active -> triggered`;每天、每周、每月提醒成功触发后保持 `active`,只更新 `last_triggered_at` 和下一次 `next_trigger_at`。 + +同一环境同一应用库只允许一个 scheduler 进程运行;测试中要用幂等键验证重复扫描不会重复创建通知。 + +- [ ] **Step 4: 实现提醒触发幂等** + +幂等键: + +```text +reminder_id + trigger_time + receiver_id + notification_channel +``` + +- [ ] **Step 5: 实现通知补发** + +补发必须保留原失败记录,并写新的通知发送结果。 + +- [ ] **Step 6: 跑测试** + +Run: + +```bash +python manage.py test apps.drafts apps.reminders apps.notifications +``` + +Expected: 草稿不重复转换、提醒不重复触发、通知补发测试通过。 + +--- + +### Task 7: Admin、路由汇总、最小验收脚本 + +**Files:** +- Modify: `config/urls.py` +- Modify: `apps/*/admin.py` +- Create: `tests/test_minimal_closure.py` +- Modify: `README.md` + +- [ ] **Step 1: 汇总 API 路由** + +`config/urls.py` 挂载: + +1. `/api/ai-drafts/` +2. `/api/tasks/` +3. `/api/reminders/` +4. `/api/notifications/` +5. `/api/feedbacks/` +6. `/api/failure-records/` +7. `/api/feishu/` +8. `/api/auth/feishu/` + +- [ ] **Step 2: 注册 Admin** + +Admin 至少可查看和维护: + +1. 用户。 +2. 人员映射。 +3. Prompt 上下文。 +4. AI 草稿。 +5. 事项。 +6. 提醒。 +7. 通知。 +8. 反馈。 +9. 失败记录。 +10. 操作日志。 +11. 模型调用日志。 +12. 飞书事件。 + +- [ ] **Step 3: 写最小闭环测试** + +测试覆盖: + +```text +boss 用户提交一句话 +-> mock AI 返回 task 草稿 +-> boss 确认 +-> 创建事项 +-> mock 飞书通知成功 +-> 接收人反馈 completed +-> 事项状态 completed +-> 有操作日志和通知记录 +``` + +- [ ] **Step 4: 更新 README 本地启动** + +补充: + +1. 安装依赖。 +2. 环境变量。 +3. 迁移。 +4. 创建测试用户。 +5. 启动 Web。 +6. 启动 scheduler。 +7. 运行测试。 + +- [ ] **Step 5: 跑完整测试** + +Run: + +```bash +python manage.py test +python manage.py check +``` + +Expected: 全部测试通过,Django check 无错误。 + +--- + +## 完成标准 + +1. 所有模型字段与 `docs/contracts/数据对象约定.md` 一致。 +2. 所有状态与 `docs/contracts/状态流转约定.md` 一致。 +3. 所有接口路径与 `docs/contracts/API接口约定.md` 一致。 +4. AI 只生成草稿,人工确认后才创建事项或提醒。 +5. 普通员工不能给别人创建事项或提醒。 +6. 飞书回调验签和幂等有测试。 +7. 定时提醒重复触发防护有测试。 +8. 通知失败、AI 解析失败、回调失败有失败记录。 +9. 普通日志不包含密钥、token、完整手机号或完整邮箱。 +10. `python manage.py test` 和 `python manage.py check` 通过。 + +## 执行备注 + +如果执行中发现本计划与 spec 或 contracts 冲突,以 contracts 为准,并先提出计划变更建议;不要偷偷修改业务边界。 diff --git a/docs/plans/completed/02_飞书通知回调实施计划.md b/docs/plans/completed/02_飞书通知回调实施计划.md index 8b13789..e0f8cf5 100644 --- a/docs/plans/completed/02_飞书通知回调实施计划.md +++ b/docs/plans/completed/02_飞书通知回调实施计划.md @@ -1 +1,9 @@ +# 飞书通知回调实施计划归档占位 +当前没有已完成的飞书通知回调实施计划。 + +后续当飞书通知、交互卡片和回调能力完成并通过联调验收后,再从 `docs/plans/active/` 移入本目录。当前施工依据只看: + +```text +docs/plans/active/01_老板一句话闭环实施计划.md +``` diff --git a/docs/specs/01_老板AI秘书与AI草稿.md b/docs/specs/01_老板AI秘书与AI草稿.md index 8b13789..042802a 100644 --- a/docs/specs/01_老板AI秘书与AI草稿.md +++ b/docs/specs/01_老板AI秘书与AI草稿.md @@ -1 +1,160 @@ +# 01_老板 AI 秘书与 AI 草稿 +## 1. 模块目标 + +老板 AI 秘书负责接收老板在飞书机器人私聊或平台输入的一句话,判断意图,并整理成可人工确认的草稿。第一版 AI 只生成草稿或回答,不直接创建事项、不直接创建提醒、不直接发送通知。 + +## 2. 第一版做什么 + +1. 支持老板在平台输入文本。 +2. 支持老板通过飞书机器人私聊输入文本。 +3. 判断意图类型:`task`、`reminder`、`qa`、`realtime_qa`、`note`、`unknown`。 +4. 对 `task` 生成事项草稿。 +5. 对 `reminder` 生成提醒草稿。 +6. 对 `qa` 直接用大白话回答,不生成草稿。 +7. 对 `realtime_qa` 提示第一版暂不支持正式实时查询,不创建草稿、不通知、不做交易判断。 +8. 对 `unknown` 追问关键缺失信息,最多 3 个补充项。 +9. 支持老板确认、补充/重说、取消草稿。 +10. 支持补充/重说 30 分钟上下文,超时后按新输入处理。 +11. 支持复杂事项转程经理确认。 +12. AI 调用时加载公司背景摘要、老板大白话风格和第一版业务规则版本。 + +## 3. 第一版不做 + +1. 不做老板独立 App。 +2. 不做语音、图片、文件上传或多模态输入。 +3. 不做员工通用 AI 工作台。 +4. 不让 AI 自动替代程经理拆复杂任务。 +5. 不让 AI 未经确认直接通知别人。 +6. 不做实时天气、新闻、股价、行情查询的正式能力。 +7. 不把老板解释中的游戏化表达写进事项标题、接收人、时间、反馈要求等结构化字段。 + +## 4. 核心流程 + +平台入口: + +```text +老板输入一句话 +-> POST /api/ai-drafts/parse +-> 后端加载 prompt_contexts +-> 调用 ai_client +-> 校验模型 JSON +-> 写入 model_call_logs +-> 生成 ai_drafts +-> 前端展示草稿 +``` + +飞书机器人入口: + +```text +老板私聊机器人 +-> 飞书事件回调 +-> 后端验签 +-> 匹配平台用户 +-> 校验 boss 角色 +-> 检查 bot_contexts 是否等待补充 +-> 调用 AI 生成或重写草稿 +-> 发送飞书确认卡片 +-> 写入 feishu_events、ai_drafts、operation_logs +``` + +非老板私聊机器人: + +```text +收到机器人私聊 +-> 匹配用户 +-> 发现不是 boss +-> 不调用 AI +-> 不生成草稿 +-> 回复进入平台处理 +-> 写入未授权访问失败记录 +``` + +## 5. 数据对象 + +本模块主要使用: + +1. `users` +2. `person_mappings` +3. `bot_contexts` +4. `prompt_contexts` +5. `ai_drafts` +6. `model_call_logs` +7. `feishu_events` +8. `failure_records` +9. `operation_logs` + +字段以 `docs/contracts/数据对象约定.md` 为准。 + +## 6. 接口需求 + +主要接口: + +1. `POST /api/ai-drafts/parse` +2. `GET /api/ai-drafts` +3. `GET /api/ai-drafts/{id}` +4. `PATCH /api/ai-drafts/{id}` +5. `POST /api/ai-drafts/{id}/confirm` +6. `POST /api/ai-drafts/{id}/cancel` +7. `POST /api/ai-drafts/{id}/convert` +8. `POST /api/ai-drafts/{id}/follow-up` +9. `POST /api/feishu/events` +10. `POST /api/feishu/card-callback` + +接口格式以 `docs/contracts/API接口约定.md` 为准。 + +## 7. 权限规则 + +1. 飞书机器人私聊入口第一版只允许老板使用。 +2. 非老板私聊机器人时,不调用模型、不生成草稿,只记录未授权访问。 +3. 老板可以确认、补充/重说、取消自己发起的草稿。 +4. 程经理只能确认转给自己的复杂事项草稿。 +5. 管理员 / AI 团队只能协助排查,不代替老板或程经理做业务确认。 + +## 8. 状态流转 + +草稿状态以 `docs/contracts/状态流转约定.md` 为准。核心约束: + +1. `pending_confirmation` 只能等待确认、取消、补充或转程经理。 +2. 未确认草稿不得创建事项、提醒或通知。 +3. `parse_failed` 不得继续转换。 +4. `converted` 草稿不得重复转换。 +5. 补充/重说会生成新草稿,并通过 `parent_draft_id` 指向上一版草稿。 + +## 9. 失败和日志 + +必须记录: + +1. 原始输入和 AI 输出摘要。 +2. 模型调用使用的背景摘要版本、老板风格版本和业务规则版本。 +3. AI JSON 解析失败。 +4. 缺少人员映射。 +5. 非老板机器人访问。 +6. 补充/重说上下文过期。 +7. 人工确认、修改、取消、转程经理确认。 + +不得记录: + +1. API Key。 +2. 飞书 token。 +3. 完整手机号。 +4. 完整邮箱。 +5. 飞书 App Secret。 + +## 10. 给 AI 的测试样例 + +1. 老板输入“明天上午提醒东东给我订会议室”,应生成 `reminder` 草稿,不直接创建提醒。 +2. 老板输入“让剑楠下周给我看一下期货策略风险”,应生成 `task` 草稿,并倾向 `manager_confirm`。 +3. 老板输入“今天杭州天气怎么样”,应识别为 `realtime_qa`,不生成事项或提醒。 +4. 普通员工私聊机器人,应返回未开放提示,并写入未授权访问记录。 +5. 老板点击补充/重说后 30 分钟内再发消息,应关联上一版草稿。 +6. AI 输出 JSON 缺少 `draft_type` 时,应写入解析失败,不创建草稿闭环对象。 + +## 11. Review 重点 + +1. 是否严格保证 AI 只生成草稿。 +2. 是否所有关键动作都需要人工确认。 +3. 是否避免将游戏化表达写入结构化字段。 +4. 是否记录模型版本和 prompt_contexts 版本。 +5. 是否对非老板机器人访问做了后端权限校验。 +6. 是否对模型 JSON 做了结构校验和失败记录。 diff --git a/docs/specs/02_事项任务.md b/docs/specs/02_事项任务.md index 8b13789..a66a2f8 100644 --- a/docs/specs/02_事项任务.md +++ b/docs/specs/02_事项任务.md @@ -1 +1,131 @@ +# 02_事项任务 +## 1. 模块目标 + +事项任务模块承接老板 AI 秘书草稿、程经理确认和手动创建事项,负责通知接收人、记录反馈、展示状态和沉淀失败原因。第一版只做轻量事项闭环,不做完整项目管理。 + +## 2. 第一版做什么 + +1. 事项可以来自 AI 草稿确认。 +2. 事项可以由程经理确认复杂草稿后生成。 +3. 事项可以由老板或程经理手动创建。 +4. 普通员工第一版不默认给别人创建事项。 +5. 事项必须有发起人、接收人、事项内容、反馈要求和状态。 +6. 事项生成前必须经过人工确认。 +7. 事项生成后可以创建飞书通知。 +8. 接收人可以反馈:已收到、处理中、已完成、有问题。 +9. 有问题反馈必须填写一句原因。 +10. 发起人、程经理或有权限人员可以查看处理进度。 +11. 通知失败或无人反馈的事项需要可见,但不单独做看板。 + +## 3. 第一版不做 + +1. 不做复杂项目管理系统。 +2. 不做多级子任务。 +3. 不做复杂审批流。 +4. 不做绩效排名。 +5. 不做任务依赖和甘特图。 +6. 不做项目级看板。 +7. 不做独立反馈看板。 +8. 不从 AI 工作台结果生成事项。 + +## 4. 核心流程 + +简单事项: + +```text +AI 草稿或手动输入 +-> 人工确认 +-> 创建 tasks +-> 创建 notifications +-> 飞书通知接收人 +-> 接收人反馈 +-> 更新事项状态 +-> 写入 operation_logs +``` + +复杂事项: + +```text +老板确认转程经理 +-> 创建 pending_manager_confirm 事项或待确认记录 +-> 给程经理发飞书提醒 +-> 程经理进入平台确认、修改和分发 +-> 通知接收人 +-> 接收反馈 +``` + +## 5. 数据对象 + +本模块主要使用: + +1. `ai_drafts` +2. `tasks` +3. `notifications` +4. `feedbacks` +5. `failure_records` +6. `operation_logs` + +字段以 `docs/contracts/数据对象约定.md` 为准。 + +## 6. 接口需求 + +主要接口: + +1. `GET /api/tasks` +2. `POST /api/tasks` +3. `GET /api/tasks/{id}` +4. `PATCH /api/tasks/{id}` +5. `POST /api/tasks/{id}/manager-confirm` +6. `POST /api/tasks/{id}/cancel` +7. `POST /api/tasks/{id}/notify` +8. `POST /api/tasks/{id}/feedback` + +接口格式以 `docs/contracts/API接口约定.md` 为准。 + +## 7. 权限规则 + +1. 老板可以创建事项。 +2. 程经理可以创建和分发事项。 +3. 普通员工不能给别人创建事项。 +4. 接收人只能反馈自己相关事项。 +5. 程经理只能确认待自己处理的复杂事项。 +6. 管理员 / AI 团队可以为排查查看必要记录,但不处理业务分歧。 + +## 8. 状态流转 + +事项状态以 `docs/contracts/状态流转约定.md` 为准。核心约束: + +1. 未确认事项不得通知接收人。 +2. `pending_manager_confirm` 必须由程经理确认后才能进入通知流程。 +3. 通知失败进入 `notify_failed`,不得假装已通知。 +4. 已取消事项不能反馈、通知或补发。 +5. 有问题反馈会将事项标记为 `problem`,并记录原因。 + +## 9. 失败和日志 + +必须记录: + +1. 事项创建来源:AI 草稿、手动创建或程经理确认。 +2. 创建、修改、取消、通知、补发、反馈操作。 +3. 权限拒绝。 +4. 通知失败。 +5. 有问题反馈原因。 +6. 人员映射缺失或接收人不明确。 + +## 10. 给 AI 的测试样例 + +1. 普通员工请求给同事创建事项,应返回权限错误。 +2. 老板确认简单事项后,事项进入待通知或已通知状态。 +3. 研究类事项应进入程经理确认路径。 +4. 接收人反馈“有问题”但不填原因,应返回校验错误。 +5. 通知失败时,事项状态不得变成已通知。 +6. 已取消事项不得再次通知。 + +## 11. Review 重点 + +1. 后端是否做了权限校验,而不是只靠前端隐藏按钮。 +2. 状态流转是否只走允许路径。 +3. 通知失败是否留下失败记录。 +4. 有问题反馈是否强制原因。 +5. 是否避免把复杂项目管理能力混入第一版。 diff --git a/docs/specs/03_飞书通知与反馈.md b/docs/specs/03_飞书通知与反馈.md index 8b13789..e2ebae4 100644 --- a/docs/specs/03_飞书通知与反馈.md +++ b/docs/specs/03_飞书通知与反馈.md @@ -1 +1,146 @@ +# 03_飞书通知与反馈 +## 1. 模块目标 + +飞书模块负责平台登录身份、老板机器人私聊入口、个人消息通知、交互卡片确认和反馈回调。第一版飞书是闭环主入口之一,所有回调必须验签、幂等、可追溯。 + +## 2. 第一版做什么 + +1. 飞书扫码登录 / 身份登录。 +2. 根据飞书身份匹配平台用户和角色。 +3. 接收老板机器人私聊消息。 +4. 非老板私聊机器人时提示进入平台并记录未授权访问。 +5. 发送 AI 草稿确认卡片给老板。 +6. 发送复杂事项待确认提醒给程经理,按钮只跳转平台。 +7. 发送事项或提醒通知给接收人。 +8. 接收卡片按钮回调。 +9. 支持接收人反馈已收到、处理中、已完成、有问题。 +10. 记录飞书事件、通知发送结果和回调处理结果。 + +## 3. 第一版不做 + +1. 不把机器人开放成程经理或普通员工通用派活入口。 +2. 不让程经理在机器人里对话分发事项。 +3. 不在飞书消息里展开敏感全文。 +4. 不做飞书卡片内复杂字段编辑表单。 +5. 不绕过平台角色权限。 + +## 4. 核心流程 + +飞书登录: + +```text +用户点击飞书登录 +-> 跳转飞书授权 +-> 飞书回调 auth callback +-> 校验 state 和 code +-> 换取飞书身份 +-> 匹配平台用户 +-> 写入 feishu_auth_sessions +-> 建立平台登录态 +``` + +机器人私聊: + +```text +飞书推送消息事件 +-> 验签 +-> 记录 feishu_events +-> 匹配平台用户 +-> 校验 boss 角色 +-> 调用 AI 草稿服务 +-> 发送确认卡片 +``` + +卡片回调: + +```text +飞书卡片按钮点击 +-> 验签 +-> 记录 feishu_events +-> 查找 notification / draft / task / reminder +-> 校验操作人权限 +-> 执行业务动作 +-> 写 operation_logs +-> 返回飞书处理结果 +``` + +## 5. 数据对象 + +本模块主要使用: + +1. `users` +2. `person_mappings` +3. `feishu_auth_sessions` +4. `feishu_events` +5. `notifications` +6. `feedbacks` +7. `bot_contexts` +8. `failure_records` +9. `operation_logs` + +字段以 `docs/contracts/数据对象约定.md` 为准。 + +## 6. 接口需求 + +主要接口: + +1. `GET /api/auth/feishu/login` +2. `GET /api/auth/feishu/callback` +3. `POST /api/feishu/events` +4. `POST /api/feishu/bot/messages` +5. `POST /api/feishu/card-callback` +6. `POST /api/notifications/{id}/retry` + +接口格式以 `docs/contracts/API接口约定.md` 为准。 + +## 7. 权限规则 + +1. 飞书身份只用于认证和操作人追溯,业务权限仍以平台角色为准。 +2. 机器人私聊入口第一版只允许老板使用。 +3. 老板只能确认、取消、补充自己发起的草稿。 +4. 程经理待办提醒只能跳转平台确认。 +5. 反馈人必须是事项或提醒接收人。 +6. 管理员 / AI 团队可以处理系统失败和补发,但不能代替业务反馈。 + +## 8. 状态与幂等 + +状态以 `docs/contracts/状态流转约定.md` 为准。幂等约束: + +1. 同一个飞书 `event_id` 只处理一次。 +2. 同一个通知只允许一个有效发送结果。 +3. 同一个卡片按钮重复点击不得重复创建事项、提醒或反馈。 +4. 回调处理失败必须标记 `feishu_events.process_status = failed` 并写失败记录。 + +## 9. 失败和日志 + +必须记录: + +1. 飞书登录成功或失败。 +2. 飞书事件原始 payload。 +3. 机器人消息处理结果。 +4. 卡片回调处理结果。 +5. 通知发送成功或失败。 +6. 验签失败。 +7. 找不到关联对象。 +8. 操作人无权操作。 +9. 有问题反馈缺少原因。 + +普通日志不得打印飞书 token、App Secret、完整手机号或完整邮箱。 + +## 10. 给 AI 的测试样例 + +1. 验签失败的回调应返回拒绝并写失败记录。 +2. 同一 `event_id` 重放应幂等,不重复创建反馈。 +3. 非接收人点击反馈按钮应返回权限错误。 +4. 老板点击取消草稿后,草稿不能再转换。 +5. 非老板私聊机器人不应调用 AI。 +6. 飞书通知失败时,应写 `failure_records` 并保留通知失败状态。 + +## 11. Review 重点 + +1. 回调是否验签。 +2. 回调是否幂等。 +3. 飞书身份是否没有直接绕过平台权限。 +4. 通知内容是否只发摘要和链接。 +5. 失败是否可复盘。 diff --git a/docs/specs/04_定时提醒.md b/docs/specs/04_定时提醒.md index 8b13789..d978c1f 100644 --- a/docs/specs/04_定时提醒.md +++ b/docs/specs/04_定时提醒.md @@ -1 +1,139 @@ +# 04_定时提醒 +## 1. 模块目标 + +定时提醒模块负责创建一次性或固定周期提醒,到点生成通知、发送飞书消息、按需接收反馈,并记录触发结果和失败原因。 + +## 2. 第一版做什么 + +1. 支持一次性提醒。 +2. 支持每天、每周、每月固定周期提醒。 +3. 支持提醒来自手动创建。 +4. 支持提醒来自老板 AI 草稿确认。 +5. 支持提醒与事项关联。 +6. 到点后通知接收人。 +7. 通知成功或失败都要记录。 +8. 支持查看自己相关提醒状态。 +9. 创建人、发起人、管理员可以修改、暂停或取消提醒。 +10. 提醒可以设置是否需要接收人反馈。 + +## 3. 第一版不做 + +1. 不做 cron 表达式。 +2. 不做自定义复杂周期规则。 +3. 不做日历系统。 +4. 不做复杂自动化流程。 +5. 不自动操作外部系统。 +6. 不从 AI 工作台结果生成提醒。 + +## 4. 核心流程 + +创建提醒: + +```text +手动创建或草稿确认 +-> 后端校验创建权限 +-> 写入 reminders +-> 计算 next_trigger_at +-> 写 operation_logs +``` + +触发提醒: + +```text +scheduler 扫描 due reminders +-> 校验提醒状态 +-> 生成幂等键 +-> 创建 notifications +-> 调用飞书发送 +-> 更新 last_triggered_at 和 next_trigger_at +-> 成功或失败都写记录 +``` + +反馈: + +```text +接收人点击卡片反馈 +-> 飞书回调验签 +-> 校验接收人权限 +-> 写 feedbacks +-> 保留 reminders 调度状态,反馈结果通过 feedbacks 展示 +``` + +## 5. 数据对象 + +本模块主要使用: + +1. `ai_drafts` +2. `tasks` +3. `reminders` +4. `notifications` +5. `feedbacks` +6. `failure_records` +7. `operation_logs` + +字段以 `docs/contracts/数据对象约定.md` 为准。 + +## 6. 接口需求 + +主要接口: + +1. `GET /api/reminders` +2. `POST /api/reminders` +3. `GET /api/reminders/{id}` +4. `PATCH /api/reminders/{id}` +5. `POST /api/reminders/{id}/pause` +6. `POST /api/reminders/{id}/resume` +7. `POST /api/reminders/{id}/cancel` +8. `POST /api/reminders/{id}/notify` +9. `POST /api/reminders/{id}/feedback` + +接口格式以 `docs/contracts/API接口约定.md` 为准。 + +## 7. 权限规则 + +1. 所有人可以创建自己的提醒。 +2. 老板和程经理可以给别人创建提醒。 +3. 普通员工不能给同事创建提醒。 +4. 创建人、发起人、管理员可以修改、暂停或取消提醒。 +5. 接收人只能反馈自己相关提醒。 + +## 8. 状态流转 + +提醒状态以 `docs/contracts/状态流转约定.md` 为准。核心约束: + +1. `active` 提醒才允许 scheduler 触发。 +2. `paused` 不触发,但可以恢复。 +3. `cancelled` 不触发、不可恢复。 +4. `trigger_failed` 必须写失败记录。 +5. 同一个提醒同一触发时间同一接收人只能生成一条有效通知。 +6. 一次性提醒成功触发后进入 `triggered`;周期提醒成功触发后保持 `active` 并计算下一次 `next_trigger_at`。 +7. 提醒反馈不改变提醒调度状态,反馈结果通过 `feedbacks` 展示。 + +## 9. 失败和日志 + +必须记录: + +1. 提醒创建、修改、暂停、恢复、取消。 +2. scheduler 触发成功或失败。 +3. 飞书通知发送成功或失败。 +4. 幂等冲突或重复触发跳过。 +5. 权限拒绝。 +6. 有问题反馈原因。 + +## 10. 给 AI 的测试样例 + +1. 普通员工给同事创建提醒,应返回权限错误。 +2. `paused` 提醒到点不应触发通知。 +3. 同一提醒同一触发时间重复扫描,不应重复创建通知。 +4. 每周提醒触发后,应计算下一次提醒时间。 +5. 通知失败应写失败记录。 +6. 自己提醒自己默认不需要反馈,老板或程经理给别人提醒默认需要反馈。 + +## 11. Review 重点 + +1. 是否防止重复触发。 +2. 是否限制普通员工给别人创建提醒。 +3. 是否不支持 cron 等第一版不做内容。 +4. scheduler 是否走 service 层而不是直接改业务表。 +5. 失败是否可复盘。 diff --git a/docs/specs/05_权限日志失败记录.md b/docs/specs/05_权限日志失败记录.md index 8b13789..ab62a63 100644 --- a/docs/specs/05_权限日志失败记录.md +++ b/docs/specs/05_权限日志失败记录.md @@ -1 +1,135 @@ +# 05_权限日志失败记录 +## 1. 模块目标 + +权限、日志和失败记录模块负责保证第一版闭环可控、可追溯、可复盘。权限必须在后端校验,关键操作必须写日志,AI、飞书、调度和业务失败必须形成失败记录。 + +## 2. 第一版做什么 + +1. 定义老板、程经理、普通员工、管理员 / AI 团队四类角色。 +2. 控制事项、提醒、草稿、反馈、失败记录的可见范围和操作范围。 +3. 记录关键操作日志。 +4. 记录 AI 解析失败、人员映射缺失、飞书通知失败、回调失败、定时触发失败、用户反馈有问题等失败。 +5. 支持管理员 / AI 团队查看和处理失败记录。 +6. 对敏感信息做日志边界约束。 + +## 3. 第一版不做 + +1. 不做复杂组织架构。 +2. 不做细粒度多级权限。 +3. 不做复杂审批流。 +4. 不做独立失败看板或复杂 BI。 +5. 不把飞书身份直接等同于业务权限。 +6. 不把密钥、token、完整手机号、完整邮箱写入普通日志。 + +## 4. 核心流程 + +权限校验: + +```text +请求进入 DRF view +-> permission class 做入口校验 +-> serializer 做参数校验 +-> service 做业务权限和状态校验 +-> 通过后执行业务动作 +``` + +失败记录: + +```text +业务或外部调用失败 +-> 写 failure_records +-> 保留关联对象和失败类型 +-> 管理员 / AI 团队处理 +-> 填写处理结果 +-> 写 operation_logs +``` + +操作日志: + +```text +关键动作发生 +-> 记录 actor、action、target_type、target_id +-> 记录操作渠道和结果摘要 +-> 避免记录敏感明文 +``` + +## 5. 数据对象 + +本模块主要使用: + +1. `users` +2. `failure_records` +3. `operation_logs` +4. `model_call_logs` +5. `feishu_events` + +字段以 `docs/contracts/数据对象约定.md` 为准。 + +## 6. 接口需求 + +主要接口: + +1. `GET /api/users/me` +2. `GET /api/failure-records` +3. `GET /api/failure-records/{id}` +4. `PATCH /api/failure-records/{id}` +5. `POST /api/failure-records/{id}/resolve` +6. `GET /api/notifications` +7. `GET /api/notifications/{id}` +8. `GET /api/feedbacks` + +接口格式以 `docs/contracts/API接口约定.md` 为准。 + +## 7. 权限规则 + +1. 普通员工只能看自己作为接收人、创建人或反馈人的记录。 +2. 老板能看自己发起、创建或接收的记录。 +3. 程经理能看自己发起、负责、待确认,以及第一批试用管理范围内的记录。 +4. 管理员 / AI 团队能看失败记录、通知记录、人员映射和必要操作日志。 +5. 普通员工不能给别人创建事项或提醒。 +6. 反馈人必须是事项或提醒接收人。 +7. 飞书登录用户必须匹配到启用状态的平台用户后才能进入平台。 + +## 8. 状态流转 + +失败记录状态以 `docs/contracts/状态流转约定.md` 为准。核心约束: + +1. 新失败进入 `pending`。 +2. 处理中进入 `processing`。 +3. 填写处理结果后进入 `resolved`。 +4. 确认不处理可进入 `cancelled`。 +5. 失败记录状态变化必须写操作日志。 + +## 9. 必须写日志的动作 + +1. 飞书登录成功或失败。 +2. 机器人收到老板消息。 +3. 非老板私聊机器人。 +4. AI 生成草稿、解析失败。 +5. 人工确认、修改、取消草稿。 +6. 老板点击补充/重说。 +7. 程经理确认复杂事项。 +8. 创建事项、创建提醒。 +9. 发送通知、补发通知、通知失败。 +10. 接收反馈,尤其是有问题反馈。 +11. 定时提醒触发成功或失败。 +12. 失败记录处理。 +13. 背景摘要或老板风格提示词版本启用。 + +## 10. 给 AI 的测试样例 + +1. 普通员工创建给别人的事项,应被拒绝并写权限失败日志。 +2. 普通员工创建给别人的提醒,应被拒绝。 +3. 非接收人提交反馈,应被拒绝。 +4. 管理员处理失败记录时,必须留下处理结果。 +5. 日志中不得包含完整手机号、完整邮箱、飞书 token 或密钥。 +6. 未匹配平台用户的飞书登录应失败并写失败记录。 + +## 11. Review 重点 + +1. 后端权限是否完整。 +2. 状态流转是否可追踪。 +3. 失败记录是否包含关联对象、失败类型和处理结果。 +4. 日志是否记录操作人和渠道。 +5. 敏感信息是否被脱敏。