model

package
v0.21.0 Latest Latest
Warning

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

Go to latest
Published: Aug 26, 2026 License: MIT Imports: 5 Imported by: 0

Documentation

Index

Constants

View Source
const (
	AlertLevelInfo     = "info"
	AlertLevelWarn     = "warn"
	AlertLevelCritical = "critical"
)

告警级别(FR-085)。按严重度递增,用于路由与展示着色。

View Source
const (
	// AlertTriggerMetric 指标阈值(节点 cpu/memory/disk,FR-011 原型)。
	AlertTriggerMetric = "metric"
	// AlertTriggerInstanceCrash 实例崩溃(state_change → CRASHED)。
	AlertTriggerInstanceCrash = "instance_crash"
	// AlertTriggerNodeOffline 节点离线(心跳超时被标记 offline)。
	AlertTriggerNodeOffline = "node_offline"
	// AlertTriggerLogKeyword 日志关键字(实例 stdout/stderr 命中关键字)。
	AlertTriggerLogKeyword = "log_keyword"
	// AlertTriggerPlayerEvent 玩家事件(接 FR-066 PlayerEventService)。
	AlertTriggerPlayerEvent = "player_event"
	// AlertTriggerBackupFailed 备份失败。
	AlertTriggerBackupFailed = "backup_failed"
)

告警触发类型(FR-085)。在 FR-011 的指标阈值之外扩展为多触发源。

View Source
const (
	ChannelTypeWebhook  = "webhook"
	ChannelTypeEmail    = "email"
	ChannelTypeDingtalk = "dingtalk"
	ChannelTypeWecom    = "wecom"
	ChannelTypeFeishu   = "feishu"
	ChannelTypeDiscord  = "discord"
	ChannelTypeTelegram = "telegram"
	ChannelTypeInApp    = "inapp"
)

通知通道类型(FR-085)。在通用 webhook 之外扩展主流 IM / 邮件 / 站内。

View Source
const (
	// ArtifactReconcileRunning 对账进行中(异步执行,前端轮询)。
	ArtifactReconcileRunning = "running"
	// ArtifactReconcileSucceeded 对账完成,差异明细已落库。
	ArtifactReconcileSucceeded = "succeeded"
	// ArtifactReconcileFailed 对账失败(存储遍历报错 / CP 重启中断),ErrorMessage 带原因。
	ArtifactReconcileFailed = "failed"
)

对账运行状态(FR-349,见 spec artifact-s3-reconcile §3.2)。

View Source
const (
	// ArtifactReconcileTriggerManual 面板手动触发。
	ArtifactReconcileTriggerManual = "manual"
	// ArtifactReconcileTriggerScheduled 定期任务触发。
	ArtifactReconcileTriggerScheduled = "scheduled"
)

对账触发方式。

View Source
const (
	// ArtifactDiffMissing 缺失:索引有、S3 无——下载必 404 的高危项。
	ArtifactDiffMissing = "missing"
	// ArtifactDiffOrphan 孤儿:S3 有、索引无——白占存储。
	ArtifactDiffOrphan = "orphan"
)

差异类别。

View Source
const (
	// ArtifactDiffOpen 待处置。
	ArtifactDiffOpen = "open"
	// ArtifactDiffResolved 已处置(ResolvedAction 记方式)。
	ArtifactDiffResolved = "resolved"
)

差异处置状态。

View Source
const (
	// ArtifactDiffActionMarkedLost 缺失 → 资产已标记失效(StorageState=lost)。
	ArtifactDiffActionMarkedLost = "marked_lost"
	// ArtifactDiffActionCleaned 孤儿 → S3 对象已清理删除。
	ArtifactDiffActionCleaned = "cleaned"
	// ArtifactDiffActionStale 差异已过时(run 后资产被删/迁移、或同键对象已被新上传合法引用),
	// 处置时守卫命中,不动资产也不删对象(FR-349 处置安全性,见 spec §3.5)。
	ArtifactDiffActionStale = "stale"
)

差异处置方式。

View Source
const (
	// ServerProbePackageKey 是 ServerProbe 制品包的稳定机器键(FR-409)。
	ServerProbePackageKey = "serverprobe"
	// ArtifactProviderGitHubRelease 是 GitHub Releases 来源 provider。
	ArtifactProviderGitHubRelease = "github-release"
	// ArtifactProviderLocalUpload 是平台管理员上传到 CP 制品库的来源 provider。
	ArtifactProviderLocalUpload = "local-upload"
)
View Source
const (
	MetricNodeCPUPct    = "node_cpu_pct"
	MetricNodeMemUsed   = "node_mem_used"
	MetricNodeMemTotal  = "node_mem_total"
	MetricNodeDiskUsed  = "node_disk_used"
	MetricNodeDiskTotal = "node_disk_total"
	MetricNodeNetRxRate = "node_net_rx_rate"
	MetricNodeNetTxRate = "node_net_tx_rate"
	MetricNodeLoad      = "node_load" // 1 分钟 load average(FR-062)

	// FR-401:由 FR-400 已认证 Heartbeat 当前快照沉淀的共享 Bot Worker 运行时指标。
	// 它们属于节点维度,不代表任一 Bot 或压测会话独占的资源。
	MetricWorkerProcessRSSBytes = "worker_process_rss_bytes"
	MetricWorkerProcessCPUPct   = "worker_process_cpu_pct"
	MetricBotWorkerRSSBytes     = "bot_worker_rss_bytes"
	MetricBotWorkerCPUPct       = "bot_worker_cpu_pct"
	MetricBotActiveCount        = "bot_active_count"
	MetricBotConnectingCount    = "bot_connecting_count"
	MetricBotCapacityMax        = "bot_capacity_max"
	MetricBotEventLoopP95MS     = "bot_event_loop_p95_ms"

	MetricInstTPS           = "inst_tps"
	MetricInstMSPT          = "inst_mspt"
	MetricInstPlayersOnline = "inst_players_online"
	MetricInstHeapUsed      = "inst_heap_used"
	MetricInstHeapMax       = "inst_heap_max"
	MetricInstThreads       = "inst_threads"
	MetricInstCPUPct        = "inst_cpu_pct"
	MetricInstUptime        = "inst_uptime"

	MetricWorldLoadedChunks = "world_loaded_chunks"
	MetricWorldEntities     = "world_entities"
	MetricWorldTileEntities = "world_tile_entities"
)

指标键(metric_key)。完整语义见 docs/specs/timeseries-metrics/api.md。

View Source
const (
	// TaskKindJDKInstall JDK 一键下载安装任务(FR-183 首批载体,见 ADR-040)。
	TaskKindJDKInstall = "jdk_install"
	// TaskKindPkgInstall 全局包安装/升级任务(FR-307)。
	TaskKindPkgInstall = "pkg_install"
	// TaskKindRuntimeInstall 非 JDK 运行时一键下载安装任务(FR-299,首批 Node.js)。
	// 复用 jdk_install 的异步任务模式;终态副作用落 model.NodeRuntime。
	TaskKindRuntimeInstall = "runtime_install"
	// TaskKindProvision 一键搭建后端子服任务(FR-319):与其它 kind 不同,执行体在 CP 后台
	// goroutine(下载在 worker、编排在 CP),进度/终态由 CP 直写而非 worker 心跳快照。
	TaskKindProvision = "provision"
	// TaskKindImport 导入现有服务器(migrate 搬迁)任务(FR-323,CP 后台 goroutine)。
	TaskKindImport = "import"
	// TaskKindClone 克隆实例(拷贝工作目录)任务(FR-323,CP 后台 goroutine)。
	TaskKindClone = "clone"
	// TaskKindBackupCreate 备份创建(打包工作目录)任务(FR-323,CP 后台 goroutine)。
	TaskKindBackupCreate = "backup_create"
	// TaskKindBackupRestore 备份恢复(回放备份链)任务(FR-323,CP 后台 goroutine)。
	TaskKindBackupRestore = "backup_restore"
	// TaskKindArtifactMigrate 制品存量迁移任务(FR-348,CP 后台 goroutine):
	// 逐制品搬运到目标存储渠道(先改记录再删源),全程一次仅允许一个在途。
	TaskKindArtifactMigrate = "artifact_migrate"
)

任务种类常量(kind)。新增长任务类型时在此登记。

View Source
const AssetBackendLocal = "local"

AssetBackendLocal 本地存储后端标识(默认)。

View Source
const AssetBackendS3 = "s3"

AssetBackendS3 S3 兼容对象存储后端标识(FR-347,见 ADR-073)。

View Source
const EnvTagPrefix = "env:"

EnvTagPrefix 是「环境维度」复用 Tags 字段的约定前缀(FR-047)。 不新增独立字段/迁移:环境用 `env:dev` / `env:test` / `env:prod` 形式的标签表达, 一个实例至多取首个 env 标签作为其环境,其余 env 标签忽略(避免歧义)。

View Source
const SelfUpdateCheckCacheID = 1

SelfUpdateCheckCacheID 是单行缓存的固定主键。

Variables

This section is empty.

Functions

func EnvFromTags

func EnvFromTags(tags []string) string

EnvFromTags 返回实例的环境维度值(去掉 `env:` 前缀后的部分),取首个 env 标签。 无 env 标签时返回空串,表示「未分环境」。

func MatchEnv

func MatchEnv(tags []string, env string) bool

MatchEnv 判断实例标签是否属于指定环境。 env 传空串表示不按环境过滤(恒为真);否则要求实例的首个 env 标签等于 env。

func MatchTag

func MatchTag(tags []string, tag string) bool

MatchTag 判断实例标签集合是否精确包含指定标签。 tag 传空串表示不按标签过滤(恒为真)。用于「按任意标签筛选」, 区别于环境维度(环境只认 env: 前缀的首个值)。

func NormalizeTags

func NormalizeTags(tags []string) []string

NormalizeTags 规范化标签集合:去首尾空白、丢弃空项、去重并保持首次出现顺序。 大小写敏感(与 Network 群组名一致),不做小写折叠。

func ParseTags

func ParseTags(raw string) []string

ParseTags 把实例持久化的 Tags(JSON 字符串数组)解析为规范化切片。 兼容空串/非法 JSON:返回空切片而非报错,避免历史脏数据阻断列表查询。 规范化:去首尾空白、丢弃空项、去重保序——与下方 NormalizeTags 行为一致, 保证「读出来再写回去」幂等。

func ValidArtifactStorageChannelType added in v0.18.0

func ValidArtifactStorageChannelType(t ArtifactStorageChannelType) bool

ValidArtifactStorageChannelType 校验渠道类型是否在允许枚举内。

func ValidAssetType

func ValidAssetType(t AssetType) bool

ValidAssetType 校验类型是否在允许枚举内。

func ValidBackupStorageType

func ValidBackupStorageType(t BackupStorageType) bool

ValidBackupStorageType 校验后端类型是否在允许枚举内(local 仅用于占位,不作为远程后端创建)。

func ValidChannelID

func ValidChannelID(s string) bool

ValidChannelID 校验频道 slug 合法性:仅小写字母/数字/连字符,首字符为字母或数字,长度 2-64。

func ValidInstanceRole

func ValidInstanceRole(r InstanceRole) bool

ValidInstanceRole 校验角色是否在允许枚举内。

func ValidMetricScope

func ValidMetricScope(s MetricScope) bool

ValidMetricScope 校验 scope 是否在允许枚举内。

Types

type AgentCallLog added in v0.20.0

type AgentCallLog struct {
	ID uint `gorm:"primaryKey" json:"id"`
	// TokenID 鉴权成功后的 agent token 主键。
	TokenID uint `gorm:"not null;index:idx_agent_call_token_created,priority:1;index" json:"tokenId"`
	// TokenName 冗余快照(吊销后仍可读)。
	TokenName string `gorm:"type:varchar(128);not null" json:"tokenName"`
	// Action 与 service.AgentAction* 或 MCP 事件对齐(如 agent.whoami)。
	Action string `gorm:"type:varchar(64);not null;index:idx_agent_call_action_created,priority:1" json:"action"`
	// Capability 本次授权实际使用的能力标签(V2 capability 或 V1 legacy.*);会话事件可空。
	Capability string `gorm:"type:varchar(64)" json:"capability,omitempty"`
	// Client 调用方:mcp | jmagent | curl | unknown(优先 X-JM-Agent-Client)。
	Client string `gorm:"type:varchar(32);not null;default:unknown" json:"client"`
	// Transport 可选:streamable_http | sse | http | 空。
	Transport string `gorm:"type:varchar(32)" json:"transport,omitempty"`
	// TargetType 目标类型(instance/node 等,可空)。
	TargetType string `gorm:"type:varchar(32)" json:"targetType,omitempty"`
	// TargetID 目标 ID 字符串(可空)。
	TargetID string `gorm:"type:varchar(64)" json:"targetId,omitempty"`
	// Success 是否成功(策略 403 记 false;业务失败亦 false)。
	Success bool `json:"success"`
	// Error 失败时截断短文(禁 Token 明文)。
	Error string `gorm:"type:varchar(512)" json:"error,omitempty"`
	// LatencyMs 处理耗时毫秒。
	LatencyMs uint `json:"latencyMs"`
	// IP 客户端 IP。
	IP string `gorm:"type:varchar(64)" json:"ip"`
	// CreatedAt 写入时间;复合索引供按 token/时间、action/时间查询。
	CreatedAt time.Time `gorm:"index:idx_agent_call_token_created,priority:2;index:idx_agent_call_action_created,priority:2;index" json:"createdAt"`
}

