diff --git a/server/internal/database/database.go b/server/internal/database/database.go index 030e1f5..85385ec 100644 --- a/server/internal/database/database.go +++ b/server/internal/database/database.go @@ -23,7 +23,7 @@ func Open(cfg config.DatabaseConfig, logger *zap.Logger) (*gorm.DB, error) { return nil, fmt.Errorf("open sqlite: %w", err) } - if err := db.AutoMigrate(&model.User{}, &model.SystemConfig{}, &model.StorageTarget{}, &model.OAuthSession{}, &model.BackupTask{}, &model.BackupRecord{}, &model.Notification{}, &model.Node{}, &model.BackupTaskStorageTarget{}, &model.AuditLog{}, &model.AgentCommand{}); err != nil { + if err := db.AutoMigrate(&model.User{}, &model.SystemConfig{}, &model.StorageTarget{}, &model.OAuthSession{}, &model.BackupTask{}, &model.BackupRecord{}, &model.Notification{}, &model.Node{}, &model.BackupTaskStorageTarget{}, &model.AuditLog{}, &model.AgentCommand{}, &model.AgentInstallToken{}); err != nil { return nil, fmt.Errorf("migrate schema: %w", err) } diff --git a/server/internal/model/agent_install_token.go b/server/internal/model/agent_install_token.go new file mode 100644 index 0000000..f211d7e --- /dev/null +++ b/server/internal/model/agent_install_token.go @@ -0,0 +1,36 @@ +package model + +import "time" + +// AgentInstallToken 一次性安装令牌,用于 /install/:token 公开端点。 +// +// 生命周期:创建 → 消费(ConsumedAt 非空即作废)→ 超过 ExpiresAt 后被 GC 硬删除。 +type AgentInstallToken struct { + ID uint `gorm:"primaryKey" json:"id"` + Token string `gorm:"size:64;uniqueIndex;not null" json:"token"` + NodeID uint `gorm:"not null;index" json:"nodeId"` + Mode string `gorm:"size:16;not null" json:"mode"` // systemd|docker|foreground + Arch string `gorm:"size:16;not null" json:"arch"` // amd64|arm64|auto + AgentVer string `gorm:"size:32;not null" json:"agentVersion"` + DownloadSrc string `gorm:"size:16;not null;default:'github'" json:"downloadSrc"` + ExpiresAt time.Time `gorm:"not null;index" json:"expiresAt"` + ConsumedAt *time.Time `json:"consumedAt,omitempty"` + CreatedByID uint `gorm:"not null" json:"createdById"` + CreatedAt time.Time `json:"createdAt"` +} + +func (AgentInstallToken) TableName() string { return "agent_install_tokens" } + +// 合法模式/架构/下载源常量 +const ( + InstallModeSystemd = "systemd" + InstallModeDocker = "docker" + InstallModeForeground = "foreground" + + InstallArchAmd64 = "amd64" + InstallArchArm64 = "arm64" + InstallArchAuto = "auto" + + InstallSourceGitHub = "github" + InstallSourceGhproxy = "ghproxy" +) diff --git a/server/internal/model/node.go b/server/internal/model/node.go index 87aca51..3c81335 100644 --- a/server/internal/model/node.go +++ b/server/internal/model/node.go @@ -19,10 +19,12 @@ type Node struct { IsLocal bool `gorm:"not null;default:false" json:"isLocal"` OS string `gorm:"size:64" json:"os"` Arch string `gorm:"size:32" json:"arch"` - AgentVer string `gorm:"column:agent_version;size:32" json:"agentVersion"` - LastSeen time.Time `gorm:"column:last_seen" json:"lastSeen"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` + AgentVer string `gorm:"column:agent_version;size:32" json:"agentVersion"` + LastSeen time.Time `gorm:"column:last_seen" json:"lastSeen"` + PrevToken string `gorm:"size:128;index" json:"-"` + PrevTokenExpires *time.Time `gorm:"column:prev_token_expires" json:"-"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` } func (Node) TableName() string {