# 会议出勤 Outlook 同步上线说明

## 1. 目标与范围
- 目标：将会议出勤从“手工建会”切换为“管理员从 Outlook 候选事件纳管，同步到会议出勤”。
- 范围：
  - Outlook 候选事件列表（按当前管理员邮箱）
  - 纳管 / 取消纳管
  - Webhook + Delta + 对账兜底同步
  - 系列会议（series master + occurrence/exception）

## 2. 上线前准备

### 2.1 Azure/Graph 权限
在 Azure Portal 的应用注册中确保已授予并完成管理员同意：
- `Calendars.Read`（Application）
- `Calendars.ReadWrite`（Application）
- `User.Read.All`（Application）

说明：如果只需读取可改为最小权限，但当前实现含订阅/同步维护，按以上权限执行更稳妥。

### 2.2 Exchange 访问范围（推荐）
- 推荐启用 Exchange App RBAC / 应用访问策略，将应用权限限制在业务邮箱范围。
- 若未限制，应用级权限可访问租户内更多邮箱，存在越权风险。

### 2.3 回调地址
- Webhook 回调地址必须可被 Microsoft Graph 访问。
- 路径使用系统固定路由（后端控制器），域名取系统基础配置。

## 3. 环境变量与配置

### 3.1 必需环境变量（后端）
- `AZURE_TENANT_ID`
- `AZURE_CLIENT_ID`
- `AZURE_CLIENT_SECRET`

### 3.2 可选环境变量
- `APP_PUBLIC_BASE_URL`（建议显式配置，保证回调地址与生成链接稳定）

### 3.3 后台可配（默认已内置）
在“Outlook 同步 > 同步设置”可配置：
- `Reconcile Cron`
- `Delta Batch Size`
- `Lookahead Days`
- `Lookback Days`
- `Renew Before (minutes)`
- `Include organizer as attendee`

## 4. 发布步骤

1. 拉取代码并安装依赖。
2. 执行数据库迁移：
   - `cd backend && npx prisma migrate deploy`
3. 构建：
   - `cd backend && npm run build`
   - `cd frontend && npm run build`
4. 重启服务（后端、前端、任务调度进程）。
5. 健康检查：
   - 登录系统
   - 打开 `Outlook 同步` 页面确认可加载候选与已纳管列表

## 5. 上线后后台操作（必须）

1. 使用会议管理员账号进入 `Outlook 同步` 页面。
2. 在候选会议中选择需要纳管的事件（系列只纳管主会议）。
3. 对历史手工系列会议执行人工收口（按既定方案）：
   - 在系统内将旧系列结束时间截断到当天前
   - 清理未来未发生实例
4. 点击 `触发对账` 一次，做首轮补齐。
5. 检查“已纳管会议”中最近同步时间是否更新。
6. 抽查会议详情：
   - 时间显示（会议时区 + 观察者时区）
   - 内部参会人 / Outlook 外部参会人是否正确

## 6. 运行期策略（默认）
- 实时：Webhook 触发后进入增量同步
- 兜底：短周期 delta 轮询
- 对账：定时 reconcile
- 取消纳管策略：仅停止后续同步，不删除历史会议

## 7. 常见问题

### 7.1 候选列表为空
- 确认当前登录管理员邮箱在 Outlook 有相关事件
- 确认 Azure 应用权限已管理员同意
- 触发一次对账后再刷新

### 7.2 系列会议不显示子实例
- 先展开系列主会议
- 若首次纳管后短时为空，等待后台 bootstrap 完成再刷新

### 7.3 已取消会议显示异常
- 默认不显示已取消；仅勾选“包含已取消”才显示

### 7.4 日志出现 `Failed to write logs to database, falling back to file`
- 检查日志库连通性、迁移是否执行、日志表权限

## 8. 回滚策略
- 代码回滚到上一稳定版本
- 数据库按变更窗口执行回滚计划（如仅可前滚则执行修复迁移）
- 暂停 Outlook 对账任务，避免持续写入
- 保留已同步历史会议数据，避免审计链断裂

## 9. 验收清单
- 候选列表可在 1s 级返回（命中快照）
- 系列主会议可纳管，子实例不可单独纳管
- 纳管/取消纳管均有明确 toast 反馈
- 对账可触发并有反馈
- 会议详情时间显示统一（会议时区 + 观察者时区）
- 会议详情内部/外部参会人展示正确

