Commit 910ebbc5 by luoqi

chore(db): consolidate 14 migrations into single 20260526000000_init

合并 W3 之前所有增量 migration 为单文件 init,便于 fresh deploy。
旧 migration 已在 dev 环境跑过;prod 首次部署直接走 init。
parent 7758f537
-- Remove deprecated Platform.field_mapping column.
-- AssemblerEngine + per-host assembler.yaml(`apps/pac-service/data/<host>/assemblers/*.yaml`)
-- 已完全替代该字段;保留它只会让 v1 / v2 模型混淆。
ALTER TABLE "platforms" DROP COLUMN IF EXISTS "field_mapping";
-- Plan 模型重构:patient-级 plan + scenario-级 plan_reasons 子表
-- 对应 db-review-confirm §1:plan 1:N reason
--
-- 旧:followup_plans 含 scenario / inclusion_reason / evidence 字段,
-- partial UNIQUE on (platform_id, tenant_id, patient_id, scenario) WHERE status active/assigned
-- 新:followup_plans 只剩触达决策字段,scenario 维度移到 plan_reasons,
-- partial UNIQUE on (platform_id, tenant_id, patient_id) WHERE status active/assigned
-- 1) FollowupPlan: 移除字段 + 改 UNIQUE
ALTER TABLE "followup_plans"
DROP COLUMN IF EXISTS "scenario",
DROP COLUMN IF EXISTS "inclusion_reason",
DROP COLUMN IF EXISTS "evidence",
ADD COLUMN IF NOT EXISTS "contact_attempts" INT NOT NULL DEFAULT 0;
-- 删旧 UNIQUE/索引(若存在),换新 UNIQUE 不含 scenario
DROP INDEX IF EXISTS "followup_plans_platform_id_tenant_id_patient_id_scenario_ver_key";
DROP INDEX IF EXISTS "followup_plans_scenario_status_idx";
DROP INDEX IF EXISTS "followup_plans_active_per_patient_scenario_idx";
-- 新 UNIQUE: (platform_id, tenant_id, patient_id, version)
ALTER TABLE "followup_plans"
ADD CONSTRAINT "followup_plans_platform_id_tenant_id_patient_id_version_key"
UNIQUE ("platform_id", "tenant_id", "patient_id", "version");
-- 新 partial UNIQUE:patient 级 single-active(不再含 scenario)
CREATE UNIQUE INDEX IF NOT EXISTS "followup_plans_active_per_patient_idx"
ON "followup_plans" ("platform_id", "tenant_id", "patient_id")
WHERE "status" IN ('active', 'assigned');
-- 2) PlanReason 子表
CREATE TABLE IF NOT EXISTS "plan_reasons" (
"id" UUID PRIMARY KEY DEFAULT gen_random_uuid(),
"plan_id" UUID NOT NULL REFERENCES "followup_plans"("id") ON DELETE CASCADE,
"scenario" TEXT NOT NULL,
"priority_score" DOUBLE PRECISION NOT NULL,
"reason" TEXT NOT NULL,
"evidence_fact_ids" UUID[] NOT NULL DEFAULT '{}',
"created_at" TIMESTAMPTZ(3) NOT NULL DEFAULT now(),
"updated_at" TIMESTAMPTZ(3) NOT NULL,
CONSTRAINT "plan_reasons_plan_id_scenario_key" UNIQUE ("plan_id", "scenario")
);
CREATE INDEX IF NOT EXISTS "plan_reasons_scenario_idx" ON "plan_reasons" ("scenario");
CREATE INDEX IF NOT EXISTS "plan_reasons_evidence_gin_idx" ON "plan_reasons" USING GIN ("evidence_fact_ids");
-- 产品收集字段(回访中心信息字段.docx 吸收)
-- 1) Patient: tags + primary_contact_type
-- 2) PlanReason: lifecycle / source / source_actor_id / campaign_id / closed_reason / closed_at + index
-- 3) PlanExecution: invalid_reason
-- 1) Patient
ALTER TABLE "patients"
ADD COLUMN IF NOT EXISTS "tags" TEXT[] NOT NULL DEFAULT '{}',
ADD COLUMN IF NOT EXISTS "primary_contact_type" TEXT;
-- 2) PlanReason
ALTER TABLE "plan_reasons"
ADD COLUMN IF NOT EXISTS "lifecycle" TEXT NOT NULL DEFAULT 'one_shot',
ADD COLUMN IF NOT EXISTS "source" TEXT NOT NULL DEFAULT 'algorithm',
ADD COLUMN IF NOT EXISTS "source_actor_id" TEXT,
ADD COLUMN IF NOT EXISTS "campaign_id" TEXT,
ADD COLUMN IF NOT EXISTS "closed_reason" TEXT,
ADD COLUMN IF NOT EXISTS "closed_at" TIMESTAMPTZ(3);
CREATE INDEX IF NOT EXISTS "plan_reasons_campaign_id_idx" ON "plan_reasons" ("campaign_id");
-- 3) PlanExecution
ALTER TABLE "plan_executions"
ADD COLUMN IF NOT EXISTS "invalid_reason" TEXT;
-- 大重命名:platform → host(表 + 列)+ Patient 重构 + PatientProfile 副表 + fact_type 清理
-- 1) 重命名 platforms 表
ALTER TABLE "platforms" RENAME TO "hosts";
-- 2) 重命名 platform_id 列 → host_id(子表 12 个)
ALTER TABLE "patients" RENAME COLUMN "platform_id" TO "host_id";
ALTER TABLE "patient_transactions" RENAME COLUMN "platform_id" TO "host_id";
ALTER TABLE "patient_facts" RENAME COLUMN "platform_id" TO "host_id";
ALTER TABLE "personas" RENAME COLUMN "platform_id" TO "host_id";
ALTER TABLE "persona_recompute_logs" RENAME COLUMN "platform_id" TO "host_id";
ALTER TABLE "followup_plans" RENAME COLUMN "platform_id" TO "host_id";
ALTER TABLE "plan_scripts" RENAME COLUMN "platform_id" TO "host_id";
ALTER TABLE "plan_summaries" RENAME COLUMN "platform_id" TO "host_id";
ALTER TABLE "plan_executions" RENAME COLUMN "platform_id" TO "host_id";
ALTER TABLE "plan_generation_logs" RENAME COLUMN "platform_id" TO "host_id";
ALTER TABLE "agent_invocations" RENAME COLUMN "platform_id" TO "host_id";
ALTER TABLE "sync_logs" RENAME COLUMN "platform_id" TO "host_id";
-- 3) Patient 重构:删 status/合规/标签/merge 字段,加 active
ALTER TABLE "patients"
DROP COLUMN IF EXISTS "status",
DROP COLUMN IF EXISTS "merged_into_id",
DROP COLUMN IF EXISTS "do_not_contact",
DROP COLUMN IF EXISTS "do_not_contact_reason",
DROP COLUMN IF EXISTS "do_not_contact_at",
DROP COLUMN IF EXISTS "deceased",
DROP COLUMN IF EXISTS "deceased_at",
DROP COLUMN IF EXISTS "tags",
DROP COLUMN IF EXISTS "primary_contact_type",
ADD COLUMN IF NOT EXISTS "active" BOOLEAN NOT NULL DEFAULT TRUE;
-- 旧召回池索引含已删字段,重建
DROP INDEX IF EXISTS "patients_platform_id_tenant_id_status_do_not_contact_deceas_idx";
DROP INDEX IF EXISTS "patients_host_id_tenant_id_status_do_not_contact_deceased_idx";
CREATE INDEX IF NOT EXISTS "patients_host_id_tenant_id_active_idx"
ON "patients" ("host_id", "tenant_id", "active");
-- 4) PatientProfile 副表(1:1)
CREATE TABLE IF NOT EXISTS "patient_profiles" (
"patient_id" UUID PRIMARY KEY REFERENCES "patients"("id") ON DELETE CASCADE,
"do_not_contact" BOOLEAN NOT NULL DEFAULT FALSE,
"do_not_contact_reason" TEXT,
"do_not_contact_at" TIMESTAMPTZ(3),
"deceased" BOOLEAN NOT NULL DEFAULT FALSE,
"deceased_at" TIMESTAMPTZ(3),
"tags" TEXT[] NOT NULL DEFAULT '{}',
"notes" TEXT,
"primary_contact_type" TEXT,
"created_at" TIMESTAMPTZ(3) NOT NULL DEFAULT now(),
"updated_at" TIMESTAMPTZ(3) NOT NULL
);
CREATE INDEX IF NOT EXISTS "patient_profiles_do_not_contact_idx" ON "patient_profiles" ("do_not_contact");
CREATE INDEX IF NOT EXISTS "patient_profiles_deceased_idx" ON "patient_profiles" ("deceased");
-- 5) fact_type 清理:删 6 个衍生类 + 重命名 charge_order_record → order_record + appointment_plan → appointment_record
-- 由于 dev mock 数据,直接删 fact 行而非 transform
DELETE FROM "patient_facts"
WHERE "type" IN ('diagnosis_record', 'treatment_record', 'treatment_plan',
'review_plan', 'payment_plan');
UPDATE "patient_facts" SET "type" = 'order_record' WHERE "type" = 'charge_order_record';
UPDATE "patient_facts" SET "type" = 'appointment_record' WHERE "type" = 'appointment_plan';
-- 6) action / subjectType 重命名
UPDATE "patient_transactions" SET "action" = 'order_submitted' WHERE "action" = 'charge_order_submitted';
UPDATE "patient_transactions" SET "subject_type" = 'order' WHERE "subject_type" = 'charge_order';
/*
Warnings:
- You are about to drop the column `triggered_by` on the `personas` table. All the data in the column will be lost.
- Added the required column `source` to the `personas` table without a default value. This is not possible if the table is not empty.
*/
-- DropForeignKey
ALTER TABLE "patient_profiles" DROP CONSTRAINT "patient_profiles_patient_id_fkey";
-- DropForeignKey
ALTER TABLE "plan_reasons" DROP CONSTRAINT "plan_reasons_plan_id_fkey";
-- DropIndex
DROP INDEX "patient_facts_transaction_ids_gin";
-- DropIndex
DROP INDEX "plan_reasons_evidence_gin_idx";
-- AlterTable
ALTER TABLE "hosts" RENAME CONSTRAINT "platforms_pkey" TO "hosts_pkey";
-- AlterTable
ALTER TABLE "personas" DROP COLUMN "triggered_by",
ADD COLUMN "source" TEXT NOT NULL;
-- AlterTable
ALTER TABLE "plan_reasons" ALTER COLUMN "id" DROP DEFAULT,
ALTER COLUMN "evidence_fact_ids" DROP DEFAULT;
-- RenameForeignKey
ALTER TABLE "agent_invocations" RENAME CONSTRAINT "agent_invocations_platform_id_fkey" TO "agent_invocations_host_id_fkey";
-- RenameForeignKey
ALTER TABLE "followup_plans" RENAME CONSTRAINT "followup_plans_platform_id_fkey" TO "followup_plans_host_id_fkey";
-- RenameForeignKey
ALTER TABLE "patient_facts" RENAME CONSTRAINT "patient_facts_platform_id_fkey" TO "patient_facts_host_id_fkey";
-- RenameForeignKey
ALTER TABLE "patient_transactions" RENAME CONSTRAINT "patient_transactions_platform_id_fkey" TO "patient_transactions_host_id_fkey";
-- RenameForeignKey
ALTER TABLE "patients" RENAME CONSTRAINT "patients_platform_id_fkey" TO "patients_host_id_fkey";
-- RenameForeignKey
ALTER TABLE "persona_recompute_logs" RENAME CONSTRAINT "persona_recompute_logs_platform_id_fkey" TO "persona_recompute_logs_host_id_fkey";
-- RenameForeignKey
ALTER TABLE "personas" RENAME CONSTRAINT "personas_platform_id_fkey" TO "personas_host_id_fkey";
-- RenameForeignKey
ALTER TABLE "plan_executions" RENAME CONSTRAINT "plan_executions_platform_id_fkey" TO "plan_executions_host_id_fkey";
-- RenameForeignKey
ALTER TABLE "plan_generation_logs" RENAME CONSTRAINT "plan_generation_logs_platform_id_fkey" TO "plan_generation_logs_host_id_fkey";
-- RenameForeignKey
ALTER TABLE "plan_scripts" RENAME CONSTRAINT "plan_scripts_platform_id_fkey" TO "plan_scripts_host_id_fkey";
-- RenameForeignKey
ALTER TABLE "plan_summaries" RENAME CONSTRAINT "plan_summaries_platform_id_fkey" TO "plan_summaries_host_id_fkey";
-- RenameForeignKey
ALTER TABLE "sync_logs" RENAME CONSTRAINT "sync_logs_platform_id_fkey" TO "sync_logs_host_id_fkey";
-- AddForeignKey
ALTER TABLE "patient_profiles" ADD CONSTRAINT "patient_profiles_patient_id_fkey" FOREIGN KEY ("patient_id") REFERENCES "patients"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "plan_reasons" ADD CONSTRAINT "plan_reasons_plan_id_fkey" FOREIGN KEY ("plan_id") REFERENCES "followup_plans"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- RenameIndex
ALTER INDEX "agent_invocations_platform_id_tenant_id_idx" RENAME TO "agent_invocations_host_id_tenant_id_idx";
-- RenameIndex
ALTER INDEX "followup_plans_platform_id_tenant_id_idx" RENAME TO "followup_plans_host_id_tenant_id_idx";
-- RenameIndex
ALTER INDEX "followup_plans_platform_id_tenant_id_patient_id_version_key" RENAME TO "followup_plans_host_id_tenant_id_patient_id_version_key";
-- RenameIndex
ALTER INDEX "followup_plans_platform_id_tenant_id_target_clinic_id_idx" RENAME TO "followup_plans_host_id_tenant_id_target_clinic_id_idx";
-- RenameIndex
ALTER INDEX "platforms_app_id_key" RENAME TO "hosts_app_id_key";
-- RenameIndex
ALTER INDEX "platforms_name_key" RENAME TO "hosts_name_key";
-- RenameIndex
ALTER INDEX "patient_facts_platform_id_tenant_id_idx" RENAME TO "patient_facts_host_id_tenant_id_idx";
-- RenameIndex
ALTER INDEX "patient_facts_platform_id_tenant_id_subject_id_version_key" RENAME TO "patient_facts_host_id_tenant_id_subject_id_version_key";
-- RenameIndex
ALTER INDEX "patient_transactions_platform_id_tenant_id_clinic_id_idx" RENAME TO "patient_transactions_host_id_tenant_id_clinic_id_idx";
-- RenameIndex
ALTER INDEX "patients_platform_id_tenant_id_external_id_key" RENAME TO "patients_host_id_tenant_id_external_id_key";
-- RenameIndex
ALTER INDEX "patients_platform_id_tenant_id_idx" RENAME TO "patients_host_id_tenant_id_idx";
-- RenameIndex
ALTER INDEX "persona_recompute_logs_platform_id_tenant_id_idx" RENAME TO "persona_recompute_logs_host_id_tenant_id_idx";
-- RenameIndex
ALTER INDEX "personas_platform_id_tenant_id_idx" RENAME TO "personas_host_id_tenant_id_idx";
-- RenameIndex
ALTER INDEX "plan_executions_platform_id_tenant_id_executor_clinic_id_idx" RENAME TO "plan_executions_host_id_tenant_id_executor_clinic_id_idx";
-- RenameIndex
ALTER INDEX "plan_generation_logs_platform_id_tenant_id_idx" RENAME TO "plan_generation_logs_host_id_tenant_id_idx";
-- RenameIndex
ALTER INDEX "plan_scripts_platform_id_tenant_id_idx" RENAME TO "plan_scripts_host_id_tenant_id_idx";
-- RenameIndex
ALTER INDEX "plan_summaries_platform_id_tenant_id_idx" RENAME TO "plan_summaries_host_id_tenant_id_idx";
-- RenameIndex
ALTER INDEX "sync_logs_platform_id_tenant_id_resource_idx" RENAME TO "sync_logs_host_id_tenant_id_resource_idx";
/*
Warnings:
- You are about to drop the column `agent_version` on the `agent_invocations` table. All the data in the column will be lost.
- You are about to drop the column `gateway_provider` on the `agent_invocations` table. All the data in the column will be lost.
- You are about to drop the column `workflow_id` on the `agent_invocations` table. All the data in the column will be lost.
- Added the required column `input_hash` to the `agent_invocations` table without a default value. This is not possible if the table is not empty.
- Added the required column `model_provider` to the `agent_invocations` table without a default value. This is not possible if the table is not empty.
- Added the required column `prompt_version` to the `agent_invocations` table without a default value. This is not possible if the table is not empty.
- Added the required column `skill_key` to the `agent_invocations` table without a default value. This is not possible if the table is not empty.
- Added the required column `workflow_run_id` to the `agent_invocations` table without a default value. This is not possible if the table is not empty.
- Made the column `model_name` on table `agent_invocations` required. This step will fail if there are existing NULL values in that column.
*/
-- AlterTable
ALTER TABLE "agent_invocations" DROP COLUMN "agent_version",
DROP COLUMN "gateway_provider",
DROP COLUMN "workflow_id",
ADD COLUMN "cache_hit" BOOLEAN NOT NULL DEFAULT false,
ADD COLUMN "eval_mode" TEXT NOT NULL DEFAULT 'production',
ADD COLUMN "golden_set_case_id" TEXT,
ADD COLUMN "input_hash" TEXT NOT NULL,
ADD COLUMN "judge_rubric" JSONB,
ADD COLUMN "judge_score" DECIMAL(3,2),
ADD COLUMN "model_provider" TEXT NOT NULL,
ADD COLUMN "parent_invocation_id" UUID,
ADD COLUMN "prompt_version" TEXT NOT NULL,
ADD COLUMN "skill_key" TEXT NOT NULL,
ADD COLUMN "workflow_run_id" UUID NOT NULL,
ALTER COLUMN "model_name" SET NOT NULL;
-- CreateIndex
CREATE INDEX "agent_invocations_skill_key_prompt_version_started_at_idx" ON "agent_invocations"("skill_key", "prompt_version", "started_at");
-- CreateIndex
CREATE INDEX "agent_invocations_workflow_run_id_idx" ON "agent_invocations"("workflow_run_id");
-- CreateIndex
CREATE INDEX "agent_invocations_parent_invocation_id_idx" ON "agent_invocations"("parent_invocation_id");
-- CreateIndex
CREATE INDEX "agent_invocations_input_hash_idx" ON "agent_invocations"("input_hash");
-- CreateIndex
CREATE INDEX "agent_invocations_eval_mode_skill_key_idx" ON "agent_invocations"("eval_mode", "skill_key");
-- Rename agent_invocations.skill_key -> call_key
-- (词义对齐:Anthropic Agent Skills 是另一回事 — md 文件 + 渐进式披露;
-- 我们这里只是"一次 LLM 调用配方",改名 call_key 避免混淆。)
-- Drop old indexes that reference skill_key
DROP INDEX IF EXISTS "agent_invocations_skill_key_prompt_version_started_at_idx";
DROP INDEX IF EXISTS "agent_invocations_eval_mode_skill_key_idx";
-- Rename column
ALTER TABLE "agent_invocations" RENAME COLUMN "skill_key" TO "call_key";
-- Recreate indexes with new column name
CREATE INDEX "agent_invocations_call_key_prompt_version_started_at_idx"
ON "agent_invocations"("call_key", "prompt_version", "started_at");
CREATE INDEX "agent_invocations_eval_mode_call_key_idx"
ON "agent_invocations"("eval_mode", "call_key");
-- agent_invocations.cost_cents (Int 分) → cost_yuan (Decimal 元 6 位小数)
-- 原因:单次 LLM 调用成本常 <0.01 分(如 ¥0.0034),Int 分粒度全归零,仪表盘看不出差异。
ALTER TABLE "agent_invocations"
ADD COLUMN "cost_yuan" NUMERIC(12, 6) NOT NULL DEFAULT 0;
-- 历史数据搬迁:cost_cents (Int 分) → cost_yuan (¥) = cost_cents / 100
UPDATE "agent_invocations" SET "cost_yuan" = "cost_cents"::numeric / 100;
ALTER TABLE "agent_invocations" DROP COLUMN "cost_cents";
-- AlterTable
ALTER TABLE "agent_invocations" ADD COLUMN "cached_input_tokens" INTEGER NOT NULL DEFAULT 0,
ADD COLUMN "reasoning_tokens" INTEGER NOT NULL DEFAULT 0;
-- AlterTable
ALTER TABLE "patient_transactions" ADD COLUMN "canonical_payload" JSONB;
-- AlterTable
ALTER TABLE "plan_reasons" ADD COLUMN "breakdown" JSONB;
-- AlterTable
ALTER TABLE "followup_plans" ADD COLUMN "goal" TEXT;
-- AlterTable
ALTER TABLE "patients" ADD COLUMN "medical_record_number" TEXT;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment