Files
silk/项目整改实施计划_V1.0.md
T
2026-08-13 23:54:04 +08:00

35 KiB
Raw Blame History

蚕病智能防控平台整改实施计划

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: 依据《蚕病智能防控平台规格说明书 V2.2》,先消除安全与业务正确性风险,再建立可迁移、可测试、可观测、可恢复的试点闭环。

Architecture: 保持现有 Go/Gin 主业务后端、Python/FastAPI AI 微服务、React Web、Taro 小程序、React Native APP 和 IoTDB/PostgreSQL/S3/WVP 基础。整改采用“小步迁移 + TDD + 功能开关 + 可回滚发布”,不在本计划中替换既有主技术栈。

Tech Stack: Go 1.23、Gin、GORM、PostgreSQL、IoTDB、Valkey/Redis、MQTT、FastAPI、ONNX Runtime、React、Taro 4、React Native 0.74、Vitest、pytest。

Global Constraints

  • 不得手改 miniapp/dist/web/dist/、APK、Linux 二进制等生成产物。
  • 不得覆盖无关的用户修改;每个任务只提交本任务文件。
  • 新功能先写失败测试,再做最小实现,再运行模块和全量检查。
  • 生产密钥只通过环境变量/密钥管理注入,不写入提交文件。
  • 所有 schema 修改先备份、再迁移;生产不允许 GORM AutoMigrate 自动改表。
  • 每项交付必须追加 开发交接记录.md,记录设计依据、验证证据和回滚点。
  • 涉及发布时严格执行 AGENTS.md 的开发服务器部署前置、备份和回滚要求。
  • 任务 0 的开放技术选型未确认前,不得擅自引入迁移工具、CI 平台或新外部服务。

1. 执行原则与分工

1.1 优先级

波次 目标 任务 预计串行工期
Wave 0 决策与基线 01 23 人日
Wave 1 P0 安全与正确性 27 1015 人日
Wave 2 工程可靠性 89 610 人日
Wave 3 业务闭环 1012 2033 人日
Wave 4 验收与发布 1314 711 人日

工期只用于排期,不是验收标准。多人并行时,任务 2 是涉及数据库实体任务的前置;任务 3~7 可在接口边界明确后分支并行,但合并前必须统一回归。

1.2 建议责任域

  • 后端负责人:任务 210、13。
  • AI 负责人:任务 6 中 AI 响应与模型元数据、任务 14 AI 验收。
  • Web/小程序负责人:任务 1、11、12 的端侧部分。
  • 运维负责人:任务 3、8、9、13 的配置、监控、备份和发布。
  • 测试负责人:维护需求 ID—用例—结果矩阵,不以开发自测替代验收。
  • 领域专家:确认 qPCR 规则、风险动作、病种清单和知识来源。

1.3 每个任务的完成定义

  1. 需求 ID 与验收用例明确。
  2. 失败测试已观察到预期失败原因。
  3. 实现和迁移完成,模块测试通过。
  4. 相关模块全量检查通过或准确记录环境阻断。
  5. 文档、配置示例和交接记录更新。
  6. 回滚步骤经过静态复核;涉及部署时完成实际冒烟。

Task 0: 固化开放决策与整改基线

Requirements: V2.2 第 13 章
Owner: 项目负责人 + 后端/运维/领域负责人
Estimated effort: 0.51 人日

Files:

  • Create: docs/decisions/2026-08-13-remediation-decisions.md
  • Modify: 后续工作计划.md
  • Modify: 开发交接记录.md

Interfaces:

  • Consumes: 蚕病智能防控平台规格说明书_V2.2.md 的开放决策。

  • Produces: 迁移工具、CI 平台、保留期限、qPCR 规则负责人、APP 范围和模型门槛的书面决定。

  • Step 1: 召开 60 分钟决策会并逐项记录负责人、选项、理由和生效日期

文档必须使用如下固定表头:

| Decision ID | 结论 | 备选方案 | 选择理由 | 影响 | 负责人 | 复审条件 |
|---|---|---|---|---|---|---|
  • Step 2: 明确七项决定

必须覆盖:数据库迁移工具、CI 承载平台、制品位置、数据保留期限、qPCR 方案确认流程、APP 产品范围、二分类转多病种指标门槛。不得写“以后再定”;暂不实施时写“保持现状 + 明确复审触发条件”。

  • Step 3: 将 Wave 14 写入 后续工作计划.md,使用七态能力状态而不是单一勾选

  • Step 4: 评审并提交

rg -n "Decision ID|迁移|CI|保留|qPCR|APP|二分类" docs/decisions/2026-08-13-remediation-decisions.md
git diff --check

