Files
silk/开发交接记录.md
T
2026-08-14 00:45:22 +08:00

924 lines
56 KiB
Markdown
Raw 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「部署到开发服务器」章节。
---
## 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 连接方式。