AgentCallLog Agent 调用流水(FR-390 / FR-395,见 ADR-076/080)。 覆盖 /api/v1/agent/* Ops 读+写与 MCP tool;与人类 audit 表独立。 token_name 为签发时名称快照,吊销后仍可读;error 截断短文,禁 Token 明文。

type AgentToken added in v0.20.0

type AgentToken struct {
	ID uint `gorm:"primaryKey" json:"id"`
	// Name 运营可见名称。
	Name string `gorm:"type:varchar(128);not null" json:"name"`
	// TokenHash 明文的 SHA-256 十六进制小写。库内不存明文。
	TokenHash string `gorm:"column:token_hash;type:char(64);uniqueIndex;not null" json:"-"`
	// TokenPrefix 明文前缀(如 jmat_ab12),仅供列表识别。
	TokenPrefix string `gorm:"column:token_prefix;type:varchar(16);not null" json:"tokenPrefix"`
	// ScopedInstanceIDs 可访问实例 ID 列表(JSON 数组)。空表示「未授权任何实例读/写」——默认从严。
	ScopedInstanceIDs string `gorm:"column:scoped_instance_ids;type:text" json:"scopedInstanceIds"`
	// ScopedNodeIDs 可访问节点 ID 列表(JSON 数组)。空表示未授权任何节点。
	ScopedNodeIDs string `gorm:"column:scoped_node_ids;type:text" json:"scopedNodeIds"`
	// WriteAllowlist 写操作白名单(JSON 字符串数组),如 ["instance.life","node.maintenance"]。
	// 仅 V1 策略使用;V2 保持空并改用 Capabilities。
	WriteAllowlist string `gorm:"column:write_allowlist;type:text" json:"writeAllowlist"`
	// PolicyVersion 策略版本:1=V1 写白名单;2=V2 capability。既有记录默认 1。
	PolicyVersion int `gorm:"column:policy_version;not null;default:1" json:"policyVersion"`
	// Capabilities V2 能力分组(JSON 字符串数组)。仅 policy_version=2 使用。
	Capabilities string `gorm:"column:capabilities;type:text" json:"capabilities,omitempty"`
	// ExpiresAt 过期时间;到期即校验失败。
	ExpiresAt time.Time `gorm:"not null;index" json:"expiresAt"`
	// Revoked 吊销标记;true 即立即失效。
	Revoked bool `gorm:"default:false;not null;index" json:"revoked"`
	// LastUsedAt 最近一次成功鉴权时间(可选更新)。
	LastUsedAt *time.Time `json:"lastUsedAt"`
	CreatedAt  time.Time  `json:"createdAt"`
	// CreatedBy 签发该 token 的平台管理员用户 ID。
	CreatedBy uint `json:"createdBy"`
}

AgentToken Agent 专用令牌(FR-384 / FR-395,见 ADR-076/080)。 落库只存 SHA-256 哈希;明文仅签发时一次性返回,不可二次读取。 与人类 JWT 分离:scope(实例/节点白名单)+ V1 write_allowlist / V2 capabilities 约束 agent 能力面。

type AgentTransferTicket added in v0.21.0

type AgentTransferTicket struct {
	Digest     string     `gorm:"primaryKey;type:char(64)"`
	ExpiresAt  time.Time  `gorm:"not null;index"`
	ConsumedAt *time.Time `gorm:"index"`
	CreatedAt  time.Time
}

AgentTransferTicket 保存传输票据的摘要与消费状态,确保重启及多进程部署下仍保持一次性语义。

type AlertChannel

type AlertChannel struct {
	ID      uint   `gorm:"primaryKey" json:"id"`
	UUID    string `gorm:"type:char(36);uniqueIndex;not null" json:"uuid"`
	Name    string `gorm:"type:varchar(128);not null" json:"name"`
	Type    string `gorm:"type:varchar(32);not null" json:"type"`
	Enabled bool   `gorm:"default:true" json:"enabled"`
	// Config 通道连接配置的 JSON 串。各类型字段不同(见 service/channel_notifier.go ChannelConfig):
	//   webhook/dingtalk/wecom/feishu/discord: {"url":"${ENV}"}(URL 含 access_token/secret,强制 ${ENV} 引用)
	//   telegram: {"token":"${ENV}","chatId":"..."}
	//   email:    {"host","port","username","password":"${ENV}","from","to"}
	//   inapp:    {}(无外部配置)
	// 凭证子字段(URL/token/password)强制经 ${ENV_VAR} 引用,CreateChannel/UpdateChannel 时校验、发送时解析。
	Config    string         `gorm:"type:text" json:"config"`
	CreatedAt time.Time      `json:"createdAt"`
	UpdatedAt time.Time      `json:"updatedAt"`
	DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
}

AlertChannel 通知通道(FR-085)。一个通道是一个可复用的通知出口, 多条规则可路由到同一通道。敏感凭证字段(webhook 地址含 secret、SMTP 密码、bot token) 必须以 ${ENV_VAR} 形式引用环境变量,不得硬编码明文(见 .claude/rules/config-files.md)。

func (*AlertChannel) BeforeCreate

func (c *AlertChannel) BeforeCreate(tx *gorm.DB) error

BeforeCreate 创建前自动生成 UUID。

type AlertEvent

type AlertEvent struct {
	ID       uint `gorm:"primaryKey" json:"id"`
	RuleID   uint `gorm:"not null;index" json:"ruleId"`
	TargetID uint `json:"targetId"`
	// Level/TriggerType 冗余快照规则当时的级别与类型,便于历史筛选(规则可能被改/删)。
	Level       string `gorm:"type:varchar(16);default:warn" json:"level"`
	TriggerType string `gorm:"type:varchar(32);default:metric" json:"triggerType"`
	// DedupKey 去抖键(rule + target + 触发标识)。聚合窗口内复发更新同一活跃事件而非新建。
	DedupKey string  `gorm:"type:varchar(256);index" json:"-"`
	Value    float64 `json:"value"`
	Message  string  `gorm:"type:varchar(512)" json:"message"`
	// Count 聚合计数:去抖窗口内该告警被触发的次数(≥1)。
	Count    int       `gorm:"default:1" json:"count"`
	Resolved bool      `gorm:"default:false" json:"resolved"`
	FiredAt  time.Time `json:"firedAt"`
	// LastFiredAt 最近一次复发时间(聚合时更新)。
	LastFiredAt *time.Time `json:"lastFiredAt"`
	ResolvedAt  *time.Time `json:"resolvedAt"`

	// ── 确认 / 已读(FR-085)──
	Acknowledged   bool       `gorm:"default:false" json:"acknowledged"`
	AcknowledgedBy *uint      `json:"acknowledgedBy"`
	AcknowledgedAt *time.Time `json:"acknowledgedAt"`
	// Read 站内已读状态(仅影响未读角标,不影响确认)。
	Read bool `gorm:"default:false" json:"read"`

	Rule AlertRule `gorm:"foreignKey:RuleID" json:"rule,omitempty"`
}

AlertEvent 告警事件(FR-011 + FR-085 扩展)。

type AlertRule

type AlertRule struct {
	ID   uint   `gorm:"primaryKey" json:"id"`
	UUID string `gorm:"type:char(36);uniqueIndex;not null" json:"uuid"`
	Name string `gorm:"type:varchar(128);not null" json:"name"`
	// TriggerType 触发类型(FR-085):metric|instance_crash|node_offline|log_keyword|player_event|backup_failed。
	// 为兼容 FR-011 存量规则,空值按 metric 处理。
	TriggerType string `gorm:"type:varchar(32);default:metric" json:"triggerType"`
	// Level 告警级别(FR-085):info|warn|critical。空值按 warn 处理。
	Level      string `gorm:"type:varchar(16);default:warn" json:"level"`
	TargetType string `gorm:"type:varchar(32);not null" json:"targetType"` // node, instance
	TargetID   *uint  `json:"targetId"`                                    // nil 表示全局

	// ── metric 触发专用(FR-011)──
	Metric      string  `gorm:"type:varchar(64)" json:"metric"`  // cpu, memory, disk
	Operator    string  `gorm:"type:varchar(4)" json:"operator"` // >, <, >=, <=, ==
	Threshold   float64 `json:"threshold"`
	DurationSec int     `gorm:"default:0" json:"durationSec"`

	// ── 非指标触发专用(FR-085)──
	// Keyword 日志关键字触发的匹配子串(log_keyword)。
	Keyword string `gorm:"type:varchar(256)" json:"keyword"`
	// EventMatch 玩家事件触发的子类型(player_event):join|quit|chat|cross_server,空=任意。
	EventMatch string `gorm:"type:varchar(64)" json:"eventMatch"`

	// ── 聚合 / 静默 / 路由(FR-085)──
	// ChannelIDs 路由目标通道 ID 列表的 JSON 串(如 "[1,2]")。空=不发外部通知(仍入事件库 + 站内)。
	ChannelIDs string `gorm:"type:varchar(256)" json:"channelIds"`
	// DedupWindowSec 去抖聚合窗口(秒)。同一告警键在窗口内重复触发只通知一次、累计计数。0=不去抖。
	DedupWindowSec int `gorm:"default:0" json:"dedupWindowSec"`
	// SilenceStart/SilenceEnd 静默窗口("HH:MM" 24h,本地时区)。落在窗口内触发的告警不发外部通知(仍入库)。
	// 支持跨午夜(start > end,如 23:00→07:00)。两者皆空=不静默。
	SilenceStart string `gorm:"type:varchar(8)" json:"silenceStart"`
	SilenceEnd   string `gorm:"type:varchar(8)" json:"silenceEnd"`
	// NotifyRecover 恢复时是否发送恢复通知(仅对可恢复的触发类型:metric/instance_crash/node_offline)。
	NotifyRecover bool `json:"notifyRecover"`

	// NotifyType/NotifyTarget 兼容 FR-011 的单 webhook 直发(未配置 ChannelIDs 时回退)。
	NotifyType   string `gorm:"type:varchar(32)" json:"notifyType"`
	NotifyTarget string `gorm:"type:varchar(512)" json:"-"`

	Enabled   bool           `gorm:"default:true" json:"enabled"`
	CreatedAt time.Time      `json:"createdAt"`
	UpdatedAt time.Time      `json:"updatedAt"`
	DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
}

AlertRule 告警规则(FR-011 + FR-085 扩展)。

func (*AlertRule) BeforeCreate

func (a *AlertRule) BeforeCreate(tx *gorm.DB) error

BeforeCreate 创建前自动生成 UUID。

type ArtifactMigration added in v0.18.0

type ArtifactMigration struct {
	ID     uint   `gorm:"primaryKey" json:"id"`
	TaskID string `gorm:"type:varchar(64);uniqueIndex;not null" json:"taskId"`
	// TargetChannelID 目标渠道(重试 = 对同目标重新发起的解析源)。
	TargetChannelID uint `gorm:"not null;index" json:"targetChannelId"`
	// Total 快照内全部 client-file 存量数。
	Total int `gorm:"not null;default:0" json:"total"`
	// Migrated 本次任务实际搬运成功数。
	Migrated int `gorm:"not null;default:0" json:"migrated"`
	// Failed 本次任务失败条数(明细见 ArtifactMigrationFailure)。
	Failed int `gorm:"not null;default:0" json:"failed"`
	// Skipped 发起时已在目标渠道数(续跑时「上轮已迁」体现于此)。
	Skipped   int       `gorm:"not null;default:0" json:"skipped"`
	CreatedAt time.Time `json:"createdAt"`
	UpdatedAt time.Time `json:"updatedAt"`
}

ArtifactMigration 一次制品存量迁移任务的登记与实时计数(FR-348,底座见 ADR-073)。 task_id 1:1 关联 tasks 行(kind=artifact_migrate)。计数独立成行而非塞 Task.Result/Detail: 失败任务无 result、Detail 被阶段文本覆写,独立行保证「总数/已迁/失败/跳过」随迁移逐条 持久推进,前端渠道页可精确展示。

type ArtifactMigrationFailure added in v0.18.0

type ArtifactMigrationFailure struct {
	ID      uint   `gorm:"primaryKey" json:"id"`
	TaskID  string `gorm:"type:varchar(64);not null;index" json:"taskId"`
	AssetID uint   `json:"assetId"`
	// SHA256 制品内容寻址键(定位失败制品)。
	SHA256    string    `gorm:"type:char(64);not null" json:"sha256"`
	Filename  string    `gorm:"type:varchar(255)" json:"filename"`
	Size      int64     `json:"size"`
	Reason    string    `gorm:"type:text" json:"reason"`
	CreatedAt time.Time `json:"createdAt"`
}

ArtifactMigrationFailure 迁移失败明细(FR-348):逐条落库可查(制品 sha256 + 原因), 按 task_id 隔离(每次任务独立一批);重试 = 重新发起同目标迁移。

type ArtifactPackage added in v0.21.0

type ArtifactPackage struct {
	ID               uint      `gorm:"primaryKey" json:"id"`
	Key              string    `gorm:"type:varchar(128);not null;uniqueIndex" json:"key"`
	Name             string    `gorm:"type:varchar(255);not null" json:"name"`
	AssetType        AssetType `gorm:"type:varchar(32);not null" json:"assetType"`
	DefaultVersionID uint      `gorm:"default:0;index" json:"defaultVersionId"`
	CreatedAt        time.Time `json:"createdAt"`
	UpdatedAt        time.Time `json:"updatedAt"`
}

ArtifactPackage 是可版本化的逻辑制品,不保存二进制字节。 实际文件仍由 Asset 的 CAS 负责,旧制品消费者无需迁移。

type ArtifactReconcileDiff added in v0.18.0

type ArtifactReconcileDiff struct {
	ID        uint `gorm:"primaryKey" json:"id"`
	RunID     uint `gorm:"not null;index" json:"runId"`
	ChannelID uint `gorm:"not null;index" json:"channelId"`
	// Kind missing | orphan。
	Kind string `gorm:"type:varchar(16);not null;index" json:"kind"`
	// AssetID missing:资产 ID;orphan:0(对象不在索引,无资产可指)。
	AssetID uint `json:"assetId"`
	// SHA256 missing:资产内容寻址键;orphan 空。
	SHA256 string `gorm:"type:char(64)" json:"sha256"`
	// ObjectKey CAS 相对键(missing=Asset.RelPath;orphan=剥渠道前缀后的对象键)。
	ObjectKey string `gorm:"type:varchar(512);not null" json:"objectKey"`
	Size      int64  `json:"size"`
	// LastModified orphan:S3 对象 Last-Modified;missing nil。
	LastModified *time.Time `json:"lastModified"`
	// Status open | resolved。
	Status     string     `gorm:"type:varchar(16);not null;default:open" json:"status"`
	ResolvedAt *time.Time `json:"resolvedAt"`
	// ResolvedAction marked_lost | cleaned | stale。
	ResolvedAction string `gorm:"type:varchar(32)" json:"resolvedAction"`
	// ResolveError 清理失败原因(保持 open 供重试)。
	ResolveError string    `gorm:"type:varchar(512)" json:"resolveError"`
	CreatedAt    time.Time `json:"createdAt"`
}

ArtifactReconcileDiff 差异明细(缺失/孤儿),随 run 落库,处置后翻 resolved(FR-349)。

type ArtifactReconcileRun added in v0.18.0

type ArtifactReconcileRun struct {
	ID        uint `gorm:"primaryKey" json:"id"`
	ChannelID uint `gorm:"not null;index" json:"channelId"`
	// ChannelName 渠道名快照:渠道后续改名/删除不影响历史报告可读。
	ChannelName string `gorm:"type:varchar(128)" json:"channelName"`
	// Status running | succeeded | failed。
	Status string `gorm:"type:varchar(16);not null" json:"status"`
	// TriggeredBy manual | scheduled。
	TriggeredBy string     `gorm:"type:varchar(16);not null" json:"triggeredBy"`
	StartedAt   time.Time  `json:"startedAt"`
	FinishedAt  *time.Time `json:"finishedAt"`
	// IndexCount 索引侧扫描条数(该渠道 s3 资产数,含已 lost)。
	IndexCount int `json:"indexCount"`
	// ObjectCount 对象侧扫描条数(渠道 prefix 下 CAS client-file 命名空间内)。
	ObjectCount int `json:"objectCount"`
	// MatchedCount 两侧一致数(仅计数不落明细)。
	MatchedCount int `json:"matchedCount"`
	MissingCount int `json:"missingCount"`
	OrphanCount  int `json:"orphanCount"`
	// ErrorMessage failed 时的原因(截断 512)。
	ErrorMessage string    `gorm:"type:varchar(512)" json:"errorMessage"`
	CreatedAt    time.Time `json:"createdAt"`
}

ArtifactReconcileRun 一次制品索引 ↔ S3 对象清单的对账运行记录(FR-349)。 逐 s3 渠道对账;local 不对账(本地文件系统由 CAS 自管)。面板查最近 N 次。

type ArtifactReconcileSetting added in v0.18.0

type ArtifactReconcileSetting struct {
	ID uint `gorm:"primaryKey" json:"id"`
	// Enabled 定期对账开关,默认开。
	Enabled bool `gorm:"not null;default:true" json:"enabled"`
	// IntervalHours 周期小时数,默认 24(每日),钳制 [1,720]。
	IntervalHours int `gorm:"not null;default:24" json:"intervalHours"`
	// NextRunAt 下次定期触发时间;禁用时 nil。首个周期从启用/启动时刻起算(不在启动瞬间扫存储)。
	NextRunAt *time.Time `json:"nextRunAt"`
	UpdatedAt time.Time  `json:"updatedAt"`
}

ArtifactReconcileSetting 定期对账设置(单行 id=1,服务 firstOrCreate 兜底;FR-349)。

type ArtifactSource added in v0.21.0

type ArtifactSource struct {
	ID           uint       `gorm:"primaryKey" json:"id"`
	PackageID    uint       `gorm:"not null;index;uniqueIndex:idx_artifact_sources_package_name" json:"packageId"`
	Provider     string     `gorm:"type:varchar(64);not null;index" json:"provider"`
	Name         string     `gorm:"type:varchar(255);not null;uniqueIndex:idx_artifact_sources_package_name" json:"name"`
	Config       string     `gorm:"type:text;not null" json:"config"`
	Enabled      bool       `gorm:"default:true;not null" json:"enabled"`
	LastSyncedAt *time.Time `json:"lastSyncedAt"`
	LastError    string     `gorm:"type:varchar(512)" json:"lastError"`
	CreatedAt    time.Time  `json:"createdAt"`
	UpdatedAt    time.Time  `json:"updatedAt"`
}

ArtifactSource 是某制品包的版本来源;Config 只保存 provider 的非敏感配置 JSON。

type ArtifactStorageChannel added in v0.18.0

type ArtifactStorageChannel struct {
	ID   uint                       `gorm:"primaryKey" json:"id"`
	Name string                     `gorm:"type:varchar(128);not null;uniqueIndex" json:"name"`
	Type ArtifactStorageChannelType `gorm:"type:varchar(16);not null" json:"type"`
	// Endpoint S3 主机[:端口],容带 scheme(适配器剥离)。
	Endpoint string `gorm:"type:varchar(512)" json:"endpoint"`
	// Bucket S3 桶名。
	Bucket string `gorm:"type:varchar(255)" json:"bucket"`
	// Region SigV4 region,缺省 us-east-1。
	Region string `gorm:"type:varchar(64)" json:"region"`
	// Prefix 对象键前缀;真实对象键 = <Prefix>/<CAS 相对路径>。
	Prefix string `gorm:"type:varchar(255)" json:"prefix"`
	// AccessKeyEnc/SecretKeyEnc AES-256-GCM 可逆加密密文(base64)。
	// json:"-":任何 API 响应不回明文也不回密文,列表以 Has* 布尔示意。
	AccessKeyEnc string `gorm:"type:text" json:"-"`
	SecretKeyEnc string `gorm:"type:text" json:"-"`
	// UseSSL S3 走 https;false 走 http(rustfs/MinIO 内网常态)。
	// 不用 gorm default:true,否则 GORM 会把显式 false(零值)覆盖回 true(同 BackupStorage 先例)。
	UseSSL bool `json:"useSsl"`
	// PresignTTLSeconds 预签名 URL 有效期秒数,默认 600(10 分钟),service 钳制 [60, 3600]。
	PresignTTLSeconds int `gorm:"default:600;not null" json:"presignTtlSeconds"`
	// Active 活跃渠道标记:写路径唯一路由开关(全表恰一条,service 事务保证)。
	Active bool `gorm:"default:false;not null" json:"active"`
	// Builtin 内置「本机存储」渠道:不可删、不可编辑,兜底活跃。
	Builtin bool `gorm:"default:false;not null" json:"builtin"`
	// LastTest* 最近一次已存渠道连通性测试结果;表单临时测试不写入。
	LastTestAt      *time.Time `json:"lastTestAt,omitempty"`
	LastTestOk      bool       `json:"lastTestOk"`
	LastTestMessage string     `gorm:"type:varchar(255)" json:"lastTestMessage"`
	// HasAccessKey/HasSecretKey 列表标示凭证已配(不回明文/密文),service 填充。
	HasAccessKey bool      `gorm:"-" json:"hasAccessKey"`
	HasSecretKey bool      `gorm:"-" json:"hasSecretKey"`
	CreatedAt    time.Time `json:"createdAt"`
	UpdatedAt    time.Time `json:"updatedAt"`
}

ArtifactStorageChannel 制品存储渠道(FR-347,见 ADR-073,修订 ADR-011 存储节)。

与备份域 BackupStorage 独立(消费方不同:备份配置下发 Worker 执行,本渠道由 CP 自身 上传/签名消费)。凭证面板直填、AES-256-GCM 可逆加密落库(复用 FR-192 KeyEncryptor 基建),与备份域的 ${ENV_VAR} 引用形态分道(理由见 ADR-073 决策 4)。

活跃语义:全表恰一条 Active(service 事务保证),仅作用于**新上传**的 client-file 制品落点;存量 Asset 按自身 StorageBackend + StorageChannelID 自述读取。 硬删除(无软删列):被 Asset 引用/内置/活跃的渠道禁删,名称删除即释放。

type ArtifactStorageChannelType added in v0.18.0

type ArtifactStorageChannelType string

ArtifactStorageChannelType 制品存储渠道类型(FR-347,见 ADR-073)。

const (
	// ArtifactStorageLocal 本地数据根 CAS(内置渠道独占,恒可用)。
	ArtifactStorageLocal ArtifactStorageChannelType = "local"
	// ArtifactStorageS3 S3 兼容对象存储(AWS S3 / MinIO / rustfs 等)。
	ArtifactStorageS3 ArtifactStorageChannelType = "s3"
)

type ArtifactVersion added in v0.21.0

type ArtifactVersion struct {
	ID             uint       `gorm:"primaryKey" json:"id"`
	PackageID      uint       `gorm:"not null;index" json:"packageId"`
	SourceID       uint       `gorm:"not null;index;uniqueIndex:idx_artifact_versions_source_version" json:"sourceId"`
	Version        string     `gorm:"type:varchar(128);not null;uniqueIndex:idx_artifact_versions_source_version" json:"version"`
	ReleaseRef     string     `gorm:"type:varchar(255);not null" json:"releaseRef"`
	AssetName      string     `gorm:"type:varchar(255);not null" json:"assetName"`
	ExpectedSHA256 string     `gorm:"type:char(64);not null" json:"expectedSha256"`
	SourceURL      string     `gorm:"type:varchar(1024);not null" json:"sourceUrl"`
	AssetID        uint       `gorm:"default:0;index" json:"assetId"`
	CachedAt       *time.Time `json:"cachedAt"`
	LastError      string     `gorm:"type:varchar(512)" json:"lastError"`
	CreatedAt      time.Time  `json:"createdAt"`
	UpdatedAt      time.Time  `json:"updatedAt"`

	Asset *Asset `gorm:"foreignKey:AssetID" json:"asset,omitempty"`
}

ArtifactVersion 记录来源的一条语义版本;AssetID 非零才表示字节已通过校验并入 CAS。

type Asset

type Asset struct {
	ID   uint      `gorm:"primaryKey" json:"id"`
	Type AssetType `gorm:"type:varchar(32);not null;index;uniqueIndex:idx_assets_type_sha256" json:"type"`
	// Name 人类可读名称(如 "paper-1.20.4"),非寻址键。
	Name string `gorm:"type:varchar(255);index" json:"name"`
	// Version 版本标记(如 "1.20.4-435"),可空。
	Version string `gorm:"type:varchar(128)" json:"version"`
	// Filename 入库时的原始文件名,决定存储扩展名与下载名。
	Filename string `gorm:"type:varchar(255)" json:"filename"`
	// SHA256 内容寻址 + 去重键(十六进制小写)。
	SHA256 string `gorm:"type:char(64);not null;index;uniqueIndex:idx_assets_type_sha256" json:"sha256"`
	// MD5 辅助完整性校验(十六进制小写)。
	MD5 string `gorm:"type:char(32)" json:"md5"`
	// Size 字节数。
	Size int64 `gorm:"not null" json:"size"`
	// ContentType MIME 类型。
	ContentType string `gorm:"type:varchar(128)" json:"contentType"`
	// SourceURL 来源地址(下载入库时记录),可空。
	SourceURL string `gorm:"type:varchar(1024)" json:"sourceUrl"`
	// Metadata 类型相关的扩展元数据(JSON 字符串)。
	Metadata string `gorm:"type:text" json:"metadata"`
	// StorageState 冷热/外置状态,默认 hot。
	StorageState AssetStorageState `gorm:"type:varchar(32);default:hot;not null" json:"storageState"`
	// StorageBackend 存储后端标识,默认 local。
	StorageBackend string `gorm:"type:varchar(64);default:local;not null" json:"storageBackend"`
	// StorageChannelID 外置存储渠道引用(FR-347,见 ADR-073):0=本地/无渠道(历史行为),
	// >0 时指向 artifact_storage_channels.id——位置由记录自述,不由全局活跃状态推断。
	StorageChannelID uint `gorm:"default:0;not null;index" json:"storageChannelId"`
	// RefCount 引用计数,>0 时禁止删除(被模板/实例占用)。
	RefCount int `gorm:"default:0;not null" json:"refCount"`
	// RelPath 物理文件相对数据根的路径(var/artifacts/<type>/<ab>/<sha256><ext>),便携登记。
	RelPath    string     `gorm:"type:varchar(512)" json:"relPath"`
	CreatedAt  time.Time  `json:"createdAt"`
	LastUsedAt *time.Time `json:"lastUsedAt"`
}

Asset 制品库资产索引(内容寻址 + 类型化元数据)。 sha256 既是寻址键也是去重键:同 (type, sha256) 复用同一条记录与同一份物理文件。 参见 ADR-011: 制品库——类型分区的内容寻址与资产模型。

type AssetStorageState

type AssetStorageState string

AssetStorageState 制品存储状态,驱动归档/外置生命周期(归档策略为后续 FR,此处先立模型)。

const (
	// AssetStorageHot 热数据,存于本地 var/artifacts。
	AssetStorageHot AssetStorageState = "hot"
	// AssetStorageArchived 已归档(仍由平台管理,位置变化)。
	AssetStorageArchived AssetStorageState = "archived"
	// AssetStorageExternal 外置到对象存储等后端。
	AssetStorageExternal AssetStorageState = "external"
	// AssetStorageLost 失效:索引在、外置对象缺失,下载不可用(FR-349 对账「标记失效」处置写入;
	// 重传同内容文件去重命中即补传对象并复位 external,自愈语义见 artifact-s3-reconcile spec §3.6)。
	AssetStorageLost AssetStorageState = "lost"
)

type AssetType

type AssetType string

AssetType 制品类型。类型间物理分目录、类型内按 sha256 去重。参见 ADR-011。

const (
	// AssetTypeCore MC 服务器核心 jar(Paper/Spigot/Velocity 等)。
	AssetTypeCore AssetType = "core"
	// AssetTypePlugin 插件 jar。
	AssetTypePlugin AssetType = "plugin"
	// AssetTypeImage 图片。
	AssetTypeImage AssetType = "image"
	// AssetTypeVideo 视频。
	AssetTypeVideo AssetType = "video"
	// AssetTypeArchive 归档包(zip/tar 等)。
	AssetTypeArchive AssetType = "archive"
	// AssetTypeBlob 通用二进制。
	AssetTypeBlob AssetType = "blob"
	// AssetTypeClientFile 客户端分发制品(OTA 单文件压缩/原文)。
	// 内容寻址键 = 制品(压缩后)自身 sha256,即 manifest files[].artifact.sha256(FR-087,见 ADR-022)。
	AssetTypeClientFile AssetType = "client-file"
	// AssetTypeClientPack 客户端分发 .jmpack 容器(zstd 压缩段拼接 + Ed25519 签名,FR-097,见 ADR-021/022)。
	AssetTypeClientPack AssetType = "client-pack"
	// AssetTypeClientCore updater-core jar 制品(集中版本管理,FR-193,见 ADR-045)。
	// 内容寻址键 = core jar 制品(压缩后)自身 sha256,即 manifest agent.core.platforms[os].artifact.sha256。
	// 一份 jar 三平台通用(ADR-021):上传一份,manifest 生成时 fan-out 填各 platform 键。
	AssetTypeClientCore AssetType = "client-core"
	// AssetTypeClientUpdaterCore updater-core jar 归档制品(FR-259,见 updater-arch-simplification spec §D)。
	// make embed-client-updater 构建的新 core jar 入库归档为此类型(不覆盖旧版,内容寻址天然多版本)。
	// 频道选定版本(ClientChannel.SelectedCoreSHA256)指向本类型制品的 sha256,coreEndpoint 据此返回版本信息。
	AssetTypeClientUpdaterCore AssetType = "client-updater-core"
	// AssetTypeServerProbe 由制品版本库管理的 ServerProbe 探针 jar(FR-409)。
	AssetTypeServerProbe AssetType = "server-probe"
)

type AuditLog

type AuditLog struct {
	ID         uint   `gorm:"primaryKey" json:"id"`
	UUID       string `gorm:"type:char(36);uniqueIndex;not null" json:"uuid"`
	UserID     uint   `gorm:"not null;index" json:"userId"`
	Action     string `gorm:"type:varchar(64);not null" json:"action"` // instance.start, user.create, etc.
	TargetType string `gorm:"type:varchar(32)" json:"targetType"`      // instance, user, group
	TargetID   string `gorm:"type:varchar(64)" json:"targetId"`
	Detail     string `gorm:"type:text" json:"detail"` // JSON
	IP         string `gorm:"type:varchar(64)" json:"ip"`
	// Failed 操作是否失败(FR-321:失败操作也留痕并带错误内容)。语义取「失败」而非「成功」:
	// 失败是非零值 true,规避 GORM 零值列不进 INSERT 的坑(存 success 时 false 会被 default 吃掉),
	// 且历史行零值天然=未失败,无需迁移回填。
	Failed bool `json:"failed"`
	// Error 失败时的错误内容(响应 error body 截断,FR-321)。
	Error     string    `gorm:"type:varchar(512)" json:"error"`
	CreatedAt time.Time `json:"createdAt"`
	User      User      `gorm:"foreignKey:UserID" json:"user,omitempty"`
}

AuditLog 审计日志。

func (*AuditLog) BeforeCreate

func (a *AuditLog) BeforeCreate(tx *gorm.DB) error

BeforeCreate 创建前自动生成 UUID。

type AuthSetupLock added in v0.21.0

type AuthSetupLock struct {
	Key       string    `gorm:"type:varchar(64);primaryKey"`
	CreatedAt time.Time `json:"not null"`
}

AuthSetupLock 是首次管理员初始化的数据库互斥锁。 单行主键约束保证并发请求或多进程部署中只有一个请求能完成初始化。

type Backup

type Backup struct {
	ID         uint         `gorm:"primaryKey" json:"id"`
	UUID       string       `gorm:"type:char(36);uniqueIndex;not null" json:"uuid"`
	InstanceID uint         `gorm:"not null;index" json:"instanceId"`
	Name       string       `gorm:"type:varchar(128);not null" json:"name"`
	FilePath   string       `gorm:"type:varchar(512)" json:"filePath"`
	FileSizeMB float64      `gorm:"default:0" json:"fileSizeMb"`
	Type       BackupType   `gorm:"default:0" json:"type"`
	Mode       BackupMode   `gorm:"default:0" json:"mode"`
	Status     BackupStatus `gorm:"default:0" json:"status"`
	// ParentID 增量备份的父备份 ID,串成备份链;全量备份为 nil(FR-056)。
	ParentID *uint `gorm:"index" json:"parentId,omitempty"`
	// Manifest 本次备份完成后工作目录的完整文件清单(JSON 序列化的 manifest 数组)。
	// 作为下一次增量的基准与链式恢复的依据,由 Worker 返回、CP 持久化。
	Manifest string `gorm:"type:text" json:"-"`
	// StorageID 远程存储后端 ID;nil 表示存于节点本地数据根(FR-057)。
	StorageID *uint `gorm:"index" json:"storageId,omitempty"`
	// StorageKey 上传到远程后端的对象键;本地备份为空(FR-057)。
	StorageKey string `gorm:"type:varchar(512)" json:"storageKey,omitempty"`
	// Checksum 归档 tar.gz 的 SHA-256,用于恢复前完整性校验(FR-171)。
	Checksum string `gorm:"type:char(64)" json:"checksum,omitempty"`
	// ChecksumAlgo 校验算法,当前固定 sha256(FR-171)。
	ChecksumAlgo string         `gorm:"type:varchar(16)" json:"checksumAlgo,omitempty"`
	CreatedAt    time.Time      `json:"createdAt"`
	DeletedAt    gorm.DeletedAt `gorm:"index" json:"-"`
}

Backup 备份记录。

func (*Backup) BeforeCreate

func (b *Backup) BeforeCreate(tx *gorm.DB) error

BeforeCreate 创建前自动生成 UUID。

type BackupMode

type BackupMode int

BackupMode 备份模式:全量或增量(FR-056)。 与 BackupType(触发来源)正交:手动/定时备份均可为全量或增量。

const (
	BackupModeFull        BackupMode = 0 // 全量:打包工作目录全部文件
	BackupModeIncremental BackupMode = 1 // 增量:仅打包相对父备份变化的文件
)

type BackupStatus

type BackupStatus int

BackupStatus 备份状态。

const (
	BackupStatusPending    BackupStatus = 0 // 待处理
	BackupStatusInProgress BackupStatus = 1 // 进行中
	BackupStatusCompleted  BackupStatus = 2 // 完成
	BackupStatusFailed     BackupStatus = 3 // 失败
)

type BackupStorage

type BackupStorage struct {
	ID   uint   `gorm:"primaryKey" json:"id"`
	Name string `gorm:"type:varchar(128);not null" json:"name"`
	// ActiveNameKey 仅活跃记录保存名称,软删时置 NULL;SQLite/MySQL 均允许唯一索引中的多个 NULL。
	ActiveNameKey *string           `gorm:"type:varchar(128);uniqueIndex:uniq_backup_storage_active_name_key" json:"-"`
	Type          BackupStorageType `gorm:"type:varchar(32);not null" json:"type"`
	// Endpoint S3 endpoint / WebDAV 基地址 / SFTP host[:port]。
	Endpoint string `gorm:"type:varchar(512)" json:"endpoint"`
	// Bucket S3 bucket(其余类型忽略)。
	Bucket string `gorm:"type:varchar(255)" json:"bucket"`
	// Region S3 region(SigV4 用,缺省 us-east-1)。
	Region string `gorm:"type:varchar(64)" json:"region"`
	// Prefix 对象键/远程目录前缀,便于多实例/多平台共用一个后端。
	Prefix string `gorm:"type:varchar(255)" json:"prefix"`
	// AccessKeyEnv 访问密钥的环境变量引用(如 ${JIANMANAGER_BACKUP_S3_AK})。
	AccessKeyEnv string `gorm:"type:varchar(255)" json:"accessKeyEnv"`
	// SecretKeyEnv 密钥的环境变量引用(如 ${JIANMANAGER_BACKUP_S3_SK})。
	SecretKeyEnv string `gorm:"type:varchar(255)" json:"secretKeyEnv"`
	// UseSSL S3 是否启用 TLS。默认由应用层(router/service)设为 true;
	// 不用 gorm default:true,否则 GORM 会把显式 false(零值)覆盖回 true。
	UseSSL bool `json:"useSsl"`
	// LastTest* 保存已落库后端最近一次连通性测试结果;表单临时测试不写入。
	LastTestAt      *time.Time `json:"lastTestAt,omitempty"`
	LastTestOk      bool       `json:"lastTestOk"`
	LastTestMessage string     `gorm:"type:varchar(255)" json:"lastTestMessage"`
	// BackupCount/UsedBytes 为 FR-152 列表聚合展示字段,不落库。
	BackupCount int64          `gorm:"-" json:"backupCount"`
	UsedBytes   int64          `gorm:"-" json:"usedBytes"`
	CreatedAt   time.Time      `json:"createdAt"`
	UpdatedAt   time.Time      `json:"updatedAt"`
	DeletedAt   gorm.DeletedAt `gorm:"index" json:"-"`
}

BackupStorage 备份远程存储后端配置(FR-057)。

凭证字段(AccessKey/SecretKey)按 .claude/rules/config-files.md 规范以 ${ENV_VAR} 形式存储, 不落明文;下发 Worker 前由 service 从环境变量解析为明文(CP 拥有配置)。参见 ADR-011 对齐。

type BackupStorageType

type BackupStorageType string

BackupStorageType 备份远程存储后端类型(FR-057)。 与制品库 Asset.StorageBackend 的语义对齐:local 表示节点本地数据根,其余为外置后端。

const (
	// BackupStorageLocal 本地:备份仅留在节点数据根 var/backups(默认)。
	BackupStorageLocal BackupStorageType = "local"
	// BackupStorageS3 S3 兼容对象存储(AWS S3 / MinIO / 阿里 OSS 等)。
	BackupStorageS3 BackupStorageType = "s3"
	// BackupStorageSFTP SFTP/SSH 远程主机。
	BackupStorageSFTP BackupStorageType = "sftp"
	// BackupStorageWebDAV WebDAV 服务。
	BackupStorageWebDAV BackupStorageType = "webdav"
)

type BackupType

type BackupType int

BackupType 备份类型。

const (
	BackupTypeManual    BackupType = 0 // 手动
	BackupTypeScheduled BackupType = 1 // 定时
)

type BanRecord

type BanRecord struct {
	ID   uint   `gorm:"primaryKey" json:"id"`
	UUID string `gorm:"type:char(36);uniqueIndex;not null" json:"uuid"`
	// PlayerName 被封禁玩家名(大小写按客户端原样存储)。
	PlayerName string `gorm:"type:varchar(64);not null;index" json:"playerName"`
	// Reason 封禁原因(下发给 RCON ban 命令并入库留档)。
	Reason string `gorm:"type:varchar(512)" json:"reason"`
	// Scope 封禁范围:network / instance / global。
	Scope BanScope `gorm:"type:varchar(16);not null;default:global" json:"scope"`
	// ScopeID 范围目标 ID:network 时为 NetworkID,instance 时为 InstanceID,global 时为 0。
	ScopeID uint `gorm:"default:0" json:"scopeId"`
	// OperatorID 执行封禁的用户 ID(关联审计)。
	OperatorID uint `gorm:"not null;index" json:"operatorId"`
	// Active 是否仍被本平台视为生效;解封置 false,保留记录用于追溯。
	Active bool `gorm:"default:true;index" json:"active"`
	// CreatedAt 封禁时间。
	CreatedAt time.Time `json:"createdAt"`
	// UnbannedAt 解封时间;未解封为 nil。
	UnbannedAt *time.Time `json:"unbannedAt"`
	// Operator 关联用户,便于列表展示操作者用户名。
	Operator User `gorm:"foreignKey:OperatorID" json:"operator,omitempty"`
}

BanRecord 玩家封禁记录(FR-054)。

RCON 是无状态命令通道,封禁执行后服务端自身的 banned-players 文件才是权威来源; 本表是 JianManager 侧的可查询审计台账:谁、何时、为何、对哪个范围封禁了某玩家, 以及该封禁当前是否仍被本平台视为生效(解封时置 Active=false 而非删除,保留历史)。

func (*BanRecord) BeforeCreate

func (b *BanRecord) BeforeCreate(tx *gorm.DB) error

BeforeCreate 创建前自动生成 UUID。

type BanScope

type BanScope string

BanScope 封禁范围(FR-054)。

const (
	// BanScopeNetwork 群组级封禁:对一个 Network 内的全部后端子服下发封禁。
	BanScopeNetwork BanScope = "network"
	// BanScopeInstance 单实例封禁:仅对一个后端子服下发封禁。
	BanScopeInstance BanScope = "instance"
	// BanScopeGlobal 全局封禁:对当前操作可达的全部后端子服下发封禁。
	BanScopeGlobal BanScope = "global"
)

type Bot

type Bot struct {
	ID              uint      `gorm:"primaryKey" json:"id"`
	UUID            string    `gorm:"type:char(36);uniqueIndex;not null" json:"uuid"`
	InstanceID      uint      `gorm:"not null;index" json:"instanceId"`
	StressSessionID *uint     `gorm:"index" json:"stressSessionId,omitempty"`
	ExecutorNodeID  *uint     `gorm:"index;index:idx_bots_executor_generation,priority:1" json:"executorNodeId,omitempty"`
	LoadBatchID     *uint     `gorm:"index" json:"loadBatchId,omitempty"`
	Name            string    `gorm:"type:varchar(128);not null" json:"name"`
	Status          BotStatus `gorm:"type:varchar(32);default:pending" json:"status"`
	// DesiredState 是 CP 对 Bot 的期望运行态(running/stopped),与 runtime Status 分离(FR-365)。
	DesiredState           BotDesiredState `gorm:"type:varchar(16);not null;default:stopped;index" json:"desiredState"`
	WorkerEpoch            string          `gorm:"type:varchar(36);not null;default:''" json:"workerEpoch"`
	WorkerEpochGeneration  int64           `gorm:"not null;default:0" json:"workerEpochGeneration"`
	LastEventSeq           int64           `gorm:"not null;default:0" json:"lastEventSeq"`
	LastSeenAt             *time.Time      `json:"lastSeenAt,omitempty"`
	ConnectedAt            *time.Time      `json:"connectedAt,omitempty"`
	DesiredStateGeneration int64           `gorm:"not null;default:1;index:idx_bots_executor_generation,priority:2" json:"desiredStateGeneration"`
	ConfigHash             string          `gorm:"type:char(64);not null;default:''" json:"configHash"`
	// ReconnectCount 累计成功触发的自动重连次数,服务端恢复后不清零(FR-365)。
	ReconnectCount int    `gorm:"not null;default:0" json:"reconnectCount"`
	CohortKey      string `gorm:"type:varchar(64);not null;default:''" json:"cohortKey"`
	// LastError 最近一次委托 Worker 失败的原因(如 bot-worker 依赖未装、节点未连)。
	// 委托成功即清空;status=error 时前端据此显示可操作指引,杜绝「创建 201 但永远 pending 零反馈」。
	LastError string         `gorm:"type:text" json:"lastError,omitempty"`
	Config    string         `gorm:"type:text" json:"config"` // JSON: server, port, auth
	Behavior  string         `gorm:"type:varchar(64)" json:"behavior"`
	WorkerID  string         `gorm:"type:varchar(128)" json:"workerId"`
	CreatedAt time.Time      `json:"createdAt"`
	UpdatedAt time.Time      `json:"updatedAt"`
	DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`

	// Instance 表示被测目标实例和权限归属,不代表 Bot 实际执行位置。
	Instance Instance `gorm:"foreignKey:InstanceID" json:"-"`
	// ExecutorNode 是实际运行 Bot Worker 的节点;为空时兼容回退 Instance.NodeID。
	ExecutorNode *Node `gorm:"foreignKey:ExecutorNodeID;constraint:OnUpdate:CASCADE,OnDelete:RESTRICT" json:"executorNode,omitempty"`
	// LoadBatch 是分布式运行所属批次;删除批次时保留 Bot 并清空关联。
	LoadBatch *BotLoadBatch `gorm:"foreignKey:LoadBatchID;constraint:OnUpdate:CASCADE,OnDelete:SET NULL" json:"-"`
	// StressSession 所属压测会话;删除会话时保留 Bot,并清空关联。
	StressSession *BotStressSession `gorm:"foreignKey:StressSessionID;constraint:OnUpdate:CASCADE,OnDelete:SET NULL" json:"-"`
}

Bot Mineflayer Bot。

func (*Bot) BeforeCreate

func (b *Bot) BeforeCreate(tx *gorm.DB) error

BeforeCreate 创建前自动生成 UUID。

type BotDesiredState added in v0.20.0

type BotDesiredState string

BotDesiredState 是 CP 对 Bot 的期望状态(desired-state 真源,FR-365)。

const (
	BotDesiredRunning BotDesiredState = "running"
	BotDesiredStopped BotDesiredState = "stopped"
)

type BotLoadActionResult added in v0.19.0

type BotLoadActionResult struct {
	ID               uint                      `gorm:"primaryKey" json:"id"`
	StressSessionID  uint                      `gorm:"not null;index" json:"stressSessionId"`
	BotID            uint                      `gorm:"not null;index" json:"botId"`
	CohortKey        string                    `gorm:"type:varchar(64);not null" json:"cohortKey"`
	StepID           string                    `gorm:"type:varchar(64);not null" json:"stepId"`
	ActionRunID      string                    `gorm:"type:char(36);not null;uniqueIndex" json:"actionRunId"`
	Attempt          int                       `gorm:"not null" json:"attempt"`
	Status           BotLoadActionResultStatus `gorm:"type:varchar(16);not null;index" json:"status"`
	ErrorCode        string                    `gorm:"type:varchar(64)" json:"errorCode,omitempty"`
	Message          string                    `gorm:"type:text" json:"message,omitempty"`
	DurationMS       int64                     `gorm:"not null;default:0" json:"durationMs"`
	CorrelationToken string                    `gorm:"type:varchar(128);index" json:"correlationToken,omitempty"`
	StartedAt        time.Time                 `gorm:"not null" json:"startedAt"`
	EndedAt          *time.Time                `json:"endedAt,omitempty"`
	ResultJSON       string                    `gorm:"type:longtext" json:"resultJson,omitempty"`
	CreatedAt        time.Time                 `json:"createdAt"`
	UpdatedAt        time.Time                 `json:"updatedAt"`

	StressSession BotStressSession `gorm:"foreignKey:StressSessionID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"-"`
	Bot           Bot              `gorm:"foreignKey:BotID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"-"`
}

BotLoadActionResult 持久化场景动作开始与首个终态。

type BotLoadActionResultStatus added in v0.19.0

type BotLoadActionResultStatus string

BotLoadActionResultStatus 是场景动作结果状态。

const (
	BotLoadActionRunning   BotLoadActionResultStatus = "running"
	BotLoadActionSucceeded BotLoadActionResultStatus = "succeeded"
	BotLoadActionFailed    BotLoadActionResultStatus = "failed"
	BotLoadActionTimedOut  BotLoadActionResultStatus = "timed_out"
	BotLoadActionCancelled BotLoadActionResultStatus = "cancelled"
)

type BotLoadBatch added in v0.19.0

type BotLoadBatch struct {
	ID                uint              `gorm:"primaryKey" json:"id"`
	UUID              string            `gorm:"type:char(36);uniqueIndex;not null" json:"uuid"`
	StressSessionID   uint              `gorm:"not null;index;uniqueIndex:uniq_bot_load_batch_ordinal" json:"stressSessionId"`
	ExecutorNodeID    uint              `gorm:"not null;index" json:"executorNodeId"`
	Ordinal           int               `gorm:"not null;uniqueIndex:uniq_bot_load_batch_ordinal" json:"ordinal"`
	PlannedCount      int               `gorm:"not null" json:"plannedCount"`
	AcceptedCount     int               `gorm:"default:0" json:"acceptedCount"`
	ConnectedCount    int               `gorm:"default:0" json:"connectedCount"`
	FailedCount       int               `gorm:"default:0" json:"failedCount"`
	State             BotLoadBatchState `gorm:"type:varchar(16);default:planned;index" json:"state"`
	IdempotencyKey    string            `gorm:"type:varchar(128);uniqueIndex;not null" json:"idempotencyKey"`
	ConnectStartAt    time.Time         `json:"connectStartAt"`
	ConnectIntervalMS int               `gorm:"not null" json:"connectIntervalMs"`
	LastError         string            `gorm:"type:text" json:"lastError,omitempty"`
	StartedAt         *time.Time        `json:"startedAt,omitempty"`
	EndedAt           *time.Time        `json:"endedAt,omitempty"`
	CreatedAt         time.Time         `json:"createdAt"`
	UpdatedAt         time.Time         `json:"updatedAt"`

	StressSession BotStressSession `gorm:"foreignKey:StressSessionID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"-"`
	ExecutorNode  Node             `gorm:"foreignKey:ExecutorNodeID;constraint:OnUpdate:CASCADE,OnDelete:RESTRICT" json:"executorNode,omitempty"`
}

BotLoadBatch 记录一次压测运行在单个执行节点上的确定性分片。

func (*BotLoadBatch) BeforeCreate added in v0.19.0

func (b *BotLoadBatch) BeforeCreate(tx *gorm.DB) error

BeforeCreate 创建前自动生成批次 UUID。

type BotLoadBatchState added in v0.19.0

type BotLoadBatchState string

BotLoadBatchState 分布式 Bot 批次状态。

const (
	BotLoadBatchPlanned     BotLoadBatchState = "planned"
	BotLoadBatchDispatching BotLoadBatchState = "dispatching"
	BotLoadBatchRunning     BotLoadBatchState = "running"
	BotLoadBatchStopped     BotLoadBatchState = "stopped"
	BotLoadBatchFailed      BotLoadBatchState = "failed"
)

type BotLoadCommandCheckpoint added in v0.20.0

type BotLoadCommandCheckpoint struct {
	ID              uint                           `gorm:"primaryKey" json:"id"`
	StressSessionID uint                           `gorm:"not null;index" json:"stressSessionId"`
	BotID           *uint                          `gorm:"index" json:"botId,omitempty"`
	RunUUID         string                         `gorm:"type:char(36);not null;uniqueIndex:uniq_bot_load_cmd_ckpt_key" json:"runUuid"`
	BotUUID         string                         `gorm:"type:char(36);not null;uniqueIndex:uniq_bot_load_cmd_ckpt_key" json:"botUuid"`
	StepID          string                         `gorm:"type:varchar(64);not null;uniqueIndex:uniq_bot_load_cmd_ckpt_key" json:"stepId"`
	CommandID       string                         `gorm:"type:varchar(64);not null;uniqueIndex:uniq_bot_load_cmd_ckpt_key" json:"commandId"`
	Occurrence      int                            `gorm:"not null;uniqueIndex:uniq_bot_load_cmd_ckpt_key" json:"occurrence"`
	Generation      int64                          `gorm:"not null" json:"generation"`
	ScheduleRunID   string                         `gorm:"type:char(36);not null;index" json:"scheduleRunId"`
	ActionRunID     string                         `gorm:"type:char(36);not null;index" json:"actionRunId"`
	PlannedAtUnixMs *int64                         `json:"plannedAtUnixMs,omitempty"`
	SentAtUnixMs    *int64                         `json:"sentAtUnixMs,omitempty"`
	Attempt         int                            `gorm:"not null;default:0" json:"attempt"`
	Status          BotLoadCommandCheckpointStatus `gorm:"type:varchar(32);not null;index" json:"status"`
	ErrorCode       string                         `gorm:"type:varchar(64)" json:"errorCode,omitempty"`
	EndedAt         *time.Time                     `json:"endedAt,omitempty"`
	CreatedAt       time.Time                      `json:"createdAt"`
	UpdatedAt       time.Time                      `json:"updatedAt"`

	StressSession BotStressSession `gorm:"foreignKey:StressSessionID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"-"`
}

BotLoadCommandCheckpoint 是 FR-369 命令编排 occurrence 账本。

func (*BotLoadCommandCheckpoint) BeforeCreate added in v0.20.0

func (c *BotLoadCommandCheckpoint) BeforeCreate(tx *gorm.DB) error

BeforeCreate 自动填充生成时间;ID 由数据库生成。

type BotLoadCommandCheckpointStatus added in v0.20.0

type BotLoadCommandCheckpointStatus string

BotLoadCommandCheckpointStatus 是命令编排 checkpoint 状态机。

const (
	BotLoadCommandCheckpointPrepared  BotLoadCommandCheckpointStatus = "prepared"
	BotLoadCommandCheckpointScheduled BotLoadCommandCheckpointStatus = "scheduled"
	BotLoadCommandCheckpointSent      BotLoadCommandCheckpointStatus = "sent"
	BotLoadCommandCheckpointFailed    BotLoadCommandCheckpointStatus = "failed"
	BotLoadCommandCheckpointTimedOut  BotLoadCommandCheckpointStatus = "timed_out"
	BotLoadCommandCheckpointCancelled BotLoadCommandCheckpointStatus = "cancelled"
)

type BotLoadMetricSample added in v0.20.0

type BotLoadMetricSample struct {
	ID              uint      `gorm:"primaryKey" json:"id"`
	StressSessionID uint      `` /* 132-byte string literal not displayed */
	SampledAt       time.Time `gorm:"not null;uniqueIndex:uniq_bot_load_metric_sample,priority:2" json:"sampledAt"`
	StageIndex      int       `gorm:"not null;index:idx_bot_load_metric_stage,priority:2" json:"stageIndex"`
	CountsJSON      string    `gorm:"type:longtext;not null" json:"countsJson"`
	CommandJSON     string    `gorm:"type:longtext;not null" json:"commandJson"`
	BarrierJSON     string    `gorm:"type:longtext;not null" json:"barrierJson"`
	ExecutorJSON    string    `gorm:"type:longtext;not null" json:"executorJson"`
	LatencyJSON     string    `gorm:"type:longtext;not null" json:"latencyJson"`
	ErrorsJSON      string    `gorm:"type:longtext;not null" json:"errorsJson"`
	// TargetLegacyJSON 可选 legacy 指标;缺失时 null,不写 0。
	TargetLegacyJSON *string   `gorm:"type:longtext" json:"targetLegacyJson,omitempty"`
	CreatedAt        time.Time `json:"createdAt"`

	StressSession BotStressSession `gorm:"foreignKey:StressSessionID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"-"`
}

