# 会议出勤（Meeting Attendance）- 错误码文档

> **版本**: v1.2
> **最后更新**: 2026-04-21
> **维护者**: 待定

---

## ✅ 机器读取区（必填）

### 错误码清单（最小）

| 错误码 | HTTP | 说明 | 处理建议 |
|--------|------|------|----------|
| MEETING_ATTENDANCE_001 | 401 | 未登录或会话失效 | 重新登录 |
| MEETING_ATTENDANCE_002 | 403 | 权限不足 | 联系管理员授权 |
| MEETING_ATTENDANCE_003 | 404 | 会议不存在 | 检查会议 ID |
| MEETING_ATTENDANCE_004 | 404 | 系列会议不存在 | 检查系列 ID |
| MEETING_ATTENDANCE_005 | 404 | 用户不存在 | 检查用户 ID |
| MEETING_ATTENDANCE_006 | 400 | 参数校验失败 | 修正参数后重试 |
| MEETING_ATTENDANCE_007 | 400 | 签到过早 | 等待开放时间 |
| MEETING_ATTENDANCE_008 | 400 | 会议已结束/已取消 | 无法签到 |
| MEETING_ATTENDANCE_009 | 400 | 设备已被使用 | 换设备或联系管理员 |
| MEETING_ATTENDANCE_010 | 400 | 重复签到 | 查看已签到状态 |
| MEETING_ATTENDANCE_011 | 403 | 不在参会名单 | 联系会议组织者 |
| MEETING_ATTENDANCE_012 | 409 | 邮箱已存在 | 更换邮箱 |
| MEETING_ATTENDANCE_013 | 500 | 服务器错误 | 稍后重试 |
| MEETING_ATTENDANCE_014 | 404 | 模板不存在 | 检查模板 ID |
| MEETING_ATTENDANCE_016 | 400 | Graph 订阅验证失败 | 检查回调地址与 clientState |
| MEETING_ATTENDANCE_017 | 409 | 候选会议已纳管 | 请直接查看纳管详情 |
| MEETING_ATTENDANCE_019 | 502 | Graph API 调用失败 | 重试或查看外部服务状态 |
| MEETING_ATTENDANCE_020 | 500 | Delta 游标失效 | 触发全量重建游标后重试 |
| MEETING_ATTENDANCE_021 | 400 | 非系列绑定不支持排除实例 | 仅在 seriesMaster 纳管下操作 |
| MEETING_ATTENDANCE_022 | 400 | 待排除实例不属于当前系列 | 校验 seriesMaster 与 occurrence 归属关系 |
| MEETING_ATTENDANCE_023 | 404 | 排除记录不存在 | 刷新列表后重试 |
| MEETING_ATTENDANCE_024 | 409 | 会议已被其他管理员绑定 | 显示绑定人并提示“接管绑定” |
| MEETING_ATTENDANCE_025 | 400 | 接管邮箱不可见该 Outlook 事件 | 切换可见邮箱后再接管 |
| MEETING_ATTENDANCE_026 | 404 | Outlook 官方源版本不存在 | 刷新同步历史或检查 versionId |
| MEETING_ATTENDANCE_027 | 404 | Outlook 官方源差异记录不存在 | 该版本可能为首个版本或尚未生成差异 |
| MEETING_ATTENDANCE_028 | 410 | Outlook 官方源原始 payload 已过保留期清理 | 使用结构化摘要继续排查，必要时重新触发同步采样 |
| MEETING_ATTENDANCE_029 | 400 | 官方源版本查询参数非法 | 修正时间范围、分页或筛选条件 |
| MEETING_ATTENDANCE_030 | 409 | 参会人已有真实出勤记录，禁止删除 | 在会议详情页提示该用户已签到或已被人工调整 |
| MEETING_ATTENDANCE_031 | 404 | 会议参会人不存在 | 刷新名单后重试 |
| MEETING_ATTENDANCE_032 | 409 | 会议已转为本地维护，不再接受 Outlook 覆盖 | 在详情页展示“已停止自动同步”提示 |
| MEETING_ATTENDANCE_033 | 400 | 扫码类型与允许签到方式不匹配 | 提示"请使用线下/线上专属二维码" |
| MEETING_ATTENDANCE_034 | 403 | 签到方式校验已开启但该用户未配置工作地 | 提示"请联系管理员配置您的工作地" |
| MEETING_ATTENDANCE_036 | 400 | 签到方式校验开启但会议未配置地点 | 后端 guard 在切换开关时会提前拦截，不应常态出现；若触发提示"会议未配置地点" |
| AGENDA_SECTION_NOT_FOUND | 404 | 议程段不存在 | sectionId 无效；提示用户刷新议程后重试（v1.0） |
| AGENDA_ITEM_NOT_FOUND | 404 | 议程项不存在 | itemId 无效；同上（v1.0） |
| AGENDA_FORBIDDEN_NOT_MANAGER_OR_CREATOR | 403 | 仅 MeetingManager / 会议创建人可修改议程 | 普通用户尝试 PATCH/POST/DELETE 议程；前端按权限点隐藏入口（v1.0） |
| UPLOAD_TASK_NOT_FOUND | 404 | 上传任务不存在 | taskId 无效；刷新"我的待办"重试（v1.0） |
| UPLOAD_TASK_NOT_OWNED | 403 | 该上传任务不属于当前用户 | 非 assignee 尝试用 `assigned` 路径上传；提示"该议程项未指派给您"（v1.0） |
| UPLOAD_TASK_ALREADY_UPLOADED | 409 | 该任务已上传 | 重复 POST 上传 / manager 对已完成任务再撤销；前端按状态隐藏入口（v1.0） |
| ATTACHMENT_NOT_FOUND | 404 | 附件不存在 | attachmentId 无效；刷新资料列表（v1.0） |
| ATTACHMENT_TOO_LARGE | 413 | 单文件不能超过 200MB | size > 200 * 1024 * 1024；提示用户压缩或分拆文件（v1.0） |
| ATTACHMENT_MIME_NOT_ALLOWED | 415 | 不支持的文件类型 | Content-Type 不在 8 项白名单（pdf/docx/pptx/xlsx/jpeg/png/mp4/mov）；提示用户转换格式（v1.0） |
| ATTACHMENT_MIME_MISMATCH | 415 | 文件内容与扩展名不一致 | magic bytes 推断的 MIME 与 Content-Type 不一致（防 `.exe` 改扩展名伪装 `.pdf`）；提示用户「文件可能被篡改」（v1.0） |
| ATTACHMENT_DELETE_FORBIDDEN | 403 | 仅上传者本人或管理员可删除 | 别人尝试删别人的资料；前端按权限点隐藏入口（v1.0） |

