docs: record billing page diagnosis

This commit is contained in:
2026-08-17 10:42:31 +08:00
parent acd929c704
commit 600cba023c

View File

@@ -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.