BotLoadMetricSample 是 FR-370 每运行 5 秒一行的聚合指标样本。

func (BotLoadMetricSample) TableName added in v0.20.0

func (BotLoadMetricSample) TableName() string

TableName 固定表名。

type BotLoadRunEvent added in v0.20.0

type BotLoadRunEvent struct {
	ID              uint                `gorm:"primaryKey" json:"id"`
	StressSessionID uint                `` /* 179-byte string literal not displayed */
	RunUUID         string              `gorm:"type:char(36);not null" json:"runUuid"`
	Type            BotLoadRunEventType `gorm:"type:varchar(32);not null;index:idx_bot_load_run_event_type,priority:2" json:"type"`
	OccurredAt      time.Time           `gorm:"not null;index:idx_bot_load_run_event_time,priority:2" json:"occurredAt"`
	StageIndex      *int                `json:"stageIndex,omitempty"`
	ActionRunID     *string             `gorm:"type:char(36);index:idx_bot_load_run_event_action,priority:2" json:"actionRunId,omitempty"`
	BotUUID         *string             `gorm:"type:char(36);index:idx_bot_load_run_event_bot,priority:2" json:"botUuid,omitempty"`
	ExecutorNodeID  *uint               `gorm:"index:idx_bot_load_run_event_executor,priority:2" json:"executorNodeId,omitempty"`
	StepID          *string             `gorm:"type:varchar(64);index:idx_bot_load_run_event_step,priority:2" json:"stepId,omitempty"`
	PayloadJSON     string              `gorm:"type:longtext;not null" json:"payloadJson"`
	LegacyJSON      *string             `gorm:"type:longtext" json:"legacyJson,omitempty"`
	CreatedAt       time.Time           `json:"createdAt"`

	StressSession BotStressSession `gorm:"foreignKey:StressSessionID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"-"`
}

