package models import ( "time" "github.com/google/uuid" ) type User struct { ID uuid.UUID `json:"id"` Email string `json:"email"` PasswordHash string `json:"-"` Name string `json:"name"` Role string `json:"role"` CreatedAt time.Time `json:"created_at"` } type Protocol struct { ID uuid.UUID `json:"id"` Code string `json:"code"` Name string `json:"name"` Description string `json:"description"` Port int `json:"port"` Enabled bool `json:"enabled"` SortOrder int `json:"sort_order"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` InstalledOn []NodeProtoRef `json:"installed_on,omitempty"` EnabledOn []NodeProtoRef `json:"enabled_on,omitempty"` } type NodeProtoRef struct { NodeID uuid.UUID `json:"node_id"` NodeName string `json:"node_name"` Host string `json:"host"` Status NodeStatus `json:"status"` } type NodeProtocol struct { NodeID uuid.UUID `json:"node_id"` ProtocolID uuid.UUID `json:"protocol_id"` ProtocolCode string `json:"protocol_code"` ProtocolName string `json:"protocol_name"` Port int `json:"port"` Installed bool `json:"installed"` Enabled bool `json:"enabled"` UpdatedAt time.Time `json:"updated_at"` } func (p Protocol) EnabledLabel() string { if p.Enabled { return "Включён" } return "Выключен" } func (p Protocol) InstallCount() int { return len(p.InstalledOn) } func (p Protocol) ActiveCount() int { return len(p.EnabledOn) } type NodeStatus string const ( NodeStatusPending NodeStatus = "pending" NodeStatusInstalling NodeStatus = "installing" NodeStatusOnline NodeStatus = "online" NodeStatusOffline NodeStatus = "offline" NodeStatusError NodeStatus = "error" ) type Node struct { ID uuid.UUID `json:"id"` Name string `json:"name"` Host string `json:"host"` SSHPort int `json:"ssh_port"` SSHUser string `json:"ssh_user"` SSHAuthType string `json:"ssh_auth_type"` // password | key SSHSecretEnc string `json:"-"` NodePort int `json:"node_port"` SecretKey string `json:"-"` ProfileID *uuid.UUID `json:"profile_id,omitempty"` ProfileName string `json:"profile_name,omitempty"` Status NodeStatus `json:"status"` InstallMode string `json:"install_mode"` // auto | manual LastError string `json:"last_error"` InstallLog string `json:"install_log"` RuntimeLog string `json:"runtime_log"` AgentVersion string `json:"agent_version"` LastSeenAt *time.Time `json:"last_seen_at,omitempty"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } func (n Node) StatusLabel() string { switch n.Status { case NodeStatusOnline: return "Online" case NodeStatusInstalling: return "Установка" case NodeStatusOffline: return "Offline" case NodeStatusError: return "Ошибка" default: return "Ожидание" } } func (n Node) ProfileIDString() string { if n.ProfileID == nil { return "" } return n.ProfileID.String() } type ConfigProfile struct { ID uuid.UUID `json:"id"` Name string `json:"name"` Description string `json:"description"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` InboundCount int `json:"inbound_count"` NodeCount int `json:"node_count"` Inbounds []Inbound `json:"inbounds,omitempty"` } type Inbound struct { ID uuid.UUID `json:"id"` ProfileID uuid.UUID `json:"profile_id"` Tag string `json:"tag"` ProtocolID uuid.UUID `json:"protocol_id"` ProtocolCode string `json:"protocol_code"` ProtocolName string `json:"protocol_name"` Port int `json:"port"` Network string `json:"network"` // tcp, ws, grpc, quic, udp Security string `json:"security"` // none, tls, reality Listen string `json:"listen"` Enabled bool `json:"enabled"` // definition enabled in profile SortOrder int `json:"sort_order"` Remark string `json:"remark"` // Transport / TLS / Reality / SS settings Path string `json:"path"` Host string `json:"host"` SNI string `json:"sni"` Fingerprint string `json:"fingerprint"` Flow string `json:"flow"` ALPN string `json:"alpn"` RealityDest string `json:"reality_dest"` RealityServerNames string `json:"reality_server_names"` RealityPrivateKey string `json:"reality_private_key"` RealityPublicKey string `json:"reality_public_key"` RealityShortID string `json:"reality_short_id"` RealityShortIDs string `json:"reality_short_ids"` SpiderX string `json:"spider_x"` RealityXver int `json:"reality_xver"` SSMethod string `json:"ss_method"` Password string `json:"password"` FallbackDest string `json:"fallback_dest"` FallbacksJSON string `json:"fallbacks_json"` TLSCertPEM string `json:"tls_cert_pem"` TLSKeyPEM string `json:"tls_key_pem"` Sniffing bool `json:"sniffing"` SniffingRouteOnly bool `json:"sniffing_route_only"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` // Per-node activation when listed under a node NodeEnabled bool `json:"node_enabled,omitempty"` } type DashboardStats struct { ProtocolsTotal int ProtocolsEnabled int AdminsTotal int NodesTotal int NodesOnline int ProfilesTotal int ClientsTotal int ClientsActive int } type ClientStatus string const ( ClientStatusActive ClientStatus = "active" ClientStatusDisabled ClientStatus = "disabled" ClientStatusExpired ClientStatus = "expired" ) type Client struct { ID uuid.UUID `json:"id"` Username string `json:"username"` Email string `json:"email"` UUID uuid.UUID `json:"uuid"` // VLESS/VMess user id Status ClientStatus `json:"status"` TrafficLimitBytes int64 `json:"traffic_limit_bytes"` // 0 = unlimited TrafficUsedBytes int64 `json:"traffic_used_bytes"` ExpireAt *time.Time `json:"expire_at,omitempty"` SubToken string `json:"sub_token"` Note string `json:"note"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` InboundIDs []uuid.UUID `json:"inbound_ids,omitempty"` InboundCount int `json:"inbound_count"` } func (c Client) StatusLabel() string { switch c.Status { case ClientStatusActive: return "Активен" case ClientStatusDisabled: return "Отключён" case ClientStatusExpired: return "Истёк" default: return string(c.Status) } } func (c Client) IsActive() bool { if c.Status != ClientStatusActive { return false } if c.ExpireAt != nil && time.Now().After(*c.ExpireAt) { return false } if c.TrafficLimitBytes > 0 && c.TrafficUsedBytes >= c.TrafficLimitBytes { return false } return true } func (c Client) TrafficLimitGB() float64 { if c.TrafficLimitBytes <= 0 { return 0 } return float64(c.TrafficLimitBytes) / (1024 * 1024 * 1024) } func (c Client) HasInbound(id uuid.UUID) bool { for _, x := range c.InboundIDs { if x == id { return true } } return false } // SubHost is one subscription endpoint (inbound on a node), Remnawave-style host. type SubHost struct { InboundID uuid.UUID `json:"inbound_id"` Tag string `json:"tag"` Remark string `json:"remark"` ProtocolCode string `json:"protocol"` ProtocolName string `json:"protocol_name"` Port int `json:"port"` Network string `json:"network"` Security string `json:"security"` Path string `json:"path,omitempty"` HostHeader string `json:"host_header,omitempty"` SNI string `json:"sni,omitempty"` Fingerprint string `json:"fingerprint,omitempty"` Flow string `json:"flow,omitempty"` ALPN string `json:"alpn,omitempty"` PublicKey string `json:"public_key,omitempty"` ShortID string `json:"short_id,omitempty"` SpiderX string `json:"spider_x,omitempty"` SSMethod string `json:"ss_method,omitempty"` Password string `json:"password,omitempty"` Address string `json:"address"` NodeName string `json:"node_name"` NodeOnline bool `json:"node_online"` Available bool `json:"available"` Link string `json:"link"` } func (h SubHost) Title() string { if h.Remark != "" { return h.Remark } if h.NodeName != "" { return h.Tag + " · " + h.NodeName } return h.Tag } type SubscriptionInfo struct { Client Client `json:"client"` Hosts []SubHost `json:"hosts"` Links []string `json:"links"` ExpireUnix int64 `json:"expire_unix"` }