domain

package
v0.0.1-beta.5 Latest Latest
Warning

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

Go to latest
Published: Aug 26, 2026 License: AGPL-3.0 Imports: 5 Imported by: 0

Documentation

Overview

SPDX-License-Identifier: AGPL-3.0-or-later Dual-licensed: AGPL-3.0-or-later (open source) or commercial license (closed-source deployment exemption); see LICENSE and LICENSE.commercial. Copyright (c) 2026 is7Qin.

Package domain 定义网关的核心领域类型;业务层(scheduler/proxy/service)只依赖本包。

Index

Constants

View Source
const (
	EmailCodeTTL         = 10 * time.Minute
	EmailCodeMaxAttempts = 5
	EmailCodeRateLimit   = 60 * time.Second
	EmailCodeDigits      = 6
)

邮件验证码常量(spec R-3)。

View Source
const AppName = "c3api"

AppName 模板变量 app_name 常量。

View Source
const CodexSearchModel = "codex-search"
View Source
const DefaultCodexSearchPricePerCall int64 = 1000
View Source
const ErrMsgMaxLen = 500

ErrMsgMaxLen 错误文本域内截断上限(usagelog.error_message varchar(500) 与 accounts.last_error 共用;部署故障修复:错误文本留痕但列长度有界)。

Variables