Expected: 七项主题均可检索,git diff --check exit 0。

Rollback: 删除决策文档并恢复计划/交接记录;尚未执行的决定不产生运行时影响。


Task 1: 恢复可复现的多端质量基线

Requirements: V2.2 第 10 章
Owner: 各端负责人
Estimated effort: 12 人日

Files:

  • Modify: miniapp/src/pages/dashboard/index.tsx
  • Modify: miniapp/package.json
  • Modify: app/package.json
  • Modify: ai-service/README.md
  • Create: scripts/verify.ps1
  • Modify: CI 配置文件(路径由 Task 0 确认的平台决定)
  • Modify: 开发交接记录.md

Interfaces:

  • Produces: 单命令验证入口 powershell -ExecutionPolicy Bypass -File scripts/verify.ps1

  • Step 1: 修复小程序 JSX 类型错误

将裸文本箭头改为明确字符节点:

<Text className={styles.sectionAction}>详情 {'>'}</Text>
<Text className={styles.sectionAction} onClick={handleAlarmTap}>全部 {'>'}</Text>
  • Step 2: 为小程序增加只读类型检查脚本,为 APP 确认本地 devDependencies 安装可用
{
  "scripts": {
    "typecheck": "tsc --noEmit"
  }
}
  • Step 3: 创建验证脚本

scripts/verify.ps1 必须按模块执行并在任一失败时返回非 0:

$ErrorActionPreference = 'Stop'
Push-Location server-go; go test ./...; go vet ./...; go build ./...; Pop-Location
Push-Location web; npm test; npm run lint; npm run build; Pop-Location
Push-Location miniapp; npm run typecheck; npm run build:weapp; Pop-Location
Push-Location app; npm run tsc; npm run lint; Pop-Location
Push-Location ai-service; python -m pytest; Pop-Location
  • Step 4: 在干净依赖环境运行并保存结果

Expected: 五个模块全部 exit 0Web lint warning 单独建单,不允许隐藏 exit code。

  • Step 5: 接入 Task 0 确认的 CI,禁止失败检查合并

Rollback: 恢复两处 JSX 与脚本变更;CI 门禁可关闭但不得删除失败证据。


Task 2: 引入版本化数据库迁移与 Schema 启动门禁

Requirements: V2.2 5.5、阶段 B
Owner: 后端负责人 + DBA/运维
Estimated effort: 23 人日

Files:

  • Create: server-go/migrations/000001_baseline.up.sql
  • Create: server-go/migrations/000001_baseline.down.sql
  • Create: server-go/internal/database/migrate.go
  • Create: server-go/internal/database/migrate_test.go
  • Modify: server-go/internal/database/db.go
  • Modify: server-go/cmd/server/main.go
  • Modify: README.md
  • Modify: 部署指南(物理机).md

Interfaces:

  • Produces: database.CheckSchemaVersion(db *gorm.DB, expected string) error

  • Constraint: 迁移执行器使用 Task 0 批准的工具;SQL 迁移文件作为唯一 schema 事实来源。

  • Step 1: 写失败测试,证明 schema 版本缺失/落后时返回错误

func TestCheckSchemaVersionRejectsMismatch(t *testing.T) {
    err := CheckSchemaVersion(fakeDBWithVersion("1"), "2")
    if err == nil { t.Fatal("expected schema mismatch") }
}
  • Step 2: 生成当前 schema 基线 SQL,并人工核对所有表、索引和约束

不得使用 AutoMigrate 输出作为未经审核的生产脚本;基线需在空库执行后与当前模型对照。

  • Step 3: 实现启动检查并移除生产自动迁移
func CheckSchemaVersion(db *gorm.DB, expected string) error

开发环境自动迁移只能由显式 ALLOW_DEV_AUTOMIGRATE=true 开启;生产配置忽略该开关并拒绝 AutoMigrate。

  • Step 4: 验证空库建库、旧库升级和 down 回滚
go test ./internal/database -run TestCheckSchemaVersion -v
go test ./...
go vet ./...
go build ./...

Expected: 版本匹配通过,不匹配时服务启动失败且日志不包含 DSN 密码。

Rollback: 恢复旧二进制和迁移前数据库备份;不得只回滚代码而保留不兼容 schema。


Task 3: 移除默认密钥与默认管理员密码

2026-08-13 用户决策:Task 3 本轮跳过,留到最后处理。期间不删除默认密钥/默认管理员密码,不执行客户端密码预填清理。

Requirements: IAM-004、SEC-001、SEC-002
Owner: 后端 + 运维 + 各客户端负责人
Estimated effort: 12 人日

