# Configuration System ## Design Philosophy BEDS configuration follows two rules: 1. **The base file is always safe to commit.** It contains structure and production-safe defaults. No real passwords, no real hostnames. It is the documentation of what the config looks like. 2. **The env file is never committed.** It contains the real values for a specific environment. It lives on the server and is gitignored. If the env file is lost, you rebuild it — you never recover it from git history. This is the same pattern used in the PHP Namaste framework from day one. The `namaste.xml` base file was committed. The `env.xml` override was not. The habit was intentional: committing credentials to source control, even a private repo, is a category of mistake that ends careers. ## File Locations ``` config/ ├── beds.toml ← committed — base config, safe defaults ├── env_dev.toml ← gitignored — development overrides ├── env_qa.toml ← gitignored — QA / staging overrides └── env_prod.toml ← gitignored — production overrides ``` ## Environment Selection The `BEDS_ENV` environment variable selects which override file to load: ```bash BEDS_ENV=dev cargo run # loads env_dev.toml (default if unset) BEDS_ENV=qa ./rustybeds # loads env_qa.toml BEDS_ENV=prod ./rustybeds # loads env_prod.toml ``` If `BEDS_ENV` is unset, `dev` is assumed. This means a freshly cloned repo with no env file runs in dev mode — which is the correct safe default. ## How Layering Works The `config` crate performs a deep merge. Only keys present in the env file override the base. Everything else inherits from `beds.toml`. Example — overriding only the broker password and env name: ```toml # env_dev.toml — only what differs from beds.toml [id] env_name = "development" [broker_services.app_server] pass = "my-dev-rabbitmq-password" ``` Every other value — host, port, vhost, instance counts — is inherited from `beds.toml`. You do not need to repeat the full config in the env file. ## Configuration Sections ### Root Flags ```toml debug = false # debug-level log output syslog = true # route logs to journald syslog_mirror_console = true # also echo to console when syslog=true audit_on = false # global auditing master switch journal_on = false # global journaling master switch ``` ### `[id]` — Node Identity ```toml [id] env_name = "production" # development | qa | production version = "1.0" # match your git release tag wbid = "ms" # 2-char corporate identifier — prefixed to all collection names ``` The `wbid` is permanent. Once your MongoDB collections are created with a given `wbid`, changing it means renaming every collection and updating every template. Choose carefully. ### `[broker_services]` — RabbitMQ ```toml [broker_services] queue_tag = "prod_" # prefixed to every queue name — isolates envs vhost = "prod" # RabbitMQ virtual host timer_violation = 3000 # ms before a broker round-trip is a slow query warning records_per_xfer = 5000 # max records per broker response — circuit breaker keepalive = true # TCP keepalive — always true in production heartbeat = 60 # AMQP heartbeat interval in seconds use_ssl = false # TLS for broker connections cert_path = "/etc/rabbitmq" ``` Per-node broker config: ```toml [broker_services.app_server] host = "localhost" port = 5672 api_port = 15672 # management UI user = "beds" pass = "changeme" rpi = 50 # records per interval — broker fetch throttle [broker_services.app_server.instances] r_broker = 2 # read brokers w_broker = 2 # write brokers m_broker = 0 # migration brokers (0 = disabled) ``` ### `[rec_services]` — MongoDB One entry per BEDS service role that needs MongoDB. Key is the service name (`app_server`, `admin`, `segundo`, `tercero`): ```toml [rec_services.app_server] host = "localhost" port = 27017 user = "beds" pass = "changeme" database = "beds_app" use_ssl = false ``` See `beds.toml` for topology examples (standalone, replica set, sharded cluster). ### `[rel_services]` — MariaDB One entry per service role, with master (required) and secondary (optional): ```toml [rel_services.app_server.master] host = "localhost" port = 3306 user = "beds" pass = "changeme" database = "beds_app" [rel_services.app_server.secondary] # optional read replica host = "replica.internal" port = 3306 user = "beds_readonly" pass = "changeme" database = "beds_app" ``` Secondary failure is always non-fatal — BEDS logs a warning and operates master-only. ## The Test Fixture All tests load from `tests/fixtures/beds_test.toml` instead of the live config. This file is committed — it contains only localhost addresses and placeholder credentials. Tests never read `config/beds.toml`. The fixture is loaded via `config::load_from()`: ```rust // in unit tests (inside source files) fn test_cfg() -> BedsConfig { load_from("tests/fixtures/beds_test.toml", "") .expect("test fixture failed to load") } // in integration tests (under tests/) let cfg = common::load_test_config(); ``` If a test needs a different value, mutate the loaded struct — do not create a separate fixture file for every test variation. The fixture is the baseline; tests modify what they need. ## Adding a New Config Section 1. Add the TOML section to `beds.toml` with safe defaults and full commentary 2. Add the same section to `tests/fixtures/beds_test.toml` with test-safe values 3. Add the corresponding struct(s) to `src/config/structs.rs` 4. Export the new type from `src/config/mod.rs` 5. Add the field to `BedsConfig` 6. Update this wiki page