Browse Source

docs: add comments for all functions

mhsanaei 3 days ago
parent
commit
6ced549dea
63 changed files with 624 additions and 113 deletions
  1. 12 0
      config/config.go
  2. 11 0
      database/db.go
  3. 44 32
      database/model/model.go
  4. 19 1
      logger/logger.go
  5. 14 0
      main.go
  6. 9 0
      sub/sub.go
  7. 7 0
      sub/subController.go
  8. 3 0
      sub/subJsonService.go
  9. 7 0
      sub/subService.go
  10. 4 0
      util/common/err.go
  11. 1 0
      util/common/format.go
  12. 3 0
      util/common/multi_error.go
  13. 3 0
      util/crypto/crypto.go
  14. 5 2
      util/json_util/json.go
  15. 5 0
      util/random/random.go
  16. 3 0
      util/reflect_util/reflect.go
  17. 2 0
      util/sys/psutil.go
  18. 4 0
      util/sys/sys_linux.go
  19. 5 0
      util/sys/sys_windows.go
  20. 4 0
      web/controller/api.go
  21. 5 0
      web/controller/base.go
  22. 24 0
      web/controller/inbound.go
  23. 8 0
      web/controller/index.go
  24. 23 0
      web/controller/server.go
  25. 10 0
      web/controller/setting.go
  26. 8 0
      web/controller/util.go
  27. 10 0
      web/controller/xray_setting.go
  28. 7 0
      web/controller/xui.go
  29. 62 49
      web/entity/entity.go
  30. 10 3
      web/global/global.go
  31. 13 5
      web/global/hashStorage.go
  32. 2 0
      web/job/check_client_ip_job.go
  33. 3 1
      web/job/check_cpu_usage.go
  34. 3 1
      web/job/check_hash_storage.go
  35. 6 2
      web/job/check_xray_running_job.go
  36. 2 0
      web/job/clear_logs_job.go
  37. 4 0
      web/job/periodic_traffic_reset_job.go
  38. 6 3
      web/job/stats_notify_job.go
  39. 3 0
      web/job/xray_traffic_job.go
  40. 17 2
      web/locale/locale.go
  41. 6 0
      web/middleware/domainValidator.go
  42. 3 0
      web/middleware/redirect.go
  43. 10 0
      web/network/auto_https_conn.go
  44. 6 0
      web/network/auto_https_listener.go
  45. 19 0
      web/service/inbound.go
  46. 2 0
      web/service/outbound.go
  47. 2 0
      web/service/panel.go
  48. 11 4
      web/service/server.go
  49. 2 0
      web/service/setting.go
  50. 62 6
      web/service/tgbot.go
  51. 4 0
      web/service/user.go
  52. 2 0
      web/service/warp.go
  53. 15 1
      web/service/xray.go
  54. 2 0
      web/service/xray_setting.go
  55. 12 0
      web/session/session.go
  56. 19 1
      web/web.go
  57. 14 0
      xray/api.go
  58. 2 0
      xray/client_traffic.go
  59. 3 0
      xray/config.go
  60. 3 0
      xray/inbound.go
  61. 3 0
      xray/log_writer.go
  62. 29 0
      xray/process.go
  63. 2 0
      xray/traffic.go

+ 12 - 0
config/config.go

