Skip to main content

backbone_bucket/config/
app_config.rs

1//! Application configuration
2//!
3//! Loads configuration from YAML files and environment variables.
4
5use serde::Deserialize;
6use std::path::Path;
7
8/// Module configuration
9#[derive(Debug, Clone, Deserialize)]
10pub struct ModuleConfig {
11    pub server: ServerConfig,
12    pub database: DatabaseConfig,
13    pub module: ModuleSettings,
14    #[serde(default)]
15    pub features: FeatureFlags,
16    #[serde(default)]
17    pub logging: LoggingConfig,
18}
19
20#[derive(Debug, Clone, Deserialize)]
21pub struct ServerConfig {
22    pub host: String,
23    pub port: u16,
24    #[serde(default = "default_grpc_port")]
25    pub grpc_port: u16,
26}
27
28fn default_grpc_port() -> u16 {
29    50051
30}
31
32#[derive(Debug, Clone, Deserialize)]
33pub struct DatabaseConfig {
34    pub url: String,
35    #[serde(default = "default_max_connections")]
36    pub max_connections: u32,
37    #[serde(default = "default_min_connections")]
38    pub min_connections: u32,
39    #[serde(default = "default_connect_timeout")]
40    pub connect_timeout: u64,
41    #[serde(default = "default_idle_timeout")]
42    pub idle_timeout: u64,
43}
44
45fn default_max_connections() -> u32 {
46    20
47}
48fn default_min_connections() -> u32 {
49    5
50}
51fn default_connect_timeout() -> u64 {
52    30
53}
54fn default_idle_timeout() -> u64 {
55    600
56}
57
58#[derive(Debug, Clone, Deserialize)]
59pub struct ModuleSettings {
60    pub name: String,
61    #[serde(default = "default_enabled")]
62    pub enabled: bool,
63}
64
65fn default_enabled() -> bool {
66    true
67}
68
69#[derive(Debug, Clone, Deserialize, Default)]
70pub struct FeatureFlags {
71    #[serde(default)]
72    pub soft_delete: bool,
73    #[serde(default)]
74    pub state_machines: bool,
75    #[serde(default)]
76    pub workflows: bool,
77}
78
79#[derive(Debug, Clone, Deserialize)]
80pub struct LoggingConfig {
81    #[serde(default = "default_log_level")]
82    pub level: String,
83    #[serde(default = "default_log_format")]
84    pub format: String,
85}
86
87fn default_log_level() -> String {
88    "info".to_string()
89}
90fn default_log_format() -> String {
91    "json".to_string()
92}
93
94impl Default for LoggingConfig {
95    fn default() -> Self {
96        Self {
97            level: default_log_level(),
98            format: default_log_format(),
99        }
100    }
101}
102
103impl ModuleConfig {
104    /// Load configuration from YAML file
105    pub fn from_file<P: AsRef<Path>>(path: P) -> anyhow::Result<Self> {
106        let content = std::fs::read_to_string(path)?;
107        let config: ModuleConfig = serde_yaml::from_str(&content)?;
108        Ok(config)
109    }
110
111    /// Load configuration with environment-specific overrides
112    pub fn load(env: Option<&str>) -> anyhow::Result<Self> {
113        let base_path = "config/application.yml";
114        let mut config = Self::from_file(base_path)?;
115
116        if let Some(environment) = env {
117            let env_path = format!("config/application-{}.yml", environment);
118            if Path::new(&env_path).exists() {
119                let env_content = std::fs::read_to_string(&env_path)?;
120                let env_config: serde_yaml::Value = serde_yaml::from_str(&env_content)?;
121                // Merge env config into base config
122                // For now, just reload - proper merge would be more complex
123                if let Ok(merged) = serde_yaml::from_value(env_config) {
124                    config = merged;
125                }
126            }
127        }
128
129        Ok(config)
130    }
131}