Files
curriculum-project-hub/hub/prisma/migrations/20260707072854_init/migration.sql
T
hongjr03 e60aa43731 test(hub): integration 测试套件(13 tests,真 prisma+真 cph)
三层 integration,对齐 unit 层:
- trigger.test.ts: @bot→run→lock→release→card 全链路;权限拒绝(READ
  不能 triggerAgent ADR-0004);竞态 busy(ADR-0002);未绑定 chat 忽略
  (ADR-0001);无 @bot 忽略 —— 5 tests
- lock.test.ts: acquire/release 回环;排他性(同 project 二次 acquire 抛);
  WellFormed(终止 run 持锁即抛);release 幂等;isTerminal 对齐 spec —— 5 tests
- cph.test.ts: 真 cph binary 跑 TH-141 examples 的 check(exit 0)+
  build student PDF(exit 0)+ 空目录 check(非 0)—— 3 tests
helpers: resetDb(truncate CASCADE)、mockFeishuRuntime(记录 sentTexts/
  sentCards)、MockProvider(fixed stop 响应)、seedProject(project→user→grant)
prisma migrate dev init 生成初始 migration 并应用到 cph_hub_test 库。
vitest config 改 fileParallelism=false(integration 共享一 DB,串行避免
truncate/insert 竞态)。
vitest run 35/35(22 unit + 13 integration)通过;tsc rc=0。
2026-07-07 15:40:28 +08:00

272 lines
9.5 KiB
SQL