Files:

  • Modify: server-go/internal/config/config.go
  • Create: server-go/internal/config/config_test.go
  • Modify: server-go/internal/handler/auth.go
  • Modify: miniapp/src/pages/login/index.tsx
  • Modify: app/src/screens/LoginScreen.tsx
  • Create: server-go/.env.example
  • Modify: app/.env.example
  • Modify: README.md

Interfaces:

  • Produces: config.ValidateForEnvironment(cfg *Config, environment string) error

  • Step 1: 写表驱动测试,验证 production 缺 JWT/S3/ZLM/Internal API/管理员初始化配置时失败

func TestValidateForEnvironmentRejectsProductionDefaults(t *testing.T) {
    cfg := &Config{JWTSecret: "silk-secret-please-change-me"}
    if err := ValidateForEnvironment(cfg, "production"); err == nil {
        t.Fatal("expected insecure config rejection")
    }
}
  • Step 2: 删除敏感字段的可用默认值,保留非敏感本地地址默认值

生产环境必须显式设置 APP_ENV=production;关键字段为空、长度不足或等于历史默认值均拒绝启动。

  • Step 3: 删除小程序和 APP 密码预填
const [password, setPassword] = useState('');
  • Step 4: 生成轮换清单并由运维在目标环境执行

轮换范围至少包括 PostgreSQL、Redis、MQTT、JWT、S3、WVP、ZLM、Internal API 和默认管理员。

  • Step 5: 验证
go test ./internal/config ./internal/handler -v
rg -n "silk@123|Silk-App-Secret|silk-internal-2026|su6Tied" server-go miniapp/src app/src

Expected: 测试通过;源码搜索不再出现可用历史密钥。文档可提及已废弃值,但不得作为配置示例。

Rollback: 代码可恢复,但已轮换密钥不得回退为历史值;使用新生成密钥更新旧版本运行环境。


Task 4: 收口视频访问与摄像头密钥输出

Requirements: IAM-003、VIDEO-001、VIDEO-002、SEC-003、SEC-004
Owner: 视频后端负责人
Estimated effort: 23 人日

Files:

  • Modify: server-go/internal/model/models.go
  • Create: server-go/internal/handler/video_dto.go
  • Create: server-go/internal/handler/video_auth.go
  • Create: server-go/internal/handler/video_auth_test.go
  • Modify: server-go/internal/handler/video_camera.go
  • Modify: server-go/internal/handler/video_clip.go
  • Modify: server-go/internal/handler/video_stream.go
  • Modify: server-go/internal/middleware/auth.go
  • Modify: web/src/dal/video.ts

Interfaces:

  • Produces: IssueVideoToken(userID, resourceType, resourceID string, ttl time.Duration) (string, error)

  • Produces: ValidateVideoToken(token, resourceType, resourceID string) error

  • Token TTL: 5 分钟;绑定资源类型、ID、用户、用途和过期时间。

  • Step 1: 写安全回归测试

func TestCameraResponseNeverContainsSecrets(t *testing.T)
func TestVideoStreamRejectsMissingOrWrongResourceToken(t *testing.T)
func TestVideoTokenExpires(t *testing.T)
  • Step 2: 将模型密钥字段标记为不序列化,并使用公开 DTO
PasswordEnc    *string `json:"-"`
GbAuthPassword *string `json:"-"`

CameraPublic 只包含播放和管理界面需要的非敏感字段;WVP 配置响应删除 sipPassword

  • Step 3: 播放地址改为短时令牌

/video/clips/:id/play/video/cameras/:id/play 先执行 JWT、权限和对象范围校验,再返回带短时 token 的 URL。stream/proxy 路由即使位于 auth 白名单,也必须验证该 token。

  • Step 4: 验证直接枚举 ID、跨用户 token、过期 token 和资源错配均为 401/403
go test ./internal/handler -run "Video|CameraResponse" -v
go test ./...

Rollback: 可临时回滚到“JWT header 直接保护 stream”模式;禁止回滚为公开流或返回密钥。


Task 5: 修复 WebSocket 越权与 AI 流 SSRF

Requirements: IAM-003、SEC-005、SEC-007、VIDEO-004
Owner: 后端 + AI 负责人
Estimated effort: 23 人日

Files:

  • Modify: server-go/internal/ws/gateway.go
  • Create: server-go/internal/ws/gateway_test.go
  • Modify: server-go/cmd/server/main.go
  • Modify: server-go/internal/config/config.go
  • Modify: ai-service/app/main.py
  • Create: ai-service/app/stream_tasks.py
  • Modify: ai-service/tests/test_api.py

