# ADP PTO 同步 - API 契约

## 接口数量汇总

| 域 | 数量 | 说明 |
|---|---|---|
| ADP 同步管理 | 3 | 手动触发 linker / pto sync；查询同步状态 |
| Meeting PTO 标记 | 1 | 手动应用 PTO 到会议签到 |
| Admin PTO 数据查看 | 1 | 列表查询（管理员校验工具） |

**总计**：5 个接口

---

## 域 1：ADP 同步管理（admin only）

### 1.1 手动触发 ADP Linker

```
POST /api/v1/adp-sync/linker/trigger
权限: meeting_attendance:manage（会议管理员/IT admin）
```

**Request**: 无 body

**Response 200**:
```json
{
  "executionId": "uuid",
  "status": "RUNNING",
  "triggeredAt": "2026-04-25T10:00:00.000Z"
}
```

**Errors**:
- 403 `INSUFFICIENT_PERMISSIONS` - 非管理员
- 409 `TASK_ALREADY_RUNNING` - 任务正在执行中

### 1.2 手动触发 ADP PTO Sync

```
POST /api/v1/adp-sync/pto/trigger
权限: meeting_attendance:manage
```

**Request** (可选 body):
```json
{
  "windowStartDays": -7,
  "windowEndDays": 35
}
```

**Response 200**: 同 1.1

**约束**: `windowStartDays - windowEndDays` 不得超过 42（ADP 6 周窗口限制）

### 1.3 查询同步任务状态

```
GET /api/v1/adp-sync/status
权限: meeting_attendance:manage
```

**Response 200**:
```json
{
  "tasks": [
    {
      "code": "ADP_LINKER",
      "lastRunAt": "...",
      "lastStatus": "SUCCESS",
      "totalRuns": 30,
      "successRuns": 28,
      "failedRuns": 2,
      "lastExecution": {
        "id": "...",
        "status": "SUCCESS",
        "duration": 12500,
        "result": { "recordsFetched": 175, "recordsUpserted": 170, "recordsUnmatched": 5 },
        "logs": "..."
      }
    },
    { "code": "ADP_PTO_SYNC", "..." }
  ]
}
```

---

## 域 2：Meeting PTO 标记（会议管理员）

### 2.1 手动对会议应用 PTO 标记

```
POST /api/v1/meetings/:meetingId/apply-pto
权限: isMeetingAdminRole = true（Administrator / MeetingManager）
```

**作用**：扫描该会议的必参会人，凡 ADP PTO 时段与会议时段重叠的，将其 `MeetingAttendance.status` 设为 `PTO`，并写一条 `MeetingAttendanceAuditLog`。

**Request**: 无 body

**Response 200**:
```json
{
  "meetingId": "...",
  "marked": 3,
  "details": [
    { "userId": "u1", "previousStatus": "NOT_CHECKED_IN", "scheduleId": "s1" }
  ]
}
```

**Errors**:
- 403 `INSUFFICIENT_PERMISSIONS` - 非会议管理员
- 404 `MEETING_NOT_FOUND`

### 2.2 自动触发（非 HTTP 接口）

`MeetingService.create` / `MeetingService.update` 内部钩子，会议保存后异步调用 `applyPtoMarking`，actor 为 `'system'`。失败仅记日志，不影响会议保存。

---

## 域 3：Admin PTO 数据查看（会议管理员）

### 3.1 列表查询

```
GET /api/v1/adp-sync/admin/pto-schedules
权限: isMeetingAdminRole = true
```

**Query parameters**:

| 参数 | 类型 | 默认 | 约束 |
|---|---|---|---|
| `startDate` | ISO Date | 本月 1 日 | 不得早于 today - 30d |
| `endDate` | ISO Date | 下月末 | 不得晚于 today + 60d |
| `userId` | UUID | - | 可选 |
| `departmentId` | UUID | - | 可选 |
| `q` | string | - | 按姓名/邮箱模糊搜索 |
| `page` | int | 1 | |
| `pageSize` | int | 50 | 最大 200 |

**Response 200**:
```json
{
  "items": [
    {
      "id": "...",
      "user": { "id": "...", "displayName": "Ali Allie", "email": "..." },
      "leaveDate": "2026-04-01",
      "startTime": "2026-04-01T09:00:00-08:00",
      "endTime": "2026-04-01T13:00:00-08:00",
      "syncedAt": "2026-04-25T02:30:00.000Z"
    }
  ],
  "total": 12,
  "page": 1,
  "pageSize": 50
}
```

**adpAoid / adpEntryId 字段不在默认列表中返回**（隐私收口）。需要 debug 时另调单条 `GET /pto-schedules/:id` 接口（暂未实现）。

**约束（按 D4）**:
- ❌ 不提供 CSV 导出
- ❌ 不提供日历视图数据接口
- ❌ 不开放给普通员工 / 经理

**审计**: 每次访问写一条 `MeetingAttendanceDataAccessLog`，`accessType=READ_ATTENDANCES`，`hasSensitiveData=true`。

**Errors**:
- 403 `INSUFFICIENT_PERMISSIONS`
- 400 `INVALID_DATE_RANGE` - 超出允许窗口
