# Oncall v2: devops-dev 部署方案 + 功能改造测试报告（草案）

日期: 2026-04-29
仓库: /Users/hu/aisupport

## 一、需求覆盖状态

1) Category UTC 时间窗（from_hour_utc / to_hour_utc）
- 状态: 已完成后端模型/API/前端表单改造（待你本地运行集成验证）
- 规则:
  - from <= to: 命中区间 [from, to]
  - from > to: 跨天区间，命中 hour >= from OR hour <= to
  - 默认 0~23（全天）

2) 本地部署可绕过权限、访问者具备全部权限
- 状态: 已完成（后端 bypass 模式增强）
- 说明: ShouldBypassAuth() 下 validate/me 将返回所有 category 的 Managed/Read

3) devops-dev 集群部署方案（不实际部署）
- 状态: 已完成清单与步骤，新增独立 overlay（见下文）

4) 全功能测试与报告（含 robin/engineer/holiday）
- 状态: 已补测试计划与命令；受本机 Go toolchain 冲突影响，未完成全量自动化执行
- 说明: 需要你本地修复 Go 版本后执行完整回归命令

---

## 二、代码改动清单

### 后端

1. Category 增加 UTC 时间窗字段
- 文件: services/oncall-v2/models/models.go
- 变更:
  - Category.FromHourUTC int `json:"from_hour_utc"` (default 0)
  - Category.ToHourUTC int `json:"to_hour_utc"` (default 23)

2. 新增时间窗校验与命中判断
- 文件: services/oncall-v2/service/scheduler.go
- 新增函数:
  - sanitizeCategoryHourRange(from,to)
  - isHourInCategoryWindow(hour,from,to)

3. 时间窗生效到读接口
- 文件: services/oncall-v2/service/scheduler.go
- 影响:
  - GetShiftView()：按当前 UTC 小时过滤 category
  - GetCurrentOverview()：按当前 UTC 小时过滤 category
  - Overview 输出新增 from_hour_utc / to_hour_utc

4. Category CRUD 支持时间窗
- 文件: services/oncall-v2/service/scheduler.go
  - AddCategory(...) 增加 fromHourUTC/toHourUTC 参数并校验
- 文件: services/oncall-v2/service/category_detail.go
  - 新增 UpdateCategoryRequest
  - 新增 UpdateCategory(categoryID, req) 支持 name/group/period/manager_emails/from/to 更新

5. Category 详情返回时间窗
- 文件: services/oncall-v2/service/category_detail.go
- 返回新增:
  - timezone_window: { from_hour_utc, to_hour_utc, description }

6. category schedule window 返回时间窗
- 文件: services/oncall-v2/service/category_schedule_window.go
- 返回新增:
  - timezone_window

7. API 路由新增/更新
- 文件: services/oncall-v2/api/router.go
- 变更:
  - POST /api1/category/add 支持 from_hour_utc / to_hour_utc
  - 新增 POST /api1/category/update

8. 本地 bypass 权限增强
- 文件: services/oncall-v2/service/auth.go
- 变更:
  - getUserCategoryAccess() 在 ShouldBypassAuth() 下返回所有未禁用 category 的 managed/read

9. API 文档更新
- 文件: services/oncall-v2/swagger.yaml
- 变更:
  - /api1/category/add 增加 from_hour_utc/to_hour_utc 字段
  - 新增 /api1/category/update

### 前端

1. 新建 category 时支持填写 UTC 时间窗
- 文件: apps/oncall-v2-web/src/pages/ShiftView.js
- 变更:
  - 创建弹窗增加 from_hour_utc / to_hour_utc
  - 调用 postApi1CategoryAdd 时透传 from/to

2. category 详情展示与编辑时间窗
- 文件: apps/oncall-v2-web/src/pages/CategoryDetail.js
- 变更:
  - Overview 展示 UTC Window
  - 新增 Category Base Config 表单（name/group/period/manager_emails/from/to）
  - 新增 handleUpdateCategoryConfig 调用 /api1/category/update

3. 前端 SDK 方法补充
- 文件: apps/oncall-v2-web/src/api/services/DefaultService.ts
- 变更:
  - postApi1CategoryAdd 增加 from_hour_utc/to_hour_utc 类型
  - 新增 postApi1CategoryUpdate()

---

## 三、devops-dev 部署方案（*.pingcap.net）

目标建议域名:
- https://oncall.devops.pingcap.net/oncall/shiftview
- API: https://oncall.devops.pingcap.net/api1/...

原因:
- 子域隔离清晰，避免与现有 dev.devops.pingcap.com 路由冲突
- 仍然符合你“*.pingcap.net 可解析”的条件

### 新增 overlay 文件