Interfaces:

  • WebSocket: NewHub(jwtSecret string, authorizer DeviceAuthorizer, allowedOrigins []string)

  • AI 流接口:POST /internal/stream-tasks 接受 taskId 和已解析的内部流引用,不接受公网客户端任意 URL。

  • Step 1: 写失败测试,覆盖非法 Origin、refresh token、无权 deviceKey 和全局广播泄露

  • Step 2: 增加设备授权接口并在 subscribe 时校验

type DeviceAuthorizer interface {
    CanReadDevice(userID, deviceKey string) (bool, error)
}

删除普通连接的无范围 telemetry.all 广播;管理视图使用单独权限和组织范围订阅。

  • Step 3: 禁止长期 JWT 出现在 query,改用一次性 WebSocket ticket

ticket 有效期 60 秒、仅使用一次;日志中不记录 ticket 值。

  • Step 4: 将 AI 流读取移到受限 worker

只允许 Go 后端以内部认证创建任务;限制并发、帧数、分辨率、超时和允许的内部地址范围。FastAPI 路由不得在事件循环中直接执行长时间 VideoCapture.read()

  • Step 5: 验证
go test ./internal/ws -v
Push-Location ai-service; python -m pytest tests/test_api.py -v; Pop-Location

Rollback: 关闭流 AI 功能开关;WebSocket 保留来源和对象授权,不得回滚为 CheckOrigin=true


Task 6: 修复 AI 风险语义并隔离 Mock 数据

Requirements: AI-INS-002004、RISK-001003
Owner: AI + Go 后端负责人
Estimated effort: 23 人日

Files:

  • Modify: ai-service/app/main.py
  • Modify: ai-service/app/config.py
  • Modify: ai-service/tests/test_api.py
  • Modify: server-go/internal/service/ai_client.go
  • Modify: server-go/internal/service/risk.go
  • Modify: server-go/internal/service/risk_test.go
  • Modify: server-go/internal/handler/inspection.go
  • Modify: server-go/internal/handler/inspection_test.go
  • Create: server-go/migrations/000007_inspection_idempotency.up.sql
  • Create: server-go/migrations/000007_inspection_idempotency.down.sql
  • Modify: server-go/internal/model/inspection.go
  • Create: server-go/migrations/000002_risk_assessment.up.sql
  • Create: server-go/migrations/000002_risk_assessment.down.sql

Interfaces:

  • AI response adds modelVersion, isMock, abnormalProbability

  • Go produces RiskAssessment with score、level、confidence、components、missing、modelVersion、ruleVersion。

  • Step 1: 写关键失败测试

func TestHealthyHighConfidenceDoesNotIncreaseRisk(t *testing.T) {
    got := AbnormalProbability([]AIDetection{{ClassName: "healthy", Confidence: .95}})
    if got != 0 { t.Fatalf("got %v", got) }
}

func TestSickHighConfidenceIncreasesRisk(t *testing.T) {
    got := AbnormalProbability([]AIDetection{{ClassName: "sick", Confidence: .9}})
    if got != .9 { t.Fatalf("got %v", got) }
}
  • Step 2: 扩展 AI 响应并明确异常类别集合

二分类 sick 和多病种中除 healthy 外的已配置异常类别贡献风险;空检测返回 unknown,不自动当健康。

  • Step 3: 用可空组件计算风险
type RiskInput struct {
    AI, Env, Stage, Uniformity *float64
}
type RiskAssessment struct {
    Score float64; Level, Confidence, RuleVersion string
    Components map[string]*float64; Missing []string
}

缺失组件不填 0;V2 规则将可用权重归一化,并把 confidence 降为 low/medium。具体权重先沿用 0.5/0.2/0.15/0.15,标记为待试点校准规则而非科学事实。

  • Step 4: 持久化输入快照、模型/规则版本和 mock 标识

Mock 记录可保存供联调,但查询统计默认排除;生产环境收到 isMock=true 时记录失败并告警。

  • Step 5: 评估历史数据

生成只读 SQL 报告统计历史 healthy 高置信度记录及其风险等级;未经人工确认不得批量重算或覆盖。

  • Step 6: 验证
go test ./internal/service -run "Risk|Abnormal" -v
go test ./internal/handler -run Inspection -v
Push-Location ai-service; python -m pytest -v; Pop-Location

Rollback: 功能开关回退到只展示 AI 原始结果、不计算综合风险;不得恢复错误的最大置信度算法。


Task 7: 修订 qPCR 判读与检测质控

Requirements: DET-003005
Owner: 后端负责人 + 领域专家
Estimated effort: 12 人日

