Files
geo/server/internal/ops/config/config.go
T
root 9760bec8bd feat(ops/site-mappings): wire site domain mapping routes and monitoring DB
Register site-domain-mappings CRUD endpoints under the authenticated ops
router, add a monitoring_database config block (falling back to the main
ops database when unset) for the service to share the monitoring pool.
2026-04-29 16:02:11 +08:00

115 lines
3.2 KiB
Go

package config
import (
"fmt"
"os"
"strings"
"time"
"github.com/spf13/viper"
sharedconfig "github.com/geo-platform/tenant-api/internal/shared/config"
)
type Config struct {
Server sharedconfig.ServerConfig `mapstructure:"server"`
Database sharedconfig.DatabaseConfig `mapstructure:"database"`
MonitoringDatabase sharedconfig.DatabaseConfig `mapstructure:"monitoring_database"`
Log sharedconfig.LogConfig `mapstructure:"log"`
JWT JWTConfig `mapstructure:"jwt"`
DefaultAdmin DefaultAdminConfig `mapstructure:"default_admin"`
AdminUsers AdminUsersConfig `mapstructure:"admin_users"`
IPRegion IPRegionConfig `mapstructure:"ip_region"`
}
type JWTConfig struct {
Secret string `mapstructure:"secret"`
AccessTTL time.Duration `mapstructure:"access_ttl"`
}
type DefaultAdminConfig struct {
Username string `mapstructure:"username"`
Password string `mapstructure:"password"`
DisplayName string `mapstructure:"display_name"`
Email string `mapstructure:"email"`
}
type AdminUsersConfig struct {
DefaultPlanCode string `mapstructure:"default_plan_code"`
}
type IPRegionConfig struct {
V4XDBPath string `mapstructure:"v4_xdb_path"`
V6XDBPath string `mapstructure:"v6_xdb_path"`
}
func Load(path string) (*Config, error) {
v := viper.New()
v.SetConfigFile(path)
v.SetEnvPrefix("OPS")
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
v.AutomaticEnv()
v.SetDefault("server.port", 8090)
v.SetDefault("server.mode", "debug")
v.SetDefault("log.level", "info")
v.SetDefault("log.format", "json")
v.SetDefault("jwt.access_ttl", 8*time.Hour)
v.SetDefault("default_admin.username", "admin")
v.SetDefault("default_admin.display_name", "Administrator")
v.SetDefault("admin_users.default_plan_code", "free")
v.SetDefault("ip_region.v4_xdb_path", "")
v.SetDefault("ip_region.v6_xdb_path", "")
if err := v.ReadInConfig(); err != nil {
return nil, fmt.Errorf("read config: %w", err)
}
var cfg Config
if err := v.Unmarshal(&cfg); err != nil {
return nil, fmt.Errorf("unmarshal config: %w", err)
}
if err := applyEnvOverrides(&cfg); err != nil {
return nil, err
}
if cfg.JWT.Secret == "" {
return nil, fmt.Errorf("jwt.secret is required (set jwt.secret in yaml or OPS_JWT_SECRET env)")
}
if cfg.MonitoringDatabase.DBName == "" {
cfg.MonitoringDatabase = cfg.Database
}
return &cfg, nil
}
func applyEnvOverrides(cfg *Config) error {
if v := os.Getenv("OPS_JWT_SECRET"); v != "" {
cfg.JWT.Secret = v
}
if v := os.Getenv("OPS_DEFAULT_ADMIN_USERNAME"); v != "" {
cfg.DefaultAdmin.Username = v
}
if v := os.Getenv("OPS_DEFAULT_ADMIN_PASSWORD"); v != "" {
cfg.DefaultAdmin.Password = v
}
if v := os.Getenv("OPS_DEFAULT_ADMIN_DISPLAY_NAME"); v != "" {
cfg.DefaultAdmin.DisplayName = v
}
if v := os.Getenv("OPS_DEFAULT_ADMIN_EMAIL"); v != "" {
cfg.DefaultAdmin.Email = v
}
if v := os.Getenv("OPS_ADMIN_USERS_DEFAULT_PLAN_CODE"); v != "" {
cfg.AdminUsers.DefaultPlanCode = v
}
if v := os.Getenv("OPS_IP_REGION_V4_XDB_PATH"); v != "" {
cfg.IPRegion.V4XDBPath = v
}
if v := os.Getenv("OPS_IP_REGION_V6_XDB_PATH"); v != "" {
cfg.IPRegion.V6XDBPath = v
}
return nil
}