57c29dc58f
- Removed YAML configuration files for the scraper and web commands, transitioning to an environment-based configuration system. - Updated configuration structs to utilize `env` tags for loading values from `.env` files, enhancing security and flexibility. - Implemented reflection-based parsing for environment variables, ensuring type-safe configuration loading. - Revised documentation to reflect the new configuration approach, including usage examples and best practices for environment variable naming conventions.
253 lines
7.1 KiB
Markdown
253 lines
7.1 KiB
Markdown
# Environment-Based Configuration System
|
|
|
|
This package provides a configuration system for the Tender Management backend that loads configuration exclusively from `.env` files. It maintains the same structure as the previous YAML-based system while using environment variables for all configuration values.
|
|
|
|
## Architecture
|
|
|
|
### Base Configuration (`BaseConfig`)
|
|
|
|
The configuration system provides common configuration structs that are used across all commands:
|
|
|
|
- **ServerConfig**: HTTP server configuration (host, port, timeouts)
|
|
- **DatabaseConfig**: MongoDB connection configuration
|
|
- **CacheConfig**: Redis connection configuration
|
|
- **LoggingConfig**: Logging system configuration
|
|
- **RateLimitConfig**: Rate limiting configuration
|
|
|
|
### Command-Specific Configuration
|
|
|
|
Each command can extend the base configuration by embedding the common configs and adding their own specific configuration fields.
|
|
|
|
## Usage
|
|
|
|
### 1. Create Command-Specific Config
|
|
|
|
Create a config file for your command (e.g., `cmd/yourcommand/config.go`):
|
|
|
|
```go
|
|
package main
|
|
|
|
import (
|
|
"time"
|
|
"tm/pkg/config"
|
|
)
|
|
|
|
// Config holds configuration for your command
|
|
type Config struct {
|
|
config.ServerConfig
|
|
config.DatabaseConfig
|
|
config.CacheConfig
|
|
config.LoggingConfig
|
|
YourSpecific YourSpecificConfig
|
|
}
|
|
|
|
type YourSpecificConfig struct {
|
|
SomeField string `env:"SOME_FIELD"`
|
|
SomeTimeout time.Duration `env:"SOME_TIMEOUT"`
|
|
SomeNumber int `env:"SOME_NUMBER"`
|
|
}
|
|
```
|
|
|
|
### 2. Load Configuration
|
|
|
|
In your command's `main.go` or bootstrap file:
|
|
|
|
```go
|
|
func initConfig() Config {
|
|
conf, err := config.LoadConfig(".", &Config{})
|
|
if err != nil {
|
|
panic(fmt.Sprintf("Failed to load config: %v", err))
|
|
}
|
|
|
|
return *conf
|
|
}
|
|
```
|
|
|
|
### 3. Create .env Configuration File
|
|
|
|
Create a `.env` file in your command directory:
|
|
|
|
```env
|
|
# Server Configuration
|
|
SERVER_HOST=localhost
|
|
SERVER_PORT=8080
|
|
SERVER_TIMEOUT=30s
|
|
SERVER_READ_TIMEOUT=10s
|
|
SERVER_WRITE_TIMEOUT=10s
|
|
|
|
# Database Configuration
|
|
MONGODB_URI=mongodb://localhost:27017
|
|
MONGODB_NAME=your_database
|
|
MONGODB_TIMEOUT=10s
|
|
MONGODB_MAX_POOL_SIZE=100
|
|
|
|
# Cache Configuration
|
|
REDIS_HOST=localhost
|
|
REDIS_PORT=6379
|
|
REDIS_PASSWORD=
|
|
REDIS_DB=0
|
|
REDIS_POOL_SIZE=10
|
|
|
|
# Logging Configuration
|
|
LOG_LEVEL=info
|
|
LOG_FORMAT=json
|
|
LOG_OUTPUT=stdout
|
|
LOG_FILE_PATH=/var/log/tm/your-command.log
|
|
LOG_FILE_MAX_SIZE=100
|
|
LOG_FILE_MAX_BACKUPS=5
|
|
LOG_FILE_MAX_AGE=30
|
|
LOG_FILE_COMPRESS=true
|
|
|
|
# Your command-specific configuration
|
|
SOME_FIELD=value
|
|
SOME_TIMEOUT=30s
|
|
SOME_NUMBER=42
|
|
```
|
|
|
|
## Examples
|
|
|
|
### Web Command Config
|
|
|
|
```go
|
|
type Config struct {
|
|
config.ServerConfig
|
|
config.DatabaseConfig
|
|
config.CacheConfig
|
|
config.LoggingConfig
|
|
config.RateLimitConfig
|
|
UserAuth AuthConfig
|
|
CustomerAuth AuthConfig
|
|
Assets AssetsConfig
|
|
}
|
|
|
|
type AuthConfig struct {
|
|
JWT JWTConfig
|
|
}
|
|
|
|
type JWTConfig struct {
|
|
AccessSecret string `env:"USER_AUTH_ACCESS_SECRET"`
|
|
RefreshSecret string `env:"USER_AUTH_REFRESH_SECRET"`
|
|
AccessExpiresIn int `env:"USER_AUTH_ACCESS_EXPIRES_IN"`
|
|
RefreshExpiresIn int `env:"USER_AUTH_REFRESH_EXPIRES_IN"`
|
|
}
|
|
|
|
type AssetsConfig struct {
|
|
FlagsPath string `env:"ASSETS_FLAGS_PATH"`
|
|
}
|
|
```
|
|
|
|
### Scraper Command Config
|
|
|
|
```go
|
|
type Config struct {
|
|
config.DatabaseConfig
|
|
config.LoggingConfig
|
|
TED ScraperConfig
|
|
}
|
|
|
|
type ScraperConfig struct {
|
|
BaseURL string `env:"TED_BASE_URL"`
|
|
Timeout time.Duration `env:"TED_TIMEOUT"`
|
|
MaxRetries int `env:"TED_MAX_RETRIES"`
|
|
RetryDelay time.Duration `env:"TED_RETRY_DELAY"`
|
|
UserAgent string `env:"TED_USER_AGENT"`
|
|
MaxConcurrency int `env:"TED_MAX_CONCURRENCY"`
|
|
DownloadDir string `env:"TED_DOWNLOAD_DIR"`
|
|
CleanupAfter time.Duration `env:"TED_CLEANUP_AFTER"`
|
|
ScrapingInterval time.Duration `env:"TED_SCRAPING_INTERVAL"`
|
|
}
|
|
```
|
|
|
|
## Features
|
|
|
|
### Type Safety
|
|
|
|
The configuration loader uses Go generics to provide type-safe configuration loading. The function signature ensures that you get back exactly the type you expect.
|
|
|
|
### Environment Variable Support
|
|
|
|
The configuration system loads all values from `.env` files using the `github.com/subosito/gotenv` library.
|
|
|
|
### Reflection-Based Parsing
|
|
|
|
The system uses reflection to automatically parse environment variables into struct fields based on the `env` tags.
|
|
|
|
### Supported Types
|
|
|
|
The configuration system supports the following Go types:
|
|
- `string`
|
|
- `int`, `int8`, `int16`, `int32`, `int64`
|
|
- `bool`
|
|
- `float32`, `float64`
|
|
- `time.Duration` (parsed from strings like "30s", "1h", "5m")
|
|
|
|
## Best Practices
|
|
|
|
1. **Use descriptive environment variable names**: Choose clear, descriptive names for your environment variables (e.g., `MONGODB_URI` instead of `DB_URI`).
|
|
|
|
2. **Use consistent naming conventions**: Use uppercase with underscores for environment variable names (e.g., `SERVER_HOST`, `LOG_LEVEL`).
|
|
|
|
3. **Group related variables**: Use prefixes to group related configuration (e.g., `MONGODB_*`, `REDIS_*`, `LOG_*`).
|
|
|
|
4. **Document your configuration**: Add comments in your `.env` files explaining what each variable does.
|
|
|
|
5. **Use appropriate types**: Use `time.Duration` for durations, proper numeric types for numbers, etc.
|
|
|
|
6. **Provide sensible defaults**: Consider providing sensible defaults in your code when environment variables are not set.
|
|
|
|
## Migration from YAML System
|
|
|
|
If you're migrating from the old YAML-based configuration system:
|
|
|
|
1. Remove `mapstructure` tags from your config structs
|
|
2. Add `env` tags to your config struct fields
|
|
3. Create `.env` files instead of `config.yaml` files
|
|
4. Update your `LoadConfig` calls to use the new system
|
|
5. Update function signatures to use the new config types
|
|
|
|
Example migration:
|
|
|
|
```go
|
|
// Old way (YAML)
|
|
type Config struct {
|
|
Server config.ServerConfig `mapstructure:"server"`
|
|
Database config.DatabaseConfig `mapstructure:"database"`
|
|
}
|
|
|
|
// New way (.env)
|
|
type Config struct {
|
|
Server config.ServerConfig
|
|
Database config.DatabaseConfig
|
|
}
|
|
|
|
// Old way (YAML loading)
|
|
conf, err := config.LoadConfig(".", &Config{})
|
|
|
|
// New way (.env loading)
|
|
conf, err := config.LoadConfig(".", &Config{})
|
|
```
|
|
|
|
## Environment Variable Naming Convention
|
|
|
|
The system follows these naming conventions:
|
|
|
|
- **Server**: `SERVER_*` (e.g., `SERVER_HOST`, `SERVER_PORT`)
|
|
- **Database**: `MONGODB_*` (e.g., `MONGODB_URI`, `MONGODB_NAME`)
|
|
- **Cache**: `REDIS_*` (e.g., `REDIS_HOST`, `REDIS_PORT`)
|
|
- **Logging**: `LOG_*` (e.g., `LOG_LEVEL`, `LOG_FORMAT`)
|
|
- **Rate Limiting**: `RATE_LIMIT_*` (e.g., `RATE_LIMIT_REQUESTS_PER_MINUTE`)
|
|
|
|
## Error Handling
|
|
|
|
The configuration system provides detailed error messages when:
|
|
- The `.env` file cannot be loaded
|
|
- Environment variables cannot be parsed into the expected types
|
|
- Required fields are missing (handled by your application logic)
|
|
|
|
## Security Considerations
|
|
|
|
1. **Never commit `.env` files**: Add `.env` to your `.gitignore` file
|
|
2. **Use environment-specific files**: Create different `.env` files for different environments (`.env.local`, `.env.production`, etc.)
|
|
3. **Validate sensitive values**: Always validate sensitive configuration values like API keys and database URIs
|
|
4. **Use secure defaults**: Provide secure default values for security-related configuration
|