Files:

  • Modify: server-go/internal/model/molecular.go
  • Modify: server-go/internal/model/molecular_test.go
  • Modify: server-go/internal/model/lamp.go
  • Modify: server-go/internal/handler/lamp.go
  • Modify: web/src/dal/lamp.ts
  • Modify: web/src/pages/LampTests.tsx
  • Create: server-go/migrations/000003_detection_qc.up.sql
  • Create: server-go/migrations/000003_detection_qc.down.sql

Interfaces:

  • Produces: JudgeQPCR(input QPCRJudgeInput) QPCRJudgeResult
type QPCRJudgeInput struct {
    TargetCt *float64
    InternalControlCt *float64
    PositiveControlValid bool
    NegativeControlValid bool
    ProtocolVersion string
    Threshold float64
}
  • Step 1: 由领域专家签字确认首个 protocolVersion 与阈值适用范围

未确认前功能只能保存原始数据,不能自动输出阴性/阳性。

  • Step 2: 写表驱动测试

覆盖:阳性、阴性、缺 Ct、内参失败、阳性对照失败、阴性对照污染、临界值和未知 protocol。

  • Step 3: 实现四态结果
positive / negative / invalid / indeterminate

无 Ct 仅在对照和内参有效且方案明确允许时判 negative;其他情况为 invalid/indeterminate。

  • Step 4: UI 强制填写质控字段并展示判读依据,不允许把 invalid 显示为阴性

  • Step 5: 验证

go test ./internal/model -run QPCR -v
go test ./internal/handler -run QPCR -v
Push-Location web; npm test; npm run lint; npm run build; Pop-Location

Rollback: 回退为“只录入、不自动判读”,保留原始 Ct 和质控数据。


Task 8: 建立可靠通知、吊销与跨实例状态

Requirements: IAM-001、MSG-001、MSG-002
Owner: 后端 + 运维
Estimated effort: 35 人日

Files:

  • Create: server-go/internal/model/notification.go
  • Create: server-go/internal/service/outbox.go
  • Create: server-go/internal/service/outbox_test.go
  • Modify: server-go/internal/handler/notification.go
  • Modify: server-go/internal/middleware/token_blacklist.go
  • Modify: server-go/internal/middleware/ratelimit.go
  • Create: server-go/migrations/000004_notifications_outbox.up.sql
  • Create: server-go/migrations/000004_notifications_outbox.down.sql
  • Modify: server-go/cmd/server/main.go

Interfaces:

  • Produces: Outbox.PublishTx(tx *gorm.DB, event Event) error

  • Notification states: pending/sending/sent/retry/failed/cancelled

  • Step 1: 写测试证明服务重启后 pending 事件仍可处理,重复 eventId 不重复发送

  • Step 2: 业务事务内写 outbox,worker 领取、发送、退避重试并记录最终失败

  • Step 3: 将 token 吊销和登录限流迁移到 Redis

Redis 不可用时:生产登录/刷新采取保守失败;已认证的只读请求按安全评审决定降级,不得静默切回单机内存。

  • Step 4: 微信发送保存模板、用户授权、响应码和重试结果

  • Step 5: 验证并进行进程重启测试

go test ./internal/service ./internal/middleware ./internal/handler -run "Outbox|Notification|Revok|Rate" -v
go test ./...

Rollback: 暂停 worker 保留 outbox 数据;恢复旧读接口时不得删除未发送事件。


Task 9: 建立统一检测任务、样本链与发病事件

Requirements: DET-001/002/006、TRACE-001
Owner: 后端 + Web + 小程序负责人
Estimated effort: 58 人日

Files:

  • Create: server-go/internal/model/detection_task.go
  • Create: server-go/internal/model/sample.go
  • Create: server-go/internal/model/disease_event.go
  • Create: server-go/internal/handler/detection_task.go
  • Create: server-go/internal/handler/detection_task_test.go
  • Modify: server-go/internal/handler/inspection.go
  • Modify: server-go/internal/handler/trace.go
  • Create: server-go/migrations/000005_detection_disease_events.up.sql
  • Create: server-go/migrations/000005_detection_disease_events.down.sql
  • Create: web/src/dal/detectionTask.ts
  • Create: web/src/pages/DetectionTasks.tsx
  • Modify: web/src/router.tsx

Interfaces:

  • DetectionTask states: draft/pending/assigned/sampling/testing/review/completed/cancelled

  • Sample states: created/collected/handed_over/received/testing/consumed/disposed

  • DiseaseEvent states: suspected/confirmed/controlled/closed/reopened

  • Step 1: 写状态机和幂等失败测试

