tasks.md 8.5 KB

定时任务开放 API Implementation Plan

For agentic workers: 按本文件复用当前会话内联执行,逐项使用复选框追踪;禁止回退 V1-V6 工作区改动。

status: complete scope: V8 incremental

Goal: 为受信任外部系统提供独立的定时任务查询、幂等触发和执行状态接口,并提供只显示一次明文的服务账号 Token 管理能力。

Architecture: 管理端使用 Sa-Token 和 Forge 权限体系维护只存 HMAC Hash 的 Token;开放端使用专用 Bearer 认证、Scope 与任务资源交集授权。触发请求先在 Redis 锁内预留执行日志和幂等记录,再把执行 ID 传给 Quartz,Quartz 复用同一日志完成现有执行生命周期。

Tech Stack: Java 17、Spring Boot 3、MyBatis-Plus/Mapper XML、Quartz、Redisson、Sa-Token、Vue 3、Naive UI、Vitest、Flyway。


Task 1: Spec 与测试基线

  • 涉及文件:
    • Modify: code-copilot/changes/定时任务开放API/spec.md
    • Modify: code-copilot/changes/定时任务开放API/tasks.md
    • Create: code-copilot/changes/定时任务开放API/test-spec.md
    • Create: code-copilot/changes/定时任务开放API/execution-log.md
  • 固化服务账号、任务 ID/任务组资源范围和 Redis 失败关闭三个门禁。
  • 明确预留执行 ID、专用认证、真实 HTTP 状态和敏感字段边界。
  • 建立 P0/P1 增量验证矩阵和执行记录模板。

Task 2: Token 和幂等数据模型

  • 涉及文件:
    • Create: forge-server/db/migration/V1.0.46__add_job_open_api_credentials.sql
    • Create: entity/SysJobApiToken.java
    • Create: entity/SysJobApiIdempotency.java
    • Create: mapper/SysJobApiTokenMapper.java
    • Create: mapper/SysJobApiIdempotencyMapper.java
    • Create: resources/mapper/SysJobApiTokenMapper.xml
    • Create: resources/mapper/SysJobApiIdempotencyMapper.xml
  • 创建两个含标准审计字段、tenant_iddel_flag 的表。
  • Token 表只包含 token_key_idtoken_prefixtoken_hash,不存在明文字段。
  • 幂等表只保存幂等键 SHA-256 Hash,并用生成列保证逻辑删除后的唯一键语义。
  • Mapper XML 显式过滤 del_flag = 0,开放端方法显式忽略租户插件并携带可信 tenant_id

Task 3: Token 安全服务和管理接口

  • 涉及文件:
    • Modify: config/JobProperties.java
    • Modify: resources/application-job-example.yml
    • Create: support/JobApiTokenCodec.java
    • Create: service/JobApiTokenService.java
    • Create: controller/JobApiTokenController.java
    • Create: dto/JobApiTokenCreateRequest.java
    • Create: model/JobApiPrincipal.java
    • Create: vo/JobApiTokenCreatedVO.java
    • Create: vo/JobApiTokenVO.java
  • 生成 fja_ Token,使用 SecureRandom、URL-safe Base64、HMAC-SHA256 和恒定时间比较。
  • 创建、分页、吊销和轮换均使用租户条件和 CAS 更新;轮换在同一事务插入新 Token 并吊销旧 Token。
  • last_used_at 使用目标字段更新且节流,禁止完整实体回写。
  • 创建与轮换使用 @OperationLog(saveResponseResult = false),响应经 API 加密且明文只出现一次。
  • 单元测试覆盖 Token 格式、错误 Pepper、过期、吊销、Hash 不匹配、轮换回滚和泄露契约。

Task 4: Scope、资源授权和开放查询

  • 涉及文件:
    • Create: constant/JobApiScopes.java
    • Create: service/JobApiAuthorizationService.java
    • Add Mapper XML methods in SysJobConfigMapper and SysJobLogMapper
    • Create: vo/JobOpenApiSummaryVO.java
    • Create: vo/JobOpenApiExecutionVO.java
  • 只允许三个白名单 Scope,Token 至少选择一个任务 ID 或任务组。
  • JSON 资源数组通过 Jackson 解析,任务授权取 ID/任务组并集。
  • 列表、详情和执行查询 SQL 只投影安全摘要字段,不包含执行目标、参数、结果或异常正文。
  • 越权资源返回 403;不存在资源返回 404;客户端不能提交身份或执行目标字段。

