rebuild(stage-14): deliver migration and recovery tooling

This commit is contained in:
leefer
2026-07-30 08:29:37 +08:00
parent 9eb7b548f3
commit fa7a8dde06
17 changed files with 1397 additions and 3 deletions
+51
View File
@@ -0,0 +1,51 @@
# 阶段 14 验收
## 交付边界
- 旧系统只作为只读来源;真实演练源为 `data/review.db`,目标为新建的 `next/data/stage14-migrated.db`
- 迁移逻辑仅存在于一次性工具 `tools/legacy_migration.py`,正常应用不导入旧系统代码或旧数据库。
- 新 Docker、备份和恢复资产仅位于 `next/`,没有停止、修改或替换 NAS 正式容器。
## 真实迁移结果
- 源库 SHA-256`b7c444359c3b9b201a47ce6b23e55ad7ca4eba3d9dd67dfc8544b575d43f4924`
- SQLite `integrity_check=ok`,外键违规 0。
- 3 个账号与会员状态、1 份出生资料、2 项系统数据凭据、3 个模型配置均已转换。
- 6 条自选、3 条复盘、2 条提醒、28 条问师消息、45 条问师偏好、31 条问天历史均已迁移并保留账号归属。
- 196 次历史选股与 16 条手动策略跟踪已迁移;每个历史交易日使用明确标注的归档因子快照,不伪造旧因子覆盖率。
- 5,534 个股票目录、261 个交易日、24 份市场摘要、5,567 份最近 90 根日 K 展示归档和 24 份兼容市场洞察已迁移。
- 真实账号密码验证、管理员与永久会员状态、模型选择、问天历史和选股历史抽验通过。
- 逐项机器报告见 `real-migration-report.json`,报告不含明文令牌或模型密钥。
## 主动删除或重建
- 会话不迁移,切换后所有账号重新登录。
- 已取消的用户自主 LLM 配置不迁移。
- 旧原始因子表不复制成兼容表;由新系统受治理的数据同步和因子任务重建。
- 旧指数行仅有收盘价,缺少新图表契约要求的 OHLC,未伪造成指数 K 线。
- 日 K 展示归档每个标的保留最近 90 根;旧全量数据库和一致性备份继续作为审计资产保留。
## 备份恢复演练
- 使用 SQLite 在线备份 API 创建一致快照,归档同时包含环境密钥材料与 9 个私有 Skill 文件,共 11 个文件。
- 恢复前验证安全路径、逐文件 SHA-256 和 SQLite 完整性;默认拒绝覆盖已有数据库、环境、密钥和私有 Skill 目录。
- 恢复副本 `integrity_check=ok`,账号数 3、历史选股数 196,与迁移目标一致。
- 单元测试确认篡改数据库内容会因校验和不一致被拒绝。
## 生产与安全抽验
- Vite 生产资源由 FastAPI 同端口提供;SPA 深链接可返回入口文件,未知 `/api/*` 保持统一 JSON 404。
- 生产登录 Cookie 含 `HttpOnly``Secure``SameSite=Lax`;生产环境缺少加密密钥会拒绝启动。
- 真实迁移库副本的行情摘要读取 20 次:中位数 20.90msP95 23.55ms;日 K 返回 90 个点。
- 容器使用多阶段构建、非 root 用户、只读根文件系统、持久化数据卷、健康检查、移除 Linux capabilities 和 `no-new-privileges`
- 本机未安装 Docker,因此未声称镜像已实构建;NAS 切换前必须在有 Docker 的预发布环境补做构建、健康检查、只读根文件系统和重启恢复验证。
## 质量门
- Ruff:通过。
- pytest96 项通过。
- Vue 类型检查:通过。
- Vitest:3 个文件、7 项通过。
- Vite 生产构建:通过,CSS 89.25KBJS 279.23KB,均为构建前原始体积。
- Playwright17 项通过,单 worker,耗时 53.6 秒。
- `git diff --check` 与已知令牌/密码扫描:通过。
@@ -0,0 +1,51 @@
{
"source": "C:\\Users\\MoBai\\Documents\\gupiaofupan\\webapp\\data\\review.db",
"target": "C:\\Users\\MoBai\\Documents\\gupiaofupan\\webapp\\next\\data\\stage14-migrated.db",
"source_sha256": "b7c444359c3b9b201a47ce6b23e55ad7ca4eba3d9dd67dfc8544b575d43f4924",
"target_sha256": "9b0ca7faed7a15b4099bd09ae7a0c94b52a0c8a7dbfedb9d2b26bdf47e34d5d2",
"integrity": "ok",
"foreign_key_violations": 0,
"migrated": {
"alerts": 2,
"birth_profiles": 1,
"chart_series": 5567,
"heaven_readings": 31,
"llm_models": 3,
"llm_usage_daily": 9,
"market_entities": 5534,
"market_insight_snapshots": 24,
"market_summaries": 24,
"memberships": 3,
"mentor_messages": 28,
"mentor_preferences": 45,
"review_notes": 3,
"screener_runs": 196,
"strategy_tracks": 16,
"system_credentials": 2,
"trading_days": 261,
"users": 3,
"watchlist_entries": 6
},
"target_counts": {
"users": 3,
"memberships": 3,
"market_entities": 5537,
"market_summaries": 24,
"chart_series": 5567,
"watchlist_entries": 6,
"review_notes": 3,
"trade_entries": 0,
"alerts": 2,
"mentor_messages": 28,
"heaven_readings": 31,
"screener_runs": 196,
"custom_screener_strategies": 0,
"strategy_tracks": 16
},
"intentionally_skipped": {
"sessions": "sessions are intentionally invalidated during cutover",
"user_credentials": "per-user LLM configuration was removed from the product",
"raw_factor_tables": "reproducible provider inputs are rebuilt by governed sync jobs",
"benchmark_bars": "legacy rows lack OHLC values required by the chart contract"
}
}