Files
rustybeds/wiki/05-configuration.md
gramps 2a9afe7d77 Add MariaDB IPL validation, topology docs in beds.toml, and developer wiki
- Add MariaDB (REL) IPL validation — master required, secondary non-fatal
- Add RelNodeConfig / RelInstanceConfig structs with master/secondary pattern
- Add rel_services section to beds.toml and test fixture
- Add detailed topology commentary to beds.toml covering standalone,
  master/replica, Galera cluster, and multi-DB-per-node configurations
- Add developer wiki (wiki/) covering:
    - Origin story — PHP Namaste history, production record, why Rust
    - Architecture overview — full system diagram, all layers explained
    - The four nodes — appServer, admin, segundo, tercero with real-world context
    - IPL sequence — every step documented with rationale for ordering
    - Configuration system — layering, env selection, adding new sections
    - Queue topology — exchanges, routing keys, broker bindings, vhost isolation
    - Template system — REC/REL, TLA convention, cache map, warehousing
    - Event lineage — compound event IDs, parent/child tracking, msLogs schema
    - Glossary
- Update README with wiki index and MariaDB status

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 15:41:28 -07:00

5.8 KiB

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:

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:

# 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

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

[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

[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:

[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):

[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):

[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():

// 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