# 数据对象约定 本文件是核心表、字段、外键关系和状态字段的唯一事实源。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` | 业务角色,例如行政、程经理、下单员 | | `manager_user_id` | 第一批试用管理范围归属,可选 | | `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` | 备注 | 口径: 1. `users` 是登录、角色和权限判断的权威对象。 2. `person_mappings` 是自然语言称呼、手机号 / 邮箱、飞书身份和第一批试用人员映射的权威对象。 3. 同一个真实人员如果可以登录平台,应在 `person_mappings.user_id` 绑定对应 `users.id`。 4. 程经理第一批试用管理范围先用 `manager_user_id` 或等价白名单表达,不引入完整组织树。 ## 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. secretary_conversations 老板 AI 秘书会话。第一阶段只有一个老板秘书入口,可先固定 `conversation_id=boss_secretary_default`,但表结构要能支持后续多会话。 | 字段 | 说明 | | --- | --- | | `id` | 会话 ID | | `conversation_id` | 业务会话唯一标识 | | `boss_id` | 关联老板用户 | | `source` | `feishu`、`web`、`debug` | | `status` | `active`、`closed` | | `last_message_at` | 最近消息时间 | ## 6. secretary_messages 老板输入、AI 回复、AI 追问、普通记录和上下文回顾的统一消息记录。该表只追加,不修改,用于对话回放、上下文回顾和问题复盘。 | 字段 | 说明 | | --- | --- | | `id` | 消息 ID | | `conversation_id` | 关联 `secretary_conversations.conversation_id` | | `boss_id` | 关联老板用户 | | `source` | `feishu`、`web`、`debug` | | `message_id` | 外部消息 ID 或内部生成 ID,和 `source` 组成幂等键 | | `role` | `boss`、`assistant`、`system` | | `text` | 原始输入或 AI 回复 | | `answer` | AI 给老板的回复,可为空 | | `intent_type` | `task`、`reminder`、`qa`、`realtime_qa`、`note`、`need_more_info`、`unknown`、`unsupported`、`context_summary` | | `draft_id` | 关联 AI 草稿,可为空 | | `raw_payload` | 原始请求摘要,避免保存密钥 | | `bot_context_snapshot` | JSONB,消息发生时的上下文快照 | | `created_at` | 消息时间 | ## 7. bot_contexts 记录老板机器人私聊中的补充/重说上下文。 | 字段 | 说明 | | --- | --- | | `id` | 上下文 ID | | `conversation_id` | 当前老板秘书会话 ID | | `boss_id` | PostgreSQL 中的老板用户 ID | | `status` | `empty`、`awaiting_more_info`、`awaiting_confirm`、`awaiting_follow_up`、`expired`、`cleared` | | `pending_draft_id` | 当前待补充或待确认的草稿 ID | | `pending_draft_type` | `task`、`reminder`、`none` | | `last_intent` | 上一条有效意图 | | `expires_at` | 上下文有效期,进入待补充或待确认时重置为 30 分钟后 | | `follow_up_count` | 当前草稿累计追问轮次 | | `last_message_id` | 最近一次参与上下文判断的消息 ID | | `extracted_facts` | JSONB,从多轮对话提取的候选事实,只用于草稿修订 | | `updated_at` | 上下文最近更新时间 | `awaiting_follow_up` 专用于老板点击飞书确认卡片上的“补充/重说”后,等待下一条消息修订上一版草稿;该状态必须带 `pending_draft_id` 和 `expires_at`。 ## 8. prompt_contexts 维护 AI 秘书调用模型时加载的上下文版本。 | 字段 | 说明 | | --- | --- | | `id` | 上下文 ID | | `context_type` | `company_background_summary`、`boss_communication_style`、`ai_secretary_rules`、`role_and_alias_rules` | | `version` | 版本号 | | `title` | 标题 | | `content` | 实际使用的摘要或规则文本 | | `status` | `draft`、`active`、`archived` | | `activated_at` | 启用时间 | | `created_by` | 创建人 | 模型调用日志只保存本次使用的摘要、版本号和必要规则,避免反复保存完整背景库全文。 ## 9. ai_drafts 保存 AI 从一句话整理出的可确认草稿。 | 字段 | 说明 | | --- | --- | | `id` | 草稿 ID | | `source` | `platform`、`feishu_bot` | | `source_message_id` | 飞书或外部入口消息 ID,可选 | | `created_by` | 发起人 | | `parent_draft_id` | 补充/重说生成新草稿时,关联上一版草稿 | | `raw_input` | 原始输入 | | `intent` | `task`、`reminder`、`qa`、`realtime_qa`、`note`、`need_more_info`、`unknown`、`unsupported` | | `draft_type` | `task`、`reminder`、`none` | | `should_create_draft` | `task/reminder` 为 true;其他意图必须为 false | | `status` | 见状态流转约定 | | `title` | 草稿标题 | | `content` | 事项或提醒内容 | | `receiver_candidates` | JSON,接收人候选和置信度 | | `receiver_text` | 未映射成功时保留老板原始称呼 | | `selected_receiver_id` | 人工确认后的接收人,可选 | | `scheduled_at` | 提醒时间,可为空;任务可使用 `schedule_text` 表达期望时间 | | `schedule_text` | 老板原始时间表达 | | `recurrence_type` | `none`、`daily`、`weekly`、`monthly` | | `requires_feedback` | 是否需要反馈 | | `route_type` | `none`、`direct_after_boss_confirm`、`manager_confirm_required` | | `need_manager_confirm` | 是否需要程经理确认 | | `missing_fields` | JSON 数组 | | `questions` | JSON 数组,最多 3 个;确认草稿一般为空 | | `answer` | 给老板看的回复摘要;不得写“已通知、已创建、已发送”等执行语义 | | `active_card_notification_id` | 当前有效确认卡片通知,可选 | | `superseded_by_draft_id` | 被补充/重说的新草稿替代时,指向新草稿 | | `model_call_log_id` | 关联模型调用日志 | | `confirmed_by` | 确认人 | | `confirmed_at` | 确认时间 | | `cancelled_reason` | 取消原因 | 草稿生命周期口径: 1. 每个草稿同一时间只能有一张有效确认卡片,对应 `active_card_notification_id`。 2. 老板点击“补充/重说”后,原草稿进入 `awaiting_follow_up`,原确认卡片应失效。 3. 30 分钟内收到补充消息后,系统生成新草稿,`parent_draft_id` 指向原草稿;原草稿进入 `superseded`,`superseded_by_draft_id` 指向新草稿。 4. 超过 30 分钟仍未收到补充消息时,`bot_contexts` 标记为 `expired`,原草稿进入 `expired`;老板下一条消息按新输入处理。 5. `note` / `unknown` 不进入事项、提醒或通知闭环;如需留痕,只能保存回复、消息、模型调用日志或最小草稿记录。 ## 10. model_call_logs 记录模型输入输出、模型名、耗时和结果。 | 字段 | 说明 | | --- | --- | | `id` | 日志 ID | | `provider` | `bailian` | | `model_name` | 模型名 | | `prompt_version` | 提示词版本 | | `background_context_version` | 公司背景摘要版本 | | `boss_style_version` | 老板沟通风格版本 | | `ai_secretary_rules_version` | AI 秘书业务规则版本 | | `context_snapshot` | 本次使用的上下文版本和摘要 | | `input_text` | 用户原始输入 | | `request_payload` | 请求摘要,避免保存密钥 | | `response_payload` | 模型原始响应结构 | | `parsed_result` | 后端解析后的 `AiSecretaryResponse` JSON | | `status` | `success`、`failed` | | `error_message` | 失败原因 | | `latency_ms` | 耗时 | | `created_by` | 调用发起人 | ## 11. tasks 需要接收人处理并反馈的事情。 | 字段 | 说明 | | --- | --- | | `id` | 事项 ID | | `source_type` | `ai_draft`、`manual` | | `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` | 有问题原因,可选 | 复杂事项必须在老板确认后创建 `status=pending_manager_confirm` 的事项壳,不得一直停留在草稿中等待程经理补齐。 ## 12. reminders 未来某个时间触发的提醒。 | 字段 | 说明 | | --- | --- | | `id` | 提醒 ID | | `source_type` | `ai_draft`、`manual` | | `source_draft_id` | 来源草稿,可选 | | `related_task_id` | 关联事项,可选 | | `title` | 标题 | | `content` | 提醒内容 | | `initiator_id` | 发起人 | | `receiver_id` | 接收人 | | `status` | 见状态流转约定 | | `scheduled_at` | 首次提醒时间 | | `next_trigger_at` | 下一次触发时间 | | `recurrence_type` | `none`、`daily`、`weekly`、`monthly` | | `requires_feedback` | 是否需要反馈 | | `last_triggered_at` | 最近触发时间 | | `cancelled_at` | 取消时间 | ## 13. notifications 飞书或平台内通知发送记录。 | 字段 | 说明 | | --- | --- | | `id` | 通知 ID | | `target_type` | `ai_draft`、`task`、`reminder`、`failure_record` | | `target_id` | 关联对象 ID | | `purpose` | `draft_confirm`、`manager_confirm`、`task_notify`、`reminder_trigger` | | `receiver_id` | 接收人 | | `channel` | `feishu_personal`、`feishu_group`、`platform` | | `message_type` | `text`、`card` | | `title` | 通知标题 | | `summary` | 通知摘要 | | `link_url` | 平台详情链接 | | `card_id` | 飞书卡片 ID,可选 | | `status` | `pending`、`sending`、`sent`、`failed`、`retrying`、`cancelled`、`expired` | | `trigger_time` | 提醒触发时间;非提醒触发通知可为空 | | `idempotency_key` | 幂等键,按通知目的生成并唯一约束 | | `action_token_hash` | 平台反馈页一次性操作 token 的 hash,可选 | | `feishu_message_id` | 飞书消息 ID | | `sent_at` | 发送时间 | | `expires_at` | 卡片或通知操作过期时间,可选 | | `invalidated_at` | 被新卡片替代或业务取消时的失效时间,可选 | | `failure_reason` | 失败原因 | | `retry_count` | 重试次数 | | `last_retry_at` | 最近重试时间 | 提醒触发类通知的幂等键格式建议: ```text reminder:{reminder_id}:{trigger_time}:{receiver_id}:{channel} ``` 任务通知、草稿确认卡片和程经理待确认提醒也必须生成各自的幂等键,避免重复点击、重复补发或回调重放造成多条有效通知。 ## 14. 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` | 反馈时间 | ## 15. 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` | 处理结果 | `target_type` 可使用 `ai_draft`、`task`、`reminder`、`notification`、`feishu_event`、`model_call_log` 等实际对象类型。AI 解析失败时,如果无法创建最小 `parse_failed` 草稿,可关联 `model_call_log`。 ## 16. 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` | 操作时间 | ## 17. feishu_events 飞书回调原始事件和处理结果。 | 字段 | 说明 | | --- | --- | | `id` | 事件 ID | | `event_id` | 飞书事件 ID | | `event_type` | 事件类型 | | `operator_open_id` | 操作人 open_id | | `action_value` | 按钮值 | | `idempotency_key` | 事件处理幂等键,可选 | | `target_type` | `ai_draft`、`task`、`reminder`、`auth`、`bot` | | `target_id` | 关联业务对象 | | `notification_id` | 关联通知 | | `raw_payload` | 原始事件 | | `process_status` | `pending`、`processed`、`failed`、`ignored` | | `process_result` | 处理结果 | | `created_at` | 接收时间 | `event_id` 应尽量设置唯一约束;如果飞书某类回调没有稳定 `event_id`,则用 `operator_open_id + action_value + notification_id + target_id` 生成 `idempotency_key` 并唯一约束。重复事件只返回已处理结果,不重复创建草稿、事项、提醒、反馈或通知。 ## 18. 敏感字段规则 1. `phone`、`email` 可入库,但普通日志和普通列表接口默认脱敏。 2. API Key、App Secret、飞书 token、飞书回调验签密钥、OAuth code/state、一次性操作 token 明文不得入库到业务表或普通日志。 3. `raw_error`、`metadata`、`request_payload`、`response_payload` 必须避免密钥和完整个人联系方式。 4. 飞书通知内容只保存和发送摘要,不展开敏感全文。 5. `model_call_logs` 原始请求/响应和 `feishu_events.raw_payload` 仅供管理员 / AI 团队排查,普通员工不可见,老板和程经理只在必要业务范围内查看摘要。 6. 平台反馈页一次性操作 token 只能保存 hash,不能保存明文。