- infra/kustomize/envs/devops-dev/oncall-v2/kustomization.yaml
- infra/kustomize/envs/devops-dev/oncall-v2/namespace.yml
- infra/kustomize/envs/devops-dev/oncall-v2/configmap.yml
- infra/kustomize/envs/devops-dev/oncall-v2/patch-deployment.yml
- infra/kustomize/envs/devops-dev/oncall-v2/ingress.yml
- infra/kustomize/envs/devops-dev/oncall-v2/oncall-v2-external-secret.yml

关键配置:
- namespace: devops-dev
- ingress host: oncall.devops.pingcap.net
- path:
  - /api1 -> oncall-v2
  - /oncall -> oncall-v2-web
- APP_ENV=dev, AUTHING_ENABLED=false, DEV_BYPASS_AUTH=true
- DB 使用 ONCALL_DB_DSN（来自 ExternalSecret: devops-dev/oncall-v2）

注意:
- 前端 nginx 已改为 proxy_pass http://oncall-v2:80;（去掉硬编码命名空间）

---

## 四、建议部署步骤（不执行版）

1) 登录并切上下文
- aws sso login --profile clinic-dev
- aws eks update-kubeconfig --name devops-staging --profile clinic-dev
- kubectl config current-context

2) 准备密钥（ExternalSecret 对应远端）
- 远端 key: devops-dev/oncall-v2
- 需要至少:
  - ONCALL_DB_DSN
  - FEISHU_APP_ID（可选）
  - FEISHU_APP_SECRET（可选）

3) 构建镜像并推 ECR
- oncall-v2 backend image
- oncall-v2-web frontend image
- 更新 overlay 的 image tag（或用 kustomize edit set image）

4) 渲染检查
- kubectl kustomize infra/kustomize/envs/devops-dev/oncall-v2 > /tmp/oncall-devops-dev.yaml
- 检查 host/path/namespace/secret 引用

5) 应用
- kubectl apply -k infra/kustomize/envs/devops-dev/oncall-v2

6) 验证
- kubectl get deploy,svc,ing -n devops-dev | grep oncall-v2
- kubectl rollout status deploy/oncall-v2 -n devops-dev
- kubectl rollout status deploy/oncall-v2-web -n devops-dev
- curl -I https://oncall.devops.pingcap.net/oncall/shiftview
- curl -I https://oncall.devops.pingcap.net/api1/validate

---

## 五、测试计划与结果（当前）

### 已执行
1. kustomize 渲染检查
- 命令:
  - kubectl kustomize infra/kustomize/envs/devops-dev/oncall-v2
- 结果:
  - 通过
  - 包含 host oncall.devops.pingcap.net
  - 包含 /oncall 与 /api1 路由
  - 命名空间为 devops-dev

### 受环境阻塞（未执行完）
受 Go toolchain 冲突影响（go1.23.4 vs go1.25.0），后端 go test 无法完整跑通。

### 建议你本地执行的完整回归

A. 后端单测
- cd services/oncall-v2
- go test ./... -count=1

B. 新增接口回归（建议用 curl/postman）
1) category CRUD + 时间窗
- POST /api1/category/add
- POST /api1/category/update
- GET /api1/schedule/overview 验证 from/to 出现
- GET /api1/schedule/shiftview 验证时间窗过滤

2) robin 相关
- GET/POST /api1/category/robin
- POST /api1/schedule/updateRotationByEmail
- POST /api1/category/generate

3) engineer 相关
- POST /api1/category/engineer/add
- POST /api1/category/engineer/remove
- 验证未来排班重建是否符合预期

4) 手动改班
- POST /api1/schedule/change
- POST /api1/schedule/addshift
- POST /api1/schedule/removeshift

5) 节假日/序列
- POST /api1/calendar/split-special
- POST /api1/calendar/merge-sequence
- POST /api1/calendar/align-weekly

C. 前端构建
- cd apps/oncall-v2-web
- npm run build

D. 联调冒烟
- 访问 /oncall/shiftview
- 创建 category（含 from/to）
- 进入 category 详情页修改配置
- 验证不同 UTC 时段下 overview/shiftview 可见性

---

## 六、已知风险与建议

1) Go 环境冲突
- 先统一本机 go 版本，再跑完整自动化

2) swagger 与 SDK当前是手工 patch
- 建议后续把 swagger 作为单一源并自动 regenerate 前端 SDK

3) 时间窗过滤目前作用于“展示层”接口
- 若后续要求“生成层”也受限，需要额外定义策略（例如窗口外是否跳过生成）

---

## 七、最终访问地址（按本方案）

- 前端: https://oncall.devops.pingcap.net/oncall/shiftview
- API: https://oncall.devops.pingcap.net/api1/...

