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。
code-copilot/changes/定时任务开放API/spec.mdcode-copilot/changes/定时任务开放API/tasks.mdcode-copilot/changes/定时任务开放API/test-spec.mdcode-copilot/changes/定时任务开放API/execution-log.mdforge-server/db/migration/V1.0.46__add_job_open_api_credentials.sqlentity/SysJobApiToken.javaentity/SysJobApiIdempotency.javamapper/SysJobApiTokenMapper.javamapper/SysJobApiIdempotencyMapper.javaresources/mapper/SysJobApiTokenMapper.xmlresources/mapper/SysJobApiIdempotencyMapper.xmltenant_id、del_flag 的表。token_key_id、token_prefix、token_hash,不存在明文字段。del_flag = 0,开放端方法显式忽略租户插件并携带可信 tenant_id。config/JobProperties.javaresources/application-job-example.ymlsupport/JobApiTokenCodec.javaservice/JobApiTokenService.javacontroller/JobApiTokenController.javadto/JobApiTokenCreateRequest.javamodel/JobApiPrincipal.javavo/JobApiTokenCreatedVO.javavo/JobApiTokenVO.javafja_ Token,使用 SecureRandom、URL-safe Base64、HMAC-SHA256 和恒定时间比较。last_used_at 使用目标字段更新且节流,禁止完整实体回写。@OperationLog(saveResponseResult = false),响应经 API 加密且明文只出现一次。constant/JobApiScopes.javaservice/JobApiAuthorizationService.javaSysJobConfigMapper and SysJobLogMappervo/JobOpenApiSummaryVO.javavo/JobOpenApiExecutionVO.javamanager/JobApiRateLimitManager.javamanager/JobApiIdempotencyManager.javaservice/JobApiExecutionService.javaconstant/JobExecutionStatus.javaservice/JobExecutionLifecycleService.javascheduler/JobScheduler.javascheduler/QuartzJobExecutor.javaIdempotency-Key 限制为 8-128 位安全字符,Redis/SQL 只使用 Hash。ACCEPTED 执行日志,Quartz 启动时原子推进同一行到 RUNNING,提交失败则安全落为失败。forge-starter-auth/.../SaTokenConfig.javacontroller/openapi/JobOpenApiController.javacontroller/openapi/JobExecutionOpenApiController.javacontroller/openapi/JobOpenApiExceptionHandler.javasupport/JobOpenApiException.java/openapi/v1/jobs/** 与 /openapi/v1/executions/**。RespInfo,未知异常统一脱敏。constant/JobPermissions.javaforge-admin-ui/src/api/system/job.jsforge-admin-ui/src/views/system/job-config/job-permission.jsforge-admin-ui/src/views/system/job-config.vueforge-admin-ui/src/views/system/job-api-token.vueV1.0.46__add_job_open_api_credentials.sqlv20.19.0 运行前端单测、ESLint 和生产构建。${...}、明文 Token、敏感字段响应、Mapper XML 和 git diff --check 静态检查。execution-log.md、tasks.md 和 spec.md;真实服务与数据库联调明确标记为用户侧待验收。forge-admin-ui/src/components/job/job-open-api-usage.jsforge-admin-ui/src/views/system/__tests__/job-api-token.test.jsforge-admin-ui/src/components/job/__tests__/job-open-api-usage.test.jsforge-admin-ui/src/components/job/JobOpenApiUsageGuide.vueforge-admin-ui/src/views/system/job-api-token.vuebuildJobOpenApiExamples({ 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:read、jobs:trigger、executions:read 三类示例;传入 Scope 时只返回允许的示例,未传 Scope 时返回完整使用说明。v20.19.0 运行目标 Vitest、目标 ESLint 和生产构建,结果追加到 execution-log.md。