BotLoadRunEvent 是 FR-370 运行历史事件(append-only,不随 metric TTL 删除)。

func (BotLoadRunEvent) TableName added in v0.20.0

func (BotLoadRunEvent) TableName() string

TableName 固定表名。

type BotLoadRunEventType added in v0.20.0

type BotLoadRunEventType string

BotLoadRunEventType 是 append-only 运行事件类型。

const (
	BotLoadRunEventRunState        BotLoadRunEventType = "run-state"
	BotLoadRunEventStage           BotLoadRunEventType = "stage"
	BotLoadRunEventBarrier         BotLoadRunEventType = "barrier"
	BotLoadRunEventScenarioAction  BotLoadRunEventType = "scenario-action"
	BotLoadRunEventCommandSchedule BotLoadRunEventType = "command-schedule"
	BotLoadRunEventCommandSend     BotLoadRunEventType = "command-send"
	BotLoadRunEventWorkerHealth    BotLoadRunEventType = "worker-health"
	BotLoadRunEventExecutorCrash   BotLoadRunEventType = "executor-crash"
	BotLoadRunEventSafetyStop      BotLoadRunEventType = "safety-stop"
	BotLoadRunEventReportReady     BotLoadRunEventType = "report-ready"
)

type BotLoadRunState added in v0.20.0

type BotLoadRunState string

BotLoadRunState 是 FR-370 运行状态机枚举。

const (
	BotLoadRunPending      BotLoadRunState = "pending"
	BotLoadRunPreflighting BotLoadRunState = "preflighting"
	BotLoadRunReady        BotLoadRunState = "ready"
	BotLoadRunStarting     BotLoadRunState = "starting"
	BotLoadRunRunning      BotLoadRunState = "running"
	BotLoadRunDegraded     BotLoadRunState = "degraded"
	BotLoadRunStopping     BotLoadRunState = "stopping"
	BotLoadRunCancelling   BotLoadRunState = "cancelling"
	BotLoadRunCompleted    BotLoadRunState = "completed"
	BotLoadRunFailed       BotLoadRunState = "failed"
	BotLoadRunCancelled    BotLoadRunState = "cancelled"
)

type BotLoadTemplate added in v0.20.0

type BotLoadTemplate struct {
	ID        uint   `gorm:"primaryKey" json:"id"`
	UUID      string `gorm:"type:char(36);uniqueIndex;not null" json:"uuid"`
	CreatedBy uint   `gorm:"not null;index;uniqueIndex:uniq_bot_load_tpl_active_name,priority:1" json:"createdBy"`
	// ActiveNameKey 为 trim 后名称 UTF-8 的 SHA-256 hex;软删时置 null 以允许复用名称。
	ActiveNameKey   *string        `gorm:"type:char(64);uniqueIndex:uniq_bot_load_tpl_active_name,priority:2" json:"-"`
	Name            string         `gorm:"type:varchar(128);not null" json:"name"`
	Description     string         `gorm:"type:text;not null" json:"description"`
	CommandSchedule string         `gorm:"type:longtext;not null" json:"commandSchedule"`
	LoadProfile     string         `gorm:"type:longtext;not null" json:"loadProfile"`
	Thresholds      string         `gorm:"type:longtext;not null" json:"thresholds"`
	Tags            string         `gorm:"type:longtext;not null" json:"tags"`
	CreatedAt       time.Time      `json:"createdAt"`
	UpdatedAt       time.Time      `json:"updatedAt"`
	DeletedAt       gorm.DeletedAt `gorm:"index" json:"-"`

	Creator User `gorm:"foreignKey:CreatedBy;constraint:OnUpdate:CASCADE,OnDelete:RESTRICT" json:"-"`
}

BotLoadTemplate 是 FR-370 命令压测可复用模板(个人所有权,不绑定目标实例)。

func (*BotLoadTemplate) BeforeCreate added in v0.20.0

func (t *BotLoadTemplate) BeforeCreate(tx *gorm.DB) error

BeforeCreate 创建前自动生成 UUID。

func (BotLoadTemplate) TableName added in v0.20.0

func (BotLoadTemplate) TableName() string

TableName 固定表名。

type BotLoadVerdict added in v0.20.0

type BotLoadVerdict string

BotLoadVerdict 是运行判定结果。

const (
	BotLoadVerdictPending BotLoadVerdict = "pending"
	BotLoadVerdictPassed  BotLoadVerdict = "passed"
	BotLoadVerdictFailed  BotLoadVerdict = "failed"
	BotLoadVerdictAborted BotLoadVerdict = "aborted"
)

type BotStatus

type BotStatus string

BotStatus Bot 运行时状态(runtime 真源由 Worker/Bot Worker 上报)。

const (
	BotStatusPending      BotStatus = "pending"
	BotStatusConnecting   BotStatus = "connecting"
	BotStatusConnected    BotStatus = "connected"
	BotStatusDisconnected BotStatus = "disconnected"
	BotStatusError        BotStatus = "error"
	BotStatusStopped      BotStatus = "stopped"
)

type BotStressSession

type BotStressSession struct {
	ID                   uint                   `gorm:"primaryKey" json:"id"`
	UUID                 string                 `gorm:"type:char(36);uniqueIndex;not null" json:"uuid"`
	InstanceID           uint                   `gorm:"not null;index" json:"instanceId"`
	Name                 string                 `gorm:"type:varchar(128);not null" json:"name"`
	NamePrefix           string                 `gorm:"type:varchar(64);not null" json:"namePrefix"`
	Status               BotStressSessionStatus `gorm:"type:varchar(32);default:pending;index" json:"status"`
	BotCount             int                    `gorm:"not null" json:"botCount"`
	Behavior             string                 `gorm:"type:varchar(64)" json:"behavior"`
	Config               string                 `gorm:"type:text" json:"config"`
	OrchestrationYAML    string                 `gorm:"type:text" json:"orchestrationYaml,omitempty"`
	OrchestrationSummary string                 `gorm:"type:text" json:"orchestrationSummary,omitempty"`
	ScenarioSnapshot     string                 `gorm:"type:longtext" json:"scenarioSnapshot,omitempty"`
	CommandScheduleSnap  string                 `gorm:"type:longtext" json:"commandScheduleSnapshot,omitempty"`
	AllocationPlan       string                 `gorm:"type:text" json:"allocationPlan,omitempty"`
	SchemaVersion        int                    `gorm:"type:smallint;not null;default:1;index" json:"schemaVersion"`
	// FR-370 V2 专属列:schemaVersion=1 历史行允许 null,schemaVersion=2 由 service 强制完整。
	TemplateID     *uint            `gorm:"index" json:"templateId,omitempty"`
	LoadProfile    string           `gorm:"type:longtext" json:"loadProfile,omitempty"`
	Thresholds     string           `gorm:"type:longtext" json:"thresholds,omitempty"`
	RunState       *BotLoadRunState `gorm:"type:varchar(32);index" json:"runState,omitempty"`
	CurrentStage   *int             `json:"currentStage,omitempty"`
	Verdict        *BotLoadVerdict  `gorm:"type:varchar(16);index" json:"verdict,omitempty"`
	MaxStableBots  *int             `json:"maxStableBots,omitempty"`
	FailureSummary string           `gorm:"type:longtext" json:"failureSummary,omitempty"`
	ReportSummary  string           `gorm:"type:longtext" json:"reportSummary,omitempty"`
	Succeeded      int              `gorm:"default:0" json:"succeeded"`
	Failed         int              `gorm:"default:0" json:"failed"`
	LastError      string           `gorm:"type:text" json:"lastError,omitempty"`
	StartedAt      *time.Time       `json:"startedAt,omitempty"`
	EndedAt        *time.Time       `json:"endedAt,omitempty"`
	CreatedAt      time.Time        `json:"createdAt"`
	UpdatedAt      time.Time        `json:"updatedAt"`
	DeletedAt      gorm.DeletedAt   `gorm:"index" json:"-"`

	Instance Instance         `gorm:"foreignKey:InstanceID" json:"instance,omitempty"`
	Template *BotLoadTemplate `gorm:"foreignKey:TemplateID;constraint:OnUpdate:CASCADE,OnDelete:SET NULL" json:"-"`
}

BotStressSession Bot 压测会话。

func (*BotStressSession) BeforeCreate

func (s *BotStressSession) BeforeCreate(tx *gorm.DB) error

BeforeCreate 创建前自动生成 UUID。

type BotStressSessionStatus

type BotStressSessionStatus string

BotStressSessionStatus 压测会话状态(V1 兼容列;V2 与 run_state 同事务映射)。

const (
	BotStressSessionPending BotStressSessionStatus = "pending"
	BotStressSessionRunning BotStressSessionStatus = "running"
	BotStressSessionStopped BotStressSessionStatus = "stopped"
	BotStressSessionError   BotStressSessionStatus = "error"
)

type BusinessEvent

type BusinessEvent struct {
	ID uint `gorm:"primaryKey" json:"id"`
	// Domain 业务域命名空间(economy/inventory…);与来源 scope、DedupKey 组成唯一去重键。
	Domain string `gorm:"type:varchar(32);not null;uniqueIndex:idx_be_scope_dedup,priority:1;index:idx_be_domain_time,priority:1" json:"domain"`
	// DedupKey 业务事件去重锚点(经济域为 mce ledgerId,只有 node→zone 内唯一)。
	DedupKey string `gorm:"column:dedup_key;type:varchar(128);not null;uniqueIndex:idx_be_scope_dedup,priority:4" json:"dedupKey"`
	// Action 业务事件子类型(economy_change…),供下游分流/展示。
	Action string `gorm:"type:varchar(64);not null" json:"action"`
	// NodeUUID 事件来源节点(经济多区/多节点聚合的 node→zone 维度起点)。
	NodeUUID string `gorm:"column:node_uuid;type:varchar(64);not null;uniqueIndex:idx_be_scope_dedup,priority:2;index:idx_be_node" json:"nodeUuid"`
	// ZoneID 经济事件的 mce 区;其它业务域为空串。账本 ID 只在 node→zone 内去重。
	ZoneID string `gorm:"column:zone_id;type:varchar(64);not null;default:'';uniqueIndex:idx_be_scope_dedup,priority:3" json:"zoneId,omitempty"`
	// InstanceUUID 事件来源实例(探针所在子服实例)。
	InstanceUUID string `gorm:"column:instance_uuid;type:varchar(64);index:idx_be_instance" json:"instanceUuid"`
	// Operator 操作者身份透传位(FR-121 业务写横切硬化时回填"哪个管理员/为什么";自发事件为空)。
	Operator string `gorm:"type:varchar(128)" json:"operator,omitempty"`
	// PayloadJSON 业务信封原始载荷 JSON(CP 不解析语义,原样留存供下游/审计;经济域同时落结构化专表)。
	PayloadJSON string `gorm:"column:payload_json;type:text" json:"payloadJson"`
	// OccurredAt 业务侧事件发生时间(epoch 毫秒,来自探针信封;0 表示未携带)。
	OccurredAt int64 `gorm:"column:occurred_at;index:idx_be_domain_time,priority:2" json:"occurredAt"`
	// CreatedAt CP 落库时间。
	CreatedAt time.Time `json:"createdAt"`
}

BusinessEvent 是 JBIS 通用业务事件信封表(插件无关汇聚底座,FR-116 底座 / FR-122,见 ADR-028)。

探针经反向 WS 桥上报的业务域事件(economy/inventory…)一律按本表落库:CP **插件无关**,只认 domain/action/payload 信封 + dedupKey,不理解具体业务语义。按 (Domain, NodeUUID, ZoneID, DedupKey) 唯一去重应对桥的 **至少一次投递**与跨节点重试(同键重发 insert-or-ignore,不重复计数)。新增业务域**无需改表**。

数据所有权(架构不变量):JM 只存汇聚镜像 + 操作审计,业务真源仍在各插件存储;本表是"汇聚镜像"的通用底座, 高价值域(经济)另有结构化专表(EconomyBalanceMirror / EconomyLedgerEntry)供高效查询与对账。

type ClientChannel

type ClientChannel struct {
	ID uint `gorm:"primaryKey" json:"id"`
	// ChannelID 频道 slug:对外标识与端点路径段,全局唯一。约束 `^[a-z0-9][a-z0-9-]{1,63}$`。
	ChannelID string `gorm:"column:channel_id;type:varchar(64);uniqueIndex;not null" json:"channelId"`
	// Name 展示名。
	Name string `gorm:"type:varchar(128);not null" json:"name"`
	// Description 描述,可空。
	Description string `gorm:"type:varchar(512)" json:"description"`
	// CurrentVersion 当前 latest 版本指针占位;0=未发布。本 FR 仅建字段,编排见 FR-088。
	CurrentVersion int `gorm:"default:0;not null" json:"currentVersion"`
	// Deprecated: PinnedCoreVersion 原为频道 pin 的 updater-core 版本号(FR-193 初版,已随反转废弃,见 ADR-045 改写)。
	// updater-core 现由 CP 内嵌默认版本自动驱动 manifest agent.core,运营不再 pin/管理。保留此列(加性、默认 0)
	// 仅为兼容存量库、避免无谓迁移;不再被任何运营端点写入、不参与 manifest 生成。
	PinnedCoreVersion int `gorm:"default:0;not null" json:"-"`
	// SelectedCoreSHA256 频道选定的 updater-core 归档制品 sha256(FR-259,见 updater-arch-simplification spec §D)。
	// 指向 type=client-updater-core 的 Asset.SHA256;空=未选定(coreEndpoint 回退最新归档版本)。
	// 运营经 PUT /client-channels/:id/updater-core/selected 切换,客户端下次启动查 coreEndpoint 即用选定版本。
	SelectedCoreSHA256 string `gorm:"column:selected_core_sha256;type:char(64)" json:"-"`
	// SelectedCoreVersion 是频道级 core 分发版本号,每次切换选定 SHA 时递增。
	// 楔子只按 version 递增决定是否下载,所以选回旧 SHA 回滚时不能返回旧 Asset.Version。
	SelectedCoreVersion  int            `gorm:"column:selected_core_version;default:0;not null" json:"-"`
	ProtectionMode       string         `gorm:"column:protection_mode;type:varchar(32);default:normal;not null" json:"protectionMode"`
	ProtectionPolicyJSON string         `gorm:"column:protection_policy_json;type:text" json:"-"`
	ProtectionUpdatedAt  *time.Time     `gorm:"column:protection_updated_at" json:"protectionUpdatedAt"`
	CreatedAt            time.Time      `json:"createdAt"`
	UpdatedAt            time.Time      `json:"updatedAt"`
	DeletedAt            gorm.DeletedAt `gorm:"index" json:"-"`
}

ClientChannel 客户端分发频道:每服/每整合包一个,作为 manifest/制品端点的对外标识与路由键。 ChannelID 为运营者指定的 slug(URL 段),CurrentVersion 为 latest 版本指针占位(FR-088 编排)。 参见 ADR-022、FR-086。

type ClientDistDaily

type ClientDistDaily struct {
	ID uint `gorm:"primaryKey" json:"id"`
	// Day UTC 日期 YYYY-MM-DD。与 channel/version/kind 组成唯一键。
	Day string `gorm:"type:char(10);not null;uniqueIndex:idx_cdd_day_chan_ver_kind" json:"day"`
	// ChannelID 频道 slug。
	ChannelID string `gorm:"column:channel_id;type:varchar(64);not null;uniqueIndex:idx_cdd_day_chan_ver_kind" json:"channelId"`
	// Version manifest 版本(artifact 聚合为 0)。
	Version int `gorm:"not null;uniqueIndex:idx_cdd_day_chan_ver_kind" json:"version"`
	// Kind manifest | artifact。
	Kind string `gorm:"type:varchar(16);not null;uniqueIndex:idx_cdd_day_chan_ver_kind" json:"kind"`
	// Requests 当日该维度请求数。
	Requests int64 `gorm:"default:0;not null" json:"requests"`
	// Bytes 当日该维度总字节数。
	Bytes int64 `gorm:"default:0;not null" json:"bytes"`
}

ClientDistDaily 客户端分发按日聚合(FR-093)。**长保留**,写时增量 upsert;供下载量趋势 + 版本分布(FR-095)。

type ClientDistEvent

type ClientDistEvent struct {
	ID uint `gorm:"primaryKey" json:"id"`
	// ChannelID 频道 slug。
	ChannelID string `gorm:"column:channel_id;type:varchar(64);not null;index:idx_cde_channel_time" json:"channelId"`
	// MachineID 客户端机器码(不可信)。
	MachineID string `gorm:"column:machine_id;type:varchar(128);index" json:"machineId"`
	// IP 来源 IP(限流/分布主维度)。
	IP string `gorm:"type:varchar(64);index" json:"ip"`
	// Kind 事件类型:manifest | artifact。
	Kind string `gorm:"type:varchar(16);not null" json:"kind"`
	// Version manifest 拉取的版本号(artifact 事件为 0,制品跨版本共享)。
	Version int `gorm:"default:0;not null" json:"version"`
	// ArtifactSHA 制品 sha256(仅 artifact 事件)。
	ArtifactSHA string `gorm:"column:artifact_sha;type:char(64)" json:"artifactSha"`
	// Bytes 响应字节数。
	Bytes int64 `gorm:"default:0;not null" json:"bytes"`
	// Status HTTP 状态码(200/206/304/404…)。
	Status int `gorm:"default:0;not null" json:"status"`
	// ErrCode 语义错误码(FR-249)。成功事件为空;失败事件填与响应 error 字段一致的码
	// (INVALID_CLIENT_KEY/NO_LATEST_VERSION/ARTIFACT_NOT_FOUND/SIGN_KEY_NOT_CONFIGURED/CHANNEL_NOT_FOUND/INTERNAL_ERROR)。
	ErrCode string `gorm:"column:err_code;type:varchar(48);index" json:"errCode"`
	// ErrReason 可读错误原因(FR-265)。
	ErrReason string `gorm:"column:err_reason;type:varchar(255)" json:"errReason"`
	// Method HTTP 方法(FR-265 日志详情)。
	Method string `gorm:"type:varchar(8)" json:"method"`
	// Path 请求路径(含 query,FR-265 日志详情)。
	Path string `gorm:"type:varchar(1024)" json:"path"`
	// RequestBody 请求体预览(FR-265 排障详情,最多保存短文本;凭证类字段不写入)。
	RequestBody string `gorm:"column:request_body;type:text" json:"-"`
	// ResponseBody 响应体预览(FR-265 排障详情,最多保存短文本;二进制响应不写入)。
	ResponseBody string `gorm:"column:response_body;type:text" json:"-"`
	// RequestHeadersJSON 请求头 JSON(FR-265)。凭证类头不落库。
	RequestHeadersJSON string `gorm:"column:request_headers_json;type:text" json:"-"`
	// ResponseHeadersJSON 响应头 JSON(FR-265)。凭证类头不落库。
	ResponseHeadersJSON string `gorm:"column:response_headers_json;type:text" json:"-"`
	// ETag 响应 ETag 快捷列(FR-265)。
	ETag string `gorm:"column:etag;type:varchar(128)" json:"etag"`
	// DurationMs 处理耗时(毫秒)。
	DurationMs int64 `gorm:"column:duration_ms;default:0;not null" json:"durationMs"`
	// CreatedAt 事件时间(清理基准)。
	CreatedAt time.Time `gorm:"index:idx_cde_channel_time" json:"createdAt"`
}