---

## 🧭 人类阅读区（可选）

### 分类说明

- 权限错误: 001, 002, 034, AGENDA_FORBIDDEN_NOT_MANAGER_OR_CREATOR, UPLOAD_TASK_NOT_OWNED, ATTACHMENT_DELETE_FORBIDDEN
- 资源错误: 003, 004, 005, AGENDA_SECTION_NOT_FOUND, AGENDA_ITEM_NOT_FOUND, UPLOAD_TASK_NOT_FOUND, ATTACHMENT_NOT_FOUND
- 校验错误: 006, 007, 008, 009, 010, 011, 033, 036
- 冲突错误: 012, 015, 017, 024, 030, 032, UPLOAD_TASK_ALREADY_UPLOADED
- 集成错误: 016, 018, 019, 020, 026, 027, 028, 029
- 服务器错误: 013
- 文件上传错误（v1.0）: ATTACHMENT_TOO_LARGE (413), ATTACHMENT_MIME_NOT_ALLOWED (415), ATTACHMENT_MIME_MISMATCH (415)

### 示例响应

```json
{
  "code": "MEETING_ATTENDANCE_003",
  "message": "Meeting not found",
  "details": {}
}
```

### 边界错误处理（非模块错误码，框架/DB 层兜底）

本模块所有 controller 共用 `handleMeetingAttendanceError` helper（`errors/handle-controller-error.ts`）。除模块自定义 `MeetingAttendanceError` 外，helper 对 Prisma 框架错误统一兜底：

| Prisma 错误码 | HTTP | 响应 body | 触发场景 |
|---|---|---|---|
| `P2023` | 400 | `{ error: "Invalid id format" }` | 路径 `:id` 不是合法 UUID（PostgreSQL `uuid` 列拒绝） |
| `P2025` | 404 | `{ error: "Record not found" }` | `update` / `delete` / `findFirstOrThrow` 找不到记录 |

**与模块错误码区别**：模块错误码（MEETING_ATTENDANCE_*）走 `MeetingAttendanceError` 抛出路径，response body 包含 `code` 字段；上述边界错误是 helper 直接捕获的 framework 错误，response body 只有 `error` 字段、无 `code`（客户端可通过 HTTP 状态码 + body shape 区分）。

**为什么不立独立 MEETING_ATTENDANCE_038 之类**：P2023/P2025 是泛用边界，跟具体业务无关；放进模块错误码体系会污染领域语义。客户端处理建议：`400 Invalid id format` 跟 `404` 直接当 framework-level error 处理，不需要解码 code 字段。

详细背景：[issue #463](http://43.130.59.228/FFAIWorkspace/workspace/issues/463)。
