wangdl
c91a290536
feat: M-AI-03 Job 查询/取消/Admin/可观测性
...
Deploy API Server / build-and-unit (push) Failing after 28s
Deploy API Server / current-integration (push) Has been skipped
Deploy API Server / backward-compat (push) Has been skipped
Deploy API Server / deploy (push) Has been skipped
- AiJobController: GET /api/ai/jobs/:jobId, POST /cancel(JWT 用户隔离)
- 公开响应不含 validatedOutput/internalErrorMessage/Snapshot/Credential
- 终态取消幂等返回
- AiJobAdminController: Admin 列表/详情/重试/队列状态/Outbox 状态
- 重试:创建新 Job + parentJobId + 复制 Snapshot + OutboxEvent
- AiJobService: 用户/Admin 共享业务逻辑
- WorkerHeartbeat: activeJobCount 改为真实活跃数(ai-interactive + ai-background)
Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-21 10:08:57 +08:00
wangdl
e89c0fbd6b
fix: B1 — 无 Projector 路径调用 markSucceeded 防止 Job 卡在 running
...
Deploy API Server / build-and-unit (push) Failing after 28s
Deploy API Server / current-integration (push) Has been skipped
Deploy API Server / backward-compat (push) Has been skipped
Deploy API Server / deploy (push) Has been skipped
projectorKey 为 undefined 或 Projector 未注册时,
ProjectionExecutor 调用 markSucceeded 后再返回空 Artifact 列表。
避免 Engine 的 AI 调用成功后 Job 永远停留在 running 状态。
Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-21 09:51:10 +08:00
wangdl
4cfcb7afe5
feat: M-AI-03 Result Projector 与 Artifact 原子提交框架
...
Deploy API Server / build-and-unit (push) Failing after 29s
Deploy API Server / current-integration (push) Has been skipped
Deploy API Server / backward-compat (push) Has been skipped
Deploy API Server / deploy (push) Has been skipped
- result-projector.interface.ts: ResultProjector 接口冻结(ADR-003 §6.1)
project(tx, context) → ArtifactReference[]
- synthetic-result-projector.ts: 测试用 Synthetic Projector
幂等:已有 Artifact 时直接返回
- projection-executor.service.ts: ProjectionExecutor
事务内:projector.project(tx) + markSucceeded(tx) 原子提交
幂等检查:Job 已终态 → 跳过
NestJS multi-provider 注入 RESULT_PROJECTORS
- ai-job-execution-engine.ts: PROJECT 阶段改为调用 ProjectionExecutor
- ai-job.module.ts: 注册 ProjectionExecutor + SyntheticResultProjector
Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-21 09:49:25 +08:00
wangdl
aa1ce45d80
fix: N1-N3 — crypto 顶层导入 + 移除冗余 AbortController + _def 重命名
...
Deploy API Server / build-and-unit (push) Failing after 27s
Deploy API Server / current-integration (push) Has been skipped
Deploy API Server / backward-compat (push) Has been skipped
Deploy API Server / deploy (push) Has been skipped
- N1: require('crypto') 内联 → import * as crypto 顶层导入
- N2: 移除 Engine 内未连接的 AbortController(timeout 委托给 AiGatewayService)
- N3: writeUsageLog 的 _def 参数 → definition
Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-20 18:44:32 +08:00
wangdl
cdcf056ba5
fix: B1 — lockJob 原子递增 attemptCount + Engine 重试解锁逻辑
...
Deploy API Server / build-and-unit (push) Failing after 28s
Deploy API Server / current-integration (push) Has been skipped
Deploy API Server / backward-compat (push) Has been skipped
Deploy API Server / deploy (push) Has been skipped
- lockJob updateMany 新增 attemptCount: { increment: 1 }
- Engine retryable 错误: unlockForRetry() 重置为 queued 后再抛给 BullMQ
- Engine permanent 错误: 直接 markFailed + return(不抛错,BullMQ 不重试)
- unlockForRetry: 重置 lifecycleStatus→queued + 清除 lockedBy/lockedAt/lockUntil
- 更新测试: lockJob 验证 attemptCount 递增; schema validation 验证不抛错
Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-20 18:42:19 +08:00
wangdl
d82ae8ba71
feat: M-AI-03 统一 AiJob Worker Execution Engine
...
Deploy API Server / build-and-unit (push) Failing after 29s
Deploy API Server / current-integration (push) Has been skipped
Deploy API Server / backward-compat (push) Has been skipped
Deploy API Server / deploy (push) Has been skipped
- AiJobExecutionEngineImpl: 完整 5 阶段管线
PREPARE: read Job → terminal check → cancel check → Registry.get → CAS lockJob
RESOLVE: load Snapshot → schemaVersion check → AbortController timeout
EXECUTE: AiGatewayService.generate() (不直接导入 Provider SDK)
PROJECT: write validatedOutput + outputHash (#292 替换为 Projector)
COMPLETE: usageLog → markSucceeded
- 错误分类: classifyError() — 7 种错误码, retryable/permanent 分流
provider_rate_limited/timeout/unavailable → retryable → 抛给 BullMQ
schema/business/reference validation → permanent → markFailed
cancelled → markCancelled (3 个检查点: 执行前/Provider前/Projector前)
- Usage logging: 每次 Provider 调用写 AiUsageLog (jobId/attemptNo/credentialMode/token)
- AiJobModule: 使用 AI_JOB_EXECUTION_ENGINE token 注册,替换 #288 的 no-op
- 10 个单元测试: 全链路成功/终态跳过/取消(2)/错误分类(3)/锁冲突/Schema不兼容/UsageLog
Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-20 18:30:02 +08:00
wangdl
471aa2b872
fix : #289 检修 — TOCTOU 幂等 + promptKey 传递 + require 清理
...
Deploy API Server / build-and-unit (push) Failing after 29s
Deploy API Server / current-integration (push) Has been skipped
Deploy API Server / backward-compat (push) Has been skipped
Deploy API Server / deploy (push) Has been skipped
- 幂等保护从 findUnique 预检改为 P2002 catch(消除 TOCTOU 竞态窗口)
- AiJobLifecycleRepository: CreateJobInput 新增 promptKey,createJob 写入
- AiJobCreationService: 从 JobDefinition 传递 promptKey 到 Job
- computeHash: 内联 require('crypto') → 顶层 import * as crypto
- 测试更新: 幂等场景改为 P2002 冲突 → findUniqueOrThrow 返回已有 Job
Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-20 18:22:39 +08:00
wangdl
6668bba9b4
feat: M-AI-03 Outbox Dispatcher — 可靠投递 ai.job.enqueue 到 BullMQ
...
Deploy API Server / build-and-unit (push) Failing after 29s
Deploy API Server / current-integration (push) Has been skipped
Deploy API Server / backward-compat (push) Has been skipped
Deploy API Server / deploy (push) Has been skipped
- OutboxDispatcher: 每 5s 轮询 OutboxEvent 表,CAS 领取 → 验证 → BullMQ 投递 → 标记 published
- 采用 ADR-003 §4.3 先 CAS 后投递算法:markProcessing(CAS) → queue.add() → markPublished
- BullMQ jobId = AiJob.id(幂等重复 add)
- 崩溃窗口保护:bullmq jobId 幂等 + releaseExpiredLocks(60s)
- 错误处理:永久失败(未知eventType/Job不存在/非法queueName/超过最大尝试)
vs 暂时失败(exponential backoff 回退 pending)
- 仅在 WorkerModule 注册(API 进程不运行 Dispatcher)
Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-20 18:20:22 +08:00
wangdl
f0183c03c4
feat: M-AI-03 事务化 AiJob 创建、Snapshot 与 Enqueue Outbox
...
Deploy API Server / build-and-unit (push) Failing after 30s
Deploy API Server / current-integration (push) Has been skipped
Deploy API Server / backward-compat (push) Has been skipped
Deploy API Server / deploy (push) Has been skipped
- AiJobCreationService: 在一个 Prisma Transaction 内原子创建 Job+Snapshot+Outbox
- 幂等性: (userId, jobType, idempotencyKey) UNIQUE 约束防重复
- Job 元数据从 JobDefinition 写入 (queueName/priority/maxAttempts/timeoutMs 等)
- overrides 支持覆盖 priority/credentialMode/credentialId
- Outbox payload 仅含 {jobId},不含 userId/credentialId/snapshot
- 依赖 SnapshotBuilderService + OutboxRepository,AiJobModule 导入 AiRuntimeModule
Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-20 18:13:15 +08:00
wangdl
fcce35742f
feat: M-AI-03 注册新队列 ai-interactive/ai-background 与薄 Worker Processor
...
Deploy API Server / build-and-unit (push) Failing after 29s
Deploy API Server / current-integration (push) Has been skipped
Deploy API Server / backward-compat (push) Has been skipped
Deploy API Server / deploy (push) Has been skipped
- queue.constants.ts: 新增 QUEUE_AI_INTERACTIVE / QUEUE_AI_BACKGROUND
- queue-definitions.ts: 队列配置对齐 ADR-003 §3.1
ai-interactive: concurrency=2, attempts=2, backoff=2000ms
ai-background: concurrency=1, attempts=3, backoff=5000ms
- queue.service.ts: QueueService 注入并路由新队列
- queue.module.ts: BullModule.registerQueue 注册新队列
- AiJobExecutionEngine 接口 + AI_JOB_EXECUTION_ENGINE 注入 Token
- AiInteractiveJobWorker + AiBackgroundJobWorker: 薄 Processor,仅接收 {jobId} 调用 Engine
- worker.module.ts: 注册两个新 Processor(#291 提供 Engine 真实实现前为 no-op)
Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-20 18:02:26 +08:00
wangdl
373e5e09fa
refactor: ALLOWED_CREDENTIAL_MODES 集中到 job-definition.types.ts
...
Deploy API Server / build-and-unit (push) Successful in 32s
Deploy API Server / current-integration (push) Successful in 29s
Deploy API Server / backward-compat (push) Successful in 0s
Deploy API Server / deploy (push) Successful in 1m0s
消除 Registry 中的重复运行时数组,改为从 types 文件导入。
类型定义与运行时数组同源,避免异步风险。
Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-20 17:28:58 +08:00
wangdl
e4b922e7e4
feat: M-AI-03 Job Definition Registry 与注册校验
...
Deploy API Server / build-and-unit (push) Successful in 32s
Deploy API Server / current-integration (push) Successful in 28s
Deploy API Server / backward-compat (push) Successful in 0s
Deploy API Server / deploy (push) Successful in 58s
- JobDefinition 接口冻结(job-definition.types.ts):对齐 ADR-003 §2.1,
涵盖 queue/execution/input/output/prompt/model/credential/security
- JobDefinitionRegistry:启动时注册、运行时只读、Object.freeze 防篡改
- 10 类校验错误:DuplicateJobType/UnknownJobType/InvalidJobType/
InvalidQueueName/MissingSchema/InvalidTimeout/InvalidRetries/
InvalidCredentialMode/InvalidPromptKey/MissingBackoff
- 43 个单元测试覆盖所有校验路径 + 顺序稳定性 + 禁止覆盖
- 更新 AiJobModule 注册新 Provider
Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-20 17:24:57 +08:00
wangdl
4c736f3658
fix: Repository 层移除 modelProvider/modelName 硬编码默认值
...
Deploy API Server / build-and-unit (push) Successful in 33s
Deploy API Server / current-integration (push) Successful in 29s
Deploy API Server / backward-compat (push) Successful in 0s
Deploy API Server / deploy (push) Successful in 1m3s
modelProvider/modelName 默认值从 Repository 移至 Service/JobDefinition 层。
若调用方未传入,依赖 Prisma schema @default 保证列非空。
避免 AiJobService 忘记传值时静默使用错误 provider。
Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-20 17:22:11 +08:00
wangdl
333632dc5b
test: 补充 7 个缺失测试用例,覆盖所有 CAS 失败和只读路径
...
Deploy API Server / build-and-unit (push) Successful in 33s
Deploy API Server / backward-compat (push) Has been cancelled
Deploy API Server / deploy (push) Has been cancelled
Deploy API Server / current-integration (push) Has been cancelled
新增用例:
- markSucceeded CAS 失败(非终态 queued)→ JobNotActiveError
- markFailed CAS 失败(已终态)→ JobAlreadyTerminalError
- markFailed 接受可选 tx 参数
- extendLock CAS 失败(Job 不在 running)→ JobNotActiveError
- requestCancellation 终态 Job → JobNotCancellableError
- findExpiredLocks 过期锁查询
- findById 按 ID 查询
总测试数:43 → 50
Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-20 17:21:22 +08:00
wangdl
38d1c4f414
fix: requestCancellation TOCTOU 竞态 — update 改为 updateMany CAS
...
Deploy API Server / build-and-unit (push) Successful in 33s
Deploy API Server / current-integration (push) Successful in 29s
Deploy API Server / deploy (push) Has been cancelled
Deploy API Server / backward-compat (push) Has been cancelled
- running 路径:prisma.aiJob.update() → updateMany() CAS
- CAS 失败时重读当前状态:已取消则幂等返回,已终态则抛出 JobNotCancellableError
- 新增 2 个 TOCTOU 场景测试(已变 cancelled → 幂等,已变 succeeded → 报错)
Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-20 17:20:15 +08:00
wangdl
b08d27a449
feat: M-AI-03 AiJob 状态机与原子状态仓储
...
Deploy API Server / build-and-unit (push) Successful in 33s
Deploy API Server / current-integration (push) Successful in 29s
Deploy API Server / backward-compat (push) Successful in 0s
Deploy API Server / deploy (push) Successful in 1m4s
- AiJobStateMachine: 5 状态(queued/running/succeeded/failed/cancelled)、
合法/非法迁移验证、终态判断、双向 Shadow Write 映射
- AiJobLifecycleRepository: 唯一 lifecycleStatus 写入入口、
CAS(条件 UPDATE WHERE lifecycleStatus IN (...))抢锁/续锁/标记成功/失败/取消、
可选 tx 参数支持 Projector 事务内调用
- requestCancellation: queued 直接取消 → cancelled、
running 设置 cancelRequestedAt 信号
- 6 个类型化错误(JobLockConflict/JobNotActive/JobAlreadyTerminal/
JobNotCancellable/JobExtendLock/IllegalStateTransition)
- 41 个单元测试全部通过
Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-20 17:17:12 +08:00
wangdl
36903e797e
fix: prevent hourly API crash from unhandled CostAggregationService rejection
...
Deploy API Server / build-and-unit (push) Successful in 32s
Deploy API Server / current-integration (push) Successful in 30s
Deploy API Server / backward-compat (push) Successful in 0s
Deploy API Server / deploy (push) Successful in 58s
- setInterval callback lacked .catch() — unhandled Promise rejection
crashed the Node.js process exactly 1 hour after startup
- AiUsageLog table missing in current DB → aggregateToday() rejects →
process.exit(1) in Node 22
Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-20 16:25:16 +08:00
wangdl
3e7c02a932
fix(build): exclude scripts from tsconfig, fix JsonValue type errors
...
Deploy API Server / build-and-deploy (push) Failing after 25s
- tsconfig.build.json: exclude scripts/ (avoids Prisma delegate mismatch)
- tsconfig.json: add exclude for scripts/ and dist/
- ai-job-artifact.repository.ts: cast metadata to any (JsonValue compat)
- ai-job-snapshot.repository.ts: cast data to any (JsonValue compat)
- ai-job-artifact.repository.spec.ts: remove unused @ts-expect-error
- snapshot-builder.service.spec.ts: cast JSON fields to any
Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-20 12:43:56 +08:00
wangdl
98e442e666
fix(M-AI-02-GATE): restore physical column names, composite UNIQUE, lifecycle spec, migrate deploy
...
Deploy API Server / build-and-deploy (push) Failing after 23s
Section 2: @map("errorMessage") + @map("completedAt") decouple logical from physical names.
Forward-fix migration reverts physical columns to original names.
Section 3: jobType VARCHAR(64) → VARCHAR(32) restored.
Section 4: lifecycleStatus mapping restored to spec (pending→queued, processing→running,
completed→succeeded, failed→failed). Enum: created|queued|running|retrying|succeeded|
failed|cancel_requested|cancelled.
Section 5: idempotencyKey UNIQUE changed from single-column to composite
(userId, jobType, idempotencyKey). MySQL allows multiple NULLs.
Section 6: triggerType backfill now documents evidence basis per record.
Section 7: CI deploy.yml uses prisma migrate deploy (not db push).
Migration baseline established (28 rows in _prisma_migrations).
prisma migrate diff: No difference detected.
332 tests pass.
Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-20 12:39:56 +08:00
wangdl
7cc6947e41
feat(M-AI-02-06): polymorphic AiJobArtifact model
...
- 7 columns, (jobId,artifactType,artifactId) UNIQUE for idempotency
- ON DELETE CASCADE, (jobId,ordinal) + (artifactType,artifactId) indexes
- P2002 catch → findUnique → retry-create for CASCADE race edge case
- 12 unit tests (idempotency, batch, reverse lookup, constraint)
Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-20 12:24:33 +08:00
wangdl
1fadb724ec
feat(M-AI-02-05): immutable AiJobSnapshot model
...
- 9 columns, jobId UNIQUE, ON DELETE CASCADE
- Repository: create + findByJobId only (no update/upsert)
- 14 unit tests (immutability, security, delete strategy)
Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-20 12:24:28 +08:00
wangdl
f4259e70a0
fix(M-AI-02-04): adapt source to renamed Prisma fields
...
- completedAt → finishedAt, errorMessage → internalErrorMessage
- API JSON keys preserved for backward compat
Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-20 12:24:24 +08:00
wangdl
4fb652d273
feat: M-AI-01 Worker 进程边界与部署收口(全 8 个 Issue)
...
Deploy API Server / build-and-deploy (push) Failing after 39s
M-AI-01-01: ADR-001 统一 AI 架构决策记录 + 附录 A 依赖闭包审计
M-AI-01-02: Worker 执行依赖闭包审计(附录 A 文档)
M-AI-01-03: 分离 AppModule/WorkerModule Processor 注册
M-AI-01-04: 统一 Queue Definition Registry + 环境变量覆盖
M-AI-01-05: 独立 Worker 启动与生命周期(instanceId/校验/优雅关闭)
M-AI-01-06: Docker + systemd 部署拓扑(unit 文件 + 回滚文档)
M-AI-01-07: Worker Heartbeat(Redis TTL 90s)+ Admin 在线状态 API
M-AI-01-08: 集成验收脚本
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-19 21:22:48 +08:00
wangdl
d7647cbc3d
fix: move all-sources route before :id to avoid conflict
Deploy API Server / build-and-deploy (push) Successful in 48s
2026-06-19 15:38:32 +08:00
wangdl
178666627b
feat: add GET /admin-api/knowledge-bases/all-sources
Deploy API Server / build-and-deploy (push) Successful in 47s
2026-06-19 15:31:03 +08:00
wangdl
1abc89be23
fix: add enrichWithNames to chat sessions API
Deploy API Server / build-and-deploy (push) Successful in 46s
2026-06-19 13:30:09 +08:00
wangdl
9a392ba274
fix: add enrichWithNames to content-safety checks
Deploy API Server / build-and-deploy (push) Successful in 48s
2026-06-19 13:27:10 +08:00
wangdl
0203ccfd1f
fix: translate learning record titles to Chinese
Deploy API Server / build-and-deploy (push) Successful in 49s
2026-06-19 13:20:29 +08:00
wangdl
0ea36a7073
feat(API-ADMIN-010): add enrichWithNames to admin list controllers
...
Deploy API Server / build-and-deploy (push) Successful in 50s
- New shared helper: src/common/helpers/name-resolver.ts
- Applied to: reviews, users/members, files, knowledge-bases, imports
- Learning service refactored to use shared helper
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-19 13:04:55 +08:00
wangdl
ff4135b7c6
feat: add enrichWithNames to admin learning API
...
Deploy API Server / build-and-deploy (push) Successful in 50s
All list endpoints now return userName, kbName, materialName
resolved from User, KnowledgeBase, KnowledgeSource tables.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-19 12:41:46 +08:00
wangdl
af8d95cdb6
fix: add try-catch + error logging to processBatch
...
Deploy API Server / build-and-deploy (push) Successful in 48s
Prevents 500 from crashing the entire batch. Logs the actual error
to server log for debugging.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-19 12:18:46 +08:00
wangdl
fb7ee358ce
fix: add knowledgeBaseId to ReadingEventUploadItemDto + increase Max delta
...
Deploy API Server / build-and-deploy (push) Successful in 47s
iOS sends knowledgeBaseId in batch upload but DTO didn't have it,
causing forbidNonWhitelisted to reject with 400.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-19 12:15:56 +08:00
wangdl
43293a48e6
fix: return 'id' instead of 'jobId' in POST /imports response
...
Deploy API Server / build-and-deploy (push) Successful in 46s
iOS ImportStatusResponse expects 'id' field. The mismatch caused
DecodingError.keyNotFound on the client side.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 22:27:02 +08:00
wangdl
aef8e2a416
fix: make import lock unique per attempt + release in finally
...
Deploy API Server / build-and-deploy (push) Successful in 47s
- Add timestamp to lock key to prevent blocking retries
- Wrap create logic in try-finally to always release lock
- Reduce lock TTL from 30min to 5min
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 22:17:59 +08:00
wangdl
433e0095ee
debug: add detailed logging to DocumentImportService.createImport
...
Deploy API Server / build-and-deploy (push) Successful in 49s
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 22:16:17 +08:00
wangdl
4f614f9d1f
fix: extract userId from JWT in POST /imports controller
...
Deploy API Server / build-and-deploy (push) Successful in 47s
DocumentImport.userId is a required foreign key, but the iOS app
doesn't send it. Extract from JWT via @CurrentUser() decorator
and pass to service.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 22:13:10 +08:00
wangdl
0867b4f39a
feat(API-AI-082): add POST /sources/:id/parse trigger endpoint
...
Deploy API Server / build-and-deploy (push) Successful in 46s
Allows users to manually retry source parsing by creating a new
DocumentImport job and enqueuing it. Returns jobId for polling.
Route: POST /knowledge-bases/:kbId/sources/:id/parse
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 21:56:31 +08:00
wangdl
939adcebd3
feat(API-AI-081): add KnowledgeItem.sourceId FK to KnowledgeSource
...
Deploy API Server / build-and-deploy (push) Successful in 43s
- Prisma schema: add sourceId field + @relation to KnowledgeSource
- KnowledgeSource: add items[] reverse relation + @index on sourceId
- KnowledgeItemsRepository: accept sourceId in create()
- ImportCandidateService.accept(): pass sourceId to create()
- DocumentImport worker: pass sourceId alongside sourceRef
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 21:54:58 +08:00
wangdl
76bdba330d
fix(API-AI-080): enqueue import job + pass sourceId in KnowledgeSource pipeline
...
Deploy API Server / build-and-deploy (push) Successful in 43s
KnowledgeSourceService.addSource() was creating Source + DocumentImport
records but never enqueuing the job for processing. Also the worker
wasn't linking created KnowledgeItems back to their source.
Changes:
- Inject QueueService + RedisService into KnowledgeSourceService
- Enqueue document-import job after creating Source + DocumentImport
- Set Redis status keys (matching DocumentImportService pattern)
- Worker: resolve sourceId from job data or DocumentImport record
- Worker: pass sourceRef when creating KnowledgeItems
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 21:51:49 +08:00
wangdl
82e3a60101
refactor: merge admin/learning into admin-api/learning, restore API isolation
...
Deploy API Server / build-and-deploy (push) Successful in 45s
- Move AdminLearningService + DTOs to learning-session module
- Merge 21 new endpoints into existing admin-api/learning controller
- Add analysis and ai-usage methods to unified service
- Delete admin-learning module (no longer needed)
- Revert JwtAuthGuard /api/admin bypass (was breaking isolation)
- Fix: /api/* now exclusively serves user/iOS traffic again
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 19:26:37 +08:00
wangdl
c3fd6a221f
fix: add missing /api/admin/learning/knowledge-bases endpoint
...
Deploy API Server / build-and-deploy (push) Successful in 45s
Dashboard filter dropdown calls this to populate KB selector.
Returns knowledge bases that have reading event data with real titles.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 18:40:40 +08:00
wangdl
c0a8f7ef27
perf: add missing indexes + fix learning admin query performance
...
Deploy API Server / build-and-deploy (push) Successful in 47s
- Add 10 missing DB indexes across 5 tables (LearningSession,
ReadingEvent, MaterialReadingProgress, DailyLearningActivity,
LearningRecord) to eliminate full-table scans on count queries
- Dashboard: accept knowledgeBaseId/dateRange filters from frontend
- getAnomalies: add skip-based pagination, remove redundant counts
- Remove duplicate AdminReadingController to fix route collision
on admin/learning prefix
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 18:20:44 +08:00
wangdl
4a69d14047
test: add integration tests for snapshot-builder.service (API-AI-068)
...
Deploy API Server / build-and-deploy (push) Successful in 44s
- 59 tests covering buildSnapshot full flow + all computational methods
- buildSnapshot: defaults, privacy flags, priority rules, DB persistence, error logging
- Scope routing: material vs knowledge_base session queries
- Computational methods: weightedQuizScore, weightedReviewScore, AIScore,
weakPointSeverity, quizTrend, compositeMastery, classifyMasteryLevel
- Quality: normalizeQualityPreference, getScoreWeights presets
- Device: mapPlatformCategory, computeSwitchFrequency, mapDeviceTaskSuitability
- Helpers: modeOf, buildAllowedFields, countBy, computeSignals
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 12:23:52 +08:00
wangdl
3e43b2b52d
test: add unit tests for runtime-internal.controller (API-AI-067)
...
Deploy API Server / build-and-deploy (push) Successful in 43s
- 12 tests covering all 9 endpoints + instanceId extraction
- instanceId: from header / default "unknown"
- pollJobs: limit default 5, capabilities pass-through
- lockJob/heartbeatJob: runtimeInstanceId fallback from dto→header
- getSnapshot: direct delegation
- resolveCredential: all fields + undefined credentialId
- submitResult/submitFailure: entire dto pass-through
- submitInvocationLogs: logs array extraction
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 12:19:06 +08:00
wangdl
5fbd437232
test: add unit tests for credential-encryption.service (API-AI-066)
...
Deploy API Server / build-and-deploy (push) Successful in 45s
- 17 tests covering encrypt/decrypt/hash/mask/redact + config error
- encrypt↔decrypt round-trip, random IV, base64, empty, unicode
- hash: deterministic, different inputs, empty string
- mask: long keys (4+****+4), short keys (2+****), edge cases
- redact: sk- token replacement, no-op, short sk- skip, empty
- Missing CREDENTIAL_ENCRYPTION_KEY throws on encrypt/decrypt
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 12:16:53 +08:00
wangdl
4713758344
test: add unit tests for platform-budget.service (API-AI-065)
...
Deploy API Server / build-and-deploy (push) Successful in 45s
- 15 tests covering all 6 public methods
- checkPlatformBudget: healthy, auto-create, circuit-open, half-open limit,
half-open pass, token exceeded, cost exceeded
- recordSuccess: upsert with reset circuit to closed
- recordFailure: increment failedCount, open circuit at threshold, first-day create
- Admin: transitionToHalfOpen / closeCircuit
- getBudgetState: state + limits, auto-create fallback
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 12:15:20 +08:00
wangdl
c433b3dc5d
refactor: split shared mockFindUnique into settings/usage mocks in quota tests
...
Deploy API Server / build-and-deploy (push) Successful in 43s
- userAiSettings.findUnique → mockSettingsFindUnique
- userAiUsageDaily.findUnique → mockUsageFindUnique
- Eliminates order-dependency of mockResolvedValueOnce chains
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 12:14:33 +08:00
wangdl
9c7247aa90
test: add unit tests for user-ai-quota.service (API-AI-064)
...
Deploy API Server / build-and-deploy (push) Successful in 48s
- 15 tests covering all 4 public methods
- checkQuota: pass under limits, defaults, null usage, job/token exceeded
- incrementJobCount: correct upsert params, apiKeyMode routing
- recordTokenUsage: all token fields, costEstimate default=0
- getUsage: both modes parallel, defaults for null records, mixed
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 12:12:57 +08:00
wangdl
1a5e040ed8
test: add unit tests for user-ai.controller (API-AI-063)
...
Deploy API Server / build-and-deploy (push) Successful in 47s
- 34 tests covering all 28 endpoints
- Profile: GET/PUT with null→{} fallback
- Settings: GET/PUT delegation
- Credentials: CRUD + test (6 endpoints)
- Analysis Jobs: create/cancel/get/list with query filters
- Publish: quiz + flashcard
- Analysis Results: getAnalysis/listAnalyses/listRecommendations/listWeakPoints
- Quizzes: get/getQuestions/list with filters
- Reanalysis/Notifications/Feedback/Flashcards
- Fix: getProfile ?? {} now awaits before null-coalescing
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 11:57:38 +08:00
wangdl
b0e9796acb
fix: use ConfigService for DeepSeek base URL in testCredential
...
Deploy API Server / build-and-deploy (push) Successful in 43s
- Replace hardcoded 'https://api.deepseek.com/v1/models ' with config lookup
- Single source of truth via ai.deepseek.baseUrl (DEEPSEEK_BASE_URL env)
- Add ConfigService dep to UserAiService constructor + test mock
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 11:47:59 +08:00