ClientDistEvent 客户端分发拉取/下载明细事件(FR-093,见 ADR-023)。 **短保留 + 滚动清理**(数据量治理);供按 IP/机器码/频道/版本/时间检索与近窗去重分布。 机器码/IP 客户端可伪造、不可信,仅追踪统计。

type ClientDistSnapshot

type ClientDistSnapshot struct {
	ID uint `gorm:"primaryKey" json:"id"`
	// ChannelID 频道 slug;与 BucketTS 组成唯一键。空串=跨频道/制品共享桶。
	ChannelID string `gorm:"column:channel_id;type:varchar(64);not null;default:'';uniqueIndex:idx_cds_channel_bucket,priority:1" json:"channelId"`
	// BucketTS 小时桶起点(UTC,整小时对齐)。与 ChannelID 唯一;单列索引供区间扫描/TTL 清理。
	BucketTS time.Time `gorm:"not null;uniqueIndex:idx_cds_channel_bucket,priority:2;index:idx_cds_bucket" json:"bucketTs"`

	// 拉取侧(源 client_dist_event)。
	ManifestPulls int64 `gorm:"default:0;not null" json:"manifestPulls"` // 桶内 manifest 拉取次数
	ArtifactPulls int64 `gorm:"default:0;not null" json:"artifactPulls"` // 桶内制品拉取次数
	DownloadBytes int64 `gorm:"default:0;not null" json:"downloadBytes"` // 桶内总响应字节
	// ActiveMachines 桶内 machineId 精确去重计数(排空串)。machineId 不可信(ADR-023),仅统计近似;
	// 跨桶不可简单求和(同客户端跨小时会重复),跨区间去重口径见 ADR-049 §4。
	ActiveMachines int64 `gorm:"default:0;not null" json:"activeMachines"`
	// VersionDist 版本分布 JSON map[version]count(manifest 拉取按 version 计数)。
	VersionDist string `gorm:"column:version_dist;type:text" json:"-"`
	// PlatformDist 平台分布 JSON map[os]count(来源遥测 os 字段)。
	PlatformDist string `gorm:"column:platform_dist;type:text" json:"-"`

	// 更新侧(源 client_telemetry,按 result 分桶计数)。
	UpdateTotal      int64 `gorm:"default:0;not null" json:"updateTotal"`
	UpdateSuccess    int64 `gorm:"default:0;not null" json:"updateSuccess"`
	UpdateFailStatic int64 `gorm:"column:update_fail_static;default:0;not null" json:"updateFailStatic"` // 断网兜底启动
	UpdateRolledBack int64 `gorm:"column:update_rolled_back;default:0;not null" json:"updateRolledBack"`
	UpdateError      int64 `gorm:"default:0;not null" json:"updateError"`
	// LagDist 版本滞后分布 JSON map[lag]count(current_version - toVersion,下界 0;遥测 toVersion>0 时计)。
	LagDist string `gorm:"column:lag_dist;type:text" json:"-"`

	CreatedAt time.Time `json:"createdAt"`
	UpdatedAt time.Time `json:"updatedAt"`
}

ClientDistSnapshot 客户端分发观测时序快照:每「频道 × 小时桶」一行(FR-217,见 ADR-049)。

由后台任务把 client_dist_event(FR-093)+ client_telemetry(FR-094)离线卷积而来, 与玩家热路径的写时聚合(client_dist_daily/client_telemetry_daily)解耦——观测富维度交给离线卷积, 热路径零新增负担。ChannelID 可为空串(制品端点跨频道共享、明细 channel 可空 → 归入空频道桶; 查询「总」时含之)。分布维度以 JSON map 存 TEXT 列,免随版本/平台/滞后基数增长改表结构。

type ClientIPRule

type ClientIPRule struct {
	ID uint `gorm:"primaryKey" json:"id"`
	// CIDR IP 或 CIDR(单 IP 视作 /32、/128)。
	CIDR string `gorm:"column:cidr;type:varchar(64);not null" json:"cidr"`
	// Mode deny | allow。
	Mode string `gorm:"type:varchar(8);not null" json:"mode"`
	// Note 规则备注。
	Note string `gorm:"type:varchar(255)" json:"note"`
	// CreatedBy 创建者用户 ID(审计辅助)。
	CreatedBy uint      `gorm:"default:0;not null" json:"createdBy"`
	CreatedAt time.Time `json:"createdAt"`
}

ClientIPRule 客户端分发端点 IP 防护规则(FR-096,见 ADR-023)。运行时可改、入审计。

mode=deny:匹配即拒(黑名单,deny 始终优先);mode=allow:存在任一 allow 规则即进入**白名单模式** (仅匹配 allow 的 IP 放行)。CIDR 支持单 IP(视作 /32、/128)或网段。

type ClientMachine

type ClientMachine struct {
	ID uint `gorm:"primaryKey" json:"id"`
	// ChannelID 所属频道 slug。与 MachineID 组成唯一键。
	ChannelID string `gorm:"column:channel_id;type:varchar(64);not null;uniqueIndex:idx_client_machines_channel_machine" json:"channelId"`
	// MachineID 客户端机器码(SHA-256 十六进制,不可逆)。库内仅存哈希。
	MachineID string `gorm:"column:machine_id;type:varchar(128);not null;uniqueIndex:idx_client_machines_channel_machine" json:"machineId"`
	// HitCount 该机器码在本频道的累计拉取命中次数(弱一致统计)。
	HitCount int64 `gorm:"default:0;not null" json:"hitCount"`
	// FirstSeen 首次登记时间。
	FirstSeen time.Time `json:"firstSeen"`
	// LastSeen 最近一次登记时间。
	LastSeen time.Time `json:"lastSeen"`
}

ClientMachine 客户端机器码登记(FR-092,见 ADR-023)。

机器码由客户端生成、**不可信**——仅作统计与**辅助**限流维度,**不作信任/授权依据**(限流以 IP 为主,FR-096)。 每频道每机器码一行,记首/末见与命中计数;按机器码维度的统计看板归 FR-095、全链路追踪/留存归 FR-093。

type ClientProtectionAction

type ClientProtectionAction struct {
	ID          uint       `gorm:"primaryKey" json:"id"`
	TargetType  string     `gorm:"type:varchar(32);not null;index" json:"targetType"`
	TargetValue string     `gorm:"column:target_value;type:varchar(128);default:'';not null;index" json:"targetValue"`
	ChannelID   string     `gorm:"column:channel_id;type:varchar(64);index" json:"channelId"`
	Action      string     `gorm:"type:varchar(64);not null;index" json:"action"`
	Status      string     `gorm:"type:varchar(16);default:active;not null;index" json:"status"`
	PolicyJSON  string     `gorm:"column:policy_json;type:text" json:"-"`
	Reason      string     `gorm:"type:varchar(512)" json:"reason"`
	Auto        bool       `gorm:"default:false;not null" json:"auto"`
	ExpiresAt   *time.Time `gorm:"index" json:"expiresAt"`
	CreatedBy   uint       `gorm:"default:0;not null" json:"createdBy"`
	CreatedAt   time.Time  `json:"createdAt"`
	UpdatedAt   time.Time  `json:"updatedAt"`
	CanceledAt  *time.Time `json:"canceledAt"`
}

type ClientPullKey

type ClientPullKey struct {
	ID uint `gorm:"primaryKey" json:"id"`
	// ChannelID 所属频道 slug(随频道删除级联清理)。
	ChannelID string `gorm:"column:channel_id;type:varchar(64);index;not null" json:"channelId"`
	// Name 密钥名(识别用途,如「正式包」「灰度」)。
	Name string `gorm:"type:varchar(128);not null" json:"name"`
	// KeyHash 拉取密钥明文的 SHA-256 十六进制小写。**鉴权依据**,库内不存明文。
	KeyHash string `gorm:"column:key_hash;type:char(64);uniqueIndex;not null" json:"-"`
	// KeyEnc 拉取密钥明文的 AES-256-GCM 可逆加密副本(base64(nonce‖密文);FR-192,见 ADR-044)。
	// 仅供平台管理员经 reveal 端点查看明文,不参与鉴权、绝不序列化给客户端。空=不可查看
	// (存量老密钥 / 创建时未配 JIANMANAGER_CLIENT_KEY_ENC_SECRET 的密钥)。加性列、默认空。
	// 密钥发出后永久使用;管理员可经编辑端点改值(重算 KeyHash + 重写 KeyEnc),不再提供轮换。
	KeyEnc string `gorm:"column:key_enc;type:text" json:"-"`
	// KeyPrefix 明文前缀(如 jmck_ab12),仅供列表识别,不足以重建密钥。
	KeyPrefix string `gorm:"column:key_prefix;type:varchar(16);not null" json:"keyPrefix"`
	// Revealable 是否可查看明文(派生字段,不落库;= KeyEnc 非空,FR-192)。
	// 供前端对存量「只有哈希」的老密钥禁用「查看」并提示;不泄露密文本身。
	Revealable bool `gorm:"-" json:"revealable"`
	// Revoked 吊销标记;true 即鉴权失败。
	Revoked bool `gorm:"default:false;index;not null" json:"revoked"`
	// ExpiresAt 可选过期时间;到期即鉴权失败。
	ExpiresAt *time.Time `json:"expiresAt"`
	// LastUsedAt 最近一次鉴权命中时间(统计用,弱一致)。
	LastUsedAt         *time.Time `json:"lastUsedAt"`
	SecurityState      string     `gorm:"column:security_state;type:varchar(32);default:normal;not null" json:"securityState"`
	ThrottlePolicyJSON string     `gorm:"column:throttle_policy_json;type:text" json:"-"`
	SecurityNote       string     `gorm:"column:security_note;type:varchar(512)" json:"securityNote"`
	SecurityUpdatedAt  *time.Time `gorm:"column:security_updated_at" json:"securityUpdatedAt"`
	CreatedAt          time.Time  `json:"createdAt"`
	// RevokedAt 吊销时间。
	RevokedAt *time.Time `json:"revokedAt"`
}

ClientPullKey 频道拉取密钥:玩家侧 updater 拉 manifest/制品时经请求头携带。 半公开凭据(随整包分发会泄露)——仅作鉴权路由 + 吊销,不作内容可信依据(内容可信靠 manifest 签名)。 鉴权只用 KeyHash(SHA-256)比对;另存 AES-256-GCM 可逆加密副本 KeyEnc(FR-192)供管理员查看明文。 参见 ADR-022 §1、ADR-044(拉取密钥可逆加密 + 管理员可查看,修订 ADR-022 决策①的「只存哈希」)。

type ClientRuntimeState

type ClientRuntimeState struct {
	ID               uint       `gorm:"primaryKey" json:"id"`
	ChannelID        string     `gorm:"column:channel_id;type:varchar(64);not null;uniqueIndex:idx_client_runtime_identity;index" json:"channelId"`
	MachineID        string     `gorm:"column:machine_id;type:varchar(128);not null;uniqueIndex:idx_client_runtime_identity;index" json:"machineId"`
	PlayerName       string     `gorm:"column:player_name;type:varchar(32);index" json:"playerName"`
	IP               string     `gorm:"type:varchar(64);index" json:"ip"`
	Platform         string     `gorm:"type:varchar(32);index" json:"platform"`
	JavaVersion      string     `gorm:"column:java_version;type:varchar(32)" json:"javaVersion"`
	Launcher         string     `gorm:"type:varchar(32);index" json:"launcher"`
	CoreVersion      string     `gorm:"column:core_version;type:varchar(64);index" json:"coreVersion"`
	LocalVersion     int        `gorm:"column:local_version;default:0;not null;index" json:"localVersion"`
	FirstSeenAt      time.Time  `gorm:"column:first_seen_at;index" json:"firstSeenAt"`
	LastHeartbeatAt  time.Time  `gorm:"column:last_heartbeat_at;index" json:"lastHeartbeatAt"`
	LastUpdateResult string     `gorm:"column:last_update_result;type:varchar(16);index" json:"lastUpdateResult"`
	LastUpdateAt     *time.Time `gorm:"column:last_update_at;index" json:"lastUpdateAt"`
	CreatedAt        time.Time  `json:"createdAt"`
	UpdatedAt        time.Time  `json:"updatedAt"`
}

ClientRuntimeState 客户端运行态最新快照(FR-265)。 按 channel_id + machine_id upsert,仅保存最新启动心跳;不作为可信身份,仅用于观测统计。

type ClientSecurityCounter

type ClientSecurityCounter struct {
	ID        uint      `gorm:"primaryKey" json:"id"`
	Scope     string    `gorm:"type:varchar(32);not null;uniqueIndex:idx_client_security_counter_bucket" json:"scope"`
	Key       string    `gorm:"type:varchar(128);not null;uniqueIndex:idx_client_security_counter_bucket" json:"key"`
	Bucket    string    `gorm:"type:varchar(32);not null;uniqueIndex:idx_client_security_counter_bucket" json:"bucket"`
	Value     int64     `gorm:"default:0;not null" json:"value"`
	UpdatedAt time.Time `json:"updatedAt"`
}

type ClientSecurityGroup

type ClientSecurityGroup struct {
	ID               uint      `gorm:"primaryKey" json:"id"`
	Name             string    `gorm:"type:varchar(128);not null;uniqueIndex" json:"name"`
	Kind             string    `gorm:"type:varchar(16);default:manual;not null" json:"kind"`
	TargetType       string    `gorm:"column:target_type;type:varchar(32);default:'';not null" json:"targetType"`
	RuleJSON         string    `gorm:"column:rule_json;type:text" json:"-"`
	ActionPolicyJSON string    `gorm:"column:action_policy_json;type:text" json:"-"`
	Enabled          bool      `gorm:"default:true;not null" json:"enabled"`
	CreatedBy        uint      `gorm:"default:0;not null" json:"createdBy"`
	CreatedAt        time.Time `json:"createdAt"`
	UpdatedAt        time.Time `json:"updatedAt"`
}

type ClientSecurityHello

type ClientSecurityHello struct {
	ID          uint      `gorm:"primaryKey" json:"id"`
	ChannelID   string    `gorm:"column:channel_id;type:varchar(64);index" json:"channelId"`
	MachineID   string    `gorm:"column:machine_id;type:varchar(128);index" json:"machineId"`
	InstallID   string    `gorm:"column:install_id;type:varchar(128);index" json:"installId"`
	PlayerName  string    `gorm:"type:varchar(64);index" json:"playerName"`
	Accepted    bool      `gorm:"default:false;not null" json:"accepted"`
	ErrCode     string    `gorm:"column:err_code;type:varchar(64);index" json:"errCode"`
	IP          string    `gorm:"type:varchar(64);index" json:"ip"`
	KeyID       uint      `gorm:"column:key_id;index" json:"keyId"`
	KeyPrefix   string    `gorm:"column:key_prefix;type:varchar(16)" json:"keyPrefix"`
	UserAgent   string    `gorm:"type:varchar(255)" json:"userAgent"`
	PayloadJSON string    `gorm:"column:payload_json;type:text" json:"-"`
	CreatedAt   time.Time `gorm:"index" json:"createdAt"`
}

type ClientSecurityProfile

type ClientSecurityProfile struct {
	ID              uint      `gorm:"primaryKey" json:"id"`
	ChannelID       string    `gorm:"column:channel_id;type:varchar(64);not null;uniqueIndex:idx_client_security_profile_identity" json:"channelId"`
	MachineID       string    `gorm:"column:machine_id;type:varchar(128);not null;uniqueIndex:idx_client_security_profile_identity" json:"machineId"`
	InstallID       string    `gorm:"column:install_id;type:varchar(128);not null;uniqueIndex:idx_client_security_profile_identity" json:"installId"`
	PlayerName      string    `gorm:"type:varchar(64)" json:"playerName"`
	PlayerNameNorm  string    `gorm:"type:varchar(64);index" json:"playerNameNorm"`
	KeyID           uint      `gorm:"column:key_id;index" json:"keyId"`
	KeyPrefix       string    `gorm:"column:key_prefix;type:varchar(16)" json:"keyPrefix"`
	FirstSeen       time.Time `gorm:"column:first_seen;index" json:"firstSeen"`
	LastSeen        time.Time `gorm:"column:last_seen;index" json:"lastSeen"`
	LastIP          string    `gorm:"column:last_ip;type:varchar(64);index" json:"lastIp"`
	UserAgent       string    `gorm:"type:varchar(255)" json:"userAgent"`
	CoreVersion     string    `gorm:"type:varchar(64)" json:"coreVersion"`
	WedgeVersion    string    `gorm:"type:varchar(64)" json:"wedgeVersion"`
	ManifestVersion string    `gorm:"type:varchar(64)" json:"manifestVersion"`
	OS              string    `gorm:"type:varchar(64)" json:"os"`
	OSVersion       string    `gorm:"type:varchar(64)" json:"osVersion"`
	Arch            string    `gorm:"type:varchar(32)" json:"arch"`
	JavaVendor      string    `gorm:"type:varchar(128)" json:"javaVendor"`
	JavaVersion     string    `gorm:"type:varchar(64)" json:"javaVersion"`
	JavaArch        string    `gorm:"type:varchar(32)" json:"javaArch"`
	Launcher        string    `gorm:"type:varchar(128)" json:"launcher"`
	Locale          string    `gorm:"type:varchar(32)" json:"locale"`
	Timezone        string    `gorm:"type:varchar(64)" json:"timezone"`
	MemoryTier      string    `gorm:"type:varchar(32)" json:"memoryTier"`
	RiskScore       int       `gorm:"default:0;not null" json:"riskScore"`
	RiskLevel       string    `gorm:"type:varchar(32);default:normal;not null" json:"riskLevel"`
	ProtectionState string    `gorm:"type:varchar(32);default:normal;not null" json:"protectionState"`
	LabelsJSON      string    `gorm:"column:labels_json;type:text" json:"-"`
	CreatedAt       time.Time `json:"createdAt"`
	UpdatedAt       time.Time `json:"updatedAt"`
}

type ClientSecurityRiskEvent

type ClientSecurityRiskEvent struct {
	ID           uint      `gorm:"primaryKey" json:"id"`
	SubjectType  string    `gorm:"column:subject_type;type:varchar(32);index" json:"subjectType"`
	SubjectValue string    `gorm:"column:subject_value;type:varchar(128);index" json:"subjectValue"`
	ChannelID    string    `gorm:"column:channel_id;type:varchar(64);index" json:"channelId"`
	MachineID    string    `gorm:"column:machine_id;type:varchar(128);index" json:"machineId"`
	InstallID    string    `gorm:"column:install_id;type:varchar(128);index" json:"installId"`
	PlayerName   string    `gorm:"type:varchar(64);index" json:"playerName"`
	IP           string    `gorm:"type:varchar(64);index" json:"ip"`
	KeyID        uint      `gorm:"column:key_id;index" json:"keyId"`
	KeyPrefix    string    `gorm:"column:key_prefix;type:varchar(16)" json:"keyPrefix"`
	RuleCode     string    `gorm:"column:rule_code;type:varchar(64);default:'';not null;index" json:"ruleCode"`
	Severity     string    `gorm:"type:varchar(32);default:info;not null" json:"severity"`
	ScoreDelta   int       `gorm:"column:score_delta;default:0;not null" json:"scoreDelta"`
	Action       string    `gorm:"type:varchar(32)" json:"action"`
	Reason       string    `gorm:"type:varchar(512)" json:"reason"`
	DetailJSON   string    `gorm:"column:detail_json;type:text" json:"-"`
	CreatedAt    time.Time `gorm:"index" json:"createdAt"`
}

type ClientTelemetry

type ClientTelemetry struct {
	ID          uint      `gorm:"primaryKey" json:"id"`
	ChannelID   string    `gorm:"column:channel_id;type:varchar(64);index:idx_ct_channel_time" json:"channelId"`
	MachineID   string    `gorm:"column:machine_id;type:varchar(128);index" json:"machineId"`
	PlayerName  string    `gorm:"column:player_name;type:varchar(32);index" json:"playerName"`
	IP          string    `gorm:"type:varchar(64)" json:"ip"`
	Result      string    `gorm:"type:varchar(16);not null" json:"result"` // success|fail-static|rolled-back|error
	FromVersion int       `gorm:"default:0;not null" json:"fromVersion"`
	ToVersion   int       `gorm:"default:0;not null" json:"toVersion"`
	CoreVersion string    `gorm:"column:core_version;type:varchar(64)" json:"coreVersion"`
	OS          string    `gorm:"column:os;type:varchar(32)" json:"os"`
	Arch        string    `gorm:"column:arch;type:varchar(16)" json:"arch"`
	JavaVersion string    `gorm:"column:java_version;type:varchar(32)" json:"javaVersion"`
	JavaVendor  string    `gorm:"column:java_vendor;type:varchar(64)" json:"javaVendor"`
	Launcher    string    `gorm:"type:varchar(32)" json:"launcher"`
	Locale      string    `gorm:"column:locale;type:varchar(32)" json:"locale"`
	Timezone    string    `gorm:"column:timezone;type:varchar(64)" json:"timezone"`
	MemoryTier  string    `gorm:"column:memory_tier;type:varchar(16)" json:"memoryTier"`
	DurationMs  int64     `gorm:"column:duration_ms;default:0;not null" json:"durationMs"`
	BootSuccess bool      `gorm:"column:boot_success;default:false;not null" json:"bootSuccess"`
	Error       string    `gorm:"type:varchar(512)" json:"error"`
	CreatedAt   time.Time `gorm:"index:idx_ct_channel_time" json:"createdAt"`
}

ClientTelemetry 客户端遥测明细(FR-094 / FR-360,见 ADR-023、contract §4.3)。 **短保留 + 滚动清理**(数据量治理)。仅环境粗粒度 + 不可逆机器码;隐私可关(客户端 opt-out)。 FR-360 增列:core_version/arch(required)与 java_vendor/locale/timezone/memory_tier(diagnostic)。

type ClientTelemetryDaily

