From 600cba023ca39d6dd81e526ba1e6014d4bfad65b Mon Sep 17 00:00:00 2001 From: brother7 <7brother7@gmail.com> Date: Mon, 17 Aug 2026 10:42:31 +0800 Subject: [PATCH] docs: record billing page diagnosis --- ...20260817-diagnose-billing-page-7c3a91e2.md | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 .project-docs/30-worklog/tasks/20260817-diagnose-billing-page-7c3a91e2.md diff --git a/.project-docs/30-worklog/tasks/20260817-diagnose-billing-page-7c3a91e2.md b/.project-docs/30-worklog/tasks/20260817-diagnose-billing-page-7c3a91e2.md new file mode 100644 index 0000000..b295b9a --- /dev/null +++ b/.project-docs/30-worklog/tasks/20260817-diagnose-billing-page-7c3a91e2.md @@ -0,0 +1,90 @@ +# Task: Diagnose billing page unavailable + +## Identity + +- Task ID: 20260817-diagnose-billing-page-7c3a91e2 +- Mode: Feature +- Branch: main +- Worktree: D:\Datas\OthersProjects\NianAIGC +- Base commit: acd929c704ec22b3ac909ecc3cd609b826376f5a +- Owner: codex +- Status: Ready for Integration + +## Scope + +- Diagnose why the production `/billing` page for a signed-in super + administrator renders the route error boundary instead of billing content. +- Trace the static frontend request and render path through Go billing HTTP and + PostgreSQL collection results. +- Keep this task diagnostic-only; do not apply an application or deployment + fix without a separate user request. + +## Intent And Constraints + +- Treat the supplied screenshot as confirmed visual evidence, but do not infer + the underlying exception from its generic fallback copy. +- Preserve the accepted static Web + Go-only API boundary. +- Do not inspect or expose authentication cookies, credentials, or Secret + values. +- Separate confirmed source/test evidence from live-cluster assumptions. + +## Outcome + +- Confirmed the screenshot is the `/billing` route error boundary, which means + an uncaught client render exception occurred; it is not evidence that + `npm run db:migrate` is the cause. +- Traced the super-admin path from `GET /api/auth/me` to + `GET /api/admin/billing`. Normal HTTP/fetch failures are caught inside + `BillingManager` and render an inline alert, so they do not match the + screenshot. +- Reproduced the browser contract failure at the Go HTTP seam: a zero-value + admin overview serializes `organizations`, `members`, `ledger`, and + `priceRules` as JSON `null`, while the frontend unconditionally calls array + methods including `.find`, `.reduce`, `.filter`, `.slice`, and `.map`. +- Confirmed the PostgreSQL adapter returns nil slices for empty result sets. + This is expected on a fresh database because bootstrap creates only the + super administrator; it does not create an organization, ledger entries, or + price rules, and the default price catalog is seeded only from quote flow. +- Confirmed the live public readiness route returns HTTP 200 with PostgreSQL + configured, `/billing` returns the static HTML, and unauthenticated + `/api/admin/billing` reaches Go and returns JSON HTTP 401. The authenticated + live billing response body was not captured, so the exact production + exception remains an evidence-backed inference rather than a directly read + container/browser trace. +- Removed the temporary diagnostic regression file after reproducing the + failure; no application or deployment code was changed. + +## Verification + +- Temporary red-capable harness: + `go test ./internal/httpapi -run + TestDiagnosisBillingAdminOverviewUsesJSONArraysForEmptyCollections -count=1 + -v` — FAIL as expected; all four collection fields were `null` instead of + `[]`. +- Repeated the same harness with `-count=3`; the same four failures reproduced + on all three runs in under one second. +- `curl.exe -sS -i --max-time 15 + https://nianxxaigc.nianxx.cn/api/ready` — HTTP 200, + PostgreSQL configured. +- Unauthenticated `GET /api/admin/billing` — HTTP 401 JSON `请先登录。`, + confirming the route reaches Go rather than Nginx static fallback. +- `HEAD /billing` — HTTP 200 static HTML. +- Independent frontend and Go read-only traces agreed on the nil-slice/null + contract violation and on the route-error-versus-inline-error distinction. +- Final read-only `sol_reviewer`: PASS for Standards and Spec; no blocker. + +## Follow-ups + +- In a separate authorized fix task, normalize all Go billing response + collections to non-nil empty slices and keep a permanent HTTP regression test + asserting JSON arrays for fresh/empty state. +- Add frontend response-shape validation/defaulting so malformed backend data + becomes an inline actionable error instead of crashing the route subtree. +- Replace the stale `npm run db:migrate` route-error copy; the current + production architecture uses manual SQL plus Go APIs and the message obscures + client contract failures. + +## Promotion Candidates + +- None. This is an implementation defect within the already accepted static + Web + Go API contract, not a new architecture or product decision.