fix(report): stop listing reports via PostgREST JSON paths (BUG-574)

Staging PostgREST rejects the executiveSummary JSON-path alias, so GET /api/reports 500s. Persist a plain card_summary column from the Markdown excerpt instead.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jesse_Chen
2026-09-07 11:08:00 +08:00
parent ad9283d1bd
commit b466a6fc8c
15 changed files with 517 additions and 10 deletions
+16
View File
@@ -8838,4 +8838,20 @@
- 复发自:unknown-time `block_scan``814c924e`)按时段长度偏置
- 修复版本:`517df002`
## BUG-574 | 报告列表 JSON 路径 select 在 staging PostgREST 上 500
- 状态:resolved
- 首次发现:2026-09-07
- 最近更新:2026-09-07
- 影响面:`GET /api/reports``personal_reports` 列表查询、报告中心卡片
- 用户现象:登录后报告中心无法打开列表,接口稳定返回 500 `{"error":"报告列表暂时无法读取","code":"report_generation_failed"}`。同一会话读取已有报告详情 200。
- 触发条件:部署含 `cfcd369d` 的应用后打开报告中心。自托管 PostgREST 解析 `card_summary:report_document->executiveSummary->>summary` 失败。
- 根因:列表 `select` 增加了 PostgREST JSON 路径别名。该语法未被 `test:db` 或真实 PostgREST 覆盖;supabase-js 返回的 PostgrestError 不是 `Error` 实例,列表日志只记 `UnknownError`
- 修复:列表改为普通列 `card_summary`;迁移增加可空 `text` 列(≤500 字符);`complete_personal_report_job` 从封面文档 `executiveSummary.summary`(MD「摘要」截取)写入。旧行不回填。列表 catch 记录 `code`/`hint`,不记行数据。
- 验证:`frontend/tests/database-personal-report-card-summary.test.ts`(可空、authenticated 只读、service_role 可写、超长拒绝、complete RPC 写入);列表/观测单测;部署后需按 `docs/operations/personal-report-staging.md` 用真实会话跑列表 GET + 详情 GET + 创建 POST。
- 防复发:新增 PostgREST JSON 路径、嵌套 embed 或别名必须有 `test:db` 真查询或部署后 smoke;禁止再用未经验证的 JSON 路径变体赌列表查询。
- 相关记录:无
- 复发自:无
- 修复版本:待提交(`codex/report-list-500-20260907`
@@ -116,6 +116,20 @@ curl -sS -o /dev/null -w '%{http_code}\n' https://staging.jyotisha.chat/api/repo
Expected logged-out status is `401`. Authenticated owner/non-owner checks must be performed in the browser or with ephemeral local credentials that are never pasted into logs.
### Post-deploy report list / detail / create smoke (required)
Apply `20260907010000_personal_report_card_summary.sql` before deploying application code that selects `personal_reports.card_summary`. After `/api/health` shows the target SHA, use a real logged-in staging session (do not paste cookies, JWTs, or birth data):
1. `GET /api/reports`**200** with `{ reports: [...] }`. Missing `cardSummary` on old rows is success, not an error. Must not return `report_generation_failed`.
2. `GET /api/reports/<existing-id>`**200** for an owned report (regression: list 500 while detail 200 was the 2026-09-07 incident).
3. `POST /api/reports` create one new longform report, then poll until `status=ready` (about 1030s). Confirm:
- detail page TOC and wide tables render from Markdown
- export downloads `.md`
- billing settles `inputTokens=0 outputTokens=0` on the catalog model
- the new list card shows `cardSummary` from the Markdown 摘要 excerpt
Do not record report bodies, birth facts, user ids, or tokens in the smoke log. Record only HTTP status, `status=ready` latency band, and whether `cardSummary` was present.
On the host, confirm no product PDF browser runtime exists:
```bash
@@ -0,0 +1,43 @@
# PROGRESS · 报告列表 500PostgREST JSON 路径(2026-09-07
工作树:`.worktrees/report-list-500-20260907`
分支:`codex/report-list-500-20260907`
基线:`origin/staging` @ `ad9283d1`(任务书写 `5c644f92`,开工 fetch 后 HEAD 为准)
任务书:`TASK-report-list-500-20260907.md`
未改 `.gitea/workflows/**`,不提升 main。
## 开工回执
- 目标:`GET /api/reports` 恢复 200;卡片摘要改普通列;列表错误日志能看到 PostgREST `code`/`hint`
- 最大风险:应用若在迁移前部署,`select card_summary` 会再次 500。必须先 `Migrate Staging Database` 再部署 web。
## 任务状态
| 任务 | 状态 | 说明 |
| --- | --- | --- |
| 1 止血:去掉 JSON 路径 select | 完成 | `REPORT_LIST_COLUMNS` 只含普通列 `card_summary` |
| 2 `card_summary` 列 + worker 写入 | 完成 | 迁移 `20260907010000``complete_personal_report_job``executiveSummary.summary` 写入(与 MD「摘要」截取同源);旧行不回填 |
| 3 观测 | 完成 | `sanitizedErrorReason` 读取非 Error 的 `code`/`hint`,不记 message/details |
| 4 部署后 smoke | blocked | 清单已写入 `docs/operations/personal-report-staging.md`;需迁移+部署+真实登录会话。本环境无 staging 登录态 |
## 偏离
任务书写「由 worker 从 MD 摘要段写入」。实现上 worker 仍通过 `extractLongformSummary(..., 500)` 写入封面 `executiveSummary.summary`,完成 RPC 在同一事务拷到 `card_summary`。没有另开一次 PostgREST JSON 路径 select,也没有改 RPC 参数签名。
## 质量门(本机跑过)
```text
tsx --test tests/safe-error-reason.test.ts tests/personal-report-longform-md.test.ts \
tests/personal-report-migration.test.ts tests/personal-report-api.test.ts
# 77 passed
tsx --test --test-concurrency=1 tests/database-personal-report-card-summary.test.ts
# 1 passedDocker Postgres 真迁移:可空、authenticated 只读、service_role 可写、500 接受、501 拒绝、complete RPC 写入摘要)
./node_modules/.bin/tsc --noEmit
# pass
```
## 推送
未推。产品要求只快进 staging、不提升 main。
+1
View File
@@ -100,6 +100,7 @@
| `TASK-report-longform-parity-20260905.md`(仓库根) | `PROGRESS-report-longform-parity-20260905.md` | 长报告对齐全量版并挂入产品附录 | 待验收 | `codex/report-longform-parity-20260905`(任务 6 待部署后核对) |
| `TASK-report-longform-gaps2-20260906.md`(仓库根) | `PROGRESS-report-longform-gaps2-20260906.md` | 长报告真实参数组合下的装配缺口 | 待验收 | `codex/report-longform-gaps2-20260906`BUG-561/562 `cfcd369d`;补洞 BUG-564 `e4d16b75` |
| `TASK-report-md-page-20260906.md` | `PROGRESS-report-md-page-20260906.md` | 长报告 Markdown 直接作为报告页 | 已合入 | `cfcd369d` / `809bdf13`BUG-563 lint 随后修) |
| `TASK-report-list-500-20260907.md`(仓库根) | `PROGRESS-report-list-500-20260907.md` | 列表 PostgREST JSON 路径 500 | 执行中 | `codex/report-list-500-20260907`BUG-574 |
### 前端基础与工程