Enhance ledger operations and referral lifecycle
CI / verify (push) Has been cancelled
CI / publish (push) Has been cancelled

Add traceable ledger filtering and permanent referral codes so operators can investigate credit activity without weakening immutable accounting guarantees.
This commit is contained in:
Rocky
2026-08-20 22:14:22 +08:00
parent 74c3fcd45f
commit b5212dcdc2
38 changed files with 3080 additions and 620 deletions
+7 -2
View File
@@ -160,6 +160,11 @@ function cursorQuery<T extends CursorQuery>(value?: string | T): CursorQuery | T
type CursorQuery = { cursor?: string };
function ledgerQuery(value?: string | LedgerQuery): CursorQuery | LedgerQuery {
if (typeof value === "string") return { cursor: value };
return value ? { ...value, referenceId: value.referenceId?.trim() } : {};
}
export const adminApi = {
session: () => request<SessionResponse>("/auth/session"),
@@ -195,12 +200,12 @@ export const adminApi = {
latestLedger: (value?: string | LedgerQuery) =>
request<PageResult<LedgerEntry>>(
`/credits/ledger${encodeQuery(cursorQuery(value))}`,
`/credits/ledger${encodeQuery(ledgerQuery(value))}`,
),
ledger: (userId: string, value?: string | LedgerQuery) =>
request<PageResult<LedgerEntry>>(
`/users/${encodeURIComponent(userId)}/ledger${encodeQuery(cursorQuery(value))}`,
`/users/${encodeURIComponent(userId)}/ledger${encodeQuery(ledgerQuery(value))}`,
),
grantCredits: (payload: CreditGrantRequest) =>
+48 -6
View File
@@ -27,8 +27,12 @@ export interface UsersQuery extends CursorPageQuery {
status?: UserSummary["status"];
}
export interface LedgerQuery extends CursorPageQuery {
type?: LedgerEntryType;
export interface LedgerQuery extends Omit<CursorPageQuery, "sort"> {
type?: LedgerAction;
entryType?: LedgerEntryType;
usageType?: UsageType;
referenceId?: string;
sort?: "createdAt" | "amount";
}
export interface AuditQuery extends CursorPageQuery {
@@ -219,23 +223,61 @@ export interface PageResult<T> {
nextCursor?: string;
}
export type LedgerEntryType =
export type LedgerAction =
| "grant"
| "reserve"
| "settle"
| "refund"
| "adjustment";
| "refund";
export type LedgerEntryType =
| "SIGNUP_TRIAL"
| "MANUAL_GRANT"
| "USAGE_RESERVE"
| "USAGE_SETTLE"
| "USAGE_RELEASE"
| "USAGE_REFUND"
| "REFERRAL_INVITER"
| "REFERRAL_INVITEE"
| "STOREKIT_PURCHASE"
| "SUBSCRIPTION_GRANT";
export type UsageType = "polish" | "asr" | "ai" | "agent" | "hotword";
export type LedgerEntryDetails =
| {
kind: "manualGrant";
reason?: string;
operatorName?: string;
}
| {
kind: "storeKit";
productId?: string;
transactionId?: string;
originalTransactionId?: string;
environment?: string;
purchasedAt?: string;
}
| {
kind: "referral";
role?: string;
relatedUserId?: string;
}
| {
kind: "usage";
reservationId?: string;
};
export interface LedgerEntry {
entryId: string;
userId: string;
type: LedgerEntryType;
type: LedgerAction;
entryType: LedgerEntryType;
amount: number;
balanceAfter: number;
reasonCode: string;
usageType?: UsageType;
referenceId?: string;
details?: LedgerEntryDetails;
createdAt: string;
}