fix: preserve billing response shape

This commit is contained in:
brother7 committed 2026-08-17 11:28:08 +08:00
1 parent 600cba023c
commit 2ef3da7af5
7 files changed
+488 -6

No files matched your search

@@ -0,0 +1,87 @@
# Task: Fix billing empty collection contract
## Identity
- Task ID: 20260817-fix-billing-empty-arrays-4f9d2a7c
- Mode: Feature
- Branch: main
- Worktree: D:\Datas\OthersProjects\NianAIGC
- Base commit: 600cba023ca39d6dd81e526ba1e6014d4bfad65b
- Owner: codex
- Status: Ready for Integration
## Scope
- Make Go billing overview responses encode empty collections as JSON arrays,
never `null`.
- Add frontend response-shape validation so malformed billing payloads produce
an inline error instead of crashing the `/billing` route subtree.
- Replace the obsolete `npm run db:migrate` route-error guidance with wording
appropriate to the static Web + Go API architecture.
- Add regression coverage at both the Go HTTP contract seam and the pure
frontend payload parsing seam.
## Intent And Constraints
- Preserve the accepted static Web + Go-only API architecture and existing
authorization behavior.
- Do not change database schema, seed fake organizations, or require production
data to make empty-state rendering safe.
- Keep the fix surgical: Go owns valid JSON output; frontend validation is a
defense against incompatible or malformed deployments.
- Work test-first from the deterministic diagnosis recorded in
`20260817-diagnose-billing-page-7c3a91e2`.
## Outcome
- Go billing overview services now normalize every response collection used by
the member and super-administrator billing pages to a non-nil slice, so an
empty database result is encoded as `[]` rather than `null`.
- The browser validates every billing object, collection element, and nested
price dimension used by the renderer before committing API data to React
state. Incompatible successful responses now produce the existing inline
error state instead of throwing during render and activating the route error
boundary. Validation preserves Go `omitempty` behavior for optional fields,
including a fresh super-administrator without `organizationId`.
- The billing route error boundary and invalid-JSON fallback now direct
operators to the Go API status and server logs rather than the removed Node
migration workflow.
- Regression tests cover the real Go HTTP response contract with an empty store
and the frontend parser contract for empty, missing, null, and malformed
payloads.
## Verification
- RED: `go test ./internal/httpapi -run TestBillingOverviewResponsesEncodeEmptyCollectionsAsArrays -count=1`
failed because empty member/admin collections encoded as `null`.
- RED: `npx vitest run tests/billing-api-contract.test.ts` failed before the
frontend parser module existed.
- PASS: `go test ./...`.
- PASS: `go vet ./...`.
- Initial final review: FAIL because top-level array checks still allowed
malformed collection elements such as `priceRules: [null]` and a null member
`organization` to reach render-time property access.
- Remediation: added complete render-shape validation and regressions for admin
organizations/wallets, members, ledger entries, price rules/dimensions/tiers,
and member organization/wallet/summary/personal data.
- PASS after remediation: `npm test` (`54` files, `174` tests).
- PASS: `npx tsc --noEmit --incremental false`.
- PASS: `npm run deploy:check` (`7` ACK manifest files).
- PASS: `npm run build` (all routes statically exported, including `/billing`).
- PASS: `check_project_docs.py --target .`.
- PASS: task-aware `check_doc_drift.py` for this task ID.
- PASS: `git diff --check` (line-ending notices only).
- Final read-only review: PASS on both Standards and Spec after the malformed
nested-payload remediation; no blockers remain.
## Follow-ups
- After publishing new Web and Go images under a fresh immutable tag, verify an
authenticated super-administrator with zero organizations sees the billing
empty state in production. This requires deployment access and is not a code
acceptance blocker.
## Promotion Candidates
- None. This task applies the existing static Web + Go API architecture and does
not introduce a new architectural decision.