22 KiB
工作流程
记录用户的协作偏好和系统化流程,方便后续模型理解项目运作方式。
用户协作风格
- 直接修复明确 bug,不强制走 brainstorming 流程
- 方案确认后立即执行,不重复讨论
- 不喜欢自动 push:commit 由模型完成,push 需要用户明说"推/push"
- 要求高级开发思维:考虑数据联动、引擎层抽象,而不是分散写 ad-hoc 逻辑
- 重视一致性:所有 Drawer 阴影、所有时间格式、所有状态计算都要统一
- 省略多余对话:能直接做的不要问,只在真有歧义时用 AskUserQuestion 给选项
- Brainstorming 适用于新功能,bug fix 和已批准方案的延续不走 brainstorming
实际工时计算流程
所有"实际开始时间"和"实际完成时间"都是 ISO 时间戳:
状态变更时机:
- DevTask: todo → in_progress 时记 startDate
testing → submitted 时记 completedAt
- TestCase: pending → running 时记 startedAt
running → passed/failed/blocked 时记 completedAt
- VersionPlan: pending → in_progress 时记 actualStartAt
in_progress → completed 时记 completedAt
计算:
- 实际工时 = (completedAt - startDate) / 3600000,精确到 0.5h
- 阶段日历耗时 = min(start) → max(end) 跨度(项目维度,不重复)
- 个人耗时 = 每个任务独立累加(个人维度)
开发任务延后原因判断
开发任务从“待开发”切换到“开发中”时,只有当前时间已经超过 expectedEndAt(预计截止)才要求填写延后原因。超过预计开始时间但仍未超过预计截止时间,不视为延后。
AI 草案领取与计划流程
开发任务和测试用例由 AI 生成后,版本详情里不再显示独立的“待排期”状态:
- DevTask / TestCase 没有负责人时显示“待领取”。
- 点击“领取并填写计划”时同时写入当前用户为负责人,并填写计划起止时间。
- 已采纳推荐负责人的 AI 草案已经有负责人,不需要领取,但开始开发/测试前仍必须点击“填写计划”补齐计划起止时间。
- DevTask 开始开发前必须同时具备
assigneeId、expectedStartAt、expectedEndAt;TestCase 开始测试前必须同时具备assigneeId、plannedTestAt、plannedEndAt。 - 计划起止时间自动按工作日历计算
estimateHours。AI 预估仍保留在aiEstimateHours,不代表负责人已确认排期。
开发任务提测流程
- DevTask 从“自测”转为“已提测”前,任务不能处于阻塞中。
- 如果
isBlocked=true,必须先解除阻塞并清空阻塞原因,再允许提测。 - “已提测”仍然是 DevTask 终态;后续测试通过或失败不回写 DevTask 状态。
测试轮次流程
测试用例支持按版本开启多轮测试:
- 旧测试用例或未写入
roundNo的测试用例默认属于第 1 轮。 - 点击“开启新一轮测试”时,系统从第 1 轮复制全部测试用例到下一轮,包含 AI 创建和人工创建的用例。
- 只有最新一轮全部测完(状态为通过、不通过或阻塞)后,才能开启下一轮;第 1 轮未测完不能开启第 2 轮。
- 新轮次保留用例范围与估时信息:关联需求、任务类型、优先级、负责人、引用来源、AI 预估、执行预估。
- 新轮次清空执行记录:状态回到待测试,不带开始/完成时间、执行人、失败原因、阻塞原因。
- 测试用例列表、当前轮次进度、无 Bug 通过率按选中的轮次展示。
- 顶部耗时汇总按当前版本全部轮次累计,实际耗时和人力投入会包含新一轮执行产生的耗时。
- 测试用例按所属需求分组展示开发提测标签:该需求下所有开发任务都已提测时显示“已提测”,否则显示“待提测”。
数据联动检查清单
新加模块或字段时,检查以下点:
- 是否需要在
linkage-engine.ts加派生函数? - 是否需要在
workspace-engine.ts加聚合? - 删除版本时是否需要清理这类数据?
- 工作台 / 版本详情 / 项目详情三处的统计是否同步?
- 是否需要新增
app_datakey(后端data-keys.ts+ 前端server-data.ts)? - 是否需要从旧浏览器数据做一次性迁移?(当前不做本地导入导出)
Drawer(侧边详情)规范
所有侧边详情遵循:
fixed inset-0 z-50 flex justify-end- 背景
bg-black/40 - Drawer 容器
w-full max-w-md h-full bg-[var(--bg)] border-l shadow-2xl flex flex-col - 顶部上下文条(可选):
px-5 py-2 bg-[var(--bg-subtle)] text-[11px] - 顶栏:
h-14 border-b bg-[var(--bg-card)] - 操作按钮按颜色编码:blue=进行/转交、emerald=完成、red=删除/失败、orange=关闭/提BUG
Modal(弹窗)规范
- 居中
flex items-center justify-center bg-black/40 rounded-2xl bg-[var(--bg-card)] border shadow-md- 提交 BUG 等图片密集型用
max-w-2xl,普通表单max-w-md或max-w-lg
字段命名规范
- 实际开始:
startDate(DevTask) /startedAt(TestCase) /actualStartAt(VersionPlan) - 实际完成:
completedAt(统一) - 派生进度:在 lib 层提供函数,不存储
历史原因导致命名不完全一致(DevTask 用 startDate 是因为最早是日期字段),但行为一致。
提交信息规范
- 中文 commit message
- 格式:
类型(模块): 描述- feat / fix / refactor / docs / test
- 描述列出关键改动点,特别是跨模块影响
- Co-Authored-By 行带版本号
文档维护流程
- 新增/改动核心架构 → 更新
architecture.md - 关键设计决策 → 追加到
decisions.md,包含"为什么" - 新功能/路线图变更 → 更新
roadmap.md - 不影响架构的功能性改动 → 不需要更新文档
Bug 排查流程
朋友拉新代码出现"显示问题"时,按顺序排查:
- 后端是否启动:
GET http://localhost:3001/api/v1/config/ai应返回 200 - 数据库是否启动并完成 Prisma 同步:
app_data表必须存在 - 对应
app_data.key是否有值,例如products-overview/requirements/dev-tasks - 前端 store 是否已经调用对应
fetch*方法 - 类型定义和实际 JSON 数据不一致(缺字段)
- 列宽溢出导致裁切
- 派生计算错误(filter 条件错)
- 跨模块联动断了(store 的 store.getState() 调用时机)
测试 / 验证流程
- 改动后必须
npx tsc --noEmit通过 - 涉及服务端数据持久化:
pnpm --filter server exec prisma validate --schema prisma/schema.prisma - 涉及 UI 改动:
curl http://localhost:3000/<path>检查 200 - 不会自动跑 dev server,假定它已经运行
AppData 并发写入流程
- 前端通过
loadServerData(key)读取业务文档时,必须缓存响应里的version。 - 前端通过
saveServerData(key, value)保存已读取过的 key 时,必须把最近一次成功读取/保存得到的version一起提交。 - 后端只在
key + updatedAt(version)匹配时更新;如果其他用户已经先保存,返回409 APP_DATA_CONFLICT,响应包含当前服务端currentVersion和currentValue。 - 收到
ServerDataConflictError时,不要自动重试覆盖。当前处理策略是阻止静默覆盖,后续 UI 冲突合并能力再单独补。
V2.4 领域写入流程
已迁移领域的 store 默认写入顺序:
- 本地状态先做乐观更新,保持 UI 响应速度。
- 优先调用
apps/web/lib/domain-api.ts中的领域 API。 - 领域 API 成功后,用服务端返回行替换本地临时行;若返回
activities,直接合并工作活动证据。 - 领域 API 不可用或旧环境未部署时,才使用
loadServerData/saveServerData做 AppData 兼容兜底。 - 不新增长期双写逻辑;AppData fallback 只用于兼容、迁移和回滚,不作为已迁移领域的事实源。
当前领域主写范围:
- Product / Project / Version:根数据主写,
products-overview仅兼容。 - Requirement:按
productId写入,需求池列表走服务端分页、搜索、筛选、排序。 - VersionPlan / DevTask / TestCase / Bug:按
versionId写入,并维护工作活动和小宝 dirty 标记。 - Member / TaskCategory:成员身份字段和任务类型字典主写关系表。
- TaskWorklog / OvertimeRecord / WorkActivity:证据型数据主写关系表,保持追加语义。
仍在 AppData 兼容配置中的内容:
- 部门、角色、密码规则。
- 加班原因。
新增领域 store 时,先写 source contract 测试证明主写不是 saveServerData('<key>'),再实现领域 API 和 fallback。
与我相关(Workspace)数据流
useProductStore → versions
useRequirementStore → requirements (with versionId)
useDevTaskStore → tasks (with versionId; legacy with requirementId)
useTestCaseStore → testCases (with versionId)
useBugStore → bugs (with versionId)
useVersionPlanStore → plans (with versionId, owner)
useAuthStore → user (filter by current user)
↓
workspace-engine.aggregateWorkItems(...)
↓
WorkItem[] (统一格式)
↓
Workspace 页面(树筛选 + tab 筛选 + 已完成开关)
新增模块时,只需在 aggregateWorkItems 中添加聚合逻辑,工作台自动展示。
AI 拆解工作流(V3.1)
详细 Agent 规范见 agent-spec.md。这里是用户视角的工作流:
1. 创建版本(不需要单独填原型链接)
↓
2. 在版本详情 → 产品方案 Tab 创建一条 product 计划
↓
3. 完成产品方案计划,提交「成果」(成果链接即原型链接,附成果标题)
↓
4. 从当前项目已采纳需求中关联需求到本版本
↓
5. 点击「AI 拆解开发任务」或「AI 拆解测试用例」按钮(位于产品方案 Tab)
↓
6. Agent 从 product 类型的 completed 计划取 resultUrl 作为原型,
抓取原型 + 关联需求 + 版本成员,输出对账报告 + 任务/用例草案
(关联需求优先;原型中明确可拆但没有 REQID 的内容进入“无需求ID”分组)
- 生成中状态和完成结果保存在前端 AI 拆解会话中;用户离开版本详情再返回时,未结束的生成继续保持“拆解中”,已完成的生成显示“查看结果”。
- 生成结果只有在用户点击「采纳选中」或「不采纳」后才清空;单纯关闭弹窗或切到其他页面不会丢失结果。
↓
7. 用户审核对账报告
├─ 系统先自动过滤已采纳过的重复 DevTask/TestCase 草案
├─ 报告全 ✅:直接确认写入
├─ 报告有无需求ID分组:确认后写入任务/用例,但不创建需求池记录
├─ 报告有 ⚠️/❓:选择性放弃部分草案 / 补充信息后重跑
└─ 报告全 ❓:放弃 AI 拆解,人工创建
↓
8. 确认后,DevTask / TestCase 草案写入对应 Tab,标记 aiDraft: true,并写入 aiEstimateHours;
无需求ID草案按 `无需求ID · 需求名称` 分组展示,不额外显示“原型发现”标记
↓
9. 团队成员在 DevTask Tab 看到紫色边的 AI 草案任务
↓
10. 任意成员编辑任务(改标题/描述/负责人/优先级/时间/分类/执行预估),保存后 aiDraft 自动清除
(changeStatus / setBlocked 等用户主动操作也会清除)
触发条件(AI 拆解按钮可点):
- 至少有 1 条 type=product 的产品方案计划处于 completed 且 resultUrl 非空
- 至少 1 条需求关联到本版本
人工创建任务/用例的引用要求:
- 创建 DevTask 时已选「关联需求」自动作为 reference 写入
- 创建表单加「原型批注」字段(手填,逗号或空格分隔,如
QY0007, QY0023) - 至少一类引用非空才能保存(V3.1 暂未做强校验,靠 UI 引导)
高级开发约束:规则先归位
涉及以下任意类型的改动时,先判断规则应该放在哪一层,不允许直接在页面组件里散写临时判断:
- 跨模块联动:例如 Requirement、VersionPlan、DevTask、TestCase、Bug 互相派生状态。
- 状态流转:例如
pending -> in_progress -> completed、todo -> testing -> submitted。 - 完成条件:例如子任务是否完成、是否提交成果、是否允许点击完成。
- 候选数据来源:例如关联需求只能来自当前项目已采纳需求,不能从全量需求池随手取。
- AI 写入契约:例如 AI 输出任务类型、引用来源、草案标记。
- AI 无需求ID分组:原型中明确可拆但没有匹配关联需求的内容,只写入 DevTask/TestCase 的
requirementName,不进入需求池或版本关联需求列表。
默认落点:
- 可派生数据进
*-engine.ts或纯函数 helper。 - 有状态流转的实体要有状态机或 workflow helper。
- 多个组件共用的候选筛选规则进 selector/helper。
- AI 输入输出字段先更新
agent-spec.md和 shared type,再改 prompt/schema。
AI 估时约束:
aiEstimateHours是 AI 建议工时,只能由 AI 拆解写入。estimateHours是执行人预估,只能由人工创建/编辑或负责人确认排期时写入。- 统计进度优先取
estimateHours,没有时取aiEstimateHours,避免 AI 草案在未确认前失去统计权重。
版本模块新增规则:
version-plan-workflow.ts是调研/产品方案/UI 设计完成条件的唯一入口。requirement-selector.ts是版本内关联需求候选的唯一入口。TaskCategory.name是 AI 草案的可复用任务类型锚点;可复用开发类型可自动入库,测试用例未知类型回退到已有测试分类。TaskCategory.code仅作为可选兼容映射,id只作为存储主键。- DevTask 新数据必须有
versionId;requirementId作为正式需求语义标签可选。版本级聚合走versionId,需求级进度只统计带requirementId的任务。 - 产品方案和 UI 设计的引用需求不再用 checkbox 直接标记完成,必须通过
requirementCoverage[]记录not_started / partial / completed、本次已完成内容和剩余内容;只有completed计入成果提交门禁。 - 产品/UI 计划右侧展示计划日志,需求进度更新和 AI 拆解触发/完成/失败都写入
VersionPlan.logs[],页面只消费日志数据,不临时拼历史。 - 调研/产品方案/UI 设计的计划级
actualStartAt只表示计划容器已开始,不直接作为具体任务日报耗时。具体调研方向或引用需求需要先点击「开始任务」,写入当前行的currentWorkStartedAt;提交「记录」时日志和work-activities保留workStartedAt,日报耗时按workStartedAt -> 记录提交时间计算,提交后清空当前行的开始时间。完全完成可直接提交结束本次耗时,部分完成才需要填写本次已完成内容和剩余未完成内容。
Production Release Workflow (2026-07-06)
Production releases use GitHub Actions as the default path. The deployment side should not manually rebuild frontend assets after every change; it keeps .env.production and Docker volumes, while Actions builds immutable images and updates the running containers.
Standard flow:
- Merge or push to
master. - GitHub Actions builds
webandserverimages withAPP_VERSION=<commit-sha>. - Actions pushes the images to GHCR.
- Actions SSHes into the server, updates
.env.productionimage tags, pulls the images, runspnpm --filter server db:deploy, and restarts Compose. - Actions verifies
/api/v1/health/versionequals the commit SHA.
If a user reports "latest code pulled but UI is still old", first compare the running version endpoint with the expected commit. A mismatch means deployment did not update the running container. A match means the code is deployed and the remaining issue is likely browser cache, data, or business logic.
Work Activity Daily Report Flow (2026-06-26)
The daily report flow uses mixed evidence:
- Automatic evidence is written when a user performs a successful domain action:
- VersionPlan created, started, or completed.
- DevTask created, started, moved to self-test, submitted to test, blocked, or unblocked.
- TestCase created, started, passed, failed, or blocked.
- Bug created, moved to fixing, fixed, closed, or transferred.
- Manual progress notes are used for multi-day work that does not change status today.
- DevTask「今日进展」必须填写
nextStartAt,默认值为第二天 09:30。 - 带
nextStartAt的进展记录按「上一条记录的nextStartAt→ 本次记录时间」计算当日耗时;如果任务是当天开始,才回退到当天实际开始时间。
- DevTask「今日进展」必须填写
/workspaceshows only the current logged-in user's report.- Project-owner and management views will reuse the same
work-activitiesdata later, but are not part of the personal workspace panel.
Implementation convention:
- Activity wording and category mapping belong in
apps/web/lib/work-activity-factory.ts. - Daily report grouping belongs in
apps/web/lib/workspace-daily-report.ts. - Page components should consume report output, not rebuild report rules.
小宝预警工作流
小宝预警位于主导航“工作区 / 小宝预警”,展示在“与我相关”上方。可见范围由角色权限控制:
xiaobao.warning:manage:查看所有未结束版本的预警。xiaobao.warning:view:仅查看当前用户在version.members中的未结束版本。
V2.6 后小宝当前 summary 由服务端后台刷新:领域写入标记 xiaobao_risk_summaries.dirty=true 并排入 xiaobao.summary.refresh,worker 从版本下的计划、开发任务、测试用例、Bug、日报和工作活动重新计算风险。页面仍可用前端 buildXiaobaoWorkItems 做兼容聚合和快照保存,但默认优先读取 V2.2 summary。
AI 解读不由人工按钮触发。服务端 summary 刷新后按 policy 排入 xiaobao.ai.interpret:at_risk、likely_delayed、blocked 自动触发;attention 当前服务端只在临近发版且仍有未完成工作时触发,页面完整趋势策略仍保留作为兼容。缓存命中时复用解读;同版本最近 6 小时内已有解读时进入 cooldown,不重复请求,风险等级升级时可绕过;缓存保存时间使用服务端写入时间,不信任模型返回的 generatedAt 作为缓存新鲜度。
静默风险包括长期无更新、无日报、无活动、进行中事项无人处理等信号。日报和工作活动是风险解释的重要证据,必须进入 AI 解读输入。
日期选择与计划时间
- 调研、产品方案、UI 设计、开发任务、测试用例、Bug 创建时使用统一工作日日期时间选择器。
- 日期选择器接入中国节假日日历。当前内置 2026 年国务院办公厅放假调休安排;其他年份先按周末/工作日兜底。
- 非工作日只提示,不阻止保存;调休工作日按工作日提示。
- 测试用例计划测试时间字段为
plannedTestAt/plannedEndAt;Bug 计划修复时间字段为plannedFixAt。 - 测试轮次复制用例时保留计划测试起止时间、AI 预估和执行预估,清空实际执行记录。
工时统计口径
- 正常任务耗时使用
calcWorkHours/calcActualElapsedHours,按中国工作日历和 9:00-12:00、13:00-18:00 工作时段计算。 - 法定节假日和周末不计入正常任务耗时;调休上班日计入正常任务耗时。
- AI 预估工时和手填执行预估工时本身是小时数,不再按日期过滤;只有从计划起止时间自动推导的执行预估会按工作日历计算。
- 加班记录使用
overtime.calcDuration,不受节假日过滤,但按项目管理口径计算:每个自然日默认最多 8h,跨天中间日期按 8h,结束晚于 18:00 的当天额外计入超出时长,避免把夜间空档当作打卡工时。 - 新建加班记录也使用工作日历日期选择器;节假日和周末可选,只提示不阻止。
生产部署流程
生产部署以 docs/deployment.md 为准,标准顺序如下:
本地服务器/局域网部署:
- 复制
.env.local-server.example为.env.local-server,按需把LOCAL_ACCESS_HOST和NEXTAUTH_URL改为本机局域网 IP。 - 运行
pnpm deploy:verify。 - 运行
pnpm deploy:local:build构建镜像。 - 运行
pnpm deploy:local:up启动服务,默认访问http://localhost:8080。 - 首次部署或升级后运行
docker compose --env-file .env.local-server -f docker-compose.local.yml exec server pnpm --filter server db:deploy。 - 用
curl http://localhost:8080/api/v1/config/ai验证 Nginx 到后端链路。
云服务器部署:
- 复制
.env.production.example为.env.production,替换密码、域名、NEXTAUTH_SECRET、AI key 等真实值。 - 运行
pnpm deploy:verify,确认生产 Docker、Compose、Nginx、env 示例和文档齐全。 - 运行
docker compose --env-file .env.production -f docker-compose.prod.yml build构建镜像。 - 运行
docker compose --env-file .env.production -f docker-compose.prod.yml up -d启动服务。 - 首次部署或升级后运行
docker compose --env-file .env.production -f docker-compose.prod.yml exec server pnpm --filter server db:deploy。 - 用
curl http://localhost/api/v1/config/ai验证 Nginx 到后端链路。 - 用
docker compose --env-file .env.production -f docker-compose.prod.yml ps和logs -f server/web/nginx排查健康状态。
生产环境不提交 .env.production。HTTPS 默认由外层负载均衡、CDN、宿主机证书工具或外层 Nginx 终止;Compose 内置 Nginx 只承担同域 HTTP 反代。