refactor: Flatten directory structure

Move project files from uzdb/ subdirectory to root directory for cleaner project structure.

Changes:
- Move frontend/ to root
- Move internal/ to root
- Move build/ to root
- Move all config files (go.mod, wails.json, etc.) to root
- Remove redundant uzdb/ subdirectory nesting

Project structure is now:
├── frontend/        # React application
├── internal/        # Go backend
├── build/           # Wails build assets
├── doc/             # Design documentation
├── main.go          # Entry point
└── ...

🤖 Generated with Qoder
This commit is contained in:
loveuer
2026-04-04 07:14:00 -07:00
parent 5a83e86bc9
commit 9874561410
83 changed files with 0 additions and 46 deletions

261
internal/config/config.go Normal file
View File

@@ -0,0 +1,261 @@
package config
import (
"encoding/json"
"os"
"path/filepath"
"sync"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
// Environment represents the application environment type
type Environment string
const (
// EnvDevelopment represents development environment
EnvDevelopment Environment = "development"
// EnvProduction represents production environment
EnvProduction Environment = "production"
)
// Config holds all configuration for the application
type Config struct {
// App settings
AppName string `json:"app_name"`
Version string `json:"version"`
Environment Environment `json:"environment"`
// Database settings (SQLite for app data)
Database DatabaseConfig `json:"database"`
// Encryption settings
Encryption EncryptionConfig `json:"encryption"`
// Logger settings
Logger LoggerConfig `json:"logger"`
// API settings (for debug HTTP server)
API APIConfig `json:"api"`
// File paths
DataDir string `json:"-"`
}
// DatabaseConfig holds database configuration
type DatabaseConfig struct {
// SQLite database file path for app data
SQLitePath string `json:"sqlite_path"`
// Max open connections
MaxOpenConns int `json:"max_open_conns"`
// Max idle connections
MaxIdleConns int `json:"max_idle_conns"`
// Connection max lifetime in minutes
MaxLifetime int `json:"max_lifetime"`
}
// EncryptionConfig holds encryption configuration
type EncryptionConfig struct {
// Key for encrypting sensitive data (passwords, etc.)
// In production, this should be loaded from secure storage
Key string `json:"-"`
// KeyFile path to load encryption key from
KeyFile string `json:"key_file"`
}
// LoggerConfig holds logger configuration
type LoggerConfig struct {
// Log level: debug, info, warn, error
Level string `json:"level"`
// Log format: json, console
Format string `json:"format"`
// Output file path (empty for stdout)
OutputPath string `json:"output_path"`
}
// APIConfig holds HTTP API configuration
type APIConfig struct {
// Enable HTTP API server (for debugging)
Enabled bool `json:"enabled"`
// Port for HTTP API server
Port string `json:"port"`
}
var (
instance *Config
once sync.Once
logger *zap.Logger
)
// Get returns the singleton config instance
func Get() *Config {
return instance
}
// GetLogger returns the zap logger
func GetLogger() *zap.Logger {
return logger
}
// Init initializes the configuration
// If config file doesn't exist, creates default config
func Init(dataDir string) (*Config, error) {
var err error
once.Do(func() {
instance = &Config{
DataDir: dataDir,
}
err = instance.load(dataDir)
})
return instance, err
}
// load loads configuration from file or creates default
func (c *Config) load(dataDir string) error {
configPath := filepath.Join(dataDir, "config.json")
// Try to load existing config
if _, err := os.Stat(configPath); err == nil {
data, err := os.ReadFile(configPath)
if err != nil {
return err
}
if err := json.Unmarshal(data, c); err != nil {
return err
}
} else {
// Create default config
c.setDefaults()
if err := c.save(configPath); err != nil {
return err
}
}
// Override with environment variables
c.loadEnv()
// Initialize logger
if err := c.initLogger(); err != nil {
return err
}
logger.Info("configuration loaded",
zap.String("environment", string(c.Environment)),
zap.String("data_dir", c.DataDir),
)
return nil
}
// setDefaults sets default configuration values
func (c *Config) setDefaults() {
c.AppName = "uzdb"
c.Version = "1.0.0"
c.Environment = EnvDevelopment
c.Database = DatabaseConfig{
SQLitePath: filepath.Join(c.DataDir, "uzdb.db"),
MaxOpenConns: 25,
MaxIdleConns: 5,
MaxLifetime: 5,
}
c.Encryption = EncryptionConfig{
Key: "", // Will be generated if empty
KeyFile: filepath.Join(c.DataDir, "encryption.key"),
}
c.Logger = LoggerConfig{
Level: "debug",
Format: "console",
OutputPath: "",
}
c.API = APIConfig{
Enabled: true,
Port: "8080",
}
}
// loadEnv loads configuration from environment variables
func (c *Config) loadEnv() {
if env := os.Getenv("UZDB_ENV"); env != "" {
c.Environment = Environment(env)
}
if port := os.Getenv("UZDB_API_PORT"); port != "" {
c.API.Port = port
}
if logLevel := os.Getenv("UZDB_LOG_LEVEL"); logLevel != "" {
c.Logger.Level = logLevel
}
if dbPath := os.Getenv("UZDB_DB_PATH"); dbPath != "" {
c.Database.SQLitePath = dbPath
}
}
// save saves configuration to file
func (c *Config) save(path string) error {
data, err := json.MarshalIndent(c, "", " ")
if err != nil {
return err
}
return os.WriteFile(path, data, 0600)
}
// initLogger initializes the zap logger
func (c *Config) initLogger() error {
var cfg zap.Config
switch c.Logger.Format {
case "json":
cfg = zap.NewProductionConfig()
default:
cfg = zap.NewDevelopmentConfig()
}
// Set log level
level, parseErr := zapcore.ParseLevel(c.Logger.Level)
if parseErr != nil {
level = zapcore.InfoLevel
}
cfg.Level.SetLevel(level)
// Configure output
if c.Logger.OutputPath != "" {
cfg.OutputPaths = []string{c.Logger.OutputPath}
cfg.ErrorOutputPaths = []string{c.Logger.OutputPath}
}
var buildErr error
logger, buildErr = cfg.Build(
zap.AddCaller(),
zap.AddStacktrace(zapcore.ErrorLevel),
)
if buildErr != nil {
return buildErr
}
return nil
}
// IsDevelopment returns true if running in development mode
func (c *Config) IsDevelopment() bool {
return c.Environment == EnvDevelopment
}
// IsProduction returns true if running in production mode
func (c *Config) IsProduction() bool {
return c.Environment == EnvProduction
}
// Sync flushes any buffered log entries
func Sync() error {
if logger != nil {
return logger.Sync()
}
return nil
}