feat(chart): add a read-only natal chart page
Independent Staging Quality Gate / validate (push) Canceled after 5m23s
Independent Staging Quality Gate / publish (push) Canceled after 0s

Open /chart from the sidebar without billing or a model. Five tabs; Western and Qizheng stay unavailable until those endpoints land. Ephemeris nav points at /ephemeris (404 until that page ships).
This commit is contained in:
jesse-ux
2026-09-15 16:27:50 +08:00
parent a3dbbde4a3
commit 830799fafb
30 changed files with 6438 additions and 1 deletions
@@ -0,0 +1,76 @@
# PROGRESS · 只读星盘页(2026-09-15
工作树:`.worktrees/chart-page-20260915`
分支:`codex/chart-page-20260915`
任务书基线:`2d7698ea`;开工时 `origin/staging` = **`4cacea8e`**(其后纯文档提交若干,代码基线以当时 HEAD 为准)。
本机 Windows。未新建 worktree。
Skill **未 bump**。未开 BUG 号(704–706 预留未用)。未改 `scripts/**``deploy/**``vendor/**``frontend/src/app/page.tsx``vedic-chart-svg.tsx``frontend/src/app/ephemeris/**`。未做 `TASK-api-server-decomposition-20260916`
## 开工基线
| 项 | 数字 |
| --- | --- |
| `frontend/src/app/page.tsx` | **1951** 行(PowerShell `(Get-Content).Count` |
| `tsc --noEmit` | 0 错 |
| 本单新增测试 | 见下;全量 `npm test` 收尾时再记 |
`frontend/node_modules` 用 junction 指向主仓 `G:\Ferti\Jyotisha\frontend\node_modules`(本 worktree 无独立安装)。
## 任务状态
| 任务 | 状态 | 说明 |
| --- | --- | --- |
| 1 BFF `/api/chart-view` | 完成 | GET;出生资料只读服务端;不 import billing / mastra |
| 2 五个 Tab | 完成 | 前三个印度 Tab 用现有 `/api/chart` + `/api/varga_full` + `/api/dasha/chara`;西洋 / 七政未上线时 `unavailable` |
| 3 侧栏两个入口 | 完成 | 星盘 `/chart`、星历 `/ephemeris`(对方未合入前 404 是预期) |
## 实现要点
- 独立 route `frontend/src/app/chart/page.tsx``force-dynamic`)。服务端 `loadChartView()` 算完再揭幕,页面组件里没有 spinner / 骨架 / 「正在加载」。
- 盘面从 `@/components/personal-report/vedic-chart-svg` 引入,导出签名零改动。
- 上游:先 `/api/chart`,再并行 chara / varga_full / western / qizheng。chara 与 varga 带上 `planets``ascendant``houses`。Vimshottari 大运取 `/api/chart``dasha.periods`,不单独打 `/api/dasha`
- 西洋 / 七政失败或 404 → 该字段 `unavailable`,其余 Tab 照常。
- 分运:Vimshottari 按标准年限比例从大运边界推,界面注明「不是引擎单独返回的字段」。Chara 名称写 **Chara Dashakn_rao 变体)**
- 中宫参数卡:≥768 六行;≤767 中宫两行(岁差、交点),完整卡在盘下。切点跟壳层。
- 侧栏新入口复用 `.report-nav-button`,当前项白玻璃 + 2px 深棕标记。
## 既有断言改动
| 文件 | 原值 | 新值 | 原因 |
| --- | --- | --- | --- |
| `tests/test_api_server_security.py` `app_routes` | 不含 `chart` | 加入 `'chart'`(排序在 `home` 前) | `_scan_app_routes` 会扫到新的 `frontend/src/app/chart/page.tsx` |
未改其他既有断言。
## Golden
`frontend/tests/fixtures/chart-view-golden.json` 来自本机 Anaconda `swisseph 2.10.03` 实跑:`domain_calculation_service.compute_chart` + `compute_vimshottari_timeline``DivisionalChartsCalculator``jaimini.calc_chara_dasha_with_antardasha`(去掉未使用的 `pratyantar_dashas`)、`western_chart_engine.build_tropical_natal_chart`。虚构出生 `1990-06-15 12:00` 北京 39.9042N 116.4074E tz+8 Raman mean node(与既有 `report-chart-blocks-golden` 同一例)。
## 测试
| 命令 | 结果 |
| --- | --- |
| `npx tsx --test tests/chart-view-route.test.ts tests/chart-page-view.test.tsx` | **14 pass / 0 fail**(本单新增) |
| 上列 + `class-name-definition` / `sidebar-contract` / `dark-theme-contract` / `personal-report-theme-contract` | **69 pass / 0 fail** |
| `./node_modules/.bin/tsc --noEmit` | **0 错** |
| `npm run lint` | **0 error**(全仓既有 warning;本单新文件 0 warning |
| `page.tsx` | 仍 1951 行,未改 |
| `npx next build --webpack` | compile + TypeScript 过;Collecting page data 死在既有 `SkillPackageRegistryError``jyotish-birth-time-rectification@10.0.26` SHA 对不上),与本单无关。未能从本机构建表确认 `/``○ Static`。 |
| `npm test` 全量 | `# tests 3067 / # pass 2909 / # fail 144 / # skipped 14`。失败集中在无 Docker 的 database-*、部署/Caddy 的 CRLF 正则、Skill SHA、Windows 下 `G:\\G:\\` 双前缀读文件。本机不是 BLOCKED 里那台 Linux 验收机(那边记 3214 / 27 fail)。本单新增 14 条,未弱化既有断言。 |
Windows 上改 `globals.css` 时曾被写成 CRLF,暗色主题合同会整文件红;已把本单改过的文件转回 LF。不要再让 CSS 带 CR。
## 合入顺序
规定:**qizheng → 本单 → ephemeris**。
2026-09-15 收尾时 `git fetch``origin/staging` = `3e58e85f`(比开工 `4cacea8e` 多 1 个纯文档提交)。**qizheng 尚未合入**staging 上没有 `/api/qizheng` / `/api/western` 端点提交)。按任务书**停在待推**,不抢推 staging。
星历入口现在指向尚未存在的 `/ephemeris`,对方合入前 404 是预期。
## 环境缺口
- 无登录态、无 Chrome:浏览器走查见 `docs/testing/chart-page-20260915.md`,不得写成通过。
- 无 Docker:未跑 `npm run test:db`(本单未动表)。
- worktree `node_modules` 是指向主仓的 junctionTurbopack `next build` 可能报 symlink 出文件系统。`/` Static 用 webpack 构建核。
+1 -1
View File
@@ -223,7 +223,7 @@
| `TASK-rectification-house-lord-gochara-research-20260913.md` | `PROGRESS-rectification-house-lord-gochara-research-20260913.md` | 研究单:宫主触发与木星/土星过运(合冲本命宫主、罗睺紧密合、年精度、用于 block 选上升)四种放宽,20 例公开 AA 离线量 block 层与 minute 层两组指标;引擎里已有宫主/功能吉凶/受控过运,只量缺的四条 | 待验收(无收益,关闭;不立实现单) | `codex/rectification-house-lord-gochara-research-20260913` |
| `TASK-qizheng-native-chart-20260915.md` | `PROGRESS-qizheng-native-chart-20260915.md` | **后端单(独占 `scripts/jyotish_api_server.py`**vendored `stem-branch` 0.8.0Apache-2.0)归档 + API 镜像 Node runtime + 七政适配器(计都派别与宿度坐标系参数化、boundary 按实测重写)+ 三个只读端点 `/api/qizheng`、`/api/western`、`/api/ephemeris_events`。实证三条:四柱时柱按 UTC 算(BUG-700,本轮不修不调用)、`ketuMode` 写死未暴露(BUG-701)、boundary 把空神煞与未闭合庙旺说成已生成(BUG-702)。BUG 段 700703 | 已推 `origin/staging` `e776cf9d` | `codex/qizheng-native-chart-20260915` |
| `TASK-chart-page-20260915.md` | `PROGRESS-chart-page-20260915.md` | **前端单(独占 `app-sidebar.tsx`,同时加星盘与星历两个入口)**:P0 只读星盘页,五个 Tab(星盘 / 基础信息 / 大运 / 西洋盘 / 七政四余),中宫排盘参数卡,三套坐标系各自标注且禁止互相换算。不扣点不调模型不出 spinner;不碰 `page.tsx`1951/2000);**不搬 `vedic-chart-svg.tsx`**rectification-board 也在用)。BUG 段 704706 | 待领取 | |
| `TASK-chart-page-20260915.md` | `PROGRESS-chart-page-20260915.md` | **前端单(独占 `app-sidebar.tsx`,同时加星盘与星历两个入口)**:P0 只读星盘页,五个 Tab(星盘 / 基础信息 / 大运 / 西洋盘 / 七政四余),中宫排盘参数卡,三套坐标系各自标注且禁止互相换算。不扣点不调模型不出 spinner;不碰 `page.tsx`1951/2000);**不搬 `vedic-chart-svg.tsx`**rectification-board 也在用)。BUG 段 704706 | 待验收 | `codex/chart-page-20260915` |
| `TASK-ephemeris-page-20260915.md` | `PROGRESS-ephemeris-page-20260915.md` | **前端单**:P1 星历页,今日五要素 + 当日行运(相对本命宫位)+ 未来九十天换座与停滞,底部「带这天去提问」出口。页面不得出现任何运势判断。含实证缺陷:panchanga 写死 Lahiri 与账户 Raman 分裂(BUG-707,只标注不修)。侧边栏入口由 chart-page 单交付。BUG 段 707709 | 待领取 | — |
| `TASK-api-server-decomposition-20260916.md` | `PROGRESS-api-server-decomposition-20260916.md` | **重构单(串行在 qizheng 单之后)**:把业务逻辑搬出 `JyotishAPIHandler`。核心不是行数,是全仓 3 处靠 `JyotishAPIHandler.__new__` 伪造空壳 handler 借方法(`consultation_workflow_service` ×2、`capture_report_blocked_repairs_golden`、`local_accuracy_report`,MCP 也走这条),依赖方向反了、handler 没有 `headers`/`wfile` 随时可炸。四阶段:拆 `__new__` 后门 → 抽 ≥150 行业务方法 → `do_POST`/`do_GET` 改路由表 → 重新冻结行数 baseline(余量 300→50)。纯搬运不改行为,`test_api_server_security.py` 3841 行断言一条不许改。预计 11,314 → 约 9,230 行。BUG 段 710+ | 待领取 | — |