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>
This commit is contained in:
170
wiki/05-configuration.md
Normal file
170
wiki/05-configuration.md
Normal file
@@ -0,0 +1,170 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user