-- CreateEnum
CREATE TYPE "PlatformRole" AS ENUM ('ADMIN', 'TEACHER');
-- CreateEnum
CREATE TYPE "AgentRunStatus" AS ENUM ('ACTIVE', 'WAITING_FOR_USER', 'COMPLETED', 'FAILED', 'TIMED_OUT', 'CANCELED');
-- CreateEnum
CREATE TYPE "AgentEntrypoint" AS ENUM ('FEISHU', 'WEB', 'CLI');
-- CreateEnum
CREATE TYPE "PermissionRole" AS ENUM ('READ', 'EDIT', 'MANAGE');
-- CreateEnum
CREATE TYPE "PermissionResourceType" AS ENUM ('PROJECT', 'ARTIFACT', 'PROJECT_GROUP');
-- CreateTable
CREATE TABLE "User" (
"id" TEXT NOT NULL,
"feishuOpenId" TEXT NOT NULL,
"displayName" TEXT NOT NULL,
"avatarUrl" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "User_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "PlatformRoleAssignment" (
"id" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"role" "PlatformRole" NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"revokedAt" TIMESTAMP(3),
CONSTRAINT "PlatformRoleAssignment_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Project" (
"id" TEXT NOT NULL,
"name" TEXT NOT NULL,
"workspaceDir" TEXT NOT NULL,
"createdByUserId" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
"archivedAt" TIMESTAMP(3),
CONSTRAINT "Project_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "ProjectGroupBinding" (
"id" TEXT NOT NULL,
"projectId" TEXT NOT NULL,
"chatId" TEXT NOT NULL,
"createdByUserId" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "ProjectGroupBinding_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "AgentSession" (
"id" TEXT NOT NULL,
"projectId" TEXT NOT NULL,
"provider" TEXT NOT NULL,
"model" TEXT NOT NULL,
"title" TEXT,
"metadata" JSONB NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
"archivedAt" TIMESTAMP(3),
CONSTRAINT "AgentSession_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "AgentRun" (
"id" TEXT NOT NULL,
"projectId" TEXT NOT NULL,
"sessionId" TEXT,
"requestedByUserId" TEXT,
"entrypoint" "AgentEntrypoint" NOT NULL,
"status" "AgentRunStatus" NOT NULL DEFAULT 'ACTIVE',
"prompt" TEXT NOT NULL,
"model" TEXT NOT NULL,
"provider" TEXT NOT NULL,
"summary" TEXT,
"inputTokens" INTEGER,
"outputTokens" INTEGER,
"metadata" JSONB NOT NULL,
"error" TEXT,
"startedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"finishedAt" TIMESTAMP(3),
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "AgentRun_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "ProjectAgentLock" (
"projectId" TEXT NOT NULL,
"runId" TEXT NOT NULL,
"holderUserId" TEXT,
"acquiredAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"expiresAt" TIMESTAMP(3),
CONSTRAINT "ProjectAgentLock_pkey" PRIMARY KEY ("projectId")
);
-- CreateTable
CREATE TABLE "PermissionGrant" (
"id" TEXT NOT NULL,
"resourceType" "PermissionResourceType" NOT NULL,
"resourceId" TEXT NOT NULL,
"principal" TEXT NOT NULL,
"role" "PermissionRole" NOT NULL,
"createdByUserId" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"revokedAt" TIMESTAMP(3),
CONSTRAINT "PermissionGrant_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "PermissionSettings" (
"id" TEXT NOT NULL,
"resourceType" "PermissionResourceType" NOT NULL,
"resourceId" TEXT NOT NULL,
"externalShare" TEXT NOT NULL,
"comment" TEXT NOT NULL,
"copyDownload" TEXT NOT NULL,
"collaboratorMgmt" TEXT NOT NULL,
"agentTrigger" TEXT NOT NULL,
"agentCancel" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "PermissionSettings_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "AuditEntry" (
"id" TEXT NOT NULL,
"runId" TEXT,
"actorUserId" TEXT,
"action" TEXT NOT NULL,
"metadata" JSONB NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "AuditEntry_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "User_feishuOpenId_key" ON "User"("feishuOpenId");
-- CreateIndex
CREATE INDEX "PlatformRoleAssignment_userId_revokedAt_idx" ON "PlatformRoleAssignment"("userId", "revokedAt");
-- CreateIndex
CREATE INDEX "PlatformRoleAssignment_role_revokedAt_idx" ON "PlatformRoleAssignment"("role", "revokedAt");
-- CreateIndex
CREATE INDEX "Project_archivedAt_idx" ON "Project"("archivedAt");
-- CreateIndex
CREATE UNIQUE INDEX "ProjectGroupBinding_projectId_key" ON "ProjectGroupBinding"("projectId");
-- CreateIndex
CREATE UNIQUE INDEX "ProjectGroupBinding_chatId_key" ON "ProjectGroupBinding"("chatId");
-- CreateIndex
CREATE INDEX "ProjectGroupBinding_chatId_idx" ON "ProjectGroupBinding"("chatId");
-- CreateIndex
CREATE INDEX "AgentSession_projectId_archivedAt_idx" ON "AgentSession"("projectId", "archivedAt");
-- CreateIndex
CREATE INDEX "AgentSession_provider_model_idx" ON "AgentSession"("provider", "model");
-- CreateIndex
CREATE INDEX "AgentSession_updatedAt_idx" ON "AgentSession"("updatedAt");
-- CreateIndex
CREATE INDEX "AgentRun_projectId_status_idx" ON "AgentRun"("projectId", "status");
-- CreateIndex
CREATE INDEX "AgentRun_sessionId_idx" ON "AgentRun"("sessionId");
-- CreateIndex
CREATE INDEX "AgentRun_requestedByUserId_idx" ON "AgentRun"("requestedByUserId");
-- CreateIndex
CREATE INDEX "AgentRun_updatedAt_idx" ON "AgentRun"("updatedAt");
-- CreateIndex
CREATE UNIQUE INDEX "ProjectAgentLock_runId_key" ON "ProjectAgentLock"("runId");
-- CreateIndex
CREATE INDEX "ProjectAgentLock_expiresAt_idx" ON "ProjectAgentLock"("expiresAt");
-- CreateIndex
CREATE INDEX "PermissionGrant_resourceType_resourceId_revokedAt_idx" ON "PermissionGrant"("resourceType", "resourceId", "revokedAt");
-- CreateIndex
CREATE INDEX "PermissionGrant_principal_revokedAt_idx" ON "PermissionGrant"("principal", "revokedAt");
-- CreateIndex
CREATE UNIQUE INDEX "PermissionGrant_resourceType_resourceId_principal_role_revo_key" ON "PermissionGrant"("resourceType", "resourceId", "principal", "role", "revokedAt");
-- CreateIndex
CREATE INDEX "PermissionSettings_resourceType_resourceId_idx" ON "PermissionSettings"("resourceType", "resourceId");
-- CreateIndex
CREATE UNIQUE INDEX "PermissionSettings_resourceType_resourceId_key" ON "PermissionSettings"("resourceType", "resourceId");
-- CreateIndex
CREATE INDEX "AuditEntry_runId_idx" ON "AuditEntry"("runId");
-- CreateIndex
CREATE INDEX "AuditEntry_actorUserId_idx" ON "AuditEntry"("actorUserId");
-- CreateIndex
CREATE INDEX "AuditEntry_createdAt_idx" ON "AuditEntry"("createdAt");
-- AddForeignKey
ALTER TABLE "PlatformRoleAssignment" ADD CONSTRAINT "PlatformRoleAssignment_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Project" ADD CONSTRAINT "Project_createdByUserId_fkey" FOREIGN KEY ("createdByUserId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "ProjectGroupBinding" ADD CONSTRAINT "ProjectGroupBinding_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "ProjectGroupBinding" ADD CONSTRAINT "ProjectGroupBinding_createdByUserId_fkey" FOREIGN KEY ("createdByUserId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "AgentSession" ADD CONSTRAINT "AgentSession_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "AgentRun" ADD CONSTRAINT "AgentRun_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "AgentRun" ADD CONSTRAINT "AgentRun_sessionId_fkey" FOREIGN KEY ("sessionId") REFERENCES "AgentSession"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "AgentRun" ADD CONSTRAINT "AgentRun_requestedByUserId_fkey" FOREIGN KEY ("requestedByUserId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "ProjectAgentLock" ADD CONSTRAINT "ProjectAgentLock_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "ProjectAgentLock" ADD CONSTRAINT "ProjectAgentLock_runId_fkey" FOREIGN KEY ("runId") REFERENCES "AgentRun"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "ProjectAgentLock" ADD CONSTRAINT "ProjectAgentLock_holderUserId_fkey" FOREIGN KEY ("holderUserId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "PermissionGrant" ADD CONSTRAINT "PermissionGrant_resourceId_fkey" FOREIGN KEY ("resourceId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "PermissionGrant" ADD CONSTRAINT "PermissionGrant_createdByUserId_fkey" FOREIGN KEY ("createdByUserId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "PermissionSettings" ADD CONSTRAINT "PermissionSettings_resourceId_fkey" FOREIGN KEY ("resourceId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "AuditEntry" ADD CONSTRAINT "AuditEntry_actorUserId_fkey" FOREIGN KEY ("actorUserId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;