9bb7144593
Approving / manually binding / revoking KOL subscriptions belonged to the operations console, not the tenant-admin role on tenant-api. Add a fresh KolSubscriptionService + repository + handlers under the ops module with its own list/manual-bind/approve/revoke routes, wire a Redis-backed cache into ops-api so admin actions can invalidate tenant prompt caches, and delete the tenant-side admin service/handler now that ops-web owns the UI. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
120 lines
3.5 KiB
Go
120 lines
3.5 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"`
|
|
Redis sharedconfig.RedisConfig `mapstructure:"redis"`
|
|
Cache sharedconfig.CacheConfig `mapstructure:"cache"`
|
|
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("redis.addr", "localhost:6379")
|
|
v.SetDefault("redis.db", 0)
|
|
v.SetDefault("cache.driver", "redis")
|
|
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
|
|
}
|