func TestDetectionTaskRejectsInvalidTransition(t *testing.T)
func TestOrangeInspectionCreatesOnlyOnePendingTask(t *testing.T)
func TestDiseaseEventRequiresEvidenceToConfirm(t *testing.T)
  • Step 2: 实现实体、外键、唯一业务键和状态转换服务

  • Step 3: 橙色巡检通过 outbox 创建“待确认”任务,不能直接指派或视为已检测

  • Step 4: 检测有效阳性或专家确认后创建 DiseaseEventTraceRecord 改为关联 DiseaseEvent

  • Step 5: Web 提供任务列表、分派、采样交接、检测和复核视图

  • Step 6: 验证完整 API 流程和重复请求

go test ./internal/model ./internal/service ./internal/handler -run "DetectionTask|Sample|DiseaseEvent" -v
Push-Location web; npm test; npm run lint; npm run build; Pop-Location

Rollback: 关闭自动建单开关,保留新表数据;旧 LAMP 记录继续只读,禁止删除已建立关联。


Task 10: 补齐消毒、种源与二维码身份链

Requirements: FARM-002、FARM-004、FARM-005、TRACE-007
Owner: 后端 + Web + 小程序负责人
Estimated effort: 46 人日

Files:

  • Create: server-go/internal/model/biosecurity.go
  • Create: server-go/internal/handler/biosecurity.go
  • Create: server-go/internal/handler/biosecurity_test.go
  • Create: server-go/migrations/000006_biosecurity.up.sql
  • Create: server-go/migrations/000006_biosecurity.down.sql
  • Create: web/src/dal/biosecurity.ts
  • Create: web/src/pages/Biosecurity.tsx
  • Create: miniapp/src/api/biosecurity.ts
  • Create: miniapp/src/pages/biosecurity/index.tsx
  • Modify: miniapp/src/app.config.ts

Interfaces:

  • QR payload only contains opaque entityTypepublicId、校验版本,不包含密码、内部自增 ID 或个人信息。

  • Step 1: 写测试覆盖二维码篡改、跨组织访问、种源链循环和消毒记录必填项

  • Step 2: 实现 SeedSource、DisinfectionRecord、二维码解析与对象授权

  • Step 3: Web 提供来源/凭证/消毒计划与执行;小程序提供扫码和现场执行

  • Step 4: 溯源初报消费种源和消毒数据,缺失时明确显示“证据不足”

  • Step 5: 验证

go test ./internal/handler ./internal/service -run "Biosecurity|SeedSource|Disinfection|QRCode" -v
Push-Location web; npm run build; Pop-Location
Push-Location miniapp; npm run typecheck; npm run build:weapp; Pop-Location

Rollback: 隐藏页面入口并停止新增写入,保留已产生的种源/消毒/二维码映射。


Task 11: 实现小程序离线巡检与可靠同步

Requirements: AI-INS-005、9.4 弱网要求
Owner: 小程序 + Go 后端负责人
Estimated effort: 46 人日

Files:

  • Create: miniapp/src/services/offlineQueue.ts
  • Create: miniapp/src/services/offlineQueue.test.ts
  • Modify: miniapp/src/pages/inspection/index.tsx
  • Modify: miniapp/src/api/inspections.ts
  • Modify: miniapp/src/store/useStore.ts
  • Modify: server-go/internal/handler/inspection.go
  • Modify: server-go/internal/handler/inspection_test.go

Interfaces:

  • Queue item states: pending/uploading/synced/conflict/failed

  • Idempotency key: 客户端生成 UUID,创建后永不变化,重试复用。

  • Step 1: 写队列单测

覆盖断网入队、重启恢复、重复点击、指数退避、成功删除本地图片引用、永久失败和冲突展示。

  • Step 2: 实现本地持久队列,限制容量并显示剩余空间

  • Step 3: 网络恢复后串行上传,401 先刷新令牌,5xx/超时重试,4xx 进入人工处理

  • Step 4: 服务端幂等键增加用户作用域,避免不同用户键碰撞

唯一约束改为 (user_id, idempotency_key),使用 000007_inspection_idempotency 迁移;先扫描并处理既有冲突,迁移不得静默删除记录。

  • Step 5: 在开发者工具模拟离线—重启—联网流程并保存截图/日志证据
Push-Location miniapp; npm run typecheck; npm run build:weapp; Pop-Location
go test ./internal/handler -run Inspection -v

Rollback: 关闭离线入口,只允许在线提交;服务端幂等改动保留,避免重复数据回归。


Task 12: 完善环境规则、会诊治理、知识审核与效果评估

Requirements: ENV-003005、EXP-002005、KB-001/002、ANA-001/002
Owner: 后端 + Web + 领域专家 + 测试负责人
Estimated effort: 58 人日

