rebuild(stage-15): complete governance and handoff
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
# NAS切换清单
|
||||
|
||||
此清单是最终人工确认前的准备资产,不授权当前任务停止或替换正式容器。
|
||||
|
||||
## 切换前阻断项
|
||||
|
||||
- [ ] NAS或预发布机实际执行`docker compose config`与`docker compose build`。
|
||||
- [ ] 验证容器以非root、只读根文件系统启动,`/app/data`可写,健康检查稳定。
|
||||
- [ ] 验证容器重启后账号、行情、自选、复盘、会员、模型、问天和选股记录不丢失。
|
||||
- [ ] 在NAS受控目录完成数据库、环境密钥和私有Skill整套备份,并做一次独立恢复。
|
||||
- [ ] 为新容器分配临时端口,完成真实数据的日间/夜间、1080P/4K/390px抽验。
|
||||
- [ ] 用户明确确认最终切换窗口。
|
||||
|
||||
## 切换步骤
|
||||
|
||||
1. 记录旧镜像、容器配置、端口和旧数据库校验和,创建最终一致性备份。
|
||||
2. 暂停旧系统写入,不删除旧容器和数据卷。
|
||||
3. 对最终只读旧库运行`tools.legacy_migration`到全新目标,核对报告和外键完整性。
|
||||
4. 用固定`APP_ENCRYPTION_KEY`和新数据卷启动新容器临时端口。
|
||||
5. 抽验真实账号登录、共享快照、私有记录、会员/模型、问天、选股和LLM一次成功调用。
|
||||
6. 切换反向代理或宿主端口;观察健康、5xx、数据库写入和后台任务至少一个完整刷新周期。
|
||||
7. 只有观察期通过后才归档旧容器;旧数据库和旧镜像按回退周期保留。
|
||||
|
||||
## 回退条件与动作
|
||||
|
||||
出现登录失败、私有数据错绑、数据库完整性失败、关键行情不可读、后台任务持续失败或无法恢复的5xx时立即回退。
|
||||
|
||||
1. 停止新容器写入并保存故障数据库副本和日志。
|
||||
2. 将流量切回旧容器;不要对新数据库自动执行migration降级。
|
||||
3. 若需用旧镜像读取新时期数据,只能恢复升级前与旧镜像匹配的整套备份。
|
||||
4. 修复后重新从最新只读旧库执行迁移,不在失败目标库上手工改表。
|
||||
|
||||
## 当前状态
|
||||
|
||||
代码、真实旧库副本迁移、备份恢复、SPA生产形态、性能、安全和全量浏览器回归均已完成。
|
||||
本机没有Docker,以上6个切换前阻断项仍需在NAS/预发布环境执行;正式容器保持不变。
|
||||
@@ -0,0 +1,69 @@
|
||||
# 人工维护手册
|
||||
|
||||
## 从哪里开始
|
||||
|
||||
产品行为先查`../../../docs/product/小白复盘-完整产品规格说明书.md`,迁移约束查
|
||||
`../../../docs/migration/重建迁移章程.md`。新代码根目录只有`next/`;旧根目录代码不得作为新运行时依赖。
|
||||
|
||||
请求主链为:页面 -> `shared/api` -> HTTP Route -> Service -> Repository/DataGateway/LLMGateway。
|
||||
`bootstrap/container.py`是唯一依赖组装点,页面注册在`workspaceRegistry.ts`,数据库版本在
|
||||
`database/migrations/registry.py`按连续编号登记。
|
||||
|
||||
## 常见改动
|
||||
|
||||
| 改动 | 修改入口 | 必须补的测试 |
|
||||
|---|---|---|
|
||||
| 页面字段/布局 | 对应`frontend/src/pages`与领域CSS | 日夜、1080P、4K、390px |
|
||||
| 新市场页面 | 页面+`workspaceRegistry.ts`+市场Route/Service | 空态、缺失、日期、移动入口 |
|
||||
| 数据源字段 | Provider契约+DataGateway策略 | 来源、单位、新鲜度、覆盖率、失败关闭 |
|
||||
| 情绪/竞价/选股公式 | 纯计算模块+版本字段 | 固定样本、边界、缺失与确定性 |
|
||||
| 新策略 | `config/screener-strategies.json` | 因子覆盖、无信号、数据不足、顺序稳定 |
|
||||
| 新思维模型 | 公开或私有Skill目录 | 目录发现、等级、私密性、上下文路由 |
|
||||
| LLM功能 | 业务Prompt+唯一`LLMGateway` | 会员、配额、回退、中断、去重 |
|
||||
| 私有记录 | 领域Repository每条SQL带`user_id` | 甲乙账号交叉读写删 |
|
||||
| 数据表变更 | 新增连续migration | 前进、失败原子性、回退、旧库升级 |
|
||||
|
||||
不要在页面直接`fetch`、在Feature直接访问外网、在Controller计算评分、为单页创建第二个弹窗或
|
||||
把颜色/间距写成新字面值。确需新共享抽象时,至少应有两个真实调用方或消除一个高风险全局出口。
|
||||
|
||||
## 数据源维护
|
||||
|
||||
- Tushare:交易日、目录、日线、正式盘后事件和财务基础。
|
||||
- iFinD:实时K线、分时、动态竞价和已授权补充字段。
|
||||
- 东方财富:仅展示分时兜底,不进入正式计算。
|
||||
- 腾讯:已登记但无正式消费者前不创建空Provider。
|
||||
- 每个保存结果都要带来源、实际日期、观察时间、用途、复权、单位、新鲜度和覆盖率。
|
||||
- 供应商失败不得返回模拟数据;跨源替代必须在DataSourcePolicy显式登记并向用户显示实际日期。
|
||||
|
||||
## 日常命令
|
||||
|
||||
```powershell
|
||||
cd next
|
||||
.\.venv\Scripts\python.exe -m tools.database status
|
||||
.\.venv\Scripts\python.exe -m ruff check backend tools tests
|
||||
.\.venv\Scripts\python.exe -m pytest
|
||||
cd frontend
|
||||
npm.cmd run check
|
||||
npm.cmd run test
|
||||
npm.cmd run build
|
||||
cd ..
|
||||
npx.cmd playwright test
|
||||
```
|
||||
|
||||
数据库`status`只读查询,不执行升级。应用启动时执行有序前进migration;显式回退只允许在副本演练。
|
||||
生产代码回退不自动降级数据,需恢复升级前整套备份。
|
||||
|
||||
## 故障定位
|
||||
|
||||
1. 先看`/api/health`和结构化日志的`request_id`,不要从前端提示猜供应商原因。
|
||||
2. 行情问题查快照的实际日期、来源、覆盖率和质量门,再查Provider;不要直接加兜底。
|
||||
3. LLM问题查`llm_requests`和`llm_attempts`,确认失败发生在首字前还是首字后。
|
||||
4. 私有数据问题用两个测试账号交叉验证SQL所有权,不只检查页面隐藏。
|
||||
5. 视觉问题先确认Shell、令牌和领域CSS归属,不追加`override/final-fix`覆盖层。
|
||||
6. migration失败先停写并恢复备份,不编辑已执行migration的签名或SQL。
|
||||
|
||||
## 复杂度红线
|
||||
|
||||
- 页面容器超过300行、业务Service超过400行、CSS超过400行时必须复核职责并记录原因。
|
||||
- 同一行为出现第二个算法、API客户端、外部数据出口、LLM入口或弹窗Host时必须停止合并。
|
||||
- 新功能先更新规格、数据边界和固定案例,再写代码;删除功能先确认历史数据、导出和回退。
|
||||
@@ -0,0 +1,136 @@
|
||||
# 产品规格覆盖矩阵
|
||||
|
||||
本矩阵以《小白复盘完整产品规格说明书》第25节的85个固定案例为唯一编号源。
|
||||
“自动”表示确定性单元/API测试;“浏览器”表示Playwright交互、响应式断言和阶段截图共同验收。
|
||||
两者都不是仅检查页面能否打开。
|
||||
|
||||
## 账户、权限与隔离
|
||||
|
||||
| 编号 | 证据 | 状态 |
|
||||
|---|---|---|
|
||||
| A01 | `test_first_account_is_admin_and_second_is_regular_user` | 自动通过 |
|
||||
| A02 | 同A01及`stage4.spec.js`普通账号流程 | 自动+浏览器通过 |
|
||||
| A03 | `test_membership_and_admin_are_independent_dimensions` | 自动通过 |
|
||||
| A04 | 同A03,管理员智能权限与会员标识分别断言 | 自动通过 |
|
||||
| A05 | `stage4.spec.js`非会员完整锁定结构 | 浏览器通过 |
|
||||
| A06 | `test_watchlist_repository_isolates_accounts` | 自动通过 |
|
||||
| A07 | `test_private_review_records_are_strictly_scoped_and_daily_notes_upsert` | 自动通过 |
|
||||
| A08 | `test_non_admin_cannot_read_or_write_system_credentials` | 自动通过 |
|
||||
| A09 | `test_csrf_password_change_and_other_session_revocation` | 自动通过 |
|
||||
| A10 | `stage4.spec.js`账户五项菜单与弹窗 | 浏览器通过 |
|
||||
|
||||
## 日期与数据真相
|
||||
|
||||
| 编号 | 证据 | 状态 |
|
||||
|---|---|---|
|
||||
| D01 | `test_latest_daily_chart_drops_empty_premarket_bar`及交易上下文样本 | 自动通过 |
|
||||
| D02 | `test_trade_context_keeps_real_snapshot_date` | 自动通过 |
|
||||
| D03 | iFinD时间戳规范化测试及`stage5.spec.js`摘要时间 | 自动+浏览器通过 |
|
||||
| D04 | 市场快照最终态测试及`stage5.spec.js` | 自动+浏览器通过 |
|
||||
| D05 | 请求日、实际日分离的市场上下文测试 | 自动通过 |
|
||||
| D06 | `test_trade_context_keeps_real_snapshot_date`的沿用快照断言 | 自动通过 |
|
||||
| D07 | `stage4.spec.js`首次无快照空态 | 浏览器通过 |
|
||||
| D08 | `stage4.spec.js`后台刷新保持当前工作区 | 浏览器通过 |
|
||||
| D09 | `stage6.spec.js`默认情绪周期与最新日期 | 浏览器通过 |
|
||||
|
||||
## 图表与详情
|
||||
|
||||
| 编号 | 证据 | 状态 |
|
||||
|---|---|---|
|
||||
| C01 | `test_latest_daily_chart_drops_empty_premarket_bar` | 自动通过 |
|
||||
| C02 | `stage5.spec.js`历史页面日期与最新悬浮行情分离 | 浏览器通过 |
|
||||
| C03 | `test_minute_chart_contract_has_real_session_bounds_and_hides_source` | 自动通过 |
|
||||
| C04 | `MarketChart.vue`实体/影线分段及阶段5截图 | 浏览器通过 |
|
||||
| C05 | 主题令牌加载态及阶段5夜间截图 | 浏览器通过 |
|
||||
| C06 | `stage5.spec.js`个股详情完整入口 | 浏览器通过 |
|
||||
| C07 | `stage5.spec.js`非个股详情边界 | 浏览器通过 |
|
||||
| C08 | 图表前收契约测试及详情摘要浏览器断言 | 自动+浏览器通过 |
|
||||
|
||||
## 情绪与市场页面
|
||||
|
||||
| 编号 | 证据 | 状态 |
|
||||
|---|---|---|
|
||||
| M01 | `test_sentiment_has_all_weighted_components_and_extreme_risk_cap` | 自动通过 |
|
||||
| M02 | `test_sentiment_phase_transitions_require_confirmed_recovery_and_fermentation` | 自动通过 |
|
||||
| M03 | 同M02的连续发酵确认断言 | 自动通过 |
|
||||
| M04 | `stage6.spec.js`当前阶段警示文本 | 浏览器通过 |
|
||||
| M05 | `stage6.spec.js`明细范围、整页滚动和末行可达 | 浏览器通过 |
|
||||
| M06 | `stage6.spec.js`低行数股池固定状态栏 | 浏览器通过 |
|
||||
| M07 | `stage7.spec.js`天梯展开、收起、滚动与等宽格 | 浏览器通过 |
|
||||
| M08 | `stage6.spec.js`动态板高与涨停表现布局 | 浏览器通过 |
|
||||
| M09 | `test_sector_members_are_normalized_and_persistently_cached`及`stage7.spec.js` | 自动+浏览器通过 |
|
||||
|
||||
## 竞价、题材、热榜与龙虎榜
|
||||
|
||||
| 编号 | 证据 | 状态 |
|
||||
|---|---|---|
|
||||
| X01 | `test_auction_lifecycle_uses_live_snapshot_then_archives_925_result` | 自动通过 |
|
||||
| X02 | `test_observing_without_dynamic_data_never_disguises_previous_archive` | 自动通过 |
|
||||
| X03 | X01的9:26选定态断言 | 自动通过 |
|
||||
| X04 | `test_auction_keeps_market_cores_and_isolates_real_limit_price` | 自动通过 |
|
||||
| X05 | 同X04的新规ST 10%涨跌幅样本 | 自动通过 |
|
||||
| X06 | 同X04的市场核心超限保留断言 | 自动通过 |
|
||||
| X07 | 竞价成交额单一聚合结果及`stage8.spec.js`摘要/柱图 | 自动+浏览器通过 |
|
||||
| X08 | `stage8.spec.js`题材悬浮统一预览与无固定K线模块 | 浏览器通过 |
|
||||
| X09 | `test_popularity_preserves_single_source_without_false_consensus`及阶段8空态 | 自动+浏览器通过 |
|
||||
| X10 | `test_dragon_list_distinguishes_missing_and_unclassified_seats` | 自动通过 |
|
||||
| X11 | `stage8.spec.js`左名录右详情、无弹窗 | 浏览器通过 |
|
||||
|
||||
## 智能选股
|
||||
|
||||
| 编号 | 证据 | 状态 |
|
||||
|---|---|---|
|
||||
| S01 | `test_curated_strategies_run_independently_of_emotion_phase` | 自动通过 |
|
||||
| S02 | `test_missing_required_factor_and_complete_no_match_are_distinct` | 自动通过 |
|
||||
| S03 | 同S02的数据不足分支 | 自动通过 |
|
||||
| S04 | `test_formula_is_deterministic_and_best_value_scores_first`及幂等运行测试 | 自动通过 |
|
||||
| S05 | 按策略标识持久化运行及`stage9.spec.js`模式切换 | 自动+浏览器通过 |
|
||||
| S06 | 多策略独立运行Repository测试及策略面板切换 | 自动+浏览器通过 |
|
||||
| S07 | `stage9.spec.js`三模式独立结果容器 | 浏览器通过 |
|
||||
| S08 | `stage9.spec.js`未执行/无信号状态 | 浏览器通过 |
|
||||
| S09 | 自定义公式确定性引擎测试;LLM仅编译受控公式 | 自动通过 |
|
||||
| S10 | `test_formula_weights_must_total_one_hundred_percent` | 自动通过 |
|
||||
| S11 | `test_running_a_strategy_never_creates_tracking_rows` | 自动通过 |
|
||||
| S12 | `stage9.spec.js`手动加入及入选价 | 自动+浏览器通过 |
|
||||
| S13 | `test_custom_strategies_and_tracks_are_account_isolated` | 自动通过 |
|
||||
| S14 | `test_tracking_statistics_and_milestone_events_are_persistent_and_idempotent` | 自动通过 |
|
||||
|
||||
## 问师、问天与LLM
|
||||
|
||||
| 编号 | 证据 | 状态 |
|
||||
|---|---|---|
|
||||
| L01 | `test_stream_accumulator_does_not_repeat_final_snapshot` | 自动通过 |
|
||||
| L02 | `test_main_failure_before_first_delta_falls_back_and_counts_once` | 自动通过 |
|
||||
| L03 | `test_failure_after_first_delta_keeps_partial_and_never_falls_back` | 自动通过 |
|
||||
| L04 | `test_context_profiles_are_distinct_and_dragon_data_is_question_driven` | 自动通过 |
|
||||
| L05 | 阶段10、11、12三个非会员同结构锁定E2E | 浏览器通过 |
|
||||
| W01 | `stage11.spec.js`观势初始空态 | 浏览器通过 |
|
||||
| W02 | `test_small_sector_with_five_of_five_quotes_passes_all_gates` | 自动通过 |
|
||||
| W03 | `test_manual_objective_sector_value_recomputes_without_overwriting_valid_data` | 自动通过 |
|
||||
| W04 | `test_missing_one_formal_index_fails_closed` | 自动通过 |
|
||||
| W05 | `test_daily_fortune_is_created_once_even_before_interpretation` | 自动通过 |
|
||||
| W06 | `heartTiming.test.ts`及`stage11.spec.js` | 自动+浏览器通过 |
|
||||
| W07 | `test_each_heart_cast_appends_exactly_one_line` | 自动通过 |
|
||||
| W08 | `test_hexagram_is_deterministic_and_contains_only_six_lines`及阶段11页面断言 | 自动+浏览器通过 |
|
||||
| W09 | 阶段11夜间观心截图和可读性断言 | 浏览器通过 |
|
||||
|
||||
## 复盘、主题与响应式
|
||||
|
||||
| 编号 | 证据 | 状态 |
|
||||
|---|---|---|
|
||||
| R01 | `stage12.spec.js`交易日志保存、Toast与无异常弹窗 | 浏览器通过 |
|
||||
| R02 | `test_trade_summary_uses_only_realized_fields_and_keeps_zero_in_denominator` | 自动通过 |
|
||||
| R03 | `test_private_review_records_are_strictly_scoped_and_daily_notes_upsert` | 自动通过 |
|
||||
| R04 | `stage12.spec.js`历史展开、收起与滚动 | 浏览器通过 |
|
||||
| U01 | 阶段4至13日夜切换E2E,无白闪/控制台错误 | 浏览器通过 |
|
||||
| U02 | 阶段6的1920×1080整页滚动与明细可达 | 浏览器通过 |
|
||||
| U03 | 阶段11观气/观心滚动与背景断言 | 浏览器通过 |
|
||||
| U04 | 阶段4至13的3840×2160截图及密度验收 | 浏览器通过 |
|
||||
| U05 | `stage13.spec.js`390×844、五入口与44px触控目标 | 浏览器通过 |
|
||||
| U06 | `stage13.spec.js`320px 16工作区、纵向记录/局部横滚 | 浏览器通过 |
|
||||
|
||||
## 汇总
|
||||
|
||||
- 固定案例:85/85已有可追踪证据。
|
||||
- 确定性、权限、隔离和失败语义均由自动测试覆盖;视觉案例同时保留真实浏览器截图。
|
||||
- Docker镜像构建、NAS容器重启与正式端口切换不属于85个页面案例,但仍是切换前阻断项,见`cutover-checklist.md`。
|
||||
@@ -0,0 +1,60 @@
|
||||
# 减法与结构审计
|
||||
|
||||
## 结论
|
||||
|
||||
重建版运行时代码共206个源码文件、25,151行;旧版运行时代码共55个文件、61,793行。
|
||||
在功能完整迁移并增加移动端后,新运行时代码减少36,642行,约59.3%。文件数量增加来自按职责拆分,
|
||||
不再由`server.py`、`app.js`、`styles.css`和覆盖样式承载整个系统。
|
||||
|
||||
一次性迁移、备份、测试与文档不计入运行时代码比较;旧系统仍保留作回退资产,但新系统没有运行时导入。
|
||||
|
||||
## 唯一出口
|
||||
|
||||
| 能力 | 权威入口 | 审计结果 |
|
||||
|---|---|---|
|
||||
| 浏览器请求 | `frontend/src/shared/api/client.ts` | 全站仅此文件直接调用`fetch` |
|
||||
| 外部行情 | `backend/data/gateway.py`+Provider | 业务Feature不直接访问外网 |
|
||||
| LLM | `backend/llm/gateway.py` | 问师、问天、复盘助手、自定义公式共用 |
|
||||
| 弹窗 | `DialogHost.vue`+UI Store | 无页面级第二套全局弹窗 |
|
||||
| 设计令牌 | `frontend/src/shared/styles/tokens.css` | 主题颜色、字号、间距集中 |
|
||||
| 移动规则 | `frontend/src/shared/styles/mobile.css` | 不复制移动页面或API |
|
||||
| 数据演进 | `backend/database/migrations/` | 10个有序、带签名migration |
|
||||
|
||||
阶段15发现并删除了LLM网关对账户领域具体类的3个反向导入,改为网关内部最小Protocol;
|
||||
组合根仍注入原服务,没有第二套权限或模型逻辑。基础数据层、数据库层没有反向依赖业务Feature。
|
||||
|
||||
## 大文件复核
|
||||
|
||||
章程的400行是维护预警线,不是机械拆分指标。以下超线文件均已逐项复核:
|
||||
|
||||
| 文件 | 行数 | 保留原因 | 必须拆分的触发条件 |
|
||||
|---|---:|---|---|
|
||||
| `data/providers/tushare.py` | 657 | 单一Provider的端点映射和统一传输 | 新增第二种协议或重复传输实现 |
|
||||
| `data/gateway.py` | 546 | 唯一数据策略、质量门和图表规范化 | 新增非行情领域或独立生命周期 |
|
||||
| `market/insights/auction.py` | 519 | 一个完整竞价确定性算法 | 新算法出现独立输入/版本/测试 |
|
||||
| `market/insights/service.py` | 490 | 四类洞察的薄编排,计算已在子模块 | 任一洞察编排可独立部署/调度 |
|
||||
| `data/repository.py` | 486 | 共享行情领域的版本化存取 | 出现第二数据库或跨域私有写入 |
|
||||
| `data/heaven.py` | 485 | 问势专用市场输入适配 | 观气/观心开始依赖行情时 |
|
||||
| `screener/repository.py` | 448 | 选股、运行和跟踪的同事务存取 | 跟踪获得独立生命周期/任务 |
|
||||
| `screener/technical.py` | 434 | 纯技术因子计算 | 新因子族能形成独立输入契约 |
|
||||
| `mobile.css` | 537 | 唯一跨页移动规则,按断点组织 | 出现页面冲突或超过650行 |
|
||||
| 4个领域CSS | 403-415 | 单一领域且仅略超阈值 | 新增覆盖层或跨领域选择器 |
|
||||
| `tools/legacy_migration.py` | 629 | 一次性离线适配,不进入运行时 | 新增第二旧版本或需要常驻运行 |
|
||||
|
||||
当前强拆这些文件只会增加接口、跳转和空抽象,不能减少业务复杂度,因此未为满足行数制造目录。
|
||||
|
||||
## 删除与未继承
|
||||
|
||||
- 未复制旧`server.py`、`database.py`、`app.js`、15,465行旧样式或8,570行覆盖样式。
|
||||
- 未保留用户自主LLM配置、模拟行情、公开网页参与正式计算、策略自动跟踪和手动执行盘后策略。
|
||||
- 未复制旧原始因子表到新运行时;正式因子由唯一数据网关和盘后任务重建。
|
||||
- 未引入ORM、通用CRUD、缓存框架、消息队列或第二套前端状态库。
|
||||
- iFinD、Tushare、东方财富与腾讯职责固定;未做无来源标识的静默多源兜底。
|
||||
|
||||
## 依赖与安全
|
||||
|
||||
- npm生产依赖审计:0个已知漏洞。
|
||||
- Python生产依赖审计:0个已知漏洞。
|
||||
- 已知令牌、密码片段、私有数据目录和备份归档未进入Git。
|
||||
- 生产响应增加CSP、`nosniff`、拒绝Frame、权限策略、Referrer策略和HTTPS HSTS。
|
||||
- 生产静态哈希资源长期缓存,SPA入口`no-cache`;API错误仍使用统一JSON契约。
|
||||
Reference in New Issue
Block a user