type ClientTelemetryDaily struct {
	ID        uint   `gorm:"primaryKey" json:"id"`
	Day       string `gorm:"type:char(10);not null;uniqueIndex:idx_ctd_day_chan_result" json:"day"`
	ChannelID string `gorm:"column:channel_id;type:varchar(64);not null;uniqueIndex:idx_ctd_day_chan_result" json:"channelId"`
	Result    string `gorm:"type:varchar(16);not null;uniqueIndex:idx_ctd_day_chan_result" json:"result"`
	Count     int64  `gorm:"default:0;not null" json:"count"`
}

ClientTelemetryDaily 遥测按日聚合(FR-094)。长保留,写时增量;供 FR-095 更新成功率/回退率趋势。 不按 FR-360 新维度打爆基数,仍仅 day×channel×result。

type ClientVersion

type ClientVersion struct {
	ID uint `gorm:"primaryKey" json:"id"`
	// ChannelID 所属频道 slug(随频道删除级联清理)。
	ChannelID string `gorm:"column:channel_id;type:varchar(64);index:idx_client_versions_channel_version,unique;not null" json:"channelId"`
	// Version 单调递增整数(同频道内唯一);防降级基准(contract §3)。
	Version int `gorm:"index:idx_client_versions_channel_version,unique;not null" json:"version"`
	// FilesJSON 文件清单快照([]ManifestFile 的 JSON):path/sha256/md5/size/sync/platform/artifact。
	FilesJSON string `gorm:"column:files_json;type:text;not null" json:"-"`
	// ManagedDirsJSON 托管目录快照([]string 的 JSON):仅这些目录可增删(减量)。
	// FR-255:可含 "*" 哨兵表「整个 gameDir」(clean-all)。
	ManagedDirsJSON string `gorm:"column:managed_dirs_json;type:text;not null" json:"-"`
	// CleanExcludeJSON 运营自定义排除快照([]string 的 JSON,FR-255):命中前缀永不删。
	// 空串=未声明(向后兼容,老版本无此列)。
	CleanExcludeJSON string `gorm:"column:clean_exclude_json;type:text" json:"-"`
	// AgentJSON 楔子 + updater-core 自更新段快照(ManifestAgent 的 JSON),可空(未声明自更新段)。
	AgentJSON string `gorm:"column:agent_json;type:text" json:"-"`
	// Note 发布备注(运营可读,信息性)。
	Note string `gorm:"type:varchar(512)" json:"note"`
	// CreatedBy 发布者用户 ID(审计辅助,0=未知)。
	CreatedBy uint      `gorm:"default:0;not null" json:"createdBy"`
	CreatedAt time.Time `json:"createdAt"`
}

ClientVersion 客户端分发版本快照(FR-087,见 ADR-022、contract §2)。 一条记录 = 频道某次发布的完整文件清单 + 同步策略 + 自更新段。Version 单调递增、与 ClientChannel.CurrentVersion 配合定位 latest。manifest 由该快照即时组装 + Ed25519 签名(不缓存签名,密钥轮换/防降级见 ADR-022)。

本 FR(latest-only)只需「能发布一版并以 latest 返回」;完整版本历史/运营回滚/管理台见 FR-088。

type EconomyBalanceMirror

type EconomyBalanceMirror struct {
	ID uint `gorm:"primaryKey" json:"id"`
	// NodeUUID 余额所在节点(聚合 node→zone 维度起点)。
	NodeUUID string `gorm:"column:node_uuid;type:varchar(64);not null;uniqueIndex:idx_ebm_scope,priority:1" json:"nodeUuid"`
	// InstanceUUID 余额来源实例,用于业务汇聚读视图按用户组做资源级隔离。
	InstanceUUID string `gorm:"column:instance_uuid;type:varchar(64);index" json:"instanceUuid"`
	// ZoneID mce 区 ID(CoreLib zoneId);跨区同名玩家独立隔离的关键维度。
	ZoneID string `gorm:"column:zone_id;type:varchar(64);not null;uniqueIndex:idx_ebm_scope,priority:2" json:"zoneId"`
	// PlayerName 玩家名(区分大小写,mce 口径)。
	PlayerName string `` /* 127-byte string literal not displayed */
	// Currency 货币 identifier(全局稳定业务键;探针侧已由 currencyId Int 折算,跨服可聚合)。
	Currency string `gorm:"type:varchar(64);not null;uniqueIndex:idx_ebm_scope,priority:4" json:"currency"`
	// CurrencyID 货币 mce Int 原值(审计回溯用;跨服不保证一致,故不作聚合键)。
	CurrencyID int `gorm:"column:currency_id;default:0;not null" json:"currencyId"`
	// Balance 最新余额(字符串承载 BigDecimal,禁浮点,防多币种精度失真)。
	Balance string `gorm:"type:varchar(64);not null" json:"balance"`
	// LastSeq 已应用的最大 mce 区内单调 seq(镜像推进游标,防乱序/重发回退余额)。
	LastSeq int64 `gorm:"column:last_seq;default:0;not null" json:"lastSeq"`
	// LastLedgerID 最近一次应用的总账流水 ID(可追溯到 [EconomyLedgerEntry])。
	LastLedgerID int64 `gorm:"column:last_ledger_id;default:0;not null" json:"lastLedgerId"`
	// LastEntryType 最近一次变更的入账类型(DEPOSIT/WITHDRAW/…)。
	LastEntryType string `gorm:"column:last_entry_type;type:varchar(32)" json:"lastEntryType"`
	// OccurredAt 最近一次变更的业务发生时间(epoch 毫秒)。
	OccurredAt int64     `gorm:"column:occurred_at;default:0;not null" json:"occurredAt"`
	UpdatedAt  time.Time `json:"updatedAt"`
}

EconomyBalanceMirror 是经济结构化镜像表:每 (节点, 区, 玩家, 货币) 的**最新余额**快照(FR-122,见 ADR-028)。

由经济变更事件流(BusinessEvent domain=economy)按 ledgerId 去重后**按 seq 单调推进**维护:仅当来量 seq ≥ 已存 seq 时覆盖余额,乱序/重发的旧事件不回退镜像。聚合维度 (NodeUUID, ZoneID, PlayerName, Currency) 唯一——**node→zone 维度**确保跨区同名玩家不串味/不重复计数(mce 账户按 zoneId 隔离,同名玩家跨区独立)。

非业务真源:余额真源仍在各服 mce 库,本表是供平台高效查询/对账的汇聚镜像(守数据所有权不变量)。

type EconomyLedgerEntry

type EconomyLedgerEntry struct {
	ID uint `gorm:"primaryKey" json:"id"`
	// LedgerID mce 总账流水 ID(去重锚点,仅 node→zone 内唯一)。
	LedgerID int64 `gorm:"column:ledger_id;not null;uniqueIndex:idx_ele_scope_ledger,priority:3" json:"ledgerId"`
	// NodeUUID / InstanceUUID 事件来源(node→zone 聚合维度)。
	NodeUUID     string `` /* 128-byte string literal not displayed */
	InstanceUUID string `gorm:"column:instance_uuid;type:varchar(64)" json:"instanceUuid"`
	// ZoneID mce 区 ID。
	ZoneID string `` /* 137-byte string literal not displayed */
	// PlayerName 玩家名。
	PlayerName string `gorm:"column:player_name;type:varchar(64);index:idx_ele_player,priority:2" json:"playerName"`
	// Currency 货币 identifier;CurrencyID 为 mce Int 原值。
	Currency   string `gorm:"type:varchar(64)" json:"currency"`
	CurrencyID int    `gorm:"column:currency_id;default:0;not null" json:"currencyId"`
	// EntryType 入账类型(DEPOSIT/WITHDRAW/CONSUME/REFUND/TRANSFER_IN/TRANSFER_OUT/ADJUST)。
	EntryType string `gorm:"column:entry_type;type:varchar(32)" json:"entryType"`
	// SignedAmount 带符号变更额(字符串承载 BigDecimal,正入负出)。
	SignedAmount string `gorm:"column:signed_amount;type:varchar(64)" json:"signedAmount"`
	// BalanceAfter 变更后余额(字符串承载 BigDecimal)。
	BalanceAfter string `gorm:"column:balance_after;type:varchar(64)" json:"balanceAfter"`
	// Seq mce 区内单调投递序号(排序/回放游标,非幂等键)。
	Seq int64 `gorm:"default:0;not null" json:"seq"`
	// OccurredAt 账务发生时间(epoch 毫秒)。
	OccurredAt int64 `gorm:"column:occurred_at;default:0;not null;index:idx_ele_time" json:"occurredAt"`
	// CreatedAt CP 落库时间。
	CreatedAt time.Time `json:"createdAt"`
}

EconomyLedgerEntry 是经济变更/操作审计表:逐条经济变更的结构化留痕(FR-122,见 ADR-028)。

与通用 BusinessEvent 并存——envelope 是插件无关底座,本表是经济域**结构化专表**,把信封 payload 拆列 供高效查询/对账(按玩家/货币/区/时间维度)。按 (NodeUUID, ZoneID, LedgerID) 唯一去重(与 envelope 同源 dedupKey), 业务数据**不降采样、不丢**(区别于监控时序,ADR-028)。append-only,不随镜像覆盖。

type FileVersion

type FileVersion struct {
	ID                  uint      `gorm:"primaryKey" json:"id"`
	InstanceID          uint      `gorm:"not null;index:idx_file_version_instance_path" json:"instanceId"`
	FilePath            string    `gorm:"type:varchar(512);not null;index:idx_file_version_instance_path" json:"filePath"`
	ContentHash         string    `gorm:"type:char(64);not null;index" json:"contentHash"`
	Content             string    `gorm:"type:longtext;not null" json:"-"`
	Size                int64     `gorm:"not null" json:"size"`
	AuthorID            uint      `gorm:"index" json:"authorId"`
	RollbackOfVersionID *uint     `gorm:"index" json:"rollbackOfVersionId,omitempty"`
	CreatedAt           time.Time `json:"createdAt"`
}

FileVersion 通用文件版本快照记录(FR-051)。

与 InstanceConfigVersion(FR-031,仅限配置文件)共用「改前快照 + 列表 + diff + 回滚」 的版本机制,但适用于实例工作目录下的任意文件(含上传覆盖的二进制文件)。 二者刻意分表:配置版本带 schema/校验语义,通用文件版本只关心字节内容, 避免把二进制内容混入按文本语义设计的 instance_config_versions 表。

版本事实源在 Control Plane 数据库(架构不变量:Worker 不碰 DB), 文件本体仍归 Worker;快照内容随写入时机由 CP 先读旧内容后落库。

Content 以 base64 编码存储,保证二进制文件(jar/zip/图片等)也能无损快照与回滚; 不直接存原始字节是为了兼容 SQLite/MySQL 的文本列与现有 GORM string 字段约定。 RollbackOfVersionID 记录本次写入是否由回滚触发,指向被回滚的源版本,便于审计回滚链。

type Group

type Group struct {
	ID          uint           `gorm:"primaryKey" json:"id"`
	UUID        string         `gorm:"type:char(36);uniqueIndex;not null" json:"uuid"`
	Name        string         `gorm:"type:varchar(128);not null" json:"name"`
	Description string         `gorm:"type:varchar(512)" json:"description"`
	CreatedAt   time.Time      `json:"createdAt"`
	UpdatedAt   time.Time      `json:"updatedAt"`
	DeletedAt   gorm.DeletedAt `gorm:"index" json:"-"`

	Members []GroupMember `gorm:"foreignKey:GroupID" json:"members,omitempty"`
	Quota   *GroupQuota   `gorm:"foreignKey:GroupID" json:"quota,omitempty"`
}

Group 用户组。

func (*Group) BeforeCreate

func (g *Group) BeforeCreate(tx *gorm.DB) error

BeforeCreate 创建前自动生成 UUID。

type GroupInstance

type GroupInstance struct {
	ID         uint      `gorm:"primaryKey" json:"id"`
	GroupID    uint      `gorm:"not null;index" json:"groupId"`
	InstanceID uint      `gorm:"uniqueIndex;not null" json:"instanceId"`
	CreatedAt  time.Time `json:"createdAt"`
}

GroupInstance 实例与用户组的关联。

type GroupMember

type GroupMember struct {
	ID        uint            `gorm:"primaryKey" json:"id"`
	GroupID   uint            `gorm:"not null;uniqueIndex:idx_group_user" json:"groupId"`
	UserID    uint            `gorm:"not null;uniqueIndex:idx_group_user" json:"userId"`
	Role      GroupMemberRole `gorm:"default:0" json:"role"`
	CreatedAt time.Time       `json:"createdAt"`

	Group Group `gorm:"foreignKey:GroupID" json:"-"`
	User  User  `gorm:"foreignKey:UserID" json:"user,omitempty"`
}

GroupMember 组成员关联。

type GroupMemberRole

type GroupMemberRole int

GroupMemberRole 组内角色。

const (
	GroupMemberRoleMember GroupMemberRole = 0 // 普通成员
	GroupMemberRoleAdmin  GroupMemberRole = 1 // 组管理员
)

type GroupQuota

type GroupQuota struct {
	ID           uint      `gorm:"primaryKey" json:"id"`
	GroupID      uint      `gorm:"uniqueIndex;not null" json:"groupId"`
	MaxInstances int       `gorm:"default:10" json:"maxInstances"`
	MaxBots      int       `gorm:"default:50" json:"maxBots"`
	MaxStorageMB int       `gorm:"default:10240" json:"maxStorageMb"`
	CreatedAt    time.Time `json:"createdAt"`
	UpdatedAt    time.Time `json:"updatedAt"`
}

GroupQuota 组配额。

type Instance

type Instance struct {
	ID          uint           `gorm:"primaryKey" json:"id"`
	UUID        string         `gorm:"type:char(36);uniqueIndex;not null" json:"uuid"`
	NodeID      uint           `gorm:"not null;index" json:"nodeId"`
	Name        string         `gorm:"type:varchar(128);not null;index" json:"name"`
	Type        InstanceType   `gorm:"type:varchar(64);not null" json:"type"`
	Role        InstanceRole   `gorm:"type:varchar(16);default:universal;index" json:"role"`
	ProcessType ProcessType    `gorm:"type:varchar(32);not null" json:"processType"`
	Status      InstanceStatus `gorm:"type:varchar(32);default:STOPPED;index" json:"status"`
	// StatusReason 记录当前状态的原因,主要用于 CRASHED:异步委托(启动/停止)失败时写入具体错误
	// (如「实例未绑定 JDK…」),供前端显示,不再让用户只见「崩溃」无因。正常状态推进时清空。
	StatusReason     string `gorm:"type:varchar(512)" json:"statusReason"`
	StartCommand     string `gorm:"type:varchar(1024);not null" json:"startCommand"`
	JDKID            uint   `gorm:"index" json:"jdkId"`
	JavaMajorVersion int    `gorm:"index" json:"javaMajorVersion"`
	LaunchSpec       string `gorm:"type:text" json:"launchSpec"`
	// ProvisionSpec 存一键搭建/代理搭建的原始请求(JSON),供损毁后「重建」复用参数重跑搭建(FR-342)。
	// 仅经搭建入口创建的实例有值;手动/导入实例为空、不适用重建。
	ProvisionSpec string `gorm:"type:text" json:"provisionSpec,omitempty"`
	WorkDir       string `gorm:"type:varchar(512)" json:"workDir"`
	// WorkDirInPlace 就地导入标记(FR-302,见 ADR-069):工作目录为托管区外的原始绝对路径
	// (ADR-007 系统分配原则的唯一合法例外)。删除实例时 CP 据此指示 Worker 跳过目录删除,
	// 原目录永不清理(双保险之一,另一道是 Worker 托管区守卫)。
	WorkDirInPlace bool   `gorm:"default:false" json:"workDirInPlace"`
	EnvVars        string `gorm:"type:text" json:"envVars"` // JSON
	// Image 是 docker 模式的容器镜像引用(如 itzg/minecraft-server:latest),仅 process_type=docker 使用(FR-078,ADR-019)。
	Image string `gorm:"type:varchar(256)" json:"image"`
	// ContainerID 记录 docker 模式实例最近一次运行的容器 ID(排障/展示用,运行态由 Worker 持有)。
	ContainerID string `gorm:"type:varchar(64)" json:"containerId"`
	// CPULimit 是 docker 模式的 CPU 核数上限(如 1.5),启动时注入容器 cgroup;0=不限制(FR-079,ADR-019)。
	CPULimit float64 `gorm:"default:0" json:"cpuLimit"`
	// MemLimitMB 是 docker 模式的内存上限(MiB),启动时注入容器 cgroup;0=不限制(FR-079,ADR-019)。
	MemLimitMB int64 `gorm:"default:0" json:"memLimitMb"`
	// DiskLimitMB 是 docker 模式的磁盘上限(MiB),仅持久化与展示,v1 不注入(依赖存储驱动)(FR-079)。
	DiskLimitMB int64 `gorm:"default:0" json:"diskLimitMb"`
	AutoStart   bool  `gorm:"default:false" json:"autoStart"`
	AutoRestart bool  `gorm:"default:true" json:"autoRestart"`
	// Deprecated: RCON 已退役(FR-067,见 ADR-016)——治理改走 ServerProbe 探针。
	// 列保留仅为迁移安全(不破坏既有库与历史实例数据),新实例不再写入、读取方不再使用。
	RCONPort     int    `gorm:"default:0" json:"rconPort"`
	RCONPassword string `gorm:"type:varchar(128)" json:"-"`
	// ForwardingSecret 是 Velocity modern 转发的 forwarding secret(代理实例 provision 时生成)。
	// 下发到所注册后端 paper 配置 + 跨代理一致校验复用;BungeeCord/Waterfall 不使用。参见 FR-035。
	ForwardingSecret string `gorm:"type:varchar(128)" json:"-"`
	// ProxyOnlineMode 代理是否向 Mojang 校验正版(true=正版网络,false=离线模式群组服)。
	// 仅代理实例使用;持久化以便 SyncProxy 重新生成配置时保留选择(默认 true)。参见 FR-035。
	ProxyOnlineMode bool `gorm:"default:true" json:"proxyOnlineMode"`
	ServerPort      int  `gorm:"default:0" json:"serverPort"`
	QueryPort       int  `gorm:"default:0" json:"queryPort"`
	// ProbePort 是 ServerProbe 监控探针 /metrics 端口(系统分配,FR-010)。0 表示未部署探针。
	ProbePort int `gorm:"default:0" json:"probePort"`
	// ProbeVersionID 是实例显式选择的 ServerProbe 版本;0 表示继承所属 Worker 或全局默认(FR-409)。
	ProbeVersionID uint           `gorm:"default:0;index" json:"probeVersionId"`
	PID            int            `gorm:"default:0" json:"pid"`
	StartedAt      *time.Time     `json:"startedAt"`
	CrashCount     int            `gorm:"default:0" json:"crashCount"`
	Tags           string         `gorm:"type:text" json:"tags"` // JSON
	CreatedAt      time.Time      `json:"createdAt"`
	UpdatedAt      time.Time      `json:"updatedAt"`
	DeletedAt      gorm.DeletedAt `gorm:"index" json:"-"`

	Node Node `gorm:"foreignKey:NodeID" json:"node,omitempty"`
}

Instance 实例。

func (*Instance) BeforeCreate

func (i *Instance) BeforeCreate(tx *gorm.DB) error

BeforeCreate 创建前自动生成 UUID。

type InstanceConfigVersion

type InstanceConfigVersion struct {
	ID                    uint      `gorm:"primaryKey" json:"id"`
	InstanceID            uint      `gorm:"not null;index:idx_cfg_version_instance_file" json:"instanceId"`
	FilePath              string    `gorm:"type:varchar(512);not null;index:idx_cfg_version_instance_file" json:"filePath"`
	ContentHash           string    `gorm:"type:char(64);not null;index" json:"contentHash"`
	Content               string    `gorm:"type:longtext;not null" json:"content"`
	Message               string    `gorm:"type:varchar(255)" json:"message"`
	AuthorID              uint      `gorm:"index" json:"authorId"`
	RollbackOfVersionID   *uint     `gorm:"index" json:"rollbackOfVersionId,omitempty"`
	RollbackedByVersionID *uint     `gorm:"index" json:"rollbackedByVersionId,omitempty"`
	CreatedAt             time.Time `json:"createdAt"`
}

InstanceConfigVersion 配置版本记录。 同一实例的同一文件可保存多条历史版本(无联合唯一约束)。 RollbackOfVersionID 记录本次写入是否由回滚触发,指向被回滚的源版本。 RollbackedByVersionID 指向"回滚此版本"产生的新版本(若存在),便于反向追溯回滚链。

type InstanceCrashSnapshot

type InstanceCrashSnapshot struct {
	ID         uint `gorm:"primaryKey" json:"id"`
	InstanceID uint `gorm:"not null;index" json:"instanceId"`
	// OccurredAt 崩溃发生时刻(Worker 侧时钟)。
	OccurredAt time.Time `json:"occurredAt"`
	// ExitCode 进程退出码;无法获知(Wait 出错/容器 Wait 错误)时为 -1。
	ExitCode int `json:"exitCode"`
	// Signal 终止信号名(Unix,如 killed/terminated);Windows / 非信号退出为空。
	Signal string `gorm:"type:varchar(32)" json:"signal"`
	// DurationMs 本次运行时长(毫秒)。
	DurationMs int64 `json:"durationMs"`
	// TailOutput 崩溃前终端尾部输出(Worker 侧截取,≤200 行 / 64KB)。
	TailOutput string    `gorm:"type:text" json:"tailOutput"`
	CreatedAt  time.Time `json:"createdAt"`
}

InstanceCrashSnapshot 实例崩溃快照(FR-313):进程非正常退出的现场留存。 Worker 在进程崩溃时经 gRPC ReportCrashSnapshot 上报,CP 持久化并按实例滚动保留 最近 5 条(写死不做配置,见 spec §6);实例删除时级联清理。

type InstanceGroupMember

type InstanceGroupMember struct {
	ID         uint      `gorm:"primaryKey" json:"id"`
	GroupID    uint      `gorm:"not null;index;uniqueIndex:idx_igmember_group_inst" json:"groupId"`
	InstanceID uint      `gorm:"not null;index;uniqueIndex:idx_igmember_group_inst" json:"instanceId"`
	CreatedAt  time.Time `json:"createdAt"`
}

