refactor(data): 收口关系表运行时数据源
Some checks failed
Deploy Production / Build, push, deploy, verify (push) Has been cancelled

- 移除已迁移业务 AppData 运行时 fallback,改走领域 API 和关系表快读
- 补齐需求产品负责人、版本计划任务 JSON 和成员 username 回填迁移
- 统一治理字典入口,并补充 AI provider、数据源契约和领域服务测试

Co-Authored-By: Codex GPT-5 <codex@openai.com>
This commit is contained in:
2026-07-09 14:59:49 +08:00
parent 1e6fb0c7aa
commit 2e595c7e72
98 changed files with 2938 additions and 1441 deletions

View File

@@ -0,0 +1,9 @@
ALTER TABLE "requirements" ADD COLUMN "product_owner_id" TEXT;
ALTER TABLE "requirements"
ADD CONSTRAINT "requirements_product_owner_id_fkey"
FOREIGN KEY ("product_owner_id") REFERENCES "users"("id")
ON DELETE SET NULL ON UPDATE CASCADE;
CREATE INDEX "requirements_product_owner_created_at_idx"
ON "requirements"("product_owner_id", "created_at" DESC);

View File

@@ -0,0 +1,48 @@
WITH raw_members AS (
SELECT member
FROM app_data
CROSS JOIN LATERAL jsonb_array_elements(
CASE
WHEN jsonb_typeof(value -> 'members') = 'array' THEN value -> 'members'
ELSE '[]'::jsonb
END
) AS member
WHERE key = 'members'
),
members AS (
SELECT
NULLIF(member ->> 'id', '') AS id,
NULLIF(member ->> 'username', '') AS username,
NULLIF(member ->> 'departmentId', '') AS department_id,
NULLIF(member ->> 'roleId', '') AS role_id,
COALESCE(member ->> 'phone', '') AS phone,
COALESCE(member ->> 'password', '') AS password,
CASE
WHEN jsonb_typeof(member -> 'isSystem') = 'boolean' THEN (member ->> 'isSystem')::boolean
ELSE NULL
END AS is_system,
COUNT(*) OVER (PARTITION BY NULLIF(member ->> 'username', '')) AS username_count
FROM raw_members
)
UPDATE users AS u
SET
username = CASE
WHEN NULLIF(u.username, '') IS NULL
AND m.username IS NOT NULL
AND m.username_count = 1
AND NOT EXISTS (
SELECT 1
FROM users AS other_user
WHERE other_user.id <> u.id
AND other_user.username = m.username
)
THEN m.username
ELSE u.username
END,
department_id = COALESCE(m.department_id, u.department_id),
role_id = COALESCE(m.role_id, u.role_id, 'member'),
phone = COALESCE(m.phone, u.phone, ''),
password = COALESCE(m.password, u.password, ''),
is_system = COALESCE(m.is_system, u.is_system, false)
FROM members AS m
WHERE u.id = m.id;

View File

@@ -0,0 +1,2 @@
ALTER TABLE "version_plans"
ADD COLUMN IF NOT EXISTS "tasks" JSONB NOT NULL DEFAULT '[]';

View File

@@ -24,7 +24,8 @@ model User {
createdTasks Task[] @relation("TaskCreator")
assignedTasks Task[] @relation("TaskAssignee")
projectMembers ProjectMember[]
requirements Requirement[]
requirements Requirement[] @relation("RequirementCreator")
productOwnedRequirements Requirement[] @relation("RequirementProductOwner")
watchedTasks TaskWatcher[]
@@map("users")
@@ -116,11 +117,13 @@ model Requirement {
sourceTarget String? @map("source_target")
platform String?
creatorId String? @map("creator_id")
productOwnerId String? @map("product_owner_id")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
product Product @relation(fields: [productId], references: [id])
creator User? @relation(fields: [creatorId], references: [id])
creator User? @relation("RequirementCreator", fields: [creatorId], references: [id])
productOwner User? @relation("RequirementProductOwner", fields: [productOwnerId], references: [id])
@@id([id, productId])
@@unique([productId, code])
@@ -290,6 +293,7 @@ model VersionPlan {
actualStartAt DateTime? @map("actual_start_at")
completedAt DateTime? @map("completed_at")
resultUrl String? @map("result_url")
tasks Json @default("[]")
requirementCoverage Json @default("[]") @map("requirement_coverage")
logs Json @default("[]")
createdAt DateTime @default(now()) @map("created_at")