Task 5: 限流、幂等和预留执行生命周期

  • 涉及文件:
    • Create: manager/JobApiRateLimitManager.java
    • Create: manager/JobApiIdempotencyManager.java
    • Create: service/JobApiExecutionService.java
    • Modify: constant/JobExecutionStatus.java
    • Modify: service/JobExecutionLifecycleService.java
    • Modify: scheduler/JobScheduler.java
    • Modify: scheduler/QuartzJobExecutor.java
  • Redisson 限流以 Token Key ID 为维度;超限返回 429,Redis 不可用返回 503。
  • Idempotency-Key 限制为 8-128 位安全字符,Redis/SQL 只使用 Hash。
  • 同 Token、任务和幂等键在锁内复用 24 小时有效记录;过期记录先逻辑删除再创建。
  • 预留 ACCEPTED 执行日志,Quartz 启动时原子推进同一行到 RUNNING,提交失败则安全落为失败。
  • 并发测试覆盖重复请求同一执行 ID、锁竞争、唯一键竞争和 Redis 故障零执行。

Task 6: Open API Controller 和独立错误边界

  • 涉及文件:
    • Modify: forge-starter-auth/.../SaTokenConfig.java
    • Create: controller/openapi/JobOpenApiController.java
    • Create: controller/openapi/JobExecutionOpenApiController.java
    • Create: controller/openapi/JobOpenApiExceptionHandler.java
    • Create: support/JobOpenApiException.java
  • 通用登录和 API 权限拦截器只排除 /openapi/v1/jobs/**/openapi/v1/executions/**
  • 每个开放接口先认证 Bearer Token,再执行 Scope、限流和资源授权。
  • 错误处理返回真实 HTTP 400/401/403/404/409/429/503 和 RespInfo,未知异常统一脱敏。
  • 安全日志只记录 Key ID、任务 ID、执行 ID、结果码和耗时。

Task 7: 权限资源和 Token 管理工作台

  • 涉及文件:
    • Modify: constant/JobPermissions.java
    • Modify: forge-admin-ui/src/api/system/job.js
    • Modify: forge-admin-ui/src/views/system/job-config/job-permission.js
    • Modify: forge-admin-ui/src/views/system/job-config.vue
    • Create: forge-admin-ui/src/views/system/job-api-token.vue
    • Modify: V1.0.46__add_job_open_api_credentials.sql
  • 增加 Token 查询、创建、吊销、轮换按钮权限及管理 API 资源,不自动扩大普通角色权限。
  • 增加隐藏管理路由,并从任务工作台按权限进入。
  • 工作台支持分页、筛选、创建、吊销、轮换和一次性 Token 弹窗。
  • Scope 使用字典,任务 ID/任务组来自后端资源选项,状态不在前端硬编码。

Task 8: 增量验证与回填

  • 运行 Job 插件单测并记录通过数量。
  • 运行 Admin Reactor 聚合测试/构建,验证 Starter Auth 装配。
  • 使用 Node v20.19.0 运行前端单测、ESLint 和生产构建。
  • 运行 Flyway ${...}、明文 Token、敏感字段响应、Mapper XML 和 git diff --check 静态检查。
  • 回填 execution-log.mdtasks.mdspec.md;真实服务与数据库联调明确标记为用户侧待验收。

Task 9: 开放 API 调用说明与可复制示例

  • 涉及文件:
    • Create: forge-admin-ui/src/components/job/job-open-api-usage.js
    • Test: forge-admin-ui/src/views/system/__tests__/job-api-token.test.js
    • Test: forge-admin-ui/src/components/job/__tests__/job-open-api-usage.test.js
    • Create: forge-admin-ui/src/components/job/JobOpenApiUsageGuide.vue
    • Modify: forge-admin-ui/src/views/system/job-api-token.vue
  • 新增失败测试,调用 buildJobOpenApiExamples({ token, scopes }) 后断言:
expect(examples.map(item => item.key)).toEqual(['list-jobs', 'trigger-job'])
expect(examples[1].command).toContain('Idempotency-Key')
expect(examples[1].command).toContain('Authorization: Bearer fja_test_token')
  • 执行 pnpm exec vitest run src/views/system/__tests__/job-api-token.test.js,确认新增测试先因导出不存在而失败。
  • 在纯函数中生成 jobs:readjobs:triggerexecutions:read 三类示例;传入 Scope 时只返回允许的示例,未传 Scope 时返回完整使用说明。
  • 新建调用说明组件,提供可编辑 Admin 服务地址、接口方法/路径、Scope 提示、cURL 复制和 401/403/429/503 说明。
  • 组件测试验证 Scope 裁剪、真实 Token 带入,以及修改服务地址后 cURL 实时更新。
  • 工作台增加常驻“调用说明”按钮;创建和轮换成功时把当前 Scope 传入一次性 Token 弹窗并展示真实 Token 示例。
  • 使用 Node v20.19.0 运行目标 Vitest、目标 ESLint 和生产构建,结果追加到 execution-log.md