InstanceGroupMember 是分组节点与实例的 M:N 关联(一个实例可属多个组织分组)。 UNIQUE(group_id, instance_id) 保证同组内不重复;删组只硬删成员关系、不触及实例。

type InstanceGroupNode

type InstanceGroupNode struct {
	ID   uint   `gorm:"primaryKey" json:"id"`
	UUID string `gorm:"type:char(36);uniqueIndex;not null" json:"uuid"`
	Name string `gorm:"type:varchar(128);not null" json:"name"`
	// ParentID 父节点 ID,NULL 表示根分组;自引用邻接表表达树。建索引便于按父查子。
	ParentID *uint `gorm:"index" json:"parentId,omitempty"`
	// Sort 同级排序权重(升序),由 service 维护;前端可拖拽改序。
	Sort      int            `gorm:"default:0" json:"sort"`
	CreatedAt time.Time      `json:"createdAt"`
	UpdatedAt time.Time      `json:"updatedAt"`
	DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
}

InstanceGroupNode 是「实例组织分组树」的一个节点(ADR-033 实例组织分组树)。 多级嵌套用自引用 ParentID 邻接表表达(NULL=根);与用户组(ADR-004 RBAC/配额)、 网络群组(ADR-007 proxy↔backend 部署)三者正交——仅供人为组织归类、折叠、批量运维, 不承载权限/配额,也不表达运行时拓扑。删非空节点默认拒删(service 校验),不级联删实例。

func (*InstanceGroupNode) BeforeCreate

func (n *InstanceGroupNode) BeforeCreate(tx *gorm.DB) error

BeforeCreate 创建前自动生成 UUID。

type InstanceRole

type InstanceRole string

InstanceRole 实例在 MC 群组服拓扑中的角色(ADR-007)。

const (
	// InstanceRoleBackend 后端子服(Paper/Spigot/Purpur),可注册进多个代理。
	InstanceRoleBackend InstanceRole = "backend"
	// InstanceRoleProxy 代理(BungeeCord/Waterfall/Velocity),聚合多个后端。
	InstanceRoleProxy InstanceRole = "proxy"
	// InstanceRoleUniversal 通用实例(默认;非群组服角色,保留自由命令)。
	InstanceRoleUniversal InstanceRole = "universal"
)

type InstanceStatus

type InstanceStatus string

InstanceStatus 实例状态。

const (
	InstanceStatusStopped  InstanceStatus = "STOPPED"
	InstanceStatusStarting InstanceStatus = "STARTING"
	InstanceStatusRunning  InstanceStatus = "RUNNING"
	InstanceStatusStopping InstanceStatus = "STOPPING"
	InstanceStatusCrashed  InstanceStatus = "CRASHED"
	// InstanceStatusDamaged 损毁(FR-342):一键搭建/代理搭建过程中任一阶段失败进入此态,
	// 原始搭建参数(ProvisionSpec)保留,可「重建」复用参数重跑搭建;损毁实例不可直接启动。
	InstanceStatusDamaged InstanceStatus = "DAMAGED"
)

type InstanceType

type InstanceType string

InstanceType 实例类型。

const (
	InstanceTypeMinecraftJava InstanceType = "minecraft_java"
	InstanceTypeGeneric       InstanceType = "generic"
)

type LogEntry

type LogEntry struct {
	ID uint `gorm:"primaryKey" json:"id"`
	// Source 区分实例日志与平台日志,过滤维度之一。
	Source LogSource `gorm:"type:varchar(16);not null;index:idx_logs_source_time,priority:1" json:"source"`
	// Level 日志级别,过滤维度之一。
	Level LogLevel `gorm:"type:varchar(8);not null;index:idx_logs_level_time,priority:1" json:"level"`
	// InstanceID 实例主键(实例日志非零);与 Time 组成复合索引承接按实例时间检索。
	InstanceID uint `gorm:"index:idx_logs_instance_time,priority:1" json:"instanceId"`
	// InstanceUUID 实例 UUID 冗余列,采集侧仅持有 UUID 时直接落库。
	InstanceUUID string `gorm:"type:char(36);index" json:"instanceUuid"`
	// NodeID 节点主键(实例/Worker 日志非零);与 Time 组成复合索引承接按节点时间检索。
	NodeID uint `gorm:"index:idx_logs_node_time,priority:1" json:"nodeId"`
	// Stream 原始流名(stdout/stderr/""),仅实例日志使用,辅助前端区分。
	Stream string `gorm:"type:varchar(8)" json:"stream,omitempty"`
	// Message 日志正文(已去除行尾换行)。关键字检索在此列上做 DB 侧 LIKE。
	Message string `gorm:"type:text;not null" json:"message"`
	// Time 日志产生时间(采集/写入时刻)。所有复合索引的次序列,统一按时间倒序检索。
	Time time.Time `` /* 178-byte string literal not displayed */
}

LogEntry 是单条持久化日志(实例运行日志或平台运行日志)。

这是高写入、按条件检索的表,因此刻意不内嵌外键关联对象(不像 AuditLog 预加载 User):

  • 以 InstanceID/NodeID 的整型外键 + 复合索引承接「按实例/节点 + 时间」的高频过滤;
  • 关键字检索走 Message 上的 DB 谓词(LIKE),不在应用层全量序列化(FR-049/FR-050);
  • InstanceUUID 冗余保存,便于采集侧(仅持有 UUID 的 Worker 事件流)直接落库而不必反查。

归档与保留由 LogService 负责:超阈值的旧条目滚动落盘到数据根 var/log 后从表中清理 (参见 ADR-005 单二进制不引 ELK、ADR-010 数据根布局)。

func (LogEntry) TableName

func (LogEntry) TableName() string

TableName 固定表名为 logs。

type LogLevel

type LogLevel string

LogLevel 日志级别。实例 stdout 默认归为 info、stderr 归为 error;平台日志沿用 slog 级别。

const (
	LogLevelDebug LogLevel = "debug"
	LogLevelInfo  LogLevel = "info"
	LogLevelWarn  LogLevel = "warn"
	LogLevelError LogLevel = "error"
)

type LogSource

type LogSource string

LogSource 日志来源类别。

const (
	// LogSourceInstance 实例运行日志(采集自 Worker 转发的进程 stdout/stderr)。
	LogSourceInstance LogSource = "instance"
	// LogSourceControlPlane 平台 Control Plane 自身结构化日志。
	LogSourceControlPlane LogSource = "control_plane"
	// LogSourceWorker 平台 Worker Node 自身结构化日志(经 gRPC 上报或本地直采,预留)。
	LogSourceWorker LogSource = "worker"
)

type MetricRollup1h

type MetricRollup1h struct {
	ID       uint      `gorm:"primaryKey" json:"id"`
	SeriesID uint      `gorm:"not null;index:idx_metric_1h_series_bucket,priority:1" json:"seriesId"`
	BucketTS time.Time `gorm:"not null;index:idx_metric_1h_series_bucket,priority:2" json:"bucketTs"`
	Avg      float64   `json:"avg"`
	Min      float64   `json:"min"`
	Max      float64   `json:"max"`
	Last     float64   `json:"last"`
	Count    int       `json:"count"`
}

MetricRollup1h 1 小时降采样档(留 ≥1 年)。结构同 5m 档,独立表便于按 TTL 清理。

type MetricRollup5m

type MetricRollup5m struct {
	ID       uint      `gorm:"primaryKey" json:"id"`
	SeriesID uint      `gorm:"not null;index:idx_metric_5m_series_bucket,priority:1" json:"seriesId"`
	BucketTS time.Time `gorm:"not null;index:idx_metric_5m_series_bucket,priority:2" json:"bucketTs"`
	Avg      float64   `json:"avg"`
	Min      float64   `json:"min"`
	Max      float64   `json:"max"`
	Last     float64   `json:"last"`
	Count    int       `json:"count"`
}

MetricRollup5m 5 分钟降采样档(留 ~30d)。仅在桶内有非空样本时生成,缺测为缺桶。

type MetricSampleRaw

type MetricSampleRaw struct {
	ID       uint      `gorm:"primaryKey" json:"id"`
	SeriesID uint      `gorm:"not null;index:idx_metric_raw_series_ts,priority:1" json:"seriesId"`
	TS       time.Time `gorm:"not null;index:idx_metric_raw_series_ts,priority:2" json:"ts"`
	Value    *float64  `json:"value"`
}

MetricSampleRaw 原始样本(30s 粒度,留 ~48h)。 Value 为指针:nil 表示缺测(采集源不可达),查询时渲染为断点,不补假值。

type MetricScope

type MetricScope string

MetricScope 时序指标的作用域维度(ADR-013)。

const (
	// MetricScopeNode 节点级指标(CPU/内存/磁盘/网络),来自心跳。
	MetricScopeNode MetricScope = "node"
	// MetricScopeInstance 实例级指标,来自 ServerProbe(TPS/MSPT/堆/线程/CPU/uptime)。
	MetricScopeInstance MetricScope = "instance"
	// MetricScopeWorld 实例下单个世界的负载,来自 ServerProbe serverprobe_world_*。
	MetricScopeWorld MetricScope = "world"
)

type MetricSeries

type MetricSeries struct {
	ID uint `gorm:"primaryKey" json:"id"`
	// NodeUUID 所属节点。
	NodeUUID string `gorm:"type:varchar(64);not null;uniqueIndex:idx_metric_series_identity,priority:1" json:"nodeUuid"`
	// InstanceID 实例级/世界级序列才有;节点级为空字符串。
	InstanceID string `gorm:"type:varchar(64);not null;default:'';uniqueIndex:idx_metric_series_identity,priority:2" json:"instanceId"`
	// Scope 作用域:node / instance / world。
	Scope MetricScope `gorm:"type:varchar(16);not null;uniqueIndex:idx_metric_series_identity,priority:3" json:"scope"`
	// MetricKey 指标键,见上方常量。
	MetricKey string `gorm:"type:varchar(48);not null;uniqueIndex:idx_metric_series_identity,priority:4" json:"metricKey"`
	// World scope=world 时的世界名,其余为空字符串。
	World string `gorm:"type:varchar(64);not null;default:'';uniqueIndex:idx_metric_series_identity,priority:5" json:"world"`
	// Unit 单位:pct/bytes/bytes_per_sec/count/ms/tps/seconds。
	Unit       string    `gorm:"type:varchar(16)" json:"unit"`
	CreatedAt  time.Time `json:"createdAt"`
	LastSeenAt time.Time `json:"lastSeenAt"`
}

MetricSeries 时序序列的身份维度表(ADR-013)。 一条序列 = (node_uuid, instance_id?, scope, metric_key, world?); 样本/卷积表只引用 series_id,对新增指标键与动态世界天然可扩展。

type Network

type Network struct {
	ID   uint   `gorm:"primaryKey" json:"id"`
	UUID string `gorm:"type:char(36);uniqueIndex;not null" json:"uuid"`
	// Name 群组名,唯一性由 service 在未软删记录间校验(不加 DB 唯一索引,便于删除后重用同名)。
	Name        string         `gorm:"type:varchar(128);not null;index" json:"name"`
	Description string         `gorm:"type:varchar(512)" json:"description"`
	CreatedAt   time.Time      `json:"createdAt"`
	UpdatedAt   time.Time      `json:"updatedAt"`
	DeletedAt   gorm.DeletedAt `gorm:"index" json:"-"`
}

Network 是 MC 群组服的非独占软标签(ADR-007):仅供 UI 分组/筛选/批量运维, 一个实例可属于多个 network;真实路由只由 server_registrations 驱动,network 不做归属容器。 删除 network 不影响成员实例与其 server_registrations。

func (*Network) BeforeCreate

func (n *Network) BeforeCreate(tx *gorm.DB) error

BeforeCreate 创建前自动生成 UUID。

type NetworkMember

type NetworkMember struct {
	ID         uint      `gorm:"primaryKey" json:"id"`
	NetworkID  uint      `gorm:"not null;index;uniqueIndex:idx_netmember_net_inst" json:"networkId"`
	InstanceID uint      `gorm:"not null;index;uniqueIndex:idx_netmember_net_inst" json:"instanceId"`
	CreatedAt  time.Time `json:"createdAt"`
}

NetworkMember 群组成员关联(Network M:N Instance)。 删除 network 时一并硬删除其成员关系,但不触及实例与 server_registrations。

type Node

type Node struct {
	ID   uint   `gorm:"primaryKey" json:"id"`
	UUID string `gorm:"type:char(36);uniqueIndex;not null" json:"uuid"`
	// Name 节点名(人类可读标签)。身份由 UUID 锚定(见 ADR-039),name 仅为可变标签,
	// 但活跃节点间名字唯一:唯一性由 database.AutoMigrate 建的「部分唯一索引」
	// (仅约束 deleted_at IS NULL 的活跃行)强制,软删除节点可释放其名供新节点复用。
	Name        string     `gorm:"type:varchar(128);not null" json:"name"`
	Host        string     `gorm:"type:varchar(256);not null" json:"host"`
	GRPCPort    int        `gorm:"column:grpc_port;not null" json:"grpcPort"`
	WSPort      int        `gorm:"not null" json:"wsPort"`
	Secret      string     `gorm:"type:varchar(128);not null" json:"-"`
	Status      NodeStatus `gorm:"default:0" json:"status"`
	OS          string     `gorm:"type:varchar(64)" json:"os"`
	Arch        string     `gorm:"type:varchar(32)" json:"arch"`
	CPUCores    int        `json:"cpuCores"`
	MemoryMB    int64      `json:"memoryMb"`
	DiskTotalMB int64      `json:"diskTotalMb"`
	CPUUsage    float32    `gorm:"default:0" json:"cpuUsage"`
	MemoryUsage float32    `gorm:"default:0" json:"memoryUsage"`
	DiskUsage   float32    `gorm:"default:0" json:"diskUsage"`
	// Maintenance 维护模式(cordon)标记。为 true 时禁止新实例调度/分配到本节点,
	// 与 Status(在线/离线,由心跳驱动)正交:节点可同时「在线 + 维护中」。
	// 参见 FR-048。
	Maintenance      bool  `gorm:"default:false" json:"maintenance"`
	MemoryUsedMB     int64 `gorm:"default:0" json:"memoryUsedMb"`
	DiskUsedMB       int64 `gorm:"default:0" json:"diskUsedMb"`
	NetworkBytesSent int64 `gorm:"default:0" json:"networkBytesSent"`
	NetworkBytesRecv int64 `gorm:"default:0" json:"networkBytesRecv"`
	// LoadAvg1 节点 1 分钟 load average(FR-062,心跳驱动)。
	LoadAvg1 float64 `gorm:"default:0" json:"loadAvg1"`
	// ManagedRuntimeObservedAt 是 Worker 随已认证 Heartbeat 上报受管运行时快照的实际观测时间。
	// 运行时不可用或旧 Worker 未上报时,相关字段必须清空,避免陈旧值被当成当前资源。
	ManagedRuntimeObservedAt     *time.Time `json:"managedRuntimeObservedAt"`
	WorkerProcessRSSBytes        *int64     `json:"workerProcessRssBytes"`
	WorkerProcessCPUPct          *float64   `json:"workerProcessCpuPct"`
	BotWorkerRSSBytes            *int64     `json:"botWorkerRssBytes"`
	BotWorkerCPUPct              *float64   `json:"botWorkerCpuPct"`
	BotActiveCount               *int32     `json:"botActiveCount"`
	BotConnectingCount           *int32     `json:"botConnectingCount"`
	BotEventLoopP95MS            *float64   `json:"botEventLoopP95Ms"`
	BotCapacityMax               *int32     `json:"botCapacityMax"`
	BotCapacityUnavailableReason string     `gorm:"type:varchar(256)" json:"botCapacityUnavailableReason"`
	BotAvailable                 bool       `gorm:"default:false" json:"botAvailable"`
	BotUnavailableReason         string     `gorm:"type:varchar(256)" json:"botUnavailableReason"`
	// ProxyMode 节点出站代理模式(FR-185,见 ADR-043):
	//   inherit(默认)= 用平台全局默认代理(settings DB > control-plane.yml > env);
	//   custom         = 用本节点自定义 ProxyURL/ProxyNoProxy。
	// CP 据此算每节点期望代理经心跳响应下发,Worker 运行时重建出站 client(免登机器改 worker.yml)。
	ProxyMode string `gorm:"type:varchar(16);default:inherit" json:"proxyMode"`
	// ProxyURL 节点自定义代理地址(仅 ProxyMode=custom 有效;含凭据,API 响应/日志脱敏)。
	ProxyURL string `gorm:"type:varchar(512)" json:"-"`
	// ProxyNoProxy 节点自定义免代理列表(逗号分隔,仅 ProxyMode=custom 有效)。
	ProxyNoProxy  string     `gorm:"type:varchar(1024)" json:"proxyNoProxy"`
	LastHeartbeat *time.Time `json:"lastHeartbeat"`
	// RuntimeSyncedAt 上次运行时库存从 Worker 同步成功的时间(FR-301)。
	// JDKService.syncFromWorker 成功即刷新(含 JDK 面板隐式同步与运行时资产页手动刷新);
	// nil = 从未同步。运行时资产页据此显示「上次同步 <相对时间>」并识别陈旧节点。
	RuntimeSyncedAt *time.Time `json:"runtimeSyncedAt"`
	// ProbeVersionID 是该 Worker 后续新实例的 ServerProbe 默认版本;0 表示继承全局默认(FR-409)。
	ProbeVersionID uint           `gorm:"default:0;index" json:"probeVersionId"`
	CreatedAt      time.Time      `json:"createdAt"`
	UpdatedAt      time.Time      `json:"updatedAt"`
	DeletedAt      gorm.DeletedAt `gorm:"index" json:"-"`

	// TunnelConnected 该节点当前是否有活跃反向隧道(FR-281,见 ADR-066)。
	// 运行态字段不落库(gorm:"-"),由 NodeService 在响应时据 TunnelRegistry 填充:
	// true=指令经隧道下发(NAT/内网节点可用),false=直拨回退(老 worker/隧道重建窗口)。
	TunnelConnected bool `gorm:"-" json:"tunnelConnected"`
}

Node Worker Node 节点。

func (*Node) BeforeCreate

func (n *Node) BeforeCreate(tx *gorm.DB) error

BeforeCreate 创建前自动生成 UUID。

type NodeEnrollToken

type NodeEnrollToken struct {
	ID uint `gorm:"primaryKey" json:"id"`
	// TokenHash enrollment token 明文的 SHA-256 十六进制小写。库内不存明文。
	TokenHash string `gorm:"column:token_hash;type:char(64);uniqueIndex;not null" json:"-"`
	// TokenPrefix 明文前缀(如 jmet_ab12),仅供列表识别,不足以重建 token。
	TokenPrefix string `gorm:"column:token_prefix;type:varchar(16);not null" json:"tokenPrefix"`
	// NodeName 预设节点名;留空则注册时以 Worker 上报名生效。
	NodeName string `gorm:"type:varchar(128)" json:"nodeName"`
	// ExpiresAt 过期时间;到期即校验失败。
	ExpiresAt time.Time `gorm:"not null" json:"expiresAt"`
	// Used 是否已消费(一次性);true 即不可再用于注册。
	Used bool `gorm:"default:false;index;not null" json:"used"`
	// UsedAt 消费时间。
	UsedAt *time.Time `json:"usedAt"`
	// UsedByNode 消费该 token 注册成功的节点 UUID(审计/追溯用)。
	UsedByNode string `gorm:"type:char(36)" json:"usedByNode"`
	// Revoked 吊销标记(运营主动作废未消费 token);true 即校验失败。
	Revoked   bool      `gorm:"default:false;not null" json:"revoked"`
	CreatedAt time.Time `json:"createdAt"`
	// CreatedBy 签发该 token 的平台管理员用户 ID(审计用)。
	CreatedBy uint `json:"createdBy"`
}

NodeEnrollToken 节点 enrollment token:新增 Worker Node 时的一次性、限时准入凭据(FR-080,见 ADR-020)。

信任模型同构 FR-086 拉取密钥与 JM 既有运行时密钥惯例:落库只存明文的 SHA-256 哈希, 明文仅签发时一次性返回、不可二次读取。Worker 注册时经 gRPC metadata 携带明文, CP 在 Register 内校验(存在 + 未过期 + 未消费 + 未吊销)并原子标记 Used(一次性)。 enrollment token 只对「新节点首次落库」设门槛,已存在节点重注册不强制 token(ADR-020 §1)。

type NodeJDK

type NodeJDK struct {
	ID           uint      `gorm:"primaryKey" json:"id"`
	NodeID       uint      `gorm:"not null;index" json:"nodeId"`
	Vendor       string    `gorm:"type:varchar(64);not null" json:"vendor"`
	MajorVersion int       `gorm:"not null;index" json:"majorVersion"`
	Version      string    `gorm:"type:varchar(64);not null" json:"version"`
	Arch         string    `gorm:"type:varchar(32);not null" json:"arch"`
	Path         string    `gorm:"type:varchar(512);not null" json:"path"`
	Managed      bool      `gorm:"default:false" json:"managed"`
	CreatedAt    time.Time `json:"createdAt"`
	UpdatedAt    time.Time `json:"updatedAt"`
}

NodeJDK 节点托管或登记的 JDK。

type NodePMConfig

type NodePMConfig struct {
	ID     uint `gorm:"primaryKey" json:"id"`
	NodeID uint `gorm:"not null;uniqueIndex" json:"nodeId"`
	// PM 包管理器偏好:npm(默认)/ pnpm / yarn。pnpm/yarn 经 corepack enable 激活。
	PM string `gorm:"type:varchar(16);not null;default:npm" json:"pm"`
	// Registries JSON 数组([]PMRegistry):默认源用 scope="" 那条,其余为 @scope 域源。
	Registries string    `gorm:"type:text" json:"-"`
	CreatedAt  time.Time `json:"createdAt"`
	UpdatedAt  time.Time `json:"updatedAt"`
}

NodePMConfig 节点级包管理器与 registry 配置(FR-306,节点单例)。 承载 corepack 激活的 PM 偏好与多 registry(默认源 + @scope 域源 + 可选凭据); registries 以 JSON 数组存 []PMRegistry;token 入库明文(节点级配置密级同 proxy.url), 出参与日志脱敏。被 FR-307 全局包管理 / FR-308 bot-worker 依赖装全局消费。

type NodeRuntime