Files:

  • Create: server-go/internal/model/governance.go
  • Create: server-go/internal/service/rule_engine.go
  • Create: server-go/internal/service/rule_engine_test.go
  • Modify: server-go/internal/service/weather_risk.go
  • Modify: server-go/internal/model/consultation.go
  • Modify: server-go/internal/handler/consultation.go
  • Modify: server-go/internal/handler/consultation_test.go
  • Modify: server-go/internal/model/knowledge.go
  • Modify: server-go/internal/handler/knowledge.go
  • Modify: server-go/internal/service/health_profile.go
  • Modify: server-go/internal/service/health_profile_test.go
  • Create: server-go/migrations/000008_governance_effectiveness.up.sql
  • Create: server-go/migrations/000008_governance_effectiveness.down.sql
  • Modify: web/src/pages/Consultations.tsx
  • Modify: web/src/pages/Knowledge.tsx
  • Modify: web/src/pages/Traces.tsx

Interfaces:

  • Produces: EvaluateRules(ctx RuleContext, rules []RuleVersion) []RuleResult

  • Consultation states: unassigned/assigned/accepted/needs_info/resolved/archived

  • Knowledge states: draft/review/published/withdrawn

  • Produces: EvaluateControlEffect(eventID string, window EffectWindow) EffectReport

  • Step 1: 写规则时窗与缺失数据测试

func TestRuleRequiresThreeContinuousDaysOfHumidity(t *testing.T)
func TestStaleTelemetryIsReportedMissing(t *testing.T)
func TestRuleResultKeepsInputAndVersion(t *testing.T)

规则输出必须保存版本、输入时间窗、命中项、缺失项和计算时间;单个最新值不得冒充连续时窗。

  • Step 2: 实现规则版本和数据新鲜度

RuleContext 至少包含批次阶段、时间窗遥测、天气、密度、通风、种源和消毒证据。缺失输入降低结论可信度,不填 0。

  • Step 3: 写并实现会诊状态机、SLA 和意见版本测试
func TestConsultationRejectsArchiveBeforeResolution(t *testing.T)
func TestConsultationOpinionCreatesNewVersion(t *testing.T)
func TestConsultationSLAMarksOverdue(t *testing.T)

每次意见修改保留作者、时间、旧版本和原因;超时只产生升级事件,不自动伪造专家结论。

  • Step 4: 增加知识审核与来源字段

未发布内容只对有审核权限用户可见;撤回后不在农户端出现,但历史病例引用保留版本快照。

  • Step 5: 实现防控效果评估

EffectReport 对比处置前后指定窗口的有效巡检风险、有效检测阳性率、复发、死亡/损失和成本;所有缺失维度单独列出,不把缺失当改善。

  • Step 6: Web 完成会诊 SLA、知识审核和效果报告入口

  • Step 7: 验证

go test ./internal/model ./internal/service ./internal/handler -run "Rule|Consultation|Knowledge|Health|Effect" -v
Push-Location web; npm test; npm run lint; npm run build; Pop-Location

Rollback: 关闭新版规则、SLA 和效果报告入口,保留版本与审核数据;不得覆盖或删除旧专家意见。


Task 13: 建立可观测性、容量与恢复验证

Requirements: V2.2 9.19.3、10.2
Owner: 运维 + 后端 + 测试负责人
Estimated effort: 46 人日

Files:

  • Modify: server-go/internal/middleware/logger.go
  • Create: server-go/internal/middleware/request_id.go
  • Modify: server-go/internal/service/ai_client.go
  • Modify: ai-service/app/main.py
  • Create: docs/operations/slo-and-alerts.md
  • Create: docs/operations/load-test-scenarios.md
  • Create: docs/operations/backup-restore-drill.md
  • Modify: 部署指南(物理机).md

Interfaces:

  • 每个 HTTP 请求生成/透传 X-Request-ID;事件使用 eventId;日志字段命名统一。

  • Step 1: 写中间件测试,验证 requestId 响应头、透传和日志脱敏

  • Step 2: 增加依赖指标

至少覆盖 PostgreSQL、Redis、MQTT、IoTDB、S3、AI、WVP、微信、天气的请求数、失败数、p95 和积压/容量。

  • Step 3: 定义并执行三类负载场景
A. 500 在线用户:80% 查询、10% 遥测趋势、5% 上传、5% 管理操作
B. 1000 WebSocket 连接:按授权设备订阅,持续 30 分钟
C. AI 峰值:指定 T4、模型版本、输入尺寸和并发,记录 p50/p95/失败率
  • Step 4: 执行备份恢复演练

