docs(platform): Add database documentation system and restructure deployment docs
Completed: - Add 6 core database documents (docs/01-平台基础层/07-数据库/) Architecture overview, migration history, environment comparison, tech debt tracking, seed data management, PostgreSQL extensions - Restructure deployment docs: archive 20 legacy files to _archive-2025/ - Create unified daily operations manual (01-日常更新操作手册.md) - Add pending deployment change tracker (03-待部署变更清单.md) - Update database development standard to v3.0 (three iron rules) - Fix Prisma schema type drift: align @db.* annotations with actual DB IIT: UUID/Timestamptz(6), SSA: Timestamp(6)/VarChar(20/50/100) - Add migration: 20260227_align_schema_with_db_types (idempotent ALTER) - Add Cursor Rule for auto-reminding deployment change documentation - Update system status guide v6.4 with deployment and DB doc references - Add architecture consultation docs (Prisma guide, SAE deployment guide) Technical details: - Manual migration due to shadow DB limitation (TD-001 in tech debt) - Deployment docs reduced from 20+ scattered files to 3 core documents - Cursor Rule triggers on schema.prisma, package.json, Dockerfile changes Made-with: Cursor
This commit is contained in:
@@ -0,0 +1,229 @@
|
||||
-- ================================================================
|
||||
-- 补丁迁移:覆盖 db push 创建的 6 张表 + 3 列
|
||||
-- 所有语句使用 IF NOT EXISTS 保证幂等(多次执行不报错)
|
||||
-- 日期:2026-02-27
|
||||
-- ================================================================
|
||||
|
||||
-- ============ iit_schema: 4 张新表 + 1 列 + 1 索引 ============
|
||||
|
||||
-- 1. IIT 字段元数据表(REDCap 字段定义缓存)
|
||||
CREATE TABLE IF NOT EXISTS "iit_schema"."field_metadata" (
|
||||
"id" TEXT NOT NULL,
|
||||
"project_id" TEXT NOT NULL,
|
||||
"field_name" TEXT NOT NULL,
|
||||
"field_label" TEXT NOT NULL,
|
||||
"field_type" TEXT NOT NULL,
|
||||
"form_name" TEXT NOT NULL,
|
||||
"section_header" TEXT,
|
||||
"validation" TEXT,
|
||||
"validation_min" TEXT,
|
||||
"validation_max" TEXT,
|
||||
"choices" TEXT,
|
||||
"required" BOOLEAN NOT NULL DEFAULT false,
|
||||
"branching" TEXT,
|
||||
"alias" TEXT,
|
||||
"rule_source" TEXT,
|
||||
"synced_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "field_metadata_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "unique_iit_field_metadata"
|
||||
ON "iit_schema"."field_metadata"("project_id", "field_name");
|
||||
CREATE INDEX IF NOT EXISTS "idx_iit_field_metadata_project"
|
||||
ON "iit_schema"."field_metadata"("project_id");
|
||||
CREATE INDEX IF NOT EXISTS "idx_iit_field_metadata_form"
|
||||
ON "iit_schema"."field_metadata"("project_id", "form_name");
|
||||
|
||||
-- 2. IIT 质控日志表
|
||||
CREATE TABLE IF NOT EXISTS "iit_schema"."qc_logs" (
|
||||
"id" TEXT NOT NULL,
|
||||
"project_id" TEXT NOT NULL,
|
||||
"record_id" TEXT NOT NULL,
|
||||
"event_id" TEXT,
|
||||
"qc_type" TEXT NOT NULL,
|
||||
"form_name" TEXT,
|
||||
"status" TEXT NOT NULL,
|
||||
"issues" JSONB NOT NULL DEFAULT '[]',
|
||||
"rules_evaluated" INTEGER NOT NULL DEFAULT 0,
|
||||
"rules_skipped" INTEGER NOT NULL DEFAULT 0,
|
||||
"rules_passed" INTEGER NOT NULL DEFAULT 0,
|
||||
"rules_failed" INTEGER NOT NULL DEFAULT 0,
|
||||
"rule_version" TEXT NOT NULL,
|
||||
"inclusion_passed" BOOLEAN,
|
||||
"exclusion_passed" BOOLEAN,
|
||||
"triggered_by" TEXT NOT NULL,
|
||||
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "qc_logs_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "idx_iit_qc_log_record_time"
|
||||
ON "iit_schema"."qc_logs"("project_id", "record_id", "created_at");
|
||||
CREATE INDEX IF NOT EXISTS "idx_iit_qc_log_status_time"
|
||||
ON "iit_schema"."qc_logs"("project_id", "status", "created_at");
|
||||
CREATE INDEX IF NOT EXISTS "idx_iit_qc_log_type_time"
|
||||
ON "iit_schema"."qc_logs"("project_id", "qc_type", "created_at");
|
||||
|
||||
-- 3. IIT 受试者记录汇总表
|
||||
CREATE TABLE IF NOT EXISTS "iit_schema"."record_summary" (
|
||||
"id" TEXT NOT NULL,
|
||||
"project_id" TEXT NOT NULL,
|
||||
"record_id" TEXT NOT NULL,
|
||||
"enrolled_at" TIMESTAMP(3),
|
||||
"enrolled_by" TEXT,
|
||||
"last_updated_at" TIMESTAMP(3) NOT NULL,
|
||||
"last_updated_by" TEXT,
|
||||
"last_form_name" TEXT,
|
||||
"form_status" JSONB NOT NULL DEFAULT '{}',
|
||||
"total_forms" INTEGER NOT NULL DEFAULT 0,
|
||||
"completed_forms" INTEGER NOT NULL DEFAULT 0,
|
||||
"completion_rate" DOUBLE PRECISION NOT NULL DEFAULT 0,
|
||||
"latest_qc_status" TEXT,
|
||||
"latest_qc_at" TIMESTAMP(3),
|
||||
"update_count" INTEGER NOT NULL DEFAULT 0,
|
||||
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updated_at" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "record_summary_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "unique_iit_record_summary"
|
||||
ON "iit_schema"."record_summary"("project_id", "record_id");
|
||||
CREATE INDEX IF NOT EXISTS "idx_iit_record_summary_enrolled"
|
||||
ON "iit_schema"."record_summary"("project_id", "enrolled_at");
|
||||
CREATE INDEX IF NOT EXISTS "idx_iit_record_summary_qc_status"
|
||||
ON "iit_schema"."record_summary"("project_id", "latest_qc_status");
|
||||
CREATE INDEX IF NOT EXISTS "idx_iit_record_summary_completion"
|
||||
ON "iit_schema"."record_summary"("project_id", "completion_rate");
|
||||
|
||||
-- 4. IIT 项目级质控统计汇总表
|
||||
CREATE TABLE IF NOT EXISTS "iit_schema"."qc_project_stats" (
|
||||
"id" TEXT NOT NULL,
|
||||
"project_id" TEXT NOT NULL,
|
||||
"total_records" INTEGER NOT NULL DEFAULT 0,
|
||||
"passed_records" INTEGER NOT NULL DEFAULT 0,
|
||||
"failed_records" INTEGER NOT NULL DEFAULT 0,
|
||||
"warning_records" INTEGER NOT NULL DEFAULT 0,
|
||||
"inclusion_met" INTEGER NOT NULL DEFAULT 0,
|
||||
"exclusion_met" INTEGER NOT NULL DEFAULT 0,
|
||||
"avg_completion_rate" DOUBLE PRECISION NOT NULL DEFAULT 0,
|
||||
"updated_at" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "qc_project_stats_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "qc_project_stats_project_id_key"
|
||||
ON "iit_schema"."qc_project_stats"("project_id");
|
||||
|
||||
-- 5. IIT projects 表新增 knowledge_base_id 列
|
||||
ALTER TABLE "iit_schema"."projects"
|
||||
ADD COLUMN IF NOT EXISTS "knowledge_base_id" TEXT;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "idx_iit_project_kb"
|
||||
ON "iit_schema"."projects"("knowledge_base_id");
|
||||
|
||||
-- ============ ssa_schema: 1 列 + 2 张新表 ============
|
||||
|
||||
-- 6a. SSA Session 新增 data_profile 列(Phase 2A)
|
||||
ALTER TABLE "ssa_schema"."ssa_sessions"
|
||||
ADD COLUMN IF NOT EXISTS "data_profile" JSONB;
|
||||
|
||||
-- 6. SSA 工作流表
|
||||
CREATE TABLE IF NOT EXISTS "ssa_schema"."ssa_workflows" (
|
||||
"id" TEXT NOT NULL DEFAULT gen_random_uuid()::text,
|
||||
"session_id" TEXT NOT NULL,
|
||||
"message_id" TEXT,
|
||||
"status" VARCHAR NOT NULL DEFAULT 'pending',
|
||||
"total_steps" INTEGER NOT NULL,
|
||||
"completed_steps" INTEGER NOT NULL DEFAULT 0,
|
||||
"workflow_plan" JSONB NOT NULL,
|
||||
"reasoning" TEXT,
|
||||
"created_at" TIMESTAMP(3) NOT NULL DEFAULT now(),
|
||||
"started_at" TIMESTAMP(3),
|
||||
"completed_at" TIMESTAMP(3),
|
||||
|
||||
CONSTRAINT "ssa_workflows_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "idx_ssa_workflow_session"
|
||||
ON "ssa_schema"."ssa_workflows"("session_id");
|
||||
CREATE INDEX IF NOT EXISTS "idx_ssa_workflow_status"
|
||||
ON "ssa_schema"."ssa_workflows"("status");
|
||||
|
||||
-- 外键:ssa_workflows.session_id → ssa_sessions.id
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.table_constraints
|
||||
WHERE constraint_name = 'ssa_workflows_session_id_fkey'
|
||||
) THEN
|
||||
ALTER TABLE "ssa_schema"."ssa_workflows"
|
||||
ADD CONSTRAINT "ssa_workflows_session_id_fkey"
|
||||
FOREIGN KEY ("session_id")
|
||||
REFERENCES "ssa_schema"."ssa_sessions"("id")
|
||||
ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- 7. SSA 工作流步骤表
|
||||
CREATE TABLE IF NOT EXISTS "ssa_schema"."ssa_workflow_steps" (
|
||||
"id" TEXT NOT NULL DEFAULT gen_random_uuid()::text,
|
||||
"workflow_id" TEXT NOT NULL,
|
||||
"step_order" INTEGER NOT NULL,
|
||||
"tool_code" VARCHAR NOT NULL,
|
||||
"tool_name" VARCHAR NOT NULL,
|
||||
"status" VARCHAR NOT NULL DEFAULT 'pending',
|
||||
"input_params" JSONB,
|
||||
"guardrail_checks" JSONB,
|
||||
"output_result" JSONB,
|
||||
"error_info" JSONB,
|
||||
"execution_ms" INTEGER,
|
||||
"started_at" TIMESTAMP(3),
|
||||
"completed_at" TIMESTAMP(3),
|
||||
|
||||
CONSTRAINT "ssa_workflow_steps_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "idx_ssa_workflow_step_workflow"
|
||||
ON "ssa_schema"."ssa_workflow_steps"("workflow_id");
|
||||
CREATE INDEX IF NOT EXISTS "idx_ssa_workflow_step_status"
|
||||
ON "ssa_schema"."ssa_workflow_steps"("status");
|
||||
|
||||
-- 外键:ssa_workflow_steps.workflow_id → ssa_workflows.id
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.table_constraints
|
||||
WHERE constraint_name = 'ssa_workflow_steps_workflow_id_fkey'
|
||||
) THEN
|
||||
ALTER TABLE "ssa_schema"."ssa_workflow_steps"
|
||||
ADD CONSTRAINT "ssa_workflow_steps_workflow_id_fkey"
|
||||
FOREIGN KEY ("workflow_id")
|
||||
REFERENCES "ssa_schema"."ssa_workflows"("id")
|
||||
ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- ============ rvw_schema: review_tasks 缺失列 ============
|
||||
|
||||
-- 8. review_tasks 后续 prisma db push 新增的 8 个列
|
||||
ALTER TABLE "rvw_schema"."review_tasks"
|
||||
ADD COLUMN IF NOT EXISTS "selected_agents" TEXT[] DEFAULT ARRAY['editorial','methodology'];
|
||||
ALTER TABLE "rvw_schema"."review_tasks"
|
||||
ADD COLUMN IF NOT EXISTS "editorial_score" DOUBLE PRECISION;
|
||||
ALTER TABLE "rvw_schema"."review_tasks"
|
||||
ADD COLUMN IF NOT EXISTS "methodology_score" DOUBLE PRECISION;
|
||||
ALTER TABLE "rvw_schema"."review_tasks"
|
||||
ADD COLUMN IF NOT EXISTS "methodology_status" TEXT;
|
||||
ALTER TABLE "rvw_schema"."review_tasks"
|
||||
ADD COLUMN IF NOT EXISTS "pico_extract" JSONB;
|
||||
ALTER TABLE "rvw_schema"."review_tasks"
|
||||
ADD COLUMN IF NOT EXISTS "context_data" JSONB;
|
||||
ALTER TABLE "rvw_schema"."review_tasks"
|
||||
ADD COLUMN IF NOT EXISTS "is_archived" BOOLEAN DEFAULT false;
|
||||
ALTER TABLE "rvw_schema"."review_tasks"
|
||||
ADD COLUMN IF NOT EXISTS "archived_at" TIMESTAMP(3);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "review_tasks_is_archived_idx"
|
||||
ON "rvw_schema"."review_tasks"("is_archived");
|
||||
Reference in New Issue
Block a user