Files
silk/开发交接记录.md
2026-08-17 21:43:26 +08:00

1352 lines
85 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 开发交接记录
> **用途**:按 AGENTS.md 沟通规则,每完成一项交付(功能/模块/部署)后在此追加「做了什么、设计思路与决策依据、验证结果、回滚点」,供同事快速了解项目进展并接手。
> **阅读顺序**:时间倒序(最新在上);先看「当前状态与剩余事项」了解全局,再按需阅读各模块明细。
## 总体背景
- 项目:智慧蚕房环境监测与智能调控系统(monorepo:`server-go` / `web` / `miniapp` / `wvp`)。
- 《后续工作计划》(2026-08-11 更新)确定混合架构:现有 Go 底座 + Python AI 微服务(`ai-service/`,规划中);生产环境全部上云,本地仅开发/训练/测试。
- **YOLO 训练相关(计划 #1-4:数据集修复、训练环境、上传、基线训练)因物理机问题挂起**,当前按用户要求优先做「独立性强、见效快」的模块。
- 开发服务器:`100.83.103.1`Ubuntu 22.04,用户 `pan`),通过 NetBird VPN 访问;部署规则见 AGENTS.md「部署到开发服务器」章节。
- 当前工作区:本地 v9 对象授权、运营能力、组织管理代码已实现但未提交;开发服务器仍为已部署的 schema v8。
---
## 2026-08-16 补充:组织管理 Web 页面与成员列表接口
### 做了什么
- 后端新增 `GET /api/v1/organizations/:id/members`,返回成员及其用户用户名/姓名/邮箱/加入时间,并对非管理员做组织归属校验;
- 新增 `web/src/pages/Organizations.tsx``web/src/dal/organization.ts`:组织列表、新增/编辑、成员抽屉、添加成员、移除成员;
- Web 新增 `/organizations` 路由和「组织管理」菜单,权限为 `organization:manage`
- 组织成员角色限定为 `member/admin`,避免误填任意字符串。
### 设计思路与决策依据
- IAM-003 需要管理员可见的“组织 → 成员”操作界面,因此先补齐成员列表接口,再接入页面;
- 页面复用现有 Ant Design + ProTable 风格,成员抽屉直接展示当前组织成员,添加时过滤已在组织内的用户;
- 组织成员权限仍沿用现有后端 `organization:manage`,不在前端保存或修改授权规则。
### 验证结果
- `go test ./...``go build ./...` 通过;
- `npm run build``npm run lint` 通过(仅既有无关 warning);
- 未部署开发服务器,未执行 v9 迁移和真实组织成员管理联调。
### 回滚点
- 本任务尚未提交;删除 `web/src/pages/Organizations.tsx``web/src/dal/organization.ts`、路由/菜单,并还原 `organization.go` 即可;
- 数据库无新增 schema;如已部署 v9,回滚仍按 v9 down migration 处理。
---
## 2026-08-15 补充:对象授权覆盖设备链路与运营能力前端闭环
### 做了什么
- IAM-003 从“房间/设备/业务记录”扩展到完整设备链路:`sensors``thresholds``alarms``telemetry``control``video record``alarm clip` 均按设备所属蚕房/组织过滤或返回 403;
- WebSocket 设备订阅改为 RBAC + `organization_members` 双重校验,跨组织用户不能再订阅同设备遥测;
- 通知列表按当前用户隔离,管理员保留全局查看;
- 案例草稿/待审核/驳回内容按来源蚕房组织或创建者可见,已发布案例仍全局共享;案例编辑和审核增加对象访问校验;
- 修复 `firstAccessibleRoomID` 在无 `roomId` 创建摄像头时错误按 `rooms.room_id` 过滤的 SQL 缺陷,改为 `rooms.org_id`
- Web「运营能力」页补齐设备维护、产量损失的编辑/删除闭环,原有列表、新增、统计、案例库和实验室结果保持不变。
### 设计思路与决策依据
- 对象授权继续使用“组织 → 房间 → 业务对象”主链;`deviceKey` 作为遥测、告警、控制的统一入口,先解析到设备房间再判断;
- WS 订阅不允许仅凭 `device:read` 角色权限跨组织访问,与 HTTP 对象授权保持一致;
- 案例库是知识共享资产,因此已发布内容保持公开;非发布内容才按来源组织和创建者隔离;
- 设备维护/产量损失延续现有后端状态与权限种子,不在前端引入新的数据访问层。
### 验证结果
- `scripts/verify.ps1` exit 0Go test/vet/build、Web test/lint/build、小程序 test/typecheck/build、APP typecheck/lint、AI pytest 均通过;
- 新增单测覆盖 sensor→device 归属解析、跨组织设备 403、`firstAccessibleRoomID` 组织范围、WS 组织成员放行/拒绝;
- 未部署开发服务器,未执行 v9 迁移和真实多组织账号越权联调。
### 回滚点
- 本任务尚未提交;回滚代码时恢复工作区对应修改即可;
- 若已执行 v9,数据库回滚执行 `migrations/000009_object_authority_and_business_capabilities.down.sql` 或恢复迁移前 `pg_dump`,随后回退旧二进制。
---
## 2026-08-14 补充:对象授权与后续计划 P2 业务能力
### 做了什么
- 新增 schema v9`organizations``organization_members``rooms.org_id``device_maintenance_records``production_loss_records``case_studies``laboratory_results`,并给 `rearing_records` 增加死亡/淘汰字段;
- 实现 IAM-003 对象级授权底座:默认组织兼容历史数据、用户成员关系、房间/设备/视频/巡检/检测/会诊/溯源/生物安全等核心记录按组织房间过滤,列表隐藏、详情和写操作越权返回 403;
- 新增组织管理接口:`GET/POST/PATCH /organizations`、组织成员添加/移除;
- 新增 ENV-006 设备资产能力:`GET/POST/PATCH/DELETE /device-maintenance`,覆盖校准/故障/维护/固件记录;
- 新增 FARM-006 产量损失能力:`GET/POST/PATCH/DELETE /production-loss-records``/production-loss-records/stats`
- 新增 KB-003 脱敏案例沉淀:`/case-studies` CRUD、从会诊生成草稿、`POST /case-studies/:id/review` 审核发布状态机;
- 新增 TRACE-004 实验室结构化数据:`GET/POST/PATCH/DELETE /laboratory-results`,关联溯源/发病事件/样本并支持病原、分型、环境样本和报告字段;
- Web 新增「运营能力」页:设备维护、产量损失统计、案例库审核、实验室结果四个工作区,路由 `/business`
- 新增权限种子:`organization:manage``device:write``farm:read/write``case:read/write``lab:read/write`,并按角色补入权限映射。
### 设计思路与决策依据
- 对象授权以“组织 → 房间 → 业务记录”为主链,设备、视频、批次、检测、会诊和溯源统一通过房间归属收敛,避免给每张表重复维护对象权限;
- 历史数据通过 `default` 组织自动回填,新注册用户自动加入默认组织,避免升级后现有非管理员账号立刻失去可见性;
- 新增业务能力沿用现有 CRUD、权限中间件和版本化 SQL 迁移模式,不引入新的数据访问层。
### 验证结果
- 已执行 `go test ./...` 通过;`go build ./...` 通过;
- 已执行 `go vet ./...` 通过;`npm run lint``npm run build` 通过;
- 新增单测覆盖对象授权查询、设备维护/产量损失/案例状态机/实验室结果校验、产量损失聚合;
- 未部署开发服务器,schema 仍为本地 v9 迁移文件;服务器部署前需按 AGENTS.md 先备份、记录回滚点并执行迁移。
### 回滚点
- 本任务尚未提交;回滚代码时恢复工作区对应修改即可;
- 若已在开发库执行 v9,回滚需先恢复迁移前 `pg_dump`,或执行 `migrations/000009_object_authority_and_business_capabilities.down.sql` 后再恢复旧二进制。
---
## 2026-08-12 补充:Web 知识库图谱预览与保存修复(故障排查 #三十二)
### 做了什么
- 修复 Web 知识库「蚕病百科」两个问题:编辑页图谱预览打不开(CSP 拦截跨源 S3 图片)、提交后 `imageUrl` 未保存(表单未注册该字段)。
- `web/src/pages/Knowledge.tsx`:「症状图谱图片」后新增隐藏 `Form.Item name="imageUrl"`,保证 `form.validateFields()` 提交时携带图片 URL。
- `web/server.cjs`CSP `img-src` 放行 `http://100.83.103.1:7480`(开发 S3 源)。
- 已部署并重启前端(新 bundle `index-CSVEb7gG.js`),并按用户确认直接改库把白僵病已上传的图谱 URL 补绑到 `diseases.image_url`
### 思路与决策
- 根因定位:日志显示上传 200、PATCH 200,但 `image_url` 为空 → 定位为前端表单未注册 `imageUrl`antd `validateFields()` 只返回已注册字段),以及 CSP 跨源拦截预览。
- 修复方式:用隐藏 `Form.Item` 注册字段(antd 标准做法),避免手工拼请求体;CSP 采用放行开发 S3 源,生产切云 OSS/COS 时再替换为 OSS/CDN 域名或改同源代理。
- 数据补绑:用户明确选择「直接改库」,回滚点为备份的 `diseases` 表 dump 与逐行 UPDATE 反向语句。
### 验证
- `web``npm run lint` 通过(仅既有无关警告)、`npm run build` 通过。
- 机制红绿验证:用 rc-field-form 验证 `validateFields()` 会丢弃未注册的 `imageUrl`,注册/合并后可携带。
- 部署验证:`http://localhost:5174/` 200CSP 头含 `http://100.83.103.1:7480`;新 bundle 200`/api/v1/health` 200bundle 中可见 `name:"imageUrl", hidden:!0`
- 数据验证:`UPDATE 1`;查询确认白僵病 `image_url` 已绑定;图片匿名 GET 200image/jpeg)。
- API 冒烟:admin 登录成功,`GET /api/v1/knowledge/diseases` 返回白僵病 `imageUrl` 已绑定(密码不写入文档)。
### 回滚点
- 前端:`/home/pan/backups/web-20260812-1605/`(旧 dist、server.cjs、web.log)恢复后重启 node。
- 数据:`diseases` 表 dump `/home/pan/backups/diseases-20260812-1605.dump`;或执行 `UPDATE diseases SET image_url=NULL, updated_at=now() WHERE id='17b1cae4-21cc-4996-9db3-96f785aef800';`
## 2026-08-12 模块:知识库初始版(计划 #10)
### 做了什么
- 后端(server-go):
- 新增 `Disease`(蚕病百科)与 `KnowledgeArticle`(知识文章)两张表;
- 种子数据:9 个蚕病条目(4 类核心病种:核型多角体病、白僵病、软化病、微粒子病 + 5 个扩展病种)+ 1 篇 AI 结果解读,启动时幂等写入;
- CRUD API`/api/v1/knowledge/diseases``/api/v1/knowledge/articles`(列表支持 category/kind/keyword 过滤);
- 权限:新增 `knowledge:read` / `knowledge:write`admin/operator 可写,viewer/farmer 只读。
- Web:新增「知识库」菜单页(蚕病百科 + AI 结果解读双 Tab,可增删改)。
- 小程序:设置页新增「知识库」入口 → 列表页 → 详情页。
### 思路与决策
- 选择理由:知识库是规格书 P0、完全独立、不依赖 YOLO 训练产物,符合「独立性强、见效快」的推进原则。
- 内容来源:全部取自规格书《蚕病智能防控平台规格说明书》3.6(知识库模块)、3.1.4(风险分级阈值)、附录 11.1(蚕病参考信息)、3.8(处置方向/排查清单),不自行编造。
- 「防治指南」字段是按规格书 3.8 的处置方向(内源扩散/外源侵入措施)与分病种排查清单整理的加工内容,非原文逐字。
- 权限设计沿用现有 RBAC 权限码模式,管理端可编辑、农户端只读。
### 验证
- 种子数据完整性测试(TDD 红→绿):核心 4 病种齐全、必填字段非空、名称唯一、AI 解读存在;`go test/build/vet` 通过。
- Web `npm run lint && npm run build`、小程序 `npm run build:weapp` 通过。
- 部署后冒烟:登录 admin → `GET /api/v1/knowledge/diseases` 返回 9 条;`articles?kind=ai_guide` 返回 1 条;DB 计数 diseases=9 / articles=1。
### 部署与回滚
- 首次部署 2026-08-12;回滚点:DB dump `/home/pan/backups/silk-20260812-1111.dump`、旧二进制 `server-go-linux.bak`、旧 dist 打包;完整记录在服务器 `/home/pan/backups/rollback-20260812/README.md`
- 相关提交:`13df3d5`(实施计划)、`50dcd65`(测试 RED)、`8e30234`(种子数据)、`3afc34d`API/权限/迁移)、`b8af17d`Web)、`93aa4ee`(小程序)。
---
## 2026-08-12 补充:LAMP 操作教程(规格书 P0)
### 做了什么
- 后端:`lamp_guide` 种子文章(原理、适用场景、设备清单、5 步操作流程、结果判读、各病种检测靶标现状);
- 小程序:知识库列表增加「LAMP 教程」入口;修复详情页对非 disease 类型(如 lamp_guide)误走病种接口的问题;
- Web 无需改动(文章 Tab 已支持 `lamp_guide` 类型)。
### 思路与决策
- LAMP 教程是规格书 3.6 的 P0 项,且 LAMP 是「目前蚕业领域最务实的分子检测方案」(规格书 3.3.2.1),优先补齐;
- 内容全部取自规格书 3.3.2.1(含操作流程表、设备清单、病种靶标研究现状),无编造;
- 规格书要求「视频+图文」,当前先做图文,视频素材后续补充。
### 验证与回滚
- 新增存在性测试(TDD 红→绿),5 个种子测试全过;`build:weapp` 通过;二次部署后 `ai_guide=1``lamp_guide=1`API 冒烟返回教程内容。
- 相关提交:`0d3124f`(种子数据)、`8bb93ad`(小程序入口 + 类型判断修复);回滚见服务器 README(旧二进制 `server-go-linux.old-20260812-2`)。
---
## 2026-08-12 补充:症状图谱图片上传(规格书 P0)
### 做了什么
- 后端:`POST /api/v1/knowledge/images`multipart 字段 `file`,限 jpg/jpeg/png/webp、≤5MB,权限 `knowledge:write`),写入 S3 `silk-images` 桶,对象键 `knowledge/<日期>/<随机>.ext`,返回可公开访问的 URL
- 配置:新增 `S3_BUCKET_IMAGES`(默认 `silk-images`);
- Web:病种编辑表单增加「症状图谱图片」上传 + 预览;
- 小程序:病种详情页顶部展示症状图。
### 思路与决策
- 规格书只规定「蚕病百科要有症状图谱」和通用图片存储链路(对象存储 + CDN),没有规定图谱图片来源;采用「通用上传能力 + 后续多来源导入」策略,避免手动塞数据库;
- 素材来源三方向(后续):YOLO 训练数据集选图、专家/合作单位素材、巡检照片沉淀;
- 存储复用现有 S3 服务(开发 Ceph、生产云 OSS/COS 仅改配置);
- v1 先做「每病种一张主图」(单 `imageUrl`),多图图谱后续用子表扩展。
### 踩坑记录(重要)
- **Ceph 的 bucket 级 public-read 不覆盖对象读取**,必须给对象本身设置 public-read`PutObjectInput.ACL`),否则 Web/小程序无法直接展示图片;生产 OSS 同样注意桶策略或 CDN 配置。
- 服务器上运行中的二进制不能被 `cp` 覆盖(`text file busy`)→ 必须先 `mv` 旧文件再 `cp` 新文件。
### 验证与回滚
- 5 个单元测试(大小/扩展名/Content-Type/键生成)TDD 红→绿;三端构建通过;
- 部署冒烟:上传 1x1 PNG → URL 匿名 GET 200`image/png`)→ 病种 `imageUrl` 绑定成功(测试数据已清空);
- 相关提交:`c8aa213`(上传接口)、`3bb1efa`Web+小程序)、`7647705`(对象公开读修复);回滚见服务器 README(旧二进制 `server-go-linux.old-20260812-5`)。
---
## 2026-08-12 模块:饲养阶段风险提示(计划 #13)
### 做了什么
- 后端:新增 `GET /api/v1/knowledge/stage-hints?stage=young|grown|late5|pupa`(只读 GET,天然幂等),返回该阶段高发病种(含病种 id,可直接跳知识详情);不传 stage 返回全部;
- 种子数据:4 个阶段(小蚕期 young / 大蚕期 grown / 5龄后期 late5 / 蛹期 pupa)及其高发病种与原因;
- 小程序:知识库页新增「饲养阶段风险提示」区块——龄期选择器 + 提示卡片,点击病种跳详情。
### 思路与决策
- 选择理由:规格书 3.2.2 的 P1 项,独立、见效快,直接复用蚕病知识库;
- 内容来源:规格书附录 11.1 高发阶段 + 3.2.3 蚕病环境风险规则(如核型多角体病 5龄后期温度突变 >30℃/<20℃ 诱发),无编造;
- 幂等性:新增接口为只读 GET,天然幂等;后续新增写接口时按需实现幂等(如幂等键);
- v1 用选择器而非自动联动:自动按蚕房龄期提示需等「蚕匾/批次管理」(#7,含龄期记录)落地后接入;
- Web 端本次未加,保持快速交付,后续需要再补。
### 验证与回滚
- 5 个单元测试(阶段 key 合法、病种引用存在、按阶段过滤、未知阶段报错)TDD 红→绿;`go test/build/vet``build:weapp` 通过;
- 部署冒烟:`all=4` 阶段;`grown` 返回软化病 + 核型多角体病(含 id);`young` 返回曲霉病提示;未知阶段 400
- 相关提交:`6d9cfc7`(后端)、`6dc6c27`(小程序);回滚见服务器 README(旧二进制 `server-go-linux.old-20260812-6`)。
---
## 2026-08-12 补充:知识库其余内容(SERS 教程 / 四季防控提醒 / 「其它未知」病种)
### 做了什么
- 种子数据:`sers_guide` 教程(原理、适用场景、设备清单、4 步操作流程、与 LAMP 对比);`seasonal_tip` 春夏秋冬 4 篇防控要点;`diseases` 新增「其它/未知(不确定但有异常)」条目(AI 检出异常但无法归入已知病种时的引导,建议分子检测确认)。
- 小程序:知识库页教程区合并展示 AI/LAMP/SERS(按类型徽标);新增「季节性防控提醒」区块——当前季节高亮卡片 + 全部季节列表。
- Web 无需改动。
### 思路与决策
- 内容来源:SERS 取自规格书 3.3.2.2;季节提醒取自附录 11.1 季节性流行规律(春蚕期核型多角体病多发、夏秋高温闷热质型/浓核/软化病多发、湿度>75% 真菌病暴发、温湿度波动诱发潜伏感染);「其它/未知」对应规格书 AI 检测输出类别(3.1.3)。
- 季节匹配用文章标题前缀约定(春季/夏季/秋季/冬季),未新增 schema 字段,保持简单;后续如需按节气推送可扩展。
- 幂等性:均为种子数据,无新增写接口。
- 专家经验沉淀(P1)暂缓:依赖专家会诊(#18)功能落地后才能沉淀历史案例。
### 验证与回滚
- 种子测试共 10 个全过(新增 SERS/四季/其它未知 3 个用例,TDD 红→绿);三端验证通过;
- 部署冒烟:`sers=1``seasonal=4``diseases=10`(含 other 类别);
- 相关提交:`a5caa48`(后端种子)、`62fbbaf`(小程序);回滚见服务器 README(旧二进制 `server-go-linux.old-20260812-7`)。
---
## 2026-08-12 模块:AI 巡检闭环后端(计划 #5 + #6)
### 做了什么
- `ai-service/`FastAPI + ONNX Runtime 检测服务骨架(`GET /health``POST /detect` 返回框/类别/置信度)。默认 `MODEL_MODE=mock`MockDetector 返回固定结果并校验图片可解析);`ONNXDetector` 已实现 YOLOv8 常见输出格式解析(letterbox + NMS),训练恢复后放 `models/best.onnx` 即切真实推理,接口不变。
- Go 后端:AI client`AIClient.Detect`multipart 上传 + 超时/错误处理);`inspection_records` 表;`POST/GET /api/v1/inspections`——图片存 S3 `silk-images/inspections/` → 调 `/detect` → 写记录;`Idempotency-Key` 幂等;`roomId` 校验。
- 权限:`inspection:create` / `inspection:read`;配置 `AI_SERVICE_BASE`
### 思路与决策
- 按规格书 3.1:AI 服务只做检测(框/类别/置信度),**风险评分留在 Go 端**(#9 公式),职责单一;
- 幂等性:`/detect` 无状态天然幂等;`POST /inspections` 用客户端 `Idempotency-Key`(唯一索引)+ 并发冲突兜底,重试不会产生重复巡检记录;
- YOLO 训练挂起不阻塞:mock 模式先跑通端到端链路,模型就位后只改环境变量;
- 图片复用 `silk-images` 桶(`inspections/` 前缀),不新建桶;
- 踩坑记录:服务器缺 `python3.10-venv`(需 apt 安装);pip 直连慢,改用清华镜像;原 `.gitignore` 全局 `*.py` 规则会忽略 ai-service,已加例外。
### 验证与部署
- 本地:ai-service pytest 6/6Go 新增 AI client 3 用例 + UUID 校验用例,`go test/build/vet` 通过;
- 服务器:ai-service 部署 `/home/pan/ai-service`:8000mock`start.sh`),pytest 6/6health 200Go 第六次部署(schema 变更前 pg_dump `silk-20260812-1635.dump`);
- 冒烟:巡检创建 201mock healthy/0.95)→ 同 key 重试返回同记录 → 列表 → 图片 URL 200;非法 roomId 400(测试数据已清理);
- 相关提交:`99137a6``b89ad5e`ai-service + gitignore)、`210bd6c`(Go 对接);回滚见服务器 README(旧二进制 `server-go-linux.old-20260812-9`)。
### 说明
- 巡检风险分级(绿/黄/橙/红)与评分引擎属计划 #9,本期只落数据字段;
- 小程序拍照巡检 UI#8)下一轮再做。
---
## 2026-08-12 模块:小程序拍照巡检(计划 #8)
### 做了什么
- 新增 `pages/inspection/`:拍照/相册选图(压缩)→ 预览 → 上传 `POST /api/v1/inspections`multipart,自动生成 `Idempotency-Key` 防重复)→ 结果卡片(AI 类别 + 置信度 + 风险提示文案)→ 巡检历史列表(最近 10 条)。
- 设置页「监控管理」新增「拍照巡检」入口;`app.config.ts` 注册页面。
### 思路与决策
- 复用 #5/#6 已部署的后端接口,本期纯小程序端,无服务端改动;
- 上传用 `Taro.uploadFile`(不是通用 request 封装),因为需要文件流 + 自定义头(Authorization / Idempotency-Key);
- 幂等键客户端生成(时间戳 + 随机串),弱网重试不会重复创建巡检记录;
- 结果展示先按二分类(healthy/sick)映射,风险分级(绿/黄/橙/红)等 #9 评分引擎落地后接入;7 类病种扩展后补充类名映射。
### 验证
- `npm run build:weapp` 编译通过;后端接口此前已冒烟(创建→幂等重试→列表→图片 200)。
- 相关提交:`8274cc8`
---
## 2026-08-12 模块:风险评分引擎(计划 #9)
### 做了什么
- `risk.go`:评分公式(0.5/0.2/0.15/0.15 权重,0-100 钳制)、分级(绿/黄/橙/红)、阶段系数(Room.Stage 粗映射)、环境系数(湿度/温度规则,取自规格书 3.2.3)。
- 巡检创建(`POST /api/v1/inspections`)时自动计算:AI 置信度取检测结果最大值;带 `roomId` 时按房间阶段 + 最新温湿度算系数;结果写入 `risk_score` / `risk_level`
### 思路与决策
- 公式与分级阈值完全按规格书 3.1.4,不自行调整;
- 评分在 Go 端(AI 服务只做检测),保持职责单一;
- 环境系数 v1 用「最新一条温湿度」按规则打分(规格书 3.2.3 的连续 3 天判定留待后续);
- 整齐度偏离度暂无数据源(需蚕匾/批次管理 #7 后才有),本期恒为 0
- 阶段系数用 Room.Stage 粗映射,等 #7 龄期字段落地后细化。
### 验证与部署
- 5 个单元测试(TDD 红→绿);`go test/build/vet` 通过;
- 第七次部署:冒烟——带房间 57.5(yellow)、不带房间 47.5yellow);
- 相关提交:`93301f0`;回滚见服务器 README(旧二进制 `server-go-linux.old-20260812-10`)。
---
## 2026-08-12 模块:蚕匾/批次/饲养记录管理(计划 #7)
### 做了什么
- 后端:`trays` / `batches` / `rearing_records` 三表 + CRUD(按 roomId/batchId 过滤),批次删除级联删除饲养记录;权限 `tray/batch/rearing:read/write`
- Web:新增「批次管理」页——批次管理 Tab(含饲养记录弹窗)、蚕匾管理 Tab、按蚕房筛选。
- 小程序:蚕房详情页展示「蚕匾」与「当前批次」只读区块。
### 思路与决策
- 按规格书 3.5:蚕房→蚕匾→批次层级,饲养记录挂批次(品种/来源/龄期/桑叶/密度);
- 批次带 `instar`(龄期 1-5)与 `status`(饲养中/已上蔟/已结束),为 #9 阶段系数与 #13 自动风险提示预留数据源;
- CRUD 沿用现有 room.go 模式(bindUpdates、uuid 校验复用 `isUUID`);删除批次时级联删除饲养记录,避免孤儿数据;
- v1 范围外:消毒记录(P1)、蚕种来源全链(P2)、产量统计(P1)。
### 验证与部署
- 三端构建通过;第八次部署(schema 变更前 pg_dump `silk-20260812-1720.dump`);
- 冒烟:蚕匾/批次/饲养记录创建→列表→删除均 200,批次删除后饲养记录级联为 0;
- 相关提交:`362a70b`(后端)、`0a5e2b1`(Web+小程序);回滚见服务器 README。
---
## 2026-08-12 模块:微信订阅消息骨架(计划 #11)
### 做了什么
- 后端:`wechat_bindings` 表 + `/wechat/binding|bind|subscribe``WechatService`code2session、access_token 内存缓存、订阅消息发送);巡检风险非绿时异步触发(未配置/未授权静默跳过)。
- 小程序:「消息订阅」设置页(绑定、授权订阅、状态展示)。
### 思路与决策
- 按用户选择先做**骨架 + 环境变量占位**:`WECHAT_APPID/WECHAT_SECRET/WECHAT_TEMPLATE_*` 默认空,未配置时接口返回明确中文错误,触发逻辑静默跳过,不影响主流程;
- 微信订阅消息为一次性订阅:每次触发需用户先 `wx.requestSubscribeMessage` 授权,小程序端已实现授权流程,模板 ID 占位待替换;
- access_token 内存缓存(提前 60 秒过期),避免每次发送都换 token;
- 订阅消息 data 用 `thing1`(等级)/`thing2`(评分)占位字段,正式模板字段不同时改 `BuildSubscribeData`
### 验证与部署
- 微信服务 6 个单测(TDD 红→绿),`go test/build/vet` 通过;`build:weapp` 通过;
- 第九次部署(schema 变更前 pg_dump `silk-20260812-1730.dump`);冒烟:binding 未绑定、bind 返回「微信未配置」502、巡检触发不崩溃;
- 相关提交:`921b185`(后端)、`bdf0515`(小程序);回滚见服务器 README(旧二进制 `server-go-linux.old-20260812-12`)。
### 待办
- 提供 AppID/Secret + 订阅消息模板 ID,替换占位后联调真实推送;
- 告警产生时的推送触发点(当前只接了巡检)。
---
## 2026-08-12 模块:和风天气接入与高发病天气预警(计划 #12)
### 做了什么
- 后端:和风天气客户端(`/v7/weather/now` 实时 + `/v7/weather/3d` 预报);规则引擎(规格书 3.2.3);`weather_alerts` 表 + `/weather/now``/weather/alerts`;启动即评估一次 + 每 30 分钟定时写入。
- Web 告警中心与小程序告警页新增天气预警展示。
### 思路与决策
- 数据源按用户确认选用和风天气(QWeather,devapi 免费版);`location` 支持经纬度或 LocationID
- 未配置(`QWEATHER_API_KEY/LOCATION` 为空)时接口返回明确错误、定时任务跳过,不阻塞主流程(与微信骨架同一模式);
- 规则 v1:白僵病(湿度≥80% + 连续阴雨)、核型多角体病(温度突变,`stage=late5` 升级)、软化病(湿度>75% 提示);微粒子病依赖蚕种来源/消毒记录,待 #7 数据联动;
- 预警写入不按天去重(v1),前端只展示最近几条,后续可加去重策略。
### 验证与部署
- 规则/客户端 9 个单测(TDD 红→绿),三端构建通过;
- 第十次部署(schema 变更前 pg_dump `silk-20260812-1745.dump`);冒烟:`/weather/alerts=[]``/weather/now` 未配置 502 明确提示;
- 相关提交:`c7f18c1`(后端)、`c4fad42`(Web+小程序);回滚见服务器 README。
### 待办
- 提供和风天气 API Key 与默认位置后启用真实数据与定时预警;
- 微粒子病规则(蚕种来源标记 + 消毒记录缺失)待批次/消毒数据接入。
---
## 2026-08-12 模块:LAMP 检测管理(计划 #14)
### 做了什么
- 后端:`lamp_tests` / `lamp_test_steps` 表 + CRUD、步骤更新、结果照片上传(S3 `lamp/` 前缀)、结果录入(自动置 `resulted`);新建任务单自动生成标准 5 步。
- Web:LAMP 检测管理页(列表/新建/步骤/结果+照片)。
- 小程序:LAMP 检测页(技术员:步骤勾选、结果拍照、结果保存)。
- Web 构建:`manualChunks` 代码拆分(修复 rolldown WASM 内存超限)。
### 思路与决策
- 按规格书 3.3.2.1 固化 5 步流程,任务单创建时自动生成,避免人工漏步;
- 结果枚举(阳性/阴性/无效)与颜色判读提示(天蓝=阳性/紫罗兰=阴性)取自规格书;AI 图像判读模型训练未开始,v1 为人工录入 + 拍照留证,接口已为 AI 判读预留(后续在 ai-service 加端点);
- 结果录入通过 PATCH 的 `result` 字段触发状态流转(pending/testing → resulted + resultedAt),保证状态一致性;
- 删除任务单级联删除步骤。
### 验证与部署
- 步骤/结果枚举 2 个单测;三端构建通过(web 构建含代码拆分修复);
- 第十一次部署(schema 变更前 pg_dump `silk-20260812-1800.dump`);冒烟:创建→5 步→步骤完成→照片→resulted→列表→级联删除全 200
- 相关提交:`c6e5a76`(后端)、`d626f9d`(Web+小程序+构建拆分);回滚见服务器 README。
---
## 2026-08-12 模块:交叉验证 AI vs LAMP(计划 #15
### 做了什么
- `CrossValidate` 纯逻辑 + `AIClassFromDetections`;LAMP 结果录入后自动与同房间最近巡检比对并回写 `cross_status/cross_reason``GET /lamp-tests/:id/cross-validation` 详情接口;Web/小程序展示比对结论。
### 思路与决策
- 按规格书:一致 → 确认诊断;不一致 → 升级专家会诊;
- 关联策略:同房间最近一条巡检记录(v1),后续可按批次/时间窗细化;
- 无关联巡检或 LAMP 判读无效时置「不一致/待确认」并给出原因,避免静默;
- 交叉验证在结果落库后执行,保证读取到最新 result。
### 验证与部署
- 2 组单测(矩阵 + AI 归纳,TDD 红→绿);三端构建通过;
- 第十二次部署(schema 变更前 pg_dump `silk-20260812-1815.dump`);冒烟:negative→consistent、positive→inconsistentAI 健康 + LAMP 阳性→建议会诊);
- 相关提交:`1798b29`;回滚见服务器 README。
---
## 2026-08-12 模块:耗材管理(计划 #16)
### 做了什么
- 后端:`consumables` 表 + CRUD、`/consumables/alerts`(低库存/临期 30 天)、`/consumables/purchase-suggestions`;模型方法 `LowStockAlert/ExpiringAlert/PurchaseSuggestion`
- Web:耗材管理页(列表 + 预警 + 采购建议)。
### 思路与决策
- 阈值语义:`quantity < min_quantity` 才预警(等于不预警);采购建议 = 补足到安全阈值(向上取整),避免小数库存;
- 效期预警窗口 30 天(含已过期),临期与过期统一 `expiring` 类型;
- 规则放模型层方法,纯逻辑可单测;
- 小程序端按方案暂不做,等技术员 Web 后台(#17)统一规划。
### 验证与部署
- 3 个单测(TDD 红→绿);三端构建通过;
- 第十三次部署(schema 变更前 pg_dump `silk-20260812-1830.dump`);冒烟:低库存→low_stock + 建议 7、临期→expiring
- 相关提交:`65c993a`(后端)、`716e5e9`(Web);回滚见服务器 README。
---
## 2026-08-12 模块:技术员巡检记录页(计划 #17)
### 做了什么
- 后端:`GET /inspections` 返回 `roomName` 联查;
- Web:「巡检记录」页(列表 + 详情抽屉:原图、检测框/置信度、风险分与等级)。
### 思路与决策
- #17 的检测任务处理(#14)与耗材(#16)已在 Web 落地,本期补齐「巡检复查」入口,使技术员后台闭环;
- 详情用抽屉而非独立页,复用列表数据,减少接口调用;
- `roomName` 用非持久化字段在查询时联查,不改变表结构。
### 验证与部署
- 三端构建通过;第十四次部署;冒烟:列表 roomName=蚕房1#、detections=1
- 相关提交:`42ff238`;回滚见服务器 README。
### 阶段二小结
- 环境监测 + LAMP + 技术员后台(#12 天气、#13 阶段提示、#14 LAMP、#15 交叉验证、#16 耗材、#17 技术员后台)全部落地。
---
## 2026-08-12 模块:专家会诊(计划 #18)
### 做了什么
- 后端:`consultations` 表 + CRUD、受理/出方案/归档接口;关联 LAMP 任务创建时自动打包病例快照(房间名/巡检/LAMP/批次/天气预警 jsonb,避免引用漂移);状态流转校验。
- Web:专家会诊页(列表、病例快照详情抽屉、受理/出方案/归档)。
### 思路与决策
- 快照用 jsonb 固化:会诊时打包当时的数据,后续巡检/检测变化不影响历史病例;
- 触发来源:LAMP 交叉验证不一致可一键发起(传 `lampTestId` 自动带快照);巡检红/橙手动发起(本期不做自动);
- 状态机显式校验,非法流转直接 400;
- 专家角色当前由 admin/operator 承担(系统角色未扩展专家,规格书 2.4 的专家端暂以 Web 管理员操作);出方案后微信订阅消息触发点待 #11 凭证到位后接入。
### 验证与部署
- 状态流转 + 快照序列化 2 组单测(TDD 红→绿);三端构建通过;
- 第十五次部署(schema 变更前 pg_dump `silk-20260812-1845.dump`);冒烟:创建(快照含 lamp+inspection+roomName)→受理→出方案→归档全通过;
- 相关提交:`bf734c1`(后端)、`12a8964`(Web);回滚见服务器 README。
---
## 2026-08-12 模块:分子检测扩展(计划 #19)
### 做了什么
- `lamp_tests` 增加 `method/extra_data`qPCR Ct 自动判读(`JudgeQPCR`,阈值可配);SERS 光谱数据上传(S3 `spectrum/`);`spectrum_entries` 光谱库(CRUD + 上传);高光谱 `hyperspectral` 预留。
- Web:分子检测页(方式选择、qPCR 判读、SERS 上传)+ 光谱库 Tab;小程序展示方式。
### 思路与决策
- 按规格书 3.3「检测方式可插拔」:不重建表,扩展现有检测任务表(method + extra_data),保持 #14/#15/#18 关联不变;
- qPCR 判读规则用通用阈值(默认 Ct<35 阳性)且阈值可配,判读原因落 extraData 便于追溯;
- SERS 光谱先做「数据回传 + 光谱库框架」,比对/识别算法待光谱数据库积累后接入(ai-service 预留);
- 高光谱本期只留方法位,等检测数据标准。
### 验证与部署
- `JudgeQPCR`/光谱校验/`buildDataKey` 3 组单测(TDD 红→绿);三端构建通过;
- 第十六次部署(schema 变更前 pg_dump `silk-20260812-1900.dump`);冒烟:qPCR Ct[32,38]→positive、SERS 光谱 URL、光谱库增查删;
- 相关提交:`7bb87dd`(后端)、`3cd1b82`(Web+小程序);回滚见服务器 README。
---
## 2026-08-12 模块:多检测方式推荐引擎(计划 #20)
### 做了什么
- `RecommendMethod` 纯逻辑 + `GET /detection-methods/recommend`;Web 分子检测新建弹窗内置推荐工具。
### 思路与决策
- 规则量化自规格书 3.3.2/11.2(时间/成本/难度);加权评分:常规平衡 3/4/3,紧急与最快提高时间权重,新手提高难度权重,低成本提高成本权重;
- 高光谱「理论可行待验证」:有其他方式时不推荐,仅有高光谱时才给出并注明;
- 纯计算接口无 DB 依赖,便于前端即时交互与后续扩展(如按批次/房间数据自动带参)。
### 验证与部署
- 6 个推荐矩阵单测(TDD 红→绿);三端构建通过;
- 第十七次部署(无 schema 变更);冒烟:low_cost→LAMP、fastest→SERS、紧急无 SERS→LAMP、仅高光谱→待验证提示;
- 相关提交:`47a2da3`;回滚见服务器 README。
---
## 2026-08-12 模块:疫病溯源(计划 #21)
### 做了什么
- `trace_records` 表 + CRUD;一级自动溯源(环境回溯/历史关联/传播推断 → 初报 + 来源判定);二级分病种排查清单(规格书 3.8.3)→ 分析报告;三级专家/实验室备注;Web 溯源页。
### 思路与决策
- 按规格书 3.8 三级架构:一级自动(数据聚合 + 规则)、二级人工排查(清单作答统计内源/外源倾向 + 置信度)、三级专业记录(字段预留);
- 环境回溯 v1 用房间最近温湿度样本(≥80% 高湿 / >30℃ 或 <20℃ 温度突变);连续多日判定待数据积累后细化;
- 历史关联用同房间同病种 resulted LAMP 记录(JSONB `@>` 匹配),90 天窗口;
- 清单答案统计:内源倾向项答「是」计内源分,「否」计外源分,反向亦然,未答计未知;结论附置信度;
- 区域关联(同乡镇)留待 #22 热力图数据接入。
### 验证与部署
- 5 组溯源规则单测(TDD 红→绿);三端构建通过;
- 第十八次部署(schema 变更前 pg_dump `silk-20260812-1920.dump`);冒烟:创建→清单 4 项→auto(reported/内源/0.6)→清单提交(analysis/0.725);
- 相关提交:`dc97d1c`(后端)、`5ce99ab`(Web);回滚见服务器 README。
---
## 2026-08-13 模块:区域发病统计(计划 #22)
### 做了什么
- `rooms.region` 字段 + `GET /trace-records/region-stats`(近 N 天按区域聚合);Web 溯源页顶部柱状图 + 病种饼图;蚕房表单区域字段。
### 思路与决策
- 区域数据由蚕房管理录入(不自动解析位置字符串,避免误判);
- v1 用 ECharts 统计图表表达热力趋势;真正乡镇/县级地图(GeoJSON 底图 + 坐标)需要地图服务或离线数据,后续按需接入;
- 聚合纯逻辑独立(分组/降序/空区域剔除),便于单测与前端复用。
### 验证与部署
- 2 组聚合单测(TDD 红→绿);三端构建通过;
- 2026-08-13 第一次部署(schema 变更前 pg_dump `silk-20260813-0010.dump`);冒烟:SmokeTown total=2、DiseaseA/B 各 1
- 相关提交:`7949f90`(后端)、`9c5af92`(Web);回滚见服务器 README。
---
## 2026-08-13 模块:蚕房健康画像与年度发病统计(计划 #24)
### 做了什么
- `/health-profiles/:roomId`(巡检/LAMP/事件聚合 → 健康分 + 评级);`/trace-records/monthly-stats`(年度按月发病);Web 蚕房「健康画像」抽屉 + 溯源页年度折线图。
### 思路与决策
- 健康分扣分制:红 -25/橙 -12/黄 -4、LAMP 阳性率 -30、会诊 -10、溯源 -8,钳制 0-100;评级 优≥85/良≥70/中≥55/差;
- 月度聚合复用 trace_records(发病事件)按 `to_char(created_at,'YYYY-MM')` 分组;
- 踩坑记录(重要):Gin 不允许在 `:id` 参数节点下再挂子路由(`/rooms/:id/health-profile``/rooms/:id` 冲突 panic)→ 独立路径;同名路由注册函数重复注册会 panic;用 `apply_patch` 新增文件时若文件已存在会覆盖旧文件(原 `health.go``/health` 路由被覆盖,已恢复);handler 读取路由参数必须与 `:param` 命名一致。
### 验证与部署
- 3 组单测(TDD 红→绿);三端构建通过;
- 2026-08-13 第二次发布(含 4 处修复);冒烟:蚕房1# score=96 优(risk 黄 1);
- 相关提交:`cbcb22e`/`ccda60e`(功能)、`725d98a`/`492d1ef`/`3e9916a`/`008a7b1`(修复);回滚见服务器 README。
---
## 2026-08-13 模块:Web 测试基建(计划 #27)
### 做了什么
- Web 引入 Vitestjsdom),`npm test` 命令;`utils/format.ts` 公共函数 + 3 个单测;巡检页接入公共函数。
### 思路与决策
- 测试基建先搭最小可用(vitest + jsdom),纯函数优先测试(TDD 红→绿),组件测试等后续按需补;
- 抽取内联映射为公共函数,既便于复用也给了首批可测单元;
- Go 侧测试骨架此前已随各模块建立(model/service/handler 均有单测)。
### 验证与部署
- `npm test` 3/3、lint、build 全过;无后端/schema 变更,Web 已同步部署;
- 相关提交:`0e6dc00`;回滚见服务器 READMEweb `dist.old-20260813-4`)。
---
## 2026-08-13 模块:ai-service 扩展(#23 骨架 + #26
### 做了什么
- `POST /stream-detect`:OpenCV 拉流抽帧(3 帧)→ 检测,返回帧数与检测列表(骨架,未接正式巡检编排);
- `GET /metrics`:模型模式/uptime/请求数/平均延迟 + nvidia-smi GPU 信息。
### 思路与决策
- #23 按计划二期,本期只做能力骨架:接口形态先定(url → 抽帧检测),视角数据与巡检任务编排待补;
- #26 监控先做服务级指标 + GPU 可选采集(nvidia-smi 存在即读,不存在返回 null),不依赖具体 GPU 型号;
- 顺带发现:开发服务器经 nvidia-smi 可读到 NVIDIA 940MX 2GB,说明本地非 T4 环境也能做基础 GPU 监控。
### 验证与部署
- pytest 8/8TDD 红→绿);ai-service 更新至开发服务器;
- 冒烟:health okmetrics 返回 GPU 信息;stream 无 url 被拒(400/422);
- 相关提交:`156b670`;回滚:ai-service 源码 git 恢复 + 重启 start.sh。
---
## 2026-08-13 决策:时序存储(计划 #25)
### 结论
MVP 沿用 IoTDB(现状);TDengine 作为生产规模化候选(先基准测试再评估)。
### 思路与依据
- IoTDB 已部署运行、代码已接入且带 PostgreSQL 降级兜底;当前量级无性能瓶颈;
- TDengine 优势(标准 SQL/聚合快/生态活跃)主要在后续复杂分析报表阶段体现,换入需承担迁移与运维成本;
- 规格书 5.2 倾向 TDengine,但《后续工作计划》本身标注「不阻塞 MVP」,属可延后决策。
### 后续触发条件
聚合报表/BI 需求复杂化、单机性能瓶颈、生产上云规划时 → 做同数据量基准测试(吞吐/延迟/成本/许可)再定;若切换采用「双写灰度 + 数据对账」迁移,并重写时序读写层。
---
## 2026-08-13 文档同步:README 与后续工作计划
### 做了什么
- `README.md`:补充已完成功能的核心能力章节(1.8-1.17)、权限码数量(36)、技术栈(Go 1.23 / FastAPI+ONNX+OpenCV / Vitest)、目录结构(ai-service)、后端模块表(12 个新模块)、环境变量表(S3_BUCKET_IMAGES、AI_SERVICE_BASE、WECHAT_*、QWEATHER_*)、本地开发命令(npm test)。
- `后续工作计划.md`:按实际完成状态勾选 #5-#24#27#23/#26 标为骨架完成,#1-4 标注「挂起:物理机问题」,顶部加完成状态说明。
### 思路
- 说明文档(README)与进度文档(后续工作计划)长期未随功能迭代更新,本次一次性同步到 2026-08-13 状态;
- 详细设计/验证/回滚仍以 `开发交接记录.md` / `变更记录.md` 为准,README 只做概览。
### 相关提交
`待提交`(README、后续工作计划、变更记录、开发交接记录)。
---
## 2026-08-13 文档同步(第二轮):README / 部署指南 / 故障排查
### 做了什么
- README:API 概览表补 12 组新接口;权限矩阵补 20 个新权限码;新增 12.6 ai-service 本地开发、12.7 开发服务器部署摘要。
- 部署指南(物理机):架构图补 ai-service:8000;新增「13. 部署 ai-service」章节。
- 故障排查处理记录:追加 8 类近期踩坑(NetBird 登录过期/隧道闪断、pip 国内源、rolldown WASM 内存、ETXTBSY、Gin 路由冲突/重复注册/文件覆盖/参数名、PowerShell 中文 JSON、tar 时间戳、SSH 命令后台化)。
### 说明
- 文档按「现状可用」原则更新,详细命令与回滚以 `开发交接记录.md` / 服务器 README 为准。
### 相关提交
`README.md``部署指南(物理机).md``故障排查处理记录.md``变更记录.md``开发交接记录.md`
---
## 环境与踩坑备忘(新同事必读)
- **VPN**:开发服务器经 NetBird 访问;服务 Running 后需 `netbird up`,登录走 SSO(管理端 `115.191.19.95:6680`)。
- **npm**:本机 npm 12 默认禁止 remote tarball,安装需 `npm install --allow-remote=all`miniapp 因 webpack 版本冲突需再加 `--legacy-peer-deps`(不改 package.json)。
- **服务器代码形态**:开发服务器**没有 silk 主仓库 git**(仅有 wvp-src),代码回滚以「文件备份 + 本地 commit」为准;部署前必做 pg_dump(涉及 schema 变更时)并保留旧二进制/旧 dist。
- **服务启动**:后端 `start.sh`(导出环境变量后 nohup 启动);注意 `start.sh``WVP_API_BASE=18978` 与当前 WVP 实际端口 `18080` 不一致(既有问题,未修)。
- **数据库**:服务器 PostgreSQL 实际为 **14**(部署指南写 16,以实际为准);库名 `silk`,用户 postgres;默认管理员 `admin / silk@123`README/config 默认值,部署指南里的 admin123 已过时)。
- **部署流程与回滚命令**:见 AGENTS.md「部署到开发服务器」章节与服务器 `/home/pan/backups/rollback-20260812/README.md`
---
## 当前状态与剩余事项
### 知识库(#10)内部剩余
- ~~SERS 操作教程(P1)~~、~~季节性防控提醒(P2)~~、~~「其它/未知」类别~~:已于 2026-08-12 完成;
- 专家经验沉淀(P1):依赖专家会诊(#18)落地后沉淀历史案例,暂缓;
- 多图图谱(每病种多张)待扩展;
- 图谱图片素材等待三个方向(数据集/专家/巡检)导入。
### 下一候选模块(方案已给出、待用户确认)
- ~~饲养阶段风险提示(#13~~:已于 2026-08-12 完成(见上方模块记录)。
### 计划中的其他模块(按《后续工作计划》)
- AI 巡检闭环:#5 ai-service、#6 Go 对接、#7 蚕匾/批次管理、#8 拍照巡检、#9 风险评分引擎、#11 推送;
- 环境监测 + LAMP#12 天气接入、#14 LAMP 检测管理、#15 交叉验证、#16 耗材管理、#17 技术员后台;
- 专家诊断 + 溯源:#18 专家会诊、#19 qPCR/SERS/高光谱、#21 疫病溯源、#22 区域热力图、#23 摄像头流巡检;
- 数据分析与运维:#24 健康画像、#25 时序存储决策、#26 GPU 监控、#27 测试基建。
---
## 2026-08-13 项目现状与规格说明书优化分析
### 做了什么
- 对照 `.cc-connect/attachments/蚕病智能防控平台规格说明书.md` V2.1,抽查 Go 后端、Web、小程序、APP、ai-service、测试和运维文档;
- 新增 `项目现状与规格说明书优化分析.md`,包含执行摘要、功能现状矩阵、规格书 V2.2 修订建议、P0/P1/P2 问题清单、分阶段优化路线图和新增功能建议;
- 识别到风险评分语义、公开视频流/密钥返回、默认凭据、迁移容错、qPCR 空 Ct 判读和小程序类型错误等高优先级问题;本次只分析和记录,未修改业务代码或部署环境。
### 设计思路与决策依据
- 采用“规格—实现—路线图”综合评审结构,把已实现、骨架/mock、手工录入、接口预留和真实联调分开,避免用单一完成勾选误导验收;
- 先以代码和本地命令为事实依据,再给出建议;codebase-memory 图谱接口在当前会话不可用,已在报告中披露并回退到目标源码核查;
- 优先级以数据/隐私暴露、业务错误传播范围、生产恢复难度和核心闭环阻断程度确定,新增功能排在安全与正确性基线之后。
### 验证结果
- `server-go`: `go test ./...``go vet ./...` 通过;
- `web`: `npm test` 3/3 通过,`npm run lint` 通过但有 5 个 warning
- `ai-service`: 本机缺 fastapi/Pillowpytest 收集失败;
- `app`: 本机目录缺 tsc/eslint 可执行依赖,类型与 lint 未运行成功;
- `miniapp`: `npx tsc --noEmit` 发现 dashboard 两处 TS1382
- 未连接开发服务器或外部依赖,未做生产联调、渗透、负载、恢复或真实模型验收。
### 回滚点
- 本交付仅新增 `项目现状与规格说明书优化分析.md` 并追加本节;回滚时删除新增文档并移除本节即可,无数据库、配置、构建产物或服务器变更。
---
## 2026-08-13 规格说明书 V2.2 与整改实施计划
### 做了什么
- 新增 `蚕病智能防控平台规格说明书_V2.2.md`:对齐当前 Go + Python 混合架构,增加能力七态、稳定需求 ID、业务异常流程、数据/API/AI/安全/非功能规范、阶段退出条件和开放决策;
- 新增 `项目整改实施计划_V1.0.md`:把阶段 A~C 拆为 15 个可独立评审任务,列出负责人、涉及文件、接口、TDD 步骤、验证命令、依赖顺序和回滚方法;
- 近期整改聚焦安全、业务正确性、迁移/CI/可靠消息、检测与发病主链、消毒/种源、离线同步和运维验收;真实多病种模型、摄像头群体 AI、SERS/高光谱等研究项明确延后。
### 设计思路与决策依据
- 规格书区分“目标能力、当前状态、验收证据”,不再以存在页面/接口等同于功能完成;
- 风险评分、检测判读、视频/密钥安全和 schema 一致性列为 Wave 1,业务扩展必须在 P0 关闭后进入;
- 对未获确认的迁移工具、CI 平台、云服务、数据保留期、APP 范围和 qPCR 专业规则只设置决策门,不擅自选型;
- 整改任务按 TDD、小步迁移、功能开关、幂等、可观测和可回滚设计,便于多同事分工执行。
### 验证结果
- 两份文档已执行标题结构、需求 ID、任务编号、占位符、路径引用和 Markdown diff 检查;
- 本次仅创建文档并追加交接记录,没有修改业务代码、依赖、数据库、生成产物或服务器;
- 文档中的命令属于后续整改验收步骤,本次未宣称相应功能已经修复或测试通过。
### 回滚点
- 删除 `蚕病智能防控平台规格说明书_V2.2.md``项目整改实施计划_V1.0.md` 并移除本节即可;原 V2.1 附件、业务代码、数据库和部署环境均未改动。
---
## 2026-08-13 codebase-memory 索引生成
### 做了什么
- 使用本机已安装的 codebase-memory-mcp v0.10.2`C:\Users\Administrator\AppData\Local\Programs\codebase-memory-mcp\codebase-memory-mcp.exe`)对仓库 `D:\silk-master-84e4ddc` 执行 `index_repository`,生成知识图谱索引:3409 节点、10351 边,状态 ready
- 当前 Codex `config.toml` 原先缺少 `codebase-memory-mcp` 的 MCP 服务配置,已补上 `[mcp_servers.codebase-memory-mcp]` 条目并验证 `codex mcp list` 显示 enabled;原配置备份为 `C:\Users\Administrator\.codex\config.toml.cbm-bak-20260813-213259`
### 设计思路与决策依据
- 索引存放在 codebase-memory-mcp 本地缓存(`C:\Users\Administrator\.cache\codebase-memory-mcp`),仓库内 `.codegraph` 仅为忽略规则占位,不提交业务产物;
- 通过官方 CLI 直接索引,不依赖当前会话是否已加载 MCP 工具,便于后续用 `search_graph`/`trace_path` 等图谱接口查询。
### 验证结果
- `list_projects`:项目 `D-silk-master-84e4ddc` 已登记(branch `dev_wjs`3409 节点、10351 边);
- `index_status`status ready;24 个文件存在局部解析缺口(多为 SCSS/少量 TSX 行),84 个文件按设计排除(gitignore/构建产物/二进制资源),非索引失败;
- `search_graph`:按 `.*Handler.*` 查询返回 5 条结果,图谱查询可用;
- `codex mcp list``codebase-memory-mcp``node_repl` 均 enabled。
### 回滚点
- 删除索引:`codebase-memory-mcp cli delete_project '{"project":"D-silk-master-84e4ddc"}'`
- 恢复 Codex 配置:用备份 `config.toml.cbm-bak-20260813-213259` 覆盖 `config.toml` 即可;本次未改业务代码、数据库或服务器。
---
## 2026-08-13 整改 Task 1:恢复可复现的多端质量基线
### 做了什么
- 修复小程序 `dashboard` 两处 TS1382 裸 `>`,新增 `npm run typecheck`
- 小程序 tsconfig 增加 `skipLibCheck`,修复 alerts、设备控制、LAMP、通知、视频播放、app、知识详情等源码类型问题,使 `tsc --noEmit` 通过;
- APP 依赖对齐 RN 0.74`react` 调整为 `18.2.0`,移除未使用的 `victory-native`,补充 `@react-native/eslint-config``eslint``prettier`,新增 `.eslintrc.js`
- APP 清理未使用导入/变量,`npm run tsc` 通过,`npm run lint` 无 error
- 新增 `scripts/verify.ps1` 单命令质量门禁,覆盖 Go、Web、小程序、APP、ai-service`ai-service/README.md` 增加质量检查说明;
- `.gitignore` 增加 `scripts/verify.ps1` 例外。CI 接入未做,等待 Task 0 确认平台。
### 设计思路与决策依据
- Task 1 目标是建立可复现门禁,因此以“最小修复、不重排全仓”为原则:Taro 依赖声明文件用 `skipLibCheck` 隔离,真实源码错误逐个修正;
- APP 不重排全仓:将 `prettier/prettier` 降为 warning,保留 1032 个风格 warning 待后续单独格式化任务处理,不让既有格式差异阻塞 lint 门禁;
- APP 安装失败根因是 RN 0.74 要求 `react@18.2.0`,以及 `victory-native` 最新依赖链引入 React 19 的 Skia;因源码未引用 `victory-native`,直接移除;
- `verify.ps1` 显式解析 Go 路径,并在存在 `.venv` 时使用 `ai-service/.venv/Scripts/python.exe`,解决本机 PATH 与系统 Python 缺依赖问题。
### 验证结果
- `powershell -ExecutionPolicy Bypass -File scripts/verify.ps1` 最终 exit 0
- Go`go test ./...``go vet ./...``go build ./...` 通过;
- Web`npm test` 3/3 通过,`npm run lint` 有 5 个 warning`npm run build` 通过;
- 小程序:`npm run typecheck``npm run build:weapp` 通过;
- APP`npm run tsc` 通过,`npm run lint` 0 error / 1032 warning
- ai-servicepytest 8/8 通过,仅保留 Starlette/httpx deprecation warning
- 未执行 CI、服务器部署、真实模型或容量验收,这些仍等待 Task 0 决策与后续任务。
### 回滚点
- 本任务前基线提交为 `1b8cab1`;回滚可删除/还原本 Task 1 分支提交,恢复 `.gitignore`、APP 依赖锁文件与小程序类型修复;
- 无数据库、环境变量、服务器或生成产物变更;APP `node_modules` 为忽略目录,不影响回滚。
---
## 2026-08-13 整改 Task 0:固化开放决策与整改基线
### 做了什么
- 新增 `docs/decisions/2026-08-13-remediation-decisions.md`,按固定表头固化 8 项决策;
- `后续工作计划.md` 增加 Wave 0-4 状态表,使用规格书 V2.2 七态能力状态;
- 决策范围覆盖迁移工具、CI/制品、数据保留、qPCR、APP 范围、模型指标门槛、云部署/域名/证书。
### 设计思路与决策依据
- 未获得明确产品/合规/专业确认的事项,按“保持现状 + 明确复审触发条件”记录,不擅自进入生产部署;
- 迁移工具选择 `golang-migrate/migrate/v4`,与实施计划中的 `NNNNNN_name.up.sql/.down.sql` 命名和 PostgreSQL 目标一致;
- CI 当前无 remote,先保留 `scripts/verify.ps1` 本地门禁,避免配置无法验证的外部 CI。
### 验证结果
- `rg -n "Decision ID|迁移|CI|保留|qPCR|APP|二分类" docs/decisions/2026-08-13-remediation-decisions.md` 可检索到对应主题;
- `git diff --check` 无空白错误;
- 本交付只新增/修改文档,不改业务代码、依赖、数据库或服务器。
### 回滚点
- 删除 `docs/decisions/2026-08-13-remediation-decisions.md`,移除 `后续工作计划.md` Wave 0-4 表和本节即可;无运行时影响。
---
## 2026-08-13 整改 Task 2:版本化数据库迁移与 Schema 启动门禁
### 做了什么
- 采用 `golang-migrate/migrate/v4 v4.18.2`,新增 `server-go/migrations/` 嵌入式迁移包;
- 新增 `000001_baseline.up.sql` / `000001_baseline.down.sql`,覆盖当前 26 张业务表、索引和唯一约束;
- 新增 `internal/database/migrate.go``RunMigrations``CheckSchemaVersion``CurrentSchemaVersion`
- 上线前将 `000001_baseline.up.sql` 调整为 `CREATE TABLE/INDEX IF NOT EXISTS`,兼容已由 AutoMigrate 建表的开发库;
- 开发服务器首轮启动暴露 `migrate.Close()` 会关闭底层数据库连接,已改为只关闭迁移 source,保留 `sql.DB` 供后续启动检查使用;
- `database.Init` 改为先执行版本化迁移并校验 `schema_migrations`,生产环境忽略 `ALLOW_DEV_AUTOMIGRATE`;开发环境仅显式开启时允许 AutoMigrate
- `config.Config` 增加 `APP_ENV``ALLOW_DEV_AUTOMIGRATE`;README 与物理机部署指南补充迁移说明和环境变量;
- 新增 sqlmock 测试,覆盖版本匹配、版本不匹配、空版本、dirty 状态和嵌入式迁移文件解析;
- 已在开发服务器 `100.83.103.1` 部署迁移版本。
### 设计思路与决策依据
- SQL 迁移文件作为唯一 schema 事实来源,不使用旧 `silk-db-backup.dump` 中的 app_runtime/public 结构(两套均为旧版);
- 基线 SQL 由当前 GORM 模型 dry-run 生成后人工核对,保留当前模型的 UUID、bigserial、jsonb、varchar 长度、默认值和索引;
- 选择 v4.18.2 而不是 v4.19.1,是因为 v4.19.1 要求 Go 1.24,项目基线为 Go 1.23
- 启动阶段任何 schema 版本缺失、落后或 dirty 都直接失败,避免代码与数据库不一致时继续提供 API。
### 验证结果
- `go test ./...``go vet ./...``go build ./...` 全部通过;
- `internal/database` 迁移版本检查与嵌入式迁移解析单测通过;
- 开发服务器:`schema_migrations``1|f``/api/v1/health` 200Web `5174` 200,后端日志显示 `版本化迁移完成 schemaVersion=1`
- 已执行旧库升级验证;真实空库建库和 down 回滚演练尚未执行。
### 回滚点
- 本任务前基线提交为 `20bea00`;回滚可还原 Task 2 提交并恢复 go.mod/go.sum
- 若迁移已应用到数据库,必须先恢复迁移前数据库备份,不能只回滚代码而保留不兼容 schema;
- 开发服务器回滚点:数据库备份 `/home/pan/backups/silk-20260813-234221.dump`,旧二进制 `/home/pan/silk/server-go/server-go-linux.bak-20260813-234221`
- 开发服务器无 git 仓库,回滚按旧二进制 + 数据库 dump 恢复,不再依赖服务器 git tag。
---
## 2026-08-13 Task 3 延后记录
### 做了什么
- 按用户要求将 Task 3“移除默认密钥与默认管理员密码”从当前执行顺序中跳过;
- 已同步记录到 `项目整改实施计划_V1.0.md``docs/decisions/2026-08-13-remediation-decisions.md``后续工作计划.md` 和本文件;
- Task 3 保留到最后处理,不是取消。
### 影响
- 默认密钥、默认管理员密码和小程序/APP 密码预填在最后阶段前继续保持现状;
- 该 P0 风险在最后阶段开始前未关闭;开始最后阶段前需要明确密钥轮换窗口、管理员初始化策略和客户端发布窗口。
### 回滚点
- 本记录仅修改文档,无代码、数据库、服务器或生成产物变更;如需回滚,删除本记录并恢复相关计划/决策表即可。
---
## 2026-08-14 整改 Task 4:收口视频访问与摄像头密钥输出
### 做了什么
- 新增视频短时令牌服务:`IssueVideoToken` / `ValidateVideoToken` / `ValidateVideoTokenForUser`,令牌绑定用户、资源类型、资源 ID、用途和 5 分钟有效期;
- `Camera.PasswordEnc``Camera.GbAuthPassword` 改为 `json:"-"`,新增 `CameraPublic` / `CameraInput` DTO,创建和更新仍可写入密码,但列表/详情/创建/更新响应不再返回密码;
- 实时播放和录像播放接口统一返回带 `videoToken` 的代理 URL,不再返回 WVP/ZLM 直连地址;
- `/video/clips/:clipId/stream``/video/cameras/:id/live/stream``/video/cameras/:id/live/proxy` 必须校验 token,缺失返回 401,错误/过期/资源错配返回 403;
- 告警片段、Web 录像列表、APP 和小程序播放链路同步改为使用带 token 的地址;
- WVP SIP 配置响应移除 `sipPassword`;前端 DAL 同步调整。
### 设计思路与决策依据
- 播放器标签无法稳定携带 Authorization,因此采用短时签名 token 作为流代理的 bearer capability,同时保留播放地址生成接口的 JWT + 权限校验;
- 摄像头密钥字段允许写回但禁止输出,创建/更新走独立 `CameraInput`,对外统一 `CameraPublic`
- 当前项目没有用户级资源 ACL,Task 4 先收口“未授权直连”和“密钥返回”两类 P0;按用户/房间的对象级授权留待后续任务。
### 验证结果
- `scripts/verify.ps1` 最终 exit 0Go test/vet/build、Web test/lint/build、小程序 typecheck/build、APP tsc/lint、AI pytest 均通过;
- 新增测试覆盖:摄像头响应不含密码字段、token 正常/过期/资源错配/用户错配、流代理缺失或错误 token 返回 401/403
- 未部署开发服务器,未做真实摄像头播放联调。
### 回滚点
- 本任务前分支提交为 `440cf80`;回滚可还原 Task 4 提交;
- 若已部署流代理版本,回滚需恢复旧二进制并重启,无需数据库变更;播放地址需由客户端重新请求。
---
## 2026-08-14 整改 Task 5:修复 WebSocket 越权与 AI 流 SSRF
### 做了什么
- WebSocket 改为一次性 ticket 连接:`GET /api/v1/ws/ticket` 签发 60 秒单次 ticket`/ws` 不再接受 JWT query,客户端统一使用 ticket
- 新增 `DeviceAuthorizer` / `DBDeviceAuthorizer``subscribe.device` 必须校验用户 `device:read` 权限;无权订阅返回 `subscribe.denied`
- WebSocket 增加 Origin 白名单,`WS_ALLOWED_ORIGINS` 可配置;
- 移除普通连接的 `telemetry.all`、全局 `alarm`、全局 `device.status` 广播,只推送给已授权订阅的设备房间;
- APP/小程序 WS 客户端先请求 ticket 再连接,避免长期 JWT 进入 URL;
- AI 服务新增 `POST /internal/stream-tasks`:要求 `X-Internal-Key``taskId``streamRef`,限制拉流 host 白名单、并发 worker 数和最大帧数;旧 `/stream-detect` 任意 URL 入口改为 410。
### 设计思路与决策依据
- WebSocket 播放/订阅场景不适合把长期 JWT 放进 URL;采用服务端签发的一次性 ticket 降低代理日志泄露和重放风险;
- 当前没有用户级资源 ACL,设备订阅先用 RBAC `device:read` 做对象授权;组织/房间级 ACL 留待后续任务;
- AI 流任务改为内部服务接口和受限 worker,避免公网客户端直接传任意 URL,也避免在 FastAPI 事件循环中阻塞式 `VideoCapture.read()`
### 验证结果
- `scripts/verify.ps1` 最终 exit 0Go test/vet/build、Web、小程序、APP、AI pytest 11/11 均通过;
- 新增 Go WS 测试覆盖非法 Origin、ticket 单次/过期、JWT query 拒绝、无权设备订阅、全局广播不泄露;
- 新增 AI 测试覆盖内部 key 校验、任务创建、metadata/公网地址拒绝和旧接口禁用;
- 未部署开发服务器,未做真实 WS 推送和摄像头拉流联调。
### 回滚点
- 本任务前分支提交为 `1a29def`;回滚可还原 Task 5 提交;
- WS/AI 改动无数据库 schema 变更;若已部署,恢复旧二进制并重启即可,但需同步回滚客户端 WS 连接方式。
## 2026-08-14 整改 Task 6:修复 AI 风险语义并隔离 Mock 数据
### 做了什么
- AI 服务 `/detect` 响应新增 `modelVersion``isMock``status``abnormalProbability``healthy` 高置信度不再贡献异常概率,空检测或 `unknown` 返回 `unknown`,不自动当健康;
- Go 风险评分改为只消费 AI 异常概率:`RiskInput` 四个组件全部可空,缺失项不填 0;可用权重归一化后输出 `RiskAssessment`score/level/confidence/modelVersion/ruleVersion/components/missing);
- 巡检记录新增 `risk_assessment``model_version``is_mock` 字段和 `000002_risk_assessment` 迁移;健康画像统计默认排除 mock,Mock 结果不触发微信告警;
- `APP_ENV=production` 时收到 `isMock=true` 按失败记录并输出 error 日志,避免把联调数据当作生产检测结论;
- Web/小程序巡检页显示 Mock 标识;交叉验证中空检测/`unknown` 不再被当作 healthy
- 新增只读历史评估 SQL `scripts/risk_historical_review.sql`,统计历史 healthy 高置信度记录与风险分布,未执行批量重算。
### 设计思路与决策依据
- 规格书 AI-INS-002 要求只用 `abnormalProbability` 计算 AI 风险,因此修复了原先取最大 confidence 导致 healthy=0.95 也能得 47.5 分的问题;
- RISK-002 要求缺失数据不能以 0 冒充正常,所以环境/阶段/整齐度改为指针输入,缺失项进入 `missing` 并在 JSON 中返回 null
- 权重沿用 0.5/0.2/0.15/0.15 并标记为 `risk-v2-2026.08.14` 待试点校准规则;`confidence` 只输出 low/medium/unknown,不声称未校准结论为 high;
- `000007_inspection_idempotency` 未另建迁移,因为 `000001_baseline` 已包含 `idempotency_key` 唯一索引;本次只补风险语义相关字段。
- 历史旧记录没有 `is_mock` 标识,不能自动判别是否来自 mock;只读 SQL 报告用于人工审阅,未批量重算或改写旧数据。
### 验证结果
- `scripts/verify.ps1` exit 0Go test/vet/build、Web test/lint/build、小程序 typecheck/build、APP typecheck/lint、AI pytest 15/15 均通过;
- 新增测试覆盖 healthy/sick/unknown 异常概率、缺失组件归一化、风险分级边界、AI 响应解析、空检测 unknown、handler 风险输入和迁移版本;
- 未部署开发服务器,未对现有库执行 `000002` 迁移;历史只读 SQL 报告未执行。
### 回滚点
- 本任务前分支提交为 `839ba91`;回滚可还原 Task 6 提交;
- 数据库回滚执行 `migrate -path ... -database ... down 1` 或手工执行 `000002_risk_assessment.down.sql`,可移除新增三列和索引;`risk_score/risk_level` 仍保留,历史数据不回写。
## 2026-08-14 Task 7 延后记录
### 做了什么
- 按用户要求将 Task 7“修订 qPCR 判读与检测质控”从当前执行顺序中跳过;
- 已同步记录到 `项目整改实施计划_V1.0.md``docs/decisions/2026-08-13-remediation-decisions.md``后续工作计划.md` 和本文件;
- Task 7 保留到最后处理,不是取消。
### 影响
- qPCR 继续维持“只录入、不自动判读”,不会在当前轮实现 positive/negative/invalid/indeterminate 四态结果;
- 恢复 Task 7 前仍需领域专家签字确认 protocolVersion、对照规则和阈值;
- 该 P0 风险在最后阶段开始前未关闭。
### 回滚点
- 本记录仅修改文档,无代码、数据库、服务器或生成产物变更;如需回滚,删除本记录并恢复相关计划/决策表即可。
## 2026-08-14 整改 Task 8:建立可靠通知、吊销与跨实例状态
### 做了什么
- 新增 `outbox_events``notifications` 表和 `000004_notifications_outbox` 迁移,通知列表从进程内存改为 PostgreSQL 持久化;
- 新增 `Outbox.PublishTx(tx, event)`:业务事务内写入事件,重复 `eventId` 通过唯一索引幂等;worker 领取、发送、退避重试并记录 `pending/sending/sent/retry/failed/cancelled`
- JWT 吊销与登录限流迁移到 Redis:新增 `middleware.StateStore`/`RedisState`,Redis 不可用时登录、刷新、吊销和已认证接口返回 503,不再静默回退单机内存;
- 巡检风险微信推送改为事务内写 Outbox,不再使用进程内 goroutine;微信发送结果保存模板、用户授权、微信 `errcode/errmsg`、尝试次数和最终状态;
- `/notifications` 改读 PostgreSQL;手动通知也落库。
### 设计思路与决策依据
- 可靠通知不能依赖进程内存;PostgreSQL 保存事件与业务同事务,Redis 只保存短时效的吊销和限流状态,降低多实例一致性风险;
- Outbox 幂等由 `event_id` 唯一索引和 `ON CONFLICT DO NOTHING` 保证;worker 领取时用 `pending/retry -> sending` 原子更新,避免多实例重复处理;
- Redis 不可用时采用保守失败而不是降级:认证状态和限流丢失会造成越权或绕过风险,业务价值大于可用性损失;
- 微信未绑定或未授权不是临时失败,写入 `cancelled`;模板未配置或微信返回错误进入重试/最终失败,便于人工查看。
### 验证结果
- `scripts/verify.ps1` exit 0Go test/vet/build、Web test/lint/build、小程序 typecheck/build、APP typecheck/lint、AI pytest 15/15 均通过;
- 新增测试覆盖 Outbox 幂等发布、重启后领取 pending、Redis 状态不可用保守失败、吊销跨状态、登录锁定/清空和微信响应码解析;
- 未部署开发服务器,未执行 `000004` 迁移;未做真实 Redis/微信联调和进程重启演练。
### 回滚点
- 本任务前分支提交为 `a6a996a`;回滚可还原 Task 8 提交;
- 数据库回滚执行 `000004_notifications_outbox.down.sql`,可删除 `notifications``outbox_events`;未发送的 Outbox 数据会随回滚丢失,回滚前必须先备份或暂停 worker;
- 认证状态回滚需恢复旧二进制,Redis 中的吊销/限流键由 TTL 自然过期。
## 2026-08-14 整改 Task 9:建立统一检测任务、样本链与发病事件
### 做了什么
- 新增 `detection_tasks``samples``disease_events` 表及 `000005_detection_disease_events` 迁移;`trace_records` 增加 `disease_event_id``lamp_tests` 增加 `detection_task_id`
- 实现统一检测任务状态机 `draft/pending/assigned/sampling/testing/review/completed/cancelled`、样本状态机 `created/collected/handed_over/received/testing/consumed/disposed`、发病事件状态机 `suspected/confirmed/controlled/closed/reopened`
- 新增 `/detection-tasks``/samples``/disease-events` 后端 API;Web 新增「检测任务」页面,支持建单、分派、样本流转、结果录入和发病事件管理;
- 橙色/红色巡检通过 Outbox 幂等创建待确认检测任务,`source_key` 唯一索引防止重复建单;LAMP 阳性或统一检测任务阳性结果自动创建发病事件,并自动生成关联溯源记录;
- 确诊发病事件必须有证据,不能仅凭状态字段确认。
### 设计思路与决策依据
- 检测任务作为 LAMP/qPCR/SERS/高光谱共用的主链,推荐方式与实际执行方式分开;自动建单只进入 `pending`,不直接视为已检测;
- 样本按任务一对一建模,先满足“人员/时间/状态可追踪”,后续如需多份样本可扩展为样本集合;
- DiseaseEvent 独立成实体,TraceRecord 改为关联 DiseaseEvent,让确诊、处置、会诊和溯源形成稳定主线;
- Outbox 和 `source_key` 幂等保证重复巡检/重复推送不会产生多个待确认任务。
### 验证结果
- `scripts/verify.ps1` exit 0Go test/vet/build、Web test/lint/build、小程序 typecheck/build、APP typecheck/lint、AI pytest 15/15 均通过;
- 新增测试覆盖检测任务/样本/发病事件状态机、确诊必须有证据、Outbox 检测建单幂等;
- 未部署开发服务器,未执行 `000005` 迁移;未做真实巡检→任务→样本→LAMP→发病事件端到端联调。
### 回滚点
- 本任务前分支提交为 `a25bc7a`;回滚可还原 Task 9 提交;
- 数据库回滚执行 `000005_detection_disease_events.down.sql`,可删除新表和关联列;已建立 `DiseaseEvent -> TraceRecord` 关联的数据会随回滚断开,回滚前需先备份;
- Web 新页面回滚只需还原路由/菜单/页面文件,旧 LAMP 页面不受影响。
## 2026-08-14 整改 Task 10:补齐消毒、种源与二维码身份链
### 做了什么
- 新增 `seed_sources``disinfection_records``identity_links` 表及 `000006_biosecurity` 迁移;`batches` 增加 `seed_source_id`
- 新增 `biosecurity:read/write` 权限并接入 admin/operator/viewer/farmer 角色;
- 种源链支持供应商、蚕种批号、检疫证号、入场时间、凭证 URL 和上链来源,创建/更新时检测循环引用;
- 消毒记录支持计划/执行两类,必填药剂和浓度,记录计划时间、执行时间、执行人、复核人和照片 URL;
- 二维码载荷只包含 `silk:v1:entityType:publicId:version`,通过 `identity_links` 映射到批次/蚕匾/样本;解析时校验实体存在、版本和权限;
- 溯源初报新增生物安全证据汇总,种源或消毒缺失时返回 `missing``evidenceSufficient=false`
- Web 新增「生物安全」页面;小程序新增扫码与现场消毒执行页。
### 设计思路与决策依据
- 二维码不包含内部 ID、密码或个人信息,使用随机 `publicId` 和数据库映射,避免可猜测身份;
- 种源链采用 `parent_id` 表达跨批次关系,并用循环检测阻止错误引用;
- 消毒记录使用同一表承载计划和执行,执行记录可关联计划,便于现场录入和复核;
- 当前项目还没有组织级 ACL,二维码解析先按实体存在性和 `biosecurity:read` RBAC 控制,组织/房间级对象授权仍待后续任务。
### 验证结果
- `scripts/verify.ps1` exit 0Go test/vet/build、Web test/lint/build、小程序 typecheck/build、APP typecheck/lint、AI pytest 15/15 均通过;
- 新增测试覆盖二维码篡改/版本解析、种源链循环/无环、消毒必填项;
- 未部署开发服务器,未执行 `000006` 迁移;未做真实二维码打印与小程序扫码联调。
### 回滚点
- 本任务前分支提交为 `cc93c9a`;回滚可还原 Task 10 提交;
- 数据库回滚执行 `000006_biosecurity.down.sql`,可删除种源、消毒、二维码映射表和 `batches.seed_source_id`
- 页面回滚需同时还原 Web 路由/菜单、小程序页面与设置入口,并移除 `biosecurity` 权限种子。
## 2026-08-14 整改 Task 11:实现小程序离线巡检与可靠同步
### 做了什么
- 新增小程序本地持久队列 `offlineQueue.ts`,队列状态为 `pending/uploading/synced/conflict/failed`
- 拍照巡检改为先保存图片到本地队列,网络恢复后串行上传;同一 `idempotencyKey` 创建后不再变化,重试复用;
- 上传 401 时先刷新 token 再重试一次;5xx/超时按指数退避重试,4xx 永久失败并展示错误,409 标记为冲突;
- 巡检页展示离线队列数量、剩余容量、失败/冲突和清理已同步入口;
- 登录恢复后会尝试同步离线队列;`scripts/verify.ps1` 新增 `miniapp test`,队列单测进入统一门禁;
- 服务端幂等键增加用户作用域:新增 `000007_inspection_idempotency` 迁移,唯一索引改为 `(user_id, idempotency_key)`,迁移先对既有同用户冲突键追加记录 ID,不删除任何记录。
### 设计思路与决策依据
- 离线上传不能依赖临时文件路径,页面入队前先用文件系统保存为本地持久路径;
- 幂等键必须客户端生成且固定,服务端按用户+键查询和唯一约束,避免不同用户撞键导致误返回;
- 4xx 通常是数据或权限问题,重试不会解决,所以进入人工处理;网络类错误才退避重试;
- 队列容量先按条目数量限制,页面显示剩余名额;后续需要更严格空间控制时可再引入文件大小统计。
### 验证结果
- `scripts/verify.ps1` exit 0Go test/vet/build、Web test/lint/build、小程序 test/typecheck/build、APP typecheck/lint、AI pytest 15/15 均通过;
- 队列单测 5/5:重启恢复、重复点击、4xx 永久失败、指数退避后最终失败、同步后清理引用;
- 未部署开发服务器,未执行 `000007` 迁移;未在微信开发者工具完成离线→重启→联网截图取证。
### 回滚点
- 本任务前分支提交为 `6b222ab`;回滚可还原 Task 11 提交;
- 数据库回滚执行 `000007_inspection_idempotency.down.sql` 可恢复全局唯一索引,但已被迁移追加后缀的历史键不会自动还原;
- 小程序回滚需还原队列服务、巡检页、请求刷新逻辑和 store,并移除 `scripts/verify.ps1` 中的 `miniapp test` 步骤。
## 2026-08-14 整改 Task 12:完善环境规则、会诊治理、知识审核与效果评估
### 做了什么
- 新增规则引擎 `EvaluateRules`:支持版本化规则、连续时窗、数据新鲜度、缺失项和输入快照,单个最新值不能冒充连续高湿;
- 会诊状态机改为 `unassigned/assigned/accepted/needs_info/resolved/archived`,分派时写入 SLA 截止时间,支持 `overdue/on_time/unscheduled` 判断;
- 新增 `consultation_opinion_versions` 表,专家每次出方案/修改保留作者、时间、版本和原因;
- 知识文章和病种新增 `status/source/sourceDate/expertConfirmedBy`,普通用户只读已发布内容,草稿/审核/撤回仅审核权限用户可见;
- 新增 `EvaluateControlEffect``/health-profiles/:roomId/effect` 效果报告 API,对比处置前后巡检风险、检测阳性率和复发,缺失维度不按 0 当改善;
- Web 会诊页适配新状态机和 SLA;知识页展示审核状态与来源;溯源页新增效果报告入口。
### 设计思路与决策依据
- 规则输出必须可复盘:版本、计算时间、输入快照、缺失项都保留;缺失输入降低结论可信度而不是填 0;
- SLA 超时只产生状态标记/升级事件,不自动伪造专家结论;
- 知识内容先默认草稿,经过审核后发布;撤回后不再进入普通知识列表,历史病例引用仍保留快照;
- 效果评估明确区分“改善/未改善/证据不足”,避免缺失数据被解释为防控有效。
### 验证结果
- `scripts/verify.ps1` exit 0Go test/vet/build、Web test/lint/build、小程序 test/typecheck/build、APP typecheck/lint、AI pytest 15/15 均通过;
- 新增测试覆盖连续 3 天高湿、过期遥测缺失、规则快照、会诊归档/意见版本/SLA、知识状态机、效果报告改善与缺失;
- 未部署开发服务器,未执行 `000008` 迁移;未接入真实领域专家审核和 SLA 升级通知。
### 回滚点
- 本任务前分支提交为 `69ef5a0`;回滚可还原 Task 12 提交;
- 数据库回滚执行 `000008_governance_effectiveness.down.sql` 可删除意见版本、规则结果、知识审核表和新增列;
- Web 页面回滚需还原会诊、知识、溯源页面及对应 DAL,不覆盖旧专家意见。
## 2026-08-14 整改 Task 13:建立可观测性、容量与恢复验证
### 做了什么
- 新增 `X-Request-ID` 中间件:请求 ID 生成或透传、响应头返回、日志记录 `requestId`query 中 token/password/secret/authorization 自动脱敏;
- 新增依赖指标注册表和 `GET /api/v1/ops/metrics`,AI 客户端记录请求数、失败数、最近延迟和 P50/P95;
- AI 服务 `/detect` 透传 `X-Request-ID`,并新增响应头测试;
- 新增 `docs/operations/slo-and-alerts.md``load-test-scenarios.md``backup-restore-drill.md`
- `部署指南(物理机).md` 增加可观测性与恢复验证要求。
### 设计思路与决策依据
- 全链路追踪从 HTTP 入口开始,先保证请求 ID 和日志脱敏,后续可替换为正式 tracing/APM
- 依赖指标采用内存快照,满足当前单实例观测;多实例或生产规模化后再接入 Prometheus/OTel
- SLO 和告警阈值先给出可执行基线,不把未运行的监控平台写入“已验证”状态;
- 备份恢复文档要求真实演练记录 RPO/RTO,避免只在文档里声明可恢复。
### 验证结果
- `scripts/verify.ps1` exit 0Go test/vet/build、Web test/lint/build、小程序 test/typecheck/build、APP typecheck/lint、AI pytest 15/15 均通过;
- 新增测试覆盖 requestId 透传/生成、敏感 query 脱敏、AI requestId 响应头;
- 未部署开发服务器,未执行 500/1000 用户负载、真实备份恢复演练或告警通道故障演练。
### 回滚点
- 本任务前分支提交为 `126c215`;回滚可还原 Task 13 提交;
- requestId/日志脱敏可安全保留;若指标采集开销过高,可降低采样频率;
- 运维文档和部署指南可直接保留,不删除已记录的恢复演练要求。
## 2026-08-14 整改 Task 14:建立规格追踪、端到端验收与发布门禁
### 做了什么
- 新增 `docs/acceptance/requirements-traceability.md`:Wave 1~3 需求 ID 到实现、测试、手工用例、环境、证据、状态、限制和负责人的追踪表;
- 新增 `docs/acceptance/core-e2e-cases.md`:覆盖 healthy 不触发、橙色仅一个任务、AI 失败重试、无效不确诊、阳性发病事件、越权 403、离线同步、通知重试、重启保持、备份恢复共 10 条核心用例;
- 新增 `docs/acceptance/release-checklist.md`:发布前、发布中、发布后和回滚门禁;
- `蚕病智能防控平台规格说明书_V2.2.md` 第 12 章增加验收文档入口和近期整改能力行;
- `scripts/verify.ps1` 已在 Task 11 起纳入小程序单测,作为当前可复现质量门禁。
### 设计思路与决策依据
- 追踪矩阵不允许只写模块名,每行必须能回溯到实现、测试、环境、证据、限制和负责人;
- E2E 用例先固定核心业务闭环,目标环境执行后再更新结果,不把“已编写”当“已验证”;
- 发布门禁要求先备份、再部署、后回滚验证,和 AGENTS.md 的服务器发布规则保持一致。
### 验证结果
- `scripts/verify.ps1` exit 0Go test/vet/build、Web test/lint/build、小程序 test/typecheck/build、APP typecheck/lint、AI pytest 15/15 均通过;
- `git diff --check` 通过;
- 未在目标环境执行 E2E-01~10,未完成真实发布和备份恢复演练。
### 回滚点
- 本任务前分支提交为 `1e6a5db`;回滚可还原 Task 14 提交;
- 本次仅新增/修改验收文档和规格书状态说明,无代码、数据库或生成产物变更;
- 如需回滚,删除 `docs/acceptance/` 并恢复规格书第 12 章及计划/交接文档即可。
## 2026-08-14 整改基线合并与部署前置
### 做了什么
- 将 Task 0~14 全部整改分支合并到 `dev_wjs`merge commit 为 `ef96a1a`
- 合并后再次执行 `scripts/verify.ps1`Go/Web/小程序/APP/AI 全部通过;
- 本机交叉编译生成 `server-go/server-go-linux``web/dist` 已由全量门禁构建。
### 设计思路与决策依据
- 整改分支本身是线性栈,直接合并 Task 14 到 `dev_wjs` 可得到完整统一基线;
- 部署前按 AGENTS.md 必须先确认服务器当前 commit、备份、端口和进程;本次因 `PAN_SSH_PASS` 未配置,不能伪造“已完成部署”。
### 验证结果
- `scripts/verify.ps1` exit 0
- Go Linux 二进制生成成功,大小约 26.4MB;
- 已从用户环境读取 `PAN_SSH_PASS`,但本机到 `100.83.103.1:22` 连接超时,Ping 100% 丢包;
- 未连接开发服务器,未执行 `pg_dump`、迁移、上传、重启或健康检查;部署阻断原因为网络不可达,不是凭据缺失。
### 回滚点
- 合并回滚:`dev_wjs` 可回到 `1b8cab1`(合并前基线);
- 后续部署需在服务器先打 `pre-<timestamp>` tag、备份数据库,再上传二进制和 `web/dist`
## 2026-08-14 下一步计划交接
### 做了什么
- 已将后续可执行事项按 P0/P1/P2 整理到 `后续工作计划.md`
- 交接项包含真实模型 E2E-02、对象级授权 IAM-003、离线取证、30 分钟 WebSocket、AI T4 峰值、Task 3/7、补充业务能力和工程化收尾。
### 设计思路与决策依据
- 当前 `dev_wjs` 是已部署基线,后续工作以验收证据、权限补齐和发布收尾为主;
- 每个交接项都写明负责人、阻塞和完成标准,避免只列模块名。
### 验证结果
- 本次仅更新计划文档,无代码、数据库或服务器变更。
### 回滚点
- 删除 `后续工作计划.md` 中“下一步工作计划”段落并恢复本文档即可。
## 2026-08-14 开发服务器部署(整改基线)
### 做了什么
- 完成 `dev_wjs` 整改基线首次开发服务器部署;
- 数据库已全量备份:`/home/pan/backups/silk-20260814-191754.dump`
- Go 后端已切换到修复后二进制,schema 迁移到 `schemaVersion=8`Web 和 AI 服务已同步更新;
- 部署中发现并修复 `outbox.Start` 阻塞主流程问题:改为后台 goroutine,提交 `3d49c03`
### 设计思路与决策依据
- 服务器应用目录无 git 仓库,采用二进制和 `web/dist` 制品部署,并在覆盖前保留旧制品;
- 数据库涉及多批 schema 变更,部署前先执行 `pg_dump`,满足回滚要求;
- AI 服务继续 mock 模式,部署前保留原 `app` 目录以便回滚。
### 验证结果
- Go `/api/v1/health` 200Web `:5174` 200AI `/health` 200
- 新路由未登录返回 401`/detection-tasks``/disease-events``/ops/metrics``/health-profiles/:id/effect``POST /biosecurity/qr/resolve`
- 使用 `admin/silk@123` 登录成功,登录态下 `/detection-tasks``/disease-events``/biosecurity/seed-sources``/biosecurity/disinfection-records``/consultations``/ops/metrics``/health-profiles/:id/effect` 均返回 200`POST /biosecurity/qr/resolve` 空载荷返回 400
- 后端日志显示 `schemaVersion=8` 和正常启动,无 panic
- IoTDB 仍不可用并降级 PostgreSQL,属部署前已知状态;
- 开发服务器 E2E-01/03/04/05/06/08/09/10 通过,E2E-02 因 mock 隔离按设计 blocked,E2E-07 队列单测通过但微信开发者工具重启取证未执行;
- 负载冒烟:500 HTTP 请求 0% 失败,p50 99.1ms/p95 182.3ms1000 WebSocket 连接 0% 失败,短时保持 p50 1506.5ms/p95 1854.9ms
- 当前 schema 全量备份:`/home/pan/backups/silk-20260814-194300.dump`,已恢复至隔离库核对表数量一致。
### 回滚点
- 数据库:`/home/pan/backups/silk-20260814-191754.dump`
- 当前 schema 数据库:`/home/pan/backups/silk-20260814-194300.dump`
- Go 旧二进制:`/home/pan/silk/server-go/server-go-linux.pre-20260814-191754`
- Go 修复前问题二进制:`/home/pan/silk/server-go/server-go-linux.broken-20260814-1921`
- Web 旧目录:`/home/pan/silk/web/dist.pre-20260814-191754`
- AI 旧目录:`/home/pan/ai-service/app.pre-20260814-191754``tests.pre-20260814-191754`