View Source
var DefaultSettings = []Setting{
	{Key: "signup_enabled", Type: SettingTypeSwitch, Value: "true"},

	{Key: "default_user_max_concurrency", Type: SettingTypeNumber, Value: "0", Min: i64p(0)},
	{Key: "default_user_balance", Type: SettingTypeNumber, Value: "0", Min: i64p(0)},
	{Key: "default_user_temp_balance", Type: SettingTypeNumber, Value: "0", Min: i64p(0)},
	{Key: "default_user_temp_balance_ttl_days", Type: SettingTypeNumber, Value: "30", Min: i64p(0)},

	{Key: "price_source_url", Type: SettingTypeString,
		Value: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json"},
	{Key: "price_sync_cron", Type: SettingTypeString, Value: "0 3 * * *"},

	{Key: "service_tier_policy_priority", Type: SettingTypeString, Value: "passthrough",
		PolicyValues: []string{"passthrough", "strip", "reject"}},
	{Key: "service_tier_policy_flex", Type: SettingTypeString, Value: "passthrough",
		PolicyValues: []string{"passthrough", "strip", "reject"}},
	{Key: "service_tier_policy_fast", Type: SettingTypeString, Value: "passthrough",
		PolicyValues: []string{"passthrough", "strip", "reject"}},

	{Key: "mail.enabled", Type: SettingTypeSwitch, Value: "false"},
	{Key: "mail.register_verification", Type: SettingTypeSwitch, Value: "false"},
	{Key: "mail.smtp_host", Type: SettingTypeString, Value: ""},
	{Key: "mail.smtp_port", Type: SettingTypeNumber, Value: "465", Min: i64p(1), Max: i64p(65535)},
	{Key: "mail.smtp_username", Type: SettingTypeString, Value: ""},
	{Key: "mail.smtp_password", Type: SettingTypeString, Value: ""},
	{Key: "mail.from_address", Type: SettingTypeString, Value: ""},
	{Key: "mail.tls", Type: SettingTypeString, Value: "implicit", PolicyValues: []string{"starttls", "implicit", "none"}},
}

内置设置注册表(类型化配置):key/type/value 默认值。管理面 PUT 落库覆盖; DB 无行即默认(Get 读路径免初始化)。新增内置项 = 在此追加 + 管理面允许列表 同步(service.ValidateSetting 用)。 数值条目 Min/Max 域(nil = 无限制):管理面 UpdateSetting 越界 → 400 拒绝 (A-P2-11 护栏前置,消费端零改动;仅注册表承载,不落库)。PolicyValues 枚举 域:字符串条目合法值清单(service 校验从注册表派生,消双处同步,P3-7)。

Functions

func TruncateErrMsg

func TruncateErrMsg(s string) string

TruncateErrMsg 把错误文本截断到 ErrMsgMaxLen 字符(按 rune 截断,不拆断 多字节 UTF-8)。仅错误分支调用(成功路径不经过),热路径零成本——短文本 (≤500 字符,含全部 ASCII 错误文案)直接返回不分配。

Types

type Account

type Account struct {
	ID         int64
	Name       string
	TemplateID int64
	Template   *Template
	// BaseURL 账号级 base_url 覆盖(路由属性,列位于 upstream_key 前——用户
	// 裁决 2026-08-14):nil = 继承模板 base_url;非空 = 覆盖模板值(api_key/
	// responses-special 静态透传的兜底——模板留空则账号级可补)。DB 恒
	// nil|非空两种形态(create 路径空串归一 nil、批量 "" 落 NULL)。
	BaseURL        *string
	UpstreamKey    string
	Status         AccountStatus
	CooldownUntil  *time.Time
	Weight         int
	MaxConcurrency int
	LastError      *string
	LastUsedAt     *time.Time
	// FailedAt SDK 上报的运行时失效时刻(account.failed_at 列,SDK 接入 T1——
	// 用户裁决 2026-08-13:仅此一列;失效原因复用既有 LastError,两原因字段
	// 并存会漂移):nil = 未失效;非 nil = 账号级终止(凭据永久失效/上游封禁/
	// 判死)的上报时刻。与 Status=disabled 语义分离:disabled = 管理面手动禁用;
	// failed_at = 运行时失效,两者可并存(失效后管理员仍可手动处理;恢复 =
	// 清 failed_at + last_error + 恢复调度,T5 细化)。调度器选号不读本字段
	//(pickFrom 只跳 disabled——摘除必须落库 status)。
	FailedAt  *time.Time
	CreatedAt time.Time
	UpdatedAt time.Time
	DeletedAt *time.Time // 软删除时间戳;nil = 存活(列表/消费路径过滤;GET 单个可查已删)
	// GroupIDs 写路径(创建/更新)专用:nil = 不设置/不变;非 nil = 替换账号
	// 全部分组(含空数组 = 清空)。读路径忽略——编辑回显走 GetAccountGroups
	// 独立查询(toDomainAccount 不填充该字段)。
	GroupIDs *[]int64
	// Ext 账号类型化鉴权扩展(account_ext 1:1 边;调度器快照加载
	// LoadGroupsAccounts/LoadGroupAccounts 合并——与 Template.StripImageTools
	// 同款快照合并先例,sdk-wiring T4 P3-4 定死路线;T2 起 codex 路由按 Ext
	// 派生 AccountCredential)。其余路径(管理面账号 CRUD 等)无 ext 边 → nil。
	Ext *AccountExt
}

type AccountCredential

type AccountCredential struct {
	AccountID         int64
	OAuthToken        string
	OAuthRefreshToken string
	OAuthExpiresAt    *time.Time
	PATKey            string
	BaseURL           string
}

AccountCredential 网关侧凭据传递形态(SDK 接入契约,T1 §4):每次调用必传 (调度器按请求选账号)。从 AccountExt 派生(CredentialFromExt)——codex-oauth → OAuthToken/OAuthRefreshToken/OAuthExpiresAt;codex-pat → PATKey。适配层 (T2 起)把 cred 转成 SDK Auth 账号级缓存键:同账号复用、失效剔除。

BaseURL(T2 扩展——调用方路由按 Selection.BaseURL 填充,不参与 CredentialFromExt 派生——AccountExt 无模板面):模板 base 派生后的完整 generations 端点(空 = SDK 内置 DefaultImagesURL)。缓存重建判定维度之一 (模板 base 变更 → 重建——与 aiclient InvalidateAll 同语义)。

func CredentialFromExt

func CredentialFromExt(e *AccountExt) AccountCredential

CredentialFromExt 从账号扩展行派生每次调用必传的凭据(投影语义:按类型取 对应凭据列组——codex-oauth → codex_oauth_* 列组、codex-pat → codex_pat_key; nil 列 → 空值;不报错——调用方按类型分流,非本类型的列不触达)。nil ext → 全零值。

type AccountExt

type AccountExt struct {
	AccountID              int64
	CredentialType         credential.Type
	CodexIdentity          *CodexIdentity `json:"codex_identity"` // 身份四元组(jsonb;nil = 未配置/异常)
	CodexOAuthToken        *string        // 凭据:oauth 访问令牌
	CodexOAuthRefreshToken *string        // 凭据:oauth 刷新令牌
	CodexOAuthExpiresAt    *time.Time     // 凭据:oauth 访问令牌过期时间
	CodexPATKey            *string        // 凭据:pat
	CodexEmail             *string        // 管理标识:账号登录邮箱(导入时人工/上游提供,非自动生成,可空)
	CodexAccountID         *string        // 上游账号/空间标识(Task B 导入必填;可空)
}

AccountExt 账号类型化鉴权扩展(account_ext 子表,1:1):credential_type ∈ {codex-oauth, codex-pat}(账号只两种 codex 类型)。字段按作用分组: 标识 → 身份(codex_identity jsonb 单列)→ 凭据 → 管理标识。身份四元组 (对齐真实 codex 客户端语义,导入时 service NewCodexIdentity() 自动生成并 持久化、账号存在期间稳定):InstallationID 必存(UUIDv4 安装级永久); SessionID/ThreadID UUIDv7 会话级(恒等 thread==session);WindowID = {thread_id}:0(导入时生成后恒定不变——零递增零状态)。nil = 未配置。 凭据列组按类型约束(service 校验):oauth 只允许 CodexOAuth* 列组;pat 只允许 CodexPATKey。CodexAccountID 为上游账号/空间标识(Task B 批量导入 必填;本 task 仅建结构——管理面写入能力 Task B 接线)。

type AccountStatus

type AccountStatus string
const (
	StatusActive    AccountStatus = "active"
	StatusUnhealthy AccountStatus = "unhealthy"
	Status429       AccountStatus = "429"
	StatusDisabled  AccountStatus = "disabled"
)

type AccountUsage

type AccountUsage struct {
	AccountID     int64
	Gateway       UsageAgg
	Upstream      *CodexUsageSnapshot
	UpstreamError *AccountUsageUpstreamError
}

AccountUsage 账号 usage 视图 item(/api/admin/accounts/usage 统一 usage API 查询 面):Gateway 恒全量(无记录全 0——前端免补零);Upstream 为 codex 额度快照 (task 3 sdkbridge;api-key/无凭据账号恒 nil);UpstreamError 为快照失败标记 (成功/nil 上游恒 nil——"无上游能力"与"快照挂了"区分)。

type AccountUsageUpstreamError

type AccountUsageUpstreamError string

AccountUsageUpstreamError 上游快照失败分类标记(upstream_error 枚举—— task 3 sdkbridge 错误分类即映射输入:ErrAuthExpired → auth_expired、 ErrUpstream → upstream_unavailable;api-key 无凭据/"缺失"恒 nil,不进 auth_expired)。

const (
	UpstreamErrorAuthExpired         AccountUsageUpstreamError = "auth_expired"         // 凭据失效(sdkbridge fatal 类)
	UpstreamErrorUpstreamUnavailable AccountUsageUpstreamError = "upstream_unavailable" // 网络/5xx 等上游错误(ErrUpstream/其余)
)

type CodexCredits

type CodexCredits struct {
	Balance *string `json:"balance,omitempty"`
}

CodexCredits 充值余额(Balance 金额字符串——如 "12.50",不解析;指针 + omitempty——上游空串 → nil → 不出字段,零填充语义)。

type CodexIdentity

type CodexIdentity struct {
	InstallationID string `json:"installation_id"`
	SessionID      string `json:"session_id"`
	ThreadID       string `json:"thread_id"`
	WindowID       string `json:"window_id"`
}

CodexIdentity codex 账号身份四元组(对齐真实客户端语义:installation_id 安装级永久;session/thread 会话级恒等;window = {thread_id}:{n} 起始 :0)—— account_ext.codex_identity jsonb 序列化契约类型(json tag 即落库形态)。 空字段 = 未提供(service 归一:全空 → 自动生成/沿用存量;identity 无清空 路径——账号存在期间稳定)。

type CodexOAuthImportItem

type CodexOAuthImportItem struct {
	CodexEmail             string
	CodexAccountID         string
	CodexOAuthToken        string
	CodexOAuthRefreshToken string
	CodexOAuthExpiresAt    *string
	MaxConcurrency         *int
	Weight                 *int
}

CodexOAuthImportItem 批量导入 codex-oauth 单行(Task B——组合幂等键 codex_email + codex_account_id;token+refresh 成对必填;expires_at 可选 原始 RFC3339 字符串(service 逐行解析——格式错误 → 行级 failed 非整批 400;nil = 过期未知 → 401 自愈);max_concurrency/weight 配置面——nil = 缺省 25/100(导入面裁决覆盖账号表默认 8))。

type CodexPATImportItem

type CodexPATImportItem struct {
	CodexEmail     string
	CodexAccountID string
	CodexPATKey    string
	MaxConcurrency *int
	Weight         *int
}

CodexPATImportItem 批量导入 codex-pat 单行(组合键同上;pat_key 必填)。

type CodexRateLimit

type CodexRateLimit struct {
	UsedPercent int        `json:"used_percent"`
	ResetAt     *time.Time `json:"reset_at,omitempty"`
}

CodexRateLimit 主窗口用量(ResetAt = SDK Unix 秒 → time.Time,JSON RFC3339; 指针 + omitempty——上游主窗口省略 reset_at(Unix 0)→ nil → 不出字段,零填充 语义:虚假 0001-01-01T00:00:00Z 不外泄)。

type CodexSpendControl

type CodexSpendControl struct {
	Limit            string `json:"limit"`
	Used             string `json:"used"`
	Remaining        string `json:"remaining"`
	UsedPercent      int    `json:"used_percent"`
	RemainingPercent int    `json:"remaining_percent"`
}

CodexSpendControl 消费控制额度(Limit/Used/Remaining 金额字符串)。

type CodexUsageSnapshot

type CodexUsageSnapshot struct {
	PlanType     string             `json:"plan_type,omitempty"`
	RateLimit    *CodexRateLimit    `json:"rate_limit,omitempty"`    // 窗口用量
	Credits      *CodexCredits      `json:"credits,omitempty"`       // 充值余额
	SpendControl *CodexSpendControl `json:"spend_control,omitempty"` // 消费限额(花了多少)
}

CodexUsageSnapshot 账号 codex 额度快照(白名单收敛契约——spec 2026-08-18 Task 3:SDK UsageStatus 五块砍四留四——RateLimitReachedType(与 allowed=false 重复的派生状态)与瞬时布尔(Allowed/LimitReached/HasCredits/Unlimited/ OverageLimitReached——5min 缓存下已过时)与 ApproxLocalMessages/ ApproxCloudMessages([]any 未定型数组——不进契约)一律不出现)。每块 nil → omitempty(上游没返回就不出字段——个人订阅账号可能无 SpendControl、team 账号可能无 Credits.Balance;上游返回什么透什么,零填充)。金额字段为字符串 不解析(SDK 有意保精度)。快照为尽力视图(展示面参考,非计费依据——真实 账本 = usage_logs)。

type EmailCode

type EmailCode struct {
	ID         int64
	Email      string
	Purpose    EmailCodePurpose
	CodeSHA256 string
	ExpiresAt  time.Time
	Attempts   int
	CreatedAt  time.Time
	UpdatedAt  time.Time
}

EmailCode 验证码行(email+purpose 唯一)。

type EmailCodePurpose

type EmailCodePurpose string

EmailCodePurpose 验证码用途。

const (
	EmailCodeRegister EmailCodePurpose = "register"
	EmailCodeReset    EmailCodePurpose = "reset"
)

func (EmailCodePurpose) TemplatePurpose

func (p EmailCodePurpose) TemplatePurpose() EmailTemplatePurpose

func (EmailCodePurpose) Valid

func (p EmailCodePurpose) Valid() bool

type EmailTemplate

type EmailTemplate struct {
	Purpose   EmailTemplatePurpose
	Subject   string
	BodyText  string
	UpdatedAt time.Time
}

EmailTemplate 邮件模板(DB 行;缺行时走 DefaultEmailTemplate 回退)。

func DefaultEmailTemplate

func DefaultEmailTemplate(purpose EmailTemplatePurpose) EmailTemplate

DefaultEmailTemplate 编译内置英文默认模板(占位符 {{code}}/{{ttl_minutes}}/{{app_name}}; 开源项目默认英文,管理台可按语言自定义覆盖)。

type EmailTemplatePurpose

type EmailTemplatePurpose string

EmailTemplatePurpose 邮件模板用途。

const (
	EmailTemplateRegisterCode EmailTemplatePurpose = "register_code"
	EmailTemplateResetCode    EmailTemplatePurpose = "reset_code"
)

func (EmailTemplatePurpose) Valid

func (p EmailTemplatePurpose) Valid() bool

type EntityStatBucket

type EntityStatBucket struct {
	BucketTime          time.Time
	EntityType          string // 'account' | 'user' | 'key'
	EntityID            int64
	Model               string
	RequestCount        int64
	ErrorCount          int64
	CallCount           int64
	InputTokens         int64
	OutputTokens        int64
	TotalTokens         int64
	CacheReadTokens     int64
	CacheCreationTokens int64
	Cost                int64
	RawCost             int64
	TTFTTotalMS         int64
	TTFTCount           int64
	TTFTMaxMS           int64
}

EntityStatBucket 实体小时卷积桶(usage_entity_stats 行语义)。

type ErrorType

type ErrorType string
const (
	ErrNone      ErrorType = "none"
	Err429       ErrorType = "429"
	Err4xx       ErrorType = "4xx"
	Err5xx       ErrorType = "5xx"
	ErrNetwork   ErrorType = "network"
	ErrAuth      ErrorType = "auth"
	ErrNoAccount ErrorType = "no_account"
	ErrAbort     ErrorType = "abort"
	ErrBilling   ErrorType = "billing" // 计费拒绝(缺价/余额不足 402)
)

type Group

type Group struct {
	ID         int64
	Name       string
	Visibility GroupVisibility
	// PriceMultiplier 万分数(T3.5 价格倍率):组默认 10000 = ×1;0 = 免费。
	// 写路径语义:Create 缺省(nil,service 归一为 10000)恒写入;Update 恒写入
	// (PUT 全量替换)。API 边界(handler/convert.go)与正常值 float64 换算
	// (1.5 ↔ 15000)。
	PriceMultiplier int
	// ProtocolConverts 分组级协议转换方向集合(只补差,W5 消费;多方向并存按
	// 客户端格式命中——chat 请求走 chat_to_*、anthropic 请求走 mess_to_resp、
	// resp 请求走 resp_to_mess):空集合 = off = 不转换(off 不进数组)。
	// 写路径语义:Create 缺省(handler 归一为空数组)恒写入;Update 恒写入
	// (service 校验集合——非法方向/重复方向/同客户端格式多方向 400;显式
	// 空数组 = 清空)。
	ProtocolConverts []ProtocolConvert
	CreatedAt        time.Time
	UpdatedAt        time.Time
	DeletedAt        *time.Time // 软删除时间戳;nil = 存活(列表/消费路径过滤;GET 单个可查已删)
}

type GroupAssignment

type GroupAssignment struct {
	ID              int64
	GroupID         int64
	UserID          int64
	PriceMultiplier *int
	CreatedAt       time.Time
}

GroupAssignment private 组的授予记录(用户 ↔ 组多对多)。 PriceMultiplier 该用户在该组的专属价格倍率(万分数,T3.5 修正:按组—— 用户在不同组可有不同倍率);nil = 未设置 → 用组倍率;0 = 免费。

type GroupVisibility

type GroupVisibility string

GroupVisibility 组可见性:public 全部用户可选;private 仅授予用户。

const (
	GroupVisibilityPublic  GroupVisibility = "public"
	GroupVisibilityPrivate GroupVisibility = "private"
)

func (GroupVisibility) Valid

func (v GroupVisibility) Valid() bool

type Image

type Image struct {
	B64JSON *string
}

Image 单张生成结果(实证:b64_json 为原始 PNG base64,无 data URL 前缀)。

type ImageGenParams

type ImageGenParams struct {
	Model      string     // 生图模型(gpt-image-2 等;必填)
	Prompt     string     // 必填
	N          *int       // nil = 1
	Size       *string    // nil = "auto"
	Quality    *string    // nil = "auto";枚举 low|medium|high|auto
	Background *string    // nil = "auto";枚举 transparent|opaque|auto
	Images     []ImageRef // edits 输入图片(≤5);generations 恒空
}

ImageGenParams 生图参数(generations/edits 共参;codex-rs 实证收敛参数集)。

type ImageRef

type ImageRef struct {
	ImageURL *string // 完整 URL 或 base64 data URL
	Raw      []byte  // 原始文件字节(multipart 上传形态)→ SDK 内部转 data URL
}

ImageRef 单张输入图(edits)。

type ImageResponse

type ImageResponse struct {
	Created      int64
	Background   *string
	Data         []Image
	OutputFormat *string
	Quality      *string
	Size         *string
	Usage        *ImageUsage // 上游未提供 → nil(网关 per-image 分量兜底)
}

ImageResponse 标准 ImagesResponse(对齐 OpenAI /v1/images/* 响应)——网关 直接据此计费(Data 长 = 张数、Usage 提取 image_tokens)。

type ImageStreamEvent

type ImageStreamEvent struct {
	Type    ImageStreamEventType // 见上常量组
	B64JSON *string              // completed:原始 PNG base64;keepalive 恒 nil
	Usage   *ImageUsage          // 仅最后一个 completed 事件携带;keepalive 恒 nil
}

ImageStreamEvent 流式事件(codex-sdk 合成流式产出——网关零合成逻辑,只做 SSE 透传:keepalive → ": ping" 注释行;completed → SSE 事件帧)。partial_image 不合成(无 wire 来源)。

type ImageStreamEventType

type ImageStreamEventType string

ImageStreamEventType 流式事件类型(wire 事件名:上游 SSE 帧 type 字段值与 codex-sdk 合成流式事件 Type 值同值域)。类型化(A-P2-10)后 SDK 升级改事件 名 → 适配层显式映射未知 Warn + 跳过(不静默透传落账 0 张);switch 消费侧 编译期暴露全部调用点。

const (
	// ImageStreamEventKeepalive 保活事件(生成等待期间每 60s 一个;
	// B64JSON/Usage 恒 nil)——网关收到首个事件即发 SSE 响应头,keepalive
	// 保证 CF 120s 响应头超时门槛内必有字节流(524 免疫)。
	ImageStreamEventKeepalive ImageStreamEventType = "keepalive"
	// ImageStreamEventCompleted 每张图一个 completed 事件(带 b64_json;
	// usage 仅最后一个事件携带)。
	ImageStreamEventCompleted ImageStreamEventType = "image_generation.completed"
	// ImageStreamEventEditCompleted edits 端点完成事件(直连上游 SSE 形态;
	// codex-sdk 合成流式不产出——edits 端点也合成 generations.completed)。
	ImageStreamEventEditCompleted ImageStreamEventType = "image_edit.completed"
)

ImageStreamEvent 事件类型常量(GenerateImageStream 合成流式事件 + 直连上游 SSE 事件名——wire 事件名四处生产字面量收敛于此:image_usage.go:65 / image_gen.go:66 / caller_images_stream.go buildCompletedFrame / billing 旁路)。

type ImageUsage

type ImageUsage struct {
	InputTokens       int64 `json:"input_tokens"`
	InputImageTokens  int64 `json:"input_image_tokens"` // input_tokens_details.image_tokens
	OutputTokens      int64 `json:"output_tokens"`
	OutputImageTokens int64 `json:"output_image_tokens"` // output_tokens_details.image_tokens
}

ImageUsage 生图 token 用量(上游 input/output_tokens_details.image_tokens 提取为平铺四字段;JSON tag 对齐 codex-sdk ImageUsage——completed SSE 帧 usage 字段映射 = JSON tag 直透,T3 spec P2-1 wire 形态定死)。

type ImportFailedItem

type ImportFailedItem struct {
	Index int
	Error string
}

ImportFailedItem 行级失败条目(index = items 原始下标——行级定位契约; error 为该行失败原因文案)。

type ImportResult

type ImportResult struct {
	Imported int
	Updated  int
	Failed   []ImportFailedItem
}

ImportResult 批量导入结果(imported 新建 / updated 键存在更新凭据 / failed 行级失败——单行失败不毁整批,整批不原子)。

type Key

type Key struct {
	ID             int64
	UserID         int64
	GroupID        int64
	Name           string
	KeyRaw         string // 明文常驻(长期可查看/复制;DB 泄露即明文暴露——自托管权衡)
	Status         KeyStatus
	MaxConcurrency int
	Quota          int64 // 累计 token 上限;0 = 不限
	QuotaUsed      int64 // 已消耗(后扣;无额度 key 恒 0)
	CreatedAt      time.Time
	UpdatedAt      time.Time
	DeletedAt      *time.Time // 软删除时间戳;nil = 存活(鉴权/列表过滤;GET 单个可查已删)
}

Key 客户端 API key(独立表,重建 group 内嵌 key 语义)。

func (*Key) HasQuota

func (k *Key) HasQuota() bool

HasQuota 是否有额度上限(quota > 0)。热路径门禁/扣减短路标志。

type KeyMeta

type KeyMeta struct {
	KeyID       int64
	UserID      int64
	GroupID     int64
	KeyStatus   KeyStatus
	KeyMaxConc  int
	UserStatus  UserStatus
	UserMaxConc int
	HasQuota    bool
	Quota       int64
	QuotaUsed   int64 // 快照值(reload 时从 DB 读);在途扣减走内存计数
	// ProtocolConverts 组级协议转换方向集合快照值(W5):空 = 不转换(热路径
	// 分支零开销);元素 = 客户端协议 → 模板协议(补差语义,转换器
	// internal/protoconv;多方向按客户端格式命中,同客户端格式多方向已被
	// 创建/更新校验拒绝)。
	ProtocolConverts []ProtocolConvert
}

KeyMeta 鉴权快照条目:key + 归属用户的关键门禁字段(Auth 内存表元素, repository.LoadKeys 构建;热路径零 DB 读取)。

type KeyStatus

type KeyStatus string

KeyStatus 客户端 key 状态。

const (
	KeyStatusActive   KeyStatus = "active"
	KeyStatusDisabled KeyStatus = "disabled"
)

func (KeyStatus) Valid

func (s KeyStatus) Valid() bool

type LedgerRow

type LedgerRow struct {
	ID          int64
	UserID      int64
	Cost        int64
	Model       string
	BillingTier string
	CallCount   int64
	Format      string
}

LedgerRow 计费游标消费行(usage_logs 未扣子集的瘦身投影;spec-f2-ledger-cursor ABI-1 冻结契约):FetchUnbilledBatch 返回、结算语句按 UserID 聚合消费。

type PriceEntry

type PriceEntry struct {
	ID                    int64
	Model                 string
	Mode                  PriceMode
	InputPerM             *int64 // 毫分/1M tokens;mode=token 必填
	OutputPerM            *int64
	CacheReadPerM         *int64
	CacheWritePerM        *int64
	PricePerCall          *int64 // 毫分/次;mode=call 必填
	ImgInTokPerM          *int64 // 毫分/1M image tokens
	ImgOutTokPerM         *int64
	PricePerImage         *int64 // 毫分/张
	Provider              *string
	MaxInputTokens        *int64
	MaxOutputTokens       *int64
	SupportsPromptCaching *bool
	Raw                   json.RawMessage
	Source                PricingSource
	CreatedAt             time.Time
	UpdatedAt             time.Time
}

PriceEntry 统一价格条目:每模型一行,mode 声明主计费方式但分量跨模式可选配。

type PriceMode

type PriceMode string

PriceMode 统一价格条目主计费方式。

const (
	PriceModeToken PriceMode = "token"
	PriceModeCall  PriceMode = "call"
	PriceModeImage PriceMode = "image"
)

func (PriceMode) Valid

func (m PriceMode) Valid() bool

type PriceVariant

type PriceVariant struct {
	ID                   int64
	Model                string
	Seq                  int
	ServiceTier          *string // equality
	CtxMin               *int64  // promptTokens >= min
	CtxMax               *int64  // promptTokens < max (spec says containment; use >=min && <max or <=max? spec says ctx_min/ctx_max contain; define >=min && <=max for simplicity, test will clarify)
	TimeStart            *string // HH:MM本地时间
	TimeEnd              *string
	DowMask              *int
	MultBP               *int // 万分数
	SetInputPerM         *int64
	SetOutputPerM        *int64
	SetCacheReadPerM     *int64
	SetCacheCreationPerM *int64
	SetPricePerCall      *int64
	SetImgInTokPerM      *int64
	SetImgOutTokPerM     *int64
	SetPricePerImage     *int64
	CreatedAt            time.Time
	UpdatedAt            time.Time
}

PriceVariant 条件变体:模型+seq 唯一,条件全可空=通配 AND 组合。

type PricingSource

type PricingSource string

PricingSource 价格行来源:litellm = 自动拉取;manual = 管理端手动设置。

const (
	PricingSourceLitellm PricingSource = "litellm"
	PricingSourceManual  PricingSource = "manual"
)

func (PricingSource) Valid

func (s PricingSource) Valid() bool

type ProtocolConvert

type ProtocolConvert string

ProtocolConvert 分组级协议转换方向枚举(补差语义:模板已支持客户端协议 → 直接转发零转换;转换仅在协议不匹配时发生)。方向 = 客户端协议 → 模板协议; off(不转换)不在枚举内——空集合表达(数组元素 ∈ 4 方向;集合校验在 service 层——非法方向/重复/同客户端格式多方向 400)。

const (
	// ProtocolConvertOff 不转换(空数组语义;不进方向数组,service 归一剔除)。
	ProtocolConvertOff ProtocolConvert = "off"
	// ProtocolConvertChatToResp 客户端 chat → 模板 resp 协议。
	ProtocolConvertChatToResp ProtocolConvert = "chat_to_resp"
	// ProtocolConvertMessToResp 客户端 messages(anthropic)→ 模板 resp 协议。
	ProtocolConvertMessToResp ProtocolConvert = "mess_to_resp"
	// ProtocolConvertRespToMess 客户端 resp → 模板 messages(anthropic)协议。
	ProtocolConvertRespToMess ProtocolConvert = "resp_to_mess"
	// ProtocolConvertChatToMess 客户端 chat → 模板 messages(anthropic)协议。
	ProtocolConvertChatToMess ProtocolConvert = "chat_to_mess"
)

func (ProtocolConvert) Valid

func (p ProtocolConvert) Valid() bool

type RedemptionApply

type RedemptionApply struct {
	Type              RedemptionType
	Value             int64 // 兑换值(毫分;concurrency 类型为并发数)
	ResourceExpiresAt *time.Time
}

RedemptionApply 兑换成功回执(/api/user/redemptions POST 响应体)。 ResourceExpiresAt = 兑换后资源到期(temp_balance 必有;balance/concurrency 恒 nil)。

type RedemptionCode

type RedemptionCode struct {
	ID                int64
	Code              string
	Type              RedemptionType
	Value             int64      // 毫分(1 USD = 100,000 毫分;concurrency 类型为并发数)
	Remark            *string    // 运营备注,可选
	ExpiresAt         *time.Time // 码未兑换即过期;nil = 永久
	ResourceExpiresAt *time.Time // 兑换后资源到期;temp_balance 必填(service 校验)
	MaxUses           int        // 1 = 单次码;>1 = 多人码
	UsedCount         int        // 已兑换次数(条件递增,防并发超卖)
	Status            RedemptionStatus
	CreatedBy         int64 // 0 = 系统(静态 admin token);>0 = platform_admin user_id
	CreatedAt         time.Time
	UpdatedAt         time.Time
}

RedemptionCode 兑换码(不可编辑:生成后仅可失效)。

type RedemptionRecord

type RedemptionRecord struct {
	ID                int64
	CodeID            int64
	Code              string
	CodeType          RedemptionType
	Value             int64 // 兑换值快照(毫分;concurrency 类型为并发数)
	Remark            *string
	ResourceExpiresAt *time.Time
	CreatedAt         time.Time
}

RedemptionRecord 我的兑换记录(/api/user/redemptions GET 行):use 快照 + 码的 type/remark 联查(use 行不存码类型;码生成后 type/remark 不可变,失效不影响)。

type RedemptionStatus

type RedemptionStatus string

RedemptionStatus 兑换码状态。

const (
	RedemptionStatusActive   RedemptionStatus = "active"
	RedemptionStatusDisabled RedemptionStatus = "disabled"
)

func (RedemptionStatus) Valid

func (s RedemptionStatus) Valid() bool

type RedemptionType

type RedemptionType string

RedemptionType 兑换码类型:资源发放的通用载体(Phase 5 计费前基础设施)。 balance = users.balance += value;concurrency = users.max_concurrency(0 = 不限特判); temp_balance = 插入 temp_balances 行(resource_expires_at 必填)。 类型 → applier 注册表:新类型 = 新增 applier,兑换流程零改动。

const (
	RedemptionTypeBalance     RedemptionType = "balance"
	RedemptionTypeConcurrency RedemptionType = "concurrency"
	RedemptionTypeTempBalance RedemptionType = "temp_balance"
)

func (RedemptionType) Valid

func (t RedemptionType) Valid() bool

type RedemptionUse

type RedemptionUse struct {
	ID                int64
	CodeID            int64
	UserID            int64
	Value             int64 // 兑换时的值快照(毫分;concurrency 类型为并发数)
	ResourceExpiresAt *time.Time
	CreatedAt         time.Time
}

RedemptionUse 兑换审计记录(全量留痕;UNIQUE(code_id, user_id) = DB 兜底幂等)。

type RequestFormat

type RequestFormat string
const (
	FormatOpenAIChat        RequestFormat = "openai-chat"
	FormatOpenAIResponses   RequestFormat = "openai-responses"
	FormatOpenAIResponsesWS RequestFormat = "openai-responses-ws" // Responses WS(Codex 客户端形态)
	FormatAnthropic         RequestFormat = "anthropic"
	// FormatOpenAIImages 图片生成(/v1/images/generations|edits,spec §4.3):
	// JSON + multipart 双协议;预检查统一价格快照 image 分量(跳过 chat
	// 价预检——P1-1 预检按格式切换)。落库 format = openai-images——usage_logs.format
	// 无 DB enum(varchar),ent 生成 FormatValidator 客户端面校验(COPY 逐行
	// 校验前置——不扩展则图片行 COPY 恒失败回灌)。
	FormatOpenAIImages RequestFormat = "openai-images"
	// FormatOpenAISearch codex search 端点格式(usage_logs 统一计费模型 spec
	// 2026-08-13):为 search 按次计费铺路——search = 1 次功能调用(call_count=1)
	// + price_per_call_millis 按次价快照。**本 task 只扩枚举**(Valid/ent 枚举/
	// COPY FormatValidator——不扩展则 search 行 COPY 恒失败回灌,对齐 openai-
	// images 先例);search 端点接入为独立 task,消费本枚举与 call_count 落账。
	FormatOpenAISearch RequestFormat = "openai-search"
)

func (RequestFormat) Valid

func (f RequestFormat) Valid() bool

type ResolvedPrices

type ResolvedPrices struct {
	Mode           PriceMode
	InputPerM      *int64
	OutputPerM     *int64
	CacheReadPerM  *int64
	CacheWritePerM *int64
	PricePerCall   *int64
	ImgInTokPerM   *int64
	ImgOutTokPerM  *int64
	PricePerImage  *int64
	VariantSeq     *int // 命中变体 seq,无命中 nil
	Provider       *string
}

ResolvedPrices 解析后生效单价组。

func ResolveEntryPrices

func ResolveEntryPrices(entry *PriceEntry, variants []*PriceVariant, tier string, promptTokens int64, at time.Time) (ResolvedPrices, bool)

ResolveEntryPrices 统一价格解析:基底取 entry 分量,按 seq 升序找第一条 匹配(tier/上下文/时段/星期 AND 组合)的变体应用 mult_bp/set_* 后返回。 variants 无需预排序——调用方按 seq 升序传入;首中即停。

type Role

type Role string

Role 用户角色(两级:platform_admin | user)。

const (
	RolePlatformAdmin Role = "platform_admin"
	RoleUser          Role = "user"
)

func (Role) Valid

func (r Role) Valid() bool

type Rule

type Rule struct {
	ID        int64
	Name      string
	Enabled   bool
	Priority  int
	When      RuleWhen
	Then      RuleThen
	CreatedAt time.Time
	UpdatedAt time.Time
	DeletedAt *time.Time // 软删除时间戳;nil = 存活(列表/规则引擎重载过滤)
}

type RuleThen

type RuleThen struct {
	Status   *AccountStatus `json:"status,omitempty"`
	Cooldown *string        `json:"cooldown,omitempty"` // time.ParseDuration 可解析的时长,如 "30s"、"5h"
	Weight   *int           `json:"weight,omitempty"`   // 0-100
	// ResponseCode nil=透传上游码,non-nil=覆写为指定码(400-599);指针即意图(fresh setup,无旧 Transmit 兼容)。
	ResponseCode *int `json:"response_code,omitempty"`
	// CustomMessage nil=透传上游文,non-nil=覆写为固定文案(禁止空串);指针即意图。
	CustomMessage *string `json:"custom_message,omitempty"`
}

type RuleWhen

type RuleWhen struct {
	Kind                   *string  `json:"kind,omitempty"`
	HTTPStatus             *int     `json:"http_status,omitempty"`
	ErrorMessageContains   *string  `json:"error_message_contains,omitempty"`
	AccountID              *int64   `json:"account_id,omitempty"`
	TemplateID             *int64   `json:"template_id,omitempty"`
	GroupID                *int64   `json:"group_id,omitempty"`
	Model                  *string  `json:"model,omitempty"`
	HTTPStatusIn           []int    `json:"http_status_in,omitempty"`            // 与 HTTPStatus 互斥,同字段 OR
	ModelIn                []string `json:"model_in,omitempty"`                  // 与 Model 互斥,同字段 OR,语义=最终请求模型 sel.Model/mapped
	ErrorMessageContainsIn []string `json:"error_message_contains_in,omitempty"` // 与 ErrorMessageContains 互斥,任一子串命中
	WindowSeconds          *int     `json:"window_seconds,omitempty"`
	Count429GE             *int     `json:"count_429_ge,omitempty"`
	// CountFailureGE 语义 = "失败事件桶"(非 ok 非 429 事件计数——5xx/network/4xx
	// 并入)。
	CountFailureGE *int     `json:"count_failure_ge,omitempty"`
	CountOKGE      *int     `json:"count_ok_ge,omitempty"`
	CountTotalGE   *int     `json:"count_total_ge,omitempty"`
	Ratio429GE     *float64 `json:"ratio_429_ge,omitempty"`
	// RatioFailureGE 同 CountFailureGE:分母为失败事件桶(5xx/network/4xx 并入)。
	RatioFailureGE *float64 `json:"ratio_failure_ge,omitempty"`
}

—— 规则引擎(可编排状态管理) ——

type Setting

type Setting struct {
	ID           int64
	Key          string
	Type         SettingType
	Value        string
	Min          *int64   // 数值最小值(含);nil = 无下限
	Max          *int64   // 数值最大值(含);nil = 无上限
	PolicyValues []string // 字符串枚举值域(如 service_tier 策略 key);空 = 不限
	UpdatedAt    time.Time
}

Setting 类型化配置(key/type/value;signup_enabled 注册开关等)。 Min/Max 数值值域(含边界;nil = 无限制)、PolicyValues 字符串枚举值域 (空 = 不限)——仅注册表条目携带(管理面 UpdateSetting 校验用,A-P2-11 护栏 前置);DB 行不落库(读路径由注册表默认兜底合并,见 SettingRepo.GetAll)。

func DefaultSetting

func DefaultSetting(key string) *Setting

DefaultSetting 返回内置 key 的默认设置;未知 key 返回 nil。

type SettingType

type SettingType string

SettingType settings 值类型。

const (
	SettingTypeSwitch SettingType = "switch"
	SettingTypeNumber SettingType = "number"
	SettingTypeString SettingType = "string"
)

func (SettingType) Valid

func (t SettingType) Valid() bool

type SettlementSummary

type SettlementSummary struct {
	BatchRows    int64 // 批行数(usage_logs 取出)
	DebitedUsers int64 // 条件扣命中用户数
	ForcedUsers  int64 // 透支补刀用户数
	Marked       int64 // 标记行数(守卫要求 == BatchRows)
	Quarantined  int64 // 幽灵/隔离行数(零扣费标记退出游标)
	Balances     []UserBalance
}

SettlementSummary 单车道结算语句结果(spec-f2opt-settlement 三车道拓扑;计数 守卫 + 定向余额对)。BatchRows/Marked 由仓库侧做 marked==batch 计数比对守卫 (不齐 = 并发标记 → 整事务回滚重放);Quarantined 为幽灵用户行数(跳扣仍标记 ——不变量 #1 尾语义);Balances 为真实用户的 (uid, balance_after) 对。

type StatBucket

type StatBucket struct {
	BucketTime          time.Time // 对齐到小时(UTC)
	GroupID             int64     // 0 = 无
	Model               string
	RequestCount        int64
	ErrorCount          int64
	InputTokens         int64
	OutputTokens        int64
	TotalTokens         int64
	CacheReadTokens     int64   // 缓存读取 token
	CacheCreationTokens int64   // 缓存写入 token
	Cost                int64   // 毫分(计费预聚合,花费统计不扫明细)
	RawCost             int64   // 毫分(乘倍率前原始成本——免费组 cost=0 但 raw 有值)
	CallCount           int64   // 按次调用:图片生成 = 张数、search = 1(离线聚合 sum(call_count) 直取)
	TTFTTotalMS         int64   // TTFT sum(avg = 查询侧 Go 除 TTFTCount)
	TTFTCount           int64   // TTFT 样本数(仅首 token 流式请求;abort 行含 TTFT 也计入其桶)
	TTFTMaxMS           int64   // TTFT max
	TTFTHist            []int64 // TTFT 直方图 10 档(len = 10;SQL 侧 count(*) FILTER 生成)
}

StatBucket 小时统计桶(usage_stats 行;离线聚合 worker 的 INSERT 行形态)。 请求路径零统计计算(spec 2026-08-14):usage_stats 只由离线聚合 worker 写入 (DELETE+INSERT 覆盖语义)——total_latency_ms 已删除(延迟列出局);TTFT 由 ttft_total_ms/ttft_count/ttft_max_ms/ttft_hist 四列承载(avg 在查询侧 Go 除; ttft_hist 10 档直方图见 stat_repo.go ttftHistBounds)。ttft_hist 为 PG bigint[] 数组列——ent 无数组类型(field.Ints 是 JSON 语义),不进 ent schema(carve-out, 评审 P1-1;统计读取面走 pgx 直查扫描)。v2 瘦身(spec 2026-08-23):维度 7→3——account_id/template_id/user_id/is_error 四维删除(实体视角由 EntityStatBucket/usage_entity_stats 承载;is_error 降为 error_count 测量列 语义),唯一键 = (bucket_time, group_id, model)。

type TTFTSummary

type TTFTSummary struct {
	Count  int64
	AvgMS  int64
	P50MS  int64
	P95MS  int64
	P99MS  int64
	MaxMS  int64
	Source string
}

TTFTSummary TTFT 卡片聚合(/stats/ttft 与 /api/user/stats/ttft 响应内核)。 Source 恒标分支身份:"exact"(usage_logs percentile_cont 精确)或 "sketch" (cube hist 服务端合并插值);空窗 = 零值结构(Count:0),Source 仍标分支 ——调用方以 Count 判空,不以 Source 判空。

type TempBalance

type TempBalance struct {
	ID        int64
	UserID    int64
	Amount    int64      // 毫分(1 USD = 100,000 毫分;handler 边界 /1e5 → USD)
	ExpiresAt *time.Time // nil = 永久额度
	Note      *string    // 固定系统备注(signup bonus / redemption code),无敏感信息
	CreatedAt time.Time
}

TempBalance 临时额度行(只读查询面:/api/user/temp-balances + /api/admin/temp-balances)。 写面仅 CreateTempBalance(标量参数);扣费走 FEFO 条件更新不经过本类型。

type Template

type Template struct {
	ID               int64
	Name             string
	BaseURL          string
	CredentialType   credential.Type            // 模板级:默认 api_key(DB 默认;号池生态类型后续)
	SupportedFormats []RequestFormat            // 模板支持的格式(非空、去重)
	Models           []string                   // 可服务模型集合
	FormatModels     map[RequestFormat][]string // 格式 → 该格式支持的模型列表;未配置 = 全部 Models
	ModelMapping     map[string]string
	// StripImageTools 模板级图像 tool 剥离开关(template_ext.strip_image_tools
	// 快照合并,W4 消费;三类型 responses-special/codex-oauth/codex-pat 公共
	// 能力):true = response.create 帧出口剥离图像工具(tools 数组 +
	// tool_choice 悬挂;input 内嵌 v1 图像内容不做)。热路径快照布尔读 + 分支
	// 零开销;false = 未配置/关闭(nil 与 false 同语义,快照收敛为 bool)。
	StripImageTools bool
	CreatedAt       time.Time
	UpdatedAt       time.Time
	DeletedAt       *time.Time // 软删除时间戳;nil = 存活(列表/消费路径过滤;GET 单个可查已删)
}

func (*Template) FormatSupports

func (t *Template) FormatSupports(f RequestFormat, m string) bool

FormatSupports 格式 f 是否支持模型 m(模型级限制): f 不在 SupportedFormats → false;FormatModels[f] 配置了 → m ∈ 列表;未配置 → true。

func (*Template) FormatsFor

func (t *Template) FormatsFor() []RequestFormat

FormatsFor 模板支持的格式列表。

func (*Template) HasModelSpace

func (t *Template) HasModelSpace() bool

HasModelSpace 模型空间是否已配置(Models/FormatModels/ModelMapping 任一非空)。 空 = 未配置 = 全模型支持(硬白名单语义下归 tier2 兜底桶)。

func (*Template) Serves

func (t *Template) Serves(m string) bool

Serves 模型是否在可服务集合(models ∪ format_models 全部列表 ∪ mapping keys)内。

type TemplateExt

type TemplateExt struct {
	TemplateID      int64
	CredentialType  credential.Type
	StripImageTools *bool // 三类型公共能力开关:模板级图像 tool 剥离(W4 消费)
}

TemplateExt 模板类型化扩展配置(template_ext 子表,1:1):credential_type ∈ {responses-special, codex-oauth, codex-pat} 的模板才有 ext 行(api_key 主列 类型无 ext 行)。模板是共享配置面:只承载类型声明 + StripImageTools 公共 能力开关(三类型通用)——凭据列组(oauth/pat)一律在账号级 account_ext (账号私有)。nil = 未配置(NULL 落库)。

type UsageAgg

type UsageAgg struct {
	AccountID   int64
	Requests    int64 // COUNT(*)
	Cost        int64 // SUM(cost),毫分(计费成本)
	RawCost     int64 // SUM(raw_cost),毫分(乘倍率前原始成本)
	TotalTokens int64 // SUM(total_tokens)
}

UsageAgg 账号 usage_logs 区间聚合行(ScanUsageAgg 行形态——统一 usage API 查询面 spec 2026-08-18):毫分 int64 原样聚合(USD 换算在 handler 展示边界 /1e5,temp-balances 先例),不做逐行事后计算。

type UsageLog

type UsageLog struct {
	ID                       int64
	RequestID                string
	ClientIP                 string // 客户端 IP(供应商头按序识别 + RemoteAddr 兜底——proxy.behind_cdn 门控;审计/排障标识,非安全边界;空 = 理论无(提取恒有兜底))
	GroupID                  int64  // 0 = 无
	AccountID                int64  // 0 = 无
	TemplateID               int64  // 0 = 无
	UserID                   int64  // 0 = 无(鉴权失败/无 key)
	KeyID                    int64  // 0 = 无
	Model                    string
	MappedModel              string // 空 = 未映射
	Format                   RequestFormat
	StatusCode               int
	ErrorType                ErrorType
	ErrorMessage             *string // nil = 无错误文本(NULL 落库)
	LatencyMS                int64
	TTFTMS                   *int64 // 首 token 时间毫秒;非流式/失败/无首 token 路径 = nil
	InputTokens              int64  // 输入 token(图片生成含 image input tokens——已并入)
	PriceInputMillis         *int64 // 输入单价快照(每 M token 毫分)
	OutputTokens             int64  // 输出 token(图片生成含 image output tokens——已并入)
	PriceOutputMillis        *int64 // 输出单价快照(每 M token 毫分)
	TotalTokens              int64  // 含 image tokens、不含 call_count(口径不变)
	CacheReadTokens          int64  // 缓存读取 token(跨协议归一化,sub2api 计费语义)
	PriceCacheReadMillis     *int64 // 缓存读单价快照;nil = 无缓存读或无缓存价
	CacheCreationTokens      int64  // 缓存写入 token(OpenAI ephemeral 5m/1h 聚合)
	PriceCacheCreationMillis *int64 // 缓存写单价快照;nil = 无缓存写或无缓存价
	CallCount                int64  // 功能调用计数:图片生成 = 张数(data 长/completed 事件数)、search = 1;不入 TotalTokens(功能调用非 token)
	PricePerCallMillis       *int64 // 按单元价快照(**毫分/单元**——search 每次 / 图片每张;例外单位,例外于上文"毫分/1M"口径——per-call 计费不走 /1e6 除法);nil = 无按单元分量
	Cost                     int64  // 毫分;错误请求(402/4xx)为 0
	// RawCost 乘倍率前的原始成本(毫分;免费组 cost=0 但 raw 有值——"实际消耗"
	// 只有 raw 能看)。回显面投影归 Task 2(本字段无 json tag,对齐 domain 全
	// 结构惯例)。
	RawCost     int64  // 毫分;bill 未装配/无价防御路径恒 0
	BillingTier string // priority/flex/fast/auto;空 = 未计费路径
	AboveHit    bool
	Overdraft   bool
	// Billed 扣费收敛标记(F2 ledger-cursor,spec 2026-08-23):false=待对账
	// 消费者扣减;true=扣费事务已完成(或出生吸收态——计费关闭/匿名行)。
	// 出生标记由 proxy.routeLog 按 NOT BillingCapture OR UserID<=0 盖章;
	// 翻转为 true 只发生在对账事务内(与 FEFO 扣减同事务原子)。
	Billed    bool
	CreatedAt time.Time
}

UsageLog 用量日志:user_id/key_id 为鉴权归属(context 传递,0 = 无)。 计费列(Phase 5):Cost 毫分(1 USD = 100,000 毫分);BillingTier 请求 service_tier 归一化值(priority/flex/fast/auto,空 = 未计费路径);AboveHit 任一分量超 above 阈值命中分段;Overdraft 本次扣费透支(负余额)。 ErrorMessage 错误文本(部署故障修复):连接级 err.Error() / 4xx+ 上游 body, 域内截断 500 字符(TruncateErrMsg);nil = 无错误文本(成功路径恒空)。 时间/价格快照(字段序对齐 ent schema):TTFTMS 首 token 时间毫秒(流式首 chunk 采集;非流式/失败/无首 token 路径 = nil);Price*Millis 每 M token 毫分 单价快照(1 USD = 100,000 毫分,pricing 同款单位;applyBilling 填充,零额外 查找)——nil = 未计费路径(no_price 防御);缓存价 nil = 该请求无缓存读或 无缓存价。 统一计费模型(spec 2026-08-13):功能调用分量 = CallCount(图片生成 = 张数 data 长/completed 事件数、search = 1)+ PricePerCallMillis 按单元价快照 (毫分/单元——search 每次 / 图片每张)。**call_count 不入 TotalTokens** (功能调用非 token——对齐原 image_count 语义;离线聚合 sum(call_count) = 功能 调用量,进 StatBucket.CallCount——spec 2026-08-14 用户裁决按次调用入桶与展示)。 图片生成 image token 已并入 InputTokens/OutputTokens(原 image_input/output_tokens 六 列删除——image token 价快照列随之删除,cost 口径不变:ImageCost 仍按 张数 × 每张价 + image token 价计算)。

type User

type User struct {
	ID           int64
	Email        string
	PasswordHash string
	Role         Role
	Status       UserStatus
	// TokenVersion JWT 撤销版本(users.token_version;改密/重置密码原子递增,
	// 登录时写入 Claims.Ver——spec 2026-08-25-jwt-password-revocation)。
	TokenVersion   int64
	MaxConcurrency int
	Balance        int64
	CreatedAt      time.Time
	UpdatedAt      time.Time
}

User 用户(顶层实体,无租户)。标识 = 邮箱;PasswordHash 为 bcrypt DefaultCost(10)(与 sub2api 同参数,存量 hash 可迁移验证)。 Balance 最小单位(毫分;1 USD = 100,000 毫分,Phase 5 计费统一单位, 管理面 API 展示/输入换算 USD)。 价格倍率按组(T3.5 修正):挂在 group_assignment 上(GroupAssignment. PriceMultiplier),用户不同组可有不同倍率——User 无倍率字段。

type UserBalance

type UserBalance struct {
	UserID  int64
	Balance int64
}

UserBalance 定向余额对(结算语句 debited/forced RETURNING (uid, balance_after); spec-f2opt-settlement §一 oracle 必改 #3):保住 Balances 定向 Set 的预检 新鲜度(10s Reload 间隙 fail-closed 预检依赖它)。

type UserSnapshot

type UserSnapshot struct {
	Status       UserStatus
	Role         Role
	TokenVersion int64 // 签发时 Claims.Ver 与此不等 → 401(改密撤销)
}

UserSnapshot 用户快照条目(Auth 内存表元素:RequireJWT/adminAuth 共用, 单次查找同时取 status+role+token_version——降权即时生效的 role 数据源, adminAuth 不再单独信任 claims.Role;token_version 为 JWT 撤销比对源, spec 2026-08-25-jwt-password-revocation)。

type UserStatus

type UserStatus string

UserStatus 用户状态。

const (
	UserStatusActive   UserStatus = "active"
	UserStatusDisabled UserStatus = "disabled"
)

func (UserStatus) Valid

func (s UserStatus) Valid() bool

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL