# Meeting Attendance Outlook Sync E2E 报告（2026-03-09）

## 测试范围

- 验证 `POST /meeting-attendance/integrations/outlook/sync/reconcile` 在真实本地环境下，能否把“仅有 seriesMaster、本地未来子快照为 0”的 Outlook 系列补齐到本地快照
- 验证补齐后候选页是否能显示该系列主会议
- 验证本次改动未影响 Outlook 同步页现有候选区、已纳管区的基本可用性

## 环境信息

| 字段 | 内容 |
|------|------|
| 执行时间 | 2026-03-08 20:47 PDT - 2026-03-08 20:59 PDT |
| 执行器 | AI Agent + Playwright MCP |
| 浏览器/设备 | Chromium / Desktop |
| 前端 | `http://localhost:3000` |
| 后端 | `http://localhost:3001/api/v1` |
| 鉴权策略 | 偏离 `storageState`，本次按用户允许使用“邮箱免密登录” |
| 登录账号 | `hongwei.zhang@ff.com`（MeetingManager） |
| storageState | 未使用 |
| 数据样本 | Outlook 系列：`测试子会议`（`hongwei.zhang@ff.com` 邮箱） |

## 执行命令

1. 目标单测
   ```bash
   cd backend && npx jest test/modules/meeting-attendance/unit/outlook-sync.service.spec.ts --runInBand --config '{"preset":"ts-jest/presets/default-esm","testEnvironment":"node","rootDir":".","moduleNameMapper":{"^@/(.*)$":"<rootDir>/src/$1","^@core/(.*)$":"<rootDir>/src/core/$1","^@engines/(.*)$":"<rootDir>/src/engines/$1","^@modules/(.*)$":"<rootDir>/src/modules/$1","^@common/(.*)$":"<rootDir>/src/common/$1"},"extensionsToTreatAsEsm":[".ts"],"transform":{"^.+\\.(t|j)s$":"ts-jest"}}'
   ```
2. 真实链路验证
   - `POST /auth/dev-email-login`
   - `GET /meeting-attendance/integrations/outlook/candidates`
   - `POST /meeting-attendance/integrations/outlook/sync/reconcile`
   - PostgreSQL 查询 `platform_meeting_attendance.outlook_event_snapshots`
3. 页面级 MCP 验证
   - 打开 `/login`
   - 使用 Dev Email Login 登录 `hongwei.zhang@ff.com`
   - 打开 `/meetingattendance/integrations/outlook`

## 用例明细

### E2E-01 对账后补齐候选系列子快照并显示在候选页

- 优先级：P0
- 前置条件：
  - `hongwei.zhang@ff.com` 邮箱内新建 Outlook 系列 `测试子会议`
  - 本地快照中该系列仅存在 `seriesMaster`，未来子快照为 `0`
- 使用的 API / 页面：
  - [053] `GET /integrations/outlook/candidates`
  - [058] `POST /integrations/outlook/sync/reconcile`
  - 页面 `/meetingattendance/integrations/outlook`
- 操作：
  1. 通过 SQL 查询确认 `测试子会议` 当前仅有 `seriesMaster=1`、`future_child_count=0`
  2. 通过服务层 Graph `instances` 拉取验证 Outlook 侧存在 `26` 个未来 `occurrence`
  3. 使用 `hongwei.zhang@ff.com` 的真实登录态触发 `Run Reconcile`
  4. 轮询数据库直到该系列未来子快照数量变化
  5. 刷新候选页并搜索 `测试子会议`
- 结果：通过
- 断言点：
  - 到达断言：Outlook 同步页标题、候选区标题可见
  - 稳定断言：候选区搜索 `测试子会议` 后出现 `测试子会议 (26)`
  - 数据断言：
    - 对账前：`master_count=1`、`child_count=0`、`future_child_count=0`
    - 对账后：`master_count=1`、`child_count=26`、`future_child_count=26`
    - 候选接口从 `beforeVisible=false` 变为 `afterVisible=true`
- 输出摘要：
  - 对账请求已接受：`accepted=true`
  - 约 21 轮轮询后补齐完成
- 资产：
  - 成功截图：[E2E-01-reconcile-candidate-success.png](/home/chentao/Code/ffworkspace/testing/reports/meeting-attendance-2026-03-09-e2e/E2E-01-reconcile-candidate-success.png)

### E2E-02 Outlook 同步页原有区域未回归

- 优先级：P1
- 前置条件：
  - `hongwei.zhang@ff.com` 可访问 Outlook 同步页
- 使用的 API / 页面：
  - [053] `GET /integrations/outlook/candidates`
  - [055] `GET /integrations/outlook/bindings`
  - 页面 `/meetingattendance/integrations/outlook`
- 操作：
  1. 登录后打开 Outlook 同步页
  2. 检查候选区、已纳管区是否正常加载
  3. 对账完成后再次检查已纳管区数据仍然存在
- 结果：通过
- 断言点：
  - 到达断言：候选区 `Candidate Meetings`、已纳管区 `Managed Meetings` 可见
  - 稳定断言：已纳管接口仍返回 `4` 条数据
  - 页面断言：已纳管列表仍显示原有系列行，未因本次补齐逻辑出现空白页或权限异常

## 契约一致性

- 与 [07-api.md](/home/chentao/Code/ffworkspace/docs/modules/meeting-attendance/07-api.md) 一致：
  - `POST /integrations/outlook/sync/reconcile` 仅返回 `accepted/mailboxId`
  - 对账后候选接口可见新系列，且 `seriesChildCount=26`
- 与 [05-ui-interaction-spec.md](/home/chentao/Code/ffworkspace/docs/modules/meeting-attendance/05-ui-interaction-spec.md) 一致：
  - Outlook 同步页可正常加载候选区、已纳管区
  - 立即对账后系列候选可补齐显示

## 覆盖度说明

- 覆盖页面：1 个
  - `/meetingattendance/integrations/outlook`
- 覆盖核心流程：2 条
  - 对账补齐缺失系列子快照
  - Outlook 同步页候选区 / 已纳管区基础回归
- 未覆盖：
  - 纳管 `测试子会议`
  - 接管、取消纳管、排除单次实例
  - 非当前邮箱 / 跨邮箱管理员视图

## 失败与阻断

- 无功能阻断
- 本次未使用 `storageState`，属于经用户允许的偏离；原因是本地存在可用的邮箱免密登录入口，验证速度更高

## 结论

- 这次改动在真实本地环境已验证生效：`测试子会议` 从“仅有 seriesMaster、未来子快照为 0、候选不可见”变为“未来子快照 26、候选可见”
- 页面层面未发现候选区和已纳管区的基础回归
- 结合已通过的后端单测，可以认为本次修复已形成闭环验证