type NodeRuntime struct {
	ID     uint `gorm:"primaryKey" json:"id"`
	NodeID uint `gorm:"not null;index;uniqueIndex:uniq_node_runtime_type_path" json:"nodeId"`
	// Type 运行时类型(nodejs / python 预留;jdk 不落本表)。
	Type string `gorm:"type:varchar(16);not null;uniqueIndex:uniq_node_runtime_type_path" json:"type"`
	// Name 展示名(如 "Node.js 22")。
	Name string `gorm:"type:varchar(64);not null" json:"name"`
	// Version 完整版本(如 "22.17.0")。
	Version string `gorm:"type:varchar(64);not null" json:"version"`
	// Major 主版本(如 22),排序/选择用。
	Major int    `gorm:"not null;index" json:"major"`
	Arch  string `gorm:"type:varchar(32)" json:"arch"`
	Path  string `gorm:"type:varchar(512);not null;uniqueIndex:uniq_node_runtime_type_path" json:"path"`
	// Managed 是否平台托管(波1 登记均为外部发现 false;FR-299 安装器落 true)。
	Managed   bool      `gorm:"default:false" json:"managed"`
	CreatedAt time.Time `json:"createdAt"`
	UpdatedAt time.Time `json:"updatedAt"`
}

NodeRuntime 节点登记/托管的非 JDK 运行时(FR-298 节点运行时库)。 JDK 沿用 node_jdks 表不迁移(实例外键 instances.jdk_id 零变更);本表承载 nodejs / python(预留)等其它类型,读侧与 node_jdks 拼成统一 Runtime 视图。

type NodeStatus

type NodeStatus int

NodeStatus 节点状态。

const (
	NodeStatusOffline  NodeStatus = 0 // 离线
	NodeStatusOnline   NodeStatus = 1 // 在线
	NodeStatusStarting NodeStatus = 2 // 启动中
)

type Notification

type Notification struct {
	ID     uint              `gorm:"primaryKey" json:"id"`
	UserID uint              `gorm:"index;not null" json:"userId"` // 收件人
	Level  NotificationLevel `gorm:"type:varchar(16);not null;default:info" json:"level"`
	Title  string            `gorm:"type:varchar(256);not null" json:"title"`
	Body   string            `gorm:"type:text" json:"body"`
	// TaskID 关联任务的业务 ID(可空,非任务类通知留空)。
	TaskID string `gorm:"type:varchar(64);index" json:"taskId,omitempty"`
	// ReadAt 已读时间,nil 表示未读。
	ReadAt    *time.Time `json:"readAt,omitempty"`
	CreatedAt time.Time  `json:"createdAt"`
}

Notification 站内信。一条投递给某用户的消息,可关联到产生它的任务(见 ADR-040)。

type NotificationLevel

type NotificationLevel string

NotificationLevel 站内信级别。

const (
	// NotificationLevelInfo 一般信息。
	NotificationLevelInfo NotificationLevel = "info"
	// NotificationLevelSuccess 成功通知(如任务完成)。
	NotificationLevelSuccess NotificationLevel = "success"
	// NotificationLevelWarning 警告。
	NotificationLevelWarning NotificationLevel = "warning"
	// NotificationLevelError 失败 / 错误通知(如任务失败)。
	NotificationLevelError NotificationLevel = "error"
)

type OrphanRuntime added in v0.20.0

type OrphanRuntime struct {
	ID           uint   `gorm:"primaryKey" json:"id"`
	UUID         string `gorm:"type:char(36);uniqueIndex;not null" json:"uuid"`
	NodeUUID     string `gorm:"type:char(36);not null;index:idx_orphan_node_inst,priority:1" json:"nodeUuid"`
	InstanceUUID string `gorm:"type:char(36);not null;index:idx_orphan_node_inst,priority:2" json:"instanceUuid"`
	// WorkerState 最近一次心跳上报的状态摘要(RUNNING/STOPPED/…)。
	WorkerState string `gorm:"type:varchar(32)" json:"workerState"`
	// WorkerPID 最近一次心跳上报的进程 PID(0=未知)。
	// 列名显式 worker_pid:避免 GORM 把 PID 缩写蛇形化为 worker_p_id(同 grpc_port 先例)。
	WorkerPID   int                 `gorm:"column:worker_pid;default:0" json:"workerPid"`
	Status      OrphanRuntimeStatus `gorm:"type:varchar(32);not null;index;default:pending" json:"status"`
	FirstSeenAt time.Time           `gorm:"not null;index" json:"firstSeenAt"`
	LastSeenAt  time.Time           `gorm:"not null" json:"lastSeenAt"`
	// DisposedAt 处置完成时刻(自动或手动)。
	DisposedAt *time.Time `json:"disposedAt,omitempty"`
	// DisposeMode auto | manual;未处置为空。
	DisposeMode string `gorm:"type:varchar(16)" json:"disposeMode,omitempty"`
	// LastError 最近一次自动/手动处置失败原因(成功后清空)。
	LastError string    `gorm:"type:varchar(512)" json:"lastError,omitempty"`
	CreatedAt time.Time `json:"createdAt"`
	UpdatedAt time.Time `json:"updatedAt"`
}

OrphanRuntime 记录 Worker 有、CP 无实例记录的无主运行时(FR-326 反向对账)。 不重建业务实例,仅跟踪发现/宽限/处置;处置后终态保留供列表与审计对照。

func (*OrphanRuntime) BeforeCreate added in v0.20.0

func (o *OrphanRuntime) BeforeCreate(tx *gorm.DB) error

BeforeCreate 创建前自动生成 UUID。

type OrphanRuntimeStatus added in v0.20.0

type OrphanRuntimeStatus string

OrphanRuntimeStatus 无主运行时处置状态(FR-326)。

const (
	// OrphanRuntimePending 首次发现,宽限观察中。
	OrphanRuntimePending OrphanRuntimeStatus = "pending"
	// OrphanRuntimeConfirmed 宽限期已过,待自动/手动处置(auto_dispose 关时停在此态)。
	OrphanRuntimeConfirmed OrphanRuntimeStatus = "confirmed"
	// OrphanRuntimeDisposed 已下发并完成处置(进程停、Worker 本地运行态已清)。
	OrphanRuntimeDisposed OrphanRuntimeStatus = "disposed"
	// OrphanRuntimeCancelled 宽限期内 CP 又出现对应实例记录,取消处置。
	OrphanRuntimeCancelled OrphanRuntimeStatus = "cancelled"
)

type PMRegistry

type PMRegistry struct {
	Name  string `json:"name"`  // 展示名(可选)
	URL   string `json:"url"`   // http(s) registry 地址
	Scope string `json:"scope"` // 空=默认源;非空=@<scope> 域源
	Token string `json:"token"` // 可选凭据(出参脱敏)
}

PMRegistry 单条 registry 配置。scope 为空表示默认 registry;非空为 @scope 域源(不含 @ 前缀由前端约定)。 Token 为可选凭据(写入 .npmrc 的 _authToken),API 出参脱敏。

type PlatformSetting

type PlatformSetting struct {
	// Key 配置键,与 SettingsService 白名单一致(如 log.level、graceful_stop.timeout)。
	Key string `gorm:"type:varchar(128);primaryKey" json:"key"`
	// Value 覆盖值的文本表示(按键各自的语义解析,如 duration 文本、整数文本)。
	Value     string    `gorm:"type:text" json:"value"`
	UpdatedAt time.Time `json:"updatedAt"`
}

PlatformSetting 平台配置的 DB 覆盖项(FR-063 / ADR-015)。

只存「被显式覆盖过的白名单键」:未覆盖的键不落库,沿用 env/YAML 基线。 生效优先级 DB 覆盖 > 环境变量 > YAML 默认,由 SettingsService 解析有效配置时叠加。

type ProcessMetricSnapshot

type ProcessMetricSnapshot struct {
	ID uint `gorm:"primaryKey" json:"id"`
	// NodeUUID 所属节点。
	NodeUUID string `gorm:"type:varchar(64);not null;index:idx_process_metric_node_sampled,priority:1" json:"nodeUuid"`
	// InstanceUUID 受管实例 UUID。
	InstanceUUID string `gorm:"type:varchar(64);not null;index:idx_process_metric_instance_sampled,priority:1" json:"instanceUuid"`
	// PID 显式列名 pid:避免 GORM 把 PID 缩写蛇形化为 p_id,与 managedProcessHistory 的
	// WHERE pid = ? 查询对齐(真机验收 FR-407 抓到:SQL logic error: no such column: pid)。
	PID              int32     `gorm:"column:pid;not null" json:"pid"`
	Name             string    `gorm:"type:varchar(128)" json:"name"`
	CPUPercent       float64   `json:"cpuPercent"`
	RSSBytes         uint64    `json:"rssBytes"`
	ReadBytesPerSec  uint64    `json:"readBytesPerSec"`
	WriteBytesPerSec uint64    `json:"writeBytesPerSec"`
	User             string    `gorm:"type:varchar(128)" json:"user"`
	CommandSummary   string    `gorm:"type:varchar(160)" json:"commandSummary"`
	SampledAt        time.Time `` /* 134-byte string literal not displayed */
	CreatedAt        time.Time `json:"createdAt"`
}

ProcessMetricSnapshot 受管实例进程 TOPN 短期快照(FR-170)。

type ProcessType

type ProcessType string

ProcessType 启动方式。

const (
	ProcessTypeDirect ProcessType = "direct"
	ProcessTypeDaemon ProcessType = "daemon"
	ProcessTypeDocker ProcessType = "docker"
	ProcessTypeRCON   ProcessType = "rcon"
)

type Schedule

type Schedule struct {
	ID         uint           `gorm:"primaryKey" json:"id"`
	UUID       string         `gorm:"type:char(36);uniqueIndex;not null" json:"uuid"`
	InstanceID uint           `gorm:"not null;index" json:"instanceId"`
	Name       string         `gorm:"type:varchar(128);not null" json:"name"`
	CronExpr   string         `gorm:"type:varchar(64);not null" json:"cronExpr"`
	Action     string         `gorm:"type:varchar(32);not null" json:"action"` // start, stop, restart, command, backup
	Payload    string         `gorm:"type:text" json:"payload"`                // JSON: command text, etc.
	Enabled    bool           `gorm:"default:true" json:"enabled"`
	LastRun    *time.Time     `json:"lastRun"`
	CreatedAt  time.Time      `json:"createdAt"`
	UpdatedAt  time.Time      `json:"updatedAt"`
	DeletedAt  gorm.DeletedAt `gorm:"index" json:"-"`
}

Schedule 定时任务。

func (*Schedule) BeforeCreate

func (s *Schedule) BeforeCreate(tx *gorm.DB) error

BeforeCreate 创建前自动生成 UUID。

type ScheduleExecutionLog

type ScheduleExecutionLog struct {
	ID         uint              `gorm:"primaryKey" json:"id"`
	ScheduleID uint              `gorm:"not null;index" json:"scheduleId"`
	Action     string            `gorm:"type:varchar(32);not null" json:"action"`
	Status     ScheduleLogStatus `gorm:"type:varchar(16);not null" json:"status"`
	Error      string            `gorm:"type:text" json:"error"`
	StartedAt  time.Time         `json:"startedAt"`
	FinishedAt time.Time         `json:"finishedAt"`
	Schedule   Schedule          `gorm:"foreignKey:ScheduleID" json:"schedule,omitempty"`
}

ScheduleExecutionLog 定时任务执行日志。

func (*ScheduleExecutionLog) BeforeCreate

func (l *ScheduleExecutionLog) BeforeCreate(tx *gorm.DB) error

BeforeCreate 预留钩子。

type ScheduleLogStatus

type ScheduleLogStatus string

ScheduleLogStatus 定时任务执行状态。

const (
	ScheduleLogStatusSuccess ScheduleLogStatus = "success"
	ScheduleLogStatusFailed  ScheduleLogStatus = "failed"
)

type SelfUpdateCheckCache

type SelfUpdateCheckCache struct {
	// ID 固定为 1:本表为单行覆盖式缓存,不按时间累积多行。
	ID uint `gorm:"primaryKey" json:"id"`
	// ResultJSON 是上次成功 CheckResult 的 JSON 序列化(含 latestVersion/source/notes/各组件状态)。
	ResultJSON string `gorm:"type:text" json:"-"`
	// Source 冗余存更新源标识(github:owner/repo@channel | feed),便于诊断不必解 blob。
	Source string `gorm:"type:varchar(255)" json:"source"`
	// CheckedAt 该次成功检查的时刻(UTC),供前端展示「上次检查:<相对时间>」。
	CheckedAt time.Time `json:"checkedAt"`
}

SelfUpdateCheckCache 持久化最近一次「成功」检查更新的结果(FR-186,增强 FR-182/FR-081)。

仅一行(ID 固定 1 单行表):每次 live 检查成功后 upsert 覆盖。整段 CheckResult 序列化为 JSON blob 存 ResultJSON,而非拆字段——CheckResult 随版本演进加字段时无需迁移,反序列化 缺字段自然降级(见 spec §6 风险)。进系统更新页直接读此缓存即时回显,后台再静默触发 live 刷新; 刷新失败保留旧缓存(不清行),页面据 CheckedAt 标注「上次检查时间」。

type ServerRegistration

type ServerRegistration struct {
	ID uint `gorm:"primaryKey" json:"id"`
	// ProxyID 代理实例 ID(role=proxy)。
	ProxyID uint `gorm:"not null;index;uniqueIndex:idx_reg_proxy_alias" json:"proxyId"`
	// BackendID 后端实例 ID(role=backend)。
	BackendID uint `gorm:"not null;index" json:"backendId"`
	// Alias 在该代理 servers{} 中的本地名([a-z0-9_-]{1,64}),同一代理内唯一。
	Alias string `gorm:"type:varchar(64);not null;uniqueIndex:idx_reg_proxy_alias" json:"alias"`
	// Priority try/优先级顺序,小值优先。
	Priority int `gorm:"default:0" json:"priority"`
	// ForcedHost 可选 forced-host 域名 → 该后端。
	ForcedHost string `gorm:"type:varchar(255)" json:"forcedHost"`
	// Restricted Velocity restricted:仅可经 forced-host/命令访问。
	Restricted bool `gorm:"default:false" json:"restricted"`
	// Enabled 是否启用(写入代理配置时跳过 disabled)。
	Enabled   bool      `gorm:"default:true" json:"enabled"`
	CreatedAt time.Time `json:"createdAt"`
	UpdatedAt time.Time `json:"updatedAt"`
}

ServerRegistration 表示一个后端子服注册进一个代理(proxy↔backend 的 M:N,ADR-007)。 每条注册携带「代理内本地属性」:在该代理 servers{} 中的 alias、try/优先级、forced-host、restricted。 同一 backend 可注册进多个 proxy;同一代理内 alias 唯一。

本模型只承载关系数据;将注册「写入代理配置 + Velocity secret 下发」属 FR-035。

type Task

type Task struct {
	ID     uint   `gorm:"primaryKey" json:"id"`
	TaskID string `gorm:"type:varchar(64);uniqueIndex;not null" json:"taskId"`
	NodeID uint   `gorm:"index" json:"nodeId"`
	Kind   string `gorm:"type:varchar(64);not null;index" json:"kind"`
	// InstanceID 关联实例(provision/import/clone 等实例级长操作任务用,FR-319/FR-323);0=无关联。
	// 启动闸据此拦截「工作目录尚未就绪就点启动」的实例(在途任务未终态即拒启)。
	InstanceID uint `gorm:"index" json:"instanceId"`
	// State 见 TaskState;以字符串存储便于跨进程一致。
	State    TaskState `gorm:"type:varchar(16);not null;default:pending;index" json:"state"`
	Progress int       `gorm:"not null;default:0" json:"progress"` // 0~100
	Title    string    `gorm:"type:varchar(256)" json:"title"`
	Detail   string    `gorm:"type:varchar(1024)" json:"detail"` // 发起参数摘要
	Error    string    `gorm:"type:text" json:"error"`           // 失败原因(仅 failed)
	Result   string    `gorm:"type:text" json:"result"`          // 成功结果 JSON(如安装出的 JDK 信息)
	// CancelRequested 标记用户已请求强制停止(FR-227):CP 据此每拍经心跳向节点下发 cancel_task_ids,
	// 直到 Worker 确认中断并上报 canceled 终态。pending 未起 / 节点离线时直接置 canceled、不设此标记。
	CancelRequested bool `gorm:"not null;default:false" json:"cancelRequested"`
	// CreatedBy 发起用户 ID,用于归属隔离与完成站内信收件人(0=系统)。
	CreatedBy uint      `gorm:"index" json:"createdBy"`
	CreatedAt time.Time `json:"createdAt"`
	UpdatedAt time.Time `json:"updatedAt"`
}

Task 一条长耗时跨进程任务(如 JDK 安装)。 task_id 为业务唯一键(UUID),Worker 经心跳上报进度时据此 upsert(见 ADR-040)。

type TaskLog

type TaskLog struct {
	ID     uint      `gorm:"primaryKey" json:"id"`
	TaskID string    `gorm:"type:varchar(64);not null;index:idx_tasklog_task_seq,unique,priority:1" json:"taskId"`
	Seq    int       `gorm:"not null;index:idx_tasklog_task_seq,unique,priority:2" json:"seq"`
	Line   string    `gorm:"type:text" json:"line"`
	TS     time.Time `json:"ts"`
}

TaskLog 任务的一行滚动日志。按 task_id + seq 幂等去重(心跳可能重复携带同一行)。

type TaskState

type TaskState string

TaskState 任务状态。pending/running 为非终态,succeeded/failed 为终态。

const (
	// TaskStatePending 任务已创建,尚未在 Worker 上开始执行。
	TaskStatePending TaskState = "pending"
	// TaskStateRunning 任务执行中。
	TaskStateRunning TaskState = "running"
	// TaskStateSucceeded 任务成功完成(终态)。
	TaskStateSucceeded TaskState = "succeeded"
	// TaskStateFailed 任务失败(终态)。
	TaskStateFailed TaskState = "failed"
	// TaskStateCanceled 任务被强制停止(终态,FR-227)。Worker 操作真被中断后由心跳上报。
	TaskStateCanceled TaskState = "canceled"
)

func (TaskState) IsTerminal

func (s TaskState) IsTerminal() bool

IsTerminal 报告状态是否为终态(成功/失败/已取消)。

type Template

type Template struct {
	ID             uint           `gorm:"primaryKey" json:"id"`
	UUID           string         `gorm:"type:char(36);uniqueIndex;not null" json:"uuid"`
	Name           string         `gorm:"type:varchar(128);not null" json:"name"`
	Type           string         `gorm:"type:varchar(64);not null" json:"type"` // minecraft_java, etc.
	Description    string         `gorm:"type:varchar(512)" json:"description"`
	StartCommand   string         `gorm:"type:varchar(1024)" json:"startCommand"`
	DefaultWorkDir string         `gorm:"type:varchar(512)" json:"defaultWorkDir"`
	DownloadURL    string         `gorm:"type:varchar(512)" json:"downloadUrl"`
	ConfigFiles    string         `gorm:"type:text" json:"configFiles"` // JSON
	CreatedAt      time.Time      `json:"createdAt"`
	UpdatedAt      time.Time      `json:"updatedAt"`
	DeletedAt      gorm.DeletedAt `gorm:"index" json:"-"`
}

Template 服务端模板。

func (*Template) BeforeCreate

func (t *Template) BeforeCreate(tx *gorm.DB) error

BeforeCreate 创建前自动生成 UUID。

type User

type User struct {
	ID       uint       `gorm:"primaryKey" json:"id"`
	UUID     string     `gorm:"type:char(36);uniqueIndex;not null" json:"uuid"`
	Username string     `gorm:"type:varchar(64);uniqueIndex;not null" json:"username"`
	Password string     `gorm:"type:varchar(128);not null" json:"-"`
	Role     UserRole   `gorm:"default:0" json:"role"`
	Status   UserStatus `gorm:"default:0" json:"status"`
	// AuthVersion 在密码、状态或角色发生安全相关变更时递增,用于立即吊销旧会话。
	AuthVersion uint           `gorm:"not null;default:0" json:"-"`
	CreatedAt   time.Time      `json:"createdAt"`
	UpdatedAt   time.Time      `json:"updatedAt"`
	DeletedAt   gorm.DeletedAt `gorm:"index" json:"-"`
}

User 用户模型。

func (*User) BeforeCreate

func (u *User) BeforeCreate(tx *gorm.DB) error

BeforeCreate 创建前自动生成 UUID。

type UserInvitation added in v0.21.0

type UserInvitation struct {
	ID            uint           `gorm:"primaryKey" json:"id"`
	Email         string         `gorm:"type:varchar(254);not null;index" json:"email"`
	TokenHash     []byte         `gorm:"type:binary(32);uniqueIndex;not null" json:"-"`
	TokenPrefix   string         `gorm:"type:varchar(16);not null" json:"-"`
	Role          UserRole       `gorm:"not null;default:0" json:"role"`
	ExpiresAt     time.Time      `gorm:"not null;index" json:"expiresAt"`
	CreatedByID   uint           `gorm:"not null;index" json:"createdBy"`
	UsedAt        *time.Time     `json:"usedAt"`
	RevokedAt     *time.Time     `json:"revokedAt"`
	EmailSentAt   *time.Time     `json:"emailSentAt"`
	EmailDelivery string         `gorm:"type:varchar(32);not null;default:not_configured" json:"emailDelivery"`
	CreatedAt     time.Time      `json:"createdAt"`
	UpdatedAt     time.Time      `json:"-"`
	DeletedAt     gorm.DeletedAt `gorm:"index" json:"-"`
}

UserInvitation 记录由平台管理员签发的一次性成员邀请。 明文令牌只在签发响应与邮件正文中短暂存在,数据库仅保存哈希。

type UserRole

type UserRole int

UserRole 用户角色。

const (
	RoleMember        UserRole = 0  // 组成员
	RoleGroupAdmin    UserRole = 1  // 组管理员
	RolePlatformAdmin UserRole = 10 // 平台管理员
)

type UserStatus

type UserStatus int

UserStatus 用户状态。

const (
	UserStatusActive   UserStatus = 0 // 启用
	UserStatusDisabled UserStatus = 1 // 禁用
)

Jump to

Keyboard shortcuts

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