model

package
v0.2.0-beta.9 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 9, 2026 License: AGPL-3.0 Imports: 70 Imported by: 0

Documentation

Index

Constants

View Source
const (
	AccountQuotaMutationReceiptVersion = 1
	AccountQuotaFingerprintVersion     = 2
)
View Source
const (
	AccountQuotaPhaseReserve = "reserve"
	AccountQuotaPhaseAdjust  = "reserve_adjust"
	AccountQuotaPhaseSettle  = "settle"
	AccountQuotaPhaseRefund  = "refund"
)
View Source
const (
	AccountQuotaTerminalRecoveryOpen          = "open"
	AccountQuotaTerminalRecoveryUsageUnknown  = "usage_unknown"
	AccountQuotaTerminalRecoveryRefundPending = "refund_pending"
	AccountQuotaTerminalRecoveryPending       = AccountQuotaTerminalRecoveryRefundPending
	AccountQuotaTerminalRecoveryClaimed       = "claimed"
	AccountQuotaTerminalRecoveryRetryable     = "retryable"
	AccountQuotaTerminalRecoveryApplied       = "applied"
	AccountQuotaTerminalRecoveryManual        = "manual"
)
View Source
const (
	AccountQuotaRefundFactKindAuthoritative      = "authoritative"
	AccountQuotaRefundFactKindLegacyWallet       = "legacy_wallet"
	AccountQuotaRefundFactKindLegacySelfUse      = "legacy_self_use"
	AccountQuotaRefundFactKindLegacySubscription = "legacy_subscription"

	AccountQuotaRefundFactPending   = "pending"
	AccountQuotaRefundFactClaimed   = "claimed"
	AccountQuotaRefundFactRetryable = "retryable"
	AccountQuotaRefundFactApplied   = "applied"
	AccountQuotaRefundFactManual    = "manual"
)
View Source
const (
	AccountQuotaSettlementKindAuthoritative      = "authoritative"
	AccountQuotaSettlementKindLegacyWallet       = "legacy_wallet"
	AccountQuotaSettlementKindLegacySelfUse      = "legacy_self_use"
	AccountQuotaSettlementKindLegacySubscription = "legacy_subscription"

	AccountQuotaSettlementPending      = "pending"
	AccountQuotaSettlementMaterialized = "materialized"
	AccountQuotaSettlementClaimed      = "claimed"
	AccountQuotaSettlementRetryable    = "retryable"
	AccountQuotaSettlementApplied      = "applied"
	AccountQuotaSettlementManual       = "manual"
)
View Source
const (
	// AdminQuotaAdjustment 操作枚举:加/减/覆盖目标用户钱包额度。
	AdminQuotaAdjustmentOperationAdd      = "add"
	AdminQuotaAdjustmentOperationSubtract = "subtract"
	AdminQuotaAdjustmentOperationOverride = "override"

	// AdminQuotaAdjustmentStatusPending 是事务内的瞬时状态;已提交的记录始终为 succeeded。
	AdminQuotaAdjustmentStatusPending   = "pending"
	AdminQuotaAdjustmentStatusSucceeded = "succeeded"
)
View Source
const (
	AuthFlowPurposeOAuth             = "oauth"
	AuthFlowPurposeTwoFALogin        = "2fa_login"
	AuthFlowPurposePasskeyLogin      = "passkey_login"
	AuthFlowPurposePasskeyRegister   = "passkey_register"
	AuthFlowPurposePasskeyStepUp     = "passkey_step_up"
	AuthFlowPurposeCodexOAuth        = "codex_oauth"
	AuthFlowPurposeTelegramBind      = "telegram_bind"
	AuthFlowPurposeTelegramAssertion = "telegram_assertion"
	AuthFlowIntentLogin              = "login"
	AuthFlowIntentBind               = "bind"
	AuthFlowTokenBytes               = 32
	AuthFlowDefaultCleanupRetention  = 24 * time.Hour
)
View Source
const (
	ChannelRoutingSourceCache    = "cache"
	ChannelRoutingSourceDatabase = "database"
)
View Source
const (
	ChannelQuotaIdentityQualityProviderConfirmed = "provider_confirmed"
	ChannelQuotaIdentityQualityCredentialScoped  = "credential_scoped"
)
View Source
const (
	CodexQuotaRouteLimitSource = "codex_relay_usage_limit"
	CodexQuotaRouteLimitCode   = "usage_limit_reached"
)
View Source
const (
	ChannelOperationCreate = "channel.create"
	ChannelOperationCopy   = "channel.copy"
)
View Source
const (
	// AffQuotaTransferStatusPending is the transient state of a transfer record
	// inside its transaction; a committed record is always succeeded.
	AffQuotaTransferStatusPending   = "pending"
	AffQuotaTransferStatusSucceeded = "succeeded"
)
View Source
const (
	LegacyUsagePreparing       = "preparing"
	LegacyUsageAdmissionFailed = "admission_failed"
	LegacyUsagePrepared        = "prepared"
	LegacyUsageUnknown         = "usage_unknown"
	LegacyUsageSettled         = "settled"
	LegacyUsageRefunded        = "refunded"
	LegacyUsageReviewPending   = "review_pending"
)
View Source
const (
	LogTypeUnknown = 0
	LogTypeTopup   = 1
	LogTypeConsume = 2
	LogTypeManage  = 3
	LogTypeSystem  = 4
	LogTypeError   = 5
	LogTypeRefund  = 6
	LogTypeLogin   = 7
)

don't use iota, avoid change log type value

View Source
const (
	LogProjectionBackfillTaskKey       = "log_projection_backfill"
	LogProjectionBackfillSchemaVersion = 1

	LogProjectionBackfillPhaseRelationalIdentity = "relational_identity"
	LogProjectionBackfillPhaseRelationalIndexes  = "relational_indexes"
	LogProjectionBackfillPhaseClickHouseIdentity = "clickhouse_identity"
	LogProjectionBackfillPhaseClickHouseMaterial = "clickhouse_materialize"
	LogProjectionBackfillPhaseCompleted          = "completed"

	LogProjectionBackfillStatusPending             = "pending"
	LogProjectionBackfillStatusRunning             = "running"
	LogProjectionBackfillStatusFailed              = "failed"
	LogProjectionBackfillStatusManualReview        = "manual_review"
	LogProjectionBackfillStatusMaintenanceRequired = "maintenance_required"
	LogProjectionBackfillStatusCompleted           = "completed"

	LogProjectionMaterializeStatusPending   = "pending"
	LogProjectionMaterializeStatusStarting  = "starting"
	LogProjectionMaterializeStatusRunning   = "running"
	LogProjectionMaterializeStatusCompleted = "completed"
	LogProjectionMaterializeStatusFailed    = "failed"
)
View Source
const (
	BillingLogProjectionIdentityStatusCanonical   = "canonical"
	BillingLogProjectionIdentityStatusQuarantined = "quarantined"
)
View Source
const (
	NameRuleExact = iota
	NameRulePrefix
	NameRuleContains
	NameRuleSuffix
)
View Source
const (
	OptionRemediationActionGroupRatioSync = "group_ratio.canonical_sync"
	OptionRemediationActionTrimSpace      = "value.trim_space"
	OptionRemediationActionJSONBOMTrim    = "json.bom_trim_repair"

	OptionRemediationDecisionKeep     = "keep"
	OptionRemediationDecisionRepair   = "repair"
	OptionRemediationDecisionReject   = "reject"
	OptionRemediationDecisionFallback = "fallback"

	OptionRemediationRiskLow    = "low"
	OptionRemediationRiskMedium = "medium"

	// OptionRemediationStatusPreviewed is reserved for future persisted
	// previews: the N5b dry-run is strictly zero-write and never stores rows.
	OptionRemediationStatusPreviewed = "previewed"
	OptionRemediationStatusApplied   = "applied"
	OptionRemediationStatusSkipped   = "skipped"
	OptionRemediationStatusFailed    = "failed"

	OptionRemediationApplyApplied        = "applied"
	OptionRemediationApplySkipped        = "skipped"
	OptionRemediationApplyFailed         = "failed"
	OptionRemediationApplyAlreadyApplied = "already_applied"
)
View Source
const (
	// TypedBulkValueTypeString is a raw string value (including JSON text for
	// map/object-typed family fields).
	TypedBulkValueTypeString = "string"
	// TypedBulkValueTypeNumber is a finite JSON number, bounded in magnitude.
	TypedBulkValueTypeNumber = "number"
	// TypedBulkValueTypeBoolean is a JSON true/false.
	TypedBulkValueTypeBoolean = "boolean"
	// TypedBulkValueTypeStringList is a JSON array of strings, persisted in
	// canonical JSON array form.
	TypedBulkValueTypeStringList = "string_list"
)
View Source
const (
	// MaxTypedBulkItems bounds the key set of one typed bulk request.
	MaxTypedBulkItems = 64
	// MaxTypedBulkKeyLength bounds the option key length (matches the 256
	// character key bound used by the option diagnostics reader).
	MaxTypedBulkKeyLength = 256
	// MaxTypedBulkValueLength bounds the canonical string form of one value
	// (matches the 65536 character option value bound).
	MaxTypedBulkValueLength = 65536
	// MaxTypedBulkStringListItems bounds the element count of one string_list.
	MaxTypedBulkStringListItems = 256
	// MaxTypedBulkStringListItemLength bounds one string_list element.
	MaxTypedBulkStringListItemLength = 1024
)
View Source
const (
	QuotaWriterTransitionStatusApplying  = "applying"
	QuotaWriterTransitionStatusSucceeded = "succeeded"
	QuotaWriterTransitionStatusFailed    = "failed"
)
View Source
const (
	SubscriptionDurationYear   = "year"
	SubscriptionDurationMonth  = "month"
	SubscriptionDurationDay    = "day"
	SubscriptionDurationHour   = "hour"
	SubscriptionDurationCustom = "custom"
)

Subscription duration units

View Source
const (
	SubscriptionResetNever   = "never"
	SubscriptionResetDaily   = "daily"
	SubscriptionResetWeekly  = "weekly"
	SubscriptionResetMonthly = "monthly"
	SubscriptionResetCustom  = "custom"
)

Subscription quota reset period

View Source
const (
	SystemInstanceStatusOnline = "online"
	SystemInstanceStatusStale  = "stale"

	SystemInstanceStaleAfterSeconds int64 = 90
)
View Source
const (
	SystemTaskStatusPending   SystemTaskStatus = "pending"
	SystemTaskStatusRunning   SystemTaskStatus = "running"
	SystemTaskStatusSucceeded SystemTaskStatus = "succeeded"
	SystemTaskStatusFailed    SystemTaskStatus = "failed"

	SystemTaskTypeLogCleanup                  = "log_cleanup"
	SystemTaskTypeChannelTest                 = "channel_test"
	SystemTaskTypeModelUpdate                 = "model_update"
	SystemTaskTypeOpenAIPriceCheck            = "openai_official_price_check"
	SystemTaskTypeMidjourneyPoll              = "midjourney_poll"
	SystemTaskTypeAsyncTaskPoll               = "async_task_poll"
	SystemTaskTypeChannelQuotaSnapshotCleanup = "channel_quota_snapshot_cleanup"
	// SystemTaskTypeChannelQuotaSnapshotSync periodically samples normalized
	// upstream account balances. Sampling is enabled by default; an explicit
	// environment override takes precedence over the administrator setting.
	SystemTaskTypeChannelQuotaSnapshotSync   = "channel_quota_snapshot_sync"
	SystemTaskTypeTaskRecovery               = "task_recovery"
	SystemTaskTypeTaskBillingOutbox          = "task_billing_outbox"
	SystemTaskTypeQuotaProjectionRecovery    = "quota_projection_recovery"
	SystemTaskTypeAccountQuotaRefundRecovery = "account_quota_refund_recovery"
	SystemTaskTypeQuotaMaintenanceBackfill   = "quota_maintenance_backfill"
	SystemTaskTypeLogProjectionBackfill      = "log_projection_backfill"
)
View Source
const (
	TaskStatusNotStart   TaskStatus = "NOT_START"
	TaskStatusSubmitted             = "SUBMITTED"
	TaskStatusQueued                = "QUEUED"
	TaskStatusInProgress            = "IN_PROGRESS"
	TaskStatusFailure               = "FAILURE"
	TaskStatusSuccess               = "SUCCESS"
	TaskStatusUnknown               = "UNKNOWN"
)
View Source
const (
	TaskPollingDispositionRetryable = "retryable"
	TaskPollingDispositionManual    = "manual"
)
View Source
const (
	TaskSubmissionTerminalRetentionSeconds int64 = 180 * 24 * 60 * 60
	TaskRecoveryPayloadVersion                   = 1

	// Runtime configuration may choose lower values, but model callers may
	// never exceed these technical bounds.
	TaskRecoveryMaxProcessingLeaseSeconds int64 = 300
	TaskRecoveryMaxRetryDelaySeconds      int64 = 24 * 60 * 60

	TaskSubmissionResolutionSourceProviderVerified = "provider_verified"
	TaskSubmissionResolutionSourceManualAudit      = "manual_audit"

	TaskSubmissionOperationKindVideoCreate = "video.create"
	TaskSubmissionOperationKindVideoRemix  = "video.remix"
	TaskSubmissionOperationKindSunoMusic   = "suno.music"
	TaskSubmissionOperationKindSunoLyrics  = "suno.lyrics"
)
View Source
const (
	TaskRecoveryDefaultScanLimit = 50
	TaskRecoveryMaxScanLimit     = 100
)
View Source
const (
	TokenBudgetBoundOpenAIResponses = "openai_responses_input_tokens"
	TokenBudgetBoundOpenAIChat      = "openai_chat_context_window"
	// Exact reviewed native model contract, not a tokenizer estimate or wildcard.
	TokenBudgetOpenAIChatModel           = "gpt-6.1-sol"
	TokenBudgetOpenAIChatContext   int64 = 1050000
	TokenBudgetOpenAIChatMaxOutput int64 = 128000
)
View Source
const (
	TokenBudgetPrepared  = "prepared"
	TokenBudgetSent      = "sent"
	TokenBudgetUnknown   = "usage_unknown"
	TokenBudgetSettled   = "settled"
	TokenBudgetCancelled = "not_sent"
)
View Source
const (
	PaymentMethodStripe       = "stripe"
	PaymentMethodCreem        = "creem"
	PaymentMethodWaffo        = "waffo"
	PaymentMethodWaffoPancake = "waffo_pancake"
	PaymentMethodBalance      = "balance"
)
View Source
const (
	PaymentProviderEpay         = "epay"
	PaymentProviderStripe       = "stripe"
	PaymentProviderCreem        = "creem"
	PaymentProviderWaffo        = "waffo"
	PaymentProviderWaffoPancake = "waffo_pancake"
	PaymentProviderBalance      = "balance"
)
View Source
const (
	UserSessionStatusActive   = "active"
	UserSessionStatusRevoking = "revoking"
	UserSessionStatusRevoked  = "revoked"
)
View Source
const (
	BatchUpdateTypeUserQuota = iota
	BatchUpdateTypeTokenQuota
	BatchUpdateTypeUsedQuota
	BatchUpdateTypeChannelUsedQuota
	BatchUpdateTypeRequestCount
	BatchUpdateTypeCount // if you add a new type, you need to add a new map and a new lock
)
View Source
const BillingSourceSelfUse = "self_use"
View Source
const ChannelModelDiscoveryFreshnessSeconds int64 = 30 * 60

ChannelModelDiscoveryFreshnessSeconds is the display freshness window, matching the existing default 30-minute model-update check cadence. Expiry only marks evidence stale when read: it never fetches, deletes, enables or disables a model, changes routing, or rewrites persisted evidence.

View Source
const ExternalIdentityProviderTelegram = "telegram"
View Source
const LogProjectionSQLiteAutoIndexMaxRows int64 = 10000
View Source
const MaxAssignedAccessPolicyJSONBytes = 65535

MySQL TEXT is limited to 65,535 bytes. Reject larger payloads before any database write so every supported dialect has the same storage contract.

View Source
const MaxOfficialPriceDocumentBytes = 1 << 20
View Source
const MaxTokenBudget int64 = 1<<53 - 1

Token budgets use actual input + output counts, never internal quota units. The maximum keeps integer JSON values exact in the existing browser client.

View Source
const OpenAIOfficialPriceCheckEnabledOptionKey = "OpenAIOfficialPriceCheckEnabled"
View Source
const OptionDiagnosticKeyParseCapChars = config.OptionDiagnosticMaxKeyChars
View Source
const OptionDiagnosticRowLimit = 1024
View Source
const OptionDiagnosticValueParseCapChars = 65536
View Source
const (
	QuotaWriterEpochSchemaVersion = 1
)
View Source
const TaskBillingContextVersion = 1

TaskBillingContextVersion identifies a complete submission-rate snapshot.

View Source
const TaskRefundLegacyCutoff int64 = 1771718400 // 2026-02-22 00:00:00 UTC

TaskRefundLegacyCutoff separates tasks created before timeout refunds were introduced. Those legacy tasks are failed without an automatic refund.

View Source
const UserFundingStateOptionKey = "user_funding_state"
View Source
const UserNameMaxLength = 20
View Source
const (
	UserQuotaMutationReceiptVersion = 1
)

Variables

View Source
var (
	ErrAccountQuotaMutationInvalidInput = errors.New("invalid account quota mutation input")
	ErrAccountQuotaMutationConflict     = errors.New("account quota mutation conflicts with existing receipt")
	ErrAccountQuotaMutationNotFound     = errors.New("account quota reserve receipt not found")
	ErrAccountQuotaMutationTerminal     = errors.New("account quota mutation is already terminal")
	ErrAccountQuotaMutationIneligible   = errors.New("account quota mutation subject is not eligible")
	ErrAccountQuotaMutationInsufficient = errors.New("insufficient account quota")
	ErrAccountQuotaMutationCASLost      = errors.New("account quota mutation compare-and-swap lost")
	ErrAccountQuotaMutationStaleReceipt = errors.New("account quota mutation receipt is not in the current reservation chain")
	ErrAccountQuotaReceiptImmutable     = errors.New("account quota mutation receipt is immutable")
)
View Source
var (
	ErrAccountQuotaTerminalRecoveryConflict = errors.New("account quota terminal recovery obligation conflicts with persisted identity")
	ErrAccountQuotaRefundIntentUnknown      = errors.New("account quota refund intent outcome is unknown")
)
View Source
var (
	ErrAccountQuotaRefundPending        = errors.New("account quota refund is durably pending")
	ErrAccountQuotaRefundFactUnknown    = errors.New("account quota refund fact outcome is unknown")
	ErrAccountQuotaRefundManualRequired = errors.New("account quota refund requires manual verification")
)
View Source
var (
	ErrAccountQuotaSettlementPending        = errors.New("account quota settlement is durably pending")
	ErrAccountQuotaSettlementFactUnknown    = errors.New("account quota settlement fact outcome is unknown")
	ErrAccountQuotaSettlementManualRequired = errors.New("account quota settlement requires manual verification")
)
View Source
var (
	ErrAssignedAccessPolicyInvalid   = errors.New("invalid assigned access policy")
	ErrAssignedAccessPolicyConflict  = errors.New("assigned access policy revision conflict")
	ErrAssignedAccessPolicyForbidden = errors.New("assigned access policy mutation forbidden")
)
View Source
var (
	ErrAuthFlowInvalid  = errors.New("auth flow is invalid")
	ErrAuthFlowExpired  = errors.New("auth flow has expired")
	ErrAuthFlowConsumed = errors.New("auth flow has already been consumed")
)
View Source
var (
	ErrChannelQuotaIdentityAliasConflict    = errors.New("channel quota identity aliases conflict")
	ErrChannelQuotaIdentityRegistryConflict = errors.New("channel quota identity key registry conflict")
	ErrChannelQuotaIdentityRegistryCorrupt  = errors.New("channel quota identity key registry is invalid")
)
View Source
var (
	ErrChannelOperationConflict   = errors.New("channel operation key conflicts with a different request")
	ErrChannelOperationKeyInvalid = errors.New("channel operation key is invalid")
)
View Source
var (
	ErrInvalidCredentials   = errors.New("invalid credentials")
	ErrUserEmptyCredentials = errors.New("empty credentials")
	ErrEmailAlreadyTaken    = errors.New("email already taken")
	ErrEmailNotFound        = errors.New("email not found")
	ErrEmailAmbiguous       = errors.New("email matches multiple users")
)

User auth errors

View Source
var (
	ErrTokenNotProvided = errors.New("token not provided")
	ErrTokenInvalid     = errors.New("token invalid")
)

Token auth errors

View Source
var (
	ErrBillingProjectionConflict        = errors.New("billing log projection conflict")
	ErrBillingProjectionDigestMismatch  = errors.New("billing log projection digest mismatch")
	ErrLogProjectionMaintenanceRequired = errors.New("log projection maintenance required")
)
View Source
var (
	ErrOptionRemediationUnavailable = errors.New("option remediation unavailable")
	ErrOptionRemediationInput       = errors.New("option remediation input invalid")
)
View Source
var (
	ErrTypedBulkUnknownKey       = errors.New("typed bulk option key is not managed")
	ErrTypedBulkDuplicateKey     = errors.New("typed bulk option key is duplicated")
	ErrTypedBulkInvalidValue     = errors.New("typed bulk option value is invalid")
	ErrTypedBulkItemCount        = errors.New("typed bulk item count out of range")
	ErrTypedBulkRevisionConflict = errors.New("typed bulk revision conflict")
	// ErrTypedBulkPublishFailed marks a post-commit runtime publication abort:
	// the database commit stands (same documented boundary as the payment
	// funding bulk) while the failed family and all later families keep their
	// previous runtime generation and OptionMap values.
	ErrTypedBulkPublishFailed = errors.New("typed bulk runtime publication failed")
)
View Source
var (
	ErrPasskeyNotFound         = errors.New("passkey credential not found")
	ErrFriendlyPasskeyNotFound = errors.New("Passkey 验证失败,请重试或联系管理员")
)
View Source
var (
	ErrPromptLearningPolicyNotFound = errors.New("prompt learning policy not found")
	ErrPromptLearningPolicyDisabled = errors.New("prompt learning policy is disabled")
	ErrPromptLearningPolicyStale    = errors.New("prompt learning policy generation is stale")
	ErrPromptLearningSampleConflict = errors.New("prompt learning sample occurrence conflicts")
	ErrPromptInstructionNotFound    = errors.New("prompt instruction version not found")
	ErrPromptInstructionConflict    = errors.New("prompt instruction command conflicts")
	ErrPromptInstructionImmutable   = errors.New("prompt instruction version is immutable")
	ErrPromptInstructionApplication = errors.New("invalid prompt instruction application transition")
	ErrPromptLearningInvalidInput   = errors.New("invalid prompt learning input")
)
View Source
var (
	ErrQuotaBalanceMutationUnknown    = errors.New("quota balance mutation outcome is unknown")
	ErrQuotaBalanceGenerationConflict = errors.New("quota balance generation conflicts with persisted identity")
	ErrQuotaBalanceSubjectBusy        = errors.New("quota balance subject is busy")
)
View Source
var (
	ErrTaskQuotaReservationInvalidInput      = errors.New("invalid task quota reservation input")
	ErrTaskQuotaReservationConflict          = errors.New("task quota reservation conflicts with the applied receipt")
	ErrTaskQuotaReservationCASLost           = errors.New("task quota reservation compare-and-swap lost")
	ErrTaskQuotaReservationIneligible        = errors.New("task quota reservation subject is not eligible")
	ErrTaskQuotaReservationInsufficientQuota = errors.New("insufficient quota for task reservation")
	ErrTaskQuotaReservationNotFound          = errors.New("task quota reservation receipt not found")
	ErrQuotaMutationReceiptImmutable         = errors.New("quota mutation receipt is immutable")
)
View Source
var (
	ErrTaskQuotaAlreadySettled         = errors.New("task quota is already settled")
	ErrTaskQuotaAlreadyRefunded        = errors.New("task quota is already refunded")
	ErrTaskQuotaSettlementInvalidInput = errors.New("invalid task quota settlement input")
	ErrTaskQuotaReleaseInvalidInput    = errors.New("invalid task quota release input")
)
View Source
var (
	ErrQuotaProjectionManual        = errors.New("quota projection obligation requires manual repair")
	ErrQuotaProjectionNotDue        = errors.New("quota projection obligation is not due")
	ErrQuotaProjectionClaimed       = errors.New("quota projection obligation is already claimed")
	ErrQuotaProjectionLeaseLost     = errors.New("quota projection obligation lease lost")
	ErrQuotaProjectionRepairInvalid = errors.New("invalid quota projection repair command")
	ErrQuotaProjectionRepairCASLost = errors.New("quota projection repair compare-and-swap lost")
)
View Source
var (
	ErrQuotaWorkIncomplete                = errors.New("quota maintenance work remains")
	ErrQuotaMaintenanceBackfillIncomplete = errors.New("quota maintenance backfill is incomplete")
)
View Source
var (
	ErrQuotaWriterEpochUnavailable    = errors.New("quota writer epoch is unavailable")
	ErrQuotaWriterEpochMismatch       = errors.New("quota writer epoch mismatch")
	ErrDurableQuotaWriterModeDisabled = errors.New("durable quota writes require authoritative writer mode")
	ErrQuotaProjectionModeDisabled    = errors.New("quota projection requires bridge or authoritative writer mode")
	ErrLegacyQuotaWriterModeDisabled  = errors.New("legacy quota writer requires legacy writer mode")
	ErrBatchQuotaCacheUnavailable     = errors.New("batch quota cache is unavailable")
)
View Source
var (
	// ErrQuotaWriterTransitionConflict means the persisted epoch row no longer
	// matches the caller's expected epoch/lock version. No evidence row is
	// written for conflicts: the winner's transition is the evidence.
	ErrQuotaWriterTransitionConflict = errors.New("quota writer mode transition conflicts with the current epoch state")
	// ErrQuotaWriterTransitionInvalid means the requested mode pair is not an
	// allowed transition (legacy->bridge->authoritative only, never downgraded).
	ErrQuotaWriterTransitionInvalid = errors.New("quota writer mode transition is not allowed")
)
View Source
var (
	ErrSubscriptionOrderNotFound      = errors.New("subscription order not found")
	ErrSubscriptionOrderStatusInvalid = errors.New("subscription order status invalid")
)
View Source
var (
	ErrTaskRecoveryInvalidRecord         = errors.New("invalid task recovery record")
	ErrTaskRecoveryInvalidTransition     = errors.New("invalid task recovery state transition")
	ErrTaskSubmissionOperationNotFound   = errors.New("task submission operation not found")
	ErrTaskSubmissionTaskNotFound        = errors.New("task submission operation task not found")
	ErrTaskSubmissionTaskIDMismatch      = errors.New("task submission operation public id does not match task id")
	ErrTaskSubmissionIdempotencyConflict = errors.New("task submission idempotency key belongs to a different request")
	ErrTaskSubmissionAttemptConflict     = errors.New("task submission attempt belongs to a different immutable request")
	ErrTaskBillingEventNotFound          = errors.New("task billing event not found")
	ErrTaskBillingEventConflict          = errors.New("task billing event key belongs to a different immutable event")
	ErrTaskBillingLogOutboxConflict      = errors.New("task billing log outbox already has a different immutable projection")
)
View Source
var (
	ErrTaskRecoveryIdentityMismatch  = errors.New("task recovery database identity does not match this deployment")
	ErrTaskRecoveryIdentityMissing   = errors.New("task recovery identity is missing for existing submission records")
	ErrTaskRecoveryIdentityImmutable = errors.New("task recovery database identity is immutable")
)
View Source
var (
	ErrTaskTerminalObservationConflict     = errors.New("task terminal observation conflict")
	ErrTaskTerminalObservationManualReview = errors.New("task terminal observation requires manual review")
)
View Source
var (
	ErrTokenBudgetInvalid   = errors.New("invalid token budget input")
	ErrTokenBudgetConflict  = errors.New("token budget revision or evidence conflict")
	ErrTokenBudgetPending   = errors.New("token budget has an unresolved request")
	ErrTokenBudgetExceeded  = errors.New("token budget is insufficient")
	ErrTokenBudgetBound     = errors.New("reported usage does not match the reserved bound")
	ErrTokenBudgetDuplicate = errors.New("token budget request has already been admitted")
)
View Source
var (
	ErrTopUpPaymentSourceUnresolved = errors.New("top-up payment source requires manual reconciliation")
	ErrPaymentMethodMismatch        = errors.New("payment method mismatch")
	ErrTopUpNotFound                = errors.New("topup not found")
	ErrTopUpStatusInvalid           = errors.New("topup status invalid")
	ErrInvalidTopUpQuota            = errors.New("invalid top-up quota")
	ErrTopUpQuotaLimitExceeded      = errors.New("top-up quota limit exceeded")
	ErrTopUpQuotaUnitUnresolved     = errors.New("top-up quota unit requires manual reconciliation")
)
View Source
var (
	ErrUserFundingUnavailable          = errors.New("user funding unavailable")
	ErrUserFundingRuntimeStale         = errors.New("user funding runtime snapshot is stale")
	ErrUserFundingWebhookAcknowledge   = errors.New("user funding webhook acknowledged without settlement")
	ErrUserFundingStateEpochExhausted  = errors.New("user funding state epoch exhausted")
	ErrUserFundingInvalidPersistedMode = errors.New("invalid persisted user funding mode")
)
View Source
var (
	ErrUserQuotaMutationReceiptImmutable  = errors.New("user quota mutation receipt is immutable")
	ErrUserQuotaMutationConflict          = errors.New("user quota mutation conflicts with existing receipt")
	ErrUserQuotaMutationInvalidInput      = errors.New("invalid user quota mutation input")
	ErrUserQuotaCASLost                   = errors.New("user quota compare-and-swap lost")
	ErrInsufficientUserQuota              = errors.New("insufficient user quota")
	ErrUserQuotaUpperBoundExceeded        = errors.New("user quota upper bound exceeded")
	ErrUserQuotaBusinessSchemaUnavailable = errors.New("user quota business writer schema capability is unavailable")
)
View Source
var (
	ErrUserSessionInvalid        = errors.New("user session is invalid")
	ErrUserSessionInactive       = errors.New("user session is inactive")
	ErrUserSessionRefreshInvalid = errors.New("user session refresh token is invalid")
	ErrUserSessionRefreshRace    = errors.New("user session refresh is already in progress")
	ErrUserSessionRefreshReuse   = errors.New("user session refresh token was reused")
	ErrUserSessionLimit          = errors.New("active user session limit reached")
	ErrUserSessionIssuanceLimit  = errors.New("user session issuance limit reached")
)
View Source
var CacheQuotaData = make(map[string]*QuotaData)
View Source
var CacheQuotaDataLock = sync.Mutex{}
View Source
var DB *gorm.DB
View Source
var ErrAccountQuotaThresholdCombination = errors.New("account thresholds cannot be combined with the current direct API Token or USD budget modes")
View Source
var ErrAccountQuotaThresholdInvalid = errors.New("invalid account quota threshold")
View Source
var ErrAccountQuotaUsageUnresolved = errors.New("account quota usage requires reconciliation")
View Source
var ErrAdminQuotaAdjustmentConflict = errors.New("admin quota adjustment conflicts with an existing request")

ErrAdminQuotaAdjustmentConflict 表示 request id 已被不同参数使用, 或记录停在无法重放的状态。

View Source
var ErrAffQuotaTransferConflict = errors.New("aff quota transfer conflicts with an existing request")

ErrAffQuotaTransferConflict is returned when a request id was already used with a different quota or ended in a state that cannot be replayed.

View Source
var (
	ErrChannelRoutingEpochUnavailable = errors.New("channel routing epoch is unavailable")
)
View Source
var ErrCodexQuotaRouteIdentity = errors.New("Codex quota routing identity is unavailable")
View Source
var (
	ErrDatabase = errors.New("database error")
)

Common errors

View Source
var ErrExternalIdentityAlreadyClaimed = errors.New("external identity is already claimed")
View Source
var ErrFeeBudgetExceeded = errors.New("USD budget is insufficient")
View Source
var ErrFeeBudgetInvalid = errors.New("invalid exact USD budget amount")
View Source
var ErrInvalidChannelRoutingSettings = errors.New("invalid channel routing settings")
View Source
var ErrModelRouteConfigChanged = errors.New("model_route_config_changed")
View Source
var ErrModelRouteConflict = errors.New("model_route_conflict")
View Source
var ErrModelRouteEndpoint = errors.New("model_route_endpoint_unsupported")
View Source
var ErrModelRouteInvalid = errors.New("model_route_invalid")
View Source
var ErrOptionDiagnosticsUnavailable = errors.New("option diagnostics unavailable")
View Source
var ErrPricePublicationConflict = errors.New("price publication has changed")
View Source
var ErrPricePublicationImmutable = errors.New("price publication receipt is immutable")
View Source
var ErrPricePublicationLocked = errors.New("model price is locked")
View Source
var ErrPricingRuntimeUnavailable = errors.New("pricing runtime publication is incomplete")
View Source
var ErrPromptLearningRun = errors.New("invalid prompt learning run transition")
View Source
var ErrRedeemFailed = errors.New("redeem.failed")

Redemption errors

View Source
var ErrSystemTaskLockLost = errors.New("system task lock lost")
View Source
var ErrTaskOperationQueryUnavailable = errors.New("task operation query unavailable")
View Source
var ErrTokenBudgetUnsupportedFunding = errors.New("strict token budget has unsupported quota funding")
View Source
var ErrTwoFAAlreadyEnabled = errors.New("2fa already enabled")
View Source
var ErrTwoFANotEnabled = errors.New("2fa not enabled")

2FA errors

View Source
var ErrUserAuthCachePending = errors.New("user authentication state update is pending")
View Source
var ErrUserAuthVersionConflict = errors.New("user authentication version update conflicted")
View Source
var ErrUserUsagePolicyConflict = errors.New("user usage policy revision conflict")
View Source
var ErrUserUsagePolicyInvalid = errors.New("invalid user usage policy")
View Source
var LOG_DB *gorm.DB

Functions

func AccountQuotaSettlementIntentSchemaReady

func AccountQuotaSettlementIntentSchemaReady() bool

func AccountQuotaUsageNeedsReview

func AccountQuotaUsageNeedsReview(ctx context.Context, db *gorm.DB, tokenID int) (bool, error)

AccountQuotaUsageNeedsReview reads the primary DB, never a cached Token. A caller must still serialize strict-budget admission with its quota mutation; this read alone is not a concurrency-safe budget reservation.

func AcquirePricingRuntimeRead

func AcquirePricingRuntimeRead() (func(), error)

AcquirePricingRuntimeRead is held only while building a quote, never during a merchant/upstream request or database settlement. Readers run concurrently.

func AdminBindSubscription

func AdminBindSubscription(userId int, planId int, sourceNote string) (string, error)

Admin bind (no payment). Creates a UserSubscription from a plan.

func AdminDeleteUserSubscription

func AdminDeleteUserSubscription(userSubscriptionId int) (string, error)

AdminDeleteUserSubscription hard-deletes a user subscription.

func AdminInvalidateUserSubscription

func AdminInvalidateUserSubscription(userSubscriptionId int) (string, error)

AdminInvalidateUserSubscription marks a user subscription as cancelled and ends it immediately.

func ApplyChannelGroupFilter

func ApplyChannelGroupFilter(query *gorm.DB, group string) *gorm.DB

func BatchDeleteChannels

func BatchDeleteChannels(ids []int) (int64, error)

func BatchDeleteTokens

func BatchDeleteTokens(ids []int, userId int) (int, error)

BatchDeleteTokens 删除指定用户的一组令牌,返回成功删除数量

func BatchInsertChannels

func BatchInsertChannels(channels []Channel) error

func BatchSetChannelTag

func BatchSetChannelTag(ids []int, tag *string) error

func BindEmailToUser

func BindEmailToUser(user *User, email string) error

BindEmailToUser atomically checks email availability and assigns it to the user, serializing concurrent binds of the same email so two accounts cannot end up sharing one address. The email is normalized before check and store.

func BindLegacyUsageReservation

func BindLegacyUsageReservation(ctx context.Context, db *gorm.DB, input LegacyUsageReservation) error

func BumpUserAuthVersion

func BumpUserAuthVersion(userId int) (int64, error)

BumpUserAuthVersion is the transaction-owning variant used by password, role, status and security-factor changes outside another transaction.

func CacheUpdateChannel

func CacheUpdateChannel(channel *Channel)

func CacheUpdateChannelKeyWithContext

func CacheUpdateChannelKeyWithContext(ctx context.Context, id int, key string) error

CacheUpdateChannelKeyWithContext replaces only the credential in an existing cache entry. It performs no database/pricing rebuild and cannot keep a quota sampling lock waiting indefinitely for a concurrent full cache refresh.

func CanTransitionTaskBillingEvent

func CanTransitionTaskBillingEvent(from, to TaskBillingEventState) bool

func CanTransitionTaskBillingLogOutbox

func CanTransitionTaskBillingLogOutbox(from, to TaskBillingLogOutboxState) bool

func CanTransitionTaskSubmissionAttempt

func CanTransitionTaskSubmissionAttempt(from, to TaskSubmissionAttemptStatus) bool

func CanTransitionTaskSubmissionOperation

func CanTransitionTaskSubmissionOperation(from, to TaskSubmissionOperationStatus) bool

func CancelPromptLearningRun

func CancelPromptLearningRun(ctx context.Context, userID int, scopeRef string, runID int64) (bool, error)

CancelPromptLearningRun cancels only work that has not crossed the external submission boundary. A submitted/unknown run is intentionally left intact: an upstream request may already have consumed quota and its result must be reconciled rather than rewritten as cancelled.

func CaptureExposedPricingData

func CaptureExposedPricingData() (map[string]any, bool, error)

func CaptureOptionMapForPricingRead

func CaptureOptionMapForPricingRead() (map[string]string, error)

CaptureOptionMapForPricingRead keeps the administrator's old-value CAS view on one side of a local pricing batch publication.

func CapturePricingSyncData

func CapturePricingSyncData() (map[string]any, error)

func CapturePublicPricing

func CapturePublicPricing() ([]Pricing, []PricingVendor, error)

func CaptureQuotaUnitForOrder

func CaptureQuotaUnitForOrder() (string, error)

CaptureQuotaUnitForOrder freezes the unit before a new order is created. Controllers must pass this same value through quote, validation and Insert.

func ChannelModelDiscoverySource

func ChannelModelDiscoverySource(channel *Channel) string

func ChannelQuotaAccountRef

func ChannelQuotaAccountRef(provider, accountID string) string

ChannelQuotaAccountRef returns a non-reversible reference to an upstream account identity. Empty inputs intentionally remain unknown rather than collapsing unrelated credentials into a shared identity.

func ChannelQuotaAlertFailureQuarantines

func ChannelQuotaAlertFailureQuarantines(event ChannelQuotaAlertEvent) bool

func ChannelQuotaAlertMaxAttempts

func ChannelQuotaAlertMaxAttempts() int

func ChannelQuotaSnapshotIdentity

func ChannelQuotaSnapshotIdentity(snapshot ChannelQuotaSnapshot) (string, string, bool)

ChannelQuotaSnapshotIdentity returns a fixed-domain digest used only for grouping. New rows use the persistent subject namespace. Historical rows with only AccountRef remain readable in a distinct legacy namespace and are never equated with a new subject. Empty or malformed identities fail closed.

func ChannelQuotaSnapshotSeriesID

func ChannelQuotaSnapshotSeriesID(snapshot ChannelQuotaSnapshot) string

ChannelQuotaSnapshotSeriesID is the only identity emitted by aggregate APIs. It is stable across processes and keyring rotation but cannot be used to recover SubjectRef or the historical AccountRef.

func ChannelRoutingConfigDigest

func ChannelRoutingConfigDigest(channel *Channel) string

ChannelRoutingConfigDigest is a concurrency token for the non-secret routing fields edited together. Credentials, observations and accounting are excluded.

func CheckFeeBudgetAdmission

func CheckFeeBudgetAdmission(budget *TokenBudget) error

func CheckSetup

func CheckSetup()

func CheckUserExistOrDeleted

func CheckUserExistOrDeleted(username string, email string) (bool, error)

CheckUserExistOrDeleted check if user exist or deleted, if not exist, return false, nil, if deleted or exist, return true, nil

func ClaimExternalAuthAssertion

func ClaimExternalAuthAssertion(purpose, assertion string, expiresAt time.Time) error

ClaimExternalAuthAssertion records a signed provider assertion as consumed. The assertion is HMACed before storage and the unique token_hash index makes replay rejection atomic on SQLite, MySQL and PostgreSQL.

func ClaimExternalAuthAssertionWithTx

func ClaimExternalAuthAssertionWithTx(tx *gorm.DB, purpose, assertion string, expiresAt time.Time) error

ClaimExternalAuthAssertionWithTx records a provider assertion in the caller's transaction so replay protection can commit atomically with the authentication flow and its resulting state change.

func ClaimExternalIdentityWithTx

func ClaimExternalIdentityWithTx(tx *gorm.DB, provider, subject string, userId int) error

ClaimExternalIdentityWithTx atomically claims a provider subject for one user. Repeating the exact mapping is idempotent; every competing subject or user is rejected. Ownership is read back instead of trusting RowsAffected, whose duplicate-key semantics differ between supported databases.

func ClaimLegacyUsageRequest

func ClaimLegacyUsageRequest(ctx context.Context, db *gorm.DB, requestID string, userID, tokenID int) error

Claim the request before any legacy reserve. The unique request key prevents two sessions with the same identity from each debiting before journal insert.

func CleanupChannelPollingLocks

func CleanupChannelPollingLocks()

CleanupChannelPollingLocks removes locks for channels that no longer exist This is optional and can be called periodically to prevent memory leaks

func CleanupRelayAccountHolds

func CleanupRelayAccountHolds(ctx context.Context, db *gorm.DB, limit int) (int64, error)

CleanupRelayAccountHolds removes at most limit expired rows. Reads never extend a hold; restart uses the persisted expiry and requires no recovery write.

func CleanupSubscriptionPreConsumeRecords

func CleanupSubscriptionPreConsumeRecords(olderThanSeconds int64) (int64, error)

CleanupSubscriptionPreConsumeRecords removes old idempotency records to keep table small.

func ClearTaskPollingDisposition

func ClearTaskPollingDisposition(db *gorm.DB, task *Task) (bool, error)

func CloseDB

func CloseDB() error

func CodexThresholdCredentialFailedAfter

func CodexThresholdCredentialFailedAfter(ctx context.Context, db *gorm.DB, credentialSubject string, observedAt int64) (bool, error)

Newer credential-scoped failures cannot borrow another credential's healthy account sample. Failures remain scoped and do not poison other accounts.

func CompleteChannelModelDiscovery

func CompleteChannelModelDiscovery(ctx context.Context, attempt ChannelModelDiscoveryAttempt, models []string, succeeded bool) (bool, error)

CompleteChannelModelDiscovery rejects superseded/configuration-mismatched responses atomically. Failed fetches retain the last successful catalogue. Terminal attempts accept identical replay without writes and reject changes.

func CompleteOpenAIPriceCheck

func CompleteOpenAIPriceCheck(ctx context.Context, task *SystemTask, runnerID string, saveSource func(*gorm.DB) (*OpenAIPriceCheckResult, error), errorCode string) error

CompleteOpenAIPriceCheck commits frozen evidence and the successful task receipt together. The source callback must only save immutable evidence; it must never publish prices. An expired/canceled/fenced worker cannot save a new source or replace the last successful receipt. A nil callback finishes a failed attempt without touching source evidence.

func CompleteSubscriptionOrder

func CompleteSubscriptionOrder(tradeNo string, providerPayload string, expectedPaymentProvider string, actualPaymentMethod string, decision UserFundingWebhookDecision) error

Complete a subscription order (idempotent). Creates a UserSubscription snapshot from the plan. expectedPaymentProvider guards against cross-gateway callback attacks (empty skips the check). actualPaymentMethod updates the order's PaymentMethod to reflect the real payment type used (empty skips update).

func CompleteSubscriptionOrderTrusted

func CompleteSubscriptionOrderTrusted(tradeNo string, providerPayload string, expectedPaymentProvider string, actualPaymentMethod string) error

func ComputeBillingProjectionDigest

func ComputeBillingProjectionDigest(log *Log) string

ComputeBillingProjectionDigest returns the versioned digest of the complete immutable log projection. Database identity and physical-delivery fields are intentionally excluded: Id and LogRowKey differ between replayed rows.

func CountActiveUserSessions

func CountActiveUserSessions(userID int, now int64) (int64, error)

func CountAllChannels

func CountAllChannels() (int64, error)

CountAllChannels returns total channels in DB

func CountAllTags

func CountAllTags() (int64, error)

CountAllTags returns number of non-empty distinct tags

func CountAllTasks

func CountAllTasks(queryParams TaskQueryParams) int64

CountAllTasks returns total midjourney tasks for admin query

func CountAllUserTask

func CountAllUserTask(userId int, queryParams TaskQueryParams) int64

CountAllUserTask returns total midjourney tasks for user

func CountChannelQuotaSnapshotsWithQuery

func CountChannelQuotaSnapshotsWithQuery(ctx context.Context, channelID int, start, end int64, filter ChannelQuotaSnapshotQuery) (int64, error)

CountChannelQuotaSnapshotsWithQuery counts every observation in a selected time range. It is intentionally separate from the legacy bounded list API so history endpoints can reject or flag a dense range before allocating its raw observations.

func CountChannelTags

func CountChannelTags(query *gorm.DB) (int64, error)

func CountChannelsByType

func CountChannelsByType(channelType int) (int64, error)

Count channels of specific type

func CountChannelsGroupByType

func CountChannelsGroupByType() (map[int64]int64, error)

Return map[type]count for all channels

func CountOldLog

func CountOldLog(ctx context.Context, targetTimestamp int64) (int64, error)

func CountUnsafeOldLogs

func CountUnsafeOldLogs(ctx context.Context, targetTimestamp int64) (int64, error)

func CountUserSessionsCreatedSince

func CountUserSessionsCreatedSince(userID int, createdAfter int64) (int64, error)

CountUserSessionsCreatedSince counts every issued row, regardless of its current status or expiry. userID zero selects the global count.

func CountUserSubscriptionsByPlan

func CountUserSubscriptionsByPlan(userId int, planId int) (int64, error)

func CountUserTokens

func CountUserTokens(userId int) (int64, error)

CountUserTokens returns total number of tokens for the given user, used for pagination

func CountUsersByEmail

func CountUsersByEmail(email string) (int64, error)

func CreateCustomOAuthProvider

func CreateCustomOAuthProvider(provider *CustomOAuthProvider) error

CreateCustomOAuthProvider creates a new custom OAuth provider

func CreateLog

func CreateLog(db *gorm.DB, logRecord *Log) error

func CreateLogs

func CreateLogs(db *gorm.DB, logs []*Log) error

func CreateNextLogProjectionIndex

func CreateNextLogProjectionIndex(ctx context.Context, db *gorm.DB) (bool, bool, error)

func CreatePendingTwoFASetupBackupCodes

func CreatePendingTwoFASetupBackupCodes(userId int, codes []string) error

CreatePendingTwoFASetupBackupCodes stores recovery codes for an unverified setup. Regeneration for an enabled factor must advance auth_version.

func CreateUserOAuthBinding

func CreateUserOAuthBinding(binding *UserOAuthBinding) error

CreateUserOAuthBinding creates a new OAuth binding

func CreateUserOAuthBindingWithTx

func CreateUserOAuthBindingWithTx(tx *gorm.DB, binding *UserOAuthBinding) error

CreateUserOAuthBindingWithTx creates a new OAuth binding within a transaction

func CreateUserSession

func CreateUserSession(session *UserSession) error

func CurrentTypedBulkRevision

func CurrentTypedBulkRevision() (int64, error)

CurrentTypedBulkRevision returns the persistent typed bulk revision (0 when no typed bulk has committed yet). It backs the form-loading GET endpoint.

func DecreaseTokenQuota

func DecreaseTokenQuota(id int, key string, quota int) (err error)

func DecreaseTokenQuotaWithContext

func DecreaseTokenQuotaWithContext(input QuotaMutationContext, tokenID int, key string, quota int) error

func DecreaseUserQuota

func DecreaseUserQuota(id int, quota int, db bool) (err error)

func DecreaseUserQuotaWithContext

func DecreaseUserQuotaWithContext(input QuotaMutationContext, id int, quota int) error

func DeleteChannelByStatus

func DeleteChannelByStatus(status int64) (int64, error)

func DeleteCustomOAuthProvider

func DeleteCustomOAuthProvider(id int) error

DeleteCustomOAuthProvider deletes a custom OAuth provider by ID

func DeleteDisabledChannel

func DeleteDisabledChannel() (int64, error)

func DeleteExpiredAuthFlows

func DeleteExpiredAuthFlows(now time.Time) error

func DeleteExpiredUserSessions

func DeleteExpiredUserSessions(now int64) error

func DeleteInvalidRedemptions

func DeleteInvalidRedemptions() (int64, error)

func DeleteOldChannelQuotaSnapshotBatch

func DeleteOldChannelQuotaSnapshotBatch(ctx context.Context, cutoff int64, limit int) (int64, error)

DeleteOldChannelQuotaSnapshotBatch deletes at most limit snapshots observed before cutoff. IDs are selected first so the limit is honored consistently across SQLite, MySQL, and PostgreSQL dialects.

func DeleteOldLogBatch

func DeleteOldLogBatch(ctx context.Context, targetTimestamp int64, limit int) (int64, error)

func DeleteOldRevokedUserSessions

func DeleteOldRevokedUserSessions(now int64) error

func DeletePasskeyByUserIDWithAuthVersion

func DeletePasskeyByUserIDWithAuthVersion(userID int) error

func DeletePerfMetricsBefore

func DeletePerfMetricsBefore(cutoffTs int64) error

func DeletePrefillGroupByID

func DeletePrefillGroupByID(id int) error

DeleteByID 根据 ID 删除组

func DeleteRedemptionById

func DeleteRedemptionById(id int) (err error)

func DeleteStaleSystemInstance

func DeleteStaleSystemInstance(nodeName string, now int64) (bool, error)

func DeleteStaleSystemInstances

func DeleteStaleSystemInstances(now int64) (int64, error)

func DeleteTokenById

func DeleteTokenById(id int, userId int) (err error)

func DeleteUserById

func DeleteUserById(id int) (err error)

func DeleteUserOAuthBinding

func DeleteUserOAuthBinding(userId, providerId int) error

DeleteUserOAuthBinding deletes an OAuth binding

func DeltaUpdateUserQuota

func DeltaUpdateUserQuota(id int, delta int) (err error)

func DisableChannelByTag

func DisableChannelByTag(tag string) error

func DisableModelLimits

func DisableModelLimits(tokenId int) error

func DisableTwoFAWithAuthVersion

func DisableTwoFAWithAuthVersion(userId int) error

DisableTwoFAWithAuthVersion atomically removes the factor and invalidates every access token issued against the previous security configuration.

func EditChannelByTag

func EditChannelByTag(tag string, newTag *string, modelMapping *string, models *string, group *string, priority *int64, weight *uint, paramOverride *string, headerOverride *string) error

func EffectiveAccessProfileID

func EffectiveAccessProfileID(groupName string) string

EffectiveAccessProfileID returns the stable identity for a token while keeping the legacy group as the source of truth during the compatibility period. An empty group is the standard profile.

func EffectiveAccountTierID

func EffectiveAccountTierID(groupName string) string

EffectiveAccountTierID returns the stable account-tier identity for a user. It deliberately does not influence channel routing; that remains the job of the token access profile and the legacy group compatibility path.

func EnableChannelByTag

func EnableChannelByTag(tag string) error

func EnsureAccountQuotaRefundRecovery

EnsureAccountQuotaRefundRecovery persists the refund intent before any refund attempt. The lifecycle row is created atomically with the authoritative reserve; this method only claims that existing obligation or resolves an already committed terminal receipt.

func EnsureChannelQuotaIdentityKeyring

func EnsureChannelQuotaIdentityKeyring(ctx context.Context, db *gorm.DB, keyring common.ChannelQuotaIdentityKeyring) error

EnsureChannelQuotaIdentityKeyring explicitly validates and registers a deployment keyring without resolving identity material. Startup paths can call it before enabling quota sampling.

func EnsureChannelQuotaSamplingTarget

func EnsureChannelQuotaSamplingTarget(ctx context.Context, db *gorm.DB, channelID int, identity ChannelQuotaSamplingIdentity) error

func EnsureClickHouseBillingProjectionIdentity

func EnsureClickHouseBillingProjectionIdentity(ctx context.Context, db *gorm.DB, eventID string, digest string) error

func EnsureEmailAvailable

func EnsureEmailAvailable(email string, excludeUserID int) error

func EnsureLogProjectionSchemaWithDB

func EnsureLogProjectionSchemaWithDB(db *gorm.DB) error

func EnsureQuotaMaintenanceBackfillCursorsWithDB

func EnsureQuotaMaintenanceBackfillCursorsWithDB(db *gorm.DB) error

EnsureQuotaMaintenanceBackfillCursorsWithDB creates only the small durable cursors required by asynchronous backfill. It never scans or rewrites source rows, so startup schema migration remains bounded.

func EnsureQuotaWriterEpochStateWithDB

func EnsureQuotaWriterEpochStateWithDB(db *gorm.DB) error

EnsureQuotaWriterEpochStateWithDB creates the default legacy singleton after schema migration. It never advances the epoch or changes mode.

func EnsureTaskRecoveryIdentity

func EnsureTaskRecoveryIdentity(tx *gorm.DB) error

EnsureTaskRecoveryIdentity runs on startup when the deployment requests recovery and before every operation insert. A row absent from an otherwise populated operation store is ambiguous, so it is never silently rebound. The unique singleton arbitrates concurrent first-starts across SQL dialects.

func ExpireDueSubscriptions

func ExpireDueSubscriptions(limit int) (int, error)

ExpireDueSubscriptions marks expired subscriptions and handles group downgrade.

func ExpireStaleSystemTaskLocks

func ExpireStaleSystemTaskLocks(now int64) error

func ExpireSubscriptionOrder

func ExpireSubscriptionOrder(tradeNo string, expectedPaymentProvider string, decision UserFundingWebhookDecision) error

func ExpireSubscriptionOrderTrusted

func ExpireSubscriptionOrderTrusted(tradeNo string, expectedPaymentProvider string) error

func FailLegacyUsageAdmission

func FailLegacyUsageAdmission(ctx context.Context, db *gorm.DB, requestID string) error

This state proves no upstream request was sent; existing refund facts still own compensation. It never asserts that the debit has already been refunded.

func FindEarliestPendingSystemTasks

func FindEarliestPendingSystemTasks(taskTypes []string) (map[string]*SystemTask, error)

func FingerprintChannelOperation

func FingerprintChannelOperation(value any) (string, error)

func FingerprintTaskSubmissionRequest

func FingerprintTaskSubmissionRequest(canonicalRequest []byte) string

FingerprintTaskSubmissionRequest hashes an already canonicalized request. Canonicalization belongs to the protocol layer; this helper never persists or returns the original request bytes.

func FinishSystemTask

func FinishSystemTask(taskID string, lockedBy string, status SystemTaskStatus, resultPayload any, errorMessage string) error

func FinishSystemTaskWithContext

func FinishSystemTaskWithContext(ctx context.Context, taskID string, lockedBy string, status SystemTaskStatus, resultPayload any, errorMessage string) error

func FixAbility

func FixAbility() (int, int, error)

func GenerateSystemTaskID

func GenerateSystemTaskID() (string, error)

func GenerateTaskID

func GenerateTaskID() string

GenerateTaskID 生成对外暴露的 task_xxxx 格式 ID

func GenerateTaskSubmissionOperationPublicID

func GenerateTaskSubmissionOperationPublicID() (string, error)

func GetBindingCountByProviderId

func GetBindingCountByProviderId(providerId int) (int64, error)

GetBindingCountByProviderId returns the number of bindings for a provider

func GetBoundChannelsByModelsMap

func GetBoundChannelsByModelsMap(modelNames []string) (map[string][]BoundChannel, error)

func GetChannelPollingLock

func GetChannelPollingLock(channelId int) *sync.Mutex

GetChannelPollingLock returns or creates a mutex for the given channel ID

func GetCommittedChannelRoutingEpoch

func GetCommittedChannelRoutingEpoch(db *gorm.DB) (int64, error)

func GetDBTimestamp

func GetDBTimestamp() int64

GetDBTimestamp returns a UNIX timestamp from database time. Falls back to application time on error.

func GetEnabledModels

func GetEnabledModels() []string

func GetGroupEnabledModels

func GetGroupEnabledModels(group string) []string

func GetLatestSystemTasks

func GetLatestSystemTasks(taskTypes []string) (map[string]*SystemTask, error)

func GetMaxUserId

func GetMaxUserId() int

func GetMissingModels

func GetMissingModels() ([]string, error)

GetMissingModels returns model names that are referenced in the system

func GetModelEnableGroups

func GetModelEnableGroups(modelName string) []string

func GetModelQuotaTypes

func GetModelQuotaTypes(modelName string) []int

GetModelQuotaTypes 返回指定模型的计费类型集合(来自缓存)

func GetModelSupportEndpointTypes

func GetModelSupportEndpointTypes(model string) []constant.EndpointType

func GetPaginatedChannelTags

func GetPaginatedChannelTags(query *gorm.DB, offset int, limit int) ([]*string, error)

func GetPaginatedTags

func GetPaginatedTags(offset int, limit int) ([]*string, error)

func GetPreferredModelOwnerChannelTypes

func GetPreferredModelOwnerChannelTypes(modelNames []string, groups []string) (map[string]int, error)

func GetSupportedEndpointMap

func GetSupportedEndpointMap() map[string]common.EndpointInfo

GetSupportedEndpointMap 返回全局端点到路径的映射

func GetTwoFAStats

func GetTwoFAStats() (map[string]interface{}, error)

GetTwoFAStats 获取2FA统计信息(管理员使用)

func GetUnusedBackupCodeCount

func GetUnusedBackupCodeCount(userId int) (int, error)

GetUnusedBackupCodeCount 获取未使用的备用码数量

func GetUserCheckinStats

func GetUserCheckinStats(userId int, month string) (map[string]interface{}, error)

GetUserCheckinStats 获取用户签到统计信息

func GetUserEmail

func GetUserEmail(id int) (email string, err error)

func GetUserGroup

func GetUserGroup(id int, fromDB bool) (group string, err error)

GetUserGroup gets group from Redis first, falls back to DB if needed

func GetUserIdByAffCode

func GetUserIdByAffCode(affCode string) (int, error)

func GetUserLanguage

func GetUserLanguage(userId int) string

GetUserLanguage returns the user's language preference from cache Uses the existing GetUserCache mechanism for efficiency

func GetUserQuota

func GetUserQuota(id int, fromDB bool) (quota int, err error)

GetUserQuota gets quota from Redis first, falls back to DB if needed

func GetUserSetting

func GetUserSetting(id int, fromDB bool) (settingMap dto.UserSetting, err error)

GetUserSetting gets setting from Redis first, falls back to DB if needed

func GetUserUsedQuota

func GetUserUsedQuota(id int) (quota int, err error)

func GetUsernameById

func GetUsernameById(id int, fromDB bool) (username string, err error)

GetUsernameById gets username from Redis first, falls back to DB if needed

func GetVendorModelCounts

func GetVendorModelCounts() (map[int64]int64, error)

func HardDeleteUserById

func HardDeleteUserById(id int) error

func HasActiveUserSubscription

func HasActiveUserSubscription(userId int) (bool, error)

HasActiveUserSubscription returns whether the user has any active subscription. This is a lightweight existence check to avoid heavy pre-consume transactions.

func HasCheckedInToday

func HasCheckedInToday(userId int) (bool, error)

HasCheckedInToday 检查用户今天是否已签到

func HasUnfinishedMidjourneyTasks

func HasUnfinishedMidjourneyTasks() bool

HasUnfinishedMidjourneyTasks reports whether at least one Midjourney task is still in progress. It is a cheap existence check (LIMIT 1) used to decide whether the midjourney_poll system task needs to run; when no task is pending the scheduler skips creating a row entirely.

func HasUnfinishedSyncTasks

func HasUnfinishedSyncTasks() bool

HasUnfinishedSyncTasks reports whether at least one async (Suno/video) task is still in progress. It is a cheap existence check (LIMIT 1) used to decide whether the async_task_poll system task needs to run; when no task is pending the scheduler skips creating a row entirely.

func HasVersionedCodexQuotaEvidence

func HasVersionedCodexQuotaEvidence(ctx context.Context, db *gorm.DB) (bool, error)

HasVersionedCodexQuotaEvidence prevents a missing deployment keyring from turning unreadable confirmed account evidence into an empty legacy lookup.

func HashTaskSubmissionIdempotencyKey

func HashTaskSubmissionIdempotencyKey(rawKey string) (string, error)

HashTaskSubmissionIdempotencyKey produces the only representation of a client key that may be persisted. The deployment secret prevents low-entropy client keys from becoming an offline lookup table if the database is copied.

func HydrateTokenQuotaCache

func HydrateTokenQuotaCache(key string, id int, remainQuota, usedQuota int, quotaVersion int64) error

HydrateTokenQuotaCache updates an existing token projection with epoch and QuotaVersion anti-rollback. Cache misses are intentionally not materialized.

func HydrateUserQuotaCache

func HydrateUserQuotaCache(userId int, quota int, quotaVersion int64) error

HydrateUserQuotaCache updates user quota projection in Redis with version anti-rollback. If the cache key does not exist or has an older schema, it does nothing (allowing GetUserCache to hydrate cleanly). If incoming QuotaVersion is older than cached, it rejects/drops to prevent version rollback.

func IncreaseTokenQuota

func IncreaseTokenQuota(tokenId int, key string, quota int) (err error)

func IncreaseTokenQuotaWithContext

func IncreaseTokenQuotaWithContext(input QuotaMutationContext, tokenID int, key string, quota int) error

func IncreaseUserQuota

func IncreaseUserQuota(id int, quota int, db bool) (err error)

func IncreaseUserQuotaWithContext

func IncreaseUserQuotaWithContext(input QuotaMutationContext, id int, quota int) error

func IncrementUserAuthVersionWithTx

func IncrementUserAuthVersionWithTx(tx *gorm.DB, userId int) (int64, error)

IncrementUserAuthVersionWithTx locks the user, publishes the next deny fence, then persists the version in the caller's transaction. Unscoped is intentional so the same fail-closed path also covers hard deletion of an already soft-deleted user.

func InitBatchUpdater

func InitBatchUpdater()

func InitChannelCache

func InitChannelCache() error

func InitColumnNamesForTest

func InitColumnNamesForTest()

InitColumnNamesForTest initializes the dialect-aware column identifiers for test fixtures that swap model.DB without running InitDB/InitLogDB. It only re-runs initCol and is a no-op for already-initialized processes.

func InitDB

func InitDB() (err error)

func InitLogDB

func InitLogDB() (err error)

func InitOptionMap

func InitOptionMap()

func InitializeAccountQuotaReservationHeadsWithDB

func InitializeAccountQuotaReservationHeadsWithDB(db *gorm.DB) error

InitializeAccountQuotaReservationHeadsWithDB backfills receipt fingerprints, reservation heads, and lifecycle obligations in bounded keyset pages.

func InitializeExternalIdentityClaims

func InitializeExternalIdentityClaims() error

InitializeExternalIdentityClaims imports legacy Telegram bindings after the claim table is migrated. Existing duplicate ownership fails migration rather than preserving an ambiguous login identity.

func InitializeQuotaBalanceBatchDrainsWithDB

func InitializeQuotaBalanceBatchDrainsWithDB(db *gorm.DB) error

func InitializeQuotaProjectionObligationsWithDB

func InitializeQuotaProjectionObligationsWithDB(db *gorm.DB) error

InitializeQuotaProjectionObligationsWithDB safely initializes fields added by schema version 2. It does not claim, apply, or requeue any obligation.

func InitializeUserAuthVersions

func InitializeUserAuthVersions() error

InitializeUserAuthVersions must run after AutoMigrate when upgrading an existing database. It is idempotent and portable across all supported DBs.

func InsertChannelWithAbilities

func InsertChannelWithAbilities(ctx context.Context, channel *Channel) error

InsertChannelWithAbilities creates a single channel and its routing abilities in one transaction. Validation remains the controller's responsibility.

func InspectAccountQuotaRecovery

func InspectAccountQuotaRecovery(db *gorm.DB, requestID string) (*AccountQuotaMutationReceipt, *AccountQuotaMutationReceipt, error)

InspectAccountQuotaRecovery is read-only. It never infers an upstream result.

func InvalidatePricingCache

func InvalidatePricingCache()

func InvalidateSubscriptionPlanCache

func InvalidateSubscriptionPlanCache(planId int)

func InvalidateTokenQuotaCache

func InvalidateTokenQuotaCache(key string) error

InvalidateTokenQuotaCache invalidates the token cache for mutation

func InvalidateUserQuotaCache

func InvalidateUserQuotaCache(userId int) error

InvalidateUserQuotaCache clears user cache

func InvalidateUserTokensCache

func InvalidateUserTokensCache(userId int) error

InvalidateUserTokensCache 清理指定用户所有令牌在 Redis 中的缓存, 配合 InvalidateUserCache 使用,可在用户被禁用/删除时立即阻断其令牌的请求。 下一次请求将从数据库重新加载令牌及用户状态,从而立即识别出被禁用的用户。

func IsAdmin

func IsAdmin(userId int) bool

func IsBasicModelRouteChannel

func IsBasicModelRouteChannel(channelType int) bool

func IsChannelCacheRefreshError

func IsChannelCacheRefreshError(err error) bool

func IsChannelEnabledForAnyGroupModel

func IsChannelEnabledForAnyGroupModel(groups []string, modelName string, channelID int) bool

func IsChannelEnabledForGroupModel

func IsChannelEnabledForGroupModel(group string, modelName string, channelID int) bool

func IsDiscordIdAlreadyTaken

func IsDiscordIdAlreadyTaken(discordId string) bool

func IsEmailAlreadyTaken

func IsEmailAlreadyTaken(email string) bool

func IsEmailAvailable

func IsEmailAvailable(email string, excludeUserID int) (bool, error)

func IsGitHubIdAlreadyTaken

func IsGitHubIdAlreadyTaken(githubId string) bool

func IsLinuxDOIdAlreadyTaken

func IsLinuxDOIdAlreadyTaken(linuxDOId string) bool

func IsLogProjectionBackfillTerminal

func IsLogProjectionBackfillTerminal(state *LogProjectionBackfillState) bool

func IsModelNameDuplicated

func IsModelNameDuplicated(id int, name string) (bool, error)

func IsOidcIdAlreadyTaken

func IsOidcIdAlreadyTaken(oidcId string) bool

func IsPaymentFundingOptionKey

func IsPaymentFundingOptionKey(key string) bool

func IsPrefillGroupNameDuplicated

func IsPrefillGroupNameDuplicated(id int, name string) (bool, error)

IsPrefillGroupNameDuplicated 检查组名称是否重复(排除自身 ID)

func IsProviderUserIdTaken

func IsProviderUserIdTaken(providerId int, providerUserId string) bool

IsProviderUserIdTaken checks if a provider user ID is already bound to any user

func IsSlugTaken

func IsSlugTaken(slug string, excludeId int) bool

IsSlugTaken checks if a slug is already taken by another provider Returns true on DB errors (fail-closed) to prevent slug conflicts

func IsTelegramIdAlreadyTaken

func IsTelegramIdAlreadyTaken(telegramId string) bool

func IsTwoFAEnabled

func IsTwoFAEnabled(userId int) (bool, error)

IsTwoFAEnabled 检查用户是否启用了2FA

func IsVendorNameDuplicated

func IsVendorNameDuplicated(id int, name string) (bool, error)

IsVendorNameDuplicated 检查供应商名称是否重复(排除自身 ID)

func IsWeChatIdAlreadyTaken

func IsWeChatIdAlreadyTaken(wechatId string) bool

func LegacyUsageNeedsReview

func LegacyUsageNeedsReview(ctx context.Context, db *gorm.DB, tokenID int) (bool, error)

func LogQuotaData

func LogQuotaData(params QuotaDataLogParams)

func ManualCompleteTopUp

func ManualCompleteTopUp(tradeNo string, callerIp string) error

ManualCompleteTopUp 管理员手动完成订单并给用户充值

func MarkChannelQuotaAlertDelivered

func MarkChannelQuotaAlertDelivered(ctx context.Context, event ChannelQuotaAlertEvent, workerID string, deliveredAt int64) (bool, error)

MarkChannelQuotaAlertDelivered completes a claim and records the actual delivery time. The event remains immutable; only delivery bookkeeping moves.

func MarkChannelQuotaAlertFailed

func MarkChannelQuotaAlertFailed(ctx context.Context, event ChannelQuotaAlertEvent, workerID, errorCode string, failedAt int64) (bool, error)

MarkChannelQuotaAlertFailed ends a claim. Failures use bounded exponential retry; terminal failures stay auditable in quarantined state.

func MarkChannelQuotaSamplingTargetAttempt

func MarkChannelQuotaSamplingTargetAttempt(ctx context.Context, db *gorm.DB, channelID int, subjectRef, result, confirmedSubjectRef string) error

func MarkSystemTaskLeaseExpired

func MarkSystemTaskLeaseExpired(taskID string) error

func MarkTaskPollingManual

func MarkTaskPollingManual(db *gorm.DB, task *Task, reasonCode string, now int64) (bool, error)

func MarkTaskPollingRetryable

func MarkTaskPollingRetryable(db *gorm.DB, task *Task, reasonCode string, now int64) (bool, error)

MarkTaskPollingRetryable records local uncertainty without changing the task lifecycle status. The attempt-count predicate prevents concurrent pollers from extending the backoff twice from the same snapshot.

func MarkTaskTerminalObservationManualReview

func MarkTaskTerminalObservationManualReview(db *gorm.DB, observationID, expectedVersion int64) error

func MarkTaskTerminalObservationRetryable

func MarkTaskTerminalObservationRetryable(db *gorm.DB, observationID, expectedVersion int64, retryDelaySeconds int64) error

func MaskTokenKey

func MaskTokenKey(key string) string

func MigrateAccessProfileIdentifiers

func MigrateAccessProfileIdentifiers() error

MigrateAccessProfileIdentifiers only fills missing identities. Non-empty values, including an explicit standard ID for a legacy vip group, survive every restart. This migration does not change the legacy routing contract.

func MigrateRetiredFrontendOptions

func MigrateRetiredFrontendOptions() error

MigrateRetiredFrontendOptions normalizes options that belonged to the removed dashboard frontend. Each legacy console setting is migrated in its own transaction so one malformed value cannot block the other settings.

func MjBulkUpdate

func MjBulkUpdate(mjIds []string, params map[string]any) error

func MjBulkUpdateByTaskIds

func MjBulkUpdateByTaskIds(taskIDs []int, params map[string]any) error

func NormalizeChannelGroupFilter

func NormalizeChannelGroupFilter(group string) string

func NormalizeChannelOperationKey

func NormalizeChannelOperationKey(key string) (string, error)

func NormalizeEmail

func NormalizeEmail(email string) string

func NormalizeFeeBudgetUSD

func NormalizeFeeBudgetUSD(value string) (string, error)

Amounts remain decimal strings across SQL and JSON. Never round each request to cents, convert through quota/float64, or depend on global division precision. A bounded encoding also prevents attacker-controlled decimal exponents.

func NormalizeResetPeriod

func NormalizeResetPeriod(period string) string

func OptionRemediationHashForPreview

func OptionRemediationHashForPreview(value string) string

OptionRemediationHashForPreview hashes a runtime value for the dry-run conflict preview. The hash is metadata; the value never leaves the caller.

func OptionRemediationKnownActions

func OptionRemediationKnownActions() []string

OptionRemediationKnownActions exposes the closed action allow-list for request validation in the service layer.

func PerfMetricStartTime

func PerfMetricStartTime(hours int) int64

func PingDB

func PingDB() error

func PlanOptionRemediations

func PlanOptionRemediations(keys []string, includeAll bool, actionFilter map[string]bool) ([]OptionRemediationPlan, OptionRemediationCoverage, error)

PlanOptionRemediations builds the dry-run plan. With includeAll it reuses the bounded diagnostics snapshot; otherwise it reads each requested key through the same bounded per-key projection. It performs no writes of any kind and never touches OptionMap or a runtime generation.

func PostConsumeUserSubscriptionDelta

func PostConsumeUserSubscriptionDelta(userSubscriptionId int, delta int64) error

Update subscription used amount by delta (positive consume more, negative refund).

func PrepareLogProjectionIdentity

func PrepareLogProjectionIdentity(log *Log) error

func PricingRuntimeReady

func PricingRuntimeReady() bool

PricingRuntimeReady reports whether this process has a complete local price generation. A successful full options reload clears a publication fault; an unrelated single-key write must not clear it.

func ProjectQuotaMutationReceipt

func ProjectQuotaMutationReceipt(ctx context.Context, db *gorm.DB, receipt quotaProjectionReceipt) error

ProjectQuotaMutationReceipt is post-commit only. Projection failure never changes the acknowledged main-ledger result.

func ProjectUsageReviewDecision

func ProjectUsageReviewDecision(ctx context.Context, db, logDB *gorm.DB, decisionID int64) error

ProjectUsageReviewDecision applies counters exactly once on the primary DB, then projects a stable event to the log DB. The existing log canonicalization deduplicates repeated deliveries after a lost cross-database acknowledgement.

func PublishSetupFundingOptions

func PublishSetupFundingOptions(
	selfUseModeEnabled bool,
	demoSiteEnabled bool,
	state UserFundingStateSnapshot,
) error

func PublishUserAuthCache

func PublishUserAuthCache(userId int) error

PublishUserAuthCache refreshes the current database state after a successful auth-sensitive transaction without touching the cached quota field.

func PublishUserFundingState

func PublishUserFundingState(state UserFundingStateSnapshot) error

func PurchaseSubscriptionWithBalance

func PurchaseSubscriptionWithBalance(userId int, planId int, expectedEpoch ...uint64) error

PurchaseSubscriptionWithBalance creates a subscription by deducting the user's wallet quota. 模式分发:legacy 保持迁移前直写;authoritative 经 receipt 内核扣减, 事件键 "subscription-wallet:{tradeNo}" 与订单行同事务提交;bridge fail-closed。

func QuarantineBillingProjectionEvent

func QuarantineBillingProjectionEvent(ctx context.Context, db *gorm.DB, eventID string, reason string) error

func QuotaDataBucketStart

func QuotaDataBucketStart(
	timestamp int64,
	granularity QuotaDataGranularity,
	timezoneOffsetMinutes int,
) int64

QuotaDataBucketStart returns the UTC timestamp of the bucket boundary for a fixed timezone offset. The offset uses the same convention as the dashboard API: minutes east of UTC (for example, Asia/Shanghai is +480).

func QuotaMaintenanceBackfillsComplete

func QuotaMaintenanceBackfillsComplete(ctx context.Context, db *gorm.DB) (bool, error)

QuotaMaintenanceBackfillsComplete is the admission gate for authoritative account writes. The durable cursor is part of the state, not merely a progress hint: a cursor that has not reached a terminal complete state keeps the gate closed even when the current row-shape probes happen to find no work. This prevents a partially migrated v1 chain from being replayed by the authoritative writer.

func QuotaProjectionObligationRecoveryEnabled

func QuotaProjectionObligationRecoveryEnabled() bool

func QuotaWriterInflightSessions

func QuotaWriterInflightSessions() int64

func ReadDatabaseUnixTime

func ReadDatabaseUnixTime(ctx context.Context, db *gorm.DB) (int64, error)

ReadDatabaseUnixTime never substitutes a node clock when the database clock fails.

func RealtimeDispatchPending

func RealtimeDispatchPending(metadata string) (bool, error)

Only the server-recorded Realtime protocol permits segmented reservations while dispatch remains pending. HTTP and malformed evidence stay blocked.

func Recharge

func Recharge(referenceId string, customerId string, callerIp string, decision UserFundingWebhookDecision) error

func RechargeCreem

func RechargeCreem(referenceId string, customerEmail string, customerName string, callerIp string, decision UserFundingWebhookDecision, source ...CreemPaymentSource) error

func RechargeCreemTrusted

func RechargeCreemTrusted(referenceId string, customerEmail string, customerName string, callerIp string) error

func RechargeEpay

func RechargeEpay(tradeNo string, actualPaymentMethod string, callerIp string, decision UserFundingWebhookDecision) (bool, error)

func RechargeEpayTrusted

func RechargeEpayTrusted(tradeNo string, actualPaymentMethod string, callerIp string) (bool, error)

func RechargeTrusted

func RechargeTrusted(referenceId string, customerId string, callerIp string) error

func RechargeWaffo

func RechargeWaffo(tradeNo string, callerIp string, decision UserFundingWebhookDecision) error

func RechargeWaffoPancake

func RechargeWaffoPancake(tradeNo string, decision UserFundingWebhookDecision, source ...WaffoPancakePaymentSource) error

func RechargeWaffoPancakeTrusted

func RechargeWaffoPancakeTrusted(tradeNo string) error

func RechargeWaffoTrusted

func RechargeWaffoTrusted(tradeNo string, callerIp string) error

func ReclaimExpiredTaskBillingEvent

func ReclaimExpiredTaskBillingEvent(tx *gorm.DB, eventID int64, lease TaskRecoveryProcessingLease, expectedVersion, checkedAt int64) (bool, error)

func ReclaimExpiredTaskBillingLogOutbox

func ReclaimExpiredTaskBillingLogOutbox(tx *gorm.DB, outboxID int64, lease TaskRecoveryProcessingLease, expectedVersion, checkedAt int64) (bool, error)

func RecomputeAccountQuotaReceiptFingerprint

func RecomputeAccountQuotaReceiptFingerprint(receipt *AccountQuotaMutationReceipt) (string, error)

RecomputeAccountQuotaReceiptFingerprint verifies that a stored receipt has all durable inputs required to reproduce its request identity.

func RecordChannelQuotaSnapshot

func RecordChannelQuotaSnapshot(snapshot *ChannelQuotaSnapshot) error

RecordChannelQuotaSnapshot appends a normalized quota observation. It is safe to call when the database has not been initialized (for example in lightweight controller tests).

func RecordChannelQuotaSnapshotBatchWithContext

func RecordChannelQuotaSnapshotBatchWithContext(ctx context.Context, snapshots []ChannelQuotaSnapshot, options ChannelQuotaSnapshotBatchOptions) error

RecordChannelQuotaSnapshotBatchWithContext atomically reads the previous successful sample, derives absence markers, and writes the complete immutable sample. A replay with the same sample id is accepted only when its provider rows are byte-for-byte equivalent at the normalized field level.

func RecordChannelQuotaSnapshotWithContext

func RecordChannelQuotaSnapshotWithContext(ctx context.Context, snapshot *ChannelQuotaSnapshot) error

RecordChannelQuotaSnapshotWithContext bounds both deduplication queries and insertion, including time spent waiting for an available database connection.

func RecordConsumeLog

func RecordConsumeLog(c *gin.Context, userId int, params RecordConsumeLogParams)

func RecordErrorLog

func RecordErrorLog(c *gin.Context, userId int, channelId int, modelName string, tokenName string, content string, tokenId int, useTimeSeconds int,
	isStream bool, group string, other map[string]interface{})

func RecordExist

func RecordExist(err error) (bool, error)

func RecordLog

func RecordLog(userId int, logType int, content string)

func RecordLogWithAdminInfo

func RecordLogWithAdminInfo(userId int, logType int, content string, adminInfo map[string]interface{})

RecordLogWithAdminInfo 记录操作日志,并将管理员相关信息存入 Other.admin_info,

func RecordLoginLog

func RecordLoginLog(userId int, username string, content string, ip string, action string, params map[string]interface{}, extra map[string]interface{})

RecordLoginLog 记录用户登录成功的审计日志(type=LogTypeLogin)。 username 由调用方传入(登录流程已持有用户对象),避免额外的数据库查询。 content 为英文兜底文本(用于导出);action+params 供前端本地化渲染。 extra 可携带 login_method、user_agent 等附加信息(普通用户可见)。

func RecordOperationAuditLog

func RecordOperationAuditLog(logUserId int, content string, ip string, action string, params map[string]interface{}, adminInfo map[string]interface{}, auditInfo map[string]interface{})

RecordOperationAuditLog 记录管理/高危操作审计日志(type=LogTypeManage)。 logUserId 为日志归属者,管理审计日志应归属实际操作者;目标资源/用户放入 action params。username 内部按 logUserId 查询。content 为英文兜底文本(供导出使用)。 action+params 写入 Other.op,供前端本地化渲染(普通用户可见,不含敏感信息)。 adminInfo 存放操作者身份(写入 Other.admin_info,普通用户查询时剥离); auditInfo 存放路由/方法/结果等中间件兜底信息(写入 Other.audit_info,普通用户查询时剥离)。

func RecordRealtimeUsageCheckpoint

func RecordRealtimeUsageCheckpoint(ctx context.Context, db *gorm.DB, requestID string, userID, tokenID int, reserveID int64, checkpoint hosttypes.RealtimeUsageCheckpoint) error

func RecordRelayAccountHold

func RecordRelayAccountHold(ctx context.Context, db *gorm.DB, selected *Channel, key, identity string, seconds int) (bool, error)

RecordRelayAccountHold serializes with channel edits and cannot shorten a newer hold. The selected raw credential is checked, never stored in this row.

func RecordTaskBillingLog

func RecordTaskBillingLog(params RecordTaskBillingLogParams)

func RecordTopupLog

func RecordTopupLog(userId int, content string, callerIp string, paymentMethod string, callbackPaymentMethod string)

func RecoverAccountQuotaSettlementIntent

func RecoverAccountQuotaSettlementIntent(ctx context.Context, db *gorm.DB, intent *AccountQuotaSettlementIntent, workerID string) (*AccountQuotaSettlementIntent, *AccountQuotaSettlementFact, error)

RecoverAccountQuotaSettlementIntent materializes and applies one durable inbox row. Repeated or concurrent scans converge through fact and receipt fingerprints rather than through task payload ordering.

func RecoverExpiredPromptLearningRuns

func RecoverExpiredPromptLearningRuns(ctx context.Context, now int64, limit int) (int64, error)

RecoverExpiredPromptLearningRuns only requeues work before submission. The absence of an upstream receipt in leased/preparing states makes it safe to retry; submitted work remains an explicit unknown/outcome workflow.

func Redeem

func Redeem(key string, userId int, expectedEpoch ...uint64) (quota int, err error)

func RefreshAccountQuotaSettlementIntentSchemaCapability

func RefreshAccountQuotaSettlementIntentSchemaCapability(db *gorm.DB) bool

func RefreshPricing

func RefreshPricing()

RefreshPricing 强制立即重新计算与定价相关的缓存。 该方法用于需要最新数据的内部管理 API, 因此会绕过默认的 1 分钟延迟刷新。

func RefreshUserGroupCache

func RefreshUserGroupCache(userId int) error

RefreshUserGroupCache writes the database-authoritative group into an existing user hash without changing the user's authentication version.

func RefreshUserQuotaBusinessSchemaCapability

func RefreshUserQuotaBusinessSchemaCapability(db *gorm.DB) error

func RefundSubscriptionPreConsume

func RefundSubscriptionPreConsume(requestId string) error

RefundSubscriptionPreConsume is idempotent and refunds pre-consumed subscription quota by requestId.

func RelayChannelConfigDigest

func RelayChannelConfigDigest(channel *Channel) string

RelayChannelConfigDigest excludes operational counters, but includes every dispatch-affecting channel setting. A config replacement retires old holds.

func ReleaseExternalIdentityWithTx

func ReleaseExternalIdentityWithTx(tx *gorm.DB, provider string, userId int) error

func ReleaseNamedSystemTaskLockWithContext

func ReleaseNamedSystemTaskLockWithContext(ctx context.Context, lockType string, taskID string, lockedBy string) error

ReleaseNamedSystemTaskLockWithContext releases only the exact named lease held by taskID and lockedBy. A lost/expired lease is an idempotent no-op.

func ReleaseSystemTaskLock

func ReleaseSystemTaskLock(taskID string, lockedBy string) error

func ReleaseSystemTaskLockWithContext

func ReleaseSystemTaskLockWithContext(ctx context.Context, taskID string, lockedBy string) error

func RenewSystemTaskLock

func RenewSystemTaskLock(taskID string, lockedBy string, lockUntil int64) error

func RenewSystemTaskLockWithContext

func RenewSystemTaskLockWithContext(ctx context.Context, taskID string, lockedBy string, lockUntil int64) error

func RenewSystemTaskLockWithFence

func RenewSystemTaskLockWithFence(ctx context.Context, taskID string, lockedBy string, fenceToken int64, lockUntil int64) error

func ReplaceBackupCodesWithAuthVersion

func ReplaceBackupCodesWithAuthVersion(userId int, codes []string) error

ReplaceBackupCodesWithAuthVersion atomically replaces the factor's recovery credentials and advances the user's authentication version.

func ReserveTokenBudget

func ReserveTokenBudget(ctx context.Context, db *gorm.DB, input TokenBudgetReservation) error

ReserveTokenBudget accepts only server-verified, frozen request bounds. It cannot be exposed directly as an HTTP endpoint accepting client estimates.

func ResetDueSubscriptions

func ResetDueSubscriptions(limit int) (int, error)

ResetDueSubscriptions resets subscriptions whose next_reset_time has passed.

func ResetUserPasswordByEmail

func ResetUserPasswordByEmail(email string, password string) error

func ResolveSelfUseNoBalanceAdmission

func ResolveSelfUseNoBalanceAdmission(ctx context.Context, db *gorm.DB, userID int) (bool, error)

func RevokeAllUserSessions

func RevokeAllUserSessions(userID int, reason string) (int64, error)

func RevokeOtherUserSessions

func RevokeOtherUserSessions(userID int, currentSID, reason string) (int64, error)

func RevokeUserSession

func RevokeUserSession(userID int, sid, reason string) (bool, error)

func RevokeUserSessionByRefreshHash

func RevokeUserSessionByRefreshHash(sid, presentedHash, reason string) (bool, error)

RevokeUserSessionByRefreshHash is used when logout is authenticated only by the HttpOnly refresh cookie. Possession of a SID alone is insufficient. The immediately previous digest is accepted only inside the refresh race window.

func RootUserExists

func RootUserExists() bool

func RunAccountQuotaRefundFacts

func RunAccountQuotaRefundFacts(ctx context.Context, db *gorm.DB, workerID string, limit int) (int, error)

func RunAccountQuotaSettlementFacts

func RunAccountQuotaSettlementFacts(ctx context.Context, db *gorm.DB, workerID string, limit int) (int, error)

func RunAccountQuotaSettlementIntents

func RunAccountQuotaSettlementIntents(ctx context.Context, db *gorm.DB, workerID string, limit int) (int, error)

func RunAccountQuotaTerminalRecoveryObligations

func RunAccountQuotaTerminalRecoveryObligations(ctx context.Context, db *gorm.DB, workerID string, limit int) (int, error)

func RunQuotaProjectionObligations

func RunQuotaProjectionObligations(ctx context.Context, db *gorm.DB, workerID string, limit int) (int, error)

RunQuotaProjectionObligations replays due persisted obligations. The existing distributed task-recovery obligation gate defaults off.

func RunUsageReviewProjections

func RunUsageReviewProjections(ctx context.Context, db, logDB *gorm.DB, limit int) (int, error)

func SaveLastSuccessfulChannelTestOptions

func SaveLastSuccessfulChannelTestOptions(channelID int, options ChannelTestOptions) error

func SaveLogProjectionBackfillStateFenced

func SaveLogProjectionBackfillStateFenced(ctx context.Context, mainDB *gorm.DB, state *LogProjectionBackfillState, taskID string, runnerID string, fenceToken int64, expectedVersion int64) error

func SaveQuotaDataCache

func SaveQuotaDataCache()

func SearchTags

func SearchTags(keyword string, group string, model string, idSort bool) ([]*string, error)

func SelectChannelFromRoutingPolicy

func SelectChannelFromRoutingPolicy(policy ChannelRoutingPolicy, retry int) (int, bool, error)

SelectChannelFromRoutingPolicy selects from the retry's fallback tier using the same policy for both cache-backed and database-backed routing.

func SetLogProjectionMaintenanceRequired

func SetLogProjectionMaintenanceRequired(ctx context.Context, mainDB *gorm.DB, logDB *gorm.DB, reason string) error

func SetRealtimeDispatchEvidence

func SetRealtimeDispatchEvidence(ctx context.Context, db *gorm.DB, requestID string, userID, tokenID int, reserveID int64, pricing string) error

Realtime never clears its pending marker to extend a reservation. Only a confirmed settlement or the existing authorized review closes its lifecycle.

func SetTextDispatchEvidence

func SetTextDispatchEvidence(ctx context.Context, db *gorm.DB, requestID string, userID, tokenID int, reserveID int64, pricing string, pending bool) error

SetTextDispatchEvidence records an attempt before the network call, or clears it only after a known raw refusal. It changes no balance or actual usage. Existing writer rows and locks serialize it against terminal mutations.

func SetUserAuthVersionFence

func SetUserAuthVersionFence(userId int, authVersion int64) error

SetUserAuthVersionFence publishes a fail-closed version before a restrictive database update. Pending fences expire only after every pre-existing user hash must have expired; a committed update is promoted separately to a permanent monotonic version floor.

func StartClickHouseCanonicalProjectionMaterialize

func StartClickHouseCanonicalProjectionMaterialize(ctx context.Context, db *gorm.DB) error

func StartTaskSubmissionDispatch

func StartTaskSubmissionDispatch(tx *gorm.DB, operationID int64, transition TaskSubmissionDispatchTransition) (bool, error)

StartTaskSubmissionDispatch atomically starts the single v1 dispatch. The generic operation and attempt transition APIs intentionally reject a move to dispatching so callers cannot split this critical transition across writes.

func SumUsedToken

func SumUsedToken(logType int, startTimestamp int64, endTimestamp int64, modelName string, username string, tokenName string) (token int)

func SyncChannelCache

func SyncChannelCache(frequency int)

func SyncOptions

func SyncOptions(frequency int)

func TaskBulkUpdateByID

func TaskBulkUpdateByID(ids []int64, params map[string]any) error

TaskBulkUpdateByID performs an unconditional bulk UPDATE by primary key IDs. WARNING: This function has NO CAS (Compare-And-Swap) guard — it will overwrite any concurrent status changes. DO NOT use in billing/quota lifecycle flows (e.g., timeout, success, failure transitions that trigger refunds or settlements). For status transitions that involve billing, use Task.UpdateWithStatus() instead.

func TaskCountAllTasks

func TaskCountAllTasks(queryParams SyncTaskQueryParams) int64

TaskCountAllTasks returns total tasks that match the given query params (admin usage)

func TaskCountAllUserTask

func TaskCountAllUserTask(userId int, queryParams SyncTaskQueryParams) int64

TaskCountAllUserTask returns total tasks for given user

func TaskPollingBackoff

func TaskPollingBackoff(attempt int) time.Duration

func TextDispatchPending

func TextDispatchPending(metadata string) (bool, error)

TextDispatchPending is durable uncertainty, not evidence of consumption. Malformed evidence fails closed; old empty metadata remains compatible.

func TrackQuotaWriterInflightFinish

func TrackQuotaWriterInflightFinish()

func TrackQuotaWriterInflightStart

func TrackQuotaWriterInflightStart()

func TransitionPromptInstructionApplication

func TransitionPromptInstructionApplication(ctx context.Context, applicationID, expectedLockVersion int64, targetState, backupReceipt, appliedContentHash string) (bool, error)

TransitionPromptInstructionApplication advances one recorded application using an optimistic lock. Only the future authorized executor can supply a backup/content receipt, and terminal outcomes never return to pending.

func TransitionPromptLearningRun

func TransitionPromptLearningRun(ctx context.Context, userID int, scopeRef string, runID, expectedFence int64, targetState string) (bool, error)

TransitionPromptLearningRun advances a fenced lease through the analysis state machine. It intentionally has no model or billing integration: a future executor may only call it around an already-authorized relay request.

func TransitionTaskBillingEvent

func TransitionTaskBillingEvent(tx *gorm.DB, eventID int64, transition TaskBillingEventTransition) (bool, error)

func TransitionTaskBillingLogOutbox

func TransitionTaskBillingLogOutbox(tx *gorm.DB, outboxID int64, transition TaskBillingLogOutboxTransition) (bool, error)

func TransitionTaskSubmissionAttempt

func TransitionTaskSubmissionAttempt(tx *gorm.DB, attemptID int64, transition TaskSubmissionAttemptTransition) (bool, error)

func TransitionTaskSubmissionOperation

func TransitionTaskSubmissionOperation(tx *gorm.DB, operationID int64, transition TaskSubmissionOperationTransition) (bool, error)

TransitionTaskSubmissionOperation applies one permitted transition with a status CAS. An accepted transition requires an already-created formal Task whose public TaskID equals the operation PublicID; this API never creates a placeholder task.

func TryAcquireNamedSystemTaskLockWithContext

func TryAcquireNamedSystemTaskLockWithContext(ctx context.Context, lockType string, taskID string, lockedBy string, lockUntil int64) (bool, error)

TryAcquireNamedSystemTaskLockWithContext attempts to acquire a reusable lease identified by lockType. It does not create a SystemTask row, making it suitable for short cross-instance coordination that reuses the migrated system_task_locks table.

func TryReserveTokenQuota

func TryReserveTokenQuota(id int, key string, quota int, unlimited bool) (bool, error)

func TryReserveTokenQuotaWithContext

func TryReserveTokenQuotaWithContext(input QuotaMutationContext, tokenID int, key string, quota int, unlimited bool) (bool, error)

func TryReserveUserQuota

func TryReserveUserQuota(id int, quota int) (bool, error)

func TryReserveUserQuotaWithContext

func TryReserveUserQuotaWithContext(input QuotaMutationContext, id int, quota int) (bool, error)

func UpdateAbilityByTag

func UpdateAbilityByTag(tag string, newTag *string, priority *int64, weight *uint) error

func UpdateAbilityStatus

func UpdateAbilityStatus(channelId int, status bool) error

func UpdateAbilityStatusByTag

func UpdateAbilityStatusByTag(tag string, status bool) error

func UpdateChannelCredentialElementIfUnchanged

func UpdateChannelCredentialElementIfUnchanged(ctx context.Context, channelID, channelType int, expected, replacement string) (bool, error)

UpdateChannelCredentialElementIfUnchanged replaces exactly one credential in a multi-key JSON array or newline list. The whole persisted field remains the database CAS authority; edits between its read and write lose safely.

func UpdateChannelCredentialIfUnchanged

func UpdateChannelCredentialIfUnchanged(ctx context.Context, channelID int, channelType int, expectedKey string, newKey string) (bool, error)

UpdateChannelCredentialIfUnchanged atomically replaces a channel credential only if it still matches the caller's snapshot. All in-process writers use the per-channel gate, while the database predicate remains the authority for writers in other processes. A successful write synchronously publishes the new key and advances the cache generation before releasing the gate.

func UpdateChannelStatus

func UpdateChannelStatus(channelId int, usingKey string, status int, reason string) bool

func UpdateChannelStatusWithError

func UpdateChannelStatusWithError(channelId int, usingKey string, status int, reason string) (bool, error)

func UpdateChannelStatusesWithError

func UpdateChannelStatusesWithError(channelIDs []int, status int, reason string) (int, error)

func UpdateChannelUsedQuota

func UpdateChannelUsedQuota(id int, quota int)

func UpdateCustomOAuthProvider

func UpdateCustomOAuthProvider(provider *CustomOAuthProvider) error

UpdateCustomOAuthProvider updates an existing custom OAuth provider

func UpdateLegacyUsageReservation

func UpdateLegacyUsageReservation(ctx context.Context, db *gorm.DB, requestID string, reserved, tokenReserved int64, state, reason string, actual *int64, metadata ...string) error

UpdateLegacyUsageReservation uses the same session's current reservation totals. It never performs a quota mutation or manufactures an actual amount.

func UpdateOption

func UpdateOption(key string, value string) error

func UpdateOptionsBulk

func UpdateOptionsBulk(values map[string]string) error

UpdateOptionsBulk persists multiple key/value pairs in a single database transaction, then dispatches them through updateOptionMap in one pass. If any DB write fails the whole transaction rolls back and no in-memory state is touched — safe for callers that must commit a set of related options atomically (e.g. payment gateway binding).

func UpdateOptionsTypedBulk

func UpdateOptionsTypedBulk(items []TypedBulkOption, expectedRevision *int64) (int64, []string, error)

UpdateOptionsTypedBulk is the typed bulk single writer: full normalize + validate (any failure writes nothing), one database transaction guarded by optionMutationLock with the expected-revision CAS check, then one runtime publication per family after the commit.

Publication abort semantics: if a family publication fails after the database commit, the whole group aborts, the failure is recorded through SysError, the failed family and every later family keep their previous runtime generation and OptionMap values, and ErrTypedBulkPublishFailed is returned. Families published before the failure keep their new generation; this post-commit boundary matches the payment funding bulk contract and is never presented as a cross-family atomic runtime commit.

func UpdatePasskeyAssertionState

func UpdatePasskeyAssertionState(userID int, credential *webauthn.Credential, lastUsedAt time.Time) error

UpdatePasskeyAssertionState persists only fields produced by a successful assertion. Registration identity (credential ID, public key, AAGUID, transports and attestation metadata) is immutable on this path.

func UpdatePendingTopUpStatus

func UpdatePendingTopUpStatus(tradeNo string, expectedPaymentProvider string, targetStatus string, decision UserFundingWebhookDecision) error

func UpdatePendingTopUpStatusTrusted

func UpdatePendingTopUpStatusTrusted(tradeNo string, expectedPaymentProvider string, targetStatus string) error

func UpdateProgress

func UpdateProgress(id int, progress string) error

func UpdateQuotaData

func UpdateQuotaData()

func UpdateSystemTaskState

func UpdateSystemTaskState(taskID string, lockedBy string, state any) error

func UpdateSystemTaskStateWithContext

func UpdateSystemTaskStateWithContext(ctx context.Context, taskID string, lockedBy string, state any) error

func UpdateUserAccessToken

func UpdateUserAccessToken(id int, token string) error

UpdateUserAccessToken rotates a dashboard personal access token without writing a stale user snapshot back over concurrently updated fields.

func UpdateUserBindColumn

func UpdateUserBindColumn(userId int, column string, value string) error

UpdateUserBindColumn 第三方账号绑定字段的专用更新。 绑定操作必须只写绑定列:若改为“读取完整用户 → 改一个字段 → 整体更新”, 读快照期间并发发生的封禁、降权或分组变更会被旧快照覆盖恢复。 角色、状态、分组只允许通过各自带锁/CAS 的专用方法修改。

func UpdateUserLastLoginAt

func UpdateUserLastLoginAt(id int)

func UpdateUserOAuthBinding

func UpdateUserOAuthBinding(userId, providerId int, newProviderUserId string) error

UpdateUserOAuthBinding updates an existing OAuth binding (e.g., rebind to different OAuth account)

func UpdateUserSetting

func UpdateUserSetting(userId int, setting dto.UserSetting) error

func UpdateUserUsedQuota

func UpdateUserUsedQuota(id int, quota int)

UpdateUserUsedQuota adjusts accumulated usage without changing request count.

func UpdateUserUsedQuotaAndRequestCount

func UpdateUserUsedQuotaAndRequestCount(id int, quota int)

func UpsertPasskeyCredentialWithAuthVersion

func UpsertPasskeyCredentialWithAuthVersion(credential *PasskeyCredential) error

UpsertPasskeyCredentialWithAuthVersion is reserved for enrollment changes; assertion sign-count updates must use UpdatePasskeyAssertionState.

func UpsertPerfMetric

func UpsertPerfMetric(metric *PerfMetric) error

func UpsertSystemInstance

func UpsertSystemInstance(nodeName string, info any, startedAt int64, lastSeenAt int64) error

func UserActiveSubscriptionsAllowWalletOverflow

func UserActiveSubscriptionsAllowWalletOverflow(userId int) (bool, error)

UserActiveSubscriptionsAllowWalletOverflow returns whether wallet balance may be used after the user's subscription quota is exhausted. A single active subscription that disallows wallet overflow (allow_wallet_overflow = false) blocks the fallback.

func ValidChannelQuotaAlertEventFilter

func ValidChannelQuotaAlertEventFilter(filter ChannelQuotaAlertEventFilter) bool

func ValidTaskSubmissionPublicID

func ValidTaskSubmissionPublicID(value string) bool

ValidTaskSubmissionPublicID reports whether value is a stable public task identifier. It performs no database lookup and does not disclose task ownership; protocol layers use it only to validate route-bound identifiers.

func ValidateBackupCode

func ValidateBackupCode(userId int, code string) (bool, error)

ValidateBackupCode 验证并使用备用码

func ValidateBillingProjectionCompatibility

func ValidateBillingProjectionCompatibility(candidate *Log, existing []*Log) error

func ValidateChannelModelRoutes

func ValidateChannelModelRoutes(channelType int, routes []dto.ModelRoute) error

func ValidateLogProjectionSchemaWithDB

func ValidateLogProjectionSchemaWithDB(db *gorm.DB) error

func ValidateOptionRemediationApplyItems

func ValidateOptionRemediationApplyItems(items []OptionRemediationApplyItem) error

ValidateOptionRemediationApplyItems enforces the fail-closed request shape before any database work: bounded item count, whitelisted actions, well-formed hashes, and whitelisted key families only.

func ValidateTokenBudgetSchema

func ValidateTokenBudgetSchema(db *gorm.DB) error

func ValidateTokenSnapshot

func ValidateTokenSnapshot(token *Token) error

ValidateTokenSnapshot applies the same status, expiry and quota admission to both credential lookups and a dashboard's directly loaded owned key. Callers must resolve identity and ownership before passing a snapshot here.

func ValidateTopUpQuotaCapacity

func ValidateTopUpQuotaCapacity(userId int, creditedQuota int) error

ValidateTopUpQuotaCapacity performs the user-facing pre-payment check. The settlement path repeats the same invariant with an atomic conditional update, because the wallet balance can change after checkout creation.

func ValidateUsageReviewSchema

func ValidateUsageReviewSchema(db *gorm.DB) error

func ValidateUserUsagePolicySchema

func ValidateUserUsagePolicySchema(db *gorm.DB) error

func WithChannelCredentialUpdateGate

func WithChannelCredentialUpdateGate(ctx context.Context, channelID int, fn func(context.Context) error) error

WithChannelCredentialUpdateGate serializes all in-process credential work for one channel. Waiting is canceled with ctx; the callback receives a marked context so nested UpdateChannelCredentialIfUnchanged calls reuse the same lease instead of deadlocking.

Types

type Ability

type Ability struct {
	Group     string  `json:"group" gorm:"type:varchar(64);primaryKey;autoIncrement:false"`
	Model     string  `json:"model" gorm:"type:varchar(255);primaryKey;autoIncrement:false"`
	ChannelId int     `json:"channel_id" gorm:"primaryKey;autoIncrement:false;index"`
	Enabled   bool    `json:"enabled"`
	Priority  *int64  `json:"priority" gorm:"bigint;default:0;index"`
	Weight    uint    `json:"weight" gorm:"default:0;index"`
	Tag       *string `json:"tag" gorm:"index"`
}

func GetAllEnableAbilities

func GetAllEnableAbilities() []Ability

type AbilityWithChannel

type AbilityWithChannel struct {
	Ability
	ChannelType int `json:"channel_type"`
}

func GetAllEnableAbilityWithChannels

func GetAllEnableAbilityWithChannels() ([]AbilityWithChannel, error)

type AccessProfileMetadata

type AccessProfileMetadata struct {
	ID               string   `json:"id"`
	Kind             string   `json:"kind"`
	Label            string   `json:"label"`
	Description      string   `json:"description"`
	RouteGroups      []string `json:"route_groups,omitempty"`
	ModelAllowlist   []string `json:"model_allowlist,omitempty"`
	FallbackProfiles []string `json:"fallback_profiles,omitempty"`
	Enabled          bool     `json:"enabled"`
	// Known records whether the stable ID exists in the current registry. It is
	// internal policy state and is intentionally omitted from API metadata.
	Known bool `json:"-"`
}

AccessProfileMetadata gives the legacy token group a stable domain meaning while retaining the legacy Token group and routing contract. The stable identifier is persisted additively; old clients and routing continue to use group until a future policy migration is explicitly approved.

func ResolveAccessProfile

func ResolveAccessProfile(groupName, configuredDescription string) AccessProfileMetadata

func ResolveAccessProfileID

func ResolveAccessProfileID(profileID, fallbackGroup, configuredDescription string) AccessProfileMetadata

ResolveAccessProfileID resolves an explicitly persisted profile identity. Stable built-in IDs are mapped through their legacy groups so configured labels and policy metadata remain consistent; unknown IDs remain readable as custom profiles during the compatibility period.

func ResolveAccessProfileIDWithSnapshot

func ResolveAccessProfileIDWithSnapshot(profileID, fallbackGroup, configuredDescription string, registry *setting.AccessProfileSetting) AccessProfileMetadata

ResolveAccessProfileIDWithSnapshot resolves an explicit stable identity without reading a second registry generation.

func ResolveAccessProfileWithSnapshot

func ResolveAccessProfileWithSnapshot(groupName, configuredDescription string, registry *setting.AccessProfileSetting) AccessProfileMetadata

ResolveAccessProfileWithSnapshot resolves a key policy against one detached registry generation. Callers that need to evaluate a tier and profile for a single request must pass the same snapshot to both resolvers.

type AccountBillingContext

type AccountBillingContext struct {
	Version           int               `json:"version"`
	ModelName         string            `json:"model_name"`
	OriginModelName   string            `json:"origin_model_name"`
	UsingGroup        string            `json:"using_group"`
	BillingPreference string            `json:"billing_preference"`
	ChannelID         int               `json:"channel_id"`
	ForcePreConsume   bool              `json:"force_pre_consume"`
	Playground        bool              `json:"playground"`
	FreeModel         bool              `json:"free_model"`
	Metadata          map[string]string `json:"metadata,omitempty"`
}

AccountBillingContext is the immutable pricing and routing context used for a synchronous relay reservation. It intentionally contains no credentials.

func (*AccountBillingContext) Scan

func (snapshot *AccountBillingContext) Scan(value interface{}) error

func (AccountBillingContext) Value

func (snapshot AccountBillingContext) Value() (driver.Value, error)

type AccountQuotaDeltas

type AccountQuotaDeltas struct {
	UserQuota              int64 `json:"user_quota"`
	TokenRemainQuota       int64 `json:"token_remain_quota"`
	TokenUsedQuota         int64 `json:"token_used_quota"`
	SubscriptionAmountUsed int64 `json:"subscription_amount_used"`
}

AccountQuotaDeltas records both the caller's requested mutation and the delta actually committed after trust/free handling and source selection.

func (*AccountQuotaDeltas) Scan

func (deltas *AccountQuotaDeltas) Scan(value interface{}) error

func (AccountQuotaDeltas) Value

func (deltas AccountQuotaDeltas) Value() (driver.Value, error)

type AccountQuotaMutationReceipt

type AccountQuotaMutationReceipt struct {
	ID                 int64                        `json:"id" gorm:"primaryKey"`
	ReceiptVersion     int                          `json:"receipt_version" gorm:"not null;<-:create"`
	FingerprintVersion int                          `json:"fingerprint_version" gorm:"not null;default:0;<-:create"`
	WriterEpoch        int64                        `json:"writer_epoch" gorm:"type:bigint;not null;<-:create"`
	RequestID          string                       `json:"request_id" gorm:"type:varchar(64);not null;index:idx_account_quota_request,priority:1;<-:create"`
	Phase              string                       `json:"phase" gorm:"type:varchar(16);not null;index:idx_account_quota_request,priority:2;<-:create"`
	EventKey           string                       `json:"event_key" gorm:"type:varchar(128);not null;uniqueIndex:uidx_account_quota_event;<-:create"`
	MutationSlot       string                       `json:"mutation_slot" gorm:"type:varchar(128);not null;uniqueIndex:uidx_account_quota_slot;<-:create"`
	ParentReceiptID    int64                        `json:"parent_receipt_id" gorm:"type:bigint;not null;default:0;index;<-:create"`
	AuditKey           string                       `json:"audit_key,omitempty" gorm:"type:varchar(96);not null;default:'';<-:create"`
	ReserveFingerprint string                       `json:"reserve_fingerprint" gorm:"type:char(64);not null;default:'';<-:create"`
	RequestFingerprint string                       `json:"request_fingerprint" gorm:"type:char(64);not null;<-:create"`
	BillingSource      string                       `json:"billing_source" gorm:"type:varchar(32);not null;<-:create"`
	BillingPreference  string                       `json:"billing_preference" gorm:"type:varchar(32);not null;<-:create"`
	UserID             int                          `json:"user_id" gorm:"not null;index;<-:create"`
	TokenID            int                          `json:"token_id" gorm:"not null;index;<-:create"`
	SubscriptionID     int                          `json:"subscription_id" gorm:"not null;default:0;index;<-:create"`
	RequestedQuota     int64                        `json:"requested_quota" gorm:"type:bigint;not null;<-:create"`
	AppliedQuota       int64                        `json:"applied_quota" gorm:"type:bigint;not null;<-:create"`
	RequestedDeltas    AccountQuotaDeltas           `json:"requested_deltas" gorm:"type:text;<-:create"`
	AppliedDeltas      AccountQuotaDeltas           `json:"applied_deltas" gorm:"type:text;<-:create"`
	Before             QuotaMutationAccountSnapshot `json:"before" gorm:"type:text;<-:create"`
	After              QuotaMutationAccountSnapshot `json:"after" gorm:"type:text;<-:create"`
	BillingContext     AccountBillingContext        `json:"billing_context" gorm:"type:text;<-:create"`
	CreatedAt          int64                        `json:"created_at" gorm:"type:bigint;not null;index;<-:create"`
}

AccountQuotaMutationReceipt is one immutable reserve or terminal receipt. MutationSlot is unique so settle and refund share one terminal slot.

func ExtendAccountQuotaReservation

func ExtendAccountQuotaReservation(ctx context.Context, db *gorm.DB, reserveReceiptID int64, targetQuota int64) (*AccountQuotaMutationReceipt, error)

ExtendAccountQuotaReservation raises an existing reservation to targetQuota. The returned receipt carries the new cumulative AppliedQuota while its AppliedDeltas contain only the additional atomic mutation.

func FindAccountQuotaReserveReceipt

func FindAccountQuotaReserveReceipt(db *gorm.DB, requestID string) (*AccountQuotaMutationReceipt, error)

func FindAccountQuotaTerminalReceipt

func FindAccountQuotaTerminalReceipt(db *gorm.DB, requestID string) (*AccountQuotaMutationReceipt, error)

func MutateTokenQuotaAuthoritative

func MutateTokenQuotaAuthoritative(ctx context.Context, db *gorm.DB, eventKey string, userID, tokenID int, tokenRemainDelta int64) (*AccountQuotaMutationReceipt, error)

MutateTokenQuotaAuthoritative applies one token remain/used delta with an immutable account receipt. tokenRemainDelta is mirrored to used quota.

func ResolveAccountQuotaUnknownUsage

func ResolveAccountQuotaUnknownUsage(ctx context.Context, db *gorm.DB, actorID int, input AccountQuotaTerminalInput, evidenceDigest string) (*AccountQuotaMutationReceipt, error)

ResolveAccountQuotaUnknownUsage settles a held authoritative reservation using explicitly reviewed evidence. ActualQuota is the existing internal quota unit, NOT tokens or USD. The caller must derive it from verified usage and the frozen request price. EvidenceDigest is an audit reference, not proof by itself. Root identity is checked against the primary database inside the transaction. The hold is never observably reopened: clearing it and creating the immutable terminal receipt either commit together or both roll back.

func (*AccountQuotaMutationReceipt) BeforeCreate

func (receipt *AccountQuotaMutationReceipt) BeforeCreate(tx *gorm.DB) error

func (*AccountQuotaMutationReceipt) BeforeDelete

func (*AccountQuotaMutationReceipt) BeforeDelete(*gorm.DB) error

func (*AccountQuotaMutationReceipt) BeforeUpdate

func (*AccountQuotaMutationReceipt) BeforeUpdate(*gorm.DB) error

func (AccountQuotaMutationReceipt) TableName

func (AccountQuotaMutationReceipt) TableName() string

type AccountQuotaRefundFact

type AccountQuotaRefundFact struct {
	ID                 int64  `json:"id" gorm:"primaryKey"`
	EventKey           string `json:"event_key" gorm:"type:varchar(128);not null;uniqueIndex"`
	Kind               string `json:"kind" gorm:"type:varchar(32);not null;index"`
	RequestID          string `json:"request_id" gorm:"type:varchar(64);not null;index"`
	ReserveReceiptID   int64  `json:"reserve_receipt_id" gorm:"type:bigint;not null;default:0;index"`
	AuditKey           string `json:"audit_key" gorm:"type:varchar(96);not null;default:''"`
	WriterEpoch        int64  `json:"writer_epoch" gorm:"type:bigint;not null"`
	UserID             int    `json:"user_id" gorm:"not null;index"`
	TokenID            int    `json:"token_id" gorm:"not null;index"`
	SubscriptionID     int    `json:"subscription_id" gorm:"not null;default:0;index"`
	WalletQuota        int64  `json:"wallet_quota" gorm:"type:bigint;not null"`
	SubscriptionQuota  int64  `json:"subscription_quota" gorm:"type:bigint;not null;default:0"`
	TokenQuota         int64  `json:"token_quota" gorm:"type:bigint;not null"`
	RequestFingerprint string `json:"request_fingerprint" gorm:"type:char(64);not null"`
	State              string `json:"state" gorm:"type:varchar(16);not null;index"`
	TerminalReceiptID  int64  `json:"terminal_receipt_id" gorm:"type:bigint;not null;default:0"`
	Attempts           int    `json:"attempts" gorm:"not null;default:0"`
	LastError          string `json:"last_error" gorm:"type:text;not null"`
	NextAttemptAt      int64  `json:"next_attempt_at" gorm:"type:bigint;not null;default:0;index"`
	LeaseOwner         string `json:"lease_owner" gorm:"type:varchar(128);not null;default:''"`
	LeaseUntil         int64  `json:"lease_until" gorm:"type:bigint;not null;default:0;index"`
	LockVersion        int64  `json:"lock_version" gorm:"type:bigint;not null;default:1"`
	CreatedAt          int64  `json:"created_at" gorm:"type:bigint;not null"`
	UpdatedAt          int64  `json:"updated_at" gorm:"type:bigint;not null"`
}

func EnsureAccountQuotaRefundFact

func EnsureAccountQuotaRefundFact(ctx context.Context, db *gorm.DB, input AccountQuotaRefundFactInput) (*AccountQuotaRefundFact, error)

func (AccountQuotaRefundFact) TableName

func (AccountQuotaRefundFact) TableName() string

type AccountQuotaRefundFactInput

type AccountQuotaRefundFactInput struct {
	EventKey          string
	Kind              string
	RequestID         string
	ReserveReceiptID  int64
	AuditKey          string
	WriterEpoch       int64
	UserID            int
	TokenID           int
	SubscriptionID    int
	WalletQuota       int64
	SubscriptionQuota int64
	TokenQuota        int64
}

type AccountQuotaReservationHead

type AccountQuotaReservationHead struct {
	ID                 int64  `json:"id" gorm:"primaryKey"`
	RequestID          string `json:"request_id" gorm:"type:varchar(64);not null;uniqueIndex"`
	WriterEpoch        int64  `json:"writer_epoch" gorm:"type:bigint;not null"`
	RootReceiptID      int64  `json:"root_receipt_id" gorm:"type:bigint;not null;index"`
	CurrentReceiptID   int64  `json:"current_receipt_id" gorm:"type:bigint;not null;index"`
	TerminalReceiptID  int64  `json:"terminal_receipt_id" gorm:"type:bigint;not null;default:0;index"`
	ReserveFingerprint string `json:"reserve_fingerprint" gorm:"type:char(64);not null;default:''"`
	UserID             int    `json:"user_id" gorm:"not null;index"`
	TokenID            int    `json:"token_id" gorm:"not null;index"`
	SubscriptionID     int    `json:"subscription_id" gorm:"not null;default:0;index"`
	BillingSource      string `json:"billing_source" gorm:"type:varchar(32);not null"`
	AppliedQuota       int64  `json:"applied_quota" gorm:"type:bigint;not null"`
	LockVersion        int64  `json:"lock_version" gorm:"type:bigint;not null;default:1"`
	CreatedAt          int64  `json:"created_at" gorm:"type:bigint;not null"`
	UpdatedAt          int64  `json:"updated_at" gorm:"type:bigint;not null"`
}

AccountQuotaReservationHead is the single mutable serialization point for a synchronous request. Account rows are always locked before this row: User -> Token -> Subscription -> ReservationHead -> current Receipt.

func (AccountQuotaReservationHead) TableName

func (AccountQuotaReservationHead) TableName() string

type AccountQuotaReserveInput

type AccountQuotaReserveInput struct {
	RequestID         string
	UserID            int
	TokenID           int
	RequestedQuota    int64
	BillingPreference string
	TrustQuota        int64
	AllowTrust        bool
	Playground        bool
	BillingContext    AccountBillingContext
}

type AccountQuotaSettlementFact

type AccountQuotaSettlementFact struct {
	ID                 int64  `json:"id" gorm:"primaryKey"`
	EventKey           string `json:"event_key" gorm:"type:varchar(128);not null;uniqueIndex"`
	RequestID          string `json:"request_id" gorm:"type:varchar(64);not null;index"`
	Kind               string `json:"kind" gorm:"type:varchar(32);not null;index"`
	UserID             int    `json:"user_id" gorm:"not null;index"`
	TokenID            int    `json:"token_id" gorm:"not null;index"`
	SubscriptionID     int    `json:"subscription_id" gorm:"not null;default:0;index"`
	ReserveReceiptID   int64  `json:"reserve_receipt_id" gorm:"type:bigint;not null;default:0;index"`
	WriterEpoch        int64  `json:"writer_epoch" gorm:"type:bigint;not null;default:0"`
	ActualQuota        int64  `json:"actual_quota" gorm:"type:bigint;not null;default:0"`
	Delta              int64  `json:"delta" gorm:"type:bigint;not null"`
	ApplyToken         bool   `json:"apply_token" gorm:"not null"`
	FundingApplied     bool   `json:"funding_applied" gorm:"not null"`
	TokenApplied       bool   `json:"token_applied" gorm:"not null"`
	TerminalReceiptID  int64  `json:"terminal_receipt_id" gorm:"type:bigint;not null;default:0;index"`
	RequestFingerprint string `json:"request_fingerprint" gorm:"type:char(64);not null"`
	State              string `json:"state" gorm:"type:varchar(16);not null;index"`
	Attempts           int    `json:"attempts" gorm:"not null;default:0"`
	LastError          string `json:"last_error" gorm:"type:text;not null"`
	NextAttemptAt      int64  `json:"next_attempt_at" gorm:"type:bigint;not null;default:0;index"`
	LeaseOwner         string `json:"lease_owner" gorm:"type:varchar(128);not null;default:''"`
	LeaseUntil         int64  `json:"lease_until" gorm:"type:bigint;not null;default:0;index"`
	LockVersion        int64  `json:"lock_version" gorm:"type:bigint;not null;default:1"`
	CreatedAt          int64  `json:"created_at" gorm:"type:bigint;not null"`
	UpdatedAt          int64  `json:"updated_at" gorm:"type:bigint;not null"`
}

func FindAccountQuotaSettlementFactByEventKey

func FindAccountQuotaSettlementFactByEventKey(db *gorm.DB, eventKey string) (*AccountQuotaSettlementFact, error)

FindAccountQuotaSettlementFactByEventKey retrieves a settlement fact by its unique event key. Returns (nil, nil) when no fact exists yet.

func RecoverAccountQuotaSettlementFact

func RecoverAccountQuotaSettlementFact(ctx context.Context, db *gorm.DB, fact *AccountQuotaSettlementFact, workerID string) (*AccountQuotaSettlementFact, error)

func (*AccountQuotaSettlementFact) BeforeCreate

func (fact *AccountQuotaSettlementFact) BeforeCreate(tx *gorm.DB) error

func (AccountQuotaSettlementFact) TableName

func (AccountQuotaSettlementFact) TableName() string

type AccountQuotaSettlementFactInput

type AccountQuotaSettlementFactInput struct {
	EventKey         string
	RequestID        string
	Kind             string
	UserID           int
	TokenID          int
	SubscriptionID   int
	ReserveReceiptID int64
	WriterEpoch      int64
	ActualQuota      int64
	Delta            int64
	ApplyToken       bool
}

func NormalizeAccountQuotaSettlementFactInput

func NormalizeAccountQuotaSettlementFactInput(input AccountQuotaSettlementFactInput) (AccountQuotaSettlementFactInput, string, error)

NormalizeAccountQuotaSettlementFactInput returns the canonical input and stable fingerprint without performing database I/O.

type AccountQuotaSettlementIntent

type AccountQuotaSettlementIntent struct {
	ID                 int64  `json:"id" gorm:"primaryKey"`
	EventKey           string `json:"event_key" gorm:"type:varchar(128);not null;uniqueIndex;<-:create"`
	RequestID          string `json:"request_id" gorm:"type:varchar(64);not null;index;<-:create"`
	Kind               string `json:"kind" gorm:"type:varchar(32);not null;index;<-:create"`
	UserID             int    `json:"user_id" gorm:"not null;index;<-:create"`
	TokenID            int    `json:"token_id" gorm:"not null;index;<-:create"`
	SubscriptionID     int    `json:"subscription_id" gorm:"not null;default:0;index;<-:create"`
	ReserveReceiptID   int64  `json:"reserve_receipt_id" gorm:"type:bigint;not null;default:0;index;<-:create"`
	WriterEpoch        int64  `json:"writer_epoch" gorm:"type:bigint;not null;default:0;<-:create"`
	ActualQuota        int64  `json:"actual_quota" gorm:"type:bigint;not null;default:0;<-:create"`
	Delta              int64  `json:"delta" gorm:"type:bigint;not null;<-:create"`
	ApplyToken         bool   `json:"apply_token" gorm:"not null;<-:create"`
	RequestFingerprint string `json:"request_fingerprint" gorm:"type:char(64);not null;<-:create"`
	State              string `json:"state" gorm:"type:varchar(16);not null;index"`
	FactID             int64  `json:"fact_id" gorm:"type:bigint;not null;default:0;index"`
	TerminalReceiptID  int64  `json:"terminal_receipt_id" gorm:"type:bigint;not null;default:0;index"`
	Attempts           int    `json:"attempts" gorm:"not null;default:0"`
	LastError          string `json:"last_error" gorm:"type:text;not null"`
	LockVersion        int64  `json:"lock_version" gorm:"type:bigint;not null;default:1"`
	CreatedAt          int64  `json:"created_at" gorm:"type:bigint;not null"`
	UpdatedAt          int64  `json:"updated_at" gorm:"type:bigint;not null"`
}

AccountQuotaSettlementIntent is the independent durable inbox for one settlement. A singleton wake-up task never carries accounting identity; it only asks workers to scan these rows.

func EnsureAccountQuotaSettlementIntent

func EnsureAccountQuotaSettlementIntent(ctx context.Context, db *gorm.DB, input AccountQuotaSettlementFactInput) (*AccountQuotaSettlementIntent, error)

EnsureAccountQuotaSettlementIntent persists exact settlement identity before the recoverable fact is materialized. This is the only source consumed by newly scheduled settlement recovery scans.

func (*AccountQuotaSettlementIntent) BeforeCreate

func (intent *AccountQuotaSettlementIntent) BeforeCreate(tx *gorm.DB) error

The create transaction shares the lifecycle lock with manual takeover. A check before Create alone cannot prevent a late automatic intent racing a hold.

func (AccountQuotaSettlementIntent) TableName

type AccountQuotaTerminalInput

type AccountQuotaTerminalInput struct {
	RequestID        string
	ReserveReceiptID int64
	ActualQuota      int64
	BillingContext   AccountBillingContext
	AuditKey         string
}

type AccountQuotaTerminalRecoveryObligation

type AccountQuotaTerminalRecoveryObligation struct {
	ID                 int64  `json:"id" gorm:"primaryKey"`
	RequestID          string `json:"request_id" gorm:"type:varchar(64);not null;uniqueIndex"`
	ReserveReceiptID   int64  `json:"reserve_receipt_id" gorm:"type:bigint;not null;index"`
	Phase              string `json:"phase" gorm:"type:varchar(16);not null"`
	AuditKey           string `json:"audit_key" gorm:"type:varchar(96);not null"`
	ActualQuota        int64  `json:"actual_quota" gorm:"type:bigint;not null;default:0"`
	WriterEpoch        int64  `json:"writer_epoch" gorm:"type:bigint;not null;index"`
	RequestFingerprint string `json:"request_fingerprint" gorm:"type:char(64);not null"`
	State              string `json:"state" gorm:"type:varchar(16);not null;index"`
	TerminalReceiptID  int64  `json:"terminal_receipt_id" gorm:"type:bigint;not null;default:0;index"`
	Attempts           int    `json:"attempts" gorm:"not null;default:0"`
	LastError          string `json:"last_error" gorm:"type:text;not null"`
	ReviewMetadata     string `json:"review_metadata,omitempty" gorm:"type:text"`
	NextAttemptAt      int64  `json:"next_attempt_at" gorm:"type:bigint;not null;default:0;index"`
	LeaseOwner         string `json:"lease_owner" gorm:"type:varchar(128);not null;default:''"`
	LeaseUntil         int64  `json:"lease_until" gorm:"type:bigint;not null;default:0;index"`
	LockVersion        int64  `json:"lock_version" gorm:"type:bigint;not null;default:1"`
	CreatedAt          int64  `json:"created_at" gorm:"type:bigint;not null"`
	UpdatedAt          int64  `json:"updated_at" gorm:"type:bigint;not null"`
}

func HoldAccountQuotaUnknownUsage

func HoldAccountQuotaUnknownUsage(parent context.Context, db *gorm.DB, requestID string, reserveReceiptID int64, reason string, metadata ...string) (*AccountQuotaTerminalRecoveryObligation, error)

HoldAccountQuotaUnknownUsage freezes the existing reservation lifecycle. It records no actual charge and creates no refund or settlement intent. The reservation head serializes this operation with terminal mutations; ordinary settle, refund, extension and background refund recovery already require an open lifecycle and therefore cannot clear this hold.

func PersistAccountQuotaSettlementManualEvidence

func PersistAccountQuotaSettlementManualEvidence(ctx context.Context, db *gorm.DB, input AccountQuotaTerminalInput, cause error) (*AccountQuotaTerminalRecoveryObligation, error)

PersistAccountQuotaSettlementManualEvidence records exact settlement input on the lifecycle row that was committed with the reserve. It is the final fail-closed fallback when neither the settlement inbox nor fact can be created; it never applies quota automatically.

func (AccountQuotaTerminalRecoveryObligation) TableName

type AccountQuotaThresholdPolicyInput

type AccountQuotaThresholdPolicyInput struct {
	Enabled             bool  `json:"enabled"`
	MinimumRemainingBPS int   `json:"minimum_remaining_bps"`
	MaxAgeSeconds       int64 `json:"max_age_seconds"`
}

type AccountQuotaThresholdState

type AccountQuotaThresholdState struct {
	Eligible   bool
	Reason     string
	ObservedAt int64
	ResetAt    int64
}

func ReadCodexAccountThresholdState

func ReadCodexAccountThresholdState(ctx context.Context, db *gorm.DB, subjectRef, legacyAccountRef string, now int64, policy common.AccountQuotaThreshold) (AccountQuotaThresholdState, error)

Uses the same opaque provider-account identity as exact-429 routing, but never falls back from a failed/incomplete new batch to older success.

type AccountTierMetadata

type AccountTierMetadata struct {
	ID             string   `json:"id"`
	Kind           string   `json:"kind"`
	Label          string   `json:"label"`
	Description    string   `json:"description"`
	RouteGroups    []string `json:"route_groups,omitempty"`
	ModelAllowlist []string `json:"model_allowlist,omitempty"`
	Enabled        bool     `json:"enabled"`
	Known          bool     `json:"-"`
}

AccountTierMetadata gives the legacy user group a separate account-level meaning. Account tiers and key access profiles intentionally have different identities even when old installations use the same names (default/vip).

func ResolveAccountTier

func ResolveAccountTier(groupName, configuredDescription string) AccountTierMetadata

func ResolveAccountTierID

func ResolveAccountTierID(id, configuredDescription string) AccountTierMetadata

ResolveAccountTierID resolves a persisted stable account-tier identifier without inferring it from the legacy routing group. Built-in identifiers are mapped to their canonical labels; custom identifiers remain visible as custom tiers so administrators can explain them consistently across APIs.

func ResolveAccountTierIDWithSnapshot

func ResolveAccountTierIDWithSnapshot(id, configuredDescription string, registry *setting.AccessProfileSetting) AccountTierMetadata

ResolveAccountTierIDWithSnapshot resolves a persisted tier identity against one detached registry generation.

func ResolveAccountTierWithSnapshot

func ResolveAccountTierWithSnapshot(groupName, configuredDescription string, registry *setting.AccessProfileSetting) AccountTierMetadata

ResolveAccountTierWithSnapshot resolves the account half of a request policy against the caller-provided detached registry generation.

type AdminQuotaAdjustment

type AdminQuotaAdjustment struct {
	Id                 int    `json:"id" gorm:"primaryKey;autoIncrement"`
	AdminUserId        int    `json:"admin_user_id" gorm:"not null;index"`
	TargetUserId       int    `json:"target_user_id" gorm:"not null;index;uniqueIndex:uidx_admin_quota_adjustment_request,priority:1"`
	RequestId          string `json:"request_id" gorm:"type:varchar(64);not null;uniqueIndex:uidx_admin_quota_adjustment_request,priority:2"`
	Operation          string `json:"operation" gorm:"type:varchar(16);not null"`
	Delta              int64  `json:"delta" gorm:"type:bigint;not null"`
	TargetQuota        int64  `json:"target_quota" gorm:"type:bigint;not null"`
	AppliedQuotaBefore int64  `json:"applied_quota_before" gorm:"type:bigint;not null"`
	AppliedQuotaAfter  int64  `json:"applied_quota_after" gorm:"type:bigint;not null"`
	Status             string `json:"status" gorm:"type:varchar(16);not null"`
	CreatedAt          int64  `json:"created_at" gorm:"bigint"`
	UpdatedAt          int64  `json:"updated_at" gorm:"bigint"`
}

AdminQuotaAdjustment 是一次管理员额度调整的持久操作身份。 (target_user_id, request_id) 唯一索引使客户端重试安全: 重放已 succeeded 的请求直接返回记录结果而不重复写余额; 用不同参数复用同一 request id 判为冲突。

func AdminAdjustUserQuota

func AdminAdjustUserQuota(adminUserId int, targetUserId int, operation string, value int, requestId string) (*AdminQuotaAdjustment, bool, error)

AdminAdjustUserQuota 应用一次管理员额度调整(add/subtract/override)。 三个管理端点共用:单事务内查重放(succeeded 同参数零写成功、异参数冲突)→ lockForUpdate 锁目标用户(同时在锁内做二次查重,使并发重复提交收敛为一次应用)→ 建单 → add/subtract 经模式分发,override 在锁内计算 delta=target−current 后走同一分发:

  • authoritative:receipt 内核,键 "admin-adjust:{targetUserId}:{requestId}", MutationType "admin_adjust",ReasonCode 按操作区分;
  • legacy:保持迁移前直写语义(增减用表达式、覆盖直设,减可透支);
  • bridge 及其余:fail-closed。

记录 before/after 后标记 succeeded。提交后按模式投影 receipt 或同步缓存。 返回 (adjustment, replayed, err)。

func (AdminQuotaAdjustment) TableName

func (AdminQuotaAdjustment) TableName() string

type AffQuotaTransfer

type AffQuotaTransfer struct {
	Id        int    `json:"id" gorm:"primaryKey;autoIncrement"`
	UserId    int    `json:"user_id" gorm:"not null;index;uniqueIndex:uidx_aff_quota_transfer_request,priority:1"`
	RequestId string `json:"request_id" gorm:"type:varchar(64);not null;uniqueIndex:uidx_aff_quota_transfer_request,priority:2"`
	Quota     int    `json:"quota" gorm:"not null"`
	Status    string `json:"status" gorm:"type:varchar(16);not null"`
	CreatedAt int64  `json:"created_at" gorm:"bigint"`
	UpdatedAt int64  `json:"updated_at" gorm:"bigint"`
}

AffQuotaTransfer is the durable operation identity of one affiliate-to-wallet transfer attempt. The (user_id, request_id) unique index makes client retries safe: a replayed request id returns the recorded outcome instead of moving quota twice.

func (AffQuotaTransfer) TableName

func (AffQuotaTransfer) TableName() string

type AssignedAccessPolicy

type AssignedAccessPolicy struct {
	ID          int    `json:"-" gorm:"primaryKey"`
	SubjectType string `json:"-" gorm:"type:varchar(16);not null;uniqueIndex:uidx_assigned_access_policy_subject,priority:1"`
	SubjectID   int    `json:"-" gorm:"not null;uniqueIndex:uidx_assigned_access_policy_subject,priority:2"`
	Revision    int64  `json:"-" gorm:"type:bigint;not null"`
	Assigned    bool   `json:"-" gorm:"not null"`
	PolicyJSON  string `json:"-" gorm:"type:text;not null"`
}

AssignedAccessPolicy is private administrator-owned state. Removal preserves a tombstone and monotonically increasing revision, so an old create/update can never restore a removed assignment through an ABA revision reset. PolicyJSON is validated and normalized by the service boundary; the model independently enforces its syntax and portable storage size.

func ConfigureAssignedAccessPolicy

func ConfigureAssignedAccessPolicy(ctx context.Context, db *gorm.DB, subject string, id int, expectedRevision int64, policyJSON string) (AssignedAccessPolicy, error)

ConfigureAssignedAccessPolicy performs strict compare-and-swap. Revision zero may create a row only; it cannot overwrite an assignment or its tombstone.

func MutateAssignedAccessPolicyAsAdmin

func MutateAssignedAccessPolicyAsAdmin(ctx context.Context, db *gorm.DB, actorID int, subject string, id int, expectedRevision int64, policyJSON *string) (AssignedAccessPolicy, error)

MutateAssignedAccessPolicyAsAdmin authorizes against locked, current user records in the same transaction as the assignment mutation. A nil policy removes the assignment. The caller's cached role never grants permission.

func ReadAssignedAccessPolicies

func ReadAssignedAccessPolicies(ctx context.Context, db *gorm.DB, userID, tokenID int) ([]AssignedAccessPolicy, error)

ReadAssignedAccessPolicies reads both policy scopes in one database statement so a request cannot combine policies observed on opposite sides of a commit. Results are ordered user then token, including revision-zero unassigned rows for missing subjects. A zero token ID omits the token scope for session users.

func ReadAssignedAccessPolicy

func ReadAssignedAccessPolicy(ctx context.Context, db *gorm.DB, subject string, id int) (AssignedAccessPolicy, error)

func RemoveAssignedAccessPolicy

func RemoveAssignedAccessPolicy(ctx context.Context, db *gorm.DB, subject string, id int, expectedRevision int64) (AssignedAccessPolicy, error)

type AuthFlow

type AuthFlow struct {
	Id         int64      `json:"id" gorm:"primaryKey"`
	TokenHash  string     `json:"-" gorm:"type:char(64);not null;uniqueIndex"`
	Purpose    string     `json:"purpose" gorm:"type:varchar(32);not null;index:idx_auth_flow_purpose_expiry"`
	Provider   string     `json:"provider,omitempty" gorm:"type:varchar(64)"`
	Intent     string     `json:"intent,omitempty" gorm:"type:varchar(16)"`
	UserId     int        `json:"user_id,omitempty" gorm:"index"`
	SessionId  string     `json:"session_id,omitempty" gorm:"type:varchar(64);index"`
	Payload    string     `json:"-" gorm:"type:text"`
	CreatedAt  time.Time  `json:"created_at"`
	ExpiresAt  time.Time  `json:"expires_at" gorm:"not null;index:idx_auth_flow_purpose_expiry"`
	ConsumedAt *time.Time `json:"consumed_at,omitempty" gorm:"index"`
}

AuthFlow stores one-time, short-lived state for authentication ceremonies. TokenHash is an HMAC of the opaque token; the token itself is never persisted.

func ConsumeAuthFlow

func ConsumeAuthFlow(token string, match AuthFlowMatch) (*AuthFlow, error)

ConsumeAuthFlow atomically validates and consumes a flow. Optional match fields are enforced when non-zero so tokens cannot cross purposes or users.

func ConsumeAuthFlowWithAction

func ConsumeAuthFlowWithAction(token string, match AuthFlowMatch, action func(tx *gorm.DB, flow *AuthFlow) error) (*AuthFlow, error)

ConsumeAuthFlowWithAction consumes a flow and runs action in the same database transaction. An action failure rolls the consumption back.

func CreateAuthFlow

func CreateAuthFlow(input AuthFlowCreate) (string, *AuthFlow, error)

func GetAuthFlow

func GetAuthFlow(token string, match AuthFlowMatch) (*AuthFlow, error)

GetAuthFlow validates a flow without consuming it. Callers must still use ConsumeAuthFlow with all identity-bound fields before performing the action.

func (AuthFlow) TableName

func (AuthFlow) TableName() string

type AuthFlowCreate

type AuthFlowCreate struct {
	Purpose   string
	Provider  string
	Intent    string
	UserId    int
	SessionId string
	Payload   string
	ExpiresAt time.Time
}

type AuthFlowMatch

type AuthFlowMatch struct {
	Purpose   string
	Provider  string
	Intent    string
	UserId    int
	SessionId string
}

type AuthzRole

type AuthzRole struct {
	Id          uint   `json:"id" gorm:"primaryKey;autoIncrement"`
	Key         string `json:"key" gorm:"size:64;uniqueIndex;not null"`
	Name        string `json:"name" gorm:"size:100;not null"`
	Description string `json:"description" gorm:"type:text"`
	BuiltIn     bool   `json:"built_in"`
	Enabled     bool   `json:"enabled"`
	Sort        int    `json:"sort"`
	CreatedAt   int64  `json:"created_at" gorm:"autoCreateTime;column:created_at"`
	UpdatedAt   int64  `json:"updated_at" gorm:"autoUpdateTime;column:updated_at"`
}

func (AuthzRole) TableName

func (AuthzRole) TableName() string

type BillingLogProjectionIdentity

type BillingLogProjectionIdentity struct {
	BillingEventID   string `gorm:"column:billing_event_id;type:varchar(64);primaryKey"`
	Digest           string `gorm:"column:digest;type:varchar(65);not null"`
	CanonicalVersion int    `gorm:"column:canonical_version;not null"`
	Status           string `gorm:"column:status;type:varchar(32);not null;index"`
	Reason           string `gorm:"column:reason;type:text"`
	UpdatedAt        int64  `gorm:"column:updated_at;bigint;not null"`
}

func (BillingLogProjectionIdentity) TableName

type BoundChannel

type BoundChannel struct {
	Name string `json:"name"`
	Type int    `json:"type"`
}

type CasbinRule

type CasbinRule struct {
	Id    uint   `gorm:"primaryKey;autoIncrement"`
	Ptype string `gorm:"size:100;index:idx_casbin_rule,priority:1;uniqueIndex:idx_casbin_rule_unique,priority:1"`
	V0    string `gorm:"size:100;index:idx_casbin_rule,priority:2;uniqueIndex:idx_casbin_rule_unique,priority:2"`
	V1    string `gorm:"size:100;index:idx_casbin_rule,priority:3;uniqueIndex:idx_casbin_rule_unique,priority:3"`
	V2    string `gorm:"size:100;index:idx_casbin_rule,priority:4;uniqueIndex:idx_casbin_rule_unique,priority:4"`
	V3    string `gorm:"size:100;index:idx_casbin_rule,priority:5;uniqueIndex:idx_casbin_rule_unique,priority:5"`
	V4    string `gorm:"size:100;index:idx_casbin_rule,priority:6;uniqueIndex:idx_casbin_rule_unique,priority:6"`
	V5    string `gorm:"size:100;index:idx_casbin_rule,priority:7;uniqueIndex:idx_casbin_rule_unique,priority:7"`
}

func (CasbinRule) TableName

func (CasbinRule) TableName() string

type Channel

type Channel struct {
	RoutingConfigDigest string  `json:"routing_config_digest,omitempty" gorm:"-"`
	Id                  int     `json:"id"`
	Type                int     `json:"type" gorm:"default:0"`
	Key                 string  `json:"key" gorm:"not null"`
	OpenAIOrganization  *string `json:"openai_organization"`
	TestModel           *string `json:"test_model"`
	// Managed by successful detailed tests, never accepted from channel edit payloads.
	LastSuccessfulTestOptions string  `json:"-" gorm:"type:text"`
	QuotaSamplingCursor       int64   `json:"-" gorm:"not null;default:0"`
	Status                    int     `json:"status" gorm:"default:1"`
	Name                      string  `json:"name" gorm:"index"`
	Weight                    *uint   `json:"weight" gorm:"default:0"`
	CreatedTime               int64   `json:"created_time" gorm:"bigint"`
	TestTime                  int64   `json:"test_time" gorm:"bigint"`
	ResponseTime              int     `json:"response_time"` // in milliseconds
	BaseURL                   *string `json:"base_url" gorm:"column:base_url;default:''"`
	Other                     string  `json:"other"`
	Balance                   float64 `json:"balance"` // in USD
	BalanceUpdatedTime        int64   `json:"balance_updated_time" gorm:"bigint"`
	Models                    string  `json:"models"`
	Group                     string  `json:"group" gorm:"type:varchar(64);default:'default'"`
	UsedQuota                 int64   `json:"used_quota" gorm:"bigint;default:0"`
	ModelMapping              *string `json:"model_mapping" gorm:"type:text"`
	//MaxInputTokens     *int    `json:"max_input_tokens" gorm:"default:0"`
	StatusCodeMapping *string `json:"status_code_mapping" gorm:"type:varchar(1024);default:''"`
	Priority          *int64  `json:"priority" gorm:"bigint;default:0"`
	AutoBan           *int    `json:"auto_ban" gorm:"default:1"`
	OtherInfo         string  `json:"other_info"`
	Tag               *string `json:"tag" gorm:"index"`
	Setting           *string `json:"setting" gorm:"type:text"` // 渠道额外设置
	ParamOverride     *string `json:"param_override" gorm:"type:text"`
	HeaderOverride    *string `json:"header_override" gorm:"type:text"`
	Remark            *string `json:"remark" gorm:"type:varchar(255)" validate:"max=255"`
	// add after v0.8.5
	ChannelInfo ChannelInfo `json:"channel_info" gorm:"type:json"`

	OtherSettings string `json:"settings" gorm:"column:settings"` // 其他设置,存储azure版本等不需要检索的信息,详见dto.ChannelOtherSettings

	// cache info
	Keys []string `json:"-" gorm:"-"`
}

func CacheGetChannel

func CacheGetChannel(id int) (*Channel, error)

func GetAllChannels

func GetAllChannels(startIdx int, num int, selectAll bool, idSort bool, sortOptions ...ChannelSortOptions) ([]*Channel, error)

func GetChannel

func GetChannel(group string, modelName string, retry int, requestPath string) (*Channel, error)

func GetChannelById

func GetChannelById(id int, selectAll bool) (*Channel, error)

func GetChannelsByIds

func GetChannelsByIds(ids []int) ([]*Channel, error)

func GetChannelsByTag

func GetChannelsByTag(tag string, idSort bool, selectAll bool, sortOptions ...ChannelSortOptions) ([]*Channel, error)

func GetChannelsByType

func GetChannelsByType(startIdx int, num int, idSort bool, channelType int) ([]*Channel, error)

Get channels of specified type with pagination

func GetChannelsForQuotaSnapshotSync

func GetChannelsForQuotaSnapshotSync(limit int) ([]*Channel, error)

GetChannelsForQuotaSnapshotSync returns a bounded set of enabled channels with credentials available to the internal sampler. It intentionally does not expose this projection through an API; callers use it only for the provider request and must not serialize the returned Key field. Every recorded attempt, including an error or unsupported response, advances that channel's turn so a fixed channel limit does not starve lower-priority accounts.

func GetChannelsForQuotaSnapshotSyncContext

func GetChannelsForQuotaSnapshotSyncContext(ctx context.Context, limit int) ([]*Channel, error)

GetChannelsForQuotaSnapshotSyncContext includes valid single/multi-key rows and orders channels by their last credential attempt, then legacy history. Within a channel, the scheduler independently chooses its oldest targets.

func GetRandomSatisfiedChannel

func GetRandomSatisfiedChannel(group string, modelName string, retry int, requestPath string) (*Channel, error)

func SearchChannels

func SearchChannels(keyword string, group string, model string, idSort bool, sortOptions ...ChannelSortOptions) ([]*Channel, error)

func UpdateChannelRoutingState

func UpdateChannelRoutingState(
	ctx context.Context,
	channelID int,
	mutate func(channel *Channel) (routingChanged bool, err error),
) (*Channel, bool, error)

UpdateChannelRoutingState locks and reloads the latest channel, applies one mutation, and persists channel models/settings plus abilities atomically. routingChanged controls whether the persistent routing epoch advances.

func (*Channel) AddAbilities

func (channel *Channel) AddAbilities(tx *gorm.DB) error

func (*Channel) Delete

func (channel *Channel) Delete() error

func (*Channel) DeleteAbilities

func (channel *Channel) DeleteAbilities() error

func (*Channel) GetAutoBan

func (channel *Channel) GetAutoBan() bool

func (*Channel) GetBaseURL

func (channel *Channel) GetBaseURL() string

func (*Channel) GetEnabledQuotaSamplingKeys

func (channel *Channel) GetEnabledQuotaSamplingKeys() []string

GetEnabledQuotaSamplingKeys returns the concrete credentials eligible for scheduled quota sampling. Disabled multi-key entries are excluded and raw indexes never leave this model boundary.

func (*Channel) GetGroups

func (channel *Channel) GetGroups() []string

func (*Channel) GetHeaderOverride

func (channel *Channel) GetHeaderOverride() map[string]interface{}

func (*Channel) GetKeys

func (channel *Channel) GetKeys() []string

func (*Channel) GetModelMapping

func (channel *Channel) GetModelMapping() string

func (*Channel) GetModels

func (channel *Channel) GetModels() []string

func (*Channel) GetNextEnabledKey

func (channel *Channel) GetNextEnabledKey() (string, int, *types.NewAPIError)

func (*Channel) GetNextEnabledKeyExcluding

func (channel *Channel) GetNextEnabledKeyExcluding(excluded map[int]bool) (string, int, *types.NewAPIError)

GetNextEnabledKeyExcluding omits request-scoped quota holds without disabling keys.

func (*Channel) GetOtherInfo

func (channel *Channel) GetOtherInfo() map[string]interface{}

func (*Channel) GetOtherSettings

func (channel *Channel) GetOtherSettings() dto.ChannelOtherSettings

func (*Channel) GetParamOverride

func (channel *Channel) GetParamOverride() map[string]interface{}

func (*Channel) GetPriority

func (channel *Channel) GetPriority() int64

func (*Channel) GetSetting

func (channel *Channel) GetSetting() dto.ChannelSettings

func (*Channel) GetStatusCodeMapping

func (channel *Channel) GetStatusCodeMapping() string

func (*Channel) GetTag

func (channel *Channel) GetTag() string

func (*Channel) GetWeight

func (channel *Channel) GetWeight() int

func (*Channel) Insert

func (channel *Channel) Insert() error

func (*Channel) Save

func (channel *Channel) Save() error

func (*Channel) SaveChannelInfo

func (channel *Channel) SaveChannelInfo() error

func (*Channel) SetOtherInfo

func (channel *Channel) SetOtherInfo(otherInfo map[string]interface{})

func (*Channel) SetOtherSettings

func (channel *Channel) SetOtherSettings(setting dto.ChannelOtherSettings)

func (*Channel) SetSetting

func (channel *Channel) SetSetting(setting dto.ChannelSettings)

func (*Channel) SetTag

func (channel *Channel) SetTag(tag string)

func (*Channel) Update

func (channel *Channel) Update() error

func (*Channel) UpdateAbilities

func (channel *Channel) UpdateAbilities(tx *gorm.DB) error

UpdateAbilities updates abilities of this channel. A caller-owned transaction is responsible for advancing the routing epoch; standalone updates do so in the same transaction as the ability replacement.

func (*Channel) UpdateBalance

func (channel *Channel) UpdateBalance(balance float64)

func (*Channel) UpdateBalanceWithContext

func (channel *Channel) UpdateBalanceWithContext(ctx context.Context, balance float64) error

UpdateBalanceWithContext reports write failures to bounded background tasks. The legacy UpdateBalance wrapper retains its logging-only contract.

func (*Channel) UpdateResponseTime

func (channel *Channel) UpdateResponseTime(responseTime int64)

func (*Channel) UpdateWithRoutingConfig

func (channel *Channel) UpdateWithRoutingConfig(expected string) error

func (*Channel) ValidateSettings

func (channel *Channel) ValidateSettings() error

type ChannelCachePublicationState

type ChannelCachePublicationState struct {
	DataGeneration        uint64 `json:"data_generation"`
	PublishedGeneration   uint64 `json:"published_generation"`
	ClusterCommittedEpoch int64  `json:"cluster_committed_epoch"`
	LocalPublishedEpoch   int64  `json:"local_published_epoch"`
	CacheEnabled          bool   `json:"cache_enabled"`
	CachePending          bool   `json:"cache_pending"`
}

ChannelCachePublicationState reports whether the runtime routing cache has published the latest committed channel/ability generation.

func GetChannelCachePublicationState

func GetChannelCachePublicationState() ChannelCachePublicationState

func LoadChannelCachePublicationState

func LoadChannelCachePublicationState() (ChannelCachePublicationState, error)

type ChannelCacheRefreshError

type ChannelCacheRefreshError struct {
	Err error
}

ChannelCacheRefreshError means the database mutation committed, but the runtime cache could not publish that committed generation.

func (*ChannelCacheRefreshError) Error

func (e *ChannelCacheRefreshError) Error() string

func (*ChannelCacheRefreshError) Unwrap

func (e *ChannelCacheRefreshError) Unwrap() error

type ChannelInfo

type ChannelInfo struct {
	IsMultiKey             bool                  `json:"is_multi_key"`                        // 是否多Key模式
	MultiKeySize           int                   `json:"multi_key_size"`                      // 多Key模式下的Key数量
	MultiKeyStatusList     map[int]int           `json:"multi_key_status_list"`               // key状态列表,key index -> status
	MultiKeyDisabledReason map[int]string        `json:"multi_key_disabled_reason,omitempty"` // key禁用原因列表,key index -> reason
	MultiKeyDisabledTime   map[int]int64         `json:"multi_key_disabled_time,omitempty"`   // key禁用时间列表,key index -> time
	MultiKeyPollingIndex   int                   `json:"multi_key_polling_index"`             // 多Key模式下轮询的key索引
	MultiKeyMode           constant.MultiKeyMode `json:"multi_key_mode"`
}

func CacheGetChannelInfo

func CacheGetChannelInfo(id int) (*ChannelInfo, error)

func (*ChannelInfo) Scan

func (c *ChannelInfo) Scan(value interface{}) error

Scan implements sql.Scanner interface

func (ChannelInfo) Value

func (c ChannelInfo) Value() (driver.Value, error)

Value implements driver.Valuer interface

type ChannelModelDiscovery

type ChannelModelDiscovery struct {
	ChannelID           int    `gorm:"primaryKey;autoIncrement:false"`
	ModelsJSON          string `gorm:"type:text"`
	Source              string `gorm:"type:varchar(32)"`
	Status              string `gorm:"type:varchar(32)"`
	EvidenceFingerprint string `json:"-" gorm:"type:char(64)"`
	AttemptFingerprint  string `json:"-" gorm:"type:char(64)"`
	Attempt             int64
	FetchedAt           int64
	CheckedAt           int64
}

ChannelModelDiscovery is server-owned evidence, never a routing permission. Both fingerprints are private digests; credentials and responses are not stored.

type ChannelModelDiscoveryAttempt

type ChannelModelDiscoveryAttempt struct {
	Channel     *Channel
	Sequence    int64
	Fingerprint string
}

func BeginChannelModelDiscovery

func BeginChannelModelDiscovery(ctx context.Context, channelID int) (ChannelModelDiscoveryAttempt, error)

BeginChannelModelDiscovery assigns a durable sequence before network I/O. Later starts supersede earlier completions, even within the same second.

type ChannelModelDiscoverySnapshot

type ChannelModelDiscoverySnapshot struct {
	Models    []string `json:"models"`
	Source    string   `json:"source"`
	Status    string   `json:"status"`
	FetchedAt int64    `json:"fetched_at"`
	CheckedAt int64    `json:"checked_at"`
	Stale     bool     `json:"stale"`
}

func GetChannelModelDiscovery

func GetChannelModelDiscovery(ctx context.Context, channelID int) (ChannelModelDiscoverySnapshot, error)

type ChannelModelRoute

type ChannelModelRoute struct {
	RequestedModel string `json:"requested_model"`
	UpstreamModel  string `json:"upstream_model"`
	Endpoint       string `json:"endpoint"`
	Reason         string `json:"reason"`
	ChannelID      int    `json:"channel_id"`
	ConfigDigest   string `json:"config_digest"`
}

ChannelModelRoute records only non-secret routing configuration. The digest binds the selected mapping; it is not proof of provider identity or pricing.

func ResolveChannelModelRoute

func ResolveChannelModelRoute(channel *Channel, requested, endpoint string) (ChannelModelRoute, error)

ResolveChannelModelRoute is shared by candidate selection, preview and the final selected-channel dispatch. Existing exact ModelMapping wins over rules. Callers must separately enforce enabled Models, groups and caller permissions.

type ChannelOperationResult

type ChannelOperationResult struct {
	IDs         []int    `json:"ids"`
	Names       []string `json:"names,omitempty"`
	SourceProxy string   `json:"source_proxy,omitempty"`
	Epoch       int64    `json:"epoch"`
}

func BatchInsertChannelsWithOperation

func BatchInsertChannelsWithOperation(
	ctx context.Context,
	channels []Channel,
	operationKey string,
	fingerprint string,
) (ChannelOperationResult, bool, error)

func CopyChannelWithOperation

func CopyChannelWithOperation(
	ctx context.Context,
	sourceID int,
	suffix string,
	resetBalance bool,
	operationKey string,
	fingerprint string,
) (ChannelOperationResult, bool, error)

type ChannelQuotaAggregateRow

type ChannelQuotaAggregateRow struct {
	ID              int      `gorm:"column:id"`
	ChannelID       int      `gorm:"column:channel_id"`
	ChannelName     string   `gorm:"column:channel_name"`
	SubjectRef      string   `json:"-" gorm:"column:subject_ref"`
	IdentityQuality string   `json:"-" gorm:"column:identity_quality"`
	AccountRef      string   `json:"-" gorm:"column:account_ref"`
	ObservedAt      int64    `gorm:"column:observed_at"`
	Available       float64  `gorm:"column:available"`
	Used            *float64 `gorm:"column:used"`
	Total           *float64 `gorm:"column:total"`
	Unit            string   `gorm:"column:unit"`
	Currency        string   `gorm:"column:currency"`
	MetricType      string   `gorm:"column:metric_type"`
	WindowType      string   `gorm:"column:window_type"`
	PlanType        string   `gorm:"column:plan_type"`
	WindowSeconds   int64    `gorm:"column:window_seconds"`
	ResetAt         int64    `gorm:"column:reset_at"`
	Source          string   `gorm:"column:source"`
	Status          string   `gorm:"column:status"`
	ErrorCode       string   `gorm:"column:error_code"`
}

ChannelQuotaAggregateRow is the redacted projection used by the global quota-change view. It deliberately contains no channel key, settings, or upstream response data. Account identity is represented by the channel's operator-provided name and stable numeric id.

func ListChannelQuotaAggregateRows

func ListChannelQuotaAggregateRows(ctx context.Context, start, end int64, channelIDs []int, metricType, windowType, source string) ([]ChannelQuotaAggregateRow, error)

ListChannelQuotaAggregateRows returns a bounded, redacted set of quota observations for all channels in one JOIN query. The newest rows are read first so a busy installation still gets current observations; callers sort rows within each metric/window group before deriving rates.

type ChannelQuotaAlertEvent

type ChannelQuotaAlertEvent struct {
	ID            int64  `gorm:"primaryKey"`
	EventKey      string `gorm:"type:varchar(128);not null;uniqueIndex"`
	SeriesKey     string `gorm:"type:char(64);not null;index"`
	SnapshotID    int    `gorm:"not null;index"`
	ChannelID     int    `gorm:"not null;index"`
	Status        string `gorm:"type:varchar(16);not null"`
	Kind          string `gorm:"type:varchar(16);not null"`
	State         string `gorm:"type:varchar(24);not null;index:idx_channel_quota_alert_ready,priority:1"`
	ClaimedBy     string `gorm:"type:varchar(128);not null;default:''"`
	ClaimedUntil  int64  `gorm:"type:bigint;not null;default:0;index"`
	AttemptCount  int    `gorm:"not null;default:0"`
	NextAttemptAt int64  `gorm:"type:bigint;not null;default:0;index:idx_channel_quota_alert_ready,priority:2"`
	LastErrorCode string `gorm:"type:varchar(64);not null;default:''"`
	LastErrorAt   int64  `gorm:"type:bigint;not null;default:0"`
	DeliveredAt   *int64 `gorm:"type:bigint"`
	LockVersion   int64  `gorm:"type:bigint;not null;default:1"`
	ObservedAt    int64  `gorm:"type:bigint;not null;index"`
	CreatedAt     int64  `gorm:"type:bigint;not null"`
	UpdatedAt     int64  `gorm:"type:bigint;not null;default:0"`
	// Frozen normalized evidence keeps in-app history useful after snapshot
	// retention. No credentials, account identifiers or provider payloads.
	EvidenceJSON string `gorm:"type:text" json:"-"`
}

ChannelQuotaAlertEvent is an immutable transactional-outbox event. Its delivery fields are advanced only by the bounded CAS helpers below. EventKey is stable across retries and is the receiver's at-least-once deduplication ID.

func ClaimChannelQuotaAlertEvents

func ClaimChannelQuotaAlertEvents(ctx context.Context, workerID string, now, leaseSeconds int64, limit int) ([]ChannelQuotaAlertEvent, error)

ClaimChannelQuotaAlertEvents claims ready or expired events with per-row CAS. It is intentionally portable: candidate discovery uses ordinary GORM queries, while the conditional update is the cross-process ownership authority.

func ListChannelQuotaAlertEvents

func ListChannelQuotaAlertEvents(ctx context.Context, filter ChannelQuotaAlertEventFilter, offset, limit int) ([]ChannelQuotaAlertEvent, int64, error)

ListChannelQuotaAlertEvents returns delivery history without joining account references or upstream credentials. Filters and pagination are bounded so an administrator query cannot turn into an unbounded table scan response.

type ChannelQuotaAlertEventFilter

type ChannelQuotaAlertEventFilter struct {
	State     string
	Status    string
	Kind      string
	ChannelID int
}

type ChannelQuotaAlertEvidence

type ChannelQuotaAlertEvidence struct {
	Version       int     `json:"version"`
	SnapshotID    int     `json:"snapshot_id"`
	ChannelID     int     `json:"channel_id"`
	ObservedAt    int64   `json:"observed_at"`
	Available     float64 `json:"available"`
	Total         float64 `json:"total"`
	Unit          string  `json:"unit"`
	Currency      string  `json:"currency,omitempty"`
	MetricType    string  `json:"metric_type"`
	WindowType    string  `json:"window_type"`
	WindowSeconds int64   `json:"window_seconds,omitempty"`
	ResetAt       int64   `json:"reset_at,omitempty"`
}

ChannelQuotaAlertEvidence contains only the immutable normalized observation needed to explain one event. SeriesRef, held separately by the event, isolates account + metric + window. It is never a per-Key consumption percentage.

func ReadChannelQuotaAlertEvidence

func ReadChannelQuotaAlertEvidence(ctx context.Context, event ChannelQuotaAlertEvent) *ChannelQuotaAlertEvidence

ReadChannelQuotaAlertEvidence never substitutes a later account observation. Old events can use their exact retained source; absent sources stay unknown.

type ChannelQuotaAlertState

type ChannelQuotaAlertState struct {
	ID              int64  `gorm:"primaryKey"`
	SeriesKey       string `gorm:"type:char(64);not null;uniqueIndex"`
	ChannelID       int    `gorm:"not null;index"`
	AccountRef      string `gorm:"type:char(64);not null;default:''"`
	MetricType      string `gorm:"type:varchar(32);not null"`
	WindowType      string `gorm:"type:varchar(32);not null"`
	Source          string `gorm:"type:varchar(64);not null"`
	PlanType        string `gorm:"type:varchar(32);not null;default:''"`
	Unit            string `gorm:"type:varchar(32);not null"`
	Currency        string `gorm:"type:varchar(8);not null;default:''"`
	WindowSeconds   int64  `gorm:"type:bigint;not null;default:0"`
	CurrentStatus   string `gorm:"type:varchar(16);not null"`
	ObservedAt      int64  `gorm:"type:bigint;not null"`
	LastDeliveredAt int64  `gorm:"type:bigint;not null;default:0"`
	// Event cooldown belongs to the in-app occurrence, not webhook success.
	LastSnapshotID int   `gorm:"not null;default:0"`
	LastEventAt    int64 `gorm:"type:bigint;not null;default:0"`
	CreatedAt      int64 `gorm:"type:bigint;not null"`
	UpdatedAt      int64 `gorm:"type:bigint;not null"`
}

ChannelQuotaAlertState is the current trusted status for one immutable channel-account quota series. SeriesKey is a digest so account references do not leak through indexes or future admin list endpoints.

type ChannelQuotaIdentityAlias

type ChannelQuotaIdentityAlias struct {
	Id         int64  `json:"-" gorm:"primaryKey"`
	KeyVersion string `json:"-" gorm:"type:varchar(32);not null;uniqueIndex:uidx_channel_quota_identity_alias,priority:1;<-:create"`
	LookupHMAC string `json:"-" gorm:"type:char(64);not null;uniqueIndex:uidx_channel_quota_identity_alias,priority:2;<-:create"`
	SubjectRef string `json:"-" gorm:"type:char(43);not null;index:idx_channel_quota_identity_subject;<-:create"`
	CreatedAt  int64  `json:"-" gorm:"type:bigint;not null;<-:create"`
}

ChannelQuotaIdentityAlias maps a key-versioned lookup HMAC to a random, opaque subject. It never stores provider account ids, credentials, tokens, or their raw source material.

func (ChannelQuotaIdentityAlias) TableName

func (ChannelQuotaIdentityAlias) TableName() string

type ChannelQuotaIdentityKeyRegistry

type ChannelQuotaIdentityKeyRegistry struct {
	Id              int    `json:"-" gorm:"primaryKey;autoIncrement:false;<-:create"`
	ProtocolVersion int    `json:"-" gorm:"not null;<-:create"`
	ActiveVersion   string `json:"-" gorm:"type:varchar(32);not null"`
	BootstrapNonce  string `json:"-" gorm:"type:char(43);not null;<-:create"`
	CreatedAt       int64  `json:"-" gorm:"type:bigint;not null;<-:create"`
}

ChannelQuotaIdentityKeyRegistry is the singleton serialization gate and current active-version marker for the persistent version registry. Old nodes may keep using a previously registered active version, while the current keyring cannot silently remove registered history.

func (ChannelQuotaIdentityKeyRegistry) TableName

type ChannelQuotaIdentityKeyVersion

type ChannelQuotaIdentityKeyVersion struct {
	Version     string `json:"-" gorm:"primaryKey;type:varchar(32);<-:create"`
	Fingerprint string `json:"-" gorm:"type:char(64);not null;uniqueIndex:uidx_channel_quota_identity_key_fingerprint;<-:create"`
	CreatedAt   int64  `json:"-" gorm:"type:bigint;not null;<-:create"`
}

ChannelQuotaIdentityKeyVersion binds one canonical version identifier to a fixed-domain fingerprint. The secret key is never persisted.

func (ChannelQuotaIdentityKeyVersion) TableName

type ChannelQuotaResolvedIdentity

type ChannelQuotaResolvedIdentity struct {
	SubjectRef string
	Quality    string
}

ChannelQuotaResolvedIdentity is the redacted identity returned to quota aggregation and alerting callers.

func LookupChannelQuotaIdentity

func LookupChannelQuotaIdentity(ctx context.Context, db *gorm.DB, keyring common.ChannelQuotaIdentityKeyring, provider, identityKind string, material []byte) (ChannelQuotaResolvedIdentity, bool, error)

LookupChannelQuotaIdentity reads an already registered subject without creating an alias. Routing uses it to bind an account's current credential to persisted quota observations without mutating identity state per request.

func ResolveChannelQuotaIdentity

func ResolveChannelQuotaIdentity(ctx context.Context, db *gorm.DB, keyring common.ChannelQuotaIdentityKeyring, provider, identityKind string, material []byte) (ChannelQuotaResolvedIdentity, error)

ResolveChannelQuotaIdentity resolves an upstream account id or credential to a stable opaque subject. Every key in an overlapping keyring receives an alias in one transaction, ordered by version and digest. A persistent gate serializes registry changes and first-writer subject creation across nodes.

type ChannelQuotaSamplingExpansion

type ChannelQuotaSamplingExpansion struct {
	ExpectedCursor int64
	NextCursor     int64
}

type ChannelQuotaSamplingIdentity

type ChannelQuotaSamplingIdentity struct {
	SubjectRef      string
	IdentityQuality string
}

type ChannelQuotaSamplingTarget

type ChannelQuotaSamplingTarget struct {
	ID                  int64  `json:"-" gorm:"primaryKey"`
	ChannelID           int    `` /* 132-byte string literal not displayed */
	SubjectRef          string `json:"-" gorm:"type:char(43);not null;uniqueIndex:uidx_channel_quota_sampling_target,priority:2"`
	IdentityQuality     string `json:"-" gorm:"type:varchar(24);not null"`
	ConfirmedSubjectRef string `json:"-" gorm:"type:char(43);not null;default:'';index"`
	Active              bool   `json:"-" gorm:"not null;index:idx_channel_quota_sampling_ready,priority:1"`
	LastAttemptAt       int64  `json:"-" gorm:"type:bigint;not null;default:0;index:idx_channel_quota_sampling_ready,priority:3"`
	LastResult          string `json:"-" gorm:"type:varchar(24);not null;default:''"`
	CreatedAt           int64  `json:"-" gorm:"type:bigint;not null"`
	UpdatedAt           int64  `json:"-" gorm:"type:bigint;not null"`
}

func SyncChannelQuotaSamplingTargets

func SyncChannelQuotaSamplingTargets(ctx context.Context, db *gorm.DB, channelID int, expectedChannelKey string, complete bool, identities []ChannelQuotaSamplingIdentity, expansion ...ChannelQuotaSamplingExpansion) ([]ChannelQuotaSamplingTarget, error)

func (ChannelQuotaSamplingTarget) TableName

func (ChannelQuotaSamplingTarget) TableName() string

type ChannelQuotaSnapshot

type ChannelQuotaSnapshot struct {
	// Only newly verified native WHAM samples can support a percentage gate.
	// Native observation provenance is separate from healthy admission.
	// Historical rows are never promoted from value-only evidence.
	CodexObservationQualified bool     `json:"-" gorm:"not null;default:false"`
	CodexThresholdQualified   bool     `json:"-" gorm:"not null;default:false"`
	Id                        int      `json:"id" gorm:"primaryKey"`
	ChannelId                 int      `` /* 194-byte string literal not displayed */
	ObservedAt                int64    `` /* 194-byte string literal not displayed */
	Available                 float64  `json:"available"`
	Used                      *float64 `json:"used,omitempty"`
	Total                     *float64 `json:"total,omitempty"`
	Unit                      string   `json:"unit" gorm:"size:32;default:'usd';index:idx_channel_quota_dedupe,priority:6"`
	Currency                  string   `json:"currency,omitempty" gorm:"size:8;index:idx_channel_quota_dedupe,priority:7"`
	MetricType                string   `` /* 135-byte string literal not displayed */
	WindowType                string   `` /* 142-byte string literal not displayed */
	// PlanType and WindowSeconds are populated for provider-specific rate-limit
	// observations (for example Codex OAuth). They remain empty/zero for the
	// generic balance snapshots.
	PlanType      string `json:"plan_type,omitempty" gorm:"size:32;index:idx_channel_quota_dedupe,priority:5"`
	WindowSeconds int64  `json:"window_seconds,omitempty" gorm:"bigint;index:idx_channel_quota_dedupe,priority:8"`
	ResetAt       int64  `json:"reset_at,omitempty" gorm:"bigint;index:idx_channel_quota_dedupe,priority:9"`
	Source        string `json:"source,omitempty" gorm:"size:64;index:idx_channel_quota_dedupe,priority:10"`
	SampleID      string `json:"sample_id,omitempty" gorm:"size:36;index:idx_channel_quota_sample,priority:2;<-:create"`
	// SubjectRef is a persistent opaque identity resolved by the deployment
	// key registry. It and IdentityQuality are internal authorization/accounting
	// metadata and must never be serialized by quota APIs.
	SubjectRef      string `json:"-" gorm:"type:char(43);index"`
	IdentityQuality string `json:"-" gorm:"type:varchar(24);index"`
	// AccountRef is a non-reversible, provider-namespaced reference to a
	// confirmed upstream account identity. It is empty when the sampler cannot
	// prove account ownership; such snapshots must never be merged with a known
	// account's alert state.
	AccountRef   string `json:"-" gorm:"size:64;index:idx_channel_quota_dedupe,priority:11"`
	Status       string `json:"status" gorm:"size:16;default:'success';index"`
	ErrorCode    string `json:"error_code,omitempty" gorm:"size:64"`
	ErrorMessage string `json:"error_message,omitempty" gorm:"size:255"`
	// DedupeKey is nullable so AutoMigrate can add it without rewriting old
	// rows. New rows use a unique digest of the sample id, complete series
	// identity, and observation time, allowing concurrent samplers to converge on all
	// supported SQL dialects without a wide dialect-sensitive composite index.
	// Keep the column definition free of a unique constraint. SQLite cannot
	// add a UNIQUE column with ALTER TABLE during AutoMigrate; the migration
	// creates the unique index separately after the nullable column exists.
	DedupeKey *string   `json:"-" gorm:"size:64"`
	CreatedAt time.Time `json:"created_at"`
}

ChannelQuotaSnapshot stores a normalized point-in-time view of an upstream channel account's available quota. Raw upstream responses and credentials are intentionally not persisted here.

func GetChannelQuotaAlertDeliverySnapshot

func GetChannelQuotaAlertDeliverySnapshot(ctx context.Context, event ChannelQuotaAlertEvent) (*ChannelQuotaSnapshot, error)

GetChannelQuotaAlertDeliverySnapshot loads the immutable source observation and re-verifies its channel and series identity before it enters a webhook.

func ListChannelQuotaSnapshots

func ListChannelQuotaSnapshots(channelID int, start, end int64, metricType, windowType string, limit int) ([]ChannelQuotaSnapshot, error)

ListChannelQuotaSnapshots keeps the legacy query surface for existing callers while routing through the series-aware implementation.

func ListChannelQuotaSnapshotsWithQuery

func ListChannelQuotaSnapshotsWithQuery(channelID int, start, end int64, filter ChannelQuotaSnapshotQuery, limit int) ([]ChannelQuotaSnapshot, error)

ListChannelQuotaSnapshotsWithQuery returns the most recent bounded batches in oldest-first order, optionally constrained to one complete provider series. It is intentionally additive so older callers keep their existing behavior when they do not need series metadata.

func ListLatestChannelQuotaSnapshotBatch

func ListLatestChannelQuotaSnapshotBatch(ctx context.Context, channelID int, start, end int64, metricType string) ([]ChannelQuotaSnapshot, error)

ListLatestChannelQuotaSnapshotBatch returns every row from the latest sample event in the selected range. It is used for current-state responses so two responses observed in the same second remain separate.

func ListLatestSuccessfulChannelQuotaSnapshotBatch

func ListLatestSuccessfulChannelQuotaSnapshotBatch(ctx context.Context, channelID int, metricType string, sources []string) ([]ChannelQuotaSnapshot, error)

ListLatestSuccessfulChannelQuotaSnapshotBatch returns every successful series from the latest successful immutable sample. Legacy rows without a sample id fall back to their second-resolution observation boundary.

func (ChannelQuotaSnapshot) TableName

func (ChannelQuotaSnapshot) TableName() string

type ChannelQuotaSnapshotAbsenceMarker

type ChannelQuotaSnapshotAbsenceMarker struct {
	Status       string
	ErrorCode    string
	ErrorMessage string
}

ChannelQuotaSnapshotAbsenceMarker configures the non-value event appended for a series that was present in the previous successful sample but is absent from the new successful sample.

type ChannelQuotaSnapshotBatchOptions

type ChannelQuotaSnapshotBatchOptions struct {
	PreviousSources []string
	AbsenceMarker   *ChannelQuotaSnapshotAbsenceMarker
}

ChannelQuotaSnapshotBatchOptions controls atomic provider-sample recording. PreviousSources limits absence detection to the provider's stable source family. AbsenceMarker may be nil for providers without window lifecycles.

type ChannelQuotaSnapshotHistoryResult

type ChannelQuotaSnapshotHistoryResult struct {
	Snapshots []ChannelQuotaSnapshot
	Complete  bool
}

ChannelQuotaSnapshotHistoryResult describes a deliberately bounded full range read. Complete is false when more than the caller's maxRows matched; Snapshots is then nil so callers cannot accidentally calculate a trend from a partial range.

func ListChannelQuotaSnapshotsForHistory

func ListChannelQuotaSnapshotsForHistory(ctx context.Context, channelID int, start, end int64, filter ChannelQuotaSnapshotQuery, maxRows int) (ChannelQuotaSnapshotHistoryResult, error)

ListChannelQuotaSnapshotsForHistory reads an entire selected range in chronological order, subject to the caller's explicit maxRows budget. It reads one extra row to detect a concurrent insert after a preceding count. A non-complete result never contains a partial slice.

type ChannelQuotaSnapshotQuery

type ChannelQuotaSnapshotQuery struct {
	// IdentityScoped requires an exact internal subject or legacy account
	// reference without making unrelated series metadata fields exact.
	IdentityScoped bool
	// ExactIdentity makes resolved empty metadata values meaningful instead of
	// treating them as wildcards that could mix units or subscription plans.
	ExactIdentity bool
	// EventMetadata allows missing metadata on a failed provider query while
	// rejecting failures that explicitly identify another plan or window.
	EventMetadata   bool
	SubjectRef      string
	IdentityQuality string
	AccountRef      string
	MetricType      string
	WindowType      string
	Source          string
	// Sources is a multi-source selector for callers that need a small,
	// explicit source family (for example a Codex window and its generic
	// failure marker). It takes precedence over Source when non-empty.
	Sources       []string
	PlanType      string
	Unit          string
	Currency      string
	WindowSeconds *int64
	// Statuses narrows a query to explicit normalized states. An empty slice
	// preserves the legacy wildcard behavior.
	Statuses []string
}

ListChannelQuotaSnapshots returns the most recent bounded observations in oldest-first order. Selecting the newest rows before reversing prevents a high-frequency sampler from filling the limit with only the beginning of a long 30/90-day window and dropping the current trend endpoint. History callers that need an entire time range must use ListChannelQuotaSnapshotsForHistory instead: its completeness result makes a bounded scan explicit rather than silently returning only recent rows. ChannelQuotaSnapshotQuery selects one normalized quota series. Empty string fields are treated as wildcards; WindowSeconds is nil when no window length was requested. Callers that need a single series can first resolve the latest row and then fill the omitted fields from its metadata.

type ChannelRoutingCandidate

type ChannelRoutingCandidate struct {
	CooldownUntil int64
	ModelRoute    *ChannelModelRoute
	RouteError    string
	ChannelID     int
	ChannelName   string
	ChannelType   int
	Priority      int64
	Weight        uint
}

ChannelRoutingCandidate is the non-sensitive input used to build the runtime routing policy and the administrator routing preview.

type ChannelRoutingCandidatePolicy

type ChannelRoutingCandidatePolicy struct {
	ChannelRoutingCandidate
	EffectiveWeight uint
	ExpectedShare   float64
}

ChannelRoutingCandidatePolicy describes one candidate's effective share within a single priority tier.

type ChannelRoutingEpoch

type ChannelRoutingEpoch struct {
	ID            int   `json:"id" gorm:"primaryKey"`
	SchemaVersion int   `json:"schema_version" gorm:"not null"`
	Epoch         int64 `json:"epoch" gorm:"type:bigint;not null"`
	UpdatedAt     int64 `json:"updated_at" gorm:"type:bigint;not null"`
}

ChannelRoutingEpoch is the persistent cluster authority for channel/ability routing mutations. Every transaction that changes routing data advances this singleton before committing.

func (ChannelRoutingEpoch) TableName

func (ChannelRoutingEpoch) TableName() string

type ChannelRoutingOperation

type ChannelRoutingOperation struct {
	OperationType string `json:"operation_type" gorm:"type:varchar(32);primaryKey"`
	OperationKey  string `json:"operation_key" gorm:"type:varchar(128);primaryKey"`
	Fingerprint   string `json:"fingerprint" gorm:"type:char(64);not null"`
	Result        string `json:"result" gorm:"type:text;not null"`
	CreatedAt     int64  `json:"created_at" gorm:"type:bigint;not null"`
	UpdatedAt     int64  `json:"updated_at" gorm:"type:bigint;not null"`
}

ChannelRoutingOperation stores only completed operations. The row, channel mutation, ability mutation, result, and routing epoch commit atomically.

func (ChannelRoutingOperation) TableName

func (ChannelRoutingOperation) TableName() string

type ChannelRoutingPolicy

type ChannelRoutingPolicy struct {
	Rejected []ChannelRoutingCandidate
	Tiers    []ChannelRoutingTier
}

ChannelRoutingPolicy is ordered from the highest priority tier to the lowest.

func BuildChannelRoutingPolicy

func BuildChannelRoutingPolicy(candidates []ChannelRoutingCandidate) ChannelRoutingPolicy

BuildChannelRoutingPolicy applies the routing contract without reading state: priorities are fallback tiers, all-zero tiers are shared equally, and zero weight candidates receive no traffic when any positive weight is present.

func GetChannelRoutingPolicy

func GetChannelRoutingPolicy(group string, modelName string, requestPath string) (ChannelRoutingPolicy, error)

func ReadAssignedAccessRoutingPolicy

func ReadAssignedAccessRoutingPolicy(group, modelName, requestPath string) (ChannelRoutingPolicy, error)

ReadAssignedAccessRoutingPolicy reuses the runtime candidate query without its lazy routing-schema initialization. Access previews must perform reads only, including when this is the first request after startup.

type ChannelRoutingPolicySnapshot

type ChannelRoutingPolicySnapshot struct {
	Policy                ChannelRoutingPolicy
	Source                string
	Generation            int64
	DataGeneration        uint64
	PublishedGeneration   uint64
	ClusterCommittedEpoch int64
	LocalPublishedEpoch   int64
	CacheEnabled          bool
	CachePending          bool
}

ChannelRoutingPolicySnapshot identifies the source and committed generation used to construct a runtime routing policy.

func GetRuntimeChannelRoutingPolicy

func GetRuntimeChannelRoutingPolicy(group string, modelName string, requestPath string) (ChannelRoutingPolicySnapshot, error)

GetRuntimeChannelRoutingPolicy returns the same routing view used by runtime selection. Cache-backed reads use one last-good published snapshot; database reads use one joined statement for channels and abilities.

type ChannelRoutingTier

type ChannelRoutingTier struct {
	Priority   int64
	Candidates []ChannelRoutingCandidatePolicy
}

ChannelRoutingTier is one priority fallback layer. Higher priority tiers are attempted before lower priority tiers.

type ChannelSortOptions

type ChannelSortOptions struct {
	SortBy    string
	SortOrder string
	IDSort    bool
}

func NewChannelSortOptions

func NewChannelSortOptions(sortBy string, sortOrder string, idSort bool) ChannelSortOptions

func (ChannelSortOptions) Apply

func (options ChannelSortOptions) Apply(query *gorm.DB) *gorm.DB

type ChannelTestOptions

type ChannelTestOptions struct {
	Model        string `json:"model"`
	EndpointType string `json:"endpoint_type"`
	Stream       bool   `json:"stream"`
	ChannelType  int    `json:"channel_type"`
}

ChannelTestOptions contains only the non-secret choices that made a manual channel test succeed. Keeping them on the channel row avoids browser-local behavior differences between administrators or application instances.

func GetLastSuccessfulChannelTestOptions

func GetLastSuccessfulChannelTestOptions(channelID int) (*ChannelTestOptions, error)

type Checkin

type Checkin struct {
	Id           int    `json:"id" gorm:"primaryKey;autoIncrement"`
	UserId       int    `json:"user_id" gorm:"not null;uniqueIndex:idx_user_checkin_date"`
	CheckinDate  string `json:"checkin_date" gorm:"type:varchar(10);not null;uniqueIndex:idx_user_checkin_date"` // 格式: YYYY-MM-DD
	QuotaAwarded int    `json:"quota_awarded" gorm:"not null"`
	CreatedAt    int64  `json:"created_at" gorm:"bigint"`
}

Checkin 签到记录

func GetUserCheckinRecords

func GetUserCheckinRecords(userId int, startDate, endDate string) ([]Checkin, error)

GetUserCheckinRecords 获取用户在指定日期范围内的签到记录

func UserCheckin

func UserCheckin(userId int) (*Checkin, error)

UserCheckin 执行用户签到。签到记录、额度及 authoritative receipt 在同一事务内提交,适用于 SQLite、MySQL 和 PostgreSQL。

func (Checkin) TableName

func (Checkin) TableName() string

type CheckinRecord

type CheckinRecord struct {
	CheckinDate  string `json:"checkin_date"`
	QuotaAwarded int    `json:"quota_awarded"`
}

CheckinRecord 用于API返回的签到记录(不包含敏感字段)

type ClickHouseProjectionMutation

type ClickHouseProjectionMutation struct {
	MutationID       string    `gorm:"column:mutation_id"`
	Command          string    `gorm:"column:command"`
	CreateTime       time.Time `gorm:"column:create_time"`
	IsDone           uint8     `gorm:"column:is_done"`
	LatestFailReason string    `gorm:"column:latest_fail_reason"`
}

func FindClickHouseCanonicalProjectionMutations

func FindClickHouseCanonicalProjectionMutations(ctx context.Context, db *gorm.DB, requestedAtMillis int64) ([]ClickHouseProjectionMutation, error)

func GetClickHouseCanonicalProjectionMutation

func GetClickHouseCanonicalProjectionMutation(ctx context.Context, db *gorm.DB, mutationID string) (*ClickHouseProjectionMutation, error)

type CodexQuotaRouteState

type CodexQuotaRouteState struct {
	ReasonCode string
	Blocked    bool
	ResetAt    int64
	ObservedAt int64
	Source     string
}

func ReadCodexQuotaRouteState

func ReadCodexQuotaRouteState(ctx context.Context, db *gorm.DB, subjectRef, legacyAccountRef string, now int64) (CodexQuotaRouteState, error)

ReadCodexQuotaRouteState uses confirmed account observations and exact limit markers. Read errors are returned to routing callers for a fail-closed decision.

type CreemPaymentSource

type CreemPaymentSource struct{ ProductID, OrderProductID, Currency string }

type CustomOAuthProvider

type CustomOAuthProvider struct {
	Id                    int    `json:"id" gorm:"primaryKey"`
	Name                  string `json:"name" gorm:"type:varchar(64);not null"`                          // Display name, e.g., "GitHub Enterprise"
	Slug                  string `json:"slug" gorm:"type:varchar(64);uniqueIndex;not null"`              // URL identifier, e.g., "github-enterprise"
	Icon                  string `json:"icon" gorm:"type:varchar(128);default:''"`                       // Icon name from @lobehub/icons
	Enabled               bool   `json:"enabled" gorm:"default:false"`                                   // Whether this provider is enabled
	ClientId              string `json:"client_id" gorm:"type:varchar(256)"`                             // OAuth client ID
	ClientSecret          string `json:"-" gorm:"type:varchar(512)"`                                     // OAuth client secret (not returned to frontend)
	AuthorizationEndpoint string `json:"authorization_endpoint" gorm:"type:varchar(512)"`                // Authorization URL
	TokenEndpoint         string `json:"token_endpoint" gorm:"type:varchar(512)"`                        // Token exchange URL
	UserInfoEndpoint      string `json:"user_info_endpoint" gorm:"type:varchar(512)"`                    // User info URL
	Scopes                string `json:"scopes" gorm:"type:varchar(256);default:'openid profile email'"` // OAuth scopes

	// Field mapping configuration (supports JSONPath via gjson)
	UserIdField      string `json:"user_id_field" gorm:"type:varchar(128);default:'sub'"`                 // User ID field path, e.g., "sub", "id", "data.user.id"
	UsernameField    string `json:"username_field" gorm:"type:varchar(128);default:'preferred_username'"` // Username field path
	DisplayNameField string `json:"display_name_field" gorm:"type:varchar(128);default:'name'"`           // Display name field path
	EmailField       string `json:"email_field" gorm:"type:varchar(128);default:'email'"`                 // Email field path

	// Advanced options
	WellKnown           string `json:"well_known" gorm:"type:varchar(512)"`            // OIDC discovery endpoint (optional)
	AuthStyle           int    `json:"auth_style" gorm:"default:0"`                    // 0=auto, 1=params, 2=header (Basic Auth)
	AccessPolicy        string `json:"access_policy" gorm:"type:text"`                 // JSON policy for access control based on user info
	AccessDeniedMessage string `json:"access_denied_message" gorm:"type:varchar(512)"` // Custom error message template when access is denied

	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`
}

CustomOAuthProvider stores configuration for custom OAuth providers

func GetAllCustomOAuthProviders

func GetAllCustomOAuthProviders() ([]*CustomOAuthProvider, error)

GetAllCustomOAuthProviders returns all custom OAuth providers

func GetCustomOAuthProviderById

func GetCustomOAuthProviderById(id int) (*CustomOAuthProvider, error)

GetCustomOAuthProviderById returns a custom OAuth provider by ID

func GetCustomOAuthProviderBySlug

func GetCustomOAuthProviderBySlug(slug string) (*CustomOAuthProvider, error)

GetCustomOAuthProviderBySlug returns a custom OAuth provider by slug

func GetEnabledCustomOAuthProviders

func GetEnabledCustomOAuthProviders() ([]*CustomOAuthProvider, error)

GetEnabledCustomOAuthProviders returns all enabled custom OAuth providers

func (CustomOAuthProvider) TableName

func (CustomOAuthProvider) TableName() string

type DurableQuotaWriteAudit

type DurableQuotaWriteAudit struct {
	CanEnable                bool                      `json:"can_enable"`
	State                    *QuotaWriterEpoch         `json:"state,omitempty"`
	Writers                  []QuotaWriterRegistration `json:"writers"`
	AllWritersMigrated       bool                      `json:"all_writers_migrated"`
	BatchQueueEmpty          bool                      `json:"batch_queue_empty"`
	ProjectionPending        int64                     `json:"projection_pending"`
	BalanceDrainPending      int64                     `json:"balance_drain_pending"`
	BalanceDrainInflightZero bool                      `json:"balance_drain_inflight_zero"`
	MaintenanceBackfillDone  bool                      `json:"maintenance_backfill_done"`
	RedisEpochConsistent     bool                      `json:"redis_epoch_consistent"`
	ClusterDrainAck          bool                      `json:"cluster_drain_ack"`
	InflightSessions         int64                     `json:"inflight_sessions"`
	InflightZero             bool                      `json:"inflight_zero"`
	MissingOrFailedChecks    []string                  `json:"missing_or_failed_checks,omitempty"`
}

func CanEnableDurableQuotaWrites

func CanEnableDurableQuotaWrites(ctx context.Context, db *gorm.DB) (DurableQuotaWriteAudit, error)

CanEnableDurableQuotaWrites is a fail-closed audit only. It never changes a gate, mode, epoch, cache, queue, or obligation.

type ExternalIdentityClaim

type ExternalIdentityClaim struct {
	Id        int64     `json:"id" gorm:"primaryKey"`
	Provider  string    `` /* 151-byte string literal not displayed */
	Subject   string    `json:"subject" gorm:"type:varchar(128);not null;uniqueIndex:idx_external_identity_subject,priority:2"`
	UserId    int       `json:"user_id" gorm:"not null;index;uniqueIndex:idx_external_identity_user,priority:2"`
	CreatedAt time.Time `json:"created_at"`
}

ExternalIdentityClaim is the durable ownership record for an identity issued by an external provider. The two unique indexes make both the provider subject and the user's provider slot single-owner without relying on a check-then-update sequence.

func (ExternalIdentityClaim) TableName

func (ExternalIdentityClaim) TableName() string

type FeeBudgetPolicyInput

type FeeBudgetPolicyInput struct {
	Enabled  bool   `json:"enabled"`
	LimitUSD string `json:"limit_usd"`
}

type FlowQuotaData

type FlowQuotaData struct {
	UserID      int    `json:"user_id,omitempty" gorm:"column:user_id"`
	Username    string `json:"username,omitempty" gorm:"column:username"`
	NodeName    string `json:"node_name,omitempty" gorm:"column:node_name"`
	TokenID     int    `json:"token_id,omitempty" gorm:"column:token_id"`
	TokenName   string `json:"token_name,omitempty" gorm:"-"`
	UseGroup    string `json:"use_group" gorm:"column:use_group"`
	ChannelID   int    `json:"channel_id,omitempty" gorm:"column:channel_id"`
	ChannelName string `json:"channel_name,omitempty" gorm:"-"`
	ModelName   string `json:"model_name" gorm:"column:model_name"`
	TokenUsed   int    `json:"token_used" gorm:"column:token_used"`
	Count       int    `json:"count" gorm:"column:count"`
	Quota       int    `json:"quota" gorm:"column:quota"`
}

func GetFlowQuotaData

func GetFlowQuotaData(startTime int64, endTime int64, username string, userID int, role int) ([]*FlowQuotaData, error)

type InviteRewardGrant

type InviteRewardGrant struct {
	Id        int   `json:"id" gorm:"primaryKey;autoIncrement"`
	InviterId int   `json:"inviter_id" gorm:"not null;index;uniqueIndex:uidx_invite_reward_grant_pair,priority:1"`
	InviteeId int   `json:"invitee_id" gorm:"not null;uniqueIndex:uidx_invite_reward_grant_pair,priority:2"`
	Quota     int   `json:"quota" gorm:"not null"`
	CreatedAt int64 `json:"created_at" gorm:"bigint"`
}

InviteRewardGrant is the durable, idempotent record of an inviter reward. The (inviter_id, invitee_id) unique index guarantees a repeated finishInsert/FinalizeOAuthUserCreation can never credit the inviter twice.

func (InviteRewardGrant) TableName

func (InviteRewardGrant) TableName() string

type JSONValue

type JSONValue json.RawMessage

JSONValue 基于 json.RawMessage 实现,支持从数据库的 []byte 和 string 两种类型读取

func (JSONValue) MarshalJSON

func (j JSONValue) MarshalJSON() ([]byte, error)

MarshalJSON 确保在对外编码时与 json.RawMessage 行为一致

func (*JSONValue) Scan

func (j *JSONValue) Scan(value interface{}) error

Scan 实现 sql.Scanner 接口,兼容不同驱动返回的类型

func (*JSONValue) UnmarshalJSON

func (j *JSONValue) UnmarshalJSON(data []byte) error

UnmarshalJSON 确保在对外解码时与 json.RawMessage 行为一致

func (JSONValue) Value

func (j JSONValue) Value() (driver.Value, error)

Value 实现 driver.Valuer 接口,用于数据库写入

type LegacyUsageReservation

type LegacyUsageReservation struct {
	UsagePolicyRevision int64  `json:"-" gorm:"type:bigint;not null;default:0"`
	ID                  int64  `json:"id" gorm:"primaryKey"`
	RequestID           string `json:"request_id" gorm:"type:varchar(64);not null;uniqueIndex"`
	UserID              int    `json:"user_id" gorm:"not null;index"`
	TokenID             int    `json:"token_id" gorm:"not null;index"`
	ChannelID           int    `json:"channel_id" gorm:"not null;default:0"`
	ModelName           string `json:"model_name" gorm:"size:512"`
	FundingSource       string `json:"funding_source" gorm:"type:varchar(32);not null"`
	SubscriptionID      int    `json:"subscription_id" gorm:"not null;default:0"`
	ReservedQuota       int64  `json:"reserved_quota" gorm:"type:bigint;not null"`
	TokenReservedQuota  int64  `json:"token_reserved_quota" gorm:"type:bigint;not null"`
	ActualQuota         *int64 `json:"actual_quota" gorm:"type:bigint"`
	State               string `json:"state" gorm:"type:varchar(16);not null;index"`
	Reason              string `json:"reason" gorm:"type:varchar(32);not null"`
	ReviewMetadata      string `json:"review_metadata,omitempty" gorm:"type:text"`
	ReviewedBy          int    `json:"reviewed_by" gorm:"not null;default:0"`
	EvidenceDigest      string `json:"evidence_digest" gorm:"type:varchar(64);not null;default:''"`
	LockVersion         int64  `json:"lock_version" gorm:"type:bigint;not null"`
	CreatedAt           int64  `json:"created_at" gorm:"type:bigint;not null"`
	UpdatedAt           int64  `json:"updated_at" gorm:"type:bigint;not null"`
}

LegacyUsageReservation preserves request identity before an upstream send. It is not a replacement balance ledger. All balance writes continue through existing settlement/refund facts. ReservedQuota is NOT a confirmed charge; ActualQuota remains NULL until a known settlement completes.

func ExtendLegacyUsageReservation

func ExtendLegacyUsageReservation(ctx context.Context, db *gorm.DB, requestID string, userID, tokenID int, target int64, applyToken bool) (*LegacyUsageReservation, error)

ExtendLegacyUsageReservation atomically raises an existing cumulative reservation. Its journal is also the idempotency key and the lock shared with manual usage recovery. No actual consumption is asserted here.

func FindLegacyUsageReservation

func FindLegacyUsageReservation(ctx context.Context, db *gorm.DB, requestID string) (*LegacyUsageReservation, error)

func PrepareLegacyUsageReservation

func PrepareLegacyUsageReservation(ctx context.Context, db *gorm.DB, input LegacyUsageReservation) (*LegacyUsageReservation, error)

func ResolveLegacyUnknownUsage

func ResolveLegacyUnknownUsage(ctx context.Context, db *gorm.DB, actorID int, requestID string, actual int64, evidenceDigest string) (*LegacyUsageReservation, error)

ResolveLegacyUnknownUsage persists the operator's exact decision before invoking the existing settlement-intent recovery path. A restart reuses that intent and never invents a new delta. It does not switch the quota writer.

func (LegacyUsageReservation) TableName

func (LegacyUsageReservation) TableName() string

type Log

type Log struct {
	Id                int    `json:"id" gorm:"index:idx_created_at_id,priority:2;index:idx_user_id_id,priority:2"`
	UserId            int    `json:"user_id" gorm:"index;index:idx_user_id_id,priority:1"`
	CreatedAt         int64  `json:"created_at" gorm:"bigint;index:idx_created_at_id,priority:1;index:idx_created_at_type"`
	Type              int    `json:"type" gorm:"index:idx_created_at_type"`
	Content           string `json:"content"`
	Username          string `json:"username" gorm:"index;index:index_username_model_name,priority:2;default:''"`
	TokenName         string `json:"token_name" gorm:"index;default:''"`
	ModelName         string `json:"model_name" gorm:"index;index:index_username_model_name,priority:1;default:''"`
	Quota             int    `json:"quota" gorm:"default:0"`
	PromptTokens      int    `json:"prompt_tokens" gorm:"default:0"`
	CompletionTokens  int    `json:"completion_tokens" gorm:"default:0"`
	UseTime           int    `json:"use_time" gorm:"default:0"`
	IsStream          bool   `json:"is_stream"`
	ChannelId         int    `json:"channel" gorm:"index"`
	ChannelName       string `json:"channel_name" gorm:"->"`
	TokenId           int    `json:"token_id" gorm:"default:0;index"`
	Group             string `json:"group" gorm:"index"`
	Ip                string `json:"ip" gorm:"index;default:''"`
	RequestId         string `json:"request_id,omitempty" gorm:"type:varchar(64);index:idx_logs_request_id;default:''"`
	UpstreamRequestId string `json:"upstream_request_id,omitempty" gorm:"type:varchar(128);index:idx_logs_upstream_request_id;default:''"`
	// BillingEventID is the stable at-least-once projection key emitted by the
	// main-database billing outbox. It is deliberately non-unique because a
	// log sink may replay delivery; query/export aggregation must deduplicate it.
	BillingEventID          string `json:"billing_event_id,omitempty" gorm:"type:varchar(64);index:idx_logs_billing_event_id;default:''"`
	BillingProjectionDigest string `json:"-" gorm:"column:billing_projection_digest;type:varchar(65);default:''"`
	LogRowKey               string `json:"-" gorm:"column:log_row_key;type:varchar(64);default:''"`
	Other                   string `json:"other"`
}

func GetAllLogs

func GetAllLogs(logType int, startTimestamp int64, endTimestamp int64, modelName string, username string, tokenName string, startIdx int, num int, channel int, group string, requestId string, upstreamRequestId string) (logs []*Log, total int64, err error)

func GetLogByTokenId

func GetLogByTokenId(tokenId int) (logs []*Log, err error)

func GetUserLogs

func GetUserLogs(userId int, logType int, startTimestamp int64, endTimestamp int64, modelName string, tokenName string, startIdx int, num int, group string, requestId string, upstreamRequestId string) (logs []*Log, total int64, err error)

func (*Log) BeforeCreate

func (log *Log) BeforeCreate(tx *gorm.DB) error

type LogCleanupBatchResult

type LogCleanupBatchResult struct {
	Deleted int64
	Skipped int64
	Errors  []string
}

func DeleteOldLogBatchDetailed

func DeleteOldLogBatchDetailed(ctx context.Context, targetTimestamp int64, limit int) (LogCleanupBatchResult, error)

type LogProjectionBackfillState

type LogProjectionBackfillState struct {
	TaskKey                string `json:"task_key" gorm:"type:varchar(64);primaryKey"`
	SchemaVersion          int    `json:"schema_version" gorm:"not null"`
	Phase                  string `json:"phase" gorm:"type:varchar(64);not null"`
	LastID                 int    `json:"last_id" gorm:"not null"`
	LastEventID            string `json:"last_event_id" gorm:"type:varchar(64);not null"`
	Status                 string `json:"status" gorm:"type:varchar(32);not null;index"`
	LastError              string `json:"last_error" gorm:"type:text"`
	MaterializeMutationID  string `json:"materialize_mutation_id" gorm:"type:varchar(128);not null"`
	MaterializeStatus      string `json:"materialize_status" gorm:"type:varchar(32);not null"`
	MaterializeGeneration  int64  `json:"materialize_generation" gorm:"bigint;not null"`
	MaterializeRequestedAt int64  `json:"materialize_requested_at" gorm:"bigint;not null"`
	QuarantinedEvents      int64  `json:"quarantined_events" gorm:"bigint;not null"`
	LockVersion            int64  `json:"lock_version" gorm:"bigint;not null;default:1"`
	UpdatedAt              int64  `json:"updated_at" gorm:"bigint;not null;index"`
	CompletedAt            int64  `json:"completed_at" gorm:"bigint;not null"`

	// Complete is an in-memory batch result retained for the lower-level
	// checkpoint helper. Durable completion is represented by Status/Phase.
	Complete bool `json:"-" gorm:"-"`
}

LogProjectionBackfillState is the single durable control row for the production log-projection migration. It lives in the primary database; historical log reads, writes, and DDL always run against the log database.

func BackfillClickHouseProjectionIdentityBatch

func BackfillClickHouseProjectionIdentityBatch(ctx context.Context, db *gorm.DB, state LogProjectionBackfillState, limit int) (LogProjectionBackfillState, int, error)

func BackfillLogProjectionIdentityBatch

func BackfillLogProjectionIdentityBatch(ctx context.Context, db *gorm.DB, state LogProjectionBackfillState, limit int) (LogProjectionBackfillState, int, error)

func GetLogProjectionBackfillState

func GetLogProjectionBackfillState(ctx context.Context, mainDB *gorm.DB) (*LogProjectionBackfillState, error)

func GetOrCreateLogProjectionBackfillState

func GetOrCreateLogProjectionBackfillState(ctx context.Context, mainDB *gorm.DB, logDB *gorm.DB) (*LogProjectionBackfillState, error)

func (*LogProjectionBackfillState) BeforeCreate

func (state *LogProjectionBackfillState) BeforeCreate(_ *gorm.DB) error

type LogProjectionIndexSpec

type LogProjectionIndexSpec struct {
	Name    string
	Columns string
}

type Midjourney

type Midjourney struct {
	Id          int    `json:"id"`
	Code        int    `json:"code"`
	UserId      int    `json:"user_id" gorm:"index"`
	Action      string `json:"action" gorm:"type:varchar(40);index"`
	MjId        string `json:"mj_id" gorm:"index"`
	Prompt      string `json:"prompt"`
	PromptEn    string `json:"prompt_en"`
	Description string `json:"description"`
	State       string `json:"state"`
	SubmitTime  int64  `json:"submit_time" gorm:"index"`
	StartTime   int64  `json:"start_time" gorm:"index"`
	FinishTime  int64  `json:"finish_time" gorm:"index"`
	ImageUrl    string `json:"image_url"`
	VideoUrl    string `json:"video_url"`
	VideoUrls   string `json:"video_urls"`
	Status      string `json:"status" gorm:"type:varchar(20);index"`
	Progress    string `json:"progress" gorm:"type:varchar(30);index"`
	FailReason  string `json:"fail_reason"`
	ChannelId   int    `json:"channel_id"`
	Quota       int    `json:"quota"`
	Buttons     string `json:"buttons"`
	Properties  string `json:"properties"`

	TokenId          int `json:"-" gorm:"default:0"`
	BillingChannelId int `json:"-" gorm:"default:0"`
}

func GetAllTasks

func GetAllTasks(startIdx int, num int, queryParams TaskQueryParams) []*Midjourney

func GetAllUnFinishTasks

func GetAllUnFinishTasks() []*Midjourney

func GetAllUserTask

func GetAllUserTask(userId int, startIdx int, num int, queryParams TaskQueryParams) []*Midjourney

func GetByMJId

func GetByMJId(userId int, mjId string) *Midjourney

func GetByMJIds

func GetByMJIds(userId int, mjIds []string) []*Midjourney

func GetByOnlyMJId

func GetByOnlyMJId(mjId string) *Midjourney

func GetMjByuId

func GetMjByuId(id int) *Midjourney

func (*Midjourney) GetBillingChannelId

func (midjourney *Midjourney) GetBillingChannelId() int

func (*Midjourney) Insert

func (midjourney *Midjourney) Insert() error

func (*Midjourney) Update

func (midjourney *Midjourney) Update() error

func (*Midjourney) UpdateBillingState

func (midjourney *Midjourney) UpdateBillingState() error

func (*Midjourney) UpdateWithStatus

func (midjourney *Midjourney) UpdateWithStatus(fromStatus string) (bool, error)

UpdateWithStatus performs a conditional UPDATE guarded by fromStatus (CAS). Returns (true, nil) if this caller won the update, (false, nil) if another process already moved the task out of fromStatus. UpdateWithStatus performs a conditional UPDATE guarded by fromStatus (CAS). Uses Model().Select("*").Updates() to avoid GORM Save()'s INSERT fallback.

type Model

type Model struct {
	Id           int            `json:"id"`
	ModelName    string         `json:"model_name" gorm:"size:128;not null;uniqueIndex:uk_model_name_delete_at,priority:1"`
	Description  string         `json:"description,omitempty" gorm:"type:text"`
	Icon         string         `json:"icon,omitempty" gorm:"type:varchar(128)"`
	Tags         string         `json:"tags,omitempty" gorm:"type:varchar(255)"`
	VendorID     int            `json:"vendor_id,omitempty" gorm:"index"`
	Endpoints    string         `json:"endpoints,omitempty" gorm:"type:text"`
	Status       int            `json:"status" gorm:"default:1"`
	SyncOfficial int            `json:"sync_official" gorm:"default:1"`
	CreatedTime  int64          `json:"created_time" gorm:"bigint"`
	UpdatedTime  int64          `json:"updated_time" gorm:"bigint"`
	DeletedAt    gorm.DeletedAt `json:"-" gorm:"index;uniqueIndex:uk_model_name_delete_at,priority:2"`

	BoundChannels []BoundChannel `json:"bound_channels,omitempty" gorm:"-"`
	EnableGroups  []string       `json:"enable_groups,omitempty" gorm:"-"`
	QuotaTypes    []int          `json:"quota_types,omitempty" gorm:"-"`
	NameRule      int            `json:"name_rule" gorm:"default:0"`

	MatchedModels []string `json:"matched_models,omitempty" gorm:"-"`
	MatchedCount  int      `json:"matched_count,omitempty" gorm:"-"`
}

func GetAllModels

func GetAllModels(offset int, limit int) ([]*Model, error)

func SearchModels

func SearchModels(keyword string, vendor string, status string, syncOfficial string, offset int, limit int) ([]*Model, int64, error)

func (*Model) Delete

func (mi *Model) Delete() error

func (*Model) Insert

func (mi *Model) Insert() error

func (*Model) Update

func (mi *Model) Update() error

type ModelPricingSnapshot

type ModelPricingSnapshot struct {
	Unavailable          bool
	Billing              billing_setting.BillingSnapshot
	ModelPrice           float64
	HasModelPrice        bool
	ModelRatio           float64
	HasModelRatio        bool
	MatchingModelName    string
	CompletionRatio      float64
	CacheRatio           float64
	CacheCreationRatio   float64
	ImageRatio           float64
	AudioRatio           float64
	AudioCompletionRatio float64
}

func CaptureModelPricingSnapshot

func CaptureModelPricingSnapshot(modelName string) ModelPricingSnapshot

CaptureModelPricingSnapshot pairs the billing-mode generation with all ratio fields used to estimate and later settle one model request.

type OfficialPriceVersion

type OfficialPriceVersion struct {
	ContentSHA256 string `gorm:"primaryKey;size:64"`
	Document      string `gorm:"size:1048576"`
	FetchedAt     int64
}

Natural content-addressed primary key. No mutable published-price fields: storing source evidence cannot change the effective price generation.

func GetOfficialPriceVersion

func GetOfficialPriceVersion(ctx context.Context, db *gorm.DB, digest string) (*OfficialPriceVersion, error)

func StoreOfficialPriceVersion

func StoreOfficialPriceVersion(ctx context.Context, db *gorm.DB, document string, fetchedAt int64) (*OfficialPriceVersion, error)

type OpenAIPriceCheckResult

type OpenAIPriceCheckResult struct {
	CheckedAt       int64  `json:"checked_at"`
	SourceSHA256    string `json:"source_sha256"`
	SourceFetchedAt int64  `json:"source_fetched_at"`
}

CheckedAt records a successful observation, independently of the immutable source version's first fetch time and of any administrator publication.

type Option

type Option struct {
	Key   string `json:"key" gorm:"primaryKey"`
	Value string `json:"value"`
}

func AllOption

func AllOption() ([]*Option, error)

type OptionDiagnosticAliasAssessment

type OptionDiagnosticAliasAssessment struct {
	Name            string
	Keys            []string
	Status          string
	EffectiveSource string
}

OptionDiagnosticAliasAssessment is metadata derived from the existing GroupRatio load precedence. It contains neither raw source nor normalized values.

func AssessOptionDiagnosticAliasGroups

func AssessOptionDiagnosticAliasGroups(rows []OptionDiagnosticRow, complete bool) []OptionDiagnosticAliasAssessment

AssessOptionDiagnosticAliasGroups mirrors publishLoadedGroupRatioOptionPair without publishing, logging, or exposing raw/normalized values.

type OptionDiagnosticRow

type OptionDiagnosticRow struct {
	Key         string         `gorm:"column:key" json:"-"`
	KeyTooLarge bool           `gorm:"column:key_too_large" json:"-"`
	Value       sql.NullString `gorm:"column:value" json:"-"`
	TooLarge    bool           `gorm:"column:too_large" json:"-"`
}

OptionDiagnosticRow is a bounded database-only representation. Value is intentionally not serialized and must not leave the service layer.

func ReadOptionDiagnosticRows

func ReadOptionDiagnosticRows() ([]OptionDiagnosticRow, bool, error)

ReadOptionDiagnosticRows performs the diagnostics' sole primary-database operation. SUBSTR is supported by SQLite, MySQL, and PostgreSQL. Keys are projected at their safe maximum and an independent one-character probe marks truncation; values retain one extra parse character to preserve the existing size-state contract. All SQL identifiers and limits are implementation constants.

type OptionRemediation

type OptionRemediation struct {
	Id             int64  `json:"id" gorm:"primaryKey"`
	OperatorUserId int    `json:"operator_user_id" gorm:"not null;index"`
	Action         string `json:"action" gorm:"type:varchar(64);not null"`
	TargetKey      string `json:"target_key" gorm:"type:varchar(256);not null"`
	OldValueHash   string `json:"old_value_hash" gorm:"type:varchar(80);not null;default:''"`
	NewValueHash   string `json:"new_value_hash" gorm:"type:varchar(80);not null;default:''"`
	BackupId       int64  `json:"backup_id" gorm:"not null;default:0"`
	Status         string `json:"status" gorm:"type:varchar(16);not null;index"`
	Reason         string `json:"reason" gorm:"type:varchar(512);not null;default:''"`
	CreatedAt      int64  `json:"created_at" gorm:"type:bigint;not null"`
	AppliedAt      int64  `json:"applied_at" gorm:"type:bigint;not null;default:0"`
}

OptionRemediation is the durable registry of one remediation judgment outcome. It stores hashes and a backup reference only; option values never appear here. Status "previewed" is reserved for future persisted previews: the N5b dry-run writes nothing, so only applied/skipped/failed are stored.

func ListOptionRemediations

func ListOptionRemediations(db *gorm.DB, startIdx int, pageSize int) ([]OptionRemediation, int64, error)

func (OptionRemediation) TableName

func (OptionRemediation) TableName() string

type OptionRemediationApplyItem

type OptionRemediationApplyItem struct {
	Key                  string `json:"key"`
	Action               string `json:"action"`
	ExpectedOldValueHash string `json:"expected_old_value_hash"`
	ExpectedNewValueHash string `json:"expected_new_value_hash"`
}

OptionRemediationApplyItem is one caller-claimed action instance exactly as a dry-run produced it. ExpectedOldValueHash is empty only for the create-absent-canonical case.

type OptionRemediationBackup

type OptionRemediationBackup struct {
	Id           int64  `json:"id" gorm:"primaryKey"`
	TargetKey    string `json:"target_key" gorm:"type:varchar(256);not null"`
	OldValue     string `json:"-" gorm:"type:text"`
	OldValueHash string `json:"old_value_hash" gorm:"type:varchar(80);not null;default:''"`
	CreatedAt    int64  `json:"created_at" gorm:"type:bigint;not null"`
}

OptionRemediationBackup is the same-transaction pre-write value snapshot. OldValue is database-only evidence: it is never serialized and never leaves the model layer through any API or log channel.

func (OptionRemediationBackup) TableName

func (OptionRemediationBackup) TableName() string

type OptionRemediationCoverage

type OptionRemediationCoverage struct {
	RowsScanned int  `json:"rows_scanned"`
	RowLimit    int  `json:"row_limit"`
	Complete    bool `json:"complete"`
}

OptionRemediationCoverage reports how the planning snapshot was obtained.

type OptionRemediationPlan

type OptionRemediationPlan struct {
	Key          string
	KeyClass     string
	Action       string
	Decision     string
	Reason       string
	Risk         string
	ValueState   string
	Validation   string
	OldValueHash string
	NewValueHash string
	// contains filtered or unexported fields
}

OptionRemediationPlan is one per-row judgment. oldValue/newValue hold the exact bytes involved in the write; they are unexported so the service and controller layers can only ever observe their hashes.

type OptionRemediationResult

type OptionRemediationResult struct {
	Key           string `json:"key"`
	Action        string `json:"action"`
	Status        string `json:"status"`
	Reason        string `json:"reason"`
	OldValueHash  string `json:"old_value_hash"`
	NewValueHash  string `json:"new_value_hash"`
	RemediationId int64  `json:"remediation_id"`
}

OptionRemediationResult is the per-row apply outcome.

func ApplyOptionRemediations

func ApplyOptionRemediations(operatorUserId int, items []OptionRemediationApplyItem) ([]OptionRemediationResult, error)

ApplyOptionRemediations applies claimed action instances row by row. Every row is independent: the judgment is rebuilt from the current row, verified against the claimed hashes, written in its own transaction together with the backup and registry rows, and published after its commit. A skipped or failed row never pretends the batch was atomic.

type PasskeyCredential

type PasskeyCredential struct {
	ID              int            `json:"id" gorm:"primaryKey"`
	UserID          int            `json:"user_id" gorm:"uniqueIndex;not null"`
	CredentialID    string         `json:"credential_id" gorm:"type:varchar(512);uniqueIndex;not null"` // base64 encoded
	PublicKey       string         `json:"public_key" gorm:"type:text;not null"`                        // base64 encoded
	AttestationType string         `json:"attestation_type" gorm:"type:varchar(255)"`
	AAGUID          string         `json:"aaguid" gorm:"type:varchar(512)"` // base64 encoded
	SignCount       uint32         `json:"sign_count" gorm:"default:0"`
	CloneWarning    bool           `json:"clone_warning"`
	UserPresent     bool           `json:"user_present"`
	UserVerified    bool           `json:"user_verified"`
	BackupEligible  bool           `json:"backup_eligible"`
	BackupState     bool           `json:"backup_state"`
	Transports      string         `json:"transports" gorm:"type:text"`
	Attachment      string         `json:"attachment" gorm:"type:varchar(32)"`
	LastUsedAt      *time.Time     `json:"last_used_at"`
	CreatedAt       time.Time      `json:"created_at"`
	UpdatedAt       time.Time      `json:"updated_at"`
	DeletedAt       gorm.DeletedAt `json:"-" gorm:"index"`
}

func GetPasskeyByCredentialID

func GetPasskeyByCredentialID(credentialID []byte) (*PasskeyCredential, error)

func GetPasskeyByUserID

func GetPasskeyByUserID(userID int) (*PasskeyCredential, error)

func NewPasskeyCredentialFromWebAuthn

func NewPasskeyCredentialFromWebAuthn(userID int, credential *webauthn.Credential) *PasskeyCredential

func (*PasskeyCredential) SetTransports

func (p *PasskeyCredential) SetTransports(list []protocol.AuthenticatorTransport)

func (*PasskeyCredential) ToWebAuthnCredential

func (p *PasskeyCredential) ToWebAuthnCredential() webauthn.Credential

func (*PasskeyCredential) TransportList

func (p *PasskeyCredential) TransportList() []protocol.AuthenticatorTransport

type PerfMetric

type PerfMetric struct {
	Id             int    `json:"id" gorm:"primaryKey"`
	ModelName      string `json:"model_name" gorm:"size:128;uniqueIndex:idx_perf_model_group_bucket,priority:1"`
	Group          string `json:"group" gorm:"column:group;size:64;uniqueIndex:idx_perf_model_group_bucket,priority:2"`
	BucketTs       int64  `json:"bucket_ts" gorm:"uniqueIndex:idx_perf_model_group_bucket,priority:3;index:idx_perf_bucket_ts"`
	RequestCount   int64  `json:"-" gorm:"default:0"`
	SuccessCount   int64  `json:"-" gorm:"default:0"`
	TotalLatencyMs int64  `json:"-" gorm:"default:0"`
	TtftSumMs      int64  `json:"-" gorm:"default:0"`
	TtftCount      int64  `json:"-" gorm:"default:0"`
	OutputTokens   int64  `json:"-" gorm:"default:0"`
	GenerationMs   int64  `json:"-" gorm:"default:0"`
}

PerfMetric stores aggregated relay performance metrics for the model square.

func GetPerfMetrics

func GetPerfMetrics(modelName string, group string, startTs int64, endTs int64) ([]PerfMetric, error)

func (PerfMetric) TableName

func (PerfMetric) TableName() string

type PerfMetricSummary

type PerfMetricSummary struct {
	ModelName      string `json:"model_name"`
	RequestCount   int64  `json:"request_count"`
	SuccessCount   int64  `json:"success_count"`
	TotalLatencyMs int64  `json:"total_latency_ms"`
	OutputTokens   int64  `json:"output_tokens"`
	GenerationMs   int64  `json:"generation_ms"`
}

func GetPerfMetricsSummaryAll

func GetPerfMetricsSummaryAll(startTs int64, endTs int64, groups []string) ([]PerfMetricSummary, error)

type PerfMetricSummaryBucket

type PerfMetricSummaryBucket struct {
	ModelName      string `json:"model_name"`
	BucketTs       int64  `json:"bucket_ts"`
	RequestCount   int64  `json:"request_count"`
	SuccessCount   int64  `json:"success_count"`
	TotalLatencyMs int64  `json:"total_latency_ms"`
	OutputTokens   int64  `json:"output_tokens"`
	GenerationMs   int64  `json:"generation_ms"`
}

func GetPerfMetricsSummaryBucketsAll

func GetPerfMetricsSummaryBucketsAll(startTs int64, endTs int64, groups []string) ([]PerfMetricSummaryBucket, error)

type PrefillGroup

type PrefillGroup struct {
	Id          int            `json:"id"`
	Name        string         `json:"name" gorm:"size:64;not null;uniqueIndex:uk_prefill_name,where:deleted_at IS NULL"`
	Type        string         `json:"type" gorm:"size:32;index;not null"`
	Items       JSONValue      `json:"items" gorm:"type:json"`
	Description string         `json:"description,omitempty" gorm:"type:varchar(255)"`
	CreatedTime int64          `json:"created_time" gorm:"bigint"`
	UpdatedTime int64          `json:"updated_time" gorm:"bigint"`
	DeletedAt   gorm.DeletedAt `json:"-" gorm:"index"`
}

func GetAllPrefillGroups

func GetAllPrefillGroups(groupType string) ([]*PrefillGroup, error)

GetAllPrefillGroups 获取全部组,可按类型过滤(为空则返回全部)

func (*PrefillGroup) Insert

func (g *PrefillGroup) Insert() error

Insert 新建组

func (*PrefillGroup) Update

func (g *PrefillGroup) Update() error

Update 更新组

type PricePublication

type PricePublication struct {
	ID            string `gorm:"primaryKey;size:64" json:"id"`
	RequestDigest string `gorm:"size:64" json:"request_digest"`
	ActorID       int    `json:"actor_id"`
	Action        string `gorm:"size:16" json:"action"`
	RollbackOf    string `gorm:"size:64" json:"rollback_of,omitempty"`
	BeforeJSON    string `gorm:"size:1048576" json:"-"`
	AfterJSON     string `gorm:"size:1048576" json:"-"`
	CreatedAt     int64  `json:"created_at"`
	Revision      int64  `json:"revision"`
}

PricePublication is immutable. The before/after evidence includes the whole pricing generation; rollback requires an exact match, so it cannot overwrite intervening manual changes, including changes to unselected models.

func ApplyPricePublication

func ApplyPricePublication(ctx context.Context, command PricePublicationCommand) (*PricePublication, error)

func (*PricePublication) BeforeDelete

func (*PricePublication) BeforeDelete(*gorm.DB) error

func (*PricePublication) BeforeUpdate

func (*PricePublication) BeforeUpdate(*gorm.DB) error

type PricePublicationChange

type PricePublicationChange struct {
	Model        string `json:"model"`
	Expression   string `json:"expression"`
	SourceSHA256 string `json:"source_sha256"`
	Locked       bool   `json:"locked"`
}

type PricePublicationCommand

type PricePublicationCommand struct {
	ID             string                   `json:"id"`
	ActorID        int                      `json:"actor_id"`
	ExpectedDigest string                   `json:"expected_digest"`
	Action         string                   `json:"action"`
	RollbackOf     string                   `json:"rollback_of,omitempty"`
	Changes        []PricePublicationChange `json:"changes,omitempty"`
}

Expression/source pairs are server-built service inputs, never accepted directly as rates by the public controller.

type PricePublicationSnapshot

type PricePublicationSnapshot struct {
	Modes             map[string]string     `json:"modes"`
	Expressions       map[string]string     `json:"expressions"`
	State             PricePublicationState `json:"state"`
	OtherPriceOptions map[string]string     `json:"other_price_options"`
}

func ReadPricePublicationSnapshot

func ReadPricePublicationSnapshot(ctx context.Context) (*PricePublicationSnapshot, error)

func (PricePublicationSnapshot) Digest

func (s PricePublicationSnapshot) Digest() (string, error)

type PricePublicationState

type PricePublicationState struct {
	Revision int64                          `json:"revision"`
	Models   map[string]PublishedModelPrice `json:"models"`
}

type Pricing

type Pricing struct {
	ModelName              string                  `json:"model_name"`
	Description            string                  `json:"description,omitempty"`
	Icon                   string                  `json:"icon,omitempty"`
	Tags                   string                  `json:"tags,omitempty"`
	VendorID               int                     `json:"vendor_id,omitempty"`
	QuotaType              int                     `json:"quota_type"`
	ModelRatio             float64                 `json:"model_ratio"`
	ModelPrice             float64                 `json:"model_price"`
	OwnerBy                string                  `json:"owner_by"`
	CompletionRatio        float64                 `json:"completion_ratio"`
	CacheRatio             *float64                `json:"cache_ratio,omitempty"`
	CreateCacheRatio       *float64                `json:"create_cache_ratio,omitempty"`
	ImageRatio             *float64                `json:"image_ratio,omitempty"`
	AudioRatio             *float64                `json:"audio_ratio,omitempty"`
	AudioCompletionRatio   *float64                `json:"audio_completion_ratio,omitempty"`
	EnableGroup            []string                `json:"enable_groups"`
	SupportedEndpointTypes []constant.EndpointType `json:"supported_endpoint_types"`
	BillingMode            string                  `json:"billing_mode,omitempty"`
	BillingExpr            string                  `json:"billing_expr,omitempty"`
	PricingVersion         string                  `json:"pricing_version,omitempty"`
}

func GetPricing

func GetPricing() []Pricing

type PricingVendor

type PricingVendor struct {
	ID          int    `json:"id"`
	Name        string `json:"name"`
	Description string `json:"description,omitempty"`
	Icon        string `json:"icon,omitempty"`
}

func GetVendors

func GetVendors() []PricingVendor

GetVendors 返回当前定价接口使用到的供应商信息

type PromptInstructionApplication

type PromptInstructionApplication struct {
	ID                      int64  `gorm:"primaryKey"`
	UserID                  int    `gorm:"not null;uniqueIndex:idx_prompt_instruction_application_command,priority:1;index"`
	ScopeRef                string `gorm:"type:varchar(128);not null;uniqueIndex:idx_prompt_instruction_application_command,priority:2;index"`
	CommandID               string `gorm:"type:varchar(128);not null;uniqueIndex:idx_prompt_instruction_application_command,priority:3"`
	VersionID               int64  `gorm:"type:bigint;not null;index"`
	TargetReceipt           string `gorm:"type:char(64);not null;index"`
	AuthorizationGeneration int64  `gorm:"type:bigint;not null"`
	AuthorizationExpiresAt  int64  `gorm:"type:bigint;not null;index"`
	State                   string `gorm:"type:varchar(24);not null;index"`
	BackupReceipt           string `gorm:"type:char(64);not null;default:''"`
	AppliedContentHash      string `gorm:"type:char(64);not null;default:''"`
	RollbackOfID            *int64 `gorm:"type:bigint;index"`
	LockVersion             int64  `gorm:"type:bigint;not null"`
	CreatedBy               int    `gorm:"not null"`
	CreatedAt               int64  `gorm:"type:bigint;not null;index"`
	UpdatedAt               int64  `gorm:"type:bigint;not null"`
}

PromptInstructionApplication is a durable request to apply or roll back an immutable version. TargetReceipt and backup receipt are HMAC-derived opaque references; this table never stores a host path, a file body or credentials. The actual filesystem bridge remains a separate P4 responsibility.

func CreatePromptInstructionApplication

func CreatePromptInstructionApplication(ctx context.Context, input PromptInstructionApplicationInput) (*PromptInstructionApplication, bool, error)

CreatePromptInstructionApplication records a future application request only when its policy is still enabled and its exact generation is current. The executor must recheck these values before touching any authorized file.

func (PromptInstructionApplication) TableName

type PromptInstructionApplicationInput

type PromptInstructionApplicationInput struct {
	UserID                  int
	ScopeRef                string
	CommandID               string
	VersionID               int64
	TargetReceipt           string
	AuthorizationGeneration int64
	AuthorizationExpiresAt  int64
	RollbackOfID            *int64
	CreatedBy               int
}

type PromptInstructionVersion

type PromptInstructionVersion struct {
	ID          int64  `gorm:"primaryKey"`
	UserID      int    `gorm:"not null;uniqueIndex:idx_prompt_instruction_command,priority:1;index"`
	ScopeRef    string `gorm:"type:varchar(128);not null;uniqueIndex:idx_prompt_instruction_command,priority:2;index"`
	CommandID   string `gorm:"type:varchar(128);not null;uniqueIndex:idx_prompt_instruction_command,priority:3"`
	ParentID    *int64 `gorm:"type:bigint;index"`
	Content     string `gorm:"type:text;not null"`
	ContentHash string `gorm:"type:char(64);not null;index"`
	Source      string `gorm:"type:varchar(16);not null"`
	CreatedBy   int    `gorm:"not null"`
	CreatedAt   int64  `gorm:"type:bigint;not null;index"`
}

PromptInstructionVersion is an immutable, scope-isolated instruction text. Manual edits and future generated drafts both append a new version; they cannot overwrite a reviewed historical version. CommandID is a caller's stable idempotency key, never an instruction body or filesystem path.

func CreatePromptInstructionVersion

func CreatePromptInstructionVersion(ctx context.Context, input PromptInstructionVersionInput) (*PromptInstructionVersion, bool, error)

CreatePromptInstructionVersion appends one immutable manual or generated version. Retried commands return their original version only when every immutable field agrees; a reuse with different content or parent is a conflict and never replaces the previous version.

func GetPromptInstructionVersion

func GetPromptInstructionVersion(ctx context.Context, userID int, scopeRef string, versionID int64) (*PromptInstructionVersion, error)

func ListPromptInstructionVersions

func ListPromptInstructionVersions(ctx context.Context, userID int, scopeRef string, offset, limit int) ([]PromptInstructionVersion, int64, error)

func (*PromptInstructionVersion) BeforeDelete

func (*PromptInstructionVersion) BeforeDelete(*gorm.DB) error

func (*PromptInstructionVersion) BeforeUpdate

func (*PromptInstructionVersion) BeforeUpdate(*gorm.DB) error

func (PromptInstructionVersion) TableName

func (PromptInstructionVersion) TableName() string

type PromptInstructionVersionInput

type PromptInstructionVersionInput struct {
	UserID    int
	ScopeRef  string
	CommandID string
	ParentID  *int64
	Content   string
	Source    string
	CreatedBy int
}

type PromptLearningPolicy

type PromptLearningPolicy struct {
	ID         int64  `gorm:"primaryKey"`
	UserID     int    `gorm:"not null;uniqueIndex:idx_prompt_learning_policy_scope,priority:1;index"`
	ScopeRef   string `gorm:"type:varchar(128);not null;uniqueIndex:idx_prompt_learning_policy_scope,priority:2"`
	Enabled    bool   `gorm:"not null"`
	Generation int64  `gorm:"type:bigint;not null"`
	CreatedAt  int64  `gorm:"type:bigint;not null"`
	UpdatedAt  int64  `gorm:"type:bigint;not null"`
	RevokedAt  int64  `gorm:"type:bigint;not null"`
}

PromptLearningPolicy is the revocable, server-owned authorization boundary for one user and one opaque subject scope. It deliberately contains no raw conversation data, file path, provider credential, or model request. Enabled is always explicitly written by application logic; no database default is used so SQLite, MySQL and PostgreSQL share the same behavior.

func GetPromptLearningPolicy

func GetPromptLearningPolicy(ctx context.Context, userID int, scopeRef string) (*PromptLearningPolicy, error)

func UpsertPromptLearningPolicy

func UpsertPromptLearningPolicy(ctx context.Context, input PromptLearningPolicyInput) (*PromptLearningPolicy, error)

UpsertPromptLearningPolicy creates a disabled/enabled policy only when the caller explicitly chooses its state. A changed state increments Generation; any previously admitted sample carries the old generation for audit.

func (PromptLearningPolicy) TableName

func (PromptLearningPolicy) TableName() string

type PromptLearningPolicyInput

type PromptLearningPolicyInput struct {
	UserID   int
	ScopeRef string
	Enabled  bool
}

type PromptLearningRun

type PromptLearningRun struct {
	ID                int64  `gorm:"primaryKey"`
	UserID            int    `gorm:"not null;uniqueIndex:idx_prompt_learning_run_command,priority:1;index"`
	ScopeRef          string `gorm:"type:varchar(128);not null;uniqueIndex:idx_prompt_learning_run_command,priority:2;index"`
	CommandID         string `gorm:"type:varchar(128);not null;uniqueIndex:idx_prompt_learning_run_command,priority:3"`
	PolicyGeneration  int64  `gorm:"type:bigint;not null;index"`
	BaselineVersionID *int64 `gorm:"type:bigint;index"`
	SampleUpperID     int64  `gorm:"type:bigint;not null"`
	SampleCount       int    `gorm:"not null"`
	ModelRef          string `gorm:"type:varchar(256);not null"`
	TemplateVersion   string `gorm:"type:varchar(128);not null"`
	InputTokenLimit   int    `gorm:"not null"`
	OutputTokenLimit  int    `gorm:"not null"`
	MaximumAttempts   int    `gorm:"not null"`
	State             string `gorm:"type:varchar(24);not null;index"`
	LeaseOwner        string `gorm:"type:varchar(128);not null;default:''"`
	LeaseUntil        int64  `gorm:"type:bigint;not null;index"`
	LeaseFence        int64  `gorm:"type:bigint;not null"`
	CreatedAt         int64  `gorm:"type:bigint;not null;index"`
	UpdatedAt         int64  `gorm:"type:bigint;not null"`
}

PromptLearningRun is the durable, scope-isolated unit a future worker will use for one analysis request. It freezes only bounded metadata: sample bounds/count, a baseline version, selected model/template and limits. Raw prompts, upstream request/response bodies, credentials and price data do not belong in this table.

func ClaimPromptLearningRun

func ClaimPromptLearningRun(ctx context.Context, userID int, scopeRef string, runID int64, owner string, leaseUntil int64) (*PromptLearningRun, bool, error)

ClaimPromptLearningRun leases only a pending run. The worker must present the returned fence for every later transition. Expired pre-submission work is separately recovered to pending; submitted work is never retried here.

func CreatePromptLearningRun

func CreatePromptLearningRun(ctx context.Context, input PromptLearningRunInput) (*PromptLearningRun, bool, error)

CreatePromptLearningRun records one idempotent, not-yet-executed analysis run. It verifies the policy generation and baseline scope in the same transaction, so a policy revoke or cross-scope version can never be queued as a valid future model request.

func ListPromptLearningRuns

func ListPromptLearningRuns(ctx context.Context, userID int, scopeRef string, offset, limit int) ([]PromptLearningRun, int64, error)

ListPromptLearningRuns returns only one user's own opaque scope. The view layer decides which safe fields to disclose; command IDs and lease owners remain internal operational data.

func (PromptLearningRun) TableName

func (PromptLearningRun) TableName() string

type PromptLearningRunInput

type PromptLearningRunInput struct {
	UserID            int
	ScopeRef          string
	CommandID         string
	PolicyGeneration  int64
	BaselineVersionID *int64
	SampleUpperID     int64
	SampleCount       int
	ModelRef          string
	TemplateVersion   string
	InputTokenLimit   int
	OutputTokenLimit  int
	MaximumAttempts   int
}

type PromptLearningSample

type PromptLearningSample struct {
	ID                    int64  `gorm:"primaryKey"`
	PolicyID              int64  `gorm:"type:bigint;not null;index"`
	UserID                int    `gorm:"not null;uniqueIndex:idx_prompt_learning_sample_occurrence,priority:1;index"`
	ScopeRef              string `gorm:"type:varchar(128);not null;uniqueIndex:idx_prompt_learning_sample_occurrence,priority:2;index"`
	OccurrenceFingerprint string `gorm:"type:char(64);not null;uniqueIndex:idx_prompt_learning_sample_occurrence,priority:3"`
	SemanticFingerprint   string `gorm:"type:char(64);not null;index"`
	SourceReceipt         string `gorm:"type:varchar(256);not null"`
	RedactedText          string `gorm:"type:text;not null"`
	Confidence            string `gorm:"type:varchar(16);not null"`
	PolicyGeneration      int64  `gorm:"type:bigint;not null;index"`
	State                 string `gorm:"type:varchar(16);not null;index"`
	CreatedAt             int64  `gorm:"type:bigint;not null;index"`
	UpdatedAt             int64  `gorm:"type:bigint;not null"`
}

PromptLearningSample stores only a bounded second-pass-redacted text and HMAC-derived references produced by service/promptlearning. The unique occurrence fingerprint gives the primary database authority over replay and conflict decisions; raw request payloads and credentials never enter this table.

func ListPromptLearningSamples

func ListPromptLearningSamples(ctx context.Context, userID int, scopeRef string, offset, limit int) ([]PromptLearningSample, int64, error)

func RecordPromptLearningSample

func RecordPromptLearningSample(ctx context.Context, input PromptLearningSampleInput) (*PromptLearningSample, bool, error)

RecordPromptLearningSample persists a pre-redacted trusted sample only while its exact policy generation remains enabled. Identical occurrences replay without another write; a different payload under the same occurrence is a conflict and is never silently overwritten.

func (PromptLearningSample) TableName

func (PromptLearningSample) TableName() string

type PromptLearningSampleInput

type PromptLearningSampleInput struct {
	UserID                int
	ScopeRef              string
	OccurrenceFingerprint string
	SemanticFingerprint   string
	SourceReceipt         string
	RedactedText          string
	Confidence            string
	PolicyGeneration      int64
}

type Properties

type Properties struct {
	Input             string `json:"input"`
	UpstreamModelName string `json:"upstream_model_name,omitempty"`
	OriginModelName   string `json:"origin_model_name,omitempty"`
}

func (*Properties) Scan

func (m *Properties) Scan(val interface{}) error

func (Properties) Value

func (m Properties) Value() (driver.Value, error)

type PublishedModelPrice

type PublishedModelPrice struct {
	PublicationID    string `json:"publication_id"`
	SourceSHA256     string `json:"source_sha256"`
	ExpressionSHA256 string `json:"expression_sha256"`
	Locked           bool   `json:"locked"`
}

func PublishedModelPriceForExpression

func PublishedModelPriceForExpression(modelName, expression string) (PublishedModelPrice, bool)

The caller holds AcquirePricingRuntimeRead while pairing this reference with the expression. A manual edit invalidates provenance by hash even if the administrator has retained the old publication history.

type QuotaBalanceBatchDrain

type QuotaBalanceBatchDrain struct {
	ID                 int64                    `json:"id" gorm:"primaryKey"`
	SchemaVersion      int                      `json:"schema_version" gorm:"not null"`
	GenerationKey      string                   `json:"generation_key" gorm:"type:varchar(96);not null;uniqueIndex"`
	WriterEpoch        int64                    `json:"writer_epoch" gorm:"type:bigint;not null"`
	Payload            QuotaBalanceBatchPayload `json:"payload" gorm:"type:text"`
	PayloadFingerprint string                   `json:"payload_fingerprint" gorm:"type:char(64);not null;default:''"`
	SubjectKind        int                      `json:"subject_kind" gorm:"not null;default:0;index:idx_quota_balance_subject_preparation,priority:1"`
	SubjectID          int                      `json:"subject_id" gorm:"not null;default:0;index:idx_quota_balance_subject_preparation,priority:2"`
	CacheApplied       bool                     `json:"cache_applied" gorm:"not null;default:false;index:idx_quota_balance_subject_preparation,priority:4"`
	State              string                   `json:"state" gorm:"type:varchar(16);not null;index;index:idx_quota_balance_subject_preparation,priority:3"`
	Attempts           int                      `json:"attempts" gorm:"not null"`
	LastError          string                   `json:"last_error" gorm:"type:text;not null"`
	LeaseOwner         string                   `json:"lease_owner" gorm:"type:varchar(128);not null;default:''"`
	LeaseUntil         int64                    `json:"lease_until" gorm:"type:bigint;not null;default:0;index"`
	LockVersion        int64                    `json:"lock_version" gorm:"type:bigint;not null;default:1"`
	CreatedAt          int64                    `json:"created_at" gorm:"type:bigint;not null"`
	UpdatedAt          int64                    `json:"updated_at" gorm:"type:bigint;not null;index"`
}

QuotaBalanceBatchDrain is the durable handoff between the legacy in-memory balance queue and the main database. Applying the payload and marking the generation applied happen in one transaction.

func (QuotaBalanceBatchDrain) TableName

func (QuotaBalanceBatchDrain) TableName() string

type QuotaBalanceBatchPayload

type QuotaBalanceBatchPayload struct {
	UserQuota      map[int]int    `json:"user_quota,omitempty"`
	TokenQuota     map[int]int    `json:"token_quota,omitempty"`
	TokenCacheKeys map[int]string `json:"token_cache_keys,omitempty"`
}

func (*QuotaBalanceBatchPayload) Scan

func (payload *QuotaBalanceBatchPayload) Scan(value interface{}) error

func (QuotaBalanceBatchPayload) Value

func (payload QuotaBalanceBatchPayload) Value() (driver.Value, error)

type QuotaBalanceBatchSubject

type QuotaBalanceBatchSubject struct {
	ID           int64 `json:"id" gorm:"primaryKey"`
	GenerationID int64 `` /* 213-byte string literal not displayed */
	SubjectKind  int   `` /* 200-byte string literal not displayed */
	SubjectID    int   `` /* 198-byte string literal not displayed */
}

func (QuotaBalanceBatchSubject) TableName

func (QuotaBalanceBatchSubject) TableName() string

type QuotaData

type QuotaData struct {
	Id        int    `json:"id"`
	UserID    int    `json:"user_id" gorm:"index"`
	Username  string `json:"username" gorm:"index:idx_qdt_model_user_name,priority:2;size:64;default:''"`
	ModelName string `json:"model_name" gorm:"index:idx_qdt_model_user_name,priority:1;size:64;default:''"`
	CreatedAt int64  `json:"created_at" gorm:"bigint;index:idx_qdt_created_at,priority:2"`
	UseGroup  string `json:"use_group" gorm:"index;size:64;default:''"`
	TokenID   int    `json:"token_id" gorm:"index;default:0"`
	ChannelID int    `json:"channel_id" gorm:"index;default:0"`
	NodeName  string `json:"node_name" gorm:"index;size:64;default:''"`
	TokenUsed int    `json:"token_used" gorm:"default:0"`
	Count     int    `json:"count" gorm:"default:0"`
	Quota     int    `json:"quota" gorm:"default:0"`
}

QuotaData 柱状图数据

func GetAllQuotaDates

func GetAllQuotaDates(startTime int64, endTime int64, username string) (quotaData []*QuotaData, err error)

func GetAllQuotaDatesWithGranularity

func GetAllQuotaDatesWithGranularity(
	startTime int64,
	endTime int64,
	username string,
	granularity QuotaDataGranularity,
	timezoneOffsetMinutes int,
) (quotaData []*QuotaData, err error)

func GetQuotaDataByUserId

func GetQuotaDataByUserId(userId int, startTime int64, endTime int64) (quotaData []*QuotaData, err error)

func GetQuotaDataByUserIdWithGranularity

func GetQuotaDataByUserIdWithGranularity(
	userId int,
	startTime int64,
	endTime int64,
	granularity QuotaDataGranularity,
	timezoneOffsetMinutes int,
) (quotaData []*QuotaData, err error)

func GetQuotaDataByUsername

func GetQuotaDataByUsername(username string, startTime int64, endTime int64) (quotaData []*QuotaData, err error)

func GetQuotaDataByUsernameWithGranularity

func GetQuotaDataByUsernameWithGranularity(
	username string,
	startTime int64,
	endTime int64,
	granularity QuotaDataGranularity,
	timezoneOffsetMinutes int,
) (quotaData []*QuotaData, err error)

func GetQuotaDataGroupByUser

func GetQuotaDataGroupByUser(startTime int64, endTime int64) (quotaData []*QuotaData, err error)

func GetQuotaDataGroupByUserWithGranularity

func GetQuotaDataGroupByUserWithGranularity(
	startTime int64,
	endTime int64,
	granularity QuotaDataGranularity,
	timezoneOffsetMinutes int,
) (quotaData []*QuotaData, err error)

type QuotaDataGranularity

type QuotaDataGranularity string
const (
	QuotaDataGranularityMinute QuotaDataGranularity = "minute"
	QuotaDataGranularityHour   QuotaDataGranularity = "hour"
	QuotaDataGranularityDay    QuotaDataGranularity = "day"
	QuotaDataGranularityWeek   QuotaDataGranularity = "week"
)

func ParseQuotaDataGranularity

func ParseQuotaDataGranularity(value string) (QuotaDataGranularity, bool)

func (QuotaDataGranularity) BucketSeconds

func (granularity QuotaDataGranularity) BucketSeconds() int64

type QuotaDataLogParams

type QuotaDataLogParams struct {
	UserID    int
	Username  string
	ModelName string
	Quota     int
	CreatedAt int64
	TokenUsed int
	UseGroup  string
	TokenID   int
	ChannelID int
	NodeName  string
}

type QuotaMutationAccountSnapshot

type QuotaMutationAccountSnapshot struct {
	User         QuotaMutationUserSnapshot          `json:"user"`
	Token        QuotaMutationTokenSnapshot         `json:"token"`
	Subscription *QuotaMutationSubscriptionSnapshot `json:"subscription,omitempty"`
}

func (*QuotaMutationAccountSnapshot) Scan

func (snapshot *QuotaMutationAccountSnapshot) Scan(value interface{}) error

func (QuotaMutationAccountSnapshot) Value

func (snapshot QuotaMutationAccountSnapshot) Value() (driver.Value, error)

type QuotaMutationContext

type QuotaMutationContext struct {
	Context    context.Context
	EventKey   string
	ReasonCode string
}

QuotaMutationContext supplies the durable business identity required by non-legacy quota writers. EventKey must be stable across retries.

type QuotaMutationReceipt

type QuotaMutationReceipt struct {
	ID                          int64                        `json:"id" gorm:"primaryKey"`
	ReceiptVersion              int                          `json:"receipt_version" gorm:"not null;<-:create"`
	WriterEpoch                 int64                        `json:"writer_epoch" gorm:"type:bigint;<-:create"`
	MutationType                string                       `` /* 140-byte string literal not displayed */
	MutationKey                 string                       `json:"mutation_key" gorm:"type:varchar(128);not null;uniqueIndex:uidx_quota_mutation_receipt_key;<-:create"`
	RequestFingerprint          string                       `json:"request_fingerprint" gorm:"type:char(64);not null;<-:create"`
	RequestFingerprintVersion   int                          `json:"request_fingerprint_version,omitempty" gorm:"not null;default:0;<-:create"`
	OperationRequestFingerprint string                       `json:"operation_request_fingerprint" gorm:"type:char(64);not null;<-:create"`
	OperationID                 int64                        `json:"operation_id" gorm:"not null;uniqueIndex:uidx_quota_mutation_receipt_op_type,priority:1;<-:create"`
	OperationPublicID           string                       `json:"operation_public_id" gorm:"type:varchar(48);not null;<-:create"`
	ExpectedOperationVersion    int64                        `json:"expected_operation_version" gorm:"type:bigint;not null;<-:create"`
	OperationVersionBefore      int64                        `json:"operation_version_before" gorm:"type:bigint;not null;<-:create"`
	OperationVersionAfter       int64                        `json:"operation_version_after" gorm:"type:bigint;not null;<-:create"`
	BillingEventID              string                       `json:"billing_event_id" gorm:"type:varchar(64);not null;uniqueIndex:uidx_quota_mutation_receipt_event;<-:create"`
	BillingEventKey             string                       `json:"billing_event_key" gorm:"type:varchar(128);not null;<-:create"`
	BillingEventVersion         int64                        `json:"billing_event_version" gorm:"type:bigint;not null;<-:create"`
	UserID                      int                          `json:"user_id" gorm:"not null;index:idx_quota_mutation_receipt_lookup,priority:1;<-:create"`
	TokenID                     int                          `json:"token_id" gorm:"not null;index:idx_quota_mutation_receipt_lookup,priority:2;<-:create"`
	ChannelID                   int                          `json:"channel_id" gorm:"not null;<-:create"`
	BillingSource               string                       `json:"billing_source" gorm:"type:varchar(32);not null;<-:create"`
	SubscriptionID              int                          `json:"subscription_id,omitempty" gorm:"index;<-:create"`
	BillingPreference           string                       `json:"billing_preference,omitempty" gorm:"type:varchar(32);not null;default:'';<-:create"`
	Quota                       int64                        `json:"quota" gorm:"type:bigint;not null;<-:create"`
	EstimatedQuota              int64                        `json:"estimated_quota,omitempty" gorm:"type:bigint;not null;default:0;<-:create"`
	FreeModel                   bool                         `json:"free_model,omitempty" gorm:"not null;default:false;<-:create"`
	RequestID                   string                       `json:"request_id" gorm:"type:varchar(64);not null;default:'';<-:create"`
	StatisticsVersion           int                          `json:"statistics_version,omitempty" gorm:"not null;default:0;<-:create"`
	StatisticsApplied           bool                         `json:"statistics_applied,omitempty" gorm:"not null;default:false;<-:create"`
	EvidenceID                  string                       `json:"evidence_id,omitempty" gorm:"type:varchar(191);not null;default:'';<-:create"`
	EvidenceHash                string                       `json:"evidence_hash,omitempty" gorm:"type:varchar(64);not null;default:'';<-:create"`
	EvidenceVersion             int                          `json:"evidence_version,omitempty" gorm:"not null;default:0;<-:create"`
	BillingContext              TaskQuotaBillingContext      `json:"billing_context" gorm:"type:text;not null;<-:create"`
	Before                      QuotaMutationAccountSnapshot `json:"before" gorm:"column:before_snapshot;type:text;not null;<-:create"`
	After                       QuotaMutationAccountSnapshot `json:"after" gorm:"column:after_snapshot;type:text;not null;<-:create"`
	CreatedAt                   int64                        `json:"created_at" gorm:"type:bigint;not null;index;<-:create"`
}

QuotaMutationReceipt is the immutable, auditable application receipt for one canonical Task reserve event. MutationKey is the TaskBillingEvent EventKey; RequestFingerprint covers every TaskQuotaReservationInput field, while OperationRequestFingerprint binds the receipt to the durable T0 request.

func FindTaskQuotaReceipt

func FindTaskQuotaReceipt(tx *gorm.DB, operationID int64, mutationType string, userID, tokenID int) (*QuotaMutationReceipt, error)

FindTaskQuotaReceipt performs only a main-database read for a specific receipt type.

func FindTaskQuotaReservation

func FindTaskQuotaReservation(tx *gorm.DB, operationID int64, userID, tokenID int) (*QuotaMutationReceipt, error)

FindTaskQuotaReservation performs only a main-database read. Absence is an explicit error so a caller resolving an unknown commit cannot treat an unreadable or missing obligation as authorization to refund or retry blindly.

func ReleaseTaskQuotaReservation

func ReleaseTaskQuotaReservation(tx *gorm.DB, input TaskQuotaReleaseInput) (*QuotaMutationReceipt, error)

ReleaseTaskQuotaReservation applies gate-off T4 atomically. It fully releases previously reserved task quota back to the user, token, and subscription.

func ReserveTaskQuota

func ReserveTaskQuota(tx *gorm.DB, input TaskQuotaReservationInput) (*QuotaMutationReceipt, error)

ReserveTaskQuota applies gate-off T1 atomically. It has no cache, LOG_DB, network or global DB side effects and intentionally has no production caller.

func SettleTaskQuotaReservation

func SettleTaskQuotaReservation(tx *gorm.DB, input TaskQuotaSettlementInput) (*QuotaMutationReceipt, error)

SettleTaskQuotaReservation applies gate-off T3 atomically. It calculates the delta between reserved quota and actual quota, adjusting balances (surplus refund, deficit charge, or exact match).

func (*QuotaMutationReceipt) BeforeCreate

func (receipt *QuotaMutationReceipt) BeforeCreate(tx *gorm.DB) error

func (*QuotaMutationReceipt) BeforeDelete

func (*QuotaMutationReceipt) BeforeDelete(_ *gorm.DB) error

func (*QuotaMutationReceipt) BeforeUpdate

func (*QuotaMutationReceipt) BeforeUpdate(_ *gorm.DB) error

func (QuotaMutationReceipt) TableName

func (QuotaMutationReceipt) TableName() string

type QuotaMutationSubscriptionSnapshot

type QuotaMutationSubscriptionSnapshot struct {
	ID                  int    `json:"id"`
	UserID              int    `json:"user_id"`
	PlanID              int    `json:"plan_id"`
	AmountTotal         int64  `json:"amount_total"`
	AmountUsed          int64  `json:"amount_used"`
	QuotaVersion        int64  `json:"quota_version"`
	StartTime           int64  `json:"start_time"`
	EndTime             int64  `json:"end_time"`
	Status              string `json:"status"`
	Source              string `json:"source"`
	LastResetTime       int64  `json:"last_reset_time"`
	NextResetTime       int64  `json:"next_reset_time"`
	UpgradeGroup        string `json:"upgrade_group"`
	PrevUserGroup       string `json:"prev_user_group"`
	DowngradeGroup      string `json:"downgrade_group"`
	AllowWalletOverflow bool   `json:"allow_wallet_overflow"`
	CreatedAt           int64  `json:"created_at"`
	UpdatedAt           int64  `json:"updated_at"`
}

type QuotaMutationTokenSnapshot

type QuotaMutationTokenSnapshot struct {
	ID                 int    `json:"id"`
	UserID             int    `json:"user_id"`
	Status             int    `json:"status"`
	CreatedTime        int64  `json:"created_time"`
	AccessedTime       int64  `json:"accessed_time"`
	ExpiredTime        int64  `json:"expired_time"`
	RemainQuota        int    `json:"remain_quota"`
	QuotaVersion       int64  `json:"quota_version"`
	UnlimitedQuota     bool   `json:"unlimited_quota"`
	UsedQuota          int    `json:"used_quota"`
	Group              string `json:"group"`
	AccessProfileID    string `json:"access_profile_id"`
	ModelLimitsEnabled bool   `json:"model_limits_enabled"`
	ModelLimits        string `json:"model_limits"`
	CrossGroupRetry    bool   `json:"cross_group_retry"`
}

QuotaMutationTokenSnapshot omits Key, AutoGroups and IP restrictions. Those values are credentials or routing policy inputs, not quota mutation state.

type QuotaMutationUserSnapshot

type QuotaMutationUserSnapshot struct {
	SelfUseNoBalance    bool   `json:"self_use_no_balance,omitempty"`
	UsagePolicyRevision int64  `json:"usage_policy_revision,omitempty"`
	ID                  int    `json:"id"`
	Status              int    `json:"status"`
	Role                int    `json:"role"`
	Quota               int    `json:"quota"`
	UsedQuota           int    `json:"used_quota"`
	RequestCount        int    `json:"request_count"`
	QuotaVersion        int64  `json:"quota_version"`
	Group               string `json:"group"`
	AccountTierID       string `json:"account_tier_id"`
}

QuotaMutationUserSnapshot excludes credentials and personal profile data. It contains the complete account state needed to audit or project this quota mutation without consulting a mutable cache.

func (*QuotaMutationUserSnapshot) Scan

func (snapshot *QuotaMutationUserSnapshot) Scan(value interface{}) error

func (QuotaMutationUserSnapshot) Value

func (snapshot QuotaMutationUserSnapshot) Value() (driver.Value, error)

type QuotaProjectionObligation

type QuotaProjectionObligation struct {
	ID                   int64  `json:"id" gorm:"primaryKey"`
	SchemaVersion        int    `json:"schema_version" gorm:"not null"`
	ReceiptKind          string `` /* 156-byte string literal not displayed */
	ReceiptID            int64  `json:"receipt_id" gorm:"type:bigint;not null;uniqueIndex:uidx_quota_projection_receipt,priority:2"`
	EventKey             string `json:"event_key" gorm:"type:varchar(128);not null;uniqueIndex:uidx_quota_projection_event,priority:2"`
	WriterEpoch          int64  `json:"writer_epoch" gorm:"type:bigint"`
	UserID               int    `json:"user_id" gorm:"not null;index"`
	TokenID              int    `json:"token_id" gorm:"not null;index"`
	ExpectedUserVersion  int64  `json:"expected_user_version" gorm:"type:bigint;not null"`
	ExpectedTokenVersion int64  `json:"expected_token_version" gorm:"type:bigint;not null"`
	State                string `json:"state" gorm:"type:varchar(16);not null;index:idx_quota_projection_claim,priority:1"`
	LeaseOwner           string `json:"lease_owner" gorm:"type:varchar(96);not null"`
	LeaseUntil           int64  `json:"lease_until" gorm:"type:bigint;not null;index:idx_quota_projection_claim,priority:2"`
	NextAttemptAt        int64  `json:"next_attempt_at" gorm:"type:bigint;index:idx_quota_projection_claim,priority:3"`
	Fence                int64  `json:"fence" gorm:"type:bigint;not null"`
	LockVersion          int64  `json:"lock_version" gorm:"type:bigint"`
	Attempts             int    `json:"attempts" gorm:"not null"`
	LastError            string `json:"last_error" gorm:"type:text;not null"`
	RepairAuditCommandID string `json:"repair_audit_command_id" gorm:"type:varchar(96)"`
	RepairReason         string `json:"repair_reason" gorm:"type:varchar(191)"`
	RepairedAt           int64  `json:"repaired_at" gorm:"type:bigint"`
	CreatedAt            int64  `json:"created_at" gorm:"type:bigint;not null"`
	UpdatedAt            int64  `json:"updated_at" gorm:"type:bigint;not null"`
}

QuotaProjectionObligation is committed in the same main-database transaction as its immutable receipt. Redis is only a replayable projection.

func RequeueQuotaProjectionObligation

func RequeueQuotaProjectionObligation(db *gorm.DB, input QuotaProjectionRepairInput) (*QuotaProjectionObligation, error)

RequeueQuotaProjectionObligation is an explicit, audited manual repair. It validates the immutable receipt before changing only the obligation state.

func (QuotaProjectionObligation) TableName

func (QuotaProjectionObligation) TableName() string

type QuotaProjectionObligationState

type QuotaProjectionObligationState string
const (
	QuotaProjectionObligationStatePending   QuotaProjectionObligationState = "pending"
	QuotaProjectionObligationStateClaimed   QuotaProjectionObligationState = "claimed"
	QuotaProjectionObligationStateRetryable QuotaProjectionObligationState = "retryable"
	QuotaProjectionObligationStateApplied   QuotaProjectionObligationState = "applied"
	QuotaProjectionObligationStateManual    QuotaProjectionObligationState = "manual"
)

type QuotaProjectionRepairInput

type QuotaProjectionRepairInput struct {
	ObligationID   int64
	AuditCommandID string
	Reason         string
}

type QuotaWorkCursor

type QuotaWorkCursor struct {
	Name          string `json:"name" gorm:"type:varchar(64);primaryKey"`
	LastID        int64  `json:"last_id" gorm:"type:bigint;not null;default:0"`
	HighWatermark int64  `json:"high_watermark" gorm:"type:bigint;not null;default:0"`
	Complete      bool   `json:"complete" gorm:"not null;default:false"`
	UpdatedAt     int64  `json:"updated_at" gorm:"type:bigint;not null;index"`
}

func (QuotaWorkCursor) TableName

func (QuotaWorkCursor) TableName() string

type QuotaWriterClusterDrainAck

type QuotaWriterClusterDrainAck struct {
	OperatorUserId int    `json:"operator_user_id"`
	Epoch          int64  `json:"epoch"`
	Note           string `json:"note"`
	Timestamp      int64  `json:"timestamp"`
}

func RecordQuotaWriterClusterDrainAck

func RecordQuotaWriterClusterDrainAck(db *gorm.DB, operatorUserId int, epoch int64, note string) (*QuotaWriterClusterDrainAck, error)

RecordQuotaWriterClusterDrainAck upserts the operator acknowledgement bound to the given epoch. A later successful transition advances the epoch, which invalidates older acknowledgements naturally.

type QuotaWriterDrainReport

type QuotaWriterDrainReport struct {
	Rounds               int   `json:"rounds"`
	BatchQueueRemaining  int   `json:"batch_queue_remaining"`
	BalanceDrainPending  int64 `json:"balance_drain_pending"`
	BalanceDrainInflight bool  `json:"balance_drain_inflight"`
	ProjectionPending    int64 `json:"projection_pending"`
	Complete             bool  `json:"complete"`
}

func DriveQuotaWriterDrains

func DriveQuotaWriterDrains(ctx context.Context, db *gorm.DB, budget int) (*QuotaWriterDrainReport, error)

DriveQuotaWriterDrains synchronously drives the existing drain workers to zero within a bounded number of rounds: each round runs the existing batch update flush (which persists and applies balance drain generations) and one bounded projection obligation pass. It adds no new daemon and copies no business logic; the projection pass honors the existing recovery gate. Balance generation application is legacy-only by design (see applyQuotaBalanceBatchGenerationWithDB), so pre-draining before a legacy->bridge apply is the supported recovery order.

type QuotaWriterEpoch

type QuotaWriterEpoch struct {
	ID            int    `json:"id" gorm:"primaryKey"`
	SchemaVersion int    `json:"schema_version" gorm:"not null"`
	Mode          string `json:"mode" gorm:"type:varchar(24);not null"`
	Epoch         int64  `json:"epoch" gorm:"type:bigint;not null"`
	LockVersion   int64  `json:"lock_version" gorm:"type:bigint;not null"`
	UpdatedAt     int64  `json:"updated_at" gorm:"type:bigint;not null"`
}

QuotaWriterEpoch is the singleton, main-database authority for quota writer mode and epoch. Defaults are applied by application code, not schema tags, so AutoMigrate remains stable across SQLite, MySQL 5.7, and PostgreSQL 9.6.

func GetQuotaWriterEpochState

func GetQuotaWriterEpochState(db *gorm.DB) (*QuotaWriterEpoch, error)

func (QuotaWriterEpoch) TableName

func (QuotaWriterEpoch) TableName() string

type QuotaWriterMode

type QuotaWriterMode string
const (
	QuotaWriterModeLegacy        QuotaWriterMode = "legacy"
	QuotaWriterModeBridge        QuotaWriterMode = "bridge"
	QuotaWriterModeAuthoritative QuotaWriterMode = "authoritative"
)

type QuotaWriterModeTransition

type QuotaWriterModeTransition struct {
	ID              int64  `json:"id" gorm:"primaryKey"`
	OperatorUserId  int    `json:"operator_user_id" gorm:"not null;index"`
	FromMode        string `json:"from_mode" gorm:"type:varchar(24);not null"`
	ToMode          string `json:"to_mode" gorm:"type:varchar(24);not null"`
	FromEpoch       int64  `json:"from_epoch" gorm:"type:bigint;not null"`
	ToEpoch         int64  `json:"to_epoch" gorm:"type:bigint;not null"`
	Status          string `json:"status" gorm:"type:varchar(16);not null;index"`
	PreAudit        string `json:"pre_audit" gorm:"type:text;not null"`
	PostAudit       string `json:"post_audit" gorm:"type:text;not null"`
	ClusterDrainAck bool   `json:"cluster_drain_ack" gorm:"not null;default:false"`
	AckNote         string `json:"ack_note" gorm:"type:varchar(512);not null;default:''"`
	FailureReason   string `json:"failure_reason" gorm:"type:varchar(2048);not null;default:''"`
	CreatedAt       int64  `json:"created_at" gorm:"type:bigint;not null"`
	FinishedAt      int64  `json:"finished_at" gorm:"type:bigint;not null"`
}

QuotaWriterModeTransition is the durable evidence of one mode switch attempt. Operator-visible text fields are length-bounded; audit snapshots are JSON produced by common.Marshal.

func ApplyQuotaWriterModeTransition

func ApplyQuotaWriterModeTransition(ctx context.Context, db *gorm.DB, input QuotaWriterModeTransitionInput) (*QuotaWriterModeTransition, error)

ApplyQuotaWriterModeTransition performs the gated mode switch that PlanQuotaWriterModeTransition only previews. The epoch row is locked and CAS-updated in one transaction together with the applying evidence row; Redis publication and the post-audit run after commit and only flip the evidence status, never the committed mode.

func ListQuotaWriterModeTransitions

func ListQuotaWriterModeTransitions(db *gorm.DB, startIdx int, pageSize int) ([]QuotaWriterModeTransition, int64, error)

func (QuotaWriterModeTransition) TableName

func (QuotaWriterModeTransition) TableName() string

type QuotaWriterModeTransitionInput

type QuotaWriterModeTransitionInput struct {
	TargetMode          QuotaWriterMode
	ExpectedEpoch       int64
	OperatorUserId      int
	ClusterDrainAckNote string
}

type QuotaWriterModeTransitionPlan

type QuotaWriterModeTransitionPlan struct {
	Current       QuotaWriterEpoch       `json:"current"`
	TargetMode    QuotaWriterMode        `json:"target_mode"`
	ProposedEpoch int64                  `json:"proposed_epoch"`
	Audit         DurableQuotaWriteAudit `json:"audit"`
	Ready         bool                   `json:"ready"`
	Validation    []string               `json:"validation"`
}

func PlanQuotaWriterModeTransition

func PlanQuotaWriterModeTransition(ctx context.Context, db *gorm.DB, target QuotaWriterMode) (*QuotaWriterModeTransitionPlan, error)

PlanQuotaWriterModeTransition produces a reviewable plan. WP3-A intentionally exposes no apply API, so a gate-off process cannot switch modes automatically.

type QuotaWriterRegistration

type QuotaWriterRegistration struct {
	Name     string `json:"name"`
	Migrated bool   `json:"migrated"`
}

func ProductionQuotaWriterRegistrations

func ProductionQuotaWriterRegistrations() []QuotaWriterRegistration

ProductionQuotaWriterRegistrations is deliberately explicit. WP3-A migrated durable task receipts and MutateUserQuota. WP3-B1 routes every production BillingSession lifecycle through authoritative account receipts and durable terminal facts. WP3-B2 wired the business credit paths (topup / redemption / checkin / invite / aff) into the authoritative receipt kernel. WP3-B3 migrated the subscription wallet purchase debit and the admin quota endpoints.

The remaining legacy generic writers keep Migrated=true only where every production caller was verified per-caller to be either mode-dispatched or reachable solely on legacy-only paths with the model-layer requireLegacyQuotaWriterCall guard closing non-legacy modes:

  • increase_user_quota / decrease_user_quota: callers are credit_edge (mode-dispatched), postConsumeQuotaLegacy (mode-dispatched), WalletFunding settle/refund and BillingSession reserve/rollback (legacy-only reachable), taskAdjustFunding (legacy settlement-fact gated), RefundMidjourneyQuota (mode-dispatched); the former admin endpoint callers were migrated in WP3-B3.
  • try_reserve_user_quota: only WalletFunding.PreConsume (legacy-only reachable; guarded).
  • increase_token_quota / decrease_token_quota: callers are postConsumeQuotaLegacy (mode-dispatched), taskAdjustTokenQuota (legacy settlement-fact gated), refundMidjourneyTokenQuota (mode-dispatched).
  • try_reserve_token_quota: only PreConsumeTokenQuota (legacy-only reachable; guarded).
  • subscription_wallet_overflow: the balance-paid purchase debit is mode-dispatched in PurchaseSubscriptionWithBalance (receipt key "subscription-wallet:{tradeNo}", bridge fail-closed); overflow wallet writes are reachable only via the legacy BillingSession/task legacy facts (guarded) or the authoritative Reserve kernels; subscription-side writes keep their existing CAS + upstream idempotency (SubscriptionPreConsumeRecord / settlement facts).
  • admin_quota_mutations: all three operations share the durable admin_quota_adjustments identity with mode dispatch (WP3-B3).

DeltaUpdateUserQuota is intentionally absent: repository-wide caller analysis found only the helper definition, which delegates to the registered increase/decrease writers. This table inventories production write paths that must be migrated, not unused convenience helpers.

type QuotaWriterTransitionConditionsError

type QuotaWriterTransitionConditionsError struct {
	Missing []string
}

QuotaWriterTransitionConditionsError carries the audit check names that blocked an apply. A failed evidence row is persisted alongside it.

func (*QuotaWriterTransitionConditionsError) Error

type RankingQuotaBucket

type RankingQuotaBucket struct {
	ModelName string `json:"model_name"`
	Bucket    int64  `json:"bucket"`
	Tokens    int64  `json:"tokens"`
}

func GetRankingQuotaBuckets

func GetRankingQuotaBuckets(startTime int64, endTime int64, bucketSize int64) ([]RankingQuotaBucket, error)

type RankingQuotaTotal

type RankingQuotaTotal struct {
	ModelName   string `json:"model_name"`
	TotalTokens int64  `json:"total_tokens"`
}

func GetRankingQuotaTotals

func GetRankingQuotaTotals(startTime int64, endTime int64) ([]RankingQuotaTotal, error)

type RecentLogOverview

type RecentLogOverview struct {
	Requests []RecentLogOverviewItem `json:"requests"`
	Errors   []RecentLogOverviewItem `json:"errors"`
}

func GetAdminRecentLogOverview

func GetAdminRecentLogOverview(db *gorm.DB) (RecentLogOverview, error)

func GetUserRecentLogOverview

func GetUserRecentLogOverview(db *gorm.DB, userID int) (RecentLogOverview, error)

type RecentLogOverviewItem

type RecentLogOverviewItem struct {
	ID        int    `json:"id"`
	CreatedAt int64  `json:"created_at"`
	ModelName string `json:"model_name"`
	Username  string `json:"username,omitempty"`
}

RecentLogOverviewItem is a bounded, content-free view of one log row. Raw request content, provider errors, tokens and log metadata never leave this projection.

type RecordConsumeLogParams

type RecordConsumeLogParams struct {
	ChannelId        int                    `json:"channel_id"`
	PromptTokens     int                    `json:"prompt_tokens"`
	CompletionTokens int                    `json:"completion_tokens"`
	ModelName        string                 `json:"model_name"`
	TokenName        string                 `json:"token_name"`
	Quota            int                    `json:"quota"`
	Content          string                 `json:"content"`
	TokenId          int                    `json:"token_id"`
	UseTimeSeconds   int                    `json:"use_time_seconds"`
	IsStream         bool                   `json:"is_stream"`
	Group            string                 `json:"group"`
	Other            map[string]interface{} `json:"other"`
}

type RecordTaskBillingLogParams

type RecordTaskBillingLogParams struct {
	UserId    int
	LogType   int
	Content   string
	ChannelId int
	ModelName string
	Quota     int
	TokenId   int
	Group     string
	Other     map[string]interface{}
	NodeName  string // 任务发起节点;为空时回退当前节点
}

type Redemption

type Redemption struct {
	Id           int            `json:"id"`
	UserId       int            `json:"user_id"`
	Key          string         `json:"key" gorm:"type:char(32);uniqueIndex"`
	Status       int            `json:"status" gorm:"default:1"`
	Name         string         `json:"name" gorm:"index"`
	Quota        int            `json:"quota" gorm:"default:100"`
	CreatedTime  int64          `json:"created_time" gorm:"bigint"`
	RedeemedTime int64          `json:"redeemed_time" gorm:"bigint"`
	Count        int            `json:"count" gorm:"-:all"` // only for api request
	UsedUserId   int            `json:"used_user_id"`
	DeletedAt    gorm.DeletedAt `gorm:"index"`
	ExpiredTime  int64          `json:"expired_time" gorm:"bigint"` // 过期时间,0 表示不过期
}

func GetAllRedemptions

func GetAllRedemptions(startIdx int, num int) (redemptions []*Redemption, total int64, err error)

func GetRedemptionById

func GetRedemptionById(id int) (*Redemption, error)

func SearchRedemptions

func SearchRedemptions(keyword string, status string, startIdx int, num int) (redemptions []*Redemption, total int64, err error)

func (*Redemption) Delete

func (redemption *Redemption) Delete() error

func (*Redemption) Insert

func (redemption *Redemption) Insert() error

func (*Redemption) SelectUpdate

func (redemption *Redemption) SelectUpdate() error

func (*Redemption) Update

func (redemption *Redemption) Update() error

Update Make sure your token's fields is completed, because this will update non-zero values

type RelayAccountHold

type RelayAccountHold struct {
	ChannelID    int    `json:"-" gorm:"primaryKey;autoIncrement:false"`
	Identity     string `json:"-" gorm:"primaryKey;type:varchar(64)"`
	ConfigDigest string `json:"-" gorm:"primaryKey;type:char(64)"`
	Until        int64  `json:"-" gorm:"column:hold_until;type:bigint;not null;index:idx_relay_account_hold_expiry"`
}

RelayAccountHold records transient transport health, never quota exhaustion. Identity and config digests are internal and must not be serialized to clients.

func ReadRelayAccountHolds

func ReadRelayAccountHolds(ctx context.Context, db *gorm.DB, channel *Channel) ([]RelayAccountHold, error)

func (RelayAccountHold) GoString

func (h RelayAccountHold) GoString() string

func (RelayAccountHold) String

func (RelayAccountHold) String() string

type Setup

type Setup struct {
	ID            uint   `json:"id" gorm:"primaryKey"`
	Version       string `json:"version" gorm:"type:varchar(50);not null"`
	InitializedAt int64  `json:"initialized_at" gorm:"type:bigint;not null"`
}

func GetSetup

func GetSetup() *Setup

type Stat

type Stat struct {
	Quota int `json:"quota"`
	Rpm   int `json:"rpm"`
	Tpm   int `json:"tpm"`
}

func SumUsedQuota

func SumUsedQuota(logType int, startTimestamp int64, endTimestamp int64, modelName string, username string, tokenName string, channel int, group string) (stat Stat, err error)

type SubscriptionOrder

type SubscriptionOrder struct {
	Id     int     `json:"id"`
	UserId int     `json:"user_id" gorm:"index"`
	PlanId int     `json:"plan_id" gorm:"index"`
	Money  float64 `json:"money"`

	TradeNo         string `json:"trade_no" gorm:"unique;type:varchar(255);index"`
	PaymentMethod   string `json:"payment_method" gorm:"type:varchar(50)"`
	PaymentProvider string `json:"payment_provider" gorm:"type:varchar(50);default:''"`
	Status          string `json:"status"`
	CreateTime      int64  `json:"create_time"`
	CompleteTime    int64  `json:"complete_time"`

	ProviderPayload string `json:"provider_payload" gorm:"type:text"`
	FundingEpoch    uint64 `json:"funding_epoch" gorm:"not null;default:0;index"`
}

Subscription order (payment -> webhook -> create UserSubscription)

func GetSubscriptionOrderByTradeNo

func GetSubscriptionOrderByTradeNo(tradeNo string) *SubscriptionOrder

func GetSubscriptionOrderByTradeNoWithError

func GetSubscriptionOrderByTradeNoWithError(tradeNo string) (*SubscriptionOrder, error)

GetSubscriptionOrderByTradeNoWithError distinguishes a genuinely absent order from a database failure, so payment handlers can fail closed.

func (*SubscriptionOrder) Insert

func (o *SubscriptionOrder) Insert(expectedEpoch ...uint64) error

func (*SubscriptionOrder) Update

func (o *SubscriptionOrder) Update() error

type SubscriptionPlan

type SubscriptionPlan struct {
	Id int `json:"id"`

	Title    string `json:"title" gorm:"type:varchar(128);not null"`
	Subtitle string `json:"subtitle" gorm:"type:varchar(255);default:''"`

	// Display money amount (follow existing code style: float64 for money)
	PriceAmount float64 `json:"price_amount" gorm:"type:decimal(10,6);not null;default:0"`
	Currency    string  `json:"currency" gorm:"type:varchar(8);not null;default:'USD'"`

	DurationUnit  string `json:"duration_unit" gorm:"type:varchar(16);not null;default:'month'"`
	DurationValue int    `json:"duration_value" gorm:"type:int;not null;default:1"`
	CustomSeconds int64  `json:"custom_seconds" gorm:"type:bigint;not null;default:0"`

	Enabled   bool `json:"enabled" gorm:"default:true"`
	SortOrder int  `json:"sort_order" gorm:"type:int;default:0"`

	AllowBalancePay *bool `json:"allow_balance_pay"`

	// Allow falling back to wallet balance after subscription quota is exhausted (empty = true)
	AllowWalletOverflow *bool `json:"allow_wallet_overflow"`

	StripePriceId         string `json:"stripe_price_id" gorm:"type:varchar(128);default:''"`
	CreemProductId        string `json:"creem_product_id" gorm:"type:varchar(128);default:''"`
	WaffoPancakeProductId string `json:"waffo_pancake_product_id" gorm:"type:varchar(128);default:''"`

	// Max purchases per user (0 = unlimited)
	MaxPurchasePerUser int `json:"max_purchase_per_user" gorm:"type:int;default:0"`

	// Upgrade user group after purchase (empty = no change)
	UpgradeGroup string `json:"upgrade_group" gorm:"type:varchar(64);default:''"`

	// Downgrade user group on expiry (empty = revert to the group held before purchase)
	DowngradeGroup string `json:"downgrade_group" gorm:"type:varchar(64);default:''"`

	// Total quota (amount in quota units, 0 = unlimited)
	TotalAmount int64 `json:"total_amount" gorm:"type:bigint;not null;default:0"`

	// Quota reset period for plan
	QuotaResetPeriod        string `json:"quota_reset_period" gorm:"type:varchar(16);default:'never'"`
	QuotaResetCustomSeconds int64  `json:"quota_reset_custom_seconds" gorm:"type:bigint;default:0"`

	CreatedAt int64 `json:"created_at" gorm:"bigint"`
	UpdatedAt int64 `json:"updated_at" gorm:"bigint"`
}

Subscription plan

func GetSubscriptionPlanById

func GetSubscriptionPlanById(id int) (*SubscriptionPlan, error)

func (*SubscriptionPlan) BeforeCreate

func (p *SubscriptionPlan) BeforeCreate(tx *gorm.DB) error

func (*SubscriptionPlan) BeforeUpdate

func (p *SubscriptionPlan) BeforeUpdate(tx *gorm.DB) error

func (*SubscriptionPlan) NormalizeDefaults

func (p *SubscriptionPlan) NormalizeDefaults()

type SubscriptionPlanInfo

type SubscriptionPlanInfo struct {
	PlanId    int
	PlanTitle string
}

func GetSubscriptionPlanInfoByUserSubscriptionId

func GetSubscriptionPlanInfoByUserSubscriptionId(userSubscriptionId int) (*SubscriptionPlanInfo, error)

type SubscriptionPreConsumeRecord

type SubscriptionPreConsumeRecord struct {
	Id                 int    `json:"id"`
	RequestId          string `json:"request_id" gorm:"type:varchar(64);uniqueIndex"`
	UserId             int    `json:"user_id" gorm:"index"`
	UserSubscriptionId int    `json:"user_subscription_id" gorm:"index"`
	PreConsumed        int64  `json:"pre_consumed" gorm:"type:bigint;not null;default:0"`
	Status             string `json:"status" gorm:"type:varchar(32);index"` // consumed/refunded
	CreatedAt          int64  `json:"created_at" gorm:"bigint"`
	UpdatedAt          int64  `json:"updated_at" gorm:"bigint;index"`
}

SubscriptionPreConsumeRecord stores idempotent pre-consume operations per request.

func (*SubscriptionPreConsumeRecord) BeforeCreate

func (r *SubscriptionPreConsumeRecord) BeforeCreate(tx *gorm.DB) error

func (*SubscriptionPreConsumeRecord) BeforeUpdate

func (r *SubscriptionPreConsumeRecord) BeforeUpdate(tx *gorm.DB) error

type SubscriptionPreConsumeResult

type SubscriptionPreConsumeResult struct {
	UserSubscriptionId int
	PreConsumed        int64
	AmountTotal        int64
	AmountUsedBefore   int64
	AmountUsedAfter    int64
}

func PreConsumeUserSubscription

func PreConsumeUserSubscription(requestId string, userId int, modelName string, quotaType int, amount int64) (*SubscriptionPreConsumeResult, error)

PreConsumeUserSubscription pre-consumes from any active subscription total quota.

type SubscriptionResetResult

type SubscriptionResetResult struct {
	PlanId           int    `json:"plan_id"`
	MatchedCount     int    `json:"matched_count"`
	ResetCount       int    `json:"reset_count"`
	UserCount        int    `json:"user_count"`
	AdvanceResetTime bool   `json:"advance_reset_time"`
	PlanTitle        string `json:"-"`
	AffectedUserIds  []int  `json:"-"`
}

func AdminResetPlanSubscriptions

func AdminResetPlanSubscriptions(planId int, advanceResetTime bool) (*SubscriptionResetResult, error)

func AdminResetUserSubscriptionsByPlan

func AdminResetUserSubscriptionsByPlan(userId int, planId int, advanceResetTime bool) (*SubscriptionResetResult, error)

type SubscriptionSummary

type SubscriptionSummary struct {
	Subscription *UserSubscription `json:"subscription"`
}

func GetAllActiveUserSubscriptions

func GetAllActiveUserSubscriptions(userId int) ([]SubscriptionSummary, error)

GetAllActiveUserSubscriptions returns all active subscriptions for a user.

func GetAllUserSubscriptions

func GetAllUserSubscriptions(userId int) ([]SubscriptionSummary, error)

GetAllUserSubscriptions returns all subscriptions (active and expired) for a user.

type SyncTaskQueryParams

type SyncTaskQueryParams struct {
	Platform       constant.TaskPlatform
	ChannelID      string
	TaskID         string
	UserID         string
	Action         string
	Status         string
	StartTimestamp int64
	EndTimestamp   int64
	UserIDs        []int
}

SyncTaskQueryParams 用于包含所有搜索条件的结构体,可以根据需求添加更多字段

type SystemInstance

type SystemInstance struct {
	NodeName   string `json:"node_name" gorm:"type:varchar(128);primaryKey"`
	Info       string `json:"info" gorm:"type:text"`
	StartedAt  int64  `json:"started_at" gorm:"bigint;index"`
	LastSeenAt int64  `json:"last_seen_at" gorm:"bigint;index"`
	CreatedAt  int64  `json:"created_at" gorm:"bigint;index"`
	UpdatedAt  int64  `json:"updated_at" gorm:"bigint;index"`
}

func ListSystemInstances

func ListSystemInstances() ([]*SystemInstance, error)

func (*SystemInstance) BeforeCreate

func (instance *SystemInstance) BeforeCreate(_ *gorm.DB) error

func (*SystemInstance) ToResponse

func (instance *SystemInstance) ToResponse(now int64) SystemInstanceResponse

type SystemInstanceResponse

type SystemInstanceResponse struct {
	NodeName          string `json:"node_name"`
	Status            string `json:"status"`
	StaleAfterSeconds int64  `json:"stale_after_seconds"`
	StartedAt         int64  `json:"started_at"`
	LastSeenAt        int64  `json:"last_seen_at"`
	Info              any    `json:"info"`
}

type SystemTask

type SystemTask struct {
	ID         int64            `json:"id" gorm:"primary_key"`
	TaskID     string           `json:"task_id" gorm:"type:varchar(64);uniqueIndex"`
	Type       string           `json:"type" gorm:"type:varchar(64);index"`
	Status     SystemTaskStatus `json:"status" gorm:"type:varchar(32);index"`
	ActiveKey  *string          `json:"active_key,omitempty" gorm:"type:varchar(64);uniqueIndex"`
	Payload    string           `json:"payload" gorm:"type:text"`
	State      string           `json:"state" gorm:"type:text"`
	Result     string           `json:"result" gorm:"type:text"`
	Error      string           `json:"error" gorm:"type:text"`
	LockedBy   string           `json:"locked_by" gorm:"type:varchar(128);index"`
	FenceToken int64            `json:"fence_token" gorm:"bigint;not null;default:0"`
	CreatedAt  int64            `json:"created_at" gorm:"bigint;index"`
	UpdatedAt  int64            `json:"updated_at" gorm:"bigint;index"`
}

func ClaimSystemTask

func ClaimSystemTask(id int64, taskType string, runnerID string, lockUntil int64) (*SystemTask, bool, error)

func CreateSystemTask

func CreateSystemTask(taskType string, payload any, state any) (*SystemTask, error)

func FindPendingSystemTasks

func FindPendingSystemTasks(taskType string, limit int) ([]*SystemTask, error)

func GetActiveSystemTask

func GetActiveSystemTask(taskType string) (*SystemTask, error)

func GetLatestSystemTask

func GetLatestSystemTask(taskType string) (*SystemTask, error)

GetLatestSystemTask returns the most recent task row of the given type (any status) so the scheduler can decide whether enough time has elapsed since the last run. Returns (nil, nil) when no row exists.

func GetSystemTaskByTaskID

func GetSystemTaskByTaskID(taskID string) (*SystemTask, error)

func ListSystemTasks

func ListSystemTasks(limit int) ([]*SystemTask, error)

func ReadOpenAIPriceCheckTasks

func ReadOpenAIPriceCheckTasks(ctx context.Context) (latest, successful *SystemTask, err error)

ReadOpenAIPriceCheckTasks reads two bounded task records. Failed attempts do not overwrite the last good observation, even when the source hash repeats.

func (*SystemTask) BeforeCreate

func (task *SystemTask) BeforeCreate(_ *gorm.DB) error

func (*SystemTask) DecodePayload

func (task *SystemTask) DecodePayload(v any) error

func (*SystemTask) DecodeState

func (task *SystemTask) DecodeState(v any) error

func (*SystemTask) ToResponse

func (task *SystemTask) ToResponse() SystemTaskResponse

type SystemTaskLock

type SystemTaskLock struct {
	Type        string `json:"type" gorm:"type:varchar(64);primaryKey"`
	TaskID      string `json:"task_id" gorm:"type:varchar(64);index"`
	LockedBy    string `json:"locked_by" gorm:"type:varchar(128);index"`
	LockedUntil int64  `json:"locked_until" gorm:"bigint;index"`
	FenceToken  int64  `json:"fence_token" gorm:"bigint;not null;default:0"`
	UpdatedAt   int64  `json:"updated_at" gorm:"bigint;index"`
}

func (*SystemTaskLock) BeforeCreate

func (lock *SystemTaskLock) BeforeCreate(_ *gorm.DB) error

type SystemTaskResponse

type SystemTaskResponse struct {
	ID         int64            `json:"id"`
	TaskID     string           `json:"task_id"`
	Type       string           `json:"type"`
	Status     SystemTaskStatus `json:"status"`
	ActiveKey  *string          `json:"active_key,omitempty"`
	Payload    any              `json:"payload"`
	State      any              `json:"state"`
	Result     any              `json:"result"`
	Error      string           `json:"error"`
	LockedBy   string           `json:"locked_by"`
	FenceToken int64            `json:"fence_token"`
	CreatedAt  int64            `json:"created_at"`
	UpdatedAt  int64            `json:"updated_at"`
}

type SystemTaskStatus

type SystemTaskStatus string

type Task

type Task struct {
	ID                  int64                 `json:"id" gorm:"primary_key;AUTO_INCREMENT"`
	CreatedAt           int64                 `json:"created_at" gorm:"index"`
	UpdatedAt           int64                 `json:"updated_at"`
	TaskID              string                `json:"task_id" gorm:"type:varchar(191);index"` // 第三方id,不一定有/ song id\ Task id
	Platform            constant.TaskPlatform `json:"platform" gorm:"type:varchar(30);index"` // 平台
	UserId              int                   `json:"user_id" gorm:"index"`
	Group               string                `json:"group" gorm:"type:varchar(50)"` // 修正计费用
	ChannelId           int                   `json:"channel_id" gorm:"index"`
	Quota               int                   `json:"quota"`
	Action              string                `json:"action" gorm:"type:varchar(40);index"` // 任务类型, song, lyrics, description-mode
	Status              TaskStatus            `json:"status" gorm:"type:varchar(20);index"` // 任务状态
	FailReason          string                `json:"fail_reason"`
	SubmitTime          int64                 `json:"submit_time" gorm:"index"`
	StartTime           int64                 `json:"start_time" gorm:"index"`
	FinishTime          int64                 `json:"finish_time" gorm:"index"`
	Progress            string                `json:"progress" gorm:"type:varchar(20);index"`
	PollingDisposition  string                `json:"-" gorm:"type:varchar(16);not null;default:'';index:idx_task_polling_due,priority:1"`
	NextPollAt          int64                 `json:"-" gorm:"type:bigint;not null;default:0;index:idx_task_polling_due,priority:2"`
	PollingReasonCode   string                `json:"-" gorm:"type:varchar(64);not null;default:''"`
	PollingAttemptCount int                   `json:"-" gorm:"not null;default:0"`
	Properties          Properties            `json:"properties" gorm:"type:json"`
	Username            string                `json:"username,omitempty" gorm:"-"`
	// 禁止返回给用户,内部可能包含key等隐私信息
	PrivateData TaskPrivateData `json:"-" gorm:"column:private_data;type:json"`
	Data        json.RawMessage `json:"data" gorm:"type:json"`
}

func GetAllUnFinishSyncTasks

func GetAllUnFinishSyncTasks(limit int) []*Task

func GetAllUnfinishedSyncTasksForPolling

func GetAllUnfinishedSyncTasksForPolling(limit int, now int64) ([]*Task, error)

GetAllUnfinishedSyncTasksForPolling returns due tasks while excluding manual review rows. Fresh pending work is ordered before retryable work so a large uncertainty backlog cannot consume the entire polling window.

func GetByTaskId

func GetByTaskId(userId int, taskId string) (*Task, bool, error)

func GetByTaskIds

func GetByTaskIds(userId int, taskIds []any) ([]*Task, error)

func GetTimedOutUnfinishedTasks

func GetTimedOutUnfinishedTasks(cutoffUnix int64, limit int) []*Task

func InitTask

func InitTask(platform constant.TaskPlatform, relayInfo *commonRelay.RelayInfo) *Task

func TaskGetAllTasks

func TaskGetAllTasks(startIdx int, num int, queryParams SyncTaskQueryParams) []*Task

func TaskGetAllUserTask

func TaskGetAllUserTask(userId int, startIdx int, num int, queryParams SyncTaskQueryParams) []*Task

func (*Task) GetData

func (t *Task) GetData(v any) error

func (*Task) GetResultURL

func (t *Task) GetResultURL() string

GetResultURL 获取任务结果 URL(视频地址等) 新数据存在 PrivateData.ResultURL 中;旧数据回退到 FailReason(历史兼容)

func (*Task) GetUpstreamTaskID

func (t *Task) GetUpstreamTaskID() string

GetUpstreamTaskID 获取上游真实 task ID(用于与 provider 通信) 旧数据没有 UpstreamTaskID 时,TaskID 本身就是上游 ID

func (*Task) Insert

func (Task *Task) Insert() error

func (*Task) SetData

func (t *Task) SetData(data any)

func (*Task) Snapshot

func (t *Task) Snapshot() taskSnapshot

func (*Task) ToOpenAIVideo

func (t *Task) ToOpenAIVideo() *dto.OpenAIVideo

func (*Task) Update

func (Task *Task) Update() error

func (*Task) UpdateQuota

func (t *Task) UpdateQuota() error

func (*Task) UpdateWithStatus

func (t *Task) UpdateWithStatus(fromStatus TaskStatus) (bool, error)

UpdateWithStatus performs a conditional UPDATE guarded by fromStatus (CAS). Returns (true, nil) if this caller won the update, (false, nil) if another process already moved the task out of fromStatus. MySQL commonly reports changed rows rather than matched rows, so a same-value no-op update can also return false even when the status predicate still matched.

Uses Model().Select("*").Updates() instead of Save() because GORM's Save falls back to INSERT ON CONFLICT when the WHERE-guarded UPDATE matches zero rows, which silently bypasses the CAS guard.

type TaskBillingContext

type TaskBillingContext struct {
	Version         int                `json:"version,omitempty"`
	Complete        bool               `json:"complete,omitempty"`          // All submission rates captured; zero is an explicit free rate.
	ModelPrice      float64            `json:"model_price,omitempty"`       // 模型单价
	GroupRatio      float64            `json:"group_ratio"`                 // 分组倍率
	ModelRatio      float64            `json:"model_ratio"`                 // 模型倍率
	OtherRatios     map[string]float64 `json:"other_ratios,omitempty"`      // 附加倍率(时长、分辨率等)
	OriginModelName string             `json:"origin_model_name,omitempty"` // 模型名称,必须为OriginModelName
	PerCallBilling  bool               `json:"per_call_billing,omitempty"`  // 按次计费:跳过轮询阶段的差额结算
}

TaskBillingContext 记录任务提交时的计费参数,以便轮询阶段可以重新计算额度。

func NewTaskBillingContext

func NewTaskBillingContext(info *commonRelay.RelayInfo) *TaskBillingContext

NewTaskBillingContext freezes the final submission prices, including the selected user's special group rate and an independent other-ratio map.

type TaskBillingEvent

type TaskBillingEvent struct {
	ID                int64                   `json:"id" gorm:"primaryKey"`
	EventID           string                  `json:"event_id" gorm:"type:varchar(64);not null;uniqueIndex:uidx_task_billing_event_id;<-:create"`
	EventKey          string                  `json:"event_key" gorm:"type:varchar(128);not null;uniqueIndex:uidx_task_billing_event_key;<-:create"`
	OperationID       *int64                  `json:"operation_id,omitempty" gorm:"index;<-:create"`
	TaskID            *int64                  `json:"task_id,omitempty" gorm:"index;<-:create"`
	EventType         TaskBillingEventType    `json:"event_type" gorm:"type:varchar(32);not null;index;<-:create"`
	State             TaskBillingEventState   `json:"state" gorm:"type:varchar(24);not null;index:idx_task_billing_ready,priority:1;<-:create"`
	UserID            int                     `json:"user_id" gorm:"not null;index;<-:create"`
	TokenID           int                     `json:"token_id" gorm:"not null;index;<-:create"`
	ChannelID         int                     `json:"channel_id" gorm:"index;<-:create"`
	BillingSource     string                  `json:"billing_source" gorm:"type:varchar(32);not null;<-:create"`
	SubscriptionID    int                     `json:"subscription_id,omitempty" gorm:"index;<-:create"`
	QuotaDelta        int64                   `json:"quota_delta" gorm:"type:bigint;not null;<-:create"`
	RequestID         string                  `json:"request_id,omitempty" gorm:"type:varchar(64);index;<-:create"`
	NodeName          string                  `json:"node_name,omitempty" gorm:"type:varchar(128);<-:create"`
	ReasonCode        string                  `json:"reason_code,omitempty" gorm:"type:varchar(64);<-:create"`
	ResolutionSource  string                  `json:"resolution_source,omitempty" gorm:"type:varchar(32);<-:create"`
	AuditCommandID    string                  `json:"audit_command_id,omitempty" gorm:"type:varchar(48);<-:create"`
	EvidenceID        string                  `json:"evidence_id,omitempty" gorm:"type:varchar(191);not null;default:'';<-:create"`
	EvidenceHash      string                  `json:"evidence_hash,omitempty" gorm:"type:varchar(64);not null;default:'';<-:create"`
	EvidenceVersion   int                     `json:"evidence_version,omitempty" gorm:"not null;default:0;<-:create"`
	StatisticsVersion int                     `json:"statistics_version,omitempty" gorm:"not null;default:0;<-:create"`
	StatisticsApplied bool                    `json:"statistics_applied,omitempty" gorm:"not null;default:false;<-:create"`
	ClaimedBy         string                  `json:"claimed_by,omitempty" gorm:"type:varchar(128);index;<-:create"`
	ClaimedUntil      int64                   `json:"claimed_until,omitempty" gorm:"type:bigint;index;<-:create"`
	AttemptCount      int                     `json:"attempt_count" gorm:"not null;<-:create"`
	NextAttemptAt     int64                   `json:"next_attempt_at,omitempty" gorm:"type:bigint;index:idx_task_billing_ready,priority:2;<-:create"`
	LastErrorCode     string                  `json:"last_error_code,omitempty" gorm:"type:varchar(64);<-:create"`
	LastErrorAt       int64                   `json:"last_error_at,omitempty" gorm:"type:bigint;<-:create"`
	AppliedAt         *int64                  `json:"applied_at,omitempty" gorm:"type:bigint;<-:create"`
	PayloadVersion    int                     `json:"payload_version" gorm:"not null;<-:create"`
	Payload           TaskBillingEventPayload `json:"-" gorm:"type:text;not null;<-:create"`
	LockVersion       int64                   `json:"lock_version" gorm:"type:bigint;not null;<-:create"`
	CreatedAt         int64                   `json:"created_at" gorm:"type:bigint;index;<-:create"`
	UpdatedAt         int64                   `json:"updated_at" gorm:"type:bigint;<-:create"`
}

TaskBillingEvent is the authoritative main-database ledger event. EventKey is a deterministic exactly-once business key; EventID is the stable value copied to the log outbox and projected Log row. Audit fields are bounded codes/references and intentionally exclude arbitrary request/provider data.

func CreateOrLoadTaskBillingEvent

func CreateOrLoadTaskBillingEvent(tx *gorm.DB, candidate *TaskBillingEvent) (*TaskBillingEvent, error)

CreateOrLoadTaskBillingEvent preserves the single canonical event for one operation/type business action. The Task reference is deliberately excluded from the semantic comparison: an event may be recorded before formal Task creation and later replayed through that Task's public operation reference.

func GetTaskBillingEventByEventID

func GetTaskBillingEventByEventID(tx *gorm.DB, stableEventID string) (*TaskBillingEvent, error)

func ListStaleClaimedTaskBillingEvents

func ListStaleClaimedTaskBillingEvents(tx *gorm.DB, now int64, limit int) ([]*TaskBillingEvent, error)

ListStaleClaimedTaskBillingEvents returns billing events that have been in 'claimed' state past their lease expiry.

func (*TaskBillingEvent) BeforeCreate

func (event *TaskBillingEvent) BeforeCreate(tx *gorm.DB) error

func (*TaskBillingEvent) BeforeDelete

func (event *TaskBillingEvent) BeforeDelete(_ *gorm.DB) error

func (*TaskBillingEvent) BeforeUpdate

func (event *TaskBillingEvent) BeforeUpdate(_ *gorm.DB) error

type TaskBillingEventPayload

type TaskBillingEventPayload struct {
	Version           int                  `json:"version"`
	BillingEventID    string               `json:"billing_event_id"`
	EventKey          string               `json:"event_key"`
	EventType         TaskBillingEventType `json:"event_type"`
	OperationID       int64                `json:"operation_id,omitempty"`
	TaskID            int64                `json:"task_id,omitempty"`
	UserID            int                  `json:"user_id"`
	TokenID           int                  `json:"token_id"`
	ChannelID         int                  `json:"channel_id,omitempty"`
	BillingSource     string               `json:"billing_source"`
	SubscriptionID    int                  `json:"subscription_id,omitempty"`
	QuotaDelta        int64                `json:"quota_delta"`
	RequestID         string               `json:"request_id,omitempty"`
	NodeName          string               `json:"node_name,omitempty"`
	ReasonCode        string               `json:"reason_code,omitempty"`
	ResolutionSource  string               `json:"resolution_source,omitempty"`
	AuditCommandID    string               `json:"audit_command_id,omitempty"`
	EvidenceID        string               `json:"evidence_id,omitempty"`
	EvidenceHash      string               `json:"evidence_hash,omitempty"`
	EvidenceVersion   int                  `json:"evidence_version,omitempty"`
	StatisticsVersion int                  `json:"statistics_version,omitempty"`
	StatisticsApplied bool                 `json:"statistics_applied,omitempty"`
}

TaskBillingEventPayload is the immutable v1 application snapshot used when applying or auditing an authoritative billing event. Every field is a bounded identifier, classification or amount already present in the event; there is deliberately no request body, prompt, provider response or credential field.

func (*TaskBillingEventPayload) Scan

func (payload *TaskBillingEventPayload) Scan(value interface{}) error

func (TaskBillingEventPayload) Value

func (payload TaskBillingEventPayload) Value() (driver.Value, error)

type TaskBillingEventState

type TaskBillingEventState string
const (
	TaskBillingEventStatePending      TaskBillingEventState = "pending"
	TaskBillingEventStateClaimed      TaskBillingEventState = "claimed"
	TaskBillingEventStateRetryable    TaskBillingEventState = "retryable"
	TaskBillingEventStateApplied      TaskBillingEventState = "applied"
	TaskBillingEventStateManualReview TaskBillingEventState = "manual_review"
)

func (TaskBillingEventState) Valid

func (state TaskBillingEventState) Valid() bool

type TaskBillingEventTransition

type TaskBillingEventTransition struct {
	From              TaskBillingEventState
	To                TaskBillingEventState
	Lease             TaskRecoveryProcessingLease
	WorkerID          string
	RetryDelaySeconds int64
	LastErrorCode     string
	ExpectedVersion   int64
	TransitionedAt    int64
}

type TaskBillingEventType

type TaskBillingEventType string
const (
	TaskBillingEventTypeReserve              TaskBillingEventType = "reserve"
	TaskBillingEventTypeSubmissionAdjustment TaskBillingEventType = "submission_adjustment"
	TaskBillingEventTypeTerminalSettlement   TaskBillingEventType = "terminal_settlement"
	TaskBillingEventTypeRefund               TaskBillingEventType = "refund"
	TaskBillingEventTypeManualResolution     TaskBillingEventType = "manual_resolution"
)

func (TaskBillingEventType) Valid

func (eventType TaskBillingEventType) Valid() bool

type TaskBillingLogOutbox

type TaskBillingLogOutbox struct {
	ID             int64                     `json:"id" gorm:"primaryKey"`
	BillingEventID string                    `json:"billing_event_id" gorm:"type:varchar(64);not null;uniqueIndex:uidx_task_billing_outbox_event;<-:create"`
	State          TaskBillingLogOutboxState `json:"state" gorm:"type:varchar(24);not null;index:idx_task_billing_outbox_ready,priority:1;<-:create"`
	ClaimedBy      string                    `json:"claimed_by,omitempty" gorm:"type:varchar(128);index;<-:create"`
	ClaimedUntil   int64                     `json:"claimed_until,omitempty" gorm:"type:bigint;index;<-:create"`
	AttemptCount   int                       `json:"attempt_count" gorm:"not null;<-:create"`
	NextAttemptAt  int64                     `json:"next_attempt_at,omitempty" gorm:"type:bigint;index:idx_task_billing_outbox_ready,priority:2;<-:create"`
	LastErrorCode  string                    `json:"last_error_code,omitempty" gorm:"type:varchar(64);<-:create"`
	LastErrorAt    int64                     `json:"last_error_at,omitempty" gorm:"type:bigint;<-:create"`
	DeliveredAt    *int64                    `json:"delivered_at,omitempty" gorm:"type:bigint;<-:create"`
	PayloadVersion int                       `json:"payload_version" gorm:"not null;<-:create"`
	Payload        TaskBillingLogPayload     `json:"-" gorm:"type:text;not null;<-:create"`
	LockVersion    int64                     `json:"lock_version" gorm:"type:bigint;not null;<-:create"`
	CreatedAt      int64                     `json:"created_at" gorm:"type:bigint;index;<-:create"`
	UpdatedAt      int64                     `json:"updated_at" gorm:"type:bigint;<-:create"`
}

TaskBillingLogOutbox gives each authoritative billing event exactly one durable log projection. BillingEventID is the stable event identifier copied to Log.BillingEventID; consumers must tolerate at-least-once delivery and deduplicate by that value.

func CreateOrLoadTaskBillingLogOutbox

func CreateOrLoadTaskBillingLogOutbox(tx *gorm.DB, candidate *TaskBillingLogOutbox) (*TaskBillingLogOutbox, error)

CreateOrLoadTaskBillingLogOutbox gives an authoritative billing event one durable projection receipt. Its immutable payload must match exactly on a retry; different display or usage details cannot silently attach to the existing event.

func EnsureTaskMutationOutbox

func EnsureTaskMutationOutbox(tx *gorm.DB, receipt *QuotaMutationReceipt) (*TaskBillingLogOutbox, error)

EnsureTaskMutationOutbox reconstructs a missing projection only from a validated immutable receipt and its authoritative event.

func ListClaimableTaskBillingLogOutboxes

func ListClaimableTaskBillingLogOutboxes(tx *gorm.DB, now int64, limit int) ([]*TaskBillingLogOutbox, error)

ListClaimableTaskBillingLogOutboxes returns outbox entries that are eligible for worker processing: 1. state == 'pending' 2. state == 'retryable' AND next_attempt_at <= now 3. state == 'claimed' AND claimed_until > 0 AND claimed_until <= now (lease expired)

func NewTaskBillingLogOutbox

func NewTaskBillingLogOutbox(event *TaskBillingEvent, details TaskBillingLogPayload) (*TaskBillingLogOutbox, error)

NewTaskBillingLogOutbox derives every accounting field from an authoritative event. The caller may provide only sanitized display and usage details; the hook reloads the event and verifies the complete projection at insert time.

func (*TaskBillingLogOutbox) BeforeCreate

func (outbox *TaskBillingLogOutbox) BeforeCreate(tx *gorm.DB) error

func (*TaskBillingLogOutbox) BeforeDelete

func (outbox *TaskBillingLogOutbox) BeforeDelete(_ *gorm.DB) error

func (*TaskBillingLogOutbox) BeforeUpdate

func (outbox *TaskBillingLogOutbox) BeforeUpdate(_ *gorm.DB) error

type TaskBillingLogOutboxState

type TaskBillingLogOutboxState string
const (
	TaskBillingLogOutboxStatePending     TaskBillingLogOutboxState = "pending"
	TaskBillingLogOutboxStateClaimed     TaskBillingLogOutboxState = "claimed"
	TaskBillingLogOutboxStateRetryable   TaskBillingLogOutboxState = "retryable"
	TaskBillingLogOutboxStateDelivered   TaskBillingLogOutboxState = "delivered"
	TaskBillingLogOutboxStateQuarantined TaskBillingLogOutboxState = "quarantined"
)

func (TaskBillingLogOutboxState) Valid

func (state TaskBillingLogOutboxState) Valid() bool

type TaskBillingLogOutboxTransition

type TaskBillingLogOutboxTransition struct {
	From              TaskBillingLogOutboxState
	To                TaskBillingLogOutboxState
	Lease             TaskRecoveryProcessingLease
	WorkerID          string
	RetryDelaySeconds int64
	LastErrorCode     string
	ExpectedVersion   int64
	TransitionedAt    int64
}

type TaskBillingLogPayload

type TaskBillingLogPayload struct {
	Version           int    `json:"version"`
	BillingEventID    string `json:"billing_event_id"`
	UserID            int    `json:"user_id"`
	CreatedAt         int64  `json:"created_at"`
	Type              int    `json:"type"`
	Content           string `json:"content"`
	Username          string `json:"username"`
	TokenName         string `json:"token_name"`
	ModelName         string `json:"model_name"`
	Quota             int    `json:"quota"`
	PromptTokens      int    `json:"prompt_tokens"`
	CompletionTokens  int    `json:"completion_tokens"`
	UseTime           int    `json:"use_time"`
	IsStream          bool   `json:"is_stream"`
	ChannelID         int    `json:"channel_id"`
	TokenID           int    `json:"token_id"`
	Group             string `json:"group"`
	IP                string `json:"ip"`
	RequestID         string `json:"request_id"`
	UpstreamRequestID string `json:"upstream_request_id"`
	Other             string `json:"other"`
}

TaskBillingLogPayload is the immutable, complete v1 Log projection copied to the outbox in the same main-database transaction as its billing event. The producer must supply already-sanitized billing log text; raw request bodies, prompts, upstream responses and credentials are forbidden.

func (*TaskBillingLogPayload) Scan

func (payload *TaskBillingLogPayload) Scan(value interface{}) error

func (TaskBillingLogPayload) Value

func (payload TaskBillingLogPayload) Value() (driver.Value, error)

type TaskOperationAPIIdentity

type TaskOperationAPIIdentity struct {
	TokenID     int     `gorm:"column:token_id"`
	UserID      int     `gorm:"column:user_id"`
	TokenStatus int     `gorm:"column:token_status"`
	UserStatus  int     `gorm:"column:user_status"`
	AllowIPs    *string `gorm:"column:allow_ips"`
}

TaskOperationAPIIdentity is the authoritative primary-database view needed to authenticate this read-only endpoint. It intentionally excludes the raw token key and quota data.

func ReadTaskOperationAPIIdentity

func ReadTaskOperationAPIIdentity(key string) (*TaskOperationAPIIdentity, error)

ReadTaskOperationAPIIdentity looks up both the relay token and its owning user from the primary database without consulting or populating Redis. Normal GORM scope excludes soft-deleted rows.

type TaskOperationQueryRow

type TaskOperationQueryRow struct {
	PublicID          string                        `gorm:"column:public_id" json:"-"`
	OperationKind     string                        `gorm:"column:operation_kind" json:"-"`
	Status            TaskSubmissionOperationStatus `gorm:"column:status" json:"-"`
	CreatedAt         int64                         `gorm:"column:created_at" json:"-"`
	UpdatedAt         int64                         `gorm:"column:updated_at" json:"-"`
	DispatchStartedAt *int64                        `gorm:"column:dispatch_started_at" json:"-"`
	ResolvedAt        *int64                        `gorm:"column:resolved_at" json:"-"`
}

TaskOperationQueryRow contains only fields approved for the public owner query. Keeping this projection separate prevents internal operation fields from being serialized by a controller accidentally.

func ReadTaskOperationForOwner

func ReadTaskOperationForOwner(publicID string, userID int, tokenID *int) (*TaskOperationQueryRow, error)

ReadTaskOperationForOwner performs one bounded, read-only primary-database query. The public ID and every applicable owner condition are part of that same SQL statement, so an ownership mismatch is indistinguishable from an absent resource. A nil tokenID denotes a dashboard-session query.

type TaskPrivateData

type TaskPrivateData struct {
	Key            string `json:"key,omitempty"`
	UpstreamTaskID string `json:"upstream_task_id,omitempty"` // 上游真实 task ID
	ResultURL      string `json:"result_url,omitempty"`       // 任务成功后的结果 URL(视频地址等)
	// 计费上下文:用于异步退款/差额结算(轮询阶段读取)
	BillingPreference string              `json:"billing_preference,omitempty"` // 资金来源选择策略快照
	BillingSource     string              `json:"billing_source,omitempty"`     // "wallet" 或 "subscription"
	FreeModel         bool                `json:"free_model,omitempty"`         // 提交时是否为真正免费模型
	SubscriptionId    int                 `json:"subscription_id,omitempty"`    // 订阅 ID,用于订阅退款
	TokenId           int                 `json:"token_id,omitempty"`           // 令牌 ID,用于令牌额度退款
	NodeName          string              `json:"node_name,omitempty"`          // 发起任务的节点名,轮询结算阶段据此归属日志而非最后查询节点
	BillingContext    *TaskBillingContext `json:"billing_context,omitempty"`    // 计费参数快照(用于轮询阶段重新计算)
}

func (*TaskPrivateData) Scan

func (p *TaskPrivateData) Scan(val interface{}) error

func (TaskPrivateData) Value

func (p TaskPrivateData) Value() (driver.Value, error)

type TaskQueryParams

type TaskQueryParams struct {
	ChannelID      string
	MjID           string
	StartTimestamp string
	EndTimestamp   string
}

TaskQueryParams 用于包含所有搜索条件的结构体,可以根据需求添加更多字段

type TaskQuotaBillingContext

type TaskQuotaBillingContext TaskBillingContext

TaskQuotaBillingContext is the immutable, JSON-backed copy of the task price snapshot stored in a receipt. It deliberately has the same fields as the submission TaskBillingContext while owning its database encoding contract.

func (*TaskQuotaBillingContext) Scan

func (snapshot *TaskQuotaBillingContext) Scan(value interface{}) error

func (TaskQuotaBillingContext) Value

func (snapshot TaskQuotaBillingContext) Value() (driver.Value, error)

type TaskQuotaReleaseInput

type TaskQuotaReleaseInput struct {
	OperationID               int64
	UserID                    int
	TokenID                   int
	ChannelID                 int
	ExpectedOperationVersion  int64
	ReasonCode                string
	BillingContext            TaskBillingContext
	TargetOperationStatus     TaskSubmissionOperationStatus
	ResolutionSource          string
	RequireStatisticsEvidence bool
	EvidenceID                string
	EvidenceHash              string
	EvidenceVersion           int
	RequestID                 string
}

TaskQuotaReleaseInput is the complete gate-off T4 refund release input.

type TaskQuotaReservationInput

type TaskQuotaReservationInput struct {
	OperationID              int64
	UserID                   int
	TokenID                  int
	ChannelID                int
	ExpectedOperationVersion int64
	Quota                    int64
	BillingSource            string
	SubscriptionID           int
	BillingPreference        string
	SelectBillingSource      bool
	EstimatedQuota           int64
	FreeModel                bool
	ApplyStatistics          bool
	StatisticsVersion        int
	RequestID                string
	BillingContext           TaskBillingContext
}

TaskQuotaReservationInput is the complete gate-off T1 authorization. Quota is the positive amount to reserve; the authoritative TaskBillingEvent delta is derived internally as -Quota, so callers cannot supply an arbitrary credit.

type TaskQuotaSettlementInput

type TaskQuotaSettlementInput struct {
	OperationID               int64
	UserID                    int
	TokenID                   int
	ChannelID                 int
	ExpectedOperationVersion  int64
	ActualQuota               int64
	ReasonCode                string
	BillingContext            TaskBillingContext
	TargetOperationStatus     TaskSubmissionOperationStatus
	ResolutionSource          string
	RequireStatisticsEvidence bool
	EvidenceID                string
	EvidenceHash              string
	EvidenceVersion           int
	RequestID                 string
}

TaskQuotaSettlementInput is the complete gate-off T3 terminal settlement input.

type TaskQuotaUsage

type TaskQuotaUsage struct {
	Mode  string  `json:"mode"`
	Count float64 `json:"count"`
}

type TaskRecoveryIdentity

type TaskRecoveryIdentity struct {
	ID              int    `json:"-" gorm:"primaryKey;autoIncrement:false;<-:create"`
	ProtocolVersion int    `json:"-" gorm:"not null;<-:create"`
	KeyVerifier     string `json:"-" gorm:"type:char(64);not null;<-:create"`
	CreatedAt       int64  `json:"-" gorm:"type:bigint;not null;<-:create"`
}

TaskRecoveryIdentity is a singleton binding the primary database to the dedicated idempotency key. It stores a verifier, never the key itself. V1 has no automatic rotation/reset/delete path: changing this identity could turn a replay into another billable operation.

func (*TaskRecoveryIdentity) BeforeCreate

func (identity *TaskRecoveryIdentity) BeforeCreate(_ *gorm.DB) error

func (*TaskRecoveryIdentity) BeforeDelete

func (*TaskRecoveryIdentity) BeforeDelete(_ *gorm.DB) error

func (*TaskRecoveryIdentity) BeforeUpdate

func (*TaskRecoveryIdentity) BeforeUpdate(_ *gorm.DB) error

type TaskRecoveryProcessingLease

type TaskRecoveryProcessingLease struct {
	WorkerID     string
	LeaseSeconds int64
}

type TaskStatus

type TaskStatus string

func (TaskStatus) ToVideoStatus

func (t TaskStatus) ToVideoStatus() string

type TaskSubmissionAttempt

type TaskSubmissionAttempt struct {
	ID                  int64                       `json:"id" gorm:"primaryKey"`
	OperationID         int64                       `json:"operation_id" gorm:"not null;uniqueIndex:uidx_task_submission_attempt;<-:create"`
	AttemptNo           int                         `json:"attempt_no" gorm:"not null;<-:create"`
	Status              TaskSubmissionAttemptStatus `json:"status" gorm:"type:varchar(32);not null;index;<-:create"`
	ChannelID           int                         `json:"channel_id" gorm:"not null;index;<-:create"`
	Provider            string                      `json:"provider" gorm:"type:varchar(64);not null;<-:create"`
	RequestClass        string                      `json:"request_class" gorm:"type:varchar(48);not null;<-:create"`
	ProviderOperationID string                      `json:"provider_operation_id,omitempty" gorm:"type:varchar(191);<-:create"`
	UpstreamRequestID   string                      `json:"upstream_request_id,omitempty" gorm:"type:varchar(128);<-:create"`
	TaskPlatform        string                      `json:"task_platform,omitempty" gorm:"type:varchar(30);not null;default:'';<-:create"`
	TaskAction          string                      `json:"task_action,omitempty" gorm:"type:varchar(40);not null;default:'';<-:create"`
	OutcomeCode         string                      `json:"outcome_code,omitempty" gorm:"type:varchar(64);<-:create"`
	StartedAt           *int64                      `json:"started_at,omitempty" gorm:"type:bigint;<-:create"`
	FinishedAt          *int64                      `json:"finished_at,omitempty" gorm:"type:bigint;<-:create"`
	LockVersion         int64                       `json:"lock_version" gorm:"type:bigint;not null;<-:create"`
	CreatedAt           int64                       `json:"created_at" gorm:"type:bigint;index;<-:create"`
	UpdatedAt           int64                       `json:"updated_at" gorm:"type:bigint;<-:create"`
}

TaskSubmissionAttempt contains only routing classification and stable upstream references. Raw upstream requests/responses and credentials are prohibited. V1 creates one attempt and forbids automatic redispatch after it reaches Dispatching; OperationID is unique because v1 permits exactly one.

func CreateOrLoadTaskSubmissionAttempt

func CreateOrLoadTaskSubmissionAttempt(tx *gorm.DB, candidate *TaskSubmissionAttempt) (*TaskSubmissionAttempt, error)

CreateOrLoadTaskSubmissionAttempt records the one v1 dispatch authorization for an operation. It first checks an existing row without locking a missing unique key, then serializes creation through the operation row. This avoids MySQL gap-lock deadlocks while still making PostgreSQL conflict recovery safe.

func FindAttemptByOperationID

func FindAttemptByOperationID(tx *gorm.DB, operationID int64) (*TaskSubmissionAttempt, error)

FindAttemptByOperationID returns the TaskSubmissionAttempt for an operation.

func (*TaskSubmissionAttempt) BeforeCreate

func (attempt *TaskSubmissionAttempt) BeforeCreate(tx *gorm.DB) error

func (*TaskSubmissionAttempt) BeforeDelete

func (attempt *TaskSubmissionAttempt) BeforeDelete(_ *gorm.DB) error

func (*TaskSubmissionAttempt) BeforeUpdate

func (attempt *TaskSubmissionAttempt) BeforeUpdate(_ *gorm.DB) error

type TaskSubmissionAttemptStatus

type TaskSubmissionAttemptStatus string
const (
	TaskSubmissionAttemptStatusPrepared          TaskSubmissionAttemptStatus = "prepared"
	TaskSubmissionAttemptStatusDispatching       TaskSubmissionAttemptStatus = "dispatching"
	TaskSubmissionAttemptStatusAccepted          TaskSubmissionAttemptStatus = "accepted"
	TaskSubmissionAttemptStatusRejected          TaskSubmissionAttemptStatus = "rejected"
	TaskSubmissionAttemptStatusSubmissionUnknown TaskSubmissionAttemptStatus = "submission_unknown"
)

func (TaskSubmissionAttemptStatus) Valid

func (status TaskSubmissionAttemptStatus) Valid() bool

type TaskSubmissionAttemptTransition

type TaskSubmissionAttemptTransition struct {
	From                TaskSubmissionAttemptStatus
	To                  TaskSubmissionAttemptStatus
	ProviderOperationID string
	UpstreamRequestID   string
	TaskPlatform        string
	TaskAction          string
	OutcomeCode         string
	ExpectedVersion     int64
	TransitionedAt      int64
}

type TaskSubmissionDispatchTransition

type TaskSubmissionDispatchTransition struct {
	ExpectedOperationVersion int64
	ExpectedAttemptVersion   int64
	TransitionedAt           int64
}

TaskSubmissionDispatchTransition is the one atomic v1 hand-off from a reserved operation and its prepared sole attempt to dispatching. The same database timestamp is written to both records so a crash cannot create an operation that appears delivered without its dispatch authorization.

type TaskSubmissionIdempotencyScope

type TaskSubmissionIdempotencyScope struct {
	TokenID            int
	HTTPMethod         string
	OperationKind      string
	IdempotencyKeyHash string
}

type TaskSubmissionIntentResult

type TaskSubmissionIntentResult struct {
	Operation *TaskSubmissionOperation
	Attempt   *TaskSubmissionAttempt
	Owner     bool
}

TaskSubmissionIntentResult is the atomic T0 snapshot returned before any reserve or upstream dispatch. Owner is true only when this call inserted both the operation and its sole initial attempt.

func CreateOrLoadTaskSubmissionIntent

func CreateOrLoadTaskSubmissionIntent(tx *gorm.DB, operationCandidate *TaskSubmissionOperation, attemptCandidate *TaskSubmissionAttempt) (*TaskSubmissionIntentResult, error)

CreateOrLoadTaskSubmissionIntent atomically creates an operation and its sole v1 attempt, or returns the already-persisted pair for an idempotent replay. Once an operation exists, its persisted attempt is authoritative: the current routing candidate is deliberately ignored so routing drift does not turn a client replay into an attempt conflict.

A replay whose operation is missing its attempt is rejected as an invalid durable record. Choosing a new channel at that point would invent history and cannot safely repair a submission created outside this transaction.

type TaskSubmissionOperation

type TaskSubmissionOperation struct {
	ID                 int64                         `json:"id" gorm:"primaryKey"`
	PublicID           string                        `json:"public_id" gorm:"type:varchar(48);not null;uniqueIndex:uidx_task_submission_public_id;<-:create"`
	UserID             int                           `json:"user_id" gorm:"not null;index;<-:create"`
	TokenID            int                           `json:"token_id" gorm:"not null;uniqueIndex:uidx_task_submission_idempotency,priority:1;<-:create"`
	HTTPMethod         string                        `json:"http_method" gorm:"type:varchar(16);not null;uniqueIndex:uidx_task_submission_idempotency,priority:2;<-:create"`
	OperationKind      string                        `json:"operation_kind" gorm:"type:varchar(48);not null;uniqueIndex:uidx_task_submission_idempotency,priority:3;<-:create"`
	IdempotencyKeyHash string                        `json:"-" gorm:"type:char(64);not null;uniqueIndex:uidx_task_submission_idempotency,priority:4;<-:create"`
	RequestFingerprint string                        `json:"-" gorm:"type:char(64);not null;<-:create"`
	RequestID          string                        `json:"request_id" gorm:"type:varchar(64);not null;default:'';<-:create"`
	Status             TaskSubmissionOperationStatus `json:"status" gorm:"type:varchar(32);not null;index:idx_task_submission_status_created,priority:1;<-:create"`
	BillingPreference  string                        `json:"billing_preference,omitempty" gorm:"type:varchar(32);not null;default:'';<-:create"`
	BillingSource      string                        `json:"billing_source,omitempty" gorm:"type:varchar(32);not null;default:'';<-:create"`
	SubscriptionID     int                           `json:"subscription_id,omitempty" gorm:"not null;default:0;<-:create"`
	ReservedQuota      int64                         `json:"reserved_quota,omitempty" gorm:"type:bigint;not null;default:0;<-:create"`
	EstimatedQuota     int64                         `json:"estimated_quota,omitempty" gorm:"type:bigint;not null;default:0;<-:create"`
	BillingVersion     int                           `json:"billing_version,omitempty" gorm:"not null;default:0;<-:create"`
	FreeModel          bool                          `json:"free_model,omitempty" gorm:"not null;default:false;<-:create"`
	TaskID             *int64                        `json:"task_id,omitempty" gorm:"uniqueIndex:uidx_task_submission_task;<-:create"`
	ReasonCode         string                        `json:"reason_code,omitempty" gorm:"type:varchar(64);<-:create"`
	ResolutionSource   string                        `json:"resolution_source,omitempty" gorm:"type:varchar(32);<-:create"`
	DispatchStartedAt  *int64                        `json:"dispatch_started_at,omitempty" gorm:"type:bigint;index;<-:create"`
	ResolvedAt         *int64                        `json:"resolved_at,omitempty" gorm:"type:bigint;<-:create"`
	RetentionUntil     *int64                        `json:"retention_until,omitempty" gorm:"type:bigint;index;<-:create"`
	LockVersion        int64                         `json:"lock_version" gorm:"type:bigint;not null;<-:create"`
	CreatedAt          int64                         `json:"created_at" gorm:"type:bigint;index:idx_task_submission_status_created,priority:2;<-:create"`
	UpdatedAt          int64                         `json:"updated_at" gorm:"type:bigint;<-:create"`
}

TaskSubmissionOperation is the durable intent created before an upstream request can be dispatched. It stores only digests and safe references: raw idempotency keys, request bodies, prompts, responses and provider credentials must never be placed in this table.

func CreateOrLoadTaskSubmissionOperation

func CreateOrLoadTaskSubmissionOperation(tx *gorm.DB, candidate *TaskSubmissionOperation) (*TaskSubmissionOperation, error)

CreateOrLoadTaskSubmissionOperation creates the durable idempotency owner or safely returns its existing record. A duplicate scope with a different request fingerprint (or owner) is a protocol conflict and never starts a second operation. ON CONFLICT DO NOTHING keeps PostgreSQL transactions usable for the required post-conflict read.

func FindTaskSubmissionOperationByIdempotencyScope

func FindTaskSubmissionOperationByIdempotencyScope(tx *gorm.DB, scope TaskSubmissionIdempotencyScope) (*TaskSubmissionOperation, error)

func GetTaskSubmissionOperationByPublicID

func GetTaskSubmissionOperationByPublicID(tx *gorm.DB, publicID string) (*TaskSubmissionOperation, error)

func ListStaleDispatchingOperations

func ListStaleDispatchingOperations(tx *gorm.DB, cutoffTime int64, limit int) ([]*TaskSubmissionOperation, error)

ListStaleDispatchingOperations returns operations stuck in 'dispatching' whose dispatch_started_at is at or before cutoffTime.

func ListUnfinishedPreparedOrReservedOperations

func ListUnfinishedPreparedOrReservedOperations(tx *gorm.DB, cutoffTime int64, limit int) ([]*TaskSubmissionOperation, error)

ListUnfinishedPreparedOrReservedOperations returns operations in 'prepared' or 'reserved' created at or before cutoffTime.

func ListUnknownTaskSubmissionOperations

func ListUnknownTaskSubmissionOperations(tx *gorm.DB, limit int) ([]*TaskSubmissionOperation, error)

ListUnknownTaskSubmissionOperations returns operations in 'submission_unknown' or 'outcome_unknown' that await provider inquiry or manual resolution.

func (*TaskSubmissionOperation) BeforeCreate

func (operation *TaskSubmissionOperation) BeforeCreate(tx *gorm.DB) error

func (*TaskSubmissionOperation) BeforeDelete

func (operation *TaskSubmissionOperation) BeforeDelete(_ *gorm.DB) error

func (*TaskSubmissionOperation) BeforeUpdate

func (operation *TaskSubmissionOperation) BeforeUpdate(_ *gorm.DB) error

type TaskSubmissionOperationStatus

type TaskSubmissionOperationStatus string

TaskSubmissionOperationStatus is the durable, client-queryable lifecycle of one modern task submission. SubmissionUnknown and OutcomeUnknown are both intentionally non-terminal: neither state may expire or trigger an automatic resend/refund without a separately audited resolution.

const (
	TaskSubmissionOperationStatusPrepared          TaskSubmissionOperationStatus = "prepared"
	TaskSubmissionOperationStatusReserved          TaskSubmissionOperationStatus = "reserved"
	TaskSubmissionOperationStatusDispatching       TaskSubmissionOperationStatus = "dispatching"
	TaskSubmissionOperationStatusAccepted          TaskSubmissionOperationStatus = "accepted"
	TaskSubmissionOperationStatusRejected          TaskSubmissionOperationStatus = "rejected"
	TaskSubmissionOperationStatusSubmissionUnknown TaskSubmissionOperationStatus = "submission_unknown"
	TaskSubmissionOperationStatusOutcomeUnknown    TaskSubmissionOperationStatus = "outcome_unknown"
	TaskSubmissionOperationStatusSucceeded         TaskSubmissionOperationStatus = "succeeded"
	TaskSubmissionOperationStatusFailed            TaskSubmissionOperationStatus = "failed"
	TaskSubmissionOperationStatusCanceled          TaskSubmissionOperationStatus = "canceled"
)

func (TaskSubmissionOperationStatus) Terminal

func (status TaskSubmissionOperationStatus) Terminal() bool

func (TaskSubmissionOperationStatus) Valid

func (status TaskSubmissionOperationStatus) Valid() bool

type TaskSubmissionOperationTransition

type TaskSubmissionOperationTransition struct {
	From             TaskSubmissionOperationStatus
	To               TaskSubmissionOperationStatus
	TaskID           *int64
	ReasonCode       string
	ResolutionSource string
	AuditCommandID   string
	TransitionedAt   int64
	RetentionUntil   *int64
	ExpectedVersion  int64
}

type TaskTerminalApplyResult

type TaskTerminalApplyResult struct {
	Observation *TaskTerminalObservation
	Receipt     *QuotaMutationReceipt
	Outbox      *TaskBillingLogOutbox
}

func ApplyTaskTerminalObservation

func ApplyTaskTerminalObservation(db *gorm.DB, observationID int64) (*TaskTerminalApplyResult, error)

type TaskTerminalObservation

type TaskTerminalObservation struct {
	ID                      int64                        `gorm:"primaryKey"`
	OperationID             int64                        `gorm:"not null;uniqueIndex"`
	TaskID                  int64                        `gorm:"not null;index"`
	Outcome                 string                       `gorm:"type:varchar(16);not null"`
	ActualQuota             int64                        `gorm:"type:bigint;not null"`
	TaskStatus              TaskStatus                   `gorm:"type:varchar(20);not null"`
	ReasonCode              string                       `gorm:"type:varchar(64);not null"`
	RequestID               string                       `gorm:"type:varchar(64);not null;default:''"`
	ResolutionSource        string                       `gorm:"type:varchar(32);not null;default:''"`
	EvidenceID              string                       `gorm:"type:varchar(191);not null;default:''"`
	EvidenceHash            string                       `gorm:"type:varchar(64);not null;default:''"`
	EvidenceVersion         int                          `gorm:"not null;default:0"`
	ResultURL               string                       `gorm:"type:text"`
	TaskData                string                       `json:"-" gorm:"type:text"`
	TaskStartTime           int64                        `json:"-" gorm:"type:bigint;not null;default:0"`
	TaskFinishTime          int64                        `json:"-" gorm:"type:bigint;not null;default:0"`
	OperationalResultURL    string                       `json:"-" gorm:"type:text"`
	TaskUpstreamID          string                       `json:"-" gorm:"type:varchar(191);not null;default:''"`
	ClampOp                 string                       `gorm:"type:varchar(32);not null;default:''"`
	ClampKind               string                       `gorm:"type:varchar(32);not null;default:''"`
	ClampOriginal           string                       `gorm:"type:varchar(64);not null;default:''"`
	ClampClamped            int                          `gorm:"not null;default:0"`
	ConflictCount           int                          `gorm:"not null;default:0"`
	LastConflictFingerprint string                       `gorm:"type:varchar(64);not null;default:''"`
	Fingerprint             string                       `gorm:"type:char(64);not null"`
	State                   TaskTerminalObservationState `gorm:"type:varchar(24);not null;index"`
	AppliedAt               *int64                       `gorm:"type:bigint"`
	CreatedAt               int64                        `gorm:"type:bigint;not null"`
	UpdatedAt               int64                        `gorm:"type:bigint;not null"`
	LockVersion             int64                        `gorm:"type:bigint;not null"`
	RetentionUntil          int64                        `gorm:"type:bigint;index"`
	AttemptCount            int                          `gorm:"not null;default:0"`
	NextAttemptAt           int64                        `gorm:"type:bigint;not null;default:0;index"`
	LastErrorCode           string                       `gorm:"type:varchar(64);not null;default:''"`
}

func CreateOrLoadTaskTerminalObservation

func CreateOrLoadTaskTerminalObservation(db *gorm.DB, input TaskTerminalObservationInput) (*TaskTerminalObservation, error)

func (*TaskTerminalObservation) BeforeCreate

func (o *TaskTerminalObservation) BeforeCreate(tx *gorm.DB) error

func (*TaskTerminalObservation) BeforeDelete

func (*TaskTerminalObservation) BeforeDelete(_ *gorm.DB) error

func (*TaskTerminalObservation) BeforeUpdate

func (*TaskTerminalObservation) BeforeUpdate(_ *gorm.DB) error

type TaskTerminalObservationInput

type TaskTerminalObservationInput struct {
	OperationID          int64
	TaskID               int64
	Outcome              string
	ActualQuota          int64
	ReasonCode           string
	RequestID            string
	ManualReview         bool
	ResolutionSource     string
	EvidenceID           string
	EvidenceHash         string
	EvidenceVersion      int
	ResultURL            string
	TaskData             string
	TaskStartTime        int64
	TaskFinishTime       int64
	OperationalResultURL string
	TaskUpstreamID       string
	QuotaClamp           *common.QuotaClamp
}

type TaskTerminalObservationState

type TaskTerminalObservationState string
const (
	TaskTerminalObservationPending      TaskTerminalObservationState = "pending"
	TaskTerminalObservationRetryable    TaskTerminalObservationState = "retryable"
	TaskTerminalObservationApplied      TaskTerminalObservationState = "applied"
	TaskTerminalObservationManualReview TaskTerminalObservationState = "manual_review"
)

type Token

type Token struct {
	Id                 int     `json:"id"`
	UserId             int     `json:"user_id" gorm:"index"`
	Key                string  `json:"key" gorm:"type:varchar(128);uniqueIndex"`
	Status             int     `json:"status" gorm:"default:1"`
	Name               string  `json:"name" gorm:"index" `
	CreatedTime        int64   `json:"created_time" gorm:"bigint"`
	AccessedTime       int64   `json:"accessed_time" gorm:"bigint"`
	ExpiredTime        int64   `json:"expired_time" gorm:"bigint;default:-1"` // -1 means never expired
	RemainQuota        int     `json:"remain_quota" gorm:"default:0"`
	QuotaVersion       int64   `json:"-" gorm:"type:bigint;not null;default:0"`
	UnlimitedQuota     bool    `json:"unlimited_quota"`
	ModelLimitsEnabled bool    `json:"model_limits_enabled"`
	ModelLimits        string  `json:"model_limits" gorm:"type:text"`
	AllowIps           *string `json:"allow_ips" gorm:"default:''"`
	UsedQuota          int     `json:"used_quota" gorm:"default:0"` // used quota
	Group              string  `json:"group" gorm:"default:''"`
	// AccessProfileID is the stable key-routing identity. Group remains the
	// persisted compatibility input for old clients and channel selection.
	AccessProfileID string         `json:"access_profile_id" gorm:"column:access_profile_id;type:varchar(64);default:'standard';index"`
	CrossGroupRetry bool           `json:"cross_group_retry"` // 跨分组重试,仅auto分组有效
	AutoGroups      string         `json:"-" gorm:"type:text"`
	DeletedAt       gorm.DeletedAt `gorm:"index"`
}

func GetAllUserTokens

func GetAllUserTokens(userId int, startIdx int, num int) ([]*Token, error)

func GetTokenById

func GetTokenById(id int) (*Token, error)

func GetTokenByIds

func GetTokenByIds(id int, userId int) (*Token, error)

func GetTokenByKey

func GetTokenByKey(key string, fromDB bool) (token *Token, err error)

func GetTokenKeysByIds

func GetTokenKeysByIds(ids []int, userId int) ([]Token, error)

func SearchUserTokens

func SearchUserTokens(userId int, keyword string, token string, offset int, limit int) (tokens []*Token, total int64, err error)

func ValidateUserToken

func ValidateUserToken(key string) (token *Token, err error)

func (*Token) Clean

func (token *Token) Clean()

func (*Token) Delete

func (token *Token) Delete() (err error)

func (*Token) GetAutoGroups

func (token *Token) GetAutoGroups() ([]string, error)

func (*Token) GetFullKey

func (token *Token) GetFullKey() string

func (*Token) GetIpLimits

func (token *Token) GetIpLimits() []string

func (*Token) GetMaskedKey

func (token *Token) GetMaskedKey() string

func (*Token) GetModelLimits

func (token *Token) GetModelLimits() []string

func (*Token) GetModelLimitsMap

func (token *Token) GetModelLimitsMap() map[string]bool

func (*Token) Insert

func (token *Token) Insert() error

func (*Token) IsModelLimitsEnabled

func (token *Token) IsModelLimitsEnabled() bool

func (*Token) SelectUpdate

func (token *Token) SelectUpdate() (err error)

func (*Token) SetAutoGroups

func (token *Token) SetAutoGroups(groups []string) error

func (*Token) Update

func (token *Token) Update() (err error)

Update Make sure your token's fields is completed, because this will update non-zero values

type TokenBudget

type TokenBudget struct {
	AccountThresholdEnabled bool   `json:"account_threshold_enabled" gorm:"not null;default:false"`
	AccountMinRemainingBPS  int    `json:"account_min_remaining_bps" gorm:"not null;default:0"`
	AccountMaxAgeSeconds    int64  `json:"account_max_age_seconds" gorm:"not null;default:300"`
	FeeEnabled              bool   `json:"fee_enabled" gorm:"not null;default:false"`
	FeeLimitUSD             string `json:"fee_limit_usd" gorm:"type:varchar(128);not null;default:'0'"`
	FeeUsedUSD              string `json:"fee_used_usd" gorm:"type:varchar(128);not null;default:'0'"`
	FeeReservedUSD          string `json:"fee_reserved_usd" gorm:"type:varchar(128);not null;default:'0'"`
	TokenID                 int    `json:"token_id" gorm:"primaryKey;autoIncrement:false"`
	UserID                  int    `json:"user_id" gorm:"not null;index"`
	Enabled                 bool   `json:"enabled" gorm:"not null"`
	Limit                   int64  `json:"limit" gorm:"column:token_limit;type:bigint;not null"`
	Used                    int64  `json:"used" gorm:"type:bigint;not null"`
	Reserved                int64  `json:"reserved" gorm:"type:bigint;not null"`
	PendingRequestID        string `json:"pending_request_id" gorm:"type:varchar(64);not null"`
	Revision                int64  `json:"revision" gorm:"type:bigint;not null"`
}

func ConfigureTokenBudget

func ConfigureTokenBudget(ctx context.Context, db *gorm.DB, actorID int, input TokenBudgetPolicyInput) (*TokenBudget, error)

func LookupTokenBudget

func LookupTokenBudget(ctx context.Context, db *gorm.DB, tokenID int) (*TokenBudget, error)

LookupTokenBudget is an internal admission read. A missing row means the feature is unconfigured; missing schema or unavailable storage is an error.

type TokenBudgetMutation

type TokenBudgetMutation struct {
	FeeUSD    *string
	TokenID   int
	RequestID string
	Action    string
	Input     int64
	Output    int64
	ActorID   int
	Evidence  string
	Reason    string
}

Mutations serialize through the budget before reading the request. A sent request can never be released through the pre-dispatch cancellation action.

type TokenBudgetPolicyChange

type TokenBudgetPolicyChange struct {
	ID         string `json:"id" gorm:"type:varchar(64);primaryKey"`
	Digest     string `json:"digest" gorm:"type:varchar(64);not null"`
	ActorID    int    `json:"actor_id" gorm:"not null"`
	TokenID    int    `json:"token_id" gorm:"not null;index"`
	BeforeJSON string `json:"before" gorm:"type:text;not null"`
	AfterJSON  string `json:"after" gorm:"type:text;not null"`
	CreatedAt  int64  `json:"created_at" gorm:"type:bigint;not null"`
}

func (*TokenBudgetPolicyChange) BeforeDelete

func (*TokenBudgetPolicyChange) BeforeDelete(*gorm.DB) error

func (*TokenBudgetPolicyChange) BeforeUpdate

func (*TokenBudgetPolicyChange) BeforeUpdate(*gorm.DB) error

type TokenBudgetPolicyInput

type TokenBudgetPolicyInput struct {
	AccountThreshold *AccountQuotaThresholdPolicyInput `json:"account_threshold,omitempty"`
	Fee              *FeeBudgetPolicyInput             `json:"fee,omitempty"`
	ID               string                            `json:"id"`
	TokenID          int                               `json:"token_id"`
	ExpectedRevision int64                             `json:"expected_revision"`
	Enabled          bool                              `json:"enabled"`
	Limit            int64                             `json:"limit"`
}

type TokenBudgetReservation

type TokenBudgetReservation struct {
	RequestServiceTier string  `json:"request_service_tier" gorm:"type:varchar(32);not null;default:''"`
	ObservedFeeUSD     *string `json:"observed_fee_usd" gorm:"type:varchar(128)"`
	FeeEnabled         bool    `json:"fee_enabled" gorm:"not null;default:false"`
	FeeReservedUSD     string  `json:"fee_reserved_usd" gorm:"type:varchar(128);not null;default:'0'"`
	ActualFeeUSD       *string `json:"actual_fee_usd" gorm:"type:varchar(128)"`
	FeePriceEvidence   string  `json:"-" gorm:"type:text"`
	PricingEvidence    string  `json:"-" gorm:"type:text"`
	BoundSource        string  `json:"bound_source" gorm:"type:varchar(64);not null;default:''"`
	RequestID          string  `json:"request_id" gorm:"type:varchar(64);primaryKey"`
	TokenID            int     `json:"token_id" gorm:"not null;index"`
	UserID             int     `json:"user_id" gorm:"not null;index"`
	ChannelID          int     `json:"channel_id" gorm:"not null"`
	ModelName          string  `json:"model_name" gorm:"size:512;not null"`
	PayloadSHA256      string  `json:"payload_sha256" gorm:"type:varchar(64);not null"`
	InputTokens        int64   `json:"input_tokens_bound" gorm:"type:bigint;not null"`
	MaxOutputTokens    int64   `json:"max_output_tokens" gorm:"type:bigint;not null"`
	Reserved           int64   `json:"reserved" gorm:"type:bigint;not null"`
	State              string  `json:"state" gorm:"type:varchar(16);not null;index"`
	ActualInput        *int64  `json:"actual_input" gorm:"type:bigint"`
	ActualOutput       *int64  `json:"actual_output" gorm:"type:bigint"`
	ObservedInput      *int64  `json:"observed_input" gorm:"type:bigint"`
	ObservedOutput     *int64  `json:"observed_output" gorm:"type:bigint"`
	Reason             string  `json:"reason" gorm:"type:varchar(64);not null"`
	ReviewedBy         int     `json:"reviewed_by" gorm:"not null"`
	EvidenceReference  string  `json:"evidence_reference,omitempty" gorm:"size:2048;not null"`
	EvidenceDigest     string  `json:"evidence_digest" gorm:"type:varchar(64);not null"`
	CreatedAt          int64   `json:"created_at" gorm:"type:bigint;not null"`
	UpdatedAt          int64   `json:"updated_at" gorm:"type:bigint;not null"`
}

A pre-dispatch record remains blocking even if persisting an unknown marker fails. There is intentionally no lease expiry or automatic refund of Sent.

func CancelTokenBudgetBeforeSend

func CancelTokenBudgetBeforeSend(ctx context.Context, db *gorm.DB, actorID, tokenID int, requestID, evidence string) (*TokenBudgetReservation, error)

CancelTokenBudgetBeforeSend records the audited no-send proof and the old quota refund intent together. The old recovery engine applies that intent; neither a sent request nor unknown usage can take this path.

func MutateTokenBudgetRequest

func MutateTokenBudgetRequest(ctx context.Context, db *gorm.DB, input TokenBudgetMutation) (*TokenBudgetReservation, error)

type TokenBudgetView

type TokenBudgetView struct {
	Policy  TokenBudget             `json:"policy"`
	Pending *TokenBudgetReservation `json:"pending"`
	Review  *UsageReviewDetail      `json:"review,omitempty"`
}

func ReadTokenBudget

func ReadTokenBudget(ctx context.Context, db *gorm.DB, actorID, tokenID int) (*TokenBudgetView, error)

type TopUp

type TopUp struct {
	Id              int     `json:"id"`
	UserId          int     `json:"user_id" gorm:"index"`
	Amount          int64   `json:"amount"`
	Money           float64 `json:"money"`
	TradeNo         string  `json:"trade_no" gorm:"unique;type:varchar(255);index"`
	PaymentMethod   string  `json:"payment_method" gorm:"type:varchar(50)"`
	PaymentProvider string  `json:"payment_provider" gorm:"type:varchar(50);default:''"`
	// Historical orders remain empty; never backfill from current settings.
	QuotaPerUnitSnapshot  string `json:"-" gorm:"type:varchar(64);not null;default:''"`
	CreemProductID        string `json:"-" gorm:"type:varchar(128);not null;default:''"`
	CreemCurrency         string `json:"-" gorm:"type:varchar(16);not null;default:''"`
	WaffoPancakeStoreID   string `json:"-" gorm:"type:varchar(128);not null;default:''"`
	WaffoPancakeProductID string `json:"-" gorm:"type:varchar(128);not null;default:''"`
	WaffoPancakeCurrency  string `json:"-" gorm:"type:varchar(16);not null;default:''"`
	CreateTime            int64  `json:"create_time"`
	CompleteTime          int64  `json:"complete_time"`
	Status                string `json:"status"`
	FundingEpoch          uint64 `json:"funding_epoch" gorm:"not null;default:0;index"`
}

func GetAllTopUps

func GetAllTopUps(pageInfo *common.PageInfo) (topups []*TopUp, total int64, err error)

GetAllTopUps 获取全平台的充值记录(管理员使用,不限制时间窗口)

func GetTopUpById

func GetTopUpById(id int) *TopUp

func GetTopUpByTradeNo

func GetTopUpByTradeNo(tradeNo string) *TopUp

func GetTopUpByTradeNoWithError

func GetTopUpByTradeNoWithError(tradeNo string) (*TopUp, error)

GetTopUpByTradeNoWithError distinguishes a missing order from a failed query so payment callbacks can request a retry after temporary database failures.

func GetUserTopUps

func GetUserTopUps(userId int, pageInfo *common.PageInfo) (topups []*TopUp, total int64, err error)

func SearchAllTopUps

func SearchAllTopUps(keyword string, pageInfo *common.PageInfo) (topups []*TopUp, total int64, err error)

SearchAllTopUps 按订单号搜索全平台充值记录(管理员使用,不限制时间窗口)

func SearchUserTopUps

func SearchUserTopUps(userId int, keyword string, pageInfo *common.PageInfo) (topups []*TopUp, total int64, err error)

SearchUserTopUps 按订单号搜索某用户的充值记录

func (*TopUp) Insert

func (topUp *TopUp) Insert(expectedEpoch ...uint64) error

func (*TopUp) Update

func (topUp *TopUp) Update() error

type TwoFA

type TwoFA struct {
	Id             int            `json:"id" gorm:"primaryKey"`
	UserId         int            `json:"user_id" gorm:"unique;not null;index"`
	Secret         string         `json:"-" gorm:"type:varchar(255);not null"` // TOTP密钥,不返回给前端
	IsEnabled      bool           `json:"is_enabled"`
	FailedAttempts int            `json:"failed_attempts" gorm:"default:0"`
	LockedUntil    *time.Time     `json:"locked_until,omitempty"`
	LastUsedAt     *time.Time     `json:"last_used_at,omitempty"`
	CreatedAt      time.Time      `json:"created_at"`
	UpdatedAt      time.Time      `json:"updated_at"`
	DeletedAt      gorm.DeletedAt `json:"-" gorm:"index"`
}

TwoFA 用户2FA设置表

func GetTwoFAByUserId

func GetTwoFAByUserId(userId int) (*TwoFA, error)

GetTwoFAByUserId 根据用户ID获取2FA设置

func (*TwoFA) CreatePendingTwoFASetup

func (t *TwoFA) CreatePendingTwoFASetup() error

CreatePendingTwoFASetup stores a disabled factor while the user completes enrollment. Enabling a factor must use EnableWithAuthVersion.

func (*TwoFA) DeletePendingTwoFASetup

func (t *TwoFA) DeletePendingTwoFASetup() error

DeletePendingTwoFASetup removes only an unverified setup. Enabled factors must use DisableTwoFAWithAuthVersion.

func (*TwoFA) EnableWithAuthVersion

func (t *TwoFA) EnableWithAuthVersion() error

EnableWithAuthVersion atomically enables this factor and advances the user authentication version so pre-enrollment sessions cannot remain valid.

func (*TwoFA) IncrementFailedAttempts

func (t *TwoFA) IncrementFailedAttempts() error

IncrementFailedAttempts 增加失败尝试次数

func (*TwoFA) IsLocked

func (t *TwoFA) IsLocked() bool

IsLocked 检查账户是否被锁定

func (*TwoFA) ResetFailedAttempts

func (t *TwoFA) ResetFailedAttempts() error

ResetFailedAttempts 重置失败尝试次数

func (*TwoFA) ValidateBackupCodeAndUpdateUsage

func (t *TwoFA) ValidateBackupCodeAndUpdateUsage(code string) (bool, error)

ValidateBackupCodeAndUpdateUsage 验证备用码并更新使用记录

func (*TwoFA) ValidateTOTPAndUpdateUsage

func (t *TwoFA) ValidateTOTPAndUpdateUsage(code string) (bool, error)

ValidateTOTPAndUpdateUsage 验证TOTP并更新使用记录

type TwoFABackupCode

type TwoFABackupCode struct {
	Id        int            `json:"id" gorm:"primaryKey"`
	UserId    int            `json:"user_id" gorm:"not null;index"`
	CodeHash  string         `json:"-" gorm:"type:varchar(255);not null"` // 备用码哈希
	IsUsed    bool           `json:"is_used"`
	UsedAt    *time.Time     `json:"used_at,omitempty"`
	CreatedAt time.Time      `json:"created_at"`
	DeletedAt gorm.DeletedAt `json:"-" gorm:"index"`
}

TwoFABackupCode 备用码使用记录表

type TypedBulkFieldError

type TypedBulkFieldError struct {
	Kind   error
	Key    string
	Reason string
}

TypedBulkFieldError describes one rejected request item. Kind is one of the sentinel errors above; Key identifies the offending option key when applicable; Reason carries the underlying validator detail.

func (*TypedBulkFieldError) Error

func (e *TypedBulkFieldError) Error() string

func (*TypedBulkFieldError) Is

func (e *TypedBulkFieldError) Is(target error) bool

type TypedBulkOption

type TypedBulkOption struct {
	Key   string          `json:"key"`
	Type  string          `json:"type"`
	Value json.RawMessage `json:"value"`
}

TypedBulkOption is one typed bulk request item. Value carries the raw JSON lexeme so the declared Type can be enforced against the actual JSON type.

type TypedBulkRevisionConflictError

type TypedBulkRevisionConflictError struct {
	Expected int64
	Actual   int64
}

TypedBulkRevisionConflictError reports a failed expected-revision CAS check.

func (*TypedBulkRevisionConflictError) Error

func (*TypedBulkRevisionConflictError) Is

type UsageReviewDecision

type UsageReviewDecision struct {
	ActualFeeUSD       *string `json:"actual_fee_usd,omitempty" gorm:"type:varchar(128)"`
	ActualInputTokens  *int64  `json:"actual_input_tokens,omitempty" gorm:"type:bigint"`
	ActualOutputTokens *int64  `json:"actual_output_tokens,omitempty" gorm:"type:bigint"`
	ID                 int64   `json:"id" gorm:"primaryKey"`
	RequestID          string  `json:"request_id" gorm:"type:varchar(64);not null;uniqueIndex"`
	ActorID            int     `json:"actor_id" gorm:"not null"`
	UserID             int     `json:"user_id" gorm:"not null"`
	TokenID            int     `json:"token_id" gorm:"not null"`
	ChannelID          int     `json:"channel_id" gorm:"not null"`
	ModelName          string  `json:"model_name" gorm:"size:512"`
	ActualQuota        int64   `json:"actual_quota" gorm:"type:bigint;not null"`
	EvidenceReference  string  `json:"evidence_reference" gorm:"size:2048;not null"`
	EvidenceDigest     string  `json:"evidence_digest" gorm:"type:char(64);not null"`
	CreatedAt          int64   `json:"created_at" gorm:"type:bigint;not null"`
	StatisticsApplied  bool    `json:"statistics_applied" gorm:"not null"`
	LogProjected       bool    `json:"log_projected" gorm:"not null;index"`
}

UsageReviewDecision is the immutable evidence reference for a manual resolution. It contains no prompts, credentials or provider response bodies.

func (*UsageReviewDecision) BeforeDelete

func (*UsageReviewDecision) BeforeDelete(*gorm.DB) error

func (*UsageReviewDecision) BeforeUpdate

func (*UsageReviewDecision) BeforeUpdate(*gorm.DB) error

func (UsageReviewDecision) TableName

func (UsageReviewDecision) TableName() string

type UsageReviewDetail

type UsageReviewDetail struct {
	TextDispatchPending    bool                    `json:"text_dispatch_pending"`
	CanRecoverTextDispatch bool                    `json:"can_recover_text_dispatch"`
	TokenBudget            *TokenBudgetReservation `json:"token_budget,omitempty"`
	RequestID              string                  `json:"request_id"`
	UserID                 int                     `json:"user_id"`
	TokenID                int                     `json:"token_id"`
	ChannelID              int                     `json:"channel_id"`
	ModelName              string                  `json:"model_name"`
	Writer                 string                  `json:"writer"`
	State                  string                  `json:"state"`
	ReservedQuota          int64                   `json:"reserved_quota"`
	ActualQuota            *int64                  `json:"actual_quota"`
	Reason                 string                  `json:"reason"`
	ReviewMetadata         string                  `json:"review_metadata"`
	ReserveReceiptID       int64                   `json:"reserve_receipt_id,omitempty"`
	Decision               *UsageReviewDecision    `json:"decision,omitempty"`
}

func GetUsageReview

func GetUsageReview(ctx context.Context, db *gorm.DB, actorID int, requestID string) (*UsageReviewDetail, error)

func PrepareTokenBudgetUsageReview

func PrepareTokenBudgetUsageReview(ctx context.Context, db *gorm.DB, actorID, tokenID int, requestID string, feeUSD ...*string) (*UsageReviewDetail, error)

A Root-confirmed review can recover a lost post-dispatch hold using the pricing evidence saved before dispatch. It never releases the token reserve or manufactures a terminal amount; the ordinary audited review follows.

func ReconcileUsageReview

func ReconcileUsageReview(ctx context.Context, db *gorm.DB, actorID int, requestID string, actual int64, evidence string, tokenCounts ...UsageReviewTokenCounts) (*UsageReviewDetail, error)

func RecoverTextDispatchUsage

func RecoverTextDispatchUsage(ctx context.Context, db *gorm.DB, actorID int, requestID string, actual int64, evidence string) (*UsageReviewDetail, error)

RecoverTextDispatchUsage requires an explicit finished-request confirmation at the API. It cannot infer no-send from age or refund an unknown request.

type UsageReviewPage

type UsageReviewPage struct {
	Items     []*UsageReviewDetail `json:"items"`
	NextAfter string               `json:"next_after"`
}

func ListPendingUsageReviews

func ListPendingUsageReviews(ctx context.Context, db *gorm.DB, actorID int, writer string, after int64) (*UsageReviewPage, error)

A bounded keyset scan, not a COUNT or an unbounded scan of all historical requests. Empty pages may carry a cursor when non-text open rows were skipped.

type UsageReviewTokenCounts

type UsageReviewTokenCounts struct {
	FeeUSD *string `json:"fee_usd,omitempty"`
	Input  int64
	Output int64
}

type User

type User struct {
	Id               int    `json:"id"`
	Username         string `json:"username" gorm:"unique;index" validate:"max=20"`
	Password         string `json:"password" gorm:"not null;" validate:"min=8,max=20"`
	OriginalPassword string `json:"original_password" gorm:"-:all"` // this field is only for Password change verification, don't save it to database!
	DisplayName      string `json:"display_name" gorm:"index" validate:"max=20"`
	Role             int    `json:"role" gorm:"type:int;default:1"`   // admin, common
	Status           int    `json:"status" gorm:"type:int;default:1"` // enabled, disabled
	Email            string `json:"email" gorm:"index" validate:"max=50"`
	// EmailNormalized is an internal, nullable key used for portable
	// case-insensitive uniqueness. Empty emails remain NULL so multiple users
	// may omit an email without colliding on the unique index.
	EmailNormalized  *string `json:"-" gorm:"column:email_normalized;type:varchar(50)"`
	GitHubId         string  `json:"github_id" gorm:"column:github_id;index"`
	DiscordId        string  `json:"discord_id" gorm:"column:discord_id;index"`
	OidcId           string  `json:"oidc_id" gorm:"column:oidc_id;index"`
	WeChatId         string  `json:"wechat_id" gorm:"column:wechat_id;index"`
	TelegramId       string  `json:"telegram_id" gorm:"column:telegram_id;index"`
	VerificationCode string  `json:"verification_code" gorm:"-:all"`                         // this field is only for Email verification, don't save it to database!
	AccessToken      *string `json:"-" gorm:"type:char(32);column:access_token;uniqueIndex"` // this token is for system management
	// Private policy: public user/profile DTOs cannot toggle funding behavior.
	SelfUseNoBalance    bool   `json:"-" gorm:"not null;default:false"`
	UsagePolicyRevision int64  `json:"-" gorm:"type:bigint;not null;default:0"`
	Quota               int    `json:"quota" gorm:"type:int;default:0"`
	QuotaVersion        int64  `json:"-" gorm:"type:bigint;not null;default:0"`
	UsedQuota           int    `json:"used_quota" gorm:"type:int;default:0;column:used_quota"` // used quota
	RequestCount        int    `json:"request_count" gorm:"type:int;default:0;"`               // request number
	Group               string `json:"group" gorm:"type:varchar(64);default:'default'"`
	// AccountTierID is the explicit account-level identity introduced alongside
	// the legacy group compatibility field. Routing still reads Group until the
	// independent account-tier policy is configured.
	AccountTierID    string                     `json:"account_tier_id" gorm:"column:account_tier_id;type:varchar(64);default:'standard';index"`
	AffCode          string                     `json:"aff_code" gorm:"type:varchar(32);column:aff_code;uniqueIndex"`
	AffCount         int                        `json:"aff_count" gorm:"type:int;default:0;column:aff_count"`
	AffQuota         int                        `json:"aff_quota" gorm:"type:int;default:0;column:aff_quota"`           // 邀请剩余额度
	AffHistoryQuota  int                        `json:"aff_history_quota" gorm:"type:int;default:0;column:aff_history"` // 邀请历史额度
	InviterId        int                        `json:"inviter_id" gorm:"type:int;column:inviter_id;index"`
	DeletedAt        gorm.DeletedAt             `gorm:"index"`
	LinuxDOId        string                     `json:"linux_do_id" gorm:"column:linux_do_id;index"`
	Setting          string                     `json:"setting" gorm:"type:text;column:setting"`
	Remark           string                     `json:"remark,omitempty" gorm:"type:varchar(255)" validate:"max=255"`
	StripeCustomer   string                     `json:"stripe_customer" gorm:"type:varchar(64);column:stripe_customer;index"`
	CreatedAt        int64                      `json:"created_at" gorm:"autoCreateTime;column:created_at"`
	LastLoginAt      int64                      `json:"last_login_at" gorm:"default:0;column:last_login_at"`
	AuthVersion      int64                      `json:"-" gorm:"type:bigint;not null;default:1;column:auth_version"`
	AdminPermissions map[string]map[string]bool `json:"admin_permissions,omitempty" gorm:"-:all"`
}

User if you add sensitive fields, don't forget to clean them in setupLogin function. Otherwise, the sensitive information will be saved on local storage in plain text!

func GetAllUsers

func GetAllUsers(pageInfo *common.PageInfo, sortOptions ...UserSortOptions) (users []*User, total int64, err error)

func GetRootUser

func GetRootUser() (user *User)

func GetUniqueUserByEmail

func GetUniqueUserByEmail(email string) (*User, error)

func GetUserById

func GetUserById(id int, selectAll bool) (*User, error)

func GetUserByOAuthBinding

func GetUserByOAuthBinding(providerId int, providerUserId string) (*User, error)

GetUserByOAuthBinding finds a user by provider ID and provider user ID

func SearchUsers

func SearchUsers(keyword string, group string, role *int, status *int, startIdx int, num int, sortOptions ...UserSortOptions) ([]*User, int64, error)

func ValidateAccessToken

func ValidateAccessToken(token string) (*User, error)

func (*User) BeforeCreate

func (user *User) BeforeCreate(tx *gorm.DB) error

BeforeCreate/BeforeUpdate keep the denormalized lookup key in sync even for internal callers that use GORM directly (for example payment and OAuth flows). The nullable key intentionally maps an empty email to NULL.

func (*User) BeforeUpdate

func (user *User) BeforeUpdate(tx *gorm.DB) error

func (*User) ClearBinding

func (user *User) ClearBinding(bindingType string) error

func (*User) Delete

func (user *User) Delete() error

func (*User) Edit

func (user *User) Edit(updatePassword bool) error

func (*User) EditWithTx

func (user *User) EditWithTx(tx *gorm.DB, updatePassword bool) error

func (*User) FillUserByDiscordId

func (user *User) FillUserByDiscordId() error

func (*User) FillUserByEmail

func (user *User) FillUserByEmail() error

func (*User) FillUserByGitHubId

func (user *User) FillUserByGitHubId() error

func (*User) FillUserById

func (user *User) FillUserById() error

func (*User) FillUserByLinuxDOId

func (user *User) FillUserByLinuxDOId() error

func (*User) FillUserByOidcId

func (user *User) FillUserByOidcId() error

func (*User) FillUserByTelegramId

func (user *User) FillUserByTelegramId() error

func (*User) FillUserByWeChatId

func (user *User) FillUserByWeChatId() error

func (*User) FinalizeOAuthUserCreation

func (user *User) FinalizeOAuthUserCreation(inviterId int)

FinalizeOAuthUserCreation performs post-transaction tasks for OAuth user creation. This should be called after the transaction commits successfully.

func (*User) FinishInsert

func (user *User) FinishInsert(inviterId int)

func (*User) GetAccessToken

func (user *User) GetAccessToken() string

func (*User) GetSetting

func (user *User) GetSetting() dto.UserSetting

func (*User) HardDelete

func (user *User) HardDelete() error

func (*User) Insert

func (user *User) Insert(inviterId int) error

func (*User) InsertWithTx

func (user *User) InsertWithTx(tx *gorm.DB, inviterId int) error

InsertWithTx inserts a new user within an existing transaction. This is used for OAuth registration where user creation and binding need to be atomic. Post-creation tasks (sidebar config, logs, inviter rewards) are handled after the transaction commits.

func (*User) SetAccessToken

func (user *User) SetAccessToken(token string)

func (*User) SetSetting

func (user *User) SetSetting(setting dto.UserSetting)

func (*User) ToBaseUser

func (user *User) ToBaseUser() *UserBase

func (*User) TransferAffQuotaToQuota

func (user *User) TransferAffQuotaToQuota(quota int, requestId string, expectedEpoch ...uint64) error

TransferAffQuotaToQuota moves affiliate reward quota into the wallet balance. The (user_id, request_id) pair is the durable operation identity: replaying a succeeded request returns success without any write, and reusing the request id with a different quota is a conflict.

func (*User) Update

func (user *User) Update(updatePassword bool) error

func (*User) UpdateGitHubId

func (user *User) UpdateGitHubId(newGitHubId string) error

UpdateGitHubId updates the user's GitHub ID (used for migration from login to numeric ID)

func (*User) UpdateWithTx

func (user *User) UpdateWithTx(tx *gorm.DB, updatePassword bool) error

func (*User) ValidateAndFill

func (user *User) ValidateAndFill() (err error)

ValidateAndFill check password & user status

type UserBase

type UserBase struct {
	Id               int    `json:"id"`
	Group            string `json:"group"`
	AccountTierID    string `json:"account_tier_id"`
	Email            string `json:"email"`
	Quota            int    `json:"quota"`
	Status           int    `json:"status"`
	Role             int    `json:"role"`
	Username         string `json:"username"`
	Setting          string `json:"setting"`
	AuthVersion      int64  `json:"-"`
	CacheSchema      int    `json:"-"`
	QuotaVersion     int64  `json:"quota_version"`
	QuotaWriterEpoch int64  `json:"-"`
}

func GetUserCache

func GetUserCache(userId int) (*UserBase, error)

GetUserCache gets complete user cache from hash

func (*UserBase) GetSetting

func (user *UserBase) GetSetting() dto.UserSetting

func (*UserBase) WriteContext

func (user *UserBase) WriteContext(c *gin.Context)

type UserFundingOrderKind

type UserFundingOrderKind uint8
const (
	UserFundingOrderUnknown UserFundingOrderKind = iota
	UserFundingOrderTopUp
	UserFundingOrderSubscription
)

type UserFundingRequestSnapshot

type UserFundingRequestSnapshot struct {
	State UserFundingStateSnapshot
	Ready bool
}

func GetUserFundingRequestSnapshot

func GetUserFundingRequestSnapshot() (UserFundingRequestSnapshot, error)

type UserFundingStateSnapshot

type UserFundingStateSnapshot struct {
	Mode                           operation_setting.UserFundingMode `json:"mode"`
	Epoch                          uint64                            `json:"epoch"`
	RetirementCutoffEpoch          uint64                            `json:"retirement_cutoff_epoch,omitempty"`
	RetirementTopUpIDCutoff        int                               `json:"retirement_topup_id_cutoff,omitempty"`
	RetirementSubscriptionIDCutoff int                               `json:"retirement_subscription_id_cutoff,omitempty"`
	Valid                          bool                              `json:"-"`
}

func GetUserFundingStateSnapshot

func GetUserFundingStateSnapshot() (UserFundingStateSnapshot, error)

func PersistSetupFundingOptionsTx

func PersistSetupFundingOptionsTx(
	tx *gorm.DB,
	selfUseModeEnabled bool,
	demoSiteEnabled bool,
	mode operation_setting.UserFundingMode,
) (UserFundingStateSnapshot, error)

func UpdatePaymentFundingOptionsBulk

func UpdatePaymentFundingOptionsBulk(values map[string]string) (UserFundingStateSnapshot, error)

UpdatePaymentFundingOptionsBulk commits payment configuration and the funding state revision together. Runtime publication happens after commit, with the funding mode/epoch published last as the activation barrier.

Payment runtime publication uses one candidate for the whole group: the candidate is prepared (and thereby fully validated) before any in-memory write, aborted on the first publication failure, and published with a single CAS only after every key and the funding barrier have published. If publication fails after the database commit, the runtime stays on the previous generation — the previous generation remains the authoritative read and no partial group of new values ever becomes observable.

type UserFundingWebhookAction

type UserFundingWebhookAction uint8
const (
	UserFundingWebhookAcknowledge UserFundingWebhookAction = iota
	UserFundingWebhookSettle
)

type UserFundingWebhookDecision

type UserFundingWebhookDecision struct {
	// contains filtered or unexported fields
}

func DecideUserFundingWebhook

func DecideUserFundingWebhook(tradeNo, provider string) (UserFundingWebhookDecision, error)

func (UserFundingWebhookDecision) Action

func (UserFundingWebhookDecision) Epoch

func (decision UserFundingWebhookDecision) Epoch() uint64

func (UserFundingWebhookDecision) Kind

func (UserFundingWebhookDecision) Mode

func (UserFundingWebhookDecision) Provider

func (decision UserFundingWebhookDecision) Provider() string

func (UserFundingWebhookDecision) ShouldSettle

func (decision UserFundingWebhookDecision) ShouldSettle() bool

func (UserFundingWebhookDecision) TradeNo

func (decision UserFundingWebhookDecision) TradeNo() string

type UserOAuthBinding

type UserOAuthBinding struct {
	Id             int       `json:"id" gorm:"primaryKey"`
	UserId         int       `json:"user_id" gorm:"not null;uniqueIndex:ux_user_provider"`                                    // User ID - one binding per user per provider
	ProviderId     int       `json:"provider_id" gorm:"not null;uniqueIndex:ux_user_provider;uniqueIndex:ux_provider_userid"` // Custom OAuth provider ID
	ProviderUserId string    `json:"provider_user_id" gorm:"type:varchar(256);not null;uniqueIndex:ux_provider_userid"`       // User ID from OAuth provider - one OAuth account per provider
	CreatedAt      time.Time `json:"created_at"`
}

UserOAuthBinding stores the binding relationship between users and custom OAuth providers

func GetUserOAuthBinding

func GetUserOAuthBinding(userId, providerId int) (*UserOAuthBinding, error)

GetUserOAuthBinding returns a specific binding for a user and provider

func GetUserOAuthBindingsByUserId

func GetUserOAuthBindingsByUserId(userId int) ([]*UserOAuthBinding, error)

GetUserOAuthBindingsByUserId returns all OAuth bindings for a user

func (UserOAuthBinding) TableName

func (UserOAuthBinding) TableName() string

type UserQuotaMutationInput

type UserQuotaMutationInput struct {
	UserID            int
	Delta             int64
	MutationType      string
	BusinessEventKey  string
	ReasonCode        string
	OperatorUserID    int
	Metadata          map[string]interface{}
	MaxQuotaExclusive int64
}

UserQuotaMutationInput contains the parameters for an authoritative quota mutation.

type UserQuotaMutationReceipt

type UserQuotaMutationReceipt struct {
	ID                 int64                     `json:"id" gorm:"primaryKey"`
	ReceiptVersion     int                       `json:"receipt_version" gorm:"not null;<-:create"`
	WriterEpoch        int64                     `json:"writer_epoch" gorm:"type:bigint;<-:create"`
	MutationType       string                    `json:"mutation_type" gorm:"type:varchar(32);not null;index:idx_user_quota_mutation_lookup,priority:2;<-:create"`
	BusinessEventKey   string                    `json:"business_event_key" gorm:"type:varchar(128);not null;uniqueIndex:uidx_user_quota_mutation_key;<-:create"`
	RequestFingerprint string                    `json:"request_fingerprint" gorm:"type:char(64);not null;<-:create"`
	UserID             int                       `json:"user_id" gorm:"not null;index:idx_user_quota_mutation_lookup,priority:1;<-:create"`
	Delta              int64                     `json:"delta" gorm:"type:bigint;not null;<-:create"`
	QuotaBefore        int                       `json:"quota_before" gorm:"not null;<-:create"`
	QuotaAfter         int                       `json:"quota_after" gorm:"not null;<-:create"`
	QuotaVersionBefore int64                     `json:"quota_version_before" gorm:"type:bigint;not null;<-:create"`
	QuotaVersionAfter  int64                     `json:"quota_version_after" gorm:"type:bigint;not null;<-:create"`
	ReasonCode         string                    `json:"reason_code" gorm:"type:varchar(64);not null;<-:create"`
	OperatorUserID     int                       `json:"operator_user_id" gorm:"not null;default:0;<-:create"`
	Metadata           string                    `json:"metadata" gorm:"type:text;not null;<-:create"`
	After              QuotaMutationUserSnapshot `json:"after" gorm:"type:text;<-:create"`
	CreatedAt          int64                     `json:"created_at" gorm:"type:bigint;not null;index;<-:create"`
}

UserQuotaMutationReceipt represents an immutable, auditable mutation receipt for a user's quota. BusinessEventKey enforces exact replay deduplication and conflict detection.

func FindUserQuotaMutationReceiptByEventKey

func FindUserQuotaMutationReceiptByEventKey(tx *gorm.DB, businessEventKey string) (*UserQuotaMutationReceipt, error)

FindUserQuotaMutationReceiptByEventKey retrieves a receipt by its unique business event key within a transaction.

func MutateUserQuota

func MutateUserQuota(db *gorm.DB, input UserQuotaMutationInput) (*UserQuotaMutationReceipt, error)

MutateUserQuota runs MutateUserQuotaAuthoritative inside a managed database transaction. Upon successful commit, it safely hydrates the Redis user quota projection (skipping replay).

func MutateUserQuotaAuthoritative

func MutateUserQuotaAuthoritative(tx *gorm.DB, input UserQuotaMutationInput) (*UserQuotaMutationReceipt, error)

MutateUserQuotaAuthoritative executes an atomic, authoritative quota modification within the caller's transaction tx. It enforces: 1. Exact replay idempotency on businessEventKey; 2. Conflict detection on key mismatch; 3. Row lock via lockForUpdate on the User; 4. Balance bounds and non-negative invariants; 5. Optimistic CAS on (quota, quota_version); 6. Insertion of immutable UserQuotaMutationReceipt.

func (*UserQuotaMutationReceipt) BeforeCreate

func (receipt *UserQuotaMutationReceipt) BeforeCreate(tx *gorm.DB) error

func (*UserQuotaMutationReceipt) BeforeDelete

func (*UserQuotaMutationReceipt) BeforeDelete(_ *gorm.DB) error

func (*UserQuotaMutationReceipt) BeforeUpdate

func (*UserQuotaMutationReceipt) BeforeUpdate(_ *gorm.DB) error

func (UserQuotaMutationReceipt) TableName

func (UserQuotaMutationReceipt) TableName() string

type UserSession

type UserSession struct {
	SID                 string `json:"sid" gorm:"column:sid;type:varchar(64);primaryKey"`
	UserID              int    `` /* 147-byte string literal not displayed */
	Version             int64  `json:"version" gorm:"type:bigint;not null;default:1"`
	UserAuthVersion     int64  `json:"user_auth_version" gorm:"type:bigint;not null"`
	Status              string `` /* 150-byte string literal not displayed */
	RefreshHash         string `json:"-" gorm:"type:char(64);not null"`
	PreviousRefreshHash string `json:"-" gorm:"type:varchar(64)"`
	PreviousValidUntil  int64  `json:"-" gorm:"type:bigint;not null;default:0"`
	LoginMethod         string `json:"login_method" gorm:"type:varchar(32);not null"`
	IP                  string `json:"ip" gorm:"type:varchar(64)"`
	UserAgent           string `json:"user_agent" gorm:"type:text"`
	CreatedAt           int64  `json:"created_at" gorm:"autoCreateTime;column:created_at;index:idx_user_sessions_user_created,priority:2"`
	LastActiveAt        int64  `json:"last_active_at" gorm:"type:bigint;not null;column:last_active_at"`
	ExpiresAt           int64  `` /* 152-byte string literal not displayed */
	RevokedAt           int64  `` /* 133-byte string literal not displayed */
	RevokedReason       string `json:"revoked_reason,omitempty" gorm:"type:varchar(64);column:revoked_reason"`
}

UserSession is the server-side control plane for short-lived access JWTs. RefreshHash values are HMAC digests supplied by the service layer; opaque refresh secrets are never persisted.

func AdvanceUserSessionAuthVersion

func AdvanceUserSessionAuthVersion(userID int, sid string, expectedSessionVersion, expectedUserAuthVersion, nextUserAuthVersion int64) (*UserSession, error)

AdvanceUserSessionAuthVersion preserves one browser session across a user-level security-version change. Both old access JWTs and concurrent updates are invalidated by advancing the per-session version as well.

func GetUserSessionBySID

func GetUserSessionBySID(sid string) (*UserSession, error)

func GetUserSessionCached

func GetUserSessionCached(sid string) (*UserSession, error)

GetUserSessionCached validates cached state first and falls back to the database on a miss or Redis read failure. A deny tombstone never falls back.

func ListActiveUserSessions

func ListActiveUserSessions(userID int, currentSID string, now int64) ([]UserSession, error)

func RotateUserSessionRefresh

func RotateUserSessionRefresh(userID int, sid, presentedHash, nextHash string, now int64, grace time.Duration) (*UserSession, error)

RotateUserSessionRefresh atomically rotates HMAC digests. The UPDATE itself is a compare-and-swap so SQLite, where lockForUpdate is intentionally a no-op, has the same single-winner behavior as MySQL and PostgreSQL. Only a recognized previous digest outside its grace window is treated as reuse; an unknown secret never revokes the victim session.

func (*UserSession) AfterFind

func (session *UserSession) AfterFind(_ *gorm.DB) error

func (UserSession) TableName

func (UserSession) TableName() string

type UserSortOptions

type UserSortOptions struct {
	SortBy    string
	SortOrder string
}

func NewUserSortOptions

func NewUserSortOptions(sortBy string, sortOrder string) UserSortOptions

func (UserSortOptions) Apply

func (options UserSortOptions) Apply(query *gorm.DB) *gorm.DB

type UserSubscription

type UserSubscription struct {
	Id     int `json:"id"`
	UserId int `json:"user_id" gorm:"index;index:idx_user_sub_active,priority:1"`
	PlanId int `json:"plan_id" gorm:"index"`

	AmountTotal  int64 `json:"amount_total" gorm:"type:bigint;not null;default:0"`
	AmountUsed   int64 `json:"amount_used" gorm:"type:bigint;not null;default:0"`
	QuotaVersion int64 `json:"-" gorm:"type:bigint;not null;default:0"`

	StartTime int64  `json:"start_time" gorm:"bigint"`
	EndTime   int64  `json:"end_time" gorm:"bigint;index;index:idx_user_sub_active,priority:3"`
	Status    string `json:"status" gorm:"type:varchar(32);index;index:idx_user_sub_active,priority:2"` // active/expired/cancelled

	Source string `json:"source" gorm:"type:varchar(32);default:'order'"` // order/admin

	LastResetTime int64 `json:"last_reset_time" gorm:"type:bigint;default:0"`
	NextResetTime int64 `json:"next_reset_time" gorm:"type:bigint;default:0;index"`

	UpgradeGroup  string `json:"upgrade_group" gorm:"type:varchar(64);default:''"`
	PrevUserGroup string `json:"prev_user_group" gorm:"type:varchar(64);default:''"`

	// Downgrade target group on expiry (snapshot from plan; empty = revert to PrevUserGroup)
	DowngradeGroup string `json:"downgrade_group" gorm:"type:varchar(64);default:''"`

	// Whether wallet fallback is allowed after this subscription's quota is exhausted (snapshot from plan)
	AllowWalletOverflow bool `json:"allow_wallet_overflow"`

	CreatedAt int64 `json:"created_at" gorm:"bigint"`
	UpdatedAt int64 `json:"updated_at" gorm:"bigint"`
}

User subscription instance

func CreateUserSubscriptionFromPlanTx

func CreateUserSubscriptionFromPlanTx(tx *gorm.DB, userId int, plan *SubscriptionPlan, source string) (*UserSubscription, error)

func (*UserSubscription) BeforeCreate

func (s *UserSubscription) BeforeCreate(tx *gorm.DB) error

func (*UserSubscription) BeforeUpdate

func (s *UserSubscription) BeforeUpdate(tx *gorm.DB) error

type UserUsagePolicy

type UserUsagePolicy struct {
	UserID               int   `json:"user_id"`
	NoBalance            bool  `json:"no_balance"`
	Revision             int64 `json:"revision"`
	LegacyRemainingQuota int   `json:"legacy_remaining_quota"`
}

func ConfigureUserUsagePolicy

func ConfigureUserUsagePolicy(ctx context.Context, db *gorm.DB, actorID int, input UserUsagePolicyInput) (*UserUsagePolicy, error)

This changes policy only: it never grants quota, clears usage, or rewrites a request's already captured funding source. Existing users remain limited until Root explicitly changes this private policy field.

func ReadUserUsagePolicy

func ReadUserUsagePolicy(ctx context.Context, db *gorm.DB, actorID, userID int) (*UserUsagePolicy, error)

type UserUsagePolicyChange

type UserUsagePolicyChange struct {
	ID         string `gorm:"type:varchar(64);primaryKey"`
	Digest     string `gorm:"type:varchar(64);not null"`
	ActorID    int    `gorm:"not null"`
	UserID     int    `gorm:"not null;index"`
	BeforeJSON string `gorm:"type:text;not null"`
	AfterJSON  string `gorm:"type:text;not null"`
	CreatedAt  int64  `gorm:"type:bigint;not null"`
}

func (*UserUsagePolicyChange) BeforeDelete

func (*UserUsagePolicyChange) BeforeDelete(*gorm.DB) error

func (*UserUsagePolicyChange) BeforeUpdate

func (*UserUsagePolicyChange) BeforeUpdate(*gorm.DB) error

type UserUsagePolicyInput

type UserUsagePolicyInput struct {
	ID               string `json:"id"`
	UserID           int    `json:"user_id"`
	ExpectedRevision int64  `json:"expected_revision"`
	NoBalance        bool   `json:"no_balance"`
}

type Vendor

type Vendor struct {
	Id          int            `json:"id"`
	Name        string         `json:"name" gorm:"size:128;not null;uniqueIndex:uk_vendor_name_delete_at,priority:1"`
	Description string         `json:"description,omitempty" gorm:"type:text"`
	Icon        string         `json:"icon,omitempty" gorm:"type:varchar(128)"`
	Status      int            `json:"status" gorm:"default:1"`
	CreatedTime int64          `json:"created_time" gorm:"bigint"`
	UpdatedTime int64          `json:"updated_time" gorm:"bigint"`
	DeletedAt   gorm.DeletedAt `json:"-" gorm:"index;uniqueIndex:uk_vendor_name_delete_at,priority:2"`
}

func GetAllVendors

func GetAllVendors(offset int, limit int) ([]*Vendor, error)

GetAllVendors 获取全部供应商(分页)

func GetVendorByID

func GetVendorByID(id int) (*Vendor, error)

GetVendorByID 根据 ID 获取供应商

func SearchVendors

func SearchVendors(keyword string, offset int, limit int) ([]*Vendor, int64, error)

SearchVendors 按关键字搜索供应商

func (*Vendor) Delete

func (v *Vendor) Delete() error

Delete 软删除供应商

func (*Vendor) Insert

func (v *Vendor) Insert() error

Insert 创建新的供应商记录

func (*Vendor) Update

func (v *Vendor) Update() error

Update 更新供应商记录

type WaffoPancakePaymentSource

type WaffoPancakePaymentSource struct{ StoreID, Currency string }

Source Files

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL