# Schema Configuration Fix for E2E Services **Date**: 2025-01-30 **Status**: ✅ Complete **Branch**: main ## Summary Fixed an issue where the `start-e2e-services.sh` script was ignoring the database schema configuration from custom config files and always defaulting to the `attune` schema. ## Problem When launching services with a custom config file: ```bash CONFIG_FILE=config.development.yaml ./scripts/start-e2e-services.sh ``` The services would ignore the `schema: "public"` setting in `config.development.yaml` and always use the `attune` schema instead. ### Root Cause The configuration loading system has the following priority order: 1. Base config file (e.g., `config.yaml` from `ATTUNE_CONFIG`) 2. Environment-specific config file (e.g., `config.{environment}.yaml`) 3. Environment variables (highest priority) The `start-e2e-services.sh` script was setting `ATTUNE__ENVIRONMENT=e2e`, which caused the config loader to look for and load `config.e2e.yaml` **after** loading the custom config file. Since environment-specific files have higher priority, any settings in `config.e2e.yaml` (including the default `schema: "attune"`) would override the custom config. ### Code Flow ```rust // In crates/common/src/config.rs::Config::load() // 1. Load base config (from ATTUNE_CONFIG) builder = builder.add_source(config_crate::File::with_name(&config_path)); // 2. Load environment-specific config (PROBLEM: this overrides step 1) let environment = std::env::var("ATTUNE__ENVIRONMENT").unwrap_or_else(...); let env_config_path = format!("config.{}.yaml", environment); builder = builder.add_source(config_crate::File::with_name(&env_config_path)); // 3. Load environment variables (highest priority) builder = builder.add_source(config_crate::Environment::with_prefix("ATTUNE")...); ``` When `ATTUNE__ENVIRONMENT=e2e` was set, it loaded `config.e2e.yaml` which contained `schema: "attune"`, overriding the `schema: "public"` from `config.development.yaml`. ## Solution Modified `scripts/start-e2e-services.sh` to only set `ATTUNE__ENVIRONMENT=e2e` when using the default E2E config file, allowing custom config files to determine their own environment: ```bash # Only set ATTUNE__ENVIRONMENT if using default e2e config # Otherwise, let the config file determine the environment if [ "$CONFIG_FILE" = "config.e2e.yaml" ]; then ATTUNE__ENVIRONMENT=e2e ATTUNE_CONFIG="$CONFIG_FILE" ./target/debug/$binary_name > "$log_file" 2>&1 & else ATTUNE_CONFIG="$CONFIG_FILE" ./target/debug/$binary_name > "$log_file" 2>&1 & fi ``` ## Changes Made ### Modified Files **`scripts/start-e2e-services.sh`**: 1. Added schema detection from config file to display in startup banner 2. Modified service startup to conditionally set `ATTUNE__ENVIRONMENT` only for default E2E config 3. Added configuration info display showing config file and detected schema ### Enhanced User Experience Added informative banner showing configuration being used: ``` Configuration: • Config file: config.development.yaml • Database schema: public ``` This helps users verify the correct configuration is loaded before services start. ## Verification ### Before Fix ```bash $ CONFIG_FILE=config.development.yaml ./scripts/start-e2e-services.sh # Services would show: INFO Using production schema: attune ``` ### After Fix ```bash $ CONFIG_FILE=config.development.yaml ./scripts/start-e2e-services.sh Configuration: • Config file: config.development.yaml • Database schema: public # Services now show: INFO Connecting to database with max_connections=50, schema=public ``` All services (api, executor, worker, sensor) correctly use the `public` schema. ## Usage ### Default E2E Environment ```bash # Uses config.e2e.yaml with attune schema (default) ./scripts/start-e2e-services.sh ``` ### Development Environment ```bash # Uses config.development.yaml with public schema CONFIG_FILE=config.development.yaml ./scripts/start-e2e-services.sh ``` ### Custom Configuration ```bash # Uses any custom config file with its specified schema CONFIG_FILE=my-custom-config.yaml ./scripts/start-e2e-services.sh ``` ## Related Files - `scripts/start-e2e-services.sh` - Service startup script (modified) - `crates/common/src/config.rs` - Configuration loading logic (reference) - `crates/common/src/db.rs` - Database connection with schema support (reference) - `config.development.yaml` - Development config with `schema: "public"` - `config.e2e.yaml` - E2E test config with default `schema: "attune"` ## Configuration Priority Reference For future reference, Attune's configuration loading priority is: 1. **Base config file** (lowest priority) - `config.yaml` or file specified by `ATTUNE_CONFIG` env var 2. **Environment-specific config file** - `config.{ATTUNE__ENVIRONMENT}.yaml` - Only loaded if `ATTUNE__ENVIRONMENT` is set or determined from base config 3. **Environment variables** (highest priority) - Prefix: `ATTUNE__` - Separator: `__` (double underscore) - Example: `ATTUNE__DATABASE__SCHEMA=public` ### Schema Configuration The database schema can be configured via: 1. Config file: `database.schema: "public"` 2. Environment variable: `ATTUNE__DATABASE__SCHEMA=public` 3. Default if not specified: `"attune"` ## Lessons Learned 1. **Environment variable overrides can be subtle**: Setting `ATTUNE__ENVIRONMENT` has cascading effects by triggering additional config file loads 2. **Configuration priority matters**: Higher priority sources always override lower priority ones 3. **Scripts should respect user intent**: When users provide custom config, don't override their choices 4. **Visibility helps debugging**: Showing the detected configuration at startup makes issues immediately visible ## Testing Tested with: - ✅ Default E2E config (uses `attune` schema) - ✅ Development config (uses `public` schema) - ✅ All services (api, executor, worker, sensor) respect the config - ✅ Schema detection and display in startup banner ## Impact **Positive**: - Users can now easily switch between development and E2E environments - Schema isolation works correctly for parallel testing - Configuration behavior is more intuitive and predictable **No Breaking Changes**: - Default behavior unchanged (E2E config still uses `attune` schema) - Existing scripts and workflows continue to work - Only affects behavior when custom `CONFIG_FILE` is provided ## Future Improvements Consider adding: 1. Validation warning if config file doesn't exist 2. Display full resolved configuration on startup (with sensitive values masked) 3. Config validation command: `attune config validate --file config.yaml` 4. Environment variable to completely disable environment-specific config loading