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

@@ -1,7 +1,7 @@
'use client';
import { create } from 'zustand';
import type { DevTask, DevTaskStatus } from '@/lib/dev-task';
import { generateTaskNo, isLegacyTask } from '@/lib/dev-task';
import { generateTaskNo } from '@/lib/dev-task';
import { applyDevTaskTransition, normalizeDevTaskOnCreate } from '@/lib/dev-task-workflow';
import {
createDevTaskByVersionId,
@@ -11,9 +11,9 @@ import {
updateDevTaskByVersionId,
updateDevTaskStatusByVersionId,
} from '@/lib/domain-api';
import { createEntityId, dedupeEntityIds } from '@/lib/entity-id';
import { createEntityId } from '@/lib/entity-id';
import { scheduleSaveWithOptimisticRollback } from '@/lib/optimistic-persistence';
import { loadServerData, saveServerData, SERVER_DATA_CACHE_MS } from '@/lib/server-data';
import { SERVER_DATA_CACHE_MS } from '@/lib/server-data';
import type { WorkActivity } from '@/lib/work-activity';
import {
makeDevTaskBlockedActivity,
@@ -23,27 +23,8 @@ import {
} from '@/lib/work-activity-factory';
import { useWorkActivityStore } from './useWorkActivityStore';
function saveStored(items: DevTask[]) {
saveServerData('dev-tasks', items).catch(() => {});
}
let lastTasksFetchAt = 0;
async function loadStored(): Promise<DevTask[] | null> {
try {
const parsed = await loadServerData<DevTask[]>('dev-tasks');
if (parsed) {
if (Array.isArray(parsed) && parsed.some(isLegacyTask)) {
return null;
}
const result = dedupeEntityIds(parsed, 'task');
if (result.changed) saveStored(result.items);
return result.items;
}
} catch {}
return null;
}
interface DevTaskState {
tasks: DevTask[];
loaded: boolean;
@@ -63,13 +44,18 @@ export const useDevTaskStore = create<DevTaskState>((set, get) => ({
loaded: false,
fetchTasks: async (options) => {
if (!options?.force && get().loaded && Date.now() - lastTasksFetchAt < SERVER_DATA_CACHE_MS) return;
if (!options?.versionId && !options?.force && get().loaded && Date.now() - lastTasksFetchAt < SERVER_DATA_CACHE_MS) return;
const cached = options?.versionId
? await listDevTasksByVersionId(options.versionId).catch(loadStored)
: await loadStored();
if (!options?.force && get().loaded && Date.now() - lastTasksFetchAt < SERVER_DATA_CACHE_MS) return;
? await listDevTasksByVersionId(options.versionId).catch(() => [])
: get().tasks;
if (!options?.versionId && !options?.force && get().loaded && Date.now() - lastTasksFetchAt < SERVER_DATA_CACHE_MS) return;
lastTasksFetchAt = Date.now();
set({ tasks: cached ?? [], loaded: true });
set({
tasks: options?.versionId
? mergeDevTasksForVersion(get().tasks, options.versionId, cached ?? [])
: cached ?? [],
loaded: true,
});
},
createTask: (data) => {
@@ -87,18 +73,13 @@ export const useDevTaskStore = create<DevTaskState>((set, get) => ({
set({ tasks: updated, loaded: true });
scheduleSaveWithOptimisticRollback({
save: async () => {
try {
if (!task.versionId) throw new Error('missing versionId');
const result = await createDevTaskByVersionId(task.versionId, task);
set({
tasks: get().tasks.map((item) => (item.id === task.id ? { ...task, ...result.item } : item)),
loaded: true,
});
appendDomainActivities(result.activities);
} catch {
await saveDevTasksFallback(updated);
useWorkActivityStore.getState().addActivity(makeDevTaskCreatedActivity(task, task.createdBy || task.assigneeId));
}
if (!task.versionId) throw new Error('missing versionId');
const result = await createDevTaskByVersionId(task.versionId, task);
set({
tasks: get().tasks.map((item) => (item.id === task.id ? { ...task, ...result.item } : item)),
loaded: true,
});
appendDomainActivities(result.activities);
},
expected: updated,
getCurrent: () => get().tasks,
@@ -115,14 +96,10 @@ export const useDevTaskStore = create<DevTaskState>((set, get) => ({
set({ tasks: updated, loaded: true });
scheduleSaveWithOptimisticRollback({
save: async () => {
try {
const versionId = previous.find((task) => task.id === id)?.versionId;
if (!versionId) throw new Error('missing versionId');
const result = await updateDevTaskByVersionId(versionId, id, data);
appendDomainActivities(result.activities);
} catch {
await saveDevTasksFallback(updated);
}
const versionId = previous.find((task) => task.id === id)?.versionId;
if (!versionId) throw new Error('missing versionId');
const result = await updateDevTaskByVersionId(versionId, id, data);
appendDomainActivities(result.activities);
},
expected: updated,
getCurrent: () => get().tasks,
@@ -136,13 +113,9 @@ export const useDevTaskStore = create<DevTaskState>((set, get) => ({
set({ tasks: updated, loaded: true });
scheduleSaveWithOptimisticRollback({
save: async () => {
try {
const versionId = previous.find((task) => task.id === id)?.versionId;
if (!versionId) throw new Error('missing versionId');
await deleteDevTaskByVersionId(versionId, id);
} catch {
await saveDevTasksFallback(updated);
}
const versionId = previous.find((task) => task.id === id)?.versionId;
if (!versionId) throw new Error('missing versionId');
await deleteDevTaskByVersionId(versionId, id);
},
expected: updated,
getCurrent: () => get().tasks,
@@ -166,15 +139,10 @@ export const useDevTaskStore = create<DevTaskState>((set, get) => ({
const activity = makeDevTaskStatusActivity(task, task.status, to, task.assigneeId);
scheduleSaveWithOptimisticRollback({
save: async () => {
try {
if (!task.versionId) throw new Error('missing versionId');
const result = await updateDevTaskStatusByVersionId(task.versionId, id, to);
appendDomainActivities(result.activities);
if (result.activities.length === 0 && activity) useWorkActivityStore.getState().addActivity(activity);
} catch {
await saveDevTasksFallback(updated);
if (activity) useWorkActivityStore.getState().addActivity(activity);
}
if (!task.versionId) throw new Error('missing versionId');
const result = await updateDevTaskStatusByVersionId(task.versionId, id, to);
appendDomainActivities(result.activities);
if (result.activities.length === 0 && activity) useWorkActivityStore.getState().addActivity(activity);
},
expected: updated,
getCurrent: () => get().tasks,
@@ -201,15 +169,10 @@ export const useDevTaskStore = create<DevTaskState>((set, get) => ({
: makeDevTaskUnblockedActivity(task, task.assigneeId);
scheduleSaveWithOptimisticRollback({
save: async () => {
try {
if (!task.versionId) throw new Error('missing versionId');
const result = await setDevTaskBlockedByVersionId(task.versionId, id, blocked, reason);
appendDomainActivities(result.activities);
if (result.activities.length === 0) useWorkActivityStore.getState().addActivity(activity);
} catch {
await saveDevTasksFallback(updated);
useWorkActivityStore.getState().addActivity(activity);
}
if (!task.versionId) throw new Error('missing versionId');
const result = await setDevTaskBlockedByVersionId(task.versionId, id, blocked, reason);
appendDomainActivities(result.activities);
if (result.activities.length === 0) useWorkActivityStore.getState().addActivity(activity);
},
expected: updated,
getCurrent: () => get().tasks,
@@ -231,8 +194,11 @@ export const useDevTaskStore = create<DevTaskState>((set, get) => ({
},
}));
async function saveDevTasksFallback(tasks: DevTask[]) {
await saveServerData('dev-tasks', tasks);
function mergeDevTasksForVersion(current: DevTask[], versionId: string, scopedTasks: DevTask[]) {
return [
...current.filter((task) => task.versionId !== versionId),
...scopedTasks,
];
}
function appendDomainActivities(activities: WorkActivity[]) {