@@ -1,3 +1,5 @@
+// Package config provides configuration management utilities for the 3x-ui panel,
+// including version information, logging levels, database paths, and environment variable handling.
 package config
 package config
 
 
 import (
 import (
@@ -16,8 +18,10 @@ var version string
 //go:embed name
 //go:embed name
 var name string
 var name string
 
 
+// LogLevel represents the logging level for the application.
 type LogLevel string
 type LogLevel string
 
 
+// Logging level constants
 const (
 const (
 	Debug  LogLevel = "debug"
 	Debug  LogLevel = "debug"
 	Info   LogLevel = "info"
 	Info   LogLevel = "info"
@@ -26,14 +30,17 @@ const (
 	Error  LogLevel = "error"
 	Error  LogLevel = "error"
 )
 )
 
 
+// GetVersion returns the version string of the 3x-ui application.
 func GetVersion() string {
 func GetVersion() string {
 	return strings.TrimSpace(version)
 	return strings.TrimSpace(version)
 }
 }
 
 
+// GetName returns the name of the 3x-ui application.
 func GetName() string {
 func GetName() string {
 	return strings.TrimSpace(name)
 	return strings.TrimSpace(name)
 }
 }
 
 
+// GetLogLevel returns the current logging level based on environment variables or defaults to Info.
 func GetLogLevel() LogLevel {
 func GetLogLevel() LogLevel {
 	if IsDebug() {
 	if IsDebug() {
 		return Debug
 		return Debug
@@ -45,10 +52,12 @@ func GetLogLevel() LogLevel {
 	return LogLevel(logLevel)
 	return LogLevel(logLevel)
 }
 }
 
 
+// IsDebug returns true if debug mode is enabled via the XUI_DEBUG environment variable.
 func IsDebug() bool {
 func IsDebug() bool {
 	return os.Getenv("XUI_DEBUG") == "true"
 	return os.Getenv("XUI_DEBUG") == "true"
 }
 }
 
 
+// GetBinFolderPath returns the path to the binary folder, defaulting to "bin" if not set via XUI_BIN_FOLDER.
 func GetBinFolderPath() string {
 func GetBinFolderPath() string {
 	binFolderPath := os.Getenv("XUI_BIN_FOLDER")
 	binFolderPath := os.Getenv("XUI_BIN_FOLDER")
 	if binFolderPath == "" {
 	if binFolderPath == "" {
@@ -74,6 +83,7 @@ func getBaseDir() string {
 	return exeDir
 	return exeDir
 }
 }
 
 
+// GetDBFolderPath returns the path to the database folder based on environment variables or platform defaults.
 func GetDBFolderPath() string {
 func GetDBFolderPath() string {
 	dbFolderPath := os.Getenv("XUI_DB_FOLDER")
 	dbFolderPath := os.Getenv("XUI_DB_FOLDER")
 	if dbFolderPath != "" {
 	if dbFolderPath != "" {
@@ -85,10 +95,12 @@ func GetDBFolderPath() string {
 	return "/etc/x-ui"
 	return "/etc/x-ui"
 }
 }
 
 
+// GetDBPath returns the full path to the database file.
 func GetDBPath() string {
 func GetDBPath() string {
 	return fmt.Sprintf("%s/%s.db", GetDBFolderPath(), GetName())
 	return fmt.Sprintf("%s/%s.db", GetDBFolderPath(), GetName())
 }
 }
 
 
+// GetLogFolder returns the path to the log folder based on environment variables or platform defaults.
 func GetLogFolder() string {
 func GetLogFolder() string {
 	logFolderPath := os.Getenv("XUI_LOG_FOLDER")
 	logFolderPath := os.Getenv("XUI_LOG_FOLDER")
 	if logFolderPath != "" {
 	if logFolderPath != "" {

+ 11 - 0
database/db.go

@@ -1,3 +1,5 @@
+// Package database provides database initialization, migration, and management utilities
+// for the 3x-ui panel using GORM with SQLite.
 package database
 package database
 
 
 import (
 import (
@@ -45,6 +47,7 @@ func initModels() error {
 	return nil
 	return nil
 }
 }
 
 
+// initUser creates a default admin user if the users table is empty.
 func initUser() error {
 func initUser() error {
 	empty, err := isTableEmpty("users")
 	empty, err := isTableEmpty("users")
 	if err != nil {
 	if err != nil {
@@ -68,6 +71,7 @@ func initUser() error {
 	return nil
 	return nil
 }
 }
 
 
+// runSeeders migrates user passwords to bcrypt and records seeder execution to prevent re-running.
 func runSeeders(isUsersEmpty bool) error {
 func runSeeders(isUsersEmpty bool) error {
 	empty, err := isTableEmpty("history_of_seeders")
 	empty, err := isTableEmpty("history_of_seeders")
 	if err != nil {
 	if err != nil {
@@ -107,12 +111,14 @@ func runSeeders(isUsersEmpty bool) error {
 	return nil
 	return nil
 }
 }
 
 
+// isTableEmpty returns true if the named table contains zero rows.
 func isTableEmpty(tableName string) (bool, error) {
 func isTableEmpty(tableName string) (bool, error) {
 	var count int64
 	var count int64
 	err := db.Table(tableName).Count(&count).Error
 	err := db.Table(tableName).Count(&count).Error
 	return count == 0, err
 	return count == 0, err
 }
 }
 
 
+// InitDB sets up the database connection, migrates models, and runs seeders.
 func InitDB(dbPath string) error {
 func InitDB(dbPath string) error {
 	dir := path.Dir(dbPath)
 	dir := path.Dir(dbPath)
 	err := os.MkdirAll(dir, fs.ModePerm)
 	err := os.MkdirAll(dir, fs.ModePerm)
@@ -151,6 +157,7 @@ func InitDB(dbPath string) error {
 	return runSeeders(isUsersEmpty)
 	return runSeeders(isUsersEmpty)
 }
 }
 
 
+// CloseDB closes the database connection if it exists.
 func CloseDB() error {
 func CloseDB() error {
 	if db != nil {
 	if db != nil {
 		sqlDB, err := db.DB()
 		sqlDB, err := db.DB()
@@ -162,14 +169,17 @@ func CloseDB() error {
 	return nil
 	return nil
 }
 }
 
 
+// GetDB returns the global GORM database instance.
 func GetDB() *gorm.DB {
 func GetDB() *gorm.DB {
 	return db
 	return db
 }
 }
 
 
+// IsNotFound checks if the given error is a GORM record not found error.
 func IsNotFound(err error) bool {
 func IsNotFound(err error) bool {
 	return err == gorm.ErrRecordNotFound
 	return err == gorm.ErrRecordNotFound
 }
 }
 
 
+// IsSQLiteDB checks if the given file is a valid SQLite database by reading its signature.
 func IsSQLiteDB(file io.ReaderAt) (bool, error) {
 func IsSQLiteDB(file io.ReaderAt) (bool, error) {
 	signature := []byte("SQLite format 3\x00")
 	signature := []byte("SQLite format 3\x00")
 	buf := make([]byte, len(signature))
 	buf := make([]byte, len(signature))
@@ -180,6 +190,7 @@ func IsSQLiteDB(file io.ReaderAt) (bool, error) {
 	return bytes.Equal(buf, signature), nil
 	return bytes.Equal(buf, signature), nil
 }
 }
 
 
+// Checkpoint performs a WAL checkpoint on the SQLite database to ensure data consistency.
 func Checkpoint() error {
 func Checkpoint() error {
 	// Update WAL
 	// Update WAL
 	err := db.Exec("PRAGMA wal_checkpoint;").Error
 	err := db.Exec("PRAGMA wal_checkpoint;").Error

+ 44 - 32
database/model/model.go

@@ -1,3 +1,4 @@
+// Package model defines the database models and data structures used by the 3x-ui panel.
 package model
 package model
 
 
 import (
 import (
@@ -7,8 +8,10 @@ import (
 	"github.com/mhsanaei/3x-ui/v2/xray"
 	"github.com/mhsanaei/3x-ui/v2/xray"
 )
 )
 
 
+// Protocol represents the protocol type for Xray inbounds.
 type Protocol string
 type Protocol string
 
 
+// Protocol constants for different Xray inbound protocols
 const (
 const (
 	VMESS       Protocol = "vmess"
 	VMESS       Protocol = "vmess"
 	VLESS       Protocol = "vless"
 	VLESS       Protocol = "vless"
@@ -20,27 +23,29 @@ const (
 	WireGuard   Protocol = "wireguard"
 	WireGuard   Protocol = "wireguard"
 )
 )
 
 
+// User represents a user account in the 3x-ui panel.
 type User struct {
 type User struct {
 	Id       int    `json:"id" gorm:"primaryKey;autoIncrement"`
 	Id       int    `json:"id" gorm:"primaryKey;autoIncrement"`
 	Username string `json:"username"`
 	Username string `json:"username"`
 	Password string `json:"password"`
 	Password string `json:"password"`
 }
 }
 
 
+// Inbound represents an Xray inbound configuration with traffic statistics and settings.
 type Inbound struct {
 type Inbound struct {
-	Id                   int                  `json:"id" form:"id" gorm:"primaryKey;autoIncrement"`
-	UserId               int                  `json:"-"`
-	Up                   int64                `json:"up" form:"up"`
-	Down                 int64                `json:"down" form:"down"`
-	Total                int64                `json:"total" form:"total"`
-	AllTime              int64                `json:"allTime" form:"allTime" gorm:"default:0"`
-	Remark               string               `json:"remark" form:"remark"`
-	Enable               bool                 `json:"enable" form:"enable" gorm:"index:idx_enable_traffic_reset,priority:1"`
-	ExpiryTime           int64                `json:"expiryTime" form:"expiryTime"`
-	TrafficReset         string               `json:"trafficReset" form:"trafficReset" gorm:"default:never;index:idx_enable_traffic_reset,priority:2"`
-	LastTrafficResetTime int64                `json:"lastTrafficResetTime" form:"lastTrafficResetTime" gorm:"default:0"`
-	ClientStats          []xray.ClientTraffic `gorm:"foreignKey:InboundId;references:Id" json:"clientStats" form:"clientStats"`
+	Id                   int                  `json:"id" form:"id" gorm:"primaryKey;autoIncrement"`                                                    // Unique identifier
+	UserId               int                  `json:"-"`                                                                                               // Associated user ID
+	Up                   int64                `json:"up" form:"up"`                                                                                    // Upload traffic in bytes
+	Down                 int64                `json:"down" form:"down"`                                                                                // Download traffic in bytes
+	Total                int64                `json:"total" form:"total"`                                                                              // Total traffic limit in bytes
+	AllTime              int64                `json:"allTime" form:"allTime" gorm:"default:0"`                                                         // All-time traffic usage
+	Remark               string               `json:"remark" form:"remark"`                                                                            // Human-readable remark
+	Enable               bool                 `json:"enable" form:"enable" gorm:"index:idx_enable_traffic_reset,priority:1"`                           // Whether the inbound is enabled
+	ExpiryTime           int64                `json:"expiryTime" form:"expiryTime"`                                                                    // Expiration timestamp
+	TrafficReset         string               `json:"trafficReset" form:"trafficReset" gorm:"default:never;index:idx_enable_traffic_reset,priority:2"` // Traffic reset schedule
+	LastTrafficResetTime int64                `json:"lastTrafficResetTime" form:"lastTrafficResetTime" gorm:"default:0"`                               // Last traffic reset timestamp
+	ClientStats          []xray.ClientTraffic `gorm:"foreignKey:InboundId;references:Id" json:"clientStats" form:"clientStats"`                        // Client traffic statistics
 
 
-	// config part
+	// Xray configuration fields
 	Listen         string   `json:"listen" form:"listen"`
 	Listen         string   `json:"listen" form:"listen"`
 	Port           int      `json:"port" form:"port"`
 	Port           int      `json:"port" form:"port"`
 	Protocol       Protocol `json:"protocol" form:"protocol"`
 	Protocol       Protocol `json:"protocol" form:"protocol"`
@@ -50,6 +55,7 @@ type Inbound struct {
 	Sniffing       string   `json:"sniffing" form:"sniffing"`
 	Sniffing       string   `json:"sniffing" form:"sniffing"`
 }
 }
 
 
+// OutboundTraffics tracks traffic statistics for Xray outbound connections.
 type OutboundTraffics struct {
 type OutboundTraffics struct {
 	Id    int    `json:"id" form:"id" gorm:"primaryKey;autoIncrement"`
 	Id    int    `json:"id" form:"id" gorm:"primaryKey;autoIncrement"`
 	Tag   string `json:"tag" form:"tag" gorm:"unique"`
 	Tag   string `json:"tag" form:"tag" gorm:"unique"`
@@ -58,17 +64,20 @@ type OutboundTraffics struct {
 	Total int64  `json:"total" form:"total" gorm:"default:0"`
 	Total int64  `json:"total" form:"total" gorm:"default:0"`
 }
 }
 
 
+// InboundClientIps stores IP addresses associated with inbound clients for access control.
 type InboundClientIps struct {
 type InboundClientIps struct {
 	Id          int    `json:"id" gorm:"primaryKey;autoIncrement"`
 	Id          int    `json:"id" gorm:"primaryKey;autoIncrement"`
 	ClientEmail string `json:"clientEmail" form:"clientEmail" gorm:"unique"`
 	ClientEmail string `json:"clientEmail" form:"clientEmail" gorm:"unique"`
 	Ips         string `json:"ips" form:"ips"`
 	Ips         string `json:"ips" form:"ips"`
 }
 }
 
 
+// HistoryOfSeeders tracks which database seeders have been executed to prevent re-running.
 type HistoryOfSeeders struct {
 type HistoryOfSeeders struct {
 	Id         int    `json:"id" gorm:"primaryKey;autoIncrement"`
 	Id         int    `json:"id" gorm:"primaryKey;autoIncrement"`
 	SeederName string `json:"seederName"`
 	SeederName string `json:"seederName"`
 }
 }
 
 
+// GenXrayInboundConfig generates an Xray inbound configuration from the Inbound model.
 func (i *Inbound) GenXrayInboundConfig() *xray.InboundConfig {
 func (i *Inbound) GenXrayInboundConfig() *xray.InboundConfig {
 	listen := i.Listen
 	listen := i.Listen
 	if listen != "" {
 	if listen != "" {
@@ -85,33 +94,36 @@ func (i *Inbound) GenXrayInboundConfig() *xray.InboundConfig {
 	}
 	}
 }
 }
 
 
+// Setting stores key-value configuration settings for the 3x-ui panel.
 type Setting struct {
 type Setting struct {
 	Id    int    `json:"id" form:"id" gorm:"primaryKey;autoIncrement"`
 	Id    int    `json:"id" form:"id" gorm:"primaryKey;autoIncrement"`
 	Key   string `json:"key" form:"key"`
 	Key   string `json:"key" form:"key"`
 	Value string `json:"value" form:"value"`
 	Value string `json:"value" form:"value"`
 }
 }
 
 
+// Client represents a client configuration for Xray inbounds with traffic limits and settings.
 type Client struct {
 type Client struct {
-	ID         string `json:"id"`
-	Security   string `json:"security"`
-	Password   string `json:"password"`
-	Flow       string `json:"flow"`
-	Email      string `json:"email"`
-	LimitIP    int    `json:"limitIp"`
-	TotalGB    int64  `json:"totalGB" form:"totalGB"`
-	ExpiryTime int64  `json:"expiryTime" form:"expiryTime"`
-	Enable     bool   `json:"enable" form:"enable"`
-	TgID       int64  `json:"tgId" form:"tgId"`
-	SubID      string `json:"subId" form:"subId"`
-	Comment    string `json:"comment" form:"comment"`
-	Reset      int    `json:"reset" form:"reset"`
-	CreatedAt  int64  `json:"created_at,omitempty"`
-	UpdatedAt  int64  `json:"updated_at,omitempty"`
+	ID         string `json:"id"`                           // Unique client identifier
+	Security   string `json:"security"`                     // Security method (e.g., "auto", "aes-128-gcm")
+	Password   string `json:"password"`                     // Client password
+	Flow       string `json:"flow"`                         // Flow control (XTLS)
+	Email      string `json:"email"`                        // Client email identifier
+	LimitIP    int    `json:"limitIp"`                      // IP limit for this client
+	TotalGB    int64  `json:"totalGB" form:"totalGB"`       // Total traffic limit in GB
+	ExpiryTime int64  `json:"expiryTime" form:"expiryTime"` // Expiration timestamp
+	Enable     bool   `json:"enable" form:"enable"`         // Whether the client is enabled
+	TgID       int64  `json:"tgId" form:"tgId"`             // Telegram user ID for notifications
+	SubID      string `json:"subId" form:"subId"`           // Subscription identifier
+	Comment    string `json:"comment" form:"comment"`       // Client comment
+	Reset      int    `json:"reset" form:"reset"`           // Reset period in days
+	CreatedAt  int64  `json:"created_at,omitempty"`         // Creation timestamp
+	UpdatedAt  int64  `json:"updated_at,omitempty"`         // Last update timestamp
 }
 }
 
 
+// VLESSSettings contains VLESS protocol-specific configuration settings.
 type VLESSSettings struct {
 type VLESSSettings struct {
-	Clients    []Client `json:"clients"`
-	Decryption string   `json:"decryption"`
-	Encryption string   `json:"encryption"`
-	Fallbacks  []any    `json:"fallbacks"`
+	Clients    []Client `json:"clients"`    // List of VLESS clients
+	Decryption string   `json:"decryption"` // Decryption method
+	Encryption string   `json:"encryption"` // Encryption method (usually "none" for VLESS)
+	Fallbacks  []any    `json:"fallbacks"`  // Fallback configurations
 }
 }

+ 19 - 1
logger/logger.go

@@ -1,3 +1,5 @@
+// Package logger provides logging functionality for the 3x-ui panel with
+// buffered log storage and multiple log levels.
 package logger
 package logger
 
 
 import (
 import (
@@ -9,7 +11,11 @@ import (
 )
 )
 
 
 var (
 var (
-	logger    *logging.Logger
+	logger *logging.Logger
+
+	// addToBuffer appends a log entry into the in-memory ring buffer used for
+	// retrieving recent logs via the web UI. It keeps the buffer bounded to avoid
+	// uncontrolled growth.
 	logBuffer []struct {
 	logBuffer []struct {
 		time  string
 		time  string
 		level logging.Level
 		level logging.Level
@@ -21,6 +27,7 @@ func init() {
 	InitLogger(logging.INFO)
 	InitLogger(logging.INFO)
 }
 }
 
 
+// InitLogger initializes the logger with the specified logging level.
 func InitLogger(level logging.Level) {
 func InitLogger(level logging.Level) {
 	newLogger := logging.MustGetLogger("x-ui")
 	newLogger := logging.MustGetLogger("x-ui")
 	var err error
 	var err error
@@ -47,51 +54,61 @@ func InitLogger(level logging.Level) {
 	logger = newLogger
 	logger = newLogger
 }
 }
 
 
+// Debug logs a debug message and adds it to the log buffer.
 func Debug(args ...any) {
 func Debug(args ...any) {
 	logger.Debug(args...)
 	logger.Debug(args...)
 	addToBuffer("DEBUG", fmt.Sprint(args...))
 	addToBuffer("DEBUG", fmt.Sprint(args...))
 }
 }
 
 
+// Debugf logs a formatted debug message and adds it to the log buffer.
 func Debugf(format string, args ...any) {
 func Debugf(format string, args ...any) {
 	logger.Debugf(format, args...)
 	logger.Debugf(format, args...)
 	addToBuffer("DEBUG", fmt.Sprintf(format, args...))
 	addToBuffer("DEBUG", fmt.Sprintf(format, args...))
 }
 }
 
 
+// Info logs an info message and adds it to the log buffer.
 func Info(args ...any) {
 func Info(args ...any) {
 	logger.Info(args...)
 	logger.Info(args...)
 	addToBuffer("INFO", fmt.Sprint(args...))
 	addToBuffer("INFO", fmt.Sprint(args...))
 }
 }
 
 
+// Infof logs a formatted info message and adds it to the log buffer.
 func Infof(format string, args ...any) {
 func Infof(format string, args ...any) {
 	logger.Infof(format, args...)
 	logger.Infof(format, args...)
 	addToBuffer("INFO", fmt.Sprintf(format, args...))
 	addToBuffer("INFO", fmt.Sprintf(format, args...))
 }
 }
 
 
+// Notice logs a notice message and adds it to the log buffer.
 func Notice(args ...any) {
 func Notice(args ...any) {
 	logger.Notice(args...)
 	logger.Notice(args...)
 	addToBuffer("NOTICE", fmt.Sprint(args...))
 	addToBuffer("NOTICE", fmt.Sprint(args...))
 }
 }
 
 
+// Noticef logs a formatted notice message and adds it to the log buffer.
 func Noticef(format string, args ...any) {
 func Noticef(format string, args ...any) {
 	logger.Noticef(format, args...)
 	logger.Noticef(format, args...)
 	addToBuffer("NOTICE", fmt.Sprintf(format, args...))
 	addToBuffer("NOTICE", fmt.Sprintf(format, args...))
 }
 }
 
 
+// Warning logs a warning message and adds it to the log buffer.
 func Warning(args ...any) {
 func Warning(args ...any) {
 	logger.Warning(args...)
 	logger.Warning(args...)
 	addToBuffer("WARNING", fmt.Sprint(args...))
 	addToBuffer("WARNING", fmt.Sprint(args...))
 }
 }
 
 
+// Warningf logs a formatted warning message and adds it to the log buffer.
 func Warningf(format string, args ...any) {
 func Warningf(format string, args ...any) {
 	logger.Warningf(format, args...)
 	logger.Warningf(format, args...)
 	addToBuffer("WARNING", fmt.Sprintf(format, args...))
 	addToBuffer("WARNING", fmt.Sprintf(format, args...))
 }
 }
 
 
+// Error logs an error message and adds it to the log buffer.
 func Error(args ...any) {
 func Error(args ...any) {
 	logger.Error(args...)
 	logger.Error(args...)
 	addToBuffer("ERROR", fmt.Sprint(args...))
 	addToBuffer("ERROR", fmt.Sprint(args...))
 }
 }
 
 
+// Errorf logs a formatted error message and adds it to the log buffer.
 func Errorf(format string, args ...any) {
 func Errorf(format string, args ...any) {
 	logger.Errorf(format, args...)
 	logger.Errorf(format, args...)
 	addToBuffer("ERROR", fmt.Sprintf(format, args...))
 	addToBuffer("ERROR", fmt.Sprintf(format, args...))
@@ -115,6 +132,7 @@ func addToBuffer(level string, newLog string) {
 	})
 	})
 }
 }
 
 
+// GetLogs retrieves up to c log entries from the buffer that are at or below the specified level.
 func GetLogs(c int, level string) []string {
 func GetLogs(c int, level string) []string {
 	var output []string
 	var output []string
 	logLevel, _ := logging.LogLevel(level)
 	logLevel, _ := logging.LogLevel(level)

+ 14 - 0
main.go

@@ -1,3 +1,5 @@
+// Package main is the entry point for the 3x-ui web panel application.
+// It initializes the database, web server, and handles command-line operations for managing the panel.
 package main
 package main
 
 
 import (
 import (
@@ -22,6 +24,7 @@ import (
 	"github.com/op/go-logging"
 	"github.com/op/go-logging"
 )
 )
 
 
+// runWebServer initializes and starts the web server for the 3x-ui panel.
 func runWebServer() {
 func runWebServer() {
 	log.Printf("Starting %v %v", config.GetName(), config.GetVersion())
 	log.Printf("Starting %v %v", config.GetName(), config.GetVersion())
 
 
@@ -111,6 +114,7 @@ func runWebServer() {
 	}
 	}
 }
 }
 
 
+// resetSetting resets all panel settings to their default values.
 func resetSetting() {
 func resetSetting() {
 	err := database.InitDB(config.GetDBPath())
 	err := database.InitDB(config.GetDBPath())
 	if err != nil {
 	if err != nil {
@@ -127,6 +131,7 @@ func resetSetting() {
 	}
 	}
 }
 }
 
 
+// showSetting displays the current panel settings if show is true.
 func showSetting(show bool) {
 func showSetting(show bool) {
 	if show {
 	if show {
 		settingService := service.SettingService{}
 		settingService := service.SettingService{}
@@ -176,6 +181,7 @@ func showSetting(show bool) {
 	}
 	}
 }
 }
 
 
+// updateTgbotEnableSts enables or disables the Telegram bot notifications based on the status parameter.
 func updateTgbotEnableSts(status bool) {
 func updateTgbotEnableSts(status bool) {
 	settingService := service.SettingService{}
 	settingService := service.SettingService{}
 	currentTgSts, err := settingService.GetTgbotEnabled()
 	currentTgSts, err := settingService.GetTgbotEnabled()
@@ -195,6 +201,7 @@ func updateTgbotEnableSts(status bool) {
 	}
 	}
 }
 }
 
 
+// updateTgbotSetting updates Telegram bot settings including token, chat ID, and runtime schedule.
 func updateTgbotSetting(tgBotToken string, tgBotChatid string, tgBotRuntime string) {
 func updateTgbotSetting(tgBotToken string, tgBotChatid string, tgBotRuntime string) {
 	err := database.InitDB(config.GetDBPath())
 	err := database.InitDB(config.GetDBPath())
 	if err != nil {
 	if err != nil {
@@ -232,6 +239,7 @@ func updateTgbotSetting(tgBotToken string, tgBotChatid string, tgBotRuntime stri
 	}
 	}
 }
 }
 
 
+// updateSetting updates various panel settings including port, credentials, base path, listen IP, and two-factor authentication.
 func updateSetting(port int, username string, password string, webBasePath string, listenIP string, resetTwoFactor bool) {
 func updateSetting(port int, username string, password string, webBasePath string, listenIP string, resetTwoFactor bool) {
 	err := database.InitDB(config.GetDBPath())
 	err := database.InitDB(config.GetDBPath())
 	if err != nil {
 	if err != nil {
@@ -290,6 +298,7 @@ func updateSetting(port int, username string, password string, webBasePath strin
 	}
 	}
 }
 }
 
 
+// updateCert updates the SSL certificate files for the panel.
 func updateCert(publicKey string, privateKey string) {
 func updateCert(publicKey string, privateKey string) {
 	err := database.InitDB(config.GetDBPath())
 	err := database.InitDB(config.GetDBPath())
 	if err != nil {
 	if err != nil {
@@ -317,6 +326,7 @@ func updateCert(publicKey string, privateKey string) {
 	}
 	}
 }
 }
 
 
+// GetCertificate displays the current SSL certificate settings if getCert is true.
 func GetCertificate(getCert bool) {
 func GetCertificate(getCert bool) {
 	if getCert {
 	if getCert {
 		settingService := service.SettingService{}
 		settingService := service.SettingService{}
@@ -334,6 +344,7 @@ func GetCertificate(getCert bool) {
 	}
 	}
 }
 }
 
 
+// GetListenIP displays the current panel listen IP address if getListen is true.
 func GetListenIP(getListen bool) {
 func GetListenIP(getListen bool) {
 	if getListen {
 	if getListen {
 
 
@@ -348,6 +359,7 @@ func GetListenIP(getListen bool) {
 	}
 	}
 }
 }
 
 
+// migrateDb performs database migration operations for the 3x-ui panel.
 func migrateDb() {
 func migrateDb() {
 	inboundService := service.InboundService{}
 	inboundService := service.InboundService{}
 
 
@@ -360,6 +372,8 @@ func migrateDb() {
 	fmt.Println("Migration done!")
 	fmt.Println("Migration done!")
 }
 }
 
 
+// main is the entry point of the 3x-ui application.
+// It parses command-line arguments to run the web server, migrate database, or update settings.
 func main() {
 func main() {
 	if len(os.Args) < 2 {
 	if len(os.Args) < 2 {
 		runWebServer()
 		runWebServer()

+ 9 - 0
sub/sub.go

@@ -1,3 +1,5 @@
+// Package sub provides subscription server functionality for the 3x-ui panel,
+// including HTTP/HTTPS servers for serving subscription links and JSON configurations.
 package sub
 package sub
 
 
 import (
 import (
@@ -39,6 +41,7 @@ func setEmbeddedTemplates(engine *gin.Engine) error {
 	return nil
 	return nil
 }
 }
 
 
+// Server represents the subscription server that serves subscription links and JSON configurations.
 type Server struct {
 type Server struct {
 	httpServer *http.Server
 	httpServer *http.Server
 	listener   net.Listener
 	listener   net.Listener
@@ -50,6 +53,7 @@ type Server struct {
 	cancel context.CancelFunc
 	cancel context.CancelFunc
 }
 }
 
 
+// NewServer creates a new subscription server instance with a cancellable context.
 func NewServer() *Server {
 func NewServer() *Server {
 	ctx, cancel := context.WithCancel(context.Background())
 	ctx, cancel := context.WithCancel(context.Background())
 	return &Server{
 	return &Server{
@@ -58,6 +62,8 @@ func NewServer() *Server {
 	}
 	}
 }
 }
 
 
+// initRouter configures the subscription server's Gin engine, middleware,
+// templates and static assets and returns the ready-to-use engine.
 func (s *Server) initRouter() (*gin.Engine, error) {
 func (s *Server) initRouter() (*gin.Engine, error) {
 	// Always run in release mode for the subscription server
 	// Always run in release mode for the subscription server
 	gin.DefaultWriter = io.Discard
 	gin.DefaultWriter = io.Discard
@@ -222,6 +228,7 @@ func (s *Server) getHtmlFiles() ([]string, error) {
 	return files, nil
 	return files, nil
 }
 }
 
 
+// Start initializes and starts the subscription server with configured settings.
 func (s *Server) Start() (err error) {
 func (s *Server) Start() (err error) {
 	// This is an anonymous function, no function name
 	// This is an anonymous function, no function name
 	defer func() {
 	defer func() {
@@ -295,6 +302,7 @@ func (s *Server) Start() (err error) {
 	return nil
 	return nil
 }
 }
 
 
+// Stop gracefully shuts down the subscription server and closes the listener.
 func (s *Server) Stop() error {
 func (s *Server) Stop() error {
 	s.cancel()
 	s.cancel()
 
 
@@ -309,6 +317,7 @@ func (s *Server) Stop() error {
 	return common.Combine(err1, err2)
 	return common.Combine(err1, err2)
 }
 }
 
 
+// GetCtx returns the server's context for cancellation and deadline management.
 func (s *Server) GetCtx() context.Context {
 func (s *Server) GetCtx() context.Context {
 	return s.ctx
 	return s.ctx
 }
 }

+ 7 - 0
sub/subController.go

@@ -10,6 +10,7 @@ import (
 	"github.com/gin-gonic/gin"
 	"github.com/gin-gonic/gin"
 )
 )
 
 
+// SUBController handles HTTP requests for subscription links and JSON configurations.
 type SUBController struct {
 type SUBController struct {
 	subTitle       string
 	subTitle       string
 	subPath        string
 	subPath        string
@@ -22,6 +23,7 @@ type SUBController struct {
 	subJsonService *SubJsonService
 	subJsonService *SubJsonService
 }
 }
 
 
+// NewSUBController creates a new subscription controller with the given configuration.
 func NewSUBController(
 func NewSUBController(
 	g *gin.RouterGroup,
 	g *gin.RouterGroup,
 	subPath string,
 	subPath string,
@@ -53,6 +55,8 @@ func NewSUBController(
 	return a
 	return a
 }
 }
 
 
+// initRouter registers HTTP routes for subscription links and JSON endpoints
+// on the provided router group.
 func (a *SUBController) initRouter(g *gin.RouterGroup) {
 func (a *SUBController) initRouter(g *gin.RouterGroup) {
 	gLink := g.Group(a.subPath)
 	gLink := g.Group(a.subPath)
 	gLink.GET(":subid", a.subs)
 	gLink.GET(":subid", a.subs)
@@ -62,6 +66,7 @@ func (a *SUBController) initRouter(g *gin.RouterGroup) {
 	}
 	}
 }
 }
 
 
+// subs handles HTTP requests for subscription links, returning either HTML page or base64-encoded subscription data.
 func (a *SUBController) subs(c *gin.Context) {
 func (a *SUBController) subs(c *gin.Context) {
 	subId := c.Param("subid")
 	subId := c.Param("subid")
 	scheme, host, hostWithPort, hostHeader := a.subService.ResolveRequest(c)
 	scheme, host, hostWithPort, hostHeader := a.subService.ResolveRequest(c)
@@ -119,6 +124,7 @@ func (a *SUBController) subs(c *gin.Context) {
 	}
 	}
 }
 }
 
 
+// subJsons handles HTTP requests for JSON subscription configurations.
 func (a *SUBController) subJsons(c *gin.Context) {
 func (a *SUBController) subJsons(c *gin.Context) {
 	subId := c.Param("subid")
 	subId := c.Param("subid")
 	_, host, _, _ := a.subService.ResolveRequest(c)
 	_, host, _, _ := a.subService.ResolveRequest(c)
@@ -134,6 +140,7 @@ func (a *SUBController) subJsons(c *gin.Context) {
 	}
 	}
 }
 }
 
 
+// ApplyCommonHeaders sets common HTTP headers for subscription responses including user info, update interval, and profile title.
 func (a *SUBController) ApplyCommonHeaders(c *gin.Context, header, updateInterval, profileTitle string) {
 func (a *SUBController) ApplyCommonHeaders(c *gin.Context, header, updateInterval, profileTitle string) {
 	c.Writer.Header().Set("Subscription-Userinfo", header)
 	c.Writer.Header().Set("Subscription-Userinfo", header)
 	c.Writer.Header().Set("Profile-Update-Interval", updateInterval)
 	c.Writer.Header().Set("Profile-Update-Interval", updateInterval)

+ 3 - 0
sub/subJsonService.go

@@ -17,6 +17,7 @@ import (
 //go:embed default.json
 //go:embed default.json
 var defaultJson string
 var defaultJson string
 
 
+// SubJsonService handles JSON subscription configuration generation and management.
 type SubJsonService struct {
 type SubJsonService struct {
 	configJson       map[string]any
 	configJson       map[string]any
 	defaultOutbounds []json_util.RawMessage
 	defaultOutbounds []json_util.RawMessage
@@ -28,6 +29,7 @@ type SubJsonService struct {
 	SubService     *SubService
 	SubService     *SubService
 }
 }
 
 
+// NewSubJsonService creates a new JSON subscription service with the given configuration.
 func NewSubJsonService(fragment string, noises string, mux string, rules string, subService *SubService) *SubJsonService {
 func NewSubJsonService(fragment string, noises string, mux string, rules string, subService *SubService) *SubJsonService {
 	var configJson map[string]any
 	var configJson map[string]any
 	var defaultOutbounds []json_util.RawMessage
 	var defaultOutbounds []json_util.RawMessage
@@ -67,6 +69,7 @@ func NewSubJsonService(fragment string, noises string, mux string, rules string,
 	}
 	}
 }
 }
 
 
+// GetJson generates a JSON subscription configuration for the given subscription ID and host.
 func (s *SubJsonService) GetJson(subId string, host string) (string, string, error) {
 func (s *SubJsonService) GetJson(subId string, host string) (string, string, error) {
 	inbounds, err := s.SubService.getInboundsBySubId(subId)
 	inbounds, err := s.SubService.getInboundsBySubId(subId)
 	if err != nil || len(inbounds) == 0 {
 	if err != nil || len(inbounds) == 0 {

+ 7 - 0
sub/subService.go

@@ -20,6 +20,7 @@ import (
 	"github.com/mhsanaei/3x-ui/v2/xray"
 	"github.com/mhsanaei/3x-ui/v2/xray"
 )
 )
 
 
+// SubService provides business logic for generating subscription links and managing subscription data.
 type SubService struct {
 type SubService struct {
 	address        string
 	address        string
 	showInfo       bool
 	showInfo       bool
@@ -29,6 +30,7 @@ type SubService struct {
 	settingService service.SettingService
 	settingService service.SettingService
 }
 }
 
 
+// NewSubService creates a new subscription service with the given configuration.
 func NewSubService(showInfo bool, remarkModel string) *SubService {
 func NewSubService(showInfo bool, remarkModel string) *SubService {
 	return &SubService{
 	return &SubService{
 		showInfo:    showInfo,
 		showInfo:    showInfo,
@@ -36,6 +38,7 @@ func NewSubService(showInfo bool, remarkModel string) *SubService {
 	}
 	}
 }
 }
 
 
+// GetSubs retrieves subscription links for a given subscription ID and host.
 func (s *SubService) GetSubs(subId string, host string) ([]string, int64, xray.ClientTraffic, error) {
 func (s *SubService) GetSubs(subId string, host string) ([]string, int64, xray.ClientTraffic, error) {
 	s.address = host
 	s.address = host
 	var result []string
 	var result []string
@@ -1008,6 +1011,7 @@ func searchHost(headers any) string {
 }
 }
 
 
 // PageData is a view model for subpage.html
 // PageData is a view model for subpage.html
+// PageData contains data for rendering the subscription information page.
 type PageData struct {
 type PageData struct {
 	Host         string
 	Host         string
 	BasePath     string
 	BasePath     string
@@ -1029,6 +1033,7 @@ type PageData struct {
 }
 }
 
 
 // ResolveRequest extracts scheme and host info from request/headers consistently.
 // ResolveRequest extracts scheme and host info from request/headers consistently.
+// ResolveRequest extracts scheme, host, and header information from an HTTP request.
 func (s *SubService) ResolveRequest(c *gin.Context) (scheme string, host string, hostWithPort string, hostHeader string) {
 func (s *SubService) ResolveRequest(c *gin.Context) (scheme string, host string, hostWithPort string, hostHeader string) {
 	// scheme
 	// scheme
 	scheme = "http"
 	scheme = "http"
@@ -1072,6 +1077,7 @@ func (s *SubService) ResolveRequest(c *gin.Context) (scheme string, host string,
 }
 }
 
 
 // BuildURLs constructs absolute subscription and json URLs.
 // BuildURLs constructs absolute subscription and json URLs.
+// BuildURLs constructs subscription and JSON subscription URLs for a given subscription ID.
 func (s *SubService) BuildURLs(scheme, hostWithPort, subPath, subJsonPath, subId string) (subURL, subJsonURL string) {
 func (s *SubService) BuildURLs(scheme, hostWithPort, subPath, subJsonPath, subId string) (subURL, subJsonURL string) {
 	if strings.HasSuffix(subPath, "/") {
 	if strings.HasSuffix(subPath, "/") {
 		subURL = scheme + "://" + hostWithPort + subPath + subId
 		subURL = scheme + "://" + hostWithPort + subPath + subId
@@ -1087,6 +1093,7 @@ func (s *SubService) BuildURLs(scheme, hostWithPort, subPath, subJsonPath, subId
 }
 }
 
 
 // BuildPageData parses header and prepares the template view model.
 // BuildPageData parses header and prepares the template view model.
+// BuildPageData constructs page data for rendering the subscription information page.
 func (s *SubService) BuildPageData(subId string, hostHeader string, traffic xray.ClientTraffic, lastOnline int64, subs []string, subURL, subJsonURL string) PageData {
 func (s *SubService) BuildPageData(subId string, hostHeader string, traffic xray.ClientTraffic, lastOnline int64, subs []string, subURL, subJsonURL string) PageData {
 	download := common.FormatTraffic(traffic.Down)
 	download := common.FormatTraffic(traffic.Down)
 	upload := common.FormatTraffic(traffic.Up)
 	upload := common.FormatTraffic(traffic.Up)

+ 4 - 0
util/common/err.go

@@ -1,3 +1,4 @@
+// Package common provides common utility functions for error handling, formatting, and multi-error management.
 package common
 package common
 
 
 import (
 import (
@@ -7,16 +8,19 @@ import (
 	"github.com/mhsanaei/3x-ui/v2/logger"
 	"github.com/mhsanaei/3x-ui/v2/logger"
 )
 )
 
 
+// NewErrorf creates a new error with formatted message.
 func NewErrorf(format string, a ...any) error {
 func NewErrorf(format string, a ...any) error {
 	msg := fmt.Sprintf(format, a...)
 	msg := fmt.Sprintf(format, a...)
 	return errors.New(msg)
 	return errors.New(msg)
 }
 }
 
 
+// NewError creates a new error from the given arguments.
 func NewError(a ...any) error {
 func NewError(a ...any) error {
 	msg := fmt.Sprintln(a...)
 	msg := fmt.Sprintln(a...)
 	return errors.New(msg)
 	return errors.New(msg)
 }
 }
 
 
+// Recover handles panic recovery and logs the panic error if a message is provided.
 func Recover(msg string) any {
 func Recover(msg string) any {
 	panicErr := recover()
 	panicErr := recover()
 	if panicErr != nil {
 	if panicErr != nil {

+ 1 - 0
util/common/format.go

@@ -4,6 +4,7 @@ import (
 	"fmt"
 	"fmt"
 )
 )
 
 
+// FormatTraffic formats traffic bytes into human-readable units (B, KB, MB, GB, TB, PB).
 func FormatTraffic(trafficBytes int64) string {
 func FormatTraffic(trafficBytes int64) string {
 	units := []string{"B", "KB", "MB", "GB", "TB", "PB"}
 	units := []string{"B", "KB", "MB", "GB", "TB", "PB"}
 	unitIndex := 0
 	unitIndex := 0

+ 3 - 0
util/common/multi_error.go

@@ -4,8 +4,10 @@ import (
 	"strings"
 	"strings"
 )
 )
 
 
+// multiError represents a collection of errors.
 type multiError []error
 type multiError []error
 
 
+// Error returns a string representation of all errors joined with " | ".
 func (e multiError) Error() string {
 func (e multiError) Error() string {
 	var r strings.Builder
 	var r strings.Builder
 	r.WriteString("multierr: ")
 	r.WriteString("multierr: ")
@@ -16,6 +18,7 @@ func (e multiError) Error() string {
 	return r.String()
 	return r.String()
 }
 }
 
 
+// Combine combines multiple errors into a single error, filtering out nil errors.
 func Combine(maybeError ...error) error {
 func Combine(maybeError ...error) error {
 	var errs multiError
 	var errs multiError
 	for _, err := range maybeError {
 	for _, err := range maybeError {

+ 3 - 0
util/crypto/crypto.go

@@ -1,14 +1,17 @@
+// Package crypto provides cryptographic utilities for password hashing and verification.
 package crypto
 package crypto
 
 
 import (
 import (
 	"golang.org/x/crypto/bcrypt"
 	"golang.org/x/crypto/bcrypt"
 )
 )
 
 
+// HashPasswordAsBcrypt generates a bcrypt hash of the given password.
 func HashPasswordAsBcrypt(password string) (string, error) {
 func HashPasswordAsBcrypt(password string) (string, error) {
 	hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
 	hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
 	return string(hash), err
 	return string(hash), err
 }
 }
 
 
+// CheckPasswordHash verifies if the given password matches the bcrypt hash.
 func CheckPasswordHash(hash, password string) bool {
 func CheckPasswordHash(hash, password string) bool {
 	err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
 	err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
 	return err == nil
 	return err == nil

+ 5 - 2
util/json_util/json.go

@@ -1,12 +1,15 @@
+// Package json_util provides JSON utilities including a custom RawMessage type.
 package json_util
 package json_util
 
 
 import (
 import (
 	"errors"
 	"errors"
 )
 )
 
 
+// RawMessage is a custom JSON raw message type that marshals empty slices as "null".
 type RawMessage []byte
 type RawMessage []byte
 
 
-// MarshalJSON: Customize json.RawMessage default behavior
+// MarshalJSON customizes the JSON marshaling behavior for RawMessage.
+// Empty RawMessage values are marshaled as "null" instead of "[]".
 func (m RawMessage) MarshalJSON() ([]byte, error) {
 func (m RawMessage) MarshalJSON() ([]byte, error) {
 	if len(m) == 0 {
 	if len(m) == 0 {
 		return []byte("null"), nil
 		return []byte("null"), nil
@@ -14,7 +17,7 @@ func (m RawMessage) MarshalJSON() ([]byte, error) {
 	return m, nil
 	return m, nil
 }
 }
 
 
-// UnmarshalJSON: sets *m to a copy of data.
+// UnmarshalJSON sets *m to a copy of the JSON data.
 func (m *RawMessage) UnmarshalJSON(data []byte) error {
 func (m *RawMessage) UnmarshalJSON(data []byte) error {
 	if m == nil {
 	if m == nil {
 		return errors.New("json.RawMessage: UnmarshalJSON on nil pointer")
 		return errors.New("json.RawMessage: UnmarshalJSON on nil pointer")

+ 5 - 0
util/random/random.go

@@ -1,3 +1,4 @@
+// Package random provides utilities for generating random strings and numbers.
 package random
 package random
 
 
 import (
 import (
@@ -13,6 +14,8 @@ var (
 	allSeq      [62]rune
 	allSeq      [62]rune
 )
 )
 
 
+// init initializes the character sequences used for random string generation.
+// It sets up arrays for numbers, lowercase letters, uppercase letters, and combinations.
 func init() {
 func init() {
 	for i := 0; i < 10; i++ {
 	for i := 0; i < 10; i++ {
 		numSeq[i] = rune('0' + i)
 		numSeq[i] = rune('0' + i)
@@ -33,6 +36,7 @@ func init() {
 	copy(allSeq[len(numSeq)+len(lowerSeq):], upperSeq[:])
 	copy(allSeq[len(numSeq)+len(lowerSeq):], upperSeq[:])
 }
 }
 
 
+// Seq generates a random string of length n containing alphanumeric characters (numbers, lowercase and uppercase letters).
 func Seq(n int) string {
 func Seq(n int) string {
 	runes := make([]rune, n)
 	runes := make([]rune, n)
 	for i := 0; i < n; i++ {
 	for i := 0; i < n; i++ {
@@ -41,6 +45,7 @@ func Seq(n int) string {
 	return string(runes)
 	return string(runes)
 }
 }
 
 
+// Num generates a random integer between 0 and n-1.
 func Num(n int) int {
 func Num(n int) int {
 	return rand.Intn(n)
 	return rand.Intn(n)
 }
 }

+ 3 - 0
util/reflect_util/reflect.go

@@ -1,7 +1,9 @@
+// Package reflect_util provides reflection utilities for working with struct fields and values.
 package reflect_util
 package reflect_util
 
 
 import "reflect"
 import "reflect"
 
 
+// GetFields returns all struct fields of the given reflect.Type.
 func GetFields(t reflect.Type) []reflect.StructField {
 func GetFields(t reflect.Type) []reflect.StructField {
 	num := t.NumField()
 	num := t.NumField()
 	fields := make([]reflect.StructField, 0, num)
 	fields := make([]reflect.StructField, 0, num)
@@ -11,6 +13,7 @@ func GetFields(t reflect.Type) []reflect.StructField {
 	return fields
 	return fields
 }
 }
 
 
+// GetFieldValues returns all field values of the given reflect.Value.
 func GetFieldValues(v reflect.Value) []reflect.Value {
 func GetFieldValues(v reflect.Value) []reflect.Value {
 	num := v.NumField()
 	num := v.NumField()
 	fields := make([]reflect.Value, 0, num)
 	fields := make([]reflect.Value, 0, num)

+ 2 - 0
util/sys/psutil.go

@@ -1,3 +1,5 @@
+// Package sys provides system utilities for monitoring network connections and CPU usage.
+// Platform-specific implementations are provided for Windows, Linux, and macOS.
 package sys
 package sys
 
 
 import (
 import (

+ 4 - 0
util/sys/sys_linux.go

@@ -45,6 +45,8 @@ func getLinesNum(filename string) (int, error) {
 	return sum, nil
 	return sum, nil
 }
 }
 
 
+// GetTCPCount returns the number of active TCP connections by reading
+// /proc/net/tcp and /proc/net/tcp6 when available.
 func GetTCPCount() (int, error) {
 func GetTCPCount() (int, error) {
 	root := HostProc()
 	root := HostProc()
 
 
@@ -75,6 +77,8 @@ func GetUDPCount() (int, error) {
 	return udp4 + udp6, nil
 	return udp4 + udp6, nil
 }
 }
 
 
+// safeGetLinesNum returns 0 if the file does not exist, otherwise forwards
+// to getLinesNum to count the number of lines.
 func safeGetLinesNum(path string) (int, error) {
 func safeGetLinesNum(path string) (int, error) {
 	if _, err := os.Stat(path); os.IsNotExist(err) {
 	if _, err := os.Stat(path); os.IsNotExist(err) {
 		return 0, nil
 		return 0, nil

+ 5 - 0
util/sys/sys_windows.go

@@ -12,6 +12,7 @@ import (
 	"github.com/shirou/gopsutil/v4/net"
 	"github.com/shirou/gopsutil/v4/net"
 )
 )
 
 
+// GetConnectionCount returns the number of active connections for the specified protocol ("tcp" or "udp").
 func GetConnectionCount(proto string) (int, error) {
 func GetConnectionCount(proto string) (int, error) {
 	if proto != "tcp" && proto != "udp" {
 	if proto != "tcp" && proto != "udp" {
 		return 0, errors.New("invalid protocol")
 		return 0, errors.New("invalid protocol")
@@ -24,10 +25,12 @@ func GetConnectionCount(proto string) (int, error) {
 	return len(stats), nil
 	return len(stats), nil
 }
 }
 
 
+// GetTCPCount returns the number of active TCP connections.
 func GetTCPCount() (int, error) {
 func GetTCPCount() (int, error) {
 	return GetConnectionCount("tcp")
 	return GetConnectionCount("tcp")
 }
 }
 
 
+// GetUDPCount returns the number of active UDP connections.
 func GetUDPCount() (int, error) {
 func GetUDPCount() (int, error) {
 	return GetConnectionCount("udp")
 	return GetConnectionCount("udp")
 }
 }
@@ -50,6 +53,8 @@ type filetime struct {
 	HighDateTime uint32
 	HighDateTime uint32
 }
 }
 
 
+// ftToUint64 converts a Windows FILETIME-like struct to a uint64 for
+// arithmetic and delta calculations used by CPUPercentRaw.
 func ftToUint64(ft filetime) uint64 {
 func ftToUint64(ft filetime) uint64 {
 	return (uint64(ft.HighDateTime) << 32) | uint64(ft.LowDateTime)
 	return (uint64(ft.HighDateTime) << 32) | uint64(ft.LowDateTime)
 }
 }

+ 4 - 0
web/controller/api.go

@@ -6,6 +6,7 @@ import (
 	"github.com/gin-gonic/gin"
 	"github.com/gin-gonic/gin"
 )
 )
 
 
+// APIController handles the main API routes for the 3x-ui panel, including inbounds and server management.
 type APIController struct {
 type APIController struct {
 	BaseController
 	BaseController
 	inboundController *InboundController
 	inboundController *InboundController
@@ -13,12 +14,14 @@ type APIController struct {
 	Tgbot             service.Tgbot
 	Tgbot             service.Tgbot
 }
 }
 
 
+// NewAPIController creates a new APIController instance and initializes its routes.
 func NewAPIController(g *gin.RouterGroup) *APIController {
 func NewAPIController(g *gin.RouterGroup) *APIController {
 	a := &APIController{}
 	a := &APIController{}
 	a.initRouter(g)
 	a.initRouter(g)
 	return a
 	return a
 }
 }
 
 
+// initRouter sets up the API routes for inbounds, server, and other endpoints.
 func (a *APIController) initRouter(g *gin.RouterGroup) {
 func (a *APIController) initRouter(g *gin.RouterGroup) {
 	// Main API group
 	// Main API group
 	api := g.Group("/panel/api")
 	api := g.Group("/panel/api")
@@ -36,6 +39,7 @@ func (a *APIController) initRouter(g *gin.RouterGroup) {
 	api.GET("/backuptotgbot", a.BackuptoTgbot)
 	api.GET("/backuptotgbot", a.BackuptoTgbot)
 }
 }
 
 
+// BackuptoTgbot sends a backup of the panel data to Telegram bot admins.
 func (a *APIController) BackuptoTgbot(c *gin.Context) {
 func (a *APIController) BackuptoTgbot(c *gin.Context) {
 	a.Tgbot.SendBackupToAdmins()
 	a.Tgbot.SendBackupToAdmins()
 }
 }

+ 5 - 0
web/controller/base.go

@@ -1,3 +1,5 @@
+// Package controller provides HTTP request handlers and controllers for the 3x-ui web management panel.
+// It handles routing, authentication, and API endpoints for managing Xray inbounds, settings, and more.
 package controller
 package controller
 
 
 import (
 import (
@@ -10,8 +12,10 @@ import (
 	"github.com/gin-gonic/gin"
 	"github.com/gin-gonic/gin"
 )
 )
 
 
+// BaseController provides common functionality for all controllers, including authentication checks.
 type BaseController struct{}
 type BaseController struct{}
 
 
+// checkLogin is a middleware that verifies user authentication and handles unauthorized access.
 func (a *BaseController) checkLogin(c *gin.Context) {
 func (a *BaseController) checkLogin(c *gin.Context) {
 	if !session.IsLogin(c) {
 	if !session.IsLogin(c) {
 		if isAjax(c) {
 		if isAjax(c) {
@@ -25,6 +29,7 @@ func (a *BaseController) checkLogin(c *gin.Context) {
 	}
 	}
 }
 }
 
 
+// I18nWeb retrieves an internationalized message for the web interface based on the current locale.
 func I18nWeb(c *gin.Context, name string, params ...string) string {
 func I18nWeb(c *gin.Context, name string, params ...string) string {
 	anyfunc, funcExists := c.Get("I18n")
 	anyfunc, funcExists := c.Get("I18n")
 	if !funcExists {
 	if !funcExists {

+ 24 - 0
web/controller/inbound.go

@@ -12,17 +12,20 @@ import (
 	"github.com/gin-gonic/gin"
 	"github.com/gin-gonic/gin"
 )
 )
 
 
+// InboundController handles HTTP requests related to Xray inbounds management.
 type InboundController struct {
 type InboundController struct {
 	inboundService service.InboundService
 	inboundService service.InboundService
 	xrayService    service.XrayService
 	xrayService    service.XrayService
 }
 }
 
 
+// NewInboundController creates a new InboundController and sets up its routes.
 func NewInboundController(g *gin.RouterGroup) *InboundController {
 func NewInboundController(g *gin.RouterGroup) *InboundController {
 	a := &InboundController{}
 	a := &InboundController{}
 	a.initRouter(g)
 	a.initRouter(g)
 	return a
 	return a
 }
 }
 
 
+// initRouter initializes the routes for inbound-related operations.
 func (a *InboundController) initRouter(g *gin.RouterGroup) {
 func (a *InboundController) initRouter(g *gin.RouterGroup) {
 
 
 	g.GET("/list", a.getInbounds)
 	g.GET("/list", a.getInbounds)
@@ -49,6 +52,7 @@ func (a *InboundController) initRouter(g *gin.RouterGroup) {
 	g.POST("/:id/delClientByEmail/:email", a.delInboundClientByEmail)
 	g.POST("/:id/delClientByEmail/:email", a.delInboundClientByEmail)
 }
 }
 
 
+// getInbounds retrieves the list of inbounds for the logged-in user.
 func (a *InboundController) getInbounds(c *gin.Context) {
 func (a *InboundController) getInbounds(c *gin.Context) {
 	user := session.GetLoginUser(c)
 	user := session.GetLoginUser(c)
 	inbounds, err := a.inboundService.GetInbounds(user.Id)
 	inbounds, err := a.inboundService.GetInbounds(user.Id)
@@ -59,6 +63,7 @@ func (a *InboundController) getInbounds(c *gin.Context) {
 	jsonObj(c, inbounds, nil)
 	jsonObj(c, inbounds, nil)
 }
 }
 
 
+// getInbound retrieves a specific inbound by its ID.
 func (a *InboundController) getInbound(c *gin.Context) {
 func (a *InboundController) getInbound(c *gin.Context) {
 	id, err := strconv.Atoi(c.Param("id"))
 	id, err := strconv.Atoi(c.Param("id"))
 	if err != nil {
 	if err != nil {
@@ -73,6 +78,7 @@ func (a *InboundController) getInbound(c *gin.Context) {
 	jsonObj(c, inbound, nil)
 	jsonObj(c, inbound, nil)
 }
 }
 
 
+// getClientTraffics retrieves client traffic information by email.
 func (a *InboundController) getClientTraffics(c *gin.Context) {
 func (a *InboundController) getClientTraffics(c *gin.Context) {
 	email := c.Param("email")
 	email := c.Param("email")
 	clientTraffics, err := a.inboundService.GetClientTrafficByEmail(email)
 	clientTraffics, err := a.inboundService.GetClientTrafficByEmail(email)
@@ -83,6 +89,7 @@ func (a *InboundController) getClientTraffics(c *gin.Context) {
 	jsonObj(c, clientTraffics, nil)
 	jsonObj(c, clientTraffics, nil)
 }
 }
 
 
+// getClientTrafficsById retrieves client traffic information by inbound ID.
 func (a *InboundController) getClientTrafficsById(c *gin.Context) {
 func (a *InboundController) getClientTrafficsById(c *gin.Context) {
 	id := c.Param("id")
 	id := c.Param("id")
 	clientTraffics, err := a.inboundService.GetClientTrafficByID(id)
 	clientTraffics, err := a.inboundService.GetClientTrafficByID(id)
@@ -93,6 +100,7 @@ func (a *InboundController) getClientTrafficsById(c *gin.Context) {
 	jsonObj(c, clientTraffics, nil)
 	jsonObj(c, clientTraffics, nil)
 }
 }
 
 
+// addInbound creates a new inbound configuration.
 func (a *InboundController) addInbound(c *gin.Context) {
 func (a *InboundController) addInbound(c *gin.Context) {
 	inbound := &model.Inbound{}
 	inbound := &model.Inbound{}
 	err := c.ShouldBind(inbound)
 	err := c.ShouldBind(inbound)
@@ -119,6 +127,7 @@ func (a *InboundController) addInbound(c *gin.Context) {
 	}
 	}
 }
 }
 
 
+// delInbound deletes an inbound configuration by its ID.
 func (a *InboundController) delInbound(c *gin.Context) {
 func (a *InboundController) delInbound(c *gin.Context) {
 	id, err := strconv.Atoi(c.Param("id"))
 	id, err := strconv.Atoi(c.Param("id"))
 	if err != nil {
 	if err != nil {
@@ -136,6 +145,7 @@ func (a *InboundController) delInbound(c *gin.Context) {
 	}
 	}
 }
 }
 
 
+// updateInbound updates an existing inbound configuration.
 func (a *InboundController) updateInbound(c *gin.Context) {
 func (a *InboundController) updateInbound(c *gin.Context) {
 	id, err := strconv.Atoi(c.Param("id"))
 	id, err := strconv.Atoi(c.Param("id"))
 	if err != nil {
 	if err != nil {
@@ -161,6 +171,7 @@ func (a *InboundController) updateInbound(c *gin.Context) {
 	}
 	}
 }
 }
 
 
+// getClientIps retrieves the IP addresses associated with a client by email.
 func (a *InboundController) getClientIps(c *gin.Context) {
 func (a *InboundController) getClientIps(c *gin.Context) {
 	email := c.Param("email")
 	email := c.Param("email")
 
 
@@ -173,6 +184,7 @@ func (a *InboundController) getClientIps(c *gin.Context) {
 	jsonObj(c, ips, nil)
 	jsonObj(c, ips, nil)
 }
 }
 
 
+// clearClientIps clears the IP addresses for a client by email.
 func (a *InboundController) clearClientIps(c *gin.Context) {
 func (a *InboundController) clearClientIps(c *gin.Context) {
 	email := c.Param("email")
 	email := c.Param("email")
 
 
@@ -184,6 +196,7 @@ func (a *InboundController) clearClientIps(c *gin.Context) {
 	jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.logCleanSuccess"), nil)
 	jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.logCleanSuccess"), nil)
 }
 }
 
 
+// addInboundClient adds a new client to an existing inbound.
 func (a *InboundController) addInboundClient(c *gin.Context) {
 func (a *InboundController) addInboundClient(c *gin.Context) {
 	data := &model.Inbound{}
 	data := &model.Inbound{}
 	err := c.ShouldBind(data)
 	err := c.ShouldBind(data)
@@ -203,6 +216,7 @@ func (a *InboundController) addInboundClient(c *gin.Context) {
 	}
 	}
 }
 }
 
 
+// delInboundClient deletes a client from an inbound by inbound ID and client ID.
 func (a *InboundController) delInboundClient(c *gin.Context) {
 func (a *InboundController) delInboundClient(c *gin.Context) {
 	id, err := strconv.Atoi(c.Param("id"))
 	id, err := strconv.Atoi(c.Param("id"))
 	if err != nil {
 	if err != nil {
@@ -222,6 +236,7 @@ func (a *InboundController) delInboundClient(c *gin.Context) {
 	}
 	}
 }
 }
 
 
+// updateInboundClient updates a client's configuration in an inbound.
 func (a *InboundController) updateInboundClient(c *gin.Context) {
 func (a *InboundController) updateInboundClient(c *gin.Context) {
 	clientId := c.Param("clientId")
 	clientId := c.Param("clientId")
 
 
@@ -243,6 +258,7 @@ func (a *InboundController) updateInboundClient(c *gin.Context) {
 	}
 	}
 }
 }
 
 
+// resetClientTraffic resets the traffic counter for a specific client in an inbound.
 func (a *InboundController) resetClientTraffic(c *gin.Context) {
 func (a *InboundController) resetClientTraffic(c *gin.Context) {
 	id, err := strconv.Atoi(c.Param("id"))
 	id, err := strconv.Atoi(c.Param("id"))
 	if err != nil {
 	if err != nil {
@@ -262,6 +278,7 @@ func (a *InboundController) resetClientTraffic(c *gin.Context) {
 	}
 	}
 }
 }
 
 
+// resetAllTraffics resets all traffic counters across all inbounds.
 func (a *InboundController) resetAllTraffics(c *gin.Context) {
 func (a *InboundController) resetAllTraffics(c *gin.Context) {
 	err := a.inboundService.ResetAllTraffics()
 	err := a.inboundService.ResetAllTraffics()
 	if err != nil {
 	if err != nil {
@@ -273,6 +290,7 @@ func (a *InboundController) resetAllTraffics(c *gin.Context) {
 	jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.resetAllTrafficSuccess"), nil)
 	jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.resetAllTrafficSuccess"), nil)
 }
 }
 
 
+// resetAllClientTraffics resets traffic counters for all clients in a specific inbound.
 func (a *InboundController) resetAllClientTraffics(c *gin.Context) {
 func (a *InboundController) resetAllClientTraffics(c *gin.Context) {
 	id, err := strconv.Atoi(c.Param("id"))
 	id, err := strconv.Atoi(c.Param("id"))
 	if err != nil {
 	if err != nil {
@@ -290,6 +308,7 @@ func (a *InboundController) resetAllClientTraffics(c *gin.Context) {
 	jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.resetAllClientTrafficSuccess"), nil)
 	jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.resetAllClientTrafficSuccess"), nil)
 }
 }
 
 
+// importInbound imports an inbound configuration from provided data.
 func (a *InboundController) importInbound(c *gin.Context) {
 func (a *InboundController) importInbound(c *gin.Context) {
 	inbound := &model.Inbound{}
 	inbound := &model.Inbound{}
 	err := json.Unmarshal([]byte(c.PostForm("data")), inbound)
 	err := json.Unmarshal([]byte(c.PostForm("data")), inbound)
@@ -319,6 +338,7 @@ func (a *InboundController) importInbound(c *gin.Context) {
 	}
 	}
 }
 }
 
 
+// delDepletedClients deletes clients in an inbound who have exhausted their traffic limits.
 func (a *InboundController) delDepletedClients(c *gin.Context) {
 func (a *InboundController) delDepletedClients(c *gin.Context) {
 	id, err := strconv.Atoi(c.Param("id"))
 	id, err := strconv.Atoi(c.Param("id"))
 	if err != nil {
 	if err != nil {
@@ -333,15 +353,18 @@ func (a *InboundController) delDepletedClients(c *gin.Context) {
 	jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.delDepletedClientsSuccess"), nil)
 	jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.delDepletedClientsSuccess"), nil)
 }
 }
 
 
+// onlines retrieves the list of currently online clients.
 func (a *InboundController) onlines(c *gin.Context) {
 func (a *InboundController) onlines(c *gin.Context) {
 	jsonObj(c, a.inboundService.GetOnlineClients(), nil)
 	jsonObj(c, a.inboundService.GetOnlineClients(), nil)
 }
 }
 
 
+// lastOnline retrieves the last online timestamps for clients.
 func (a *InboundController) lastOnline(c *gin.Context) {
 func (a *InboundController) lastOnline(c *gin.Context) {
 	data, err := a.inboundService.GetClientsLastOnline()
 	data, err := a.inboundService.GetClientsLastOnline()
 	jsonObj(c, data, err)
 	jsonObj(c, data, err)
 }
 }
 
 
+// updateClientTraffic updates the traffic statistics for a client by email.
 func (a *InboundController) updateClientTraffic(c *gin.Context) {
 func (a *InboundController) updateClientTraffic(c *gin.Context) {
 	email := c.Param("email")
 	email := c.Param("email")
 
 
@@ -367,6 +390,7 @@ func (a *InboundController) updateClientTraffic(c *gin.Context) {
 	jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.inboundClientUpdateSuccess"), nil)
 	jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.inboundClientUpdateSuccess"), nil)
 }
 }
 
 
+// delInboundClientByEmail deletes a client from an inbound by email address.
 func (a *InboundController) delInboundClientByEmail(c *gin.Context) {
 func (a *InboundController) delInboundClientByEmail(c *gin.Context) {
 	inboundId, err := strconv.Atoi(c.Param("id"))
 	inboundId, err := strconv.Atoi(c.Param("id"))
 	if err != nil {
 	if err != nil {

+ 8 - 0
web/controller/index.go

@@ -13,12 +13,14 @@ import (
 	"github.com/gin-gonic/gin"
 	"github.com/gin-gonic/gin"
 )
 )
 
 
+// LoginForm represents the login request structure.
 type LoginForm struct {
 type LoginForm struct {
 	Username      string `json:"username" form:"username"`
 	Username      string `json:"username" form:"username"`
 	Password      string `json:"password" form:"password"`
 	Password      string `json:"password" form:"password"`
 	TwoFactorCode string `json:"twoFactorCode" form:"twoFactorCode"`
 	TwoFactorCode string `json:"twoFactorCode" form:"twoFactorCode"`
 }
 }
 
 
+// IndexController handles the main index and login-related routes.
 type IndexController struct {
 type IndexController struct {
 	BaseController
 	BaseController
 
 
@@ -27,12 +29,14 @@ type IndexController struct {
 	tgbot          service.Tgbot
 	tgbot          service.Tgbot
 }
 }
 
 
+// NewIndexController creates a new IndexController and initializes its routes.
 func NewIndexController(g *gin.RouterGroup) *IndexController {
 func NewIndexController(g *gin.RouterGroup) *IndexController {
 	a := &IndexController{}
 	a := &IndexController{}
 	a.initRouter(g)
 	a.initRouter(g)
 	return a
 	return a
 }
 }
 
 
+// initRouter sets up the routes for index, login, logout, and two-factor authentication.
 func (a *IndexController) initRouter(g *gin.RouterGroup) {
 func (a *IndexController) initRouter(g *gin.RouterGroup) {
 	g.GET("/", a.index)
 	g.GET("/", a.index)
 	g.POST("/login", a.login)
 	g.POST("/login", a.login)
@@ -40,6 +44,7 @@ func (a *IndexController) initRouter(g *gin.RouterGroup) {
 	g.POST("/getTwoFactorEnable", a.getTwoFactorEnable)
 	g.POST("/getTwoFactorEnable", a.getTwoFactorEnable)
 }
 }
 
 
+// index handles the root route, redirecting logged-in users to the panel or showing the login page.
 func (a *IndexController) index(c *gin.Context) {
 func (a *IndexController) index(c *gin.Context) {
 	if session.IsLogin(c) {
 	if session.IsLogin(c) {
 		c.Redirect(http.StatusTemporaryRedirect, "panel/")
 		c.Redirect(http.StatusTemporaryRedirect, "panel/")
@@ -48,6 +53,7 @@ func (a *IndexController) index(c *gin.Context) {
 	html(c, "login.html", "pages.login.title", nil)
 	html(c, "login.html", "pages.login.title", nil)
 }
 }
 
 
+// login handles user authentication and session creation.
 func (a *IndexController) login(c *gin.Context) {
 func (a *IndexController) login(c *gin.Context) {
 	var form LoginForm
 	var form LoginForm
 
 
@@ -95,6 +101,7 @@ func (a *IndexController) login(c *gin.Context) {
 	jsonMsg(c, I18nWeb(c, "pages.login.toasts.successLogin"), nil)
 	jsonMsg(c, I18nWeb(c, "pages.login.toasts.successLogin"), nil)
 }
 }
 
 
+// logout handles user logout by clearing the session and redirecting to the login page.
 func (a *IndexController) logout(c *gin.Context) {
 func (a *IndexController) logout(c *gin.Context) {
 	user := session.GetLoginUser(c)
 	user := session.GetLoginUser(c)
 	if user != nil {
 	if user != nil {
@@ -107,6 +114,7 @@ func (a *IndexController) logout(c *gin.Context) {
 	c.Redirect(http.StatusTemporaryRedirect, c.GetString("base_path"))
 	c.Redirect(http.StatusTemporaryRedirect, c.GetString("base_path"))
 }
 }
 
 
+// getTwoFactorEnable retrieves the current status of two-factor authentication.
 func (a *IndexController) getTwoFactorEnable(c *gin.Context) {
 func (a *IndexController) getTwoFactorEnable(c *gin.Context) {
 	status, err := a.settingService.GetTwoFactorEnable()
 	status, err := a.settingService.GetTwoFactorEnable()
 	if err == nil {
 	if err == nil {

+ 23 - 0
web/controller/server.go

@@ -15,6 +15,7 @@ import (
 
 
 var filenameRegex = regexp.MustCompile(`^[a-zA-Z0-9_\-.]+$`)
 var filenameRegex = regexp.MustCompile(`^[a-zA-Z0-9_\-.]+$`)
 
 
+// ServerController handles server management and status-related operations.
 type ServerController struct {
 type ServerController struct {
 	BaseController
 	BaseController
 
 
@@ -27,6 +28,7 @@ type ServerController struct {
 	lastGetVersionsTime int64 // unix seconds
 	lastGetVersionsTime int64 // unix seconds
 }
 }
 
 
+// NewServerController creates a new ServerController, initializes routes, and starts background tasks.
 func NewServerController(g *gin.RouterGroup) *ServerController {
 func NewServerController(g *gin.RouterGroup) *ServerController {
 	a := &ServerController{}
 	a := &ServerController{}
 	a.initRouter(g)
 	a.initRouter(g)
@@ -34,6 +36,7 @@ func NewServerController(g *gin.RouterGroup) *ServerController {
 	return a
 	return a
 }
 }
 
 
+// initRouter sets up the routes for server status, Xray management, and utility endpoints.
 func (a *ServerController) initRouter(g *gin.RouterGroup) {
 func (a *ServerController) initRouter(g *gin.RouterGroup) {
 
 
 	g.GET("/status", a.status)
 	g.GET("/status", a.status)
@@ -58,6 +61,7 @@ func (a *ServerController) initRouter(g *gin.RouterGroup) {
 	g.POST("/getNewEchCert", a.getNewEchCert)
 	g.POST("/getNewEchCert", a.getNewEchCert)
 }
 }
 
 
+// refreshStatus updates the cached server status and collects CPU history.
 func (a *ServerController) refreshStatus() {
 func (a *ServerController) refreshStatus() {
 	a.lastStatus = a.serverService.GetStatus(a.lastStatus)
 	a.lastStatus = a.serverService.GetStatus(a.lastStatus)
 	// collect cpu history when status is fresh
 	// collect cpu history when status is fresh
@@ -66,6 +70,7 @@ func (a *ServerController) refreshStatus() {
 	}
 	}
 }
 }
 
 
+// startTask initiates background tasks for continuous status monitoring.
 func (a *ServerController) startTask() {
 func (a *ServerController) startTask() {
 	webServer := global.GetWebServer()
 	webServer := global.GetWebServer()
 	c := webServer.GetCron()
 	c := webServer.GetCron()
@@ -76,8 +81,10 @@ func (a *ServerController) startTask() {
 	})
 	})
 }
 }
 
 
+// status returns the current server status information.
 func (a *ServerController) status(c *gin.Context) { jsonObj(c, a.lastStatus, nil) }
 func (a *ServerController) status(c *gin.Context) { jsonObj(c, a.lastStatus, nil) }
 
 
+// getCpuHistoryBucket retrieves aggregated CPU usage history based on the specified time bucket.
 func (a *ServerController) getCpuHistoryBucket(c *gin.Context) {
 func (a *ServerController) getCpuHistoryBucket(c *gin.Context) {
 	bucketStr := c.Param("bucket")
 	bucketStr := c.Param("bucket")
 	bucket, err := strconv.Atoi(bucketStr)
 	bucket, err := strconv.Atoi(bucketStr)
@@ -101,6 +108,7 @@ func (a *ServerController) getCpuHistoryBucket(c *gin.Context) {
 	jsonObj(c, points, nil)
 	jsonObj(c, points, nil)
 }
 }
 
 
+// getXrayVersion retrieves available Xray versions, with caching for 1 minute.
 func (a *ServerController) getXrayVersion(c *gin.Context) {
 func (a *ServerController) getXrayVersion(c *gin.Context) {
 	now := time.Now().Unix()
 	now := time.Now().Unix()
 	if now-a.lastGetVersionsTime <= 60 { // 1 minute cache
 	if now-a.lastGetVersionsTime <= 60 { // 1 minute cache
@@ -120,18 +128,21 @@ func (a *ServerController) getXrayVersion(c *gin.Context) {
 	jsonObj(c, versions, nil)
 	jsonObj(c, versions, nil)
 }
 }
 
 
+// installXray installs or updates Xray to the specified version.
 func (a *ServerController) installXray(c *gin.Context) {
 func (a *ServerController) installXray(c *gin.Context) {
 	version := c.Param("version")
 	version := c.Param("version")
 	err := a.serverService.UpdateXray(version)
 	err := a.serverService.UpdateXray(version)
 	jsonMsg(c, I18nWeb(c, "pages.index.xraySwitchVersionPopover"), err)
 	jsonMsg(c, I18nWeb(c, "pages.index.xraySwitchVersionPopover"), err)
 }
 }
 
 
+// updateGeofile updates the specified geo file for Xray.
 func (a *ServerController) updateGeofile(c *gin.Context) {
 func (a *ServerController) updateGeofile(c *gin.Context) {
 	fileName := c.Param("fileName")
 	fileName := c.Param("fileName")
 	err := a.serverService.UpdateGeofile(fileName)
 	err := a.serverService.UpdateGeofile(fileName)
 	jsonMsg(c, I18nWeb(c, "pages.index.geofileUpdatePopover"), err)
 	jsonMsg(c, I18nWeb(c, "pages.index.geofileUpdatePopover"), err)
 }
 }
 
 
+// stopXrayService stops the Xray service.
 func (a *ServerController) stopXrayService(c *gin.Context) {
 func (a *ServerController) stopXrayService(c *gin.Context) {
 	err := a.serverService.StopXrayService()
 	err := a.serverService.StopXrayService()
 	if err != nil {
 	if err != nil {
@@ -141,6 +152,7 @@ func (a *ServerController) stopXrayService(c *gin.Context) {
 	jsonMsg(c, I18nWeb(c, "pages.xray.stopSuccess"), err)
 	jsonMsg(c, I18nWeb(c, "pages.xray.stopSuccess"), err)
 }
 }
 
 
+// restartXrayService restarts the Xray service.
 func (a *ServerController) restartXrayService(c *gin.Context) {
 func (a *ServerController) restartXrayService(c *gin.Context) {
 	err := a.serverService.RestartXrayService()
 	err := a.serverService.RestartXrayService()
 	if err != nil {
 	if err != nil {
@@ -150,6 +162,7 @@ func (a *ServerController) restartXrayService(c *gin.Context) {
 	jsonMsg(c, I18nWeb(c, "pages.xray.restartSuccess"), err)
 	jsonMsg(c, I18nWeb(c, "pages.xray.restartSuccess"), err)
 }
 }
 
 
+// getLogs retrieves the application logs based on count, level, and syslog filters.
 func (a *ServerController) getLogs(c *gin.Context) {
 func (a *ServerController) getLogs(c *gin.Context) {
 	count := c.Param("count")
 	count := c.Param("count")
 	level := c.PostForm("level")
 	level := c.PostForm("level")
@@ -158,6 +171,7 @@ func (a *ServerController) getLogs(c *gin.Context) {
 	jsonObj(c, logs, nil)
 	jsonObj(c, logs, nil)
 }
 }
 
 
+// getXrayLogs retrieves Xray logs with filtering options for direct, blocked, and proxy traffic.
 func (a *ServerController) getXrayLogs(c *gin.Context) {
 func (a *ServerController) getXrayLogs(c *gin.Context) {
 	count := c.Param("count")
 	count := c.Param("count")
 	filter := c.PostForm("filter")
 	filter := c.PostForm("filter")
@@ -202,6 +216,7 @@ func (a *ServerController) getXrayLogs(c *gin.Context) {
 	jsonObj(c, logs, nil)
 	jsonObj(c, logs, nil)
 }
 }
 
 
+// getConfigJson retrieves the Xray configuration as JSON.
 func (a *ServerController) getConfigJson(c *gin.Context) {
 func (a *ServerController) getConfigJson(c *gin.Context) {
 	configJson, err := a.serverService.GetConfigJson()
 	configJson, err := a.serverService.GetConfigJson()
 	if err != nil {
 	if err != nil {
@@ -211,6 +226,7 @@ func (a *ServerController) getConfigJson(c *gin.Context) {
 	jsonObj(c, configJson, nil)
 	jsonObj(c, configJson, nil)
 }
 }
 
 
+// getDb downloads the database file.
 func (a *ServerController) getDb(c *gin.Context) {
 func (a *ServerController) getDb(c *gin.Context) {
 	db, err := a.serverService.GetDb()
 	db, err := a.serverService.GetDb()
 	if err != nil {
 	if err != nil {
@@ -238,6 +254,7 @@ func isValidFilename(filename string) bool {
 	return filenameRegex.MatchString(filename)
 	return filenameRegex.MatchString(filename)
 }
 }
 
 
+// importDB imports a database file and restarts the Xray service.
 func (a *ServerController) importDB(c *gin.Context) {
 func (a *ServerController) importDB(c *gin.Context) {
 	// Get the file from the request body
 	// Get the file from the request body
 	file, _, err := c.Request.FormFile("db")
 	file, _, err := c.Request.FormFile("db")
@@ -258,6 +275,7 @@ func (a *ServerController) importDB(c *gin.Context) {
 	jsonObj(c, I18nWeb(c, "pages.index.importDatabaseSuccess"), nil)
 	jsonObj(c, I18nWeb(c, "pages.index.importDatabaseSuccess"), nil)
 }
 }
 
 
+// getNewX25519Cert generates a new X25519 certificate.
 func (a *ServerController) getNewX25519Cert(c *gin.Context) {
 func (a *ServerController) getNewX25519Cert(c *gin.Context) {
 	cert, err := a.serverService.GetNewX25519Cert()
 	cert, err := a.serverService.GetNewX25519Cert()
 	if err != nil {
 	if err != nil {
@@ -267,6 +285,7 @@ func (a *ServerController) getNewX25519Cert(c *gin.Context) {
 	jsonObj(c, cert, nil)
 	jsonObj(c, cert, nil)
 }
 }
 
 
+// getNewmldsa65 generates a new ML-DSA-65 key.
 func (a *ServerController) getNewmldsa65(c *gin.Context) {
 func (a *ServerController) getNewmldsa65(c *gin.Context) {
 	cert, err := a.serverService.GetNewmldsa65()
 	cert, err := a.serverService.GetNewmldsa65()
 	if err != nil {
 	if err != nil {
@@ -276,6 +295,7 @@ func (a *ServerController) getNewmldsa65(c *gin.Context) {
 	jsonObj(c, cert, nil)
 	jsonObj(c, cert, nil)
 }
 }
 
 
+// getNewEchCert generates a new ECH certificate for the given SNI.
 func (a *ServerController) getNewEchCert(c *gin.Context) {
 func (a *ServerController) getNewEchCert(c *gin.Context) {
 	sni := c.PostForm("sni")
 	sni := c.PostForm("sni")
 	cert, err := a.serverService.GetNewEchCert(sni)
 	cert, err := a.serverService.GetNewEchCert(sni)
@@ -286,6 +306,7 @@ func (a *ServerController) getNewEchCert(c *gin.Context) {
 	jsonObj(c, cert, nil)
 	jsonObj(c, cert, nil)
 }
 }
 
 
+// getNewVlessEnc generates a new VLESS encryption key.
 func (a *ServerController) getNewVlessEnc(c *gin.Context) {
 func (a *ServerController) getNewVlessEnc(c *gin.Context) {
 	out, err := a.serverService.GetNewVlessEnc()
 	out, err := a.serverService.GetNewVlessEnc()
 	if err != nil {
 	if err != nil {
@@ -295,6 +316,7 @@ func (a *ServerController) getNewVlessEnc(c *gin.Context) {
 	jsonObj(c, out, nil)
 	jsonObj(c, out, nil)
 }
 }
 
 
+// getNewUUID generates a new UUID.
 func (a *ServerController) getNewUUID(c *gin.Context) {
 func (a *ServerController) getNewUUID(c *gin.Context) {
 	uuidResp, err := a.serverService.GetNewUUID()
 	uuidResp, err := a.serverService.GetNewUUID()
 	if err != nil {
 	if err != nil {
@@ -305,6 +327,7 @@ func (a *ServerController) getNewUUID(c *gin.Context) {
 	jsonObj(c, uuidResp, nil)
 	jsonObj(c, uuidResp, nil)
 }
 }
 
 
+// getNewmlkem768 generates a new ML-KEM-768 key.
 func (a *ServerController) getNewmlkem768(c *gin.Context) {
 func (a *ServerController) getNewmlkem768(c *gin.Context) {
 	out, err := a.serverService.GetNewmlkem768()
 	out, err := a.serverService.GetNewmlkem768()
 	if err != nil {
 	if err != nil {

+ 10 - 0
web/controller/setting.go

@@ -12,6 +12,7 @@ import (
 	"github.com/gin-gonic/gin"
 	"github.com/gin-gonic/gin"
 )
 )
 
 
+// updateUserForm represents the form for updating user credentials.
 type updateUserForm struct {
 type updateUserForm struct {
 	OldUsername string `json:"oldUsername" form:"oldUsername"`
 	OldUsername string `json:"oldUsername" form:"oldUsername"`
 	OldPassword string `json:"oldPassword" form:"oldPassword"`
 	OldPassword string `json:"oldPassword" form:"oldPassword"`
@@ -19,18 +20,21 @@ type updateUserForm struct {
 	NewPassword string `json:"newPassword" form:"newPassword"`
 	NewPassword string `json:"newPassword" form:"newPassword"`
 }
 }
 
 
+// SettingController handles settings and user management operations.
 type SettingController struct {
 type SettingController struct {
 	settingService service.SettingService
 	settingService service.SettingService
 	userService    service.UserService
 	userService    service.UserService
 	panelService   service.PanelService
 	panelService   service.PanelService
 }
 }
 
 
+// NewSettingController creates a new SettingController and initializes its routes.
 func NewSettingController(g *gin.RouterGroup) *SettingController {
 func NewSettingController(g *gin.RouterGroup) *SettingController {
 	a := &SettingController{}
 	a := &SettingController{}
 	a.initRouter(g)
 	a.initRouter(g)
 	return a
 	return a
 }
 }
 
 
+// initRouter sets up the routes for settings management.
 func (a *SettingController) initRouter(g *gin.RouterGroup) {
 func (a *SettingController) initRouter(g *gin.RouterGroup) {
 	g = g.Group("/setting")
 	g = g.Group("/setting")
 
 
@@ -42,6 +46,7 @@ func (a *SettingController) initRouter(g *gin.RouterGroup) {
 	g.GET("/getDefaultJsonConfig", a.getDefaultXrayConfig)
 	g.GET("/getDefaultJsonConfig", a.getDefaultXrayConfig)
 }
 }
 
 
+// getAllSetting retrieves all current settings.
 func (a *SettingController) getAllSetting(c *gin.Context) {
 func (a *SettingController) getAllSetting(c *gin.Context) {
 	allSetting, err := a.settingService.GetAllSetting()
 	allSetting, err := a.settingService.GetAllSetting()
 	if err != nil {
 	if err != nil {
@@ -51,6 +56,7 @@ func (a *SettingController) getAllSetting(c *gin.Context) {
 	jsonObj(c, allSetting, nil)
 	jsonObj(c, allSetting, nil)
 }
 }
 
 
+// getDefaultSettings retrieves the default settings based on the host.
 func (a *SettingController) getDefaultSettings(c *gin.Context) {
 func (a *SettingController) getDefaultSettings(c *gin.Context) {
 	result, err := a.settingService.GetDefaultSettings(c.Request.Host)
 	result, err := a.settingService.GetDefaultSettings(c.Request.Host)
 	if err != nil {
 	if err != nil {
@@ -60,6 +66,7 @@ func (a *SettingController) getDefaultSettings(c *gin.Context) {
 	jsonObj(c, result, nil)
 	jsonObj(c, result, nil)
 }
 }
 
 
+// updateSetting updates all settings with the provided data.
 func (a *SettingController) updateSetting(c *gin.Context) {
 func (a *SettingController) updateSetting(c *gin.Context) {
 	allSetting := &entity.AllSetting{}
 	allSetting := &entity.AllSetting{}
 	err := c.ShouldBind(allSetting)
 	err := c.ShouldBind(allSetting)
@@ -71,6 +78,7 @@ func (a *SettingController) updateSetting(c *gin.Context) {
 	jsonMsg(c, I18nWeb(c, "pages.settings.toasts.modifySettings"), err)
 	jsonMsg(c, I18nWeb(c, "pages.settings.toasts.modifySettings"), err)
 }
 }
 
 
+// updateUser updates the current user's username and password.
 func (a *SettingController) updateUser(c *gin.Context) {
 func (a *SettingController) updateUser(c *gin.Context) {
 	form := &updateUserForm{}
 	form := &updateUserForm{}
 	err := c.ShouldBind(form)
 	err := c.ShouldBind(form)
@@ -96,11 +104,13 @@ func (a *SettingController) updateUser(c *gin.Context) {
 	jsonMsg(c, I18nWeb(c, "pages.settings.toasts.modifyUser"), err)
 	jsonMsg(c, I18nWeb(c, "pages.settings.toasts.modifyUser"), err)
 }
 }
 
 
+// restartPanel restarts the panel service after a delay.
 func (a *SettingController) restartPanel(c *gin.Context) {
 func (a *SettingController) restartPanel(c *gin.Context) {
 	err := a.panelService.RestartPanel(time.Second * 3)
 	err := a.panelService.RestartPanel(time.Second * 3)
 	jsonMsg(c, I18nWeb(c, "pages.settings.restartPanelSuccess"), err)
 	jsonMsg(c, I18nWeb(c, "pages.settings.restartPanelSuccess"), err)
 }
 }
 
 
+// getDefaultXrayConfig retrieves the default Xray configuration.
 func (a *SettingController) getDefaultXrayConfig(c *gin.Context) {
 func (a *SettingController) getDefaultXrayConfig(c *gin.Context) {
 	defaultJsonConfig, err := a.settingService.GetDefaultXrayConfig()
 	defaultJsonConfig, err := a.settingService.GetDefaultXrayConfig()
 	if err != nil {
 	if err != nil {

+ 8 - 0
web/controller/util.go

@@ -12,6 +12,7 @@ import (
 	"github.com/gin-gonic/gin"
 	"github.com/gin-gonic/gin"
 )
 )
 
 
+// getRemoteIp extracts the real IP address from the request headers or remote address.
 func getRemoteIp(c *gin.Context) string {
 func getRemoteIp(c *gin.Context) string {
 	value := c.GetHeader("X-Real-IP")
 	value := c.GetHeader("X-Real-IP")
 	if value != "" {
 	if value != "" {
@@ -27,14 +28,17 @@ func getRemoteIp(c *gin.Context) string {
 	return ip
 	return ip
 }
 }
 
 
+// jsonMsg sends a JSON response with a message and error status.
 func jsonMsg(c *gin.Context, msg string, err error) {
 func jsonMsg(c *gin.Context, msg string, err error) {
 	jsonMsgObj(c, msg, nil, err)
 	jsonMsgObj(c, msg, nil, err)
 }
 }
 
 
+// jsonObj sends a JSON response with an object and error status.
 func jsonObj(c *gin.Context, obj any, err error) {
 func jsonObj(c *gin.Context, obj any, err error) {
 	jsonMsgObj(c, "", obj, err)
 	jsonMsgObj(c, "", obj, err)
 }
 }
 
 
+// jsonMsgObj sends a JSON response with a message, object, and error status.
 func jsonMsgObj(c *gin.Context, msg string, obj any, err error) {
 func jsonMsgObj(c *gin.Context, msg string, obj any, err error) {
 	m := entity.Msg{
 	m := entity.Msg{
 		Obj: obj,
 		Obj: obj,
@@ -52,6 +56,7 @@ func jsonMsgObj(c *gin.Context, msg string, obj any, err error) {
 	c.JSON(http.StatusOK, m)
 	c.JSON(http.StatusOK, m)
 }
 }
 
 
+// pureJsonMsg sends a pure JSON message response with custom status code.
 func pureJsonMsg(c *gin.Context, statusCode int, success bool, msg string) {
 func pureJsonMsg(c *gin.Context, statusCode int, success bool, msg string) {
 	c.JSON(statusCode, entity.Msg{
 	c.JSON(statusCode, entity.Msg{
 		Success: success,
 		Success: success,
@@ -59,6 +64,7 @@ func pureJsonMsg(c *gin.Context, statusCode int, success bool, msg string) {
 	})
 	})
 }
 }
 
 
+// html renders an HTML template with the provided data and title.
 func html(c *gin.Context, name string, title string, data gin.H) {
 func html(c *gin.Context, name string, title string, data gin.H) {
 	if data == nil {
 	if data == nil {
 		data = gin.H{}
 		data = gin.H{}
@@ -81,6 +87,7 @@ func html(c *gin.Context, name string, title string, data gin.H) {
 	c.HTML(http.StatusOK, name, getContext(data))
 	c.HTML(http.StatusOK, name, getContext(data))
 }
 }
 
 
+// getContext adds version and other context data to the provided gin.H.
 func getContext(h gin.H) gin.H {
 func getContext(h gin.H) gin.H {
 	a := gin.H{
 	a := gin.H{
 		"cur_ver": config.GetVersion(),
 		"cur_ver": config.GetVersion(),
@@ -91,6 +98,7 @@ func getContext(h gin.H) gin.H {
 	return a
 	return a
 }
 }
 
 
+// isAjax checks if the request is an AJAX request.
 func isAjax(c *gin.Context) bool {
 func isAjax(c *gin.Context) bool {
 	return c.GetHeader("X-Requested-With") == "XMLHttpRequest"
 	return c.GetHeader("X-Requested-With") == "XMLHttpRequest"
 }
 }

+ 10 - 0
web/controller/xray_setting.go

@@ -6,6 +6,7 @@ import (
 	"github.com/gin-gonic/gin"
 	"github.com/gin-gonic/gin"
 )
 )
 
 
+// XraySettingController handles Xray configuration and settings operations.
 type XraySettingController struct {
 type XraySettingController struct {
 	XraySettingService service.XraySettingService
 	XraySettingService service.XraySettingService
 	SettingService     service.SettingService
 	SettingService     service.SettingService
@@ -15,12 +16,14 @@ type XraySettingController struct {
 	WarpService        service.WarpService
 	WarpService        service.WarpService
 }
 }
 
 
+// NewXraySettingController creates a new XraySettingController and initializes its routes.
 func NewXraySettingController(g *gin.RouterGroup) *XraySettingController {
 func NewXraySettingController(g *gin.RouterGroup) *XraySettingController {
 	a := &XraySettingController{}
 	a := &XraySettingController{}
 	a.initRouter(g)
 	a.initRouter(g)
 	return a
 	return a
 }
 }
 
 
+// initRouter sets up the routes for Xray settings management.
 func (a *XraySettingController) initRouter(g *gin.RouterGroup) {
 func (a *XraySettingController) initRouter(g *gin.RouterGroup) {
 	g = g.Group("/xray")
 	g = g.Group("/xray")
 	g.GET("/getDefaultJsonConfig", a.getDefaultXrayConfig)
 	g.GET("/getDefaultJsonConfig", a.getDefaultXrayConfig)
@@ -33,6 +36,7 @@ func (a *XraySettingController) initRouter(g *gin.RouterGroup) {
 	g.POST("/resetOutboundsTraffic", a.resetOutboundsTraffic)
 	g.POST("/resetOutboundsTraffic", a.resetOutboundsTraffic)
 }
 }
 
 
+// getXraySetting retrieves the Xray configuration template and inbound tags.
 func (a *XraySettingController) getXraySetting(c *gin.Context) {
 func (a *XraySettingController) getXraySetting(c *gin.Context) {
 	xraySetting, err := a.SettingService.GetXrayConfigTemplate()
 	xraySetting, err := a.SettingService.GetXrayConfigTemplate()
 	if err != nil {
 	if err != nil {
@@ -48,12 +52,14 @@ func (a *XraySettingController) getXraySetting(c *gin.Context) {
 	jsonObj(c, xrayResponse, nil)
 	jsonObj(c, xrayResponse, nil)
 }
 }
 
 
+// updateSetting updates the Xray configuration settings.
 func (a *XraySettingController) updateSetting(c *gin.Context) {
 func (a *XraySettingController) updateSetting(c *gin.Context) {
 	xraySetting := c.PostForm("xraySetting")
 	xraySetting := c.PostForm("xraySetting")
 	err := a.XraySettingService.SaveXraySetting(xraySetting)
 	err := a.XraySettingService.SaveXraySetting(xraySetting)
 	jsonMsg(c, I18nWeb(c, "pages.settings.toasts.modifySettings"), err)
 	jsonMsg(c, I18nWeb(c, "pages.settings.toasts.modifySettings"), err)
 }
 }
 
 
+// getDefaultXrayConfig retrieves the default Xray configuration.
 func (a *XraySettingController) getDefaultXrayConfig(c *gin.Context) {
 func (a *XraySettingController) getDefaultXrayConfig(c *gin.Context) {
 	defaultJsonConfig, err := a.SettingService.GetDefaultXrayConfig()
 	defaultJsonConfig, err := a.SettingService.GetDefaultXrayConfig()
 	if err != nil {
 	if err != nil {
@@ -63,10 +69,12 @@ func (a *XraySettingController) getDefaultXrayConfig(c *gin.Context) {
 	jsonObj(c, defaultJsonConfig, nil)
 	jsonObj(c, defaultJsonConfig, nil)
 }
 }
 
 
+// getXrayResult retrieves the current Xray service result.
 func (a *XraySettingController) getXrayResult(c *gin.Context) {
 func (a *XraySettingController) getXrayResult(c *gin.Context) {
 	jsonObj(c, a.XrayService.GetXrayResult(), nil)
 	jsonObj(c, a.XrayService.GetXrayResult(), nil)
 }
 }
 
 
+// warp handles Warp-related operations based on the action parameter.
 func (a *XraySettingController) warp(c *gin.Context) {
 func (a *XraySettingController) warp(c *gin.Context) {
 	action := c.Param("action")
 	action := c.Param("action")
 	var resp string
 	var resp string
@@ -90,6 +98,7 @@ func (a *XraySettingController) warp(c *gin.Context) {
 	jsonObj(c, resp, err)
 	jsonObj(c, resp, err)
 }
 }
 
 
+// getOutboundsTraffic retrieves the traffic statistics for outbounds.
 func (a *XraySettingController) getOutboundsTraffic(c *gin.Context) {
 func (a *XraySettingController) getOutboundsTraffic(c *gin.Context) {
 	outboundsTraffic, err := a.OutboundService.GetOutboundsTraffic()
 	outboundsTraffic, err := a.OutboundService.GetOutboundsTraffic()
 	if err != nil {
 	if err != nil {
@@ -99,6 +108,7 @@ func (a *XraySettingController) getOutboundsTraffic(c *gin.Context) {
 	jsonObj(c, outboundsTraffic, nil)
 	jsonObj(c, outboundsTraffic, nil)
 }
 }
 
 
+// resetOutboundsTraffic resets the traffic statistics for the specified outbound tag.
 func (a *XraySettingController) resetOutboundsTraffic(c *gin.Context) {
 func (a *XraySettingController) resetOutboundsTraffic(c *gin.Context) {
 	tag := c.PostForm("tag")
 	tag := c.PostForm("tag")
 	err := a.OutboundService.ResetOutboundTraffic(tag)
 	err := a.OutboundService.ResetOutboundTraffic(tag)

+ 7 - 0
web/controller/xui.go

@@ -4,6 +4,7 @@ import (
 	"github.com/gin-gonic/gin"
 	"github.com/gin-gonic/gin"
 )
 )
 
 
+// XUIController is the main controller for the X-UI panel, managing sub-controllers.
 type XUIController struct {
 type XUIController struct {
 	BaseController
 	BaseController
 
 
@@ -13,12 +14,14 @@ type XUIController struct {
 	xraySettingController *XraySettingController
 	xraySettingController *XraySettingController
 }
 }
 
 
+// NewXUIController creates a new XUIController and initializes its routes.
 func NewXUIController(g *gin.RouterGroup) *XUIController {
 func NewXUIController(g *gin.RouterGroup) *XUIController {
 	a := &XUIController{}
 	a := &XUIController{}
 	a.initRouter(g)
 	a.initRouter(g)
 	return a
 	return a
 }
 }
 
 
+// initRouter sets up the main panel routes and initializes sub-controllers.
 func (a *XUIController) initRouter(g *gin.RouterGroup) {
 func (a *XUIController) initRouter(g *gin.RouterGroup) {
 	g = g.Group("/panel")
 	g = g.Group("/panel")
 	g.Use(a.checkLogin)
 	g.Use(a.checkLogin)
@@ -34,18 +37,22 @@ func (a *XUIController) initRouter(g *gin.RouterGroup) {
 	a.xraySettingController = NewXraySettingController(g)
 	a.xraySettingController = NewXraySettingController(g)
 }
 }
 
 
+// index renders the main panel index page.
 func (a *XUIController) index(c *gin.Context) {
 func (a *XUIController) index(c *gin.Context) {
 	html(c, "index.html", "pages.index.title", nil)
 	html(c, "index.html", "pages.index.title", nil)
 }
 }
 
 
+// inbounds renders the inbounds management page.
 func (a *XUIController) inbounds(c *gin.Context) {
 func (a *XUIController) inbounds(c *gin.Context) {
 	html(c, "inbounds.html", "pages.inbounds.title", nil)
 	html(c, "inbounds.html", "pages.inbounds.title", nil)
 }
 }
 
 
+// settings renders the settings management page.
 func (a *XUIController) settings(c *gin.Context) {
 func (a *XUIController) settings(c *gin.Context) {
 	html(c, "settings.html", "pages.settings.title", nil)
 	html(c, "settings.html", "pages.settings.title", nil)
 }
 }
 
 
+// xraySettings renders the Xray settings page.
 func (a *XUIController) xraySettings(c *gin.Context) {
 func (a *XUIController) xraySettings(c *gin.Context) {
 	html(c, "xray.html", "pages.xray.title", nil)
 	html(c, "xray.html", "pages.xray.title", nil)
 }
 }

+ 62 - 49
web/entity/entity.go

@@ -1,3 +1,4 @@
+// Package entity defines data structures and entities used by the web layer of the 3x-ui panel.
 package entity
 package entity
 
 
 import (
 import (
@@ -10,61 +11,73 @@ import (
 	"github.com/mhsanaei/3x-ui/v2/util/common"
 	"github.com/mhsanaei/3x-ui/v2/util/common"
 )
 )
 
 
+// Msg represents a standard API response message with success status, message text, and optional data object.
 type Msg struct {
 type Msg struct {
-	Success bool   `json:"success"`
-	Msg     string `json:"msg"`
-	Obj     any    `json:"obj"`
+	Success bool   `json:"success"` // Indicates if the operation was successful
+	Msg     string `json:"msg"`     // Response message text
+	Obj     any    `json:"obj"`     // Optional data object
 }
 }
 
 
+// AllSetting contains all configuration settings for the 3x-ui panel including web server, Telegram bot, and subscription settings.
 type AllSetting struct {
 type AllSetting struct {
-	WebListen                   string `json:"webListen" form:"webListen"`
-	WebDomain                   string `json:"webDomain" form:"webDomain"`
-	WebPort                     int    `json:"webPort" form:"webPort"`
-	WebCertFile                 string `json:"webCertFile" form:"webCertFile"`
-	WebKeyFile                  string `json:"webKeyFile" form:"webKeyFile"`
-	WebBasePath                 string `json:"webBasePath" form:"webBasePath"`
-	SessionMaxAge               int    `json:"sessionMaxAge" form:"sessionMaxAge"`
-	PageSize                    int    `json:"pageSize" form:"pageSize"`
-	ExpireDiff                  int    `json:"expireDiff" form:"expireDiff"`
-	TrafficDiff                 int    `json:"trafficDiff" form:"trafficDiff"`
-	RemarkModel                 string `json:"remarkModel" form:"remarkModel"`
-	TgBotEnable                 bool   `json:"tgBotEnable" form:"tgBotEnable"`
-	TgBotToken                  string `json:"tgBotToken" form:"tgBotToken"`
-	TgBotProxy                  string `json:"tgBotProxy" form:"tgBotProxy"`
-	TgBotAPIServer              string `json:"tgBotAPIServer" form:"tgBotAPIServer"`
-	TgBotChatId                 string `json:"tgBotChatId" form:"tgBotChatId"`
-	TgRunTime                   string `json:"tgRunTime" form:"tgRunTime"`
-	TgBotBackup                 bool   `json:"tgBotBackup" form:"tgBotBackup"`
-	TgBotLoginNotify            bool   `json:"tgBotLoginNotify" form:"tgBotLoginNotify"`
-	TgCpu                       int    `json:"tgCpu" form:"tgCpu"`
-	TgLang                      string `json:"tgLang" form:"tgLang"`
-	TimeLocation                string `json:"timeLocation" form:"timeLocation"`
-	TwoFactorEnable             bool   `json:"twoFactorEnable" form:"twoFactorEnable"`
-	TwoFactorToken              string `json:"twoFactorToken" form:"twoFactorToken"`
-	SubEnable                   bool   `json:"subEnable" form:"subEnable"`
-	SubJsonEnable               bool   `json:"subJsonEnable" form:"subJsonEnable"`
-	SubTitle                    string `json:"subTitle" form:"subTitle"`
-	SubListen                   string `json:"subListen" form:"subListen"`
-	SubPort                     int    `json:"subPort" form:"subPort"`
-	SubPath                     string `json:"subPath" form:"subPath"`
-	SubDomain                   string `json:"subDomain" form:"subDomain"`
-	SubCertFile                 string `json:"subCertFile" form:"subCertFile"`
-	SubKeyFile                  string `json:"subKeyFile" form:"subKeyFile"`
-	SubUpdates                  int    `json:"subUpdates" form:"subUpdates"`
-	ExternalTrafficInformEnable bool   `json:"externalTrafficInformEnable" form:"externalTrafficInformEnable"`
-	ExternalTrafficInformURI    string `json:"externalTrafficInformURI" form:"externalTrafficInformURI"`
-	SubEncrypt                  bool   `json:"subEncrypt" form:"subEncrypt"`
-	SubShowInfo                 bool   `json:"subShowInfo" form:"subShowInfo"`
-	SubURI                      string `json:"subURI" form:"subURI"`
-	SubJsonPath                 string `json:"subJsonPath" form:"subJsonPath"`
-	SubJsonURI                  string `json:"subJsonURI" form:"subJsonURI"`
-	SubJsonFragment             string `json:"subJsonFragment" form:"subJsonFragment"`
-	SubJsonNoises               string `json:"subJsonNoises" form:"subJsonNoises"`
-	SubJsonMux                  string `json:"subJsonMux" form:"subJsonMux"`
-	SubJsonRules                string `json:"subJsonRules" form:"subJsonRules"`
-	Datepicker                  string `json:"datepicker" form:"datepicker"`
+	// Web server settings
+	WebListen     string `json:"webListen" form:"webListen"`         // Web server listen IP address
+	WebDomain     string `json:"webDomain" form:"webDomain"`         // Web server domain for domain validation
+	WebPort       int    `json:"webPort" form:"webPort"`             // Web server port number
+	WebCertFile   string `json:"webCertFile" form:"webCertFile"`     // Path to SSL certificate file for web server
+	WebKeyFile    string `json:"webKeyFile" form:"webKeyFile"`       // Path to SSL private key file for web server
+	WebBasePath   string `json:"webBasePath" form:"webBasePath"`     // Base path for web panel URLs
+	SessionMaxAge int    `json:"sessionMaxAge" form:"sessionMaxAge"` // Session maximum age in minutes
+
+	// UI settings
+	PageSize    int    `json:"pageSize" form:"pageSize"`       // Number of items per page in lists
+	ExpireDiff  int    `json:"expireDiff" form:"expireDiff"`   // Expiration warning threshold in days
+	TrafficDiff int    `json:"trafficDiff" form:"trafficDiff"` // Traffic warning threshold percentage
+	RemarkModel string `json:"remarkModel" form:"remarkModel"` // Remark model pattern for inbounds
+	Datepicker  string `json:"datepicker" form:"datepicker"`   // Date picker format
+
+	// Telegram bot settings
+	TgBotEnable      bool   `json:"tgBotEnable" form:"tgBotEnable"`           // Enable Telegram bot notifications
+	TgBotToken       string `json:"tgBotToken" form:"tgBotToken"`             // Telegram bot token
+	TgBotProxy       string `json:"tgBotProxy" form:"tgBotProxy"`             // Proxy URL for Telegram bot
+	TgBotAPIServer   string `json:"tgBotAPIServer" form:"tgBotAPIServer"`     // Custom API server for Telegram bot
+	TgBotChatId      string `json:"tgBotChatId" form:"tgBotChatId"`           // Telegram chat ID for notifications
+	TgRunTime        string `json:"tgRunTime" form:"tgRunTime"`               // Cron schedule for Telegram notifications
+	TgBotBackup      bool   `json:"tgBotBackup" form:"tgBotBackup"`           // Enable database backup via Telegram
+	TgBotLoginNotify bool   `json:"tgBotLoginNotify" form:"tgBotLoginNotify"` // Send login notifications
+	TgCpu            int    `json:"tgCpu" form:"tgCpu"`                       // CPU usage threshold for alerts
+	TgLang           string `json:"tgLang" form:"tgLang"`                     // Telegram bot language
+
+	// Security settings
+	TimeLocation    string `json:"timeLocation" form:"timeLocation"`       // Time zone location
+	TwoFactorEnable bool   `json:"twoFactorEnable" form:"twoFactorEnable"` // Enable two-factor authentication
+	TwoFactorToken  string `json:"twoFactorToken" form:"twoFactorToken"`   // Two-factor authentication token
+
+	// Subscription server settings
+	SubEnable                   bool   `json:"subEnable" form:"subEnable"`                                     // Enable subscription server
+	SubJsonEnable               bool   `json:"subJsonEnable" form:"subJsonEnable"`                             // Enable JSON subscription endpoint
+	SubTitle                    string `json:"subTitle" form:"subTitle"`                                       // Subscription title
+	SubListen                   string `json:"subListen" form:"subListen"`                                     // Subscription server listen IP
+	SubPort                     int    `json:"subPort" form:"subPort"`                                         // Subscription server port
+	SubPath                     string `json:"subPath" form:"subPath"`                                         // Base path for subscription URLs
+	SubDomain                   string `json:"subDomain" form:"subDomain"`                                     // Domain for subscription server validation
+	SubCertFile                 string `json:"subCertFile" form:"subCertFile"`                                 // SSL certificate file for subscription server
+	SubKeyFile                  string `json:"subKeyFile" form:"subKeyFile"`                                   // SSL private key file for subscription server
+	SubUpdates                  int    `json:"subUpdates" form:"subUpdates"`                                   // Subscription update interval in minutes
+	ExternalTrafficInformEnable bool   `json:"externalTrafficInformEnable" form:"externalTrafficInformEnable"` // Enable external traffic reporting
+	ExternalTrafficInformURI    string `json:"externalTrafficInformURI" form:"externalTrafficInformURI"`       // URI for external traffic reporting
+	SubEncrypt                  bool   `json:"subEncrypt" form:"subEncrypt"`                                   // Encrypt subscription responses
+	SubShowInfo                 bool   `json:"subShowInfo" form:"subShowInfo"`                                 // Show client information in subscriptions
+	SubURI                      string `json:"subURI" form:"subURI"`                                           // Subscription server URI
+	SubJsonPath                 string `json:"subJsonPath" form:"subJsonPath"`                                 // Path for JSON subscription endpoint
+	SubJsonURI                  string `json:"subJsonURI" form:"subJsonURI"`                                   // JSON subscription server URI
+	SubJsonFragment             string `json:"subJsonFragment" form:"subJsonFragment"`                         // JSON subscription fragment configuration
+	SubJsonNoises               string `json:"subJsonNoises" form:"subJsonNoises"`                             // JSON subscription noise configuration
+	SubJsonMux                  string `json:"subJsonMux" form:"subJsonMux"`                                   // JSON subscription mux configuration
+	SubJsonRules                string `json:"subJsonRules" form:"subJsonRules"`                               // JSON subscription routing rules
 }
 }
 
 
+// CheckValid validates all settings in the AllSetting struct, checking IP addresses, ports, SSL certificates, and other configuration values.
 func (s *AllSetting) CheckValid() error {
 func (s *AllSetting) CheckValid() error {
 	if s.WebListen != "" {
 	if s.WebListen != "" {
 		ip := net.ParseIP(s.WebListen)
 		ip := net.ParseIP(s.WebListen)

+ 10 - 3
web/global/global.go

@@ -1,3 +1,4 @@
+// Package global provides global variables and interfaces for accessing web and subscription servers.
 package global
 package global
 
 
 import (
 import (
@@ -12,27 +13,33 @@ var (
 	subServer SubServer
 	subServer SubServer
 )
 )
 
 
+// WebServer interface defines methods for accessing the web server instance.
 type WebServer interface {
 type WebServer interface {
-	GetCron() *cron.Cron
-	GetCtx() context.Context
+	GetCron() *cron.Cron     // Get the cron scheduler
+	GetCtx() context.Context // Get the server context
 }
 }
 
 
+// SubServer interface defines methods for accessing the subscription server instance.
 type SubServer interface {
 type SubServer interface {
-	GetCtx() context.Context
+	GetCtx() context.Context // Get the server context
 }
 }
 
 
+// SetWebServer sets the global web server instance.
 func SetWebServer(s WebServer) {
 func SetWebServer(s WebServer) {
 	webServer = s
 	webServer = s
 }
 }
 
 
+// GetWebServer returns the global web server instance.
 func GetWebServer() WebServer {
 func GetWebServer() WebServer {
 	return webServer
 	return webServer
 }
 }
 
 
+// SetSubServer sets the global subscription server instance.
 func SetSubServer(s SubServer) {
 func SetSubServer(s SubServer) {
 	subServer = s
 	subServer = s
 }
 }
 
 
+// GetSubServer returns the global subscription server instance.
 func GetSubServer() SubServer {
 func GetSubServer() SubServer {
 	return subServer
 	return subServer
 }
 }

+ 13 - 5
web/global/hashStorage.go

@@ -8,18 +8,21 @@ import (
 	"time"
 	"time"
 )
 )
 
 
+// HashEntry represents a stored hash entry with its value and timestamp.
 type HashEntry struct {
 type HashEntry struct {
-	Hash      string
-	Value     string
-	Timestamp time.Time
+	Hash      string    // MD5 hash string
+	Value     string    // Original value
+	Timestamp time.Time // Time when the hash was created
 }
 }
 
 
+// HashStorage provides thread-safe storage for hash-value pairs with expiration.
 type HashStorage struct {
 type HashStorage struct {
 	sync.RWMutex
 	sync.RWMutex
-	Data       map[string]HashEntry
-	Expiration time.Duration
+	Data       map[string]HashEntry // Map of hash to entry
+	Expiration time.Duration        // Expiration duration for entries
 }
 }
 
 
+// NewHashStorage creates a new HashStorage instance with the specified expiration duration.
 func NewHashStorage(expiration time.Duration) *HashStorage {
 func NewHashStorage(expiration time.Duration) *HashStorage {
 	return &HashStorage{
 	return &HashStorage{
 		Data:       make(map[string]HashEntry),
 		Data:       make(map[string]HashEntry),
@@ -27,6 +30,7 @@ func NewHashStorage(expiration time.Duration) *HashStorage {
 	}
 	}
 }
 }
 
 
+// SaveHash generates an MD5 hash for the given query string and stores it with a timestamp.
 func (h *HashStorage) SaveHash(query string) string {
 func (h *HashStorage) SaveHash(query string) string {
 	h.Lock()
 	h.Lock()
 	defer h.Unlock()
 	defer h.Unlock()
@@ -45,6 +49,7 @@ func (h *HashStorage) SaveHash(query string) string {
 	return md5HashString
 	return md5HashString
 }
 }
 
 
+// GetValue retrieves the original value for the given hash, returning true if found.
 func (h *HashStorage) GetValue(hash string) (string, bool) {
 func (h *HashStorage) GetValue(hash string) (string, bool) {
 	h.RLock()
 	h.RLock()
 	defer h.RUnlock()
 	defer h.RUnlock()
@@ -54,11 +59,13 @@ func (h *HashStorage) GetValue(hash string) (string, bool) {
 	return entry.Value, exists
 	return entry.Value, exists
 }
 }
 
 
+// IsMD5 checks if the given string is a valid 32-character MD5 hash.
 func (h *HashStorage) IsMD5(hash string) bool {
 func (h *HashStorage) IsMD5(hash string) bool {
 	match, _ := regexp.MatchString("^[a-f0-9]{32}$", hash)
 	match, _ := regexp.MatchString("^[a-f0-9]{32}$", hash)
 	return match
 	return match
 }
 }
 
 
+// RemoveExpiredHashes removes all hash entries that have exceeded the expiration duration.
 func (h *HashStorage) RemoveExpiredHashes() {
 func (h *HashStorage) RemoveExpiredHashes() {
 	h.Lock()
 	h.Lock()
 	defer h.Unlock()
 	defer h.Unlock()
@@ -72,6 +79,7 @@ func (h *HashStorage) RemoveExpiredHashes() {
 	}
 	}
 }
 }
 
 
+// Reset clears all stored hash entries.
 func (h *HashStorage) Reset() {
 func (h *HashStorage) Reset() {
 	h.Lock()
 	h.Lock()
 	defer h.Unlock()
 	defer h.Unlock()

+ 2 - 0
web/job/check_client_ip_job.go

@@ -18,6 +18,7 @@ import (
 	"github.com/mhsanaei/3x-ui/v2/xray"
 	"github.com/mhsanaei/3x-ui/v2/xray"
 )
 )
 
 
+// CheckClientIpJob monitors client IP addresses from access logs and manages IP blocking based on configured limits.
 type CheckClientIpJob struct {
 type CheckClientIpJob struct {
 	lastClear     int64
 	lastClear     int64
 	disAllowedIps []string
 	disAllowedIps []string
@@ -25,6 +26,7 @@ type CheckClientIpJob struct {
 
 
 var job *CheckClientIpJob
 var job *CheckClientIpJob
 
 
+// NewCheckClientIpJob creates a new client IP monitoring job instance.
 func NewCheckClientIpJob() *CheckClientIpJob {
 func NewCheckClientIpJob() *CheckClientIpJob {
 	job = new(CheckClientIpJob)
 	job = new(CheckClientIpJob)
 	return job
 	return job

+ 3 - 1
web/job/check_cpu_usage.go

@@ -9,16 +9,18 @@ import (
 	"github.com/shirou/gopsutil/v4/cpu"
 	"github.com/shirou/gopsutil/v4/cpu"
 )
 )
 
 
+// CheckCpuJob monitors CPU usage and sends Telegram notifications when usage exceeds the configured threshold.
 type CheckCpuJob struct {
 type CheckCpuJob struct {
 	tgbotService   service.Tgbot
 	tgbotService   service.Tgbot
 	settingService service.SettingService
 	settingService service.SettingService
 }
 }
 
 
+// NewCheckCpuJob creates a new CPU monitoring job instance.
 func NewCheckCpuJob() *CheckCpuJob {
 func NewCheckCpuJob() *CheckCpuJob {
 	return new(CheckCpuJob)
 	return new(CheckCpuJob)
 }
 }
 
 
-// Here run is a interface method of Job interface
+// Run checks CPU usage over the last minute and sends a Telegram alert if it exceeds the threshold.
 func (j *CheckCpuJob) Run() {
 func (j *CheckCpuJob) Run() {
 	threshold, _ := j.settingService.GetTgCpu()
 	threshold, _ := j.settingService.GetTgCpu()
 
 

+ 3 - 1
web/job/check_hash_storage.go

@@ -4,15 +4,17 @@ import (
 	"github.com/mhsanaei/3x-ui/v2/web/service"
 	"github.com/mhsanaei/3x-ui/v2/web/service"
 )
 )
 
 
+// CheckHashStorageJob periodically cleans up expired hash entries from the Telegram bot's hash storage.
 type CheckHashStorageJob struct {
 type CheckHashStorageJob struct {
 	tgbotService service.Tgbot
 	tgbotService service.Tgbot
 }
 }
 
 
+// NewCheckHashStorageJob creates a new hash storage cleanup job instance.
 func NewCheckHashStorageJob() *CheckHashStorageJob {
 func NewCheckHashStorageJob() *CheckHashStorageJob {
 	return new(CheckHashStorageJob)
 	return new(CheckHashStorageJob)
 }
 }
 
 
-// Here Run is an interface method of the Job interface
+// Run removes expired hash entries from the Telegram bot's hash storage.
 func (j *CheckHashStorageJob) Run() {
 func (j *CheckHashStorageJob) Run() {
 	// Remove expired hashes from storage
 	// Remove expired hashes from storage
 	j.tgbotService.GetHashStorage().RemoveExpiredHashes()
 	j.tgbotService.GetHashStorage().RemoveExpiredHashes()

+ 6 - 2
web/job/check_xray_running_job.go

@@ -1,3 +1,5 @@
+// Package job provides background job implementations for the 3x-ui web panel,
+// including traffic monitoring, system checks, and periodic maintenance tasks.
 package job
 package job
 
 
 import (
 import (
@@ -5,16 +7,18 @@ import (
 	"github.com/mhsanaei/3x-ui/v2/web/service"
 	"github.com/mhsanaei/3x-ui/v2/web/service"
 )
 )
 
 
+// CheckXrayRunningJob monitors Xray process health and restarts it if it crashes.
 type CheckXrayRunningJob struct {
 type CheckXrayRunningJob struct {
 	xrayService service.XrayService
 	xrayService service.XrayService
-
-	checkTime int
+	checkTime   int
 }
 }
 
 
+// NewCheckXrayRunningJob creates a new Xray health check job instance.
 func NewCheckXrayRunningJob() *CheckXrayRunningJob {
 func NewCheckXrayRunningJob() *CheckXrayRunningJob {
 	return new(CheckXrayRunningJob)
 	return new(CheckXrayRunningJob)
 }
 }
 
 
+// Run checks if Xray has crashed and restarts it after confirming it's down for 2 consecutive checks.
 func (j *CheckXrayRunningJob) Run() {
 func (j *CheckXrayRunningJob) Run() {
 	if !j.xrayService.DidXrayCrash() {
 	if !j.xrayService.DidXrayCrash() {
 		j.checkTime = 0
 		j.checkTime = 0

+ 2 - 0
web/job/clear_logs_job.go

@@ -9,8 +9,10 @@ import (
 	"github.com/mhsanaei/3x-ui/v2/xray"
 	"github.com/mhsanaei/3x-ui/v2/xray"
 )
 )
 
 
+// ClearLogsJob clears old log files to prevent disk space issues.
 type ClearLogsJob struct{}
 type ClearLogsJob struct{}
 
 
+// NewClearLogsJob creates a new log cleanup job instance.
 func NewClearLogsJob() *ClearLogsJob {
 func NewClearLogsJob() *ClearLogsJob {
 	return new(ClearLogsJob)
 	return new(ClearLogsJob)
 }
 }

+ 4 - 0
web/job/periodic_traffic_reset_job.go

@@ -5,19 +5,23 @@ import (
 	"github.com/mhsanaei/3x-ui/v2/web/service"
 	"github.com/mhsanaei/3x-ui/v2/web/service"
 )
 )
 
 
+// Period represents the time period for traffic resets.
 type Period string
 type Period string
 
 
+// PeriodicTrafficResetJob resets traffic statistics for inbounds based on their configured reset period.
 type PeriodicTrafficResetJob struct {
 type PeriodicTrafficResetJob struct {
 	inboundService service.InboundService
 	inboundService service.InboundService
 	period         Period
 	period         Period
 }
 }
 
 
+// NewPeriodicTrafficResetJob creates a new periodic traffic reset job for the specified period.
 func NewPeriodicTrafficResetJob(period Period) *PeriodicTrafficResetJob {
 func NewPeriodicTrafficResetJob(period Period) *PeriodicTrafficResetJob {
 	return &PeriodicTrafficResetJob{
 	return &PeriodicTrafficResetJob{
 		period: period,
 		period: period,
 	}
 	}
 }
 }
 
 
+// Run resets traffic statistics for all inbounds that match the configured reset period.
 func (j *PeriodicTrafficResetJob) Run() {
 func (j *PeriodicTrafficResetJob) Run() {
 	inbounds, err := j.inboundService.GetInboundsByTrafficReset(string(j.period))
 	inbounds, err := j.inboundService.GetInboundsByTrafficReset(string(j.period))
 	if err != nil {
 	if err != nil {

+ 6 - 3
web/job/stats_notify_job.go

@@ -4,23 +4,26 @@ import (
 	"github.com/mhsanaei/3x-ui/v2/web/service"
 	"github.com/mhsanaei/3x-ui/v2/web/service"
 )
 )
 
 
+// LoginStatus represents the status of a login attempt.
 type LoginStatus byte
 type LoginStatus byte
 
 
 const (
 const (
-	LoginSuccess LoginStatus = 1
-	LoginFail    LoginStatus = 0
+	LoginSuccess LoginStatus = 1 // Successful login
+	LoginFail    LoginStatus = 0 // Failed login attempt
 )
 )
 
 
+// StatsNotifyJob sends periodic statistics reports via Telegram bot.
 type StatsNotifyJob struct {
 type StatsNotifyJob struct {
 	xrayService  service.XrayService
 	xrayService  service.XrayService
 	tgbotService service.Tgbot
 	tgbotService service.Tgbot
 }
 }
 
 
+// NewStatsNotifyJob creates a new statistics notification job instance.
 func NewStatsNotifyJob() *StatsNotifyJob {
 func NewStatsNotifyJob() *StatsNotifyJob {
 	return new(StatsNotifyJob)
 	return new(StatsNotifyJob)
 }
 }
 
 
-// Here run is a interface method of Job interface
+// Run sends a statistics report via Telegram bot if Xray is running.
 func (j *StatsNotifyJob) Run() {
 func (j *StatsNotifyJob) Run() {
 	if !j.xrayService.IsXrayRunning() {
 	if !j.xrayService.IsXrayRunning() {
 		return
 		return

+ 3 - 0
web/job/xray_traffic_job.go

@@ -10,6 +10,7 @@ import (
 	"github.com/valyala/fasthttp"
 	"github.com/valyala/fasthttp"
 )
 )
 
 
+// XrayTrafficJob collects and processes traffic statistics from Xray, updating the database and optionally informing external APIs.
 type XrayTrafficJob struct {
 type XrayTrafficJob struct {
 	settingService  service.SettingService
 	settingService  service.SettingService
 	xrayService     service.XrayService
 	xrayService     service.XrayService
@@ -17,10 +18,12 @@ type XrayTrafficJob struct {
 	outboundService service.OutboundService
 	outboundService service.OutboundService
 }
 }
 
 
+// NewXrayTrafficJob creates a new traffic collection job instance.
 func NewXrayTrafficJob() *XrayTrafficJob {
 func NewXrayTrafficJob() *XrayTrafficJob {
 	return new(XrayTrafficJob)
 	return new(XrayTrafficJob)
 }
 }
 
 
+// Run collects traffic statistics from Xray and updates the database, triggering restart if needed.
 func (j *XrayTrafficJob) Run() {
 func (j *XrayTrafficJob) Run() {
 	if !j.xrayService.IsXrayRunning() {
 	if !j.xrayService.IsXrayRunning() {
 		return
 		return

+ 17 - 2
web/locale/locale.go

@@ -1,3 +1,5 @@
+// Package locale provides internationalization (i18n) support for the 3x-ui web panel,
+// including translation loading, localization, and middleware for web and bot interfaces.
 package locale
 package locale
 
 
 import (
 import (
@@ -20,17 +22,20 @@ var (
 	LocalizerBot *i18n.Localizer
 	LocalizerBot *i18n.Localizer
 )
 )
 
 
+// I18nType represents the type of interface for internationalization.
 type I18nType string
 type I18nType string
 
 
 const (
 const (
-	Bot I18nType = "bot"
-	Web I18nType = "web"
+	Bot I18nType = "bot" // Bot interface type
+	Web I18nType = "web" // Web interface type
 )
 )
 
 
+// SettingService interface defines methods for accessing locale settings.
 type SettingService interface {
 type SettingService interface {
 	GetTgLang() (string, error)
 	GetTgLang() (string, error)
 }
 }
 
 
+// InitLocalizer initializes the internationalization system with embedded translation files.
 func InitLocalizer(i18nFS embed.FS, settingService SettingService) error {
 func InitLocalizer(i18nFS embed.FS, settingService SettingService) error {
 	// set default bundle to english
 	// set default bundle to english
 	i18nBundle = i18n.NewBundle(language.MustParse("en-US"))
 	i18nBundle = i18n.NewBundle(language.MustParse("en-US"))
@@ -49,6 +54,7 @@ func InitLocalizer(i18nFS embed.FS, settingService SettingService) error {
 	return nil
 	return nil
 }
 }
 
 
+// createTemplateData creates a template data map from parameters with optional separator.
 func createTemplateData(params []string, separator ...string) map[string]any {
 func createTemplateData(params []string, separator ...string) map[string]any {
 	var sep string = "=="
 	var sep string = "=="
 	if len(separator) > 0 {
 	if len(separator) > 0 {
@@ -64,6 +70,9 @@ func createTemplateData(params []string, separator ...string) map[string]any {
 	return templateData
 	return templateData
 }
 }
 
 
+// I18n retrieves a localized message for the given key and type.
+// It supports both bot and web contexts, with optional template parameters.
+// Returns the localized message or an empty string if localization fails.
 func I18n(i18nType I18nType, key string, params ...string) string {
 func I18n(i18nType I18nType, key string, params ...string) string {
 	var localizer *i18n.Localizer
 	var localizer *i18n.Localizer
 
 
@@ -96,6 +105,7 @@ func I18n(i18nType I18nType, key string, params ...string) string {
 	return msg
 	return msg
 }
 }
 
 
+// initTGBotLocalizer initializes the bot localizer with the configured language.
 func initTGBotLocalizer(settingService SettingService) error {
 func initTGBotLocalizer(settingService SettingService) error {
 	botLang, err := settingService.GetTgLang()
 	botLang, err := settingService.GetTgLang()
 	if err != nil {
 	if err != nil {
@@ -106,6 +116,10 @@ func initTGBotLocalizer(settingService SettingService) error {
 	return nil
 	return nil
 }
 }
 
 
+// LocalizerMiddleware returns a Gin middleware that sets up localization for web requests.
+// It determines the user's language from cookies or Accept-Language header,
+// creates a localizer instance, and stores it in the Gin context for use in handlers.
+// Also provides the I18n function in the context for template rendering.
 func LocalizerMiddleware() gin.HandlerFunc {
 func LocalizerMiddleware() gin.HandlerFunc {
 	return func(c *gin.Context) {
 	return func(c *gin.Context) {
 		// Ensure bundle is initialized so creating a Localizer won't panic
 		// Ensure bundle is initialized so creating a Localizer won't panic
@@ -152,6 +166,7 @@ func loadTranslationsFromDisk(bundle *i18n.Bundle) error {
 	})
 	})
 }
 }
 
 
+// parseTranslationFiles parses embedded translation files and adds them to the i18n bundle.
 func parseTranslationFiles(i18nFS embed.FS, i18nBundle *i18n.Bundle) error {
 func parseTranslationFiles(i18nFS embed.FS, i18nBundle *i18n.Bundle) error {
 	err := fs.WalkDir(i18nFS, "translation",
 	err := fs.WalkDir(i18nFS, "translation",
 		func(path string, d fs.DirEntry, err error) error {
 		func(path string, d fs.DirEntry, err error) error {

+ 6 - 0
web/middleware/domainValidator.go

@@ -1,3 +1,5 @@
+// Package middleware provides HTTP middleware functions for the 3x-ui web panel,
+// including domain validation and URL redirection utilities.
 package middleware
 package middleware
 
 
 import (
 import (
@@ -8,6 +10,10 @@ import (
 	"github.com/gin-gonic/gin"
 	"github.com/gin-gonic/gin"
 )
 )
 
 
+// DomainValidatorMiddleware returns a Gin middleware that validates the request domain.
+// It extracts the host from the request, strips any port number, and compares it
+// against the configured domain. Requests from unauthorized domains are rejected
+// with HTTP 403 Forbidden status.
 func DomainValidatorMiddleware(domain string) gin.HandlerFunc {
 func DomainValidatorMiddleware(domain string) gin.HandlerFunc {
 	return func(c *gin.Context) {
 	return func(c *gin.Context) {
 		host := c.Request.Host
 		host := c.Request.Host

+ 3 - 0
web/middleware/redirect.go

@@ -7,6 +7,9 @@ import (
 	"github.com/gin-gonic/gin"
 	"github.com/gin-gonic/gin"
 )
 )
 
 
+// RedirectMiddleware returns a Gin middleware that handles URL redirections.
+// It provides backward compatibility by redirecting old '/xui' paths to new '/panel' paths,
+// including API endpoints. The middleware performs permanent redirects (301) for SEO purposes.
 func RedirectMiddleware(basePath string) gin.HandlerFunc {
 func RedirectMiddleware(basePath string) gin.HandlerFunc {
 	return func(c *gin.Context) {
 	return func(c *gin.Context) {
 		// Redirect from old '/xui' path to '/panel'
 		// Redirect from old '/xui' path to '/panel'

+ 10 - 0
web/network/auto_https_conn.go

@@ -1,3 +1,5 @@
+// Package network provides network utilities for the 3x-ui web panel,
+// including automatic HTTP to HTTPS redirection functionality.
 package network
 package network
 
 
 import (
 import (
@@ -9,6 +11,9 @@ import (
 	"sync"
 	"sync"
 )
 )
 
 
+// AutoHttpsConn wraps a net.Conn to provide automatic HTTP to HTTPS redirection.
+// It intercepts the first read to detect HTTP requests and responds with a 307 redirect
+// to the HTTPS equivalent URL. Subsequent reads work normally for HTTPS connections.
 type AutoHttpsConn struct {
 type AutoHttpsConn struct {
 	net.Conn
 	net.Conn
 
 
@@ -18,6 +23,8 @@ type AutoHttpsConn struct {
 	readRequestOnce sync.Once
 	readRequestOnce sync.Once
 }
 }
 
 
+// NewAutoHttpsConn creates a new AutoHttpsConn that wraps the given connection.
+// It enables automatic redirection of HTTP requests to HTTPS.
 func NewAutoHttpsConn(conn net.Conn) net.Conn {
 func NewAutoHttpsConn(conn net.Conn) net.Conn {
 	return &AutoHttpsConn{
 	return &AutoHttpsConn{
 		Conn: conn,
 		Conn: conn,
@@ -49,6 +56,9 @@ func (c *AutoHttpsConn) readRequest() bool {
 	return true
 	return true
 }
 }
 
 
+// Read implements the net.Conn Read method with automatic HTTPS redirection.
+// On the first read, it checks if the request is HTTP and redirects to HTTPS if so.
+// Subsequent reads work normally.
 func (c *AutoHttpsConn) Read(buf []byte) (int, error) {
 func (c *AutoHttpsConn) Read(buf []byte) (int, error) {
 	c.readRequestOnce.Do(func() {
 	c.readRequestOnce.Do(func() {
 		c.readRequest()
 		c.readRequest()

+ 6 - 0
web/network/auto_https_listener.go

@@ -2,16 +2,22 @@ package network
 
 
 import "net"
 import "net"
 
 
+// AutoHttpsListener wraps a net.Listener to provide automatic HTTPS redirection.
+// It returns AutoHttpsConn connections that handle HTTP to HTTPS redirection.
 type AutoHttpsListener struct {
 type AutoHttpsListener struct {
 	net.Listener
 	net.Listener
 }
 }
 
 
+// NewAutoHttpsListener creates a new AutoHttpsListener that wraps the given listener.
+// It enables automatic redirection of HTTP requests to HTTPS for all accepted connections.
 func NewAutoHttpsListener(listener net.Listener) net.Listener {
 func NewAutoHttpsListener(listener net.Listener) net.Listener {
 	return &AutoHttpsListener{
 	return &AutoHttpsListener{
 		Listener: listener,
 		Listener: listener,
 	}
 	}
 }
 }
 
 
+// Accept implements the net.Listener Accept method.
+// It accepts connections and wraps them with AutoHttpsConn for HTTPS redirection.
 func (l *AutoHttpsListener) Accept() (net.Conn, error) {
 func (l *AutoHttpsListener) Accept() (net.Conn, error) {
 	conn, err := l.Listener.Accept()
 	conn, err := l.Listener.Accept()
 	if err != nil {
 	if err != nil {

+ 19 - 0
web/service/inbound.go

@@ -1,3 +1,5 @@
+// Package service provides business logic services for the 3x-ui web panel,
+// including inbound/outbound management, user administration, settings, and Xray integration.
 package service
 package service
 
 
 import (
 import (
@@ -17,10 +19,15 @@ import (
 	"gorm.io/gorm"
 	"gorm.io/gorm"
 )
 )
 
 
+// InboundService provides business logic for managing Xray inbound configurations.
+// It handles CRUD operations for inbounds, client management, traffic monitoring,
+// and integration with the Xray API for real-time updates.
 type InboundService struct {
 type InboundService struct {
 	xrayApi xray.XrayAPI
 	xrayApi xray.XrayAPI
 }
 }
 
 
+// GetInbounds retrieves all inbounds for a specific user.
+// Returns a slice of inbound models with their associated client statistics.
 func (s *InboundService) GetInbounds(userId int) ([]*model.Inbound, error) {
 func (s *InboundService) GetInbounds(userId int) ([]*model.Inbound, error) {
 	db := database.GetDB()
 	db := database.GetDB()
 	var inbounds []*model.Inbound
 	var inbounds []*model.Inbound
@@ -31,6 +38,8 @@ func (s *InboundService) GetInbounds(userId int) ([]*model.Inbound, error) {
 	return inbounds, nil
 	return inbounds, nil
 }
 }
 
 
+// GetAllInbounds retrieves all inbounds from the database.
+// Returns a slice of all inbound models with their associated client statistics.
 func (s *InboundService) GetAllInbounds() ([]*model.Inbound, error) {
 func (s *InboundService) GetAllInbounds() ([]*model.Inbound, error) {
 	db := database.GetDB()
 	db := database.GetDB()
 	var inbounds []*model.Inbound
 	var inbounds []*model.Inbound
@@ -163,6 +172,10 @@ func (s *InboundService) checkEmailExistForInbound(inbound *model.Inbound) (stri
 	return "", nil
 	return "", nil
 }
 }
 
 
+// AddInbound creates a new inbound configuration.
+// It validates port uniqueness, client email uniqueness, and required fields,
+// then saves the inbound to the database and optionally adds it to the running Xray instance.
+// Returns the created inbound, whether Xray needs restart, and any error.
 func (s *InboundService) AddInbound(inbound *model.Inbound) (*model.Inbound, bool, error) {
 func (s *InboundService) AddInbound(inbound *model.Inbound) (*model.Inbound, bool, error) {
 	exist, err := s.checkPortExist(inbound.Listen, inbound.Port, 0)
 	exist, err := s.checkPortExist(inbound.Listen, inbound.Port, 0)
 	if err != nil {
 	if err != nil {
@@ -269,6 +282,9 @@ func (s *InboundService) AddInbound(inbound *model.Inbound) (*model.Inbound, boo
 	return inbound, needRestart, err
 	return inbound, needRestart, err
 }
 }
 
 
+// DelInbound deletes an inbound configuration by ID.
+// It removes the inbound from the database and the running Xray instance if active.
+// Returns whether Xray needs restart and any error.
 func (s *InboundService) DelInbound(id int) (bool, error) {
 func (s *InboundService) DelInbound(id int) (bool, error) {
 	db := database.GetDB()
 	db := database.GetDB()
 
 
@@ -322,6 +338,9 @@ func (s *InboundService) GetInbound(id int) (*model.Inbound, error) {
 	return inbound, nil
 	return inbound, nil
 }
 }
 
 
+// UpdateInbound modifies an existing inbound configuration.
+// It validates changes, updates the database, and syncs with the running Xray instance.
+// Returns the updated inbound, whether Xray needs restart, and any error.
 func (s *InboundService) UpdateInbound(inbound *model.Inbound) (*model.Inbound, bool, error) {
 func (s *InboundService) UpdateInbound(inbound *model.Inbound) (*model.Inbound, bool, error) {
 	exist, err := s.checkPortExist(inbound.Listen, inbound.Port, inbound.Id)
 	exist, err := s.checkPortExist(inbound.Listen, inbound.Port, inbound.Id)
 	if err != nil {
 	if err != nil {

+ 2 - 0
web/service/outbound.go

@@ -9,6 +9,8 @@ import (
 	"gorm.io/gorm"
 	"gorm.io/gorm"
 )
 )
 
 
+// OutboundService provides business logic for managing Xray outbound configurations.
+// It handles outbound traffic monitoring and statistics.
 type OutboundService struct{}
 type OutboundService struct{}
 
 
 func (s *OutboundService) AddTraffic(traffics []*xray.Traffic, clientTraffics []*xray.ClientTraffic) (error, bool) {
 func (s *OutboundService) AddTraffic(traffics []*xray.Traffic, clientTraffics []*xray.ClientTraffic) (error, bool) {

+ 2 - 0
web/service/panel.go

@@ -8,6 +8,8 @@ import (
 	"github.com/mhsanaei/3x-ui/v2/logger"
 	"github.com/mhsanaei/3x-ui/v2/logger"
 )
 )
 
 
+// PanelService provides business logic for panel management operations.
+// It handles panel restart, updates, and system-level panel controls.
 type PanelService struct{}
 type PanelService struct{}
 
 
 func (s *PanelService) RestartPanel(delay time.Duration) error {
 func (s *PanelService) RestartPanel(delay time.Duration) error {

+ 11 - 4
web/service/server.go

@@ -35,14 +35,18 @@ import (
 	"github.com/shirou/gopsutil/v4/net"
 	"github.com/shirou/gopsutil/v4/net"
 )
 )
 
 
+// ProcessState represents the current state of a system process.
 type ProcessState string
 type ProcessState string
 
 
+// Process state constants
 const (
 const (
-	Running ProcessState = "running"
-	Stop    ProcessState = "stop"
-	Error   ProcessState = "error"
+	Running ProcessState = "running" // Process is running normally
+	Stop    ProcessState = "stop"    // Process is stopped
+	Error   ProcessState = "error"   // Process is in error state
 )
 )
 
 
+// Status represents comprehensive system and application status information.
+// It includes CPU, memory, disk, network statistics, and Xray process status.
 type Status struct {
 type Status struct {
 	T           time.Time `json:"-"`
 	T           time.Time `json:"-"`
 	Cpu         float64   `json:"cpu"`
 	Cpu         float64   `json:"cpu"`
@@ -89,10 +93,13 @@ type Status struct {
 	} `json:"appStats"`
 	} `json:"appStats"`
 }
 }
 
 
+// Release represents information about a software release from GitHub.
 type Release struct {
 type Release struct {
-	TagName string `json:"tag_name"`
+	TagName string `json:"tag_name"` // The tag name of the release
 }
 }
 
 
+// ServerService provides business logic for server monitoring and management.
+// It handles system status collection, IP detection, and application statistics.
 type ServerService struct {
 type ServerService struct {
 	xrayService        XrayService
 	xrayService        XrayService
 	inboundService     InboundService
 	inboundService     InboundService

+ 2 - 0
web/service/setting.go

@@ -75,6 +75,8 @@ var defaultValueMap = map[string]string{
 	"externalTrafficInformURI":    "",
 	"externalTrafficInformURI":    "",
 }
 }
 
 
+// SettingService provides business logic for application settings management.
+// It handles configuration storage, retrieval, and validation for all system settings.
 type SettingService struct{}
 type SettingService struct{}
 
 
 func (s *SettingService) GetDefaultJsonConfig() (any, error) {
 func (s *SettingService) GetDefaultJsonConfig() (any, error) {

+ 62 - 6
web/service/tgbot.go

@@ -65,14 +65,18 @@ var (
 
 
 var userStates = make(map[int64]string)
 var userStates = make(map[int64]string)
 
 
+// LoginStatus represents the result of a login attempt.
 type LoginStatus byte
 type LoginStatus byte
 
 
+// Login status constants
 const (
 const (
-	LoginSuccess        LoginStatus = 1
-	LoginFail           LoginStatus = 0
-	EmptyTelegramUserID             = int64(0)
+	LoginSuccess        LoginStatus = 1        // Login was successful
+	LoginFail           LoginStatus = 0        // Login failed
+	EmptyTelegramUserID             = int64(0) // Default value for empty Telegram user ID
 )
 )
 
 
+// Tgbot provides business logic for Telegram bot integration.
+// It handles bot commands, user interactions, and status reporting via Telegram.
 type Tgbot struct {
 type Tgbot struct {
 	inboundService InboundService
 	inboundService InboundService
 	settingService SettingService
 	settingService SettingService
@@ -81,18 +85,22 @@ type Tgbot struct {
 	lastStatus     *Status
 	lastStatus     *Status
 }
 }
 
 
+// NewTgbot creates a new Tgbot instance.
 func (t *Tgbot) NewTgbot() *Tgbot {
 func (t *Tgbot) NewTgbot() *Tgbot {
 	return new(Tgbot)
 	return new(Tgbot)
 }
 }
 
 
+// I18nBot retrieves a localized message for the bot interface.
 func (t *Tgbot) I18nBot(name string, params ...string) string {
 func (t *Tgbot) I18nBot(name string, params ...string) string {
 	return locale.I18n(locale.Bot, name, params...)
 	return locale.I18n(locale.Bot, name, params...)
 }
 }
 
 
+// GetHashStorage returns the hash storage instance for callback queries.
 func (t *Tgbot) GetHashStorage() *global.HashStorage {
 func (t *Tgbot) GetHashStorage() *global.HashStorage {
 	return hashStorage
 	return hashStorage
 }
 }
 
 
+// Start initializes and starts the Telegram bot with the provided translation files.
 func (t *Tgbot) Start(i18nFS embed.FS) error {
 func (t *Tgbot) Start(i18nFS embed.FS) error {
 	// Initialize localizer
 	// Initialize localizer
 	err := locale.InitLocalizer(i18nFS, &t.settingService)
 	err := locale.InitLocalizer(i18nFS, &t.settingService)
@@ -173,6 +181,7 @@ func (t *Tgbot) Start(i18nFS embed.FS) error {
 	return nil
 	return nil
 }
 }
 
 
+// NewBot creates a new Telegram bot instance with optional proxy and API server settings.
 func (t *Tgbot) NewBot(token string, proxyUrl string, apiServerUrl string) (*telego.Bot, error) {
 func (t *Tgbot) NewBot(token string, proxyUrl string, apiServerUrl string) (*telego.Bot, error) {
 	if proxyUrl == "" && apiServerUrl == "" {
 	if proxyUrl == "" && apiServerUrl == "" {
 		return telego.NewBot(token)
 		return telego.NewBot(token)
@@ -209,10 +218,12 @@ func (t *Tgbot) NewBot(token string, proxyUrl string, apiServerUrl string) (*tel
 	return telego.NewBot(token, telego.WithAPIServer(apiServerUrl))
 	return telego.NewBot(token, telego.WithAPIServer(apiServerUrl))
 }
 }
 
 
+// IsRunning checks if the Telegram bot is currently running.
 func (t *Tgbot) IsRunning() bool {
 func (t *Tgbot) IsRunning() bool {
 	return isRunning
 	return isRunning
 }
 }
 
 
+// SetHostname sets the hostname for the bot.
 func (t *Tgbot) SetHostname() {
 func (t *Tgbot) SetHostname() {
 	host, err := os.Hostname()
 	host, err := os.Hostname()
 	if err != nil {
 	if err != nil {
@@ -223,6 +234,7 @@ func (t *Tgbot) SetHostname() {
 	hostname = host
 	hostname = host
 }
 }
 
 
+// Stop stops the Telegram bot and cleans up resources.
 func (t *Tgbot) Stop() {
 func (t *Tgbot) Stop() {
 	if botHandler != nil {
 	if botHandler != nil {
 		botHandler.Stop()
 		botHandler.Stop()
@@ -232,6 +244,7 @@ func (t *Tgbot) Stop() {
 	adminIds = nil
 	adminIds = nil
 }
 }
 
 
+// encodeQuery encodes the query string if it's longer than 64 characters.
 func (t *Tgbot) encodeQuery(query string) string {
 func (t *Tgbot) encodeQuery(query string) string {
 	// NOTE: we only need to hash for more than 64 chars
 	// NOTE: we only need to hash for more than 64 chars
 	if len(query) <= 64 {
 	if len(query) <= 64 {
@@ -241,6 +254,7 @@ func (t *Tgbot) encodeQuery(query string) string {
 	return hashStorage.SaveHash(query)
 	return hashStorage.SaveHash(query)
 }
 }
 
 
+// decodeQuery decodes a hashed query string back to its original form.
 func (t *Tgbot) decodeQuery(query string) (string, error) {
 func (t *Tgbot) decodeQuery(query string) (string, error) {
 	if !hashStorage.IsMD5(query) {
 	if !hashStorage.IsMD5(query) {
 		return query, nil
 		return query, nil
@@ -254,6 +268,7 @@ func (t *Tgbot) decodeQuery(query string) (string, error) {
 	return decoded, nil
 	return decoded, nil
 }
 }
 
 
+// OnReceive starts the message receiving loop for the Telegram bot.
 func (t *Tgbot) OnReceive() {
 func (t *Tgbot) OnReceive() {
 	params := telego.GetUpdatesParams{
 	params := telego.GetUpdatesParams{
 		Timeout: 10,
 		Timeout: 10,
@@ -430,6 +445,7 @@ func (t *Tgbot) OnReceive() {
 	botHandler.Start()
 	botHandler.Start()
 }
 }
 
 
+// answerCommand processes incoming command messages from Telegram users.
 func (t *Tgbot) answerCommand(message *telego.Message, chatId int64, isAdmin bool) {
 func (t *Tgbot) answerCommand(message *telego.Message, chatId int64, isAdmin bool) {
 	msg, onlyMessage := "", false
 	msg, onlyMessage := "", false
 
 
@@ -505,7 +521,7 @@ func (t *Tgbot) answerCommand(message *telego.Message, chatId int64, isAdmin boo
 	}
 	}
 }
 }
 
 
-// Helper function to send the message based on onlyMessage flag.
+// sendResponse sends the response message based on the onlyMessage flag.
 func (t *Tgbot) sendResponse(chatId int64, msg string, onlyMessage, isAdmin bool) {
 func (t *Tgbot) sendResponse(chatId int64, msg string, onlyMessage, isAdmin bool) {
 	if onlyMessage {
 	if onlyMessage {
 		t.SendMsgToTgbot(chatId, msg)
 		t.SendMsgToTgbot(chatId, msg)
@@ -514,6 +530,7 @@ func (t *Tgbot) sendResponse(chatId int64, msg string, onlyMessage, isAdmin bool
 	}
 	}
 }
 }
 
 
+// randomLowerAndNum generates a random string of lowercase letters and numbers.
 func (t *Tgbot) randomLowerAndNum(length int) string {
 func (t *Tgbot) randomLowerAndNum(length int) string {
 	charset := "abcdefghijklmnopqrstuvwxyz0123456789"
 	charset := "abcdefghijklmnopqrstuvwxyz0123456789"
 	bytes := make([]byte, length)
 	bytes := make([]byte, length)
@@ -524,6 +541,7 @@ func (t *Tgbot) randomLowerAndNum(length int) string {
 	return string(bytes)
 	return string(bytes)
 }
 }
 
 
+// randomShadowSocksPassword generates a random password for Shadowsocks.
 func (t *Tgbot) randomShadowSocksPassword() string {
 func (t *Tgbot) randomShadowSocksPassword() string {
 	array := make([]byte, 32)
 	array := make([]byte, 32)
 	_, err := rand.Read(array)
 	_, err := rand.Read(array)
@@ -533,6 +551,7 @@ func (t *Tgbot) randomShadowSocksPassword() string {
 	return base64.StdEncoding.EncodeToString(array)
 	return base64.StdEncoding.EncodeToString(array)
 }
 }
 
 
+// answerCallback processes callback queries from inline keyboards.
 func (t *Tgbot) answerCallback(callbackQuery *telego.CallbackQuery, isAdmin bool) {
 func (t *Tgbot) answerCallback(callbackQuery *telego.CallbackQuery, isAdmin bool) {
 	chatId := callbackQuery.Message.GetChat().ID
 	chatId := callbackQuery.Message.GetChat().ID
 
 
@@ -1815,6 +1834,7 @@ func (t *Tgbot) answerCallback(callbackQuery *telego.CallbackQuery, isAdmin bool
 	}
 	}
 }
 }
 
 
+// BuildInboundClientDataMessage builds a message with client data for the given inbound and protocol.
 func (t *Tgbot) BuildInboundClientDataMessage(inbound_remark string, protocol model.Protocol) (string, error) {
 func (t *Tgbot) BuildInboundClientDataMessage(inbound_remark string, protocol model.Protocol) (string, error) {
 	var message string
 	var message string
 
 
@@ -1864,6 +1884,7 @@ func (t *Tgbot) BuildInboundClientDataMessage(inbound_remark string, protocol mo
 	return message, nil
 	return message, nil
 }
 }
 
 
+// BuildJSONForProtocol builds a JSON string for the given protocol with client data.
 func (t *Tgbot) BuildJSONForProtocol(protocol model.Protocol) (string, error) {
 func (t *Tgbot) BuildJSONForProtocol(protocol model.Protocol) (string, error) {
 	var jsonString string
 	var jsonString string
 
 
@@ -1942,6 +1963,7 @@ func (t *Tgbot) BuildJSONForProtocol(protocol model.Protocol) (string, error) {
 	return jsonString, nil
 	return jsonString, nil
 }
 }
 
 
+// SubmitAddClient submits the client addition request to the inbound service.
 func (t *Tgbot) SubmitAddClient() (bool, error) {
 func (t *Tgbot) SubmitAddClient() (bool, error) {
 
 
 	inbound, err := t.inboundService.GetInbound(receiver_inbound_ID)
 	inbound, err := t.inboundService.GetInbound(receiver_inbound_ID)
@@ -1964,6 +1986,7 @@ func (t *Tgbot) SubmitAddClient() (bool, error) {
 	return t.inboundService.AddInboundClient(newInbound)
 	return t.inboundService.AddInboundClient(newInbound)
 }
 }
 
 
+// checkAdmin checks if the given Telegram ID is an admin.
 func checkAdmin(tgId int64) bool {
 func checkAdmin(tgId int64) bool {
 	for _, adminId := range adminIds {
 	for _, adminId := range adminIds {
 		if adminId == tgId {
 		if adminId == tgId {
@@ -1973,6 +1996,7 @@ func checkAdmin(tgId int64) bool {
 	return false
 	return false
 }
 }
 
 
+// SendAnswer sends a response message with an inline keyboard to the specified chat.
 func (t *Tgbot) SendAnswer(chatId int64, msg string, isAdmin bool) {
 func (t *Tgbot) SendAnswer(chatId int64, msg string, isAdmin bool) {
 	numericKeyboard := tu.InlineKeyboard(
 	numericKeyboard := tu.InlineKeyboard(
 		tu.InlineKeyboardRow(
 		tu.InlineKeyboardRow(
@@ -2028,6 +2052,7 @@ func (t *Tgbot) SendAnswer(chatId int64, msg string, isAdmin bool) {
 	t.SendMsgToTgbot(chatId, msg, ReplyMarkup)
 	t.SendMsgToTgbot(chatId, msg, ReplyMarkup)
 }
 }
 
 
+// SendMsgToTgbot sends a message to the Telegram bot with optional reply markup.
 func (t *Tgbot) SendMsgToTgbot(chatId int64, msg string, replyMarkup ...telego.ReplyMarkup) {
 func (t *Tgbot) SendMsgToTgbot(chatId int64, msg string, replyMarkup ...telego.ReplyMarkup) {
 	if !isRunning {
 	if !isRunning {
 		return
 		return
@@ -2143,6 +2168,7 @@ func (t *Tgbot) buildSubscriptionURLs(email string) (string, string, error) {
 	return subURL, subJsonURL, nil
 	return subURL, subJsonURL, nil
 }
 }
 
 
+// sendClientSubLinks sends the subscription links for the client to the chat.
 func (t *Tgbot) sendClientSubLinks(chatId int64, email string) {
 func (t *Tgbot) sendClientSubLinks(chatId int64, email string) {
 	subURL, subJsonURL, err := t.buildSubscriptionURLs(email)
 	subURL, subJsonURL, err := t.buildSubscriptionURLs(email)
 	if err != nil {
 	if err != nil {
@@ -2338,6 +2364,7 @@ func (t *Tgbot) sendClientQRLinks(chatId int64, email string) {
 	}
 	}
 }
 }
 
 
+// SendMsgToTgbotAdmins sends a message to all admin Telegram chats.
 func (t *Tgbot) SendMsgToTgbotAdmins(msg string, replyMarkup ...telego.ReplyMarkup) {
 func (t *Tgbot) SendMsgToTgbotAdmins(msg string, replyMarkup ...telego.ReplyMarkup) {
 	if len(replyMarkup) > 0 {
 	if len(replyMarkup) > 0 {
 		for _, adminId := range adminIds {
 		for _, adminId := range adminIds {
@@ -2350,6 +2377,7 @@ func (t *Tgbot) SendMsgToTgbotAdmins(msg string, replyMarkup ...telego.ReplyMark
 	}
 	}
 }
 }
 
 
+// SendReport sends a periodic report to admin chats.
 func (t *Tgbot) SendReport() {
 func (t *Tgbot) SendReport() {
 	runTime, err := t.settingService.GetTgbotRuntime()
 	runTime, err := t.settingService.GetTgbotRuntime()
 	if err == nil && len(runTime) > 0 {
 	if err == nil && len(runTime) > 0 {
@@ -2371,6 +2399,7 @@ func (t *Tgbot) SendReport() {
 	}
 	}
 }
 }
 
 
+// SendBackupToAdmins sends a database backup to admin chats.
 func (t *Tgbot) SendBackupToAdmins() {
 func (t *Tgbot) SendBackupToAdmins() {
 	if !t.IsRunning() {
 	if !t.IsRunning() {
 		return
 		return
@@ -2380,6 +2409,7 @@ func (t *Tgbot) SendBackupToAdmins() {
 	}
 	}
 }
 }
 
 
+// sendExhaustedToAdmins sends notifications about exhausted clients to admins.
 func (t *Tgbot) sendExhaustedToAdmins() {
 func (t *Tgbot) sendExhaustedToAdmins() {
 	if !t.IsRunning() {
 	if !t.IsRunning() {
 		return
 		return
@@ -2389,6 +2419,7 @@ func (t *Tgbot) sendExhaustedToAdmins() {
 	}
 	}
 }
 }
 
 
+// getServerUsage retrieves and formats server usage information.
 func (t *Tgbot) getServerUsage(chatId int64, messageID ...int) string {
 func (t *Tgbot) getServerUsage(chatId int64, messageID ...int) string {
 	info := t.prepareServerUsageInfo()
 	info := t.prepareServerUsageInfo()
 
 
@@ -2410,6 +2441,7 @@ func (t *Tgbot) sendServerUsage() string {
 	return info
 	return info
 }
 }
 
 
+// prepareServerUsageInfo prepares the server usage information string.
 func (t *Tgbot) prepareServerUsageInfo() string {
 func (t *Tgbot) prepareServerUsageInfo() string {
 	info, ipv4, ipv6 := "", "", ""
 	info, ipv4, ipv6 := "", "", ""
 
 
@@ -2459,6 +2491,7 @@ func (t *Tgbot) prepareServerUsageInfo() string {
 	return info
 	return info
 }
 }
 
 
+// UserLoginNotify sends a notification about user login attempts to admins.
 func (t *Tgbot) UserLoginNotify(username string, password string, ip string, time string, status LoginStatus) {
 func (t *Tgbot) UserLoginNotify(username string, password string, ip string, time string, status LoginStatus) {
 	if !t.IsRunning() {
 	if !t.IsRunning() {
 		return
 		return
@@ -2490,6 +2523,7 @@ func (t *Tgbot) UserLoginNotify(username string, password string, ip string, tim
 	t.SendMsgToTgbotAdmins(msg)
 	t.SendMsgToTgbotAdmins(msg)
 }
 }
 
 
+// getInboundUsages retrieves and formats inbound usage information.
 func (t *Tgbot) getInboundUsages() string {
 func (t *Tgbot) getInboundUsages() string {
 	info := ""
 	info := ""
 	// get traffic
 	// get traffic
@@ -2515,6 +2549,8 @@ func (t *Tgbot) getInboundUsages() string {
 	}
 	}
 	return info
 	return info
 }
 }
+
+// getInbounds creates an inline keyboard with all inbounds.
 func (t *Tgbot) getInbounds() (*telego.InlineKeyboardMarkup, error) {
 func (t *Tgbot) getInbounds() (*telego.InlineKeyboardMarkup, error) {
 	inbounds, err := t.inboundService.GetAllInbounds()
 	inbounds, err := t.inboundService.GetAllInbounds()
 	if err != nil {
 	if err != nil {
@@ -2546,8 +2582,7 @@ func (t *Tgbot) getInbounds() (*telego.InlineKeyboardMarkup, error) {
 	return keyboard, nil
 	return keyboard, nil
 }
 }
 
 
-// getInboundsFor builds an inline keyboard of inbounds where each button leads to a custom next action
-// nextAction should be one of: get_clients_for_sub|get_clients_for_individual|get_clients_for_qr
+// getInboundsFor builds an inline keyboard of inbounds for a custom next action.
 func (t *Tgbot) getInboundsFor(nextAction string) (*telego.InlineKeyboardMarkup, error) {
 func (t *Tgbot) getInboundsFor(nextAction string) (*telego.InlineKeyboardMarkup, error) {
 	inbounds, err := t.inboundService.GetAllInbounds()
 	inbounds, err := t.inboundService.GetAllInbounds()
 	if err != nil {
 	if err != nil {
@@ -2614,6 +2649,7 @@ func (t *Tgbot) getInboundClientsFor(inboundID int, action string) (*telego.Inli
 	return keyboard, nil
 	return keyboard, nil
 }
 }
 
 
+// getInboundsAddClient creates an inline keyboard for adding clients to inbounds.
 func (t *Tgbot) getInboundsAddClient() (*telego.InlineKeyboardMarkup, error) {
 func (t *Tgbot) getInboundsAddClient() (*telego.InlineKeyboardMarkup, error) {
 	inbounds, err := t.inboundService.GetAllInbounds()
 	inbounds, err := t.inboundService.GetAllInbounds()
 	if err != nil {
 	if err != nil {
@@ -2656,6 +2692,7 @@ func (t *Tgbot) getInboundsAddClient() (*telego.InlineKeyboardMarkup, error) {
 	return keyboard, nil
 	return keyboard, nil
 }
 }
 
 
+// getInboundClients creates an inline keyboard with clients of a specific inbound.
 func (t *Tgbot) getInboundClients(id int) (*telego.InlineKeyboardMarkup, error) {
 func (t *Tgbot) getInboundClients(id int) (*telego.InlineKeyboardMarkup, error) {
 	inbound, err := t.inboundService.GetInbound(id)
 	inbound, err := t.inboundService.GetInbound(id)
 	if err != nil {
 	if err != nil {
@@ -2690,6 +2727,7 @@ func (t *Tgbot) getInboundClients(id int) (*telego.InlineKeyboardMarkup, error)
 	return keyboard, nil
 	return keyboard, nil
 }
 }
 
 
+// clientInfoMsg formats client information message based on traffic and flags.
 func (t *Tgbot) clientInfoMsg(
 func (t *Tgbot) clientInfoMsg(
 	traffic *xray.ClientTraffic,
 	traffic *xray.ClientTraffic,
 	printEnabled bool,
 	printEnabled bool,
@@ -2796,6 +2834,7 @@ func (t *Tgbot) clientInfoMsg(
 	return output
 	return output
 }
 }
 
 
+// getClientUsage retrieves and sends client usage information to the chat.
 func (t *Tgbot) getClientUsage(chatId int64, tgUserID int64, email ...string) {
 func (t *Tgbot) getClientUsage(chatId int64, tgUserID int64, email ...string) {
 	traffics, err := t.inboundService.GetClientTrafficTgBot(tgUserID)
 	traffics, err := t.inboundService.GetClientTrafficTgBot(tgUserID)
 	if err != nil {
 	if err != nil {
@@ -2838,6 +2877,7 @@ func (t *Tgbot) getClientUsage(chatId int64, tgUserID int64, email ...string) {
 	t.SendAnswer(chatId, output, false)
 	t.SendAnswer(chatId, output, false)
 }
 }
 
 
+// searchClientIps searches and sends client IP addresses for the given email.
 func (t *Tgbot) searchClientIps(chatId int64, email string, messageID ...int) {
 func (t *Tgbot) searchClientIps(chatId int64, email string, messageID ...int) {
 	ips, err := t.inboundService.GetInboundClientIps(email)
 	ips, err := t.inboundService.GetInboundClientIps(email)
 	if err != nil || len(ips) == 0 {
 	if err != nil || len(ips) == 0 {
@@ -2865,6 +2905,7 @@ func (t *Tgbot) searchClientIps(chatId int64, email string, messageID ...int) {
 	}
 	}
 }
 }
 
 
+// clientTelegramUserInfo retrieves and sends Telegram user info for the client.
 func (t *Tgbot) clientTelegramUserInfo(chatId int64, email string, messageID ...int) {
 func (t *Tgbot) clientTelegramUserInfo(chatId int64, email string, messageID ...int) {
 	traffic, client, err := t.inboundService.GetClientByEmail(email)
 	traffic, client, err := t.inboundService.GetClientByEmail(email)
 	if err != nil {
 	if err != nil {
@@ -2917,6 +2958,7 @@ func (t *Tgbot) clientTelegramUserInfo(chatId int64, email string, messageID ...
 	}
 	}
 }
 }
 
 
+// searchClient searches for a client by email and sends the information.
 func (t *Tgbot) searchClient(chatId int64, email string, messageID ...int) {
 func (t *Tgbot) searchClient(chatId int64, email string, messageID ...int) {
 	traffic, err := t.inboundService.GetClientTrafficByEmail(email)
 	traffic, err := t.inboundService.GetClientTrafficByEmail(email)
 	if err != nil {
 	if err != nil {
@@ -2962,6 +3004,7 @@ func (t *Tgbot) searchClient(chatId int64, email string, messageID ...int) {
 	}
 	}
 }
 }
 
 
+// addClient handles the process of adding a new client to an inbound.
 func (t *Tgbot) addClient(chatId int64, msg string, messageID ...int) {
 func (t *Tgbot) addClient(chatId int64, msg string, messageID ...int) {
 	inbound, err := t.inboundService.GetInbound(receiver_inbound_ID)
 	inbound, err := t.inboundService.GetInbound(receiver_inbound_ID)
 	if err != nil {
 	if err != nil {
@@ -3058,6 +3101,7 @@ func (t *Tgbot) addClient(chatId int64, msg string, messageID ...int) {
 
 
 }
 }
 
 
+// searchInbound searches for inbounds by remark and sends the results.
 func (t *Tgbot) searchInbound(chatId int64, remark string) {
 func (t *Tgbot) searchInbound(chatId int64, remark string) {
 	inbounds, err := t.inboundService.SearchInbounds(remark)
 	inbounds, err := t.inboundService.SearchInbounds(remark)
 	if err != nil {
 	if err != nil {
@@ -3095,6 +3139,7 @@ func (t *Tgbot) searchInbound(chatId int64, remark string) {
 	}
 	}
 }
 }
 
 
+// getExhausted retrieves and sends information about exhausted clients.
 func (t *Tgbot) getExhausted(chatId int64) {
 func (t *Tgbot) getExhausted(chatId int64) {
 	trDiff := int64(0)
 	trDiff := int64(0)
 	exDiff := int64(0)
 	exDiff := int64(0)
@@ -3191,6 +3236,7 @@ func (t *Tgbot) getExhausted(chatId int64) {
 	}
 	}
 }
 }
 
 
+// notifyExhausted sends notifications for exhausted clients.
 func (t *Tgbot) notifyExhausted() {
 func (t *Tgbot) notifyExhausted() {
 	trDiff := int64(0)
 	trDiff := int64(0)
 	exDiff := int64(0)
 	exDiff := int64(0)
@@ -3262,6 +3308,7 @@ func (t *Tgbot) notifyExhausted() {
 	}
 	}
 }
 }
 
 
+// int64Contains checks if an int64 slice contains a specific item.
 func int64Contains(slice []int64, item int64) bool {
 func int64Contains(slice []int64, item int64) bool {
 	for _, s := range slice {
 	for _, s := range slice {
 		if s == item {
 		if s == item {
@@ -3271,6 +3318,7 @@ func int64Contains(slice []int64, item int64) bool {
 	return false
 	return false
 }
 }
 
 
+// onlineClients retrieves and sends information about online clients.
 func (t *Tgbot) onlineClients(chatId int64, messageID ...int) {
 func (t *Tgbot) onlineClients(chatId int64, messageID ...int) {
 	if !p.IsRunning() {
 	if !p.IsRunning() {
 		return
 		return
@@ -3305,6 +3353,7 @@ func (t *Tgbot) onlineClients(chatId int64, messageID ...int) {
 	}
 	}
 }
 }
 
 
+// sendBackup sends a backup of the database and configuration files.
 func (t *Tgbot) sendBackup(chatId int64) {
 func (t *Tgbot) sendBackup(chatId int64) {
 	output := t.I18nBot("tgbot.messages.backupTime", "Time=="+time.Now().Format("2006-01-02 15:04:05"))
 	output := t.I18nBot("tgbot.messages.backupTime", "Time=="+time.Now().Format("2006-01-02 15:04:05"))
 	t.SendMsgToTgbot(chatId, output)
 	t.SendMsgToTgbot(chatId, output)
@@ -3344,6 +3393,7 @@ func (t *Tgbot) sendBackup(chatId int64) {
 	}
 	}
 }
 }
 
 
+// sendBanLogs sends the ban logs to the specified chat.
 func (t *Tgbot) sendBanLogs(chatId int64, dt bool) {
 func (t *Tgbot) sendBanLogs(chatId int64, dt bool) {
 	if dt {
 	if dt {
 		output := t.I18nBot("tgbot.messages.datetime", "DateTime=="+time.Now().Format("2006-01-02 15:04:05"))
 		output := t.I18nBot("tgbot.messages.datetime", "DateTime=="+time.Now().Format("2006-01-02 15:04:05"))
@@ -3393,6 +3443,7 @@ func (t *Tgbot) sendBanLogs(chatId int64, dt bool) {
 	}
 	}
 }
 }
 
 
+// sendCallbackAnswerTgBot answers a callback query with a message.
 func (t *Tgbot) sendCallbackAnswerTgBot(id string, message string) {
 func (t *Tgbot) sendCallbackAnswerTgBot(id string, message string) {
 	params := telego.AnswerCallbackQueryParams{
 	params := telego.AnswerCallbackQueryParams{
 		CallbackQueryID: id,
 		CallbackQueryID: id,
@@ -3403,6 +3454,7 @@ func (t *Tgbot) sendCallbackAnswerTgBot(id string, message string) {
 	}
 	}
 }
 }
 
 
+// editMessageCallbackTgBot edits the reply markup of a message.
 func (t *Tgbot) editMessageCallbackTgBot(chatId int64, messageID int, inlineKeyboard *telego.InlineKeyboardMarkup) {
 func (t *Tgbot) editMessageCallbackTgBot(chatId int64, messageID int, inlineKeyboard *telego.InlineKeyboardMarkup) {
 	params := telego.EditMessageReplyMarkupParams{
 	params := telego.EditMessageReplyMarkupParams{
 		ChatID:      tu.ID(chatId),
 		ChatID:      tu.ID(chatId),
@@ -3414,6 +3466,7 @@ func (t *Tgbot) editMessageCallbackTgBot(chatId int64, messageID int, inlineKeyb
 	}
 	}
 }
 }
 
 
+// editMessageTgBot edits the text and reply markup of a message.
 func (t *Tgbot) editMessageTgBot(chatId int64, messageID int, text string, inlineKeyboard ...*telego.InlineKeyboardMarkup) {
 func (t *Tgbot) editMessageTgBot(chatId int64, messageID int, text string, inlineKeyboard ...*telego.InlineKeyboardMarkup) {
 	params := telego.EditMessageTextParams{
 	params := telego.EditMessageTextParams{
 		ChatID:    tu.ID(chatId),
 		ChatID:    tu.ID(chatId),
@@ -3429,6 +3482,7 @@ func (t *Tgbot) editMessageTgBot(chatId int64, messageID int, text string, inlin
 	}
 	}
 }
 }
 
 
+// SendMsgToTgbotDeleteAfter sends a message and deletes it after a specified delay.
 func (t *Tgbot) SendMsgToTgbotDeleteAfter(chatId int64, msg string, delayInSeconds int, replyMarkup ...telego.ReplyMarkup) {
 func (t *Tgbot) SendMsgToTgbotDeleteAfter(chatId int64, msg string, delayInSeconds int, replyMarkup ...telego.ReplyMarkup) {
 	// Determine if replyMarkup was passed; otherwise, set it to nil
 	// Determine if replyMarkup was passed; otherwise, set it to nil
 	var replyMarkupParam telego.ReplyMarkup
 	var replyMarkupParam telego.ReplyMarkup
@@ -3455,6 +3509,7 @@ func (t *Tgbot) SendMsgToTgbotDeleteAfter(chatId int64, msg string, delayInSecon
 	}()
 	}()
 }
 }
 
 
+// deleteMessageTgBot deletes a message from the chat.
 func (t *Tgbot) deleteMessageTgBot(chatId int64, messageID int) {
 func (t *Tgbot) deleteMessageTgBot(chatId int64, messageID int) {
 	params := telego.DeleteMessageParams{
 	params := telego.DeleteMessageParams{
 		ChatID:    tu.ID(chatId),
 		ChatID:    tu.ID(chatId),
@@ -3467,6 +3522,7 @@ func (t *Tgbot) deleteMessageTgBot(chatId int64, messageID int) {
 	}
 	}
 }
 }
 
 
+// isSingleWord checks if the text contains only a single word.
 func (t *Tgbot) isSingleWord(text string) bool {
 func (t *Tgbot) isSingleWord(text string) bool {
 	text = strings.TrimSpace(text)
 	text = strings.TrimSpace(text)
 	re := regexp.MustCompile(`\s+`)
 	re := regexp.MustCompile(`\s+`)

+ 4 - 0
web/service/user.go

@@ -12,10 +12,14 @@ import (
 	"gorm.io/gorm"
 	"gorm.io/gorm"
 )
 )
 
 
+// UserService provides business logic for user management and authentication.
+// It handles user creation, login, password management, and 2FA operations.
 type UserService struct {
 type UserService struct {
 	settingService SettingService
 	settingService SettingService
 }
 }
 
 
+// GetFirstUser retrieves the first user from the database.
+// This is typically used for initial setup or when there's only one admin user.
 func (s *UserService) GetFirstUser() (*model.User, error) {
 func (s *UserService) GetFirstUser() (*model.User, error) {
 	db := database.GetDB()
 	db := database.GetDB()
 
 

+ 2 - 0
web/service/warp.go

@@ -12,6 +12,8 @@ import (
 	"github.com/mhsanaei/3x-ui/v2/util/common"
 	"github.com/mhsanaei/3x-ui/v2/util/common"
 )
 )
 
 
+// WarpService provides business logic for Cloudflare WARP integration.
+// It manages WARP configuration and connectivity settings.
 type WarpService struct {
 type WarpService struct {
 	SettingService
 	SettingService
 }
 }

+ 15 - 1
web/service/xray.go

@@ -20,16 +20,20 @@ var (
 	result            string
 	result            string
 )
 )
 
 
+// XrayService provides business logic for Xray process management.
+// It handles starting, stopping, restarting Xray, and managing its configuration.
 type XrayService struct {
 type XrayService struct {
 	inboundService InboundService
 	inboundService InboundService
 	settingService SettingService
 	settingService SettingService
 	xrayAPI        xray.XrayAPI
 	xrayAPI        xray.XrayAPI
 }
 }
 
 
+// IsXrayRunning checks if the Xray process is currently running.
 func (s *XrayService) IsXrayRunning() bool {
 func (s *XrayService) IsXrayRunning() bool {
 	return p != nil && p.IsRunning()
 	return p != nil && p.IsRunning()
 }
 }
 
 
+// GetXrayErr returns the error from the Xray process, if any.
 func (s *XrayService) GetXrayErr() error {
 func (s *XrayService) GetXrayErr() error {
 	if p == nil {
 	if p == nil {
 		return nil
 		return nil
@@ -46,6 +50,7 @@ func (s *XrayService) GetXrayErr() error {
 	return err
 	return err
 }
 }
 
 
+// GetXrayResult returns the result string from the Xray process.
 func (s *XrayService) GetXrayResult() string {
 func (s *XrayService) GetXrayResult() string {
 	if result != "" {
 	if result != "" {
 		return result
 		return result
@@ -68,6 +73,7 @@ func (s *XrayService) GetXrayResult() string {
 	return result
 	return result
 }
 }
 
 
+// GetXrayVersion returns the version of the running Xray process.
 func (s *XrayService) GetXrayVersion() string {
 func (s *XrayService) GetXrayVersion() string {
 	if p == nil {
 	if p == nil {
 		return "Unknown"
 		return "Unknown"
@@ -75,10 +81,13 @@ func (s *XrayService) GetXrayVersion() string {
 	return p.GetVersion()
 	return p.GetVersion()
 }
 }
 
 
+// RemoveIndex removes an element at the specified index from a slice.
+// Returns a new slice with the element removed.
 func RemoveIndex(s []any, index int) []any {
 func RemoveIndex(s []any, index int) []any {
 	return append(s[:index], s[index+1:]...)
 	return append(s[:index], s[index+1:]...)
 }
 }
 
 
+// GetXrayConfig retrieves and builds the Xray configuration from settings and inbounds.
 func (s *XrayService) GetXrayConfig() (*xray.Config, error) {
 func (s *XrayService) GetXrayConfig() (*xray.Config, error) {
 	templateConfig, err := s.settingService.GetXrayConfigTemplate()
 	templateConfig, err := s.settingService.GetXrayConfigTemplate()
 	if err != nil {
 	if err != nil {
@@ -182,6 +191,7 @@ func (s *XrayService) GetXrayConfig() (*xray.Config, error) {
 	return xrayConfig, nil
 	return xrayConfig, nil
 }
 }
 
 
+// GetXrayTraffic fetches the current traffic statistics from the running Xray process.
 func (s *XrayService) GetXrayTraffic() ([]*xray.Traffic, []*xray.ClientTraffic, error) {
 func (s *XrayService) GetXrayTraffic() ([]*xray.Traffic, []*xray.ClientTraffic, error) {
 	if !s.IsXrayRunning() {
 	if !s.IsXrayRunning() {
 		err := errors.New("xray is not running")
 		err := errors.New("xray is not running")
@@ -200,6 +210,7 @@ func (s *XrayService) GetXrayTraffic() ([]*xray.Traffic, []*xray.ClientTraffic,
 	return traffic, clientTraffic, nil
 	return traffic, clientTraffic, nil
 }
 }
 
 
+// RestartXray restarts the Xray process, optionally forcing a restart even if config unchanged.
 func (s *XrayService) RestartXray(isForce bool) error {
 func (s *XrayService) RestartXray(isForce bool) error {
 	lock.Lock()
 	lock.Lock()
 	defer lock.Unlock()
 	defer lock.Unlock()
@@ -229,6 +240,7 @@ func (s *XrayService) RestartXray(isForce bool) error {
 	return nil
 	return nil
 }
 }
 
 
+// StopXray stops the running Xray process.
 func (s *XrayService) StopXray() error {
 func (s *XrayService) StopXray() error {
 	lock.Lock()
 	lock.Lock()
 	defer lock.Unlock()
 	defer lock.Unlock()
@@ -240,15 +252,17 @@ func (s *XrayService) StopXray() error {
 	return errors.New("xray is not running")
 	return errors.New("xray is not running")
 }
 }
 
 
+// SetToNeedRestart marks that Xray needs to be restarted.
 func (s *XrayService) SetToNeedRestart() {
 func (s *XrayService) SetToNeedRestart() {
 	isNeedXrayRestart.Store(true)
 	isNeedXrayRestart.Store(true)
 }
 }
 
 
+// IsNeedRestartAndSetFalse checks if restart is needed and resets the flag to false.
 func (s *XrayService) IsNeedRestartAndSetFalse() bool {
 func (s *XrayService) IsNeedRestartAndSetFalse() bool {
 	return isNeedXrayRestart.CompareAndSwap(true, false)
 	return isNeedXrayRestart.CompareAndSwap(true, false)
 }
 }
 
 
-// Check if Xray is not running and wasn't stopped manually, i.e. crashed
+// DidXrayCrash checks if Xray crashed by verifying it's not running and wasn't manually stopped.
 func (s *XrayService) DidXrayCrash() bool {
 func (s *XrayService) DidXrayCrash() bool {
 	return !s.IsXrayRunning() && !isManuallyStopped.Load()
 	return !s.IsXrayRunning() && !isManuallyStopped.Load()
 }
 }

+ 2 - 0
web/service/xray_setting.go

@@ -8,6 +8,8 @@ import (
 	"github.com/mhsanaei/3x-ui/v2/xray"
 	"github.com/mhsanaei/3x-ui/v2/xray"
 )
 )
 
 
+// XraySettingService provides business logic for Xray configuration management.
+// It handles validation and storage of Xray template configurations.
 type XraySettingService struct {
 type XraySettingService struct {
 	SettingService
 	SettingService
 }
 }

+ 12 - 0
web/session/session.go

@@ -1,3 +1,5 @@
+// Package session provides session management utilities for the 3x-ui web panel.
+// It handles user authentication state, login sessions, and session storage using Gin sessions.
 package session
 package session
 
 
 import (
 import (
@@ -19,6 +21,8 @@ func init() {
 	gob.Register(model.User{})
 	gob.Register(model.User{})
 }
 }
 
 
+// SetLoginUser stores the authenticated user in the session.
+// The user object is serialized and stored for subsequent requests.
 func SetLoginUser(c *gin.Context, user *model.User) {
 func SetLoginUser(c *gin.Context, user *model.User) {
 	if user == nil {
 	if user == nil {
 		return
 		return
@@ -27,6 +31,8 @@ func SetLoginUser(c *gin.Context, user *model.User) {
 	s.Set(loginUserKey, *user)
 	s.Set(loginUserKey, *user)
 }
 }
 
 
+// SetMaxAge configures the session cookie maximum age in seconds.
+// This controls how long the session remains valid before requiring re-authentication.
 func SetMaxAge(c *gin.Context, maxAge int) {
 func SetMaxAge(c *gin.Context, maxAge int) {
 	s := sessions.Default(c)
 	s := sessions.Default(c)
 	s.Options(sessions.Options{
 	s.Options(sessions.Options{
@@ -37,6 +43,8 @@ func SetMaxAge(c *gin.Context, maxAge int) {
 	})
 	})
 }
 }
 
 
+// GetLoginUser retrieves the authenticated user from the session.
+// Returns nil if no user is logged in or if the session data is invalid.
 func GetLoginUser(c *gin.Context) *model.User {
 func GetLoginUser(c *gin.Context) *model.User {
 	s := sessions.Default(c)
 	s := sessions.Default(c)
 	obj := s.Get(loginUserKey)
 	obj := s.Get(loginUserKey)
@@ -52,10 +60,14 @@ func GetLoginUser(c *gin.Context) *model.User {
 	return &user
 	return &user
 }
 }
 
 
+// IsLogin checks if a user is currently authenticated in the session.
+// Returns true if a valid user session exists, false otherwise.
 func IsLogin(c *gin.Context) bool {
 func IsLogin(c *gin.Context) bool {
 	return GetLoginUser(c) != nil
 	return GetLoginUser(c) != nil
 }
 }
 
 
+// ClearSession removes all session data and invalidates the session.
+// This effectively logs out the user and clears any stored session information.
 func ClearSession(c *gin.Context) {
 func ClearSession(c *gin.Context) {
 	s := sessions.Default(c)
 	s := sessions.Default(c)
 	s.Clear()
 	s.Clear()

+ 19 - 1
web/web.go

@@ -1,3 +1,5 @@
+// Package web provides the main web server implementation for the 3x-ui panel,
+// including HTTP/HTTPS serving, routing, templates, and background job scheduling.
 package web
 package web
 
 
 import (
 import (
@@ -78,15 +80,17 @@ func (f *wrapAssetsFileInfo) ModTime() time.Time {
 	return startTime
 	return startTime
 }
 }
 
 
-// Expose embedded resources for reuse by other servers (e.g., sub server)
+// EmbeddedHTML returns the embedded HTML templates filesystem for reuse by other servers.
 func EmbeddedHTML() embed.FS {
 func EmbeddedHTML() embed.FS {
 	return htmlFS
 	return htmlFS
 }
 }
 
 
+// EmbeddedAssets returns the embedded assets filesystem for reuse by other servers.
 func EmbeddedAssets() embed.FS {
 func EmbeddedAssets() embed.FS {
 	return assetsFS
 	return assetsFS
 }
 }
 
 
+// Server represents the main web server for the 3x-ui panel with controllers, services, and scheduled jobs.
 type Server struct {
 type Server struct {
 	httpServer *http.Server
 	httpServer *http.Server
 	listener   net.Listener
 	listener   net.Listener
@@ -106,6 +110,7 @@ type Server struct {
 	cancel context.CancelFunc
 	cancel context.CancelFunc
 }
 }
 
 
+// NewServer creates a new web server instance with a cancellable context.
 func NewServer() *Server {
 func NewServer() *Server {
 	ctx, cancel := context.WithCancel(context.Background())
 	ctx, cancel := context.WithCancel(context.Background())
 	return &Server{
 	return &Server{
@@ -114,6 +119,8 @@ func NewServer() *Server {
 	}
 	}
 }
 }
 
 
+// getHtmlFiles walks the local `web/html` directory and returns a list of
+// template file paths. Used only in debug/development mode.
 func (s *Server) getHtmlFiles() ([]string, error) {
 func (s *Server) getHtmlFiles() ([]string, error) {
 	files := make([]string, 0)
 	files := make([]string, 0)
 	dir, _ := os.Getwd()
 	dir, _ := os.Getwd()
@@ -133,6 +140,9 @@ func (s *Server) getHtmlFiles() ([]string, error) {
 	return files, nil
 	return files, nil
 }
 }
 
 
+// getHtmlTemplate parses embedded HTML templates from the bundled `htmlFS`
+// using the provided template function map and returns the resulting
+// template set for production usage.
 func (s *Server) getHtmlTemplate(funcMap template.FuncMap) (*template.Template, error) {
 func (s *Server) getHtmlTemplate(funcMap template.FuncMap) (*template.Template, error) {
 	t := template.New("").Funcs(funcMap)
 	t := template.New("").Funcs(funcMap)
 	err := fs.WalkDir(htmlFS, "html", func(path string, d fs.DirEntry, err error) error {
 	err := fs.WalkDir(htmlFS, "html", func(path string, d fs.DirEntry, err error) error {
@@ -156,6 +166,8 @@ func (s *Server) getHtmlTemplate(funcMap template.FuncMap) (*template.Template,
 	return t, nil
 	return t, nil
 }
 }
 
 
+// initRouter initializes Gin, registers middleware, templates, static
+// assets, controllers and returns the configured engine.
 func (s *Server) initRouter() (*gin.Engine, error) {
 func (s *Server) initRouter() (*gin.Engine, error) {
 	if config.IsDebug() {
 	if config.IsDebug() {
 		gin.SetMode(gin.DebugMode)
 		gin.SetMode(gin.DebugMode)
@@ -259,6 +271,8 @@ func (s *Server) initRouter() (*gin.Engine, error) {
 	return engine, nil
 	return engine, nil
 }
 }
 
 
+// startTask schedules background jobs (Xray checks, traffic jobs, cron
+// jobs) which the panel relies on for periodic maintenance and monitoring.
 func (s *Server) startTask() {
 func (s *Server) startTask() {
 	err := s.xrayService.RestartXray(true)
 	err := s.xrayService.RestartXray(true)
 	if err != nil {
 	if err != nil {
@@ -326,6 +340,7 @@ func (s *Server) startTask() {
 	}
 	}
 }
 }
 
 
+// Start initializes and starts the web server with configured settings, routes, and background jobs.
 func (s *Server) Start() (err error) {
 func (s *Server) Start() (err error) {
 	// This is an anonymous function, no function name
 	// This is an anonymous function, no function name
 	defer func() {
 	defer func() {
@@ -404,6 +419,7 @@ func (s *Server) Start() (err error) {
 	return nil
 	return nil
 }
 }
 
 
+// Stop gracefully shuts down the web server, stops Xray, cron jobs, and Telegram bot.
 func (s *Server) Stop() error {
 func (s *Server) Stop() error {
 	s.cancel()
 	s.cancel()
 	s.xrayService.StopXray()
 	s.xrayService.StopXray()
@@ -424,10 +440,12 @@ func (s *Server) Stop() error {
 	return common.Combine(err1, err2)
 	return common.Combine(err1, err2)
 }
 }
 
 
+// GetCtx returns the server's context for cancellation and deadline management.
 func (s *Server) GetCtx() context.Context {
 func (s *Server) GetCtx() context.Context {
 	return s.ctx
 	return s.ctx
 }
 }
 
 
+// GetCron returns the server's cron scheduler instance.
 func (s *Server) GetCron() *cron.Cron {
 func (s *Server) GetCron() *cron.Cron {
 	return s.cron
 	return s.cron
 }
 }

+ 14 - 0
xray/api.go

@@ -1,3 +1,6 @@
+// Package xray provides integration with the Xray proxy core.
+// It includes API client functionality, configuration management, traffic monitoring,
+// and process control for Xray instances.
 package xray
 package xray
 
 
 import (
 import (
@@ -25,6 +28,7 @@ import (
 	"google.golang.org/grpc/credentials/insecure"
 	"google.golang.org/grpc/credentials/insecure"
 )
 )
 
 
+// XrayAPI is a gRPC client for managing Xray core configuration, inbounds, outbounds, and statistics.
 type XrayAPI struct {
 type XrayAPI struct {
 	HandlerServiceClient *command.HandlerServiceClient
 	HandlerServiceClient *command.HandlerServiceClient
 	StatsServiceClient   *statsService.StatsServiceClient
 	StatsServiceClient   *statsService.StatsServiceClient
@@ -32,6 +36,7 @@ type XrayAPI struct {
 	isConnected          bool
 	isConnected          bool
 }
 }
 
 
+// Init connects to the Xray API server and initializes handler and stats service clients.
 func (x *XrayAPI) Init(apiPort int) error {
 func (x *XrayAPI) Init(apiPort int) error {
 	if apiPort <= 0 || apiPort > math.MaxUint16 {
 	if apiPort <= 0 || apiPort > math.MaxUint16 {
 		return fmt.Errorf("invalid Xray API port: %d", apiPort)
 		return fmt.Errorf("invalid Xray API port: %d", apiPort)
@@ -55,6 +60,7 @@ func (x *XrayAPI) Init(apiPort int) error {
 	return nil
 	return nil
 }
 }
 
 
+// Close closes the gRPC connection and resets the XrayAPI client state.
 func (x *XrayAPI) Close() {
 func (x *XrayAPI) Close() {
 	if x.grpcClient != nil {
 	if x.grpcClient != nil {
 		x.grpcClient.Close()
 		x.grpcClient.Close()
@@ -64,6 +70,7 @@ func (x *XrayAPI) Close() {
 	x.isConnected = false
 	x.isConnected = false
 }
 }
 
 
+// AddInbound adds a new inbound configuration to the Xray core via gRPC.
 func (x *XrayAPI) AddInbound(inbound []byte) error {
 func (x *XrayAPI) AddInbound(inbound []byte) error {
 	client := *x.HandlerServiceClient
 	client := *x.HandlerServiceClient
 
 
@@ -85,6 +92,7 @@ func (x *XrayAPI) AddInbound(inbound []byte) error {
 	return err
 	return err
 }
 }
 
 
+// DelInbound removes an inbound configuration from the Xray core by tag.
 func (x *XrayAPI) DelInbound(tag string) error {
 func (x *XrayAPI) DelInbound(tag string) error {
 	client := *x.HandlerServiceClient
 	client := *x.HandlerServiceClient
 	_, err := client.RemoveInbound(context.Background(), &command.RemoveInboundRequest{
 	_, err := client.RemoveInbound(context.Background(), &command.RemoveInboundRequest{
@@ -93,6 +101,7 @@ func (x *XrayAPI) DelInbound(tag string) error {
 	return err
 	return err
 }
 }
 
 
+// AddUser adds a user to an inbound in the Xray core using the specified protocol and user data.
 func (x *XrayAPI) AddUser(Protocol string, inboundTag string, user map[string]any) error {
 func (x *XrayAPI) AddUser(Protocol string, inboundTag string, user map[string]any) error {
 	var account *serial.TypedMessage
 	var account *serial.TypedMessage
 	switch Protocol {
 	switch Protocol {
@@ -153,6 +162,7 @@ func (x *XrayAPI) AddUser(Protocol string, inboundTag string, user map[string]an
 	return err
 	return err
 }
 }
 
 
+// RemoveUser removes a user from an inbound in the Xray core by email.
 func (x *XrayAPI) RemoveUser(inboundTag, email string) error {
 func (x *XrayAPI) RemoveUser(inboundTag, email string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
 	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
 	defer cancel()
 	defer cancel()
@@ -171,6 +181,7 @@ func (x *XrayAPI) RemoveUser(inboundTag, email string) error {
 	return nil
 	return nil
 }
 }
 
 
+// GetTraffic queries traffic statistics from the Xray core, optionally resetting counters.
 func (x *XrayAPI) GetTraffic(reset bool) ([]*Traffic, []*ClientTraffic, error) {
 func (x *XrayAPI) GetTraffic(reset bool) ([]*Traffic, []*ClientTraffic, error) {
 	if x.grpcClient == nil {
 	if x.grpcClient == nil {
 		return nil, nil, common.NewError("xray api is not initialized")
 		return nil, nil, common.NewError("xray api is not initialized")
@@ -205,6 +216,7 @@ func (x *XrayAPI) GetTraffic(reset bool) ([]*Traffic, []*ClientTraffic, error) {
 	return mapToSlice(tagTrafficMap), mapToSlice(emailTrafficMap), nil
 	return mapToSlice(tagTrafficMap), mapToSlice(emailTrafficMap), nil
 }
 }
 
 
+// processTraffic aggregates a traffic stat into trafficMap using regex matches and value.
 func processTraffic(matches []string, value int64, trafficMap map[string]*Traffic) {
 func processTraffic(matches []string, value int64, trafficMap map[string]*Traffic) {
 	isInbound := matches[1] == "inbound"
 	isInbound := matches[1] == "inbound"
 	tag := matches[2]
 	tag := matches[2]
@@ -231,6 +243,7 @@ func processTraffic(matches []string, value int64, trafficMap map[string]*Traffi
 	}
 	}
 }
 }
 
 
+// processClientTraffic updates clientTrafficMap with upload/download values for a client email.
 func processClientTraffic(matches []string, value int64, clientTrafficMap map[string]*ClientTraffic) {
 func processClientTraffic(matches []string, value int64, clientTrafficMap map[string]*ClientTraffic) {
 	email := matches[1]
 	email := matches[1]
 	isDown := matches[2] == "downlink"
 	isDown := matches[2] == "downlink"
@@ -248,6 +261,7 @@ func processClientTraffic(matches []string, value int64, clientTrafficMap map[st
 	}
 	}
 }
 }
 
 
+// mapToSlice converts a map of pointers to a slice of pointers.
 func mapToSlice[T any](m map[string]*T) []*T {
 func mapToSlice[T any](m map[string]*T) []*T {
 	result := make([]*T, 0, len(m))
 	result := make([]*T, 0, len(m))
 	for _, v := range m {
 	for _, v := range m {

+ 2 - 0
xray/client_traffic.go

@@ -1,5 +1,7 @@
 package xray
 package xray
 
 
+// ClientTraffic represents traffic statistics and limits for a specific client.
+// It tracks upload/download usage, expiry times, and online status for inbound clients.
 type ClientTraffic struct {
 type ClientTraffic struct {
 	Id         int    `json:"id" form:"id" gorm:"primaryKey;autoIncrement"`
 	Id         int    `json:"id" form:"id" gorm:"primaryKey;autoIncrement"`
 	InboundId  int    `json:"inboundId" form:"inboundId"`
 	InboundId  int    `json:"inboundId" form:"inboundId"`

+ 3 - 0
xray/config.go

@@ -6,6 +6,8 @@ import (
 	"github.com/mhsanaei/3x-ui/v2/util/json_util"
 	"github.com/mhsanaei/3x-ui/v2/util/json_util"
 )
 )
 
 
+// Config represents the complete Xray configuration structure.
+// It contains all sections of an Xray config file including inbounds, outbounds, routing, etc.
 type Config struct {
 type Config struct {
 	LogConfig        json_util.RawMessage `json:"log"`
 	LogConfig        json_util.RawMessage `json:"log"`
 	RouterConfig     json_util.RawMessage `json:"routing"`
 	RouterConfig     json_util.RawMessage `json:"routing"`
@@ -23,6 +25,7 @@ type Config struct {
 	Metrics          json_util.RawMessage `json:"metrics"`
 	Metrics          json_util.RawMessage `json:"metrics"`
 }
 }
 
 
+// Equals compares two Config instances for deep equality.
 func (c *Config) Equals(other *Config) bool {
 func (c *Config) Equals(other *Config) bool {
 	if len(c.InboundConfigs) != len(other.InboundConfigs) {
 	if len(c.InboundConfigs) != len(other.InboundConfigs) {
 		return false
 		return false

+ 3 - 0
xray/inbound.go

@@ -6,6 +6,8 @@ import (
 	"github.com/mhsanaei/3x-ui/v2/util/json_util"
 	"github.com/mhsanaei/3x-ui/v2/util/json_util"
 )
 )
 
 
+// InboundConfig represents an Xray inbound configuration.
+// It defines how Xray accepts incoming connections including protocol, port, and settings.
 type InboundConfig struct {
 type InboundConfig struct {
 	Listen         json_util.RawMessage `json:"listen"` // listen cannot be an empty string
 	Listen         json_util.RawMessage `json:"listen"` // listen cannot be an empty string
 	Port           int                  `json:"port"`
 	Port           int                  `json:"port"`
@@ -16,6 +18,7 @@ type InboundConfig struct {
 	Sniffing       json_util.RawMessage `json:"sniffing"`
 	Sniffing       json_util.RawMessage `json:"sniffing"`
 }
 }
 
 
+// Equals compares two InboundConfig instances for deep equality.
 func (c *InboundConfig) Equals(other *InboundConfig) bool {
 func (c *InboundConfig) Equals(other *InboundConfig) bool {
 	if !bytes.Equal(c.Listen, other.Listen) {
 	if !bytes.Equal(c.Listen, other.Listen) {
 		return false
 		return false

+ 3 - 0
xray/log_writer.go

@@ -8,14 +8,17 @@ import (
 	"github.com/mhsanaei/3x-ui/v2/logger"
 	"github.com/mhsanaei/3x-ui/v2/logger"
 )
 )
 
 
+// NewLogWriter returns a new LogWriter for processing Xray log output.
 func NewLogWriter() *LogWriter {
 func NewLogWriter() *LogWriter {
 	return &LogWriter{}
 	return &LogWriter{}
 }
 }
 
 
+// LogWriter processes and filters log output from the Xray process, handling crash detection and message filtering.
 type LogWriter struct {
 type LogWriter struct {
 	lastLine string
 	lastLine string
 }
 }
 
 
+// Write processes and filters log output from the Xray process, handling crash detection and message filtering.
 func (lw *LogWriter) Write(m []byte) (n int, err error) {
 func (lw *LogWriter) Write(m []byte) (n int, err error) {
 	crashRegex := regexp.MustCompile(`(?i)(panic|exception|stack trace|fatal error)`)
 	crashRegex := regexp.MustCompile(`(?i)(panic|exception|stack trace|fatal error)`)
 
 

+ 29 - 0
xray/process.go

@@ -18,46 +18,57 @@ import (
 	"github.com/mhsanaei/3x-ui/v2/util/common"
 	"github.com/mhsanaei/3x-ui/v2/util/common"
 )
 )
 
 
+// GetBinaryName returns the Xray binary filename for the current OS and architecture.
 func GetBinaryName() string {
 func GetBinaryName() string {
 	return fmt.Sprintf("xray-%s-%s", runtime.GOOS, runtime.GOARCH)
 	return fmt.Sprintf("xray-%s-%s", runtime.GOOS, runtime.GOARCH)
 }
 }
 
 
+// GetBinaryPath returns the full path to the Xray binary executable.
 func GetBinaryPath() string {
 func GetBinaryPath() string {
 	return config.GetBinFolderPath() + "/" + GetBinaryName()
 	return config.GetBinFolderPath() + "/" + GetBinaryName()
 }
 }
 
 
+// GetConfigPath returns the path to the Xray configuration file in the binary folder.
 func GetConfigPath() string {
 func GetConfigPath() string {
 	return config.GetBinFolderPath() + "/config.json"
 	return config.GetBinFolderPath() + "/config.json"
 }
 }
 
 
+// GetGeositePath returns the path to the geosite data file used by Xray.
 func GetGeositePath() string {
 func GetGeositePath() string {
 	return config.GetBinFolderPath() + "/geosite.dat"
 	return config.GetBinFolderPath() + "/geosite.dat"
 }
 }
 
 
+// GetGeoipPath returns the path to the geoip data file used by Xray.
 func GetGeoipPath() string {
 func GetGeoipPath() string {
 	return config.GetBinFolderPath() + "/geoip.dat"
 	return config.GetBinFolderPath() + "/geoip.dat"
 }
 }
 
 
+// GetIPLimitLogPath returns the path to the IP limit log file.
 func GetIPLimitLogPath() string {
 func GetIPLimitLogPath() string {
 	return config.GetLogFolder() + "/3xipl.log"
 	return config.GetLogFolder() + "/3xipl.log"
 }
 }
 
 
+// GetIPLimitBannedLogPath returns the path to the banned IP log file.
 func GetIPLimitBannedLogPath() string {
 func GetIPLimitBannedLogPath() string {
 	return config.GetLogFolder() + "/3xipl-banned.log"
 	return config.GetLogFolder() + "/3xipl-banned.log"
 }
 }
 
 
+// GetIPLimitBannedPrevLogPath returns the path to the previous banned IP log file.
 func GetIPLimitBannedPrevLogPath() string {
 func GetIPLimitBannedPrevLogPath() string {
 	return config.GetLogFolder() + "/3xipl-banned.prev.log"
 	return config.GetLogFolder() + "/3xipl-banned.prev.log"
 }
 }
 
 
+// GetAccessPersistentLogPath returns the path to the persistent access log file.
 func GetAccessPersistentLogPath() string {
 func GetAccessPersistentLogPath() string {
 	return config.GetLogFolder() + "/3xipl-ap.log"
 	return config.GetLogFolder() + "/3xipl-ap.log"
 }
 }
 
 
+// GetAccessPersistentPrevLogPath returns the path to the previous persistent access log file.
 func GetAccessPersistentPrevLogPath() string {
 func GetAccessPersistentPrevLogPath() string {
 	return config.GetLogFolder() + "/3xipl-ap.prev.log"
 	return config.GetLogFolder() + "/3xipl-ap.prev.log"
 }
 }
 
 
+// GetAccessLogPath reads the Xray config and returns the access log file path.
 func GetAccessLogPath() (string, error) {
 func GetAccessLogPath() (string, error) {
 	config, err := os.ReadFile(GetConfigPath())
 	config, err := os.ReadFile(GetConfigPath())
 	if err != nil {
 	if err != nil {
@@ -82,14 +93,17 @@ func GetAccessLogPath() (string, error) {
 	return "", err
 	return "", err
 }
 }
 
 
+// stopProcess calls Stop on the given Process instance.
 func stopProcess(p *Process) {
 func stopProcess(p *Process) {
 	p.Stop()
 	p.Stop()
 }
 }
 
 
+// Process wraps an Xray process instance and provides management methods.
 type Process struct {
 type Process struct {
 	*process
 	*process
 }
 }
 
 
+// NewProcess creates a new Xray process and sets up cleanup on garbage collection.
 func NewProcess(xrayConfig *Config) *Process {
 func NewProcess(xrayConfig *Config) *Process {
 	p := &Process{newProcess(xrayConfig)}
 	p := &Process{newProcess(xrayConfig)}
 	runtime.SetFinalizer(p, stopProcess)
 	runtime.SetFinalizer(p, stopProcess)
@@ -110,6 +124,7 @@ type process struct {
 	startTime time.Time
 	startTime time.Time
 }
 }
 
 
+// newProcess creates a new internal process struct for Xray.
 func newProcess(config *Config) *process {
 func newProcess(config *Config) *process {
 	return &process{
 	return &process{
 		version:   "Unknown",
 		version:   "Unknown",
@@ -119,6 +134,7 @@ func newProcess(config *Config) *process {
 	}
 	}
 }
 }
 
 
+// IsRunning returns true if the Xray process is currently running.
 func (p *process) IsRunning() bool {
 func (p *process) IsRunning() bool {
 	if p.cmd == nil || p.cmd.Process == nil {
 	if p.cmd == nil || p.cmd.Process == nil {
 		return false
 		return false
@@ -129,10 +145,12 @@ func (p *process) IsRunning() bool {
 	return false
 	return false
 }
 }
 
 
+// GetErr returns the last error encountered by the Xray process.
 func (p *process) GetErr() error {
 func (p *process) GetErr() error {
 	return p.exitErr
 	return p.exitErr
 }
 }
 
 
+// GetResult returns the last log line or error from the Xray process.
 func (p *process) GetResult() string {
 func (p *process) GetResult() string {
 	if len(p.logWriter.lastLine) == 0 && p.exitErr != nil {
 	if len(p.logWriter.lastLine) == 0 && p.exitErr != nil {
 		return p.exitErr.Error()
 		return p.exitErr.Error()
@@ -140,30 +158,37 @@ func (p *process) GetResult() string {
 	return p.logWriter.lastLine
 	return p.logWriter.lastLine
 }
 }
 
 
+// GetVersion returns the version string of the Xray process.
 func (p *process) GetVersion() string {
 func (p *process) GetVersion() string {
 	return p.version
 	return p.version
 }
 }
 
 
+// GetAPIPort returns the API port used by the Xray process.
 func (p *Process) GetAPIPort() int {
 func (p *Process) GetAPIPort() int {
 	return p.apiPort
 	return p.apiPort
 }
 }
 
 
+// GetConfig returns the configuration used by the Xray process.
 func (p *Process) GetConfig() *Config {
 func (p *Process) GetConfig() *Config {
 	return p.config
 	return p.config
 }
 }
 
 
+// GetOnlineClients returns the list of online clients for the Xray process.
 func (p *Process) GetOnlineClients() []string {
 func (p *Process) GetOnlineClients() []string {
 	return p.onlineClients
 	return p.onlineClients
 }
 }
 
 
+// SetOnlineClients sets the list of online clients for the Xray process.
 func (p *Process) SetOnlineClients(users []string) {
 func (p *Process) SetOnlineClients(users []string) {
 	p.onlineClients = users
 	p.onlineClients = users
 }
 }
 
 
+// GetUptime returns the uptime of the Xray process in seconds.
 func (p *Process) GetUptime() uint64 {
 func (p *Process) GetUptime() uint64 {
 	return uint64(time.Since(p.startTime).Seconds())
 	return uint64(time.Since(p.startTime).Seconds())
 }
 }
 
 
+// refreshAPIPort updates the API port from the inbound configs.
 func (p *process) refreshAPIPort() {
 func (p *process) refreshAPIPort() {
 	for _, inbound := range p.config.InboundConfigs {
 	for _, inbound := range p.config.InboundConfigs {
 		if inbound.Tag == "api" {
 		if inbound.Tag == "api" {
@@ -173,6 +198,7 @@ func (p *process) refreshAPIPort() {
 	}
 	}
 }
 }
 
 
+// refreshVersion updates the version string by running the Xray binary with -version.
 func (p *process) refreshVersion() {
 func (p *process) refreshVersion() {
 	cmd := exec.Command(GetBinaryPath(), "-version")
 	cmd := exec.Command(GetBinaryPath(), "-version")
 	data, err := cmd.Output()
 	data, err := cmd.Output()
@@ -188,6 +214,7 @@ func (p *process) refreshVersion() {
 	}
 	}
 }
 }
 
 
+// Start launches the Xray process with the current configuration.
 func (p *process) Start() (err error) {
 func (p *process) Start() (err error) {
 	if p.IsRunning() {
 	if p.IsRunning() {
 		return errors.New("xray is already running")
 		return errors.New("xray is already running")
@@ -245,6 +272,7 @@ func (p *process) Start() (err error) {
 	return nil
 	return nil
 }
 }
 
 
+// Stop terminates the running Xray process.
 func (p *process) Stop() error {
 func (p *process) Stop() error {
 	if !p.IsRunning() {
 	if !p.IsRunning() {
 		return errors.New("xray is not running")
 		return errors.New("xray is not running")
@@ -257,6 +285,7 @@ func (p *process) Stop() error {
 	}
 	}
 }
 }
 
 
+// writeCrashReport writes a crash report to the binary folder with a timestamped filename.
 func writeCrashReport(m []byte) error {
 func writeCrashReport(m []byte) error {
 	crashReportPath := config.GetBinFolderPath() + "/core_crash_" + time.Now().Format("20060102_150405") + ".log"
 	crashReportPath := config.GetBinFolderPath() + "/core_crash_" + time.Now().Format("20060102_150405") + ".log"
 	return os.WriteFile(crashReportPath, m, os.ModePerm)
 	return os.WriteFile(crashReportPath, m, os.ModePerm)

+ 2 - 0
xray/traffic.go

@@ -1,5 +1,7 @@
 package xray
 package xray
 
 
+// Traffic represents network traffic statistics for Xray connections.
+// It tracks upload and download bytes for inbound or outbound traffic.
 type Traffic struct {
 type Traffic struct {
 	IsInbound  bool
 	IsInbound  bool
 	IsOutbound bool
 	IsOutbound bool