feat(iit): Complete CRA Agent V3.0 P0 milestone - autonomous QC pipeline
P0-1: Variable list sync from REDCap metadata P0-2: QC rule configuration with JSON Logic + AI suggestion P0-3: Scheduled QC + report generation + eQuery closed loop P0-4: Unified dashboard + AI stream timeline + critical events Backend: - Add IitEquery, IitCriticalEvent Prisma models + migration - Add cronEnabled/cronExpression to IitProject - Implement eQuery service/controller/routes (CRUD + respond/review/close) - Implement DailyQcOrchestrator (report -> eQuery -> critical events -> notify) - Add AI rule suggestion service - Register daily QC cron worker and eQuery auto-review worker - Extend QC cockpit with timeline, trend, critical events APIs - Fix timeline issues field compat (object vs array format) Frontend: - Create IIT business module with 6 pages (Dashboard, AI Stream, eQuery, Reports, Variable List + project config pages) - Migrate IIT config from admin panel to business module - Implement health score, risk heatmap, trend chart, critical event alerts - Register IIT module in App router and top navigation Testing: - Add E2E API test script covering 7 modules (46 assertions, all passing) Tested: E2E API tests 46/46 passed, backend and frontend verified Made-with: Cursor
This commit is contained in:
@@ -948,6 +948,8 @@ model IitProject {
|
||||
redcapApiToken String @map("redcap_api_token")
|
||||
redcapUrl String @map("redcap_url")
|
||||
lastSyncAt DateTime? @map("last_sync_at")
|
||||
cronEnabled Boolean @default(false) @map("cron_enabled")
|
||||
cronExpression String? @map("cron_expression")
|
||||
status String @default("active")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
@@ -1426,6 +1428,97 @@ model IitQcProjectStats {
|
||||
@@schema("iit_schema")
|
||||
}
|
||||
|
||||
/// eQuery 表 - AI 自动生成的电子质疑,具有完整生命周期
|
||||
model IitEquery {
|
||||
id String @id @default(uuid())
|
||||
projectId String @map("project_id")
|
||||
|
||||
// 来源
|
||||
recordId String @map("record_id")
|
||||
eventId String? @map("event_id")
|
||||
formName String? @map("form_name")
|
||||
fieldName String? @map("field_name")
|
||||
qcLogId String? @map("qc_log_id")
|
||||
reportId String? @map("report_id")
|
||||
|
||||
// 质疑内容
|
||||
queryText String @map("query_text") @db.Text
|
||||
expectedAction String? @map("expected_action") @db.Text
|
||||
severity String @default("warning")
|
||||
category String?
|
||||
|
||||
// 状态机: pending → responded → reviewing → closed / reopened
|
||||
status String @default("pending")
|
||||
|
||||
// CRC 回复
|
||||
assignedTo String? @map("assigned_to")
|
||||
respondedAt DateTime? @map("responded_at")
|
||||
responseText String? @map("response_text") @db.Text
|
||||
responseData Json? @map("response_data") @db.JsonB
|
||||
|
||||
// AI 复核
|
||||
reviewResult String? @map("review_result")
|
||||
reviewNote String? @map("review_note") @db.Text
|
||||
reviewedAt DateTime? @map("reviewed_at")
|
||||
|
||||
// 关闭
|
||||
closedAt DateTime? @map("closed_at")
|
||||
closedBy String? @map("closed_by")
|
||||
resolution String? @db.Text
|
||||
|
||||
// 时间线
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
@@index([projectId], map: "idx_iit_equery_project")
|
||||
@@index([projectId, status], map: "idx_iit_equery_project_status")
|
||||
@@index([recordId], map: "idx_iit_equery_record")
|
||||
@@index([assignedTo], map: "idx_iit_equery_assigned")
|
||||
@@map("equery")
|
||||
@@schema("iit_schema")
|
||||
}
|
||||
|
||||
/// 重大事件归档表 - SAE、重大方案偏离等长期临床资产
|
||||
model IitCriticalEvent {
|
||||
id String @id @default(uuid())
|
||||
projectId String @map("project_id")
|
||||
recordId String @map("record_id")
|
||||
|
||||
// 事件分类
|
||||
eventType String @map("event_type")
|
||||
severity String @default("critical")
|
||||
|
||||
// 事件内容
|
||||
title String
|
||||
description String @db.Text
|
||||
detectedAt DateTime @map("detected_at")
|
||||
detectedBy String @default("ai") @map("detected_by")
|
||||
|
||||
// 来源追溯
|
||||
sourceQcLogId String? @map("source_qc_log_id")
|
||||
sourceEqueryId String? @map("source_equery_id")
|
||||
sourceData Json? @map("source_data") @db.JsonB
|
||||
|
||||
// 处理状态
|
||||
status String @default("open")
|
||||
handledBy String? @map("handled_by")
|
||||
handledAt DateTime? @map("handled_at")
|
||||
handlingNote String? @map("handling_note") @db.Text
|
||||
|
||||
// 上报追踪
|
||||
reportedToEc Boolean @default(false) @map("reported_to_ec")
|
||||
reportedAt DateTime? @map("reported_at")
|
||||
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
@@index([projectId], map: "idx_iit_critical_event_project")
|
||||
@@index([projectId, eventType], map: "idx_iit_critical_event_type")
|
||||
@@index([projectId, status], map: "idx_iit_critical_event_status")
|
||||
@@map("critical_events")
|
||||
@@schema("iit_schema")
|
||||
}
|
||||
|
||||
model admin_operation_logs {
|
||||
id Int @id @default(autoincrement())
|
||||
admin_id String
|
||||
|
||||
Reference in New Issue
Block a user