恢复到隔离数据库/对象存储命名空间;记录备份时间、恢复时间、数据点核对、RPO/RTO 和失败项。

  • Step 5: 建立告警阈值和负责人表,进行一次模拟故障验证通知链

Rollback: 指标与 requestId 可保持;高开销采样可降低频率,不得删除备份恢复记录。


Task 14: 建立规格追踪、端到端验收与发布门禁

Requirements: V2.2 第 1012 章
Owner: 测试负责人 + 项目负责人
Estimated effort: 35 人日

Files:

  • Create: docs/acceptance/requirements-traceability.md
  • Create: docs/acceptance/core-e2e-cases.md
  • Create: docs/acceptance/release-checklist.md
  • Modify: 蚕病智能防控平台规格说明书_V2.2.md
  • Modify: 后续工作计划.md
  • Modify: 开发交接记录.md

Interfaces:

  • Traceability columns: Requirement ID、实现、自动测试、手工用例、环境、证据、状态、限制、负责人。

  • Step 1: 为 Wave 1~3 的每个需求 ID 建立追踪行,不允许只写模块名

  • Step 2: 编写核心端到端用例

至少覆盖:

1. healthy 图片 → 低风险/不触发检测
2. sick 图片 → 橙色 → 仅一个待确认任务
3. AI 失败 → 可重试且无虚假风险
4. qPCR 对照失败 → invalid → 不确诊
5. 有效阳性 → DiseaseEvent → 自动溯源初报
6. 无权用户访问视频/设备/WebSocket → 403
7. 离线巡检 → 重启 → 联网 → 仅同步一次
8. 通知发送失败 → 重试 → 最终状态可查
9. 服务重启 → 任务/通知/吊销状态保持
10. 备份恢复 → 核心记录与对象引用核对通过
  • Step 3: 在目标环境执行全量质量门禁和端到端用例
powershell -ExecutionPolicy Bypass -File scripts/verify.ps1
git diff --check
  • Step 4: 按 AGENTS.md 完成开发服务器备份、部署、健康检查、冒烟和回滚点记录

  • Step 5: 更新能力状态

只有附有测试/环境/日期证据的功能才能从“部分可用”改为“可验收/已验证”。

Rollback: 使用发布前 tag/commit、数据库 dump、旧二进制和旧 dist;回滚后重新执行健康检查并记录原因。


2. 不纳入本轮整改的事项

以下能力保留在 V2.2 阶段 D/E,不得为了展示进度插入 Wave 1~3:

  • 7 类病种真实模型训练与发布。
  • 固定摄像头群体巡检和个体追踪。
  • LAMP 图像自动判读。
  • SERS/高光谱自动分析和方法学结论。
  • 区域传播预测模型和数字孪生自动控制。
  • 未经确认的 APP 全量蚕病功能同步。

3. 合并与发布顺序

Task 0 决策
  ↓
Task 1 质量基线 ── Task 2 迁移基线
  ↓                    ↓
Task 3 配置安全      Task 6/7 数据语义
Task 4 视频安全      Task 8 可靠事件
Task 5 WS/AI 安全        ↓
  └──────────────→ Task 9 检测/发病主链
                         ↓
                  Task 10 生物安全链
                  Task 11 离线同步
                         ↓
                  Task 12 规则/治理/效果
                         ↓
                  Task 13 运维验证
                         ↓
                  Task 14 总体验收

Task 3~5 可以分别评审,但必须在 Wave 1 集成分支统一执行安全回归。Task 6~12 每个 schema 变更必须基于 Task 2 的迁移机制顺序编号,禁止多人自行创建冲突编号。

4. 计划自检清单

  • V2.2 的 P0 问题均映射到 Task 2~7。
  • 业务可靠性和治理问题映射到 Task 8~13。
  • 每个任务有负责人、文件、接口、测试、验证和回滚。
  • 未擅自确定迁移工具、CI 平台、云服务和 qPCR 医学/检疫规则。
  • 不包含手改生成产物或在服务器直接修源码的步骤。
  • 每项部署均要求备份、健康检查、冒烟和回滚记录。
  • 研究能力与近期整改明确分离。

5. 交付节奏建议

  • 每个 Task 一个独立分支/PR;分支前缀使用 codex/ 或团队既有规范。
  • Task 3~7 每完成一项立即做针对性安全/业务回归,不等待大版本集中验证。
  • 每周更新追踪矩阵和风险清单;只汇报有证据的状态变化。
  • Wave 1 完成后再开始 Wave 3 业务扩展;P0 未关闭时不部署新增研究功能。
  • 每次评审先看测试失败/通过证据,再看代码;每次发布先看回滚点,再执行覆盖操作。