feat(shared): A6 任务协议契约、任务数据模型与系统配置

背景:A6 任务中心需要统一任务协议(九态状态机 / 队列映射 / SSE 事件)与任务落库模型,供 API、worker 与前端共用,避免各端自建枚举。
改动:
- 新增 packages/shared/src/tasks/task-protocol.ts:任务类型、架构 §3.6 九态与允许迁移、5 组 9 队列定义、Outbox/SSE 事件、进度与收敛纯函数;
- 新增 packages/shared/src/schemas/tasks.ts:提交/列表/详情/取消/重试/SSE 的 Zod DTO(body camelCase、query snake_case,列表 { items, next_cursor });
- system_configs 新增 task 分组(演练上限 20 项 / 单条成本 0.02 元 / 单条时长 3 秒),seed 按定义幂等;
- Prisma 新增 media_tasks / media_items / task_events 三表与迁移 20261104125003_a6_media_tasks(expand-only,不改旧表)。
影响面:仅新增 shared 导出、配置项与三张新表,旧接口与旧表不受影响。
回滚:撤销提交,并对三张新表执行 prisma migrate resolve/删除(无业务数据)。
验证:shared 197 tests 全绿;typecheck / lint / format:check 全绿;prisma migrate status up to date。
This commit is contained in:
Stev_Wang committed 2026-11-04 21:52:12 +08:00
1 parent b505dfe5e3
commit 4a29cf815e
8 files changed
+1267

No files matched your search

@@ -0,0 +1,93 @@
-- CreateTable
CREATE TABLE "media_tasks" (
"id" CHAR(26) NOT NULL,
"type" VARCHAR(16) NOT NULL,
"status" VARCHAR(24) NOT NULL DEFAULT 'queued',
"title" VARCHAR(200) NOT NULL,
"customer_id" CHAR(26) NOT NULL,
"customer_name" VARCHAR(128) NOT NULL,
"created_by" CHAR(26) NOT NULL,
"created_by_name" VARCHAR(64) NOT NULL,
"item_total" INTEGER NOT NULL,
"item_succeeded" INTEGER NOT NULL DEFAULT 0,
"item_failed" INTEGER NOT NULL DEFAULT 0,
"item_skipped" INTEGER NOT NULL DEFAULT 0,
"estimated_items" INTEGER NOT NULL,
"estimated_cost" DECIMAL(14,4) NOT NULL,
"estimated_seconds" INTEGER NOT NULL,
"progress" INTEGER NOT NULL DEFAULT 0,
"payload_json" JSONB NOT NULL,
"cancel_requested_at" TIMESTAMPTZ(3),
"canceled_at" TIMESTAMPTZ(3),
"canceled_by" CHAR(26),
"last_error_code" VARCHAR(32),
"last_error_message" VARCHAR(500),
"started_at" TIMESTAMPTZ(3),
"finished_at" TIMESTAMPTZ(3),
"created_at" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMPTZ(3) NOT NULL,
CONSTRAINT "media_tasks_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "media_items" (
"id" CHAR(26) NOT NULL,
"task_id" CHAR(26) NOT NULL,
"seq" INTEGER NOT NULL,
"status" VARCHAR(24) NOT NULL DEFAULT 'queued',
"failure_code" VARCHAR(64),
"failure_message" VARCHAR(500),
"attempts" INTEGER NOT NULL DEFAULT 0,
"started_at" TIMESTAMPTZ(3),
"finished_at" TIMESTAMPTZ(3),
"created_at" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMPTZ(3) NOT NULL,
CONSTRAINT "media_items_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "task_events" (
"id" CHAR(26) NOT NULL,
"task_id" CHAR(26) NOT NULL,
"seq" BIGSERIAL NOT NULL,
"event_type" VARCHAR(16) NOT NULL,
"payload_json" JSONB NOT NULL,
"created_at" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "task_events_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE INDEX "media_tasks_customer_id_created_at_idx" ON "media_tasks"("customer_id", "created_at" DESC);
-- CreateIndex
CREATE INDEX "media_tasks_status_created_at_idx" ON "media_tasks"("status", "created_at" DESC);
-- CreateIndex
CREATE INDEX "media_tasks_type_created_at_idx" ON "media_tasks"("type", "created_at" DESC);
-- CreateIndex
CREATE INDEX "media_tasks_created_by_created_at_idx" ON "media_tasks"("created_by", "created_at" DESC);
-- CreateIndex
CREATE INDEX "media_items_task_id_status_idx" ON "media_items"("task_id", "status");
-- CreateIndex
CREATE INDEX "media_items_status_idx" ON "media_items"("status");
-- CreateIndex
CREATE UNIQUE INDEX "media_items_task_id_seq_key" ON "media_items"("task_id", "seq");
-- CreateIndex
CREATE UNIQUE INDEX "task_events_seq_key" ON "task_events"("seq");
-- CreateIndex
CREATE INDEX "task_events_task_id_seq_idx" ON "task_events"("task_id", "seq");
-- AddForeignKey
ALTER TABLE "media_items" ADD CONSTRAINT "media_items_task_id_fkey" FOREIGN KEY ("task_id") REFERENCES "media_tasks"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "task_events" ADD CONSTRAINT "task_events_task_id_fkey" FOREIGN KEY ("task_id") REFERENCES "media_tasks"("id") ON DELETE CASCADE ON UPDATE CASCADE;