Files
NianAIGC/.project-docs/30-worklog/tasks/20260817-diagnose-billing-page-7c3a91e2.md
T

4.1 KiB

Task: Diagnose billing page unavailable

Identity

  • Task ID: 20260817-diagnose-billing-page-7c3a91e2
  • Mode: Feature
  • Branch: main
  • Worktree: D:\Datas\OthersProjects\NianAIGC
  • Base commit: acd929c704
  • 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.