feat(admin): per-user finance panel — balances, benefits, risk, ledger
CI / changes (pull_request) Successful in 4s
CI / unit (pull_request) Successful in 11s
CI / integration (pull_request) Successful in 28s
CI / ui (pull_request) Has been skipped
CI / conformance (pull_request) Successful in 10s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m46s

The /_gm user card gains a Finance panel: an account's chip balances per
funding segment, benefits per origin (hints, no-ads until/forever), the
recorded refund risk (abuse flag + floor-0 loss), and the append-only ledger
history newest-first. Backed by a new payments.AccountStatement read straight
from the materialized tables + the ledger (uncached — an admin, rare view).

Folds the agreed admin / reports / catalog plan into PLAN.md (the PR stack:
this panel, then the catalog editor, admin grant, refund + ledger export) and
moves the tournament-entry storage design to the tournament stage.
This commit is contained in:
Ilia Denisov
2026-07-10 04:55:55 +02:00
parent 00d1bd33e3
commit e089a0a997
8 changed files with 460 additions and 28 deletions
+63
View File
@@ -0,0 +1,63 @@
package payments
import (
"context"
"time"
"github.com/google/uuid"
)
// Statement is an account's full financial picture for the admin console: chip balances per funding
// segment, benefits per origin, the recorded refund risk, and the append-only ledger history
// (newest first). Read straight from the materialized tables + the ledger, uncached — an admin-only,
// rare view, not a hot path.
type Statement struct {
Segments []SegmentChips
Benefits []OriginBenefit
Risk RiskInfo
Ledger []LedgerEntry
}
// SegmentChips is one funding segment's chip balance.
type SegmentChips struct {
Source Source
Chips int
}
// OriginBenefit is one origin's benefit state: the hint wallet, the ad-free term (zero AdsPaidUntil
// when none) and the lifetime ad-free flag.
type OriginBenefit struct {
Origin Source
Hints int
AdsPaidUntil time.Time
AdsForever bool
}
// RiskInfo is the account's recorded refund risk: whether it is abuse-flagged and the unrecoverable
// chip loss accumulated by floor-0 refunds. Present is false when the account has no risk row.
type RiskInfo struct {
Present bool
Abuse bool
LossChips int
}
// LedgerEntry is one append-only ledger row projected for the report. The string ids are empty when
// the column is NULL; Snapshot is the raw purchase/refund JSON (empty when none).
type LedgerEntry struct {
Kind string
Source string
Origin string
ChipsDelta int
ProductID string
OrderID string
Provider string
ProviderPaymentID string
Snapshot string
CreatedAt time.Time
}
// AccountStatement assembles the account's financial picture (segments, benefits, risk, full ledger
// history) for the admin console, straight from the materialized tables and the ledger (uncached).
func (s *Service) AccountStatement(ctx context.Context, accountID uuid.UUID) (Statement, error) {
return s.store.accountStatement(ctx, accountID)
}