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:
355
config/beds.toml
355
config/beds.toml
@@ -1,41 +1,376 @@
|
||||
# =============================================================================
|
||||
# beds.toml — BEDS Base Configuration
|
||||
# =============================================================================
|
||||
#
|
||||
# This is the base configuration file for a BEDS node. It contains
|
||||
# production-safe defaults and is checked into source control. Sensitive
|
||||
# values (passwords, hostnames) live in the env override file (env_dev.toml,
|
||||
# env_qa.toml, env_prod.toml) which is NEVER committed.
|
||||
#
|
||||
# HOW LAYERING WORKS:
|
||||
# -------------------
|
||||
# BEDS loads this file first, then deep-merges the env override on top.
|
||||
# Only keys present in the env file are overridden — everything else
|
||||
# inherits from here. This means you can override a single password without
|
||||
# duplicating the entire config.
|
||||
#
|
||||
# Set the BEDS_ENV environment variable to select the override file:
|
||||
# BEDS_ENV=dev → loads config/env_dev.toml (default if unset)
|
||||
# BEDS_ENV=qa → loads config/env_qa.toml
|
||||
# BEDS_ENV=prod → loads config/env_prod.toml
|
||||
#
|
||||
# AUTHOR: mks
|
||||
# VERSION: 1.0
|
||||
#
|
||||
# HISTORY:
|
||||
# ========
|
||||
# 2026-04-02 mks original coding
|
||||
# 2026-04-04 mks added rel_services and rec_services sections
|
||||
# added topology commentary blocks
|
||||
# =============================================================================
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# ROOT FLAGS
|
||||
# =============================================================================
|
||||
|
||||
# debug: enables debug-level log output. Never true in production — the volume
|
||||
# of output will bury real events. Your dev env file should set this to true.
|
||||
debug = false
|
||||
|
||||
# syslog: routes log output to journald (systemd journal) instead of stdout.
|
||||
# Set true in production so logs survive process restarts and are queryable
|
||||
# with journalctl. Your dev env file will typically set this to false.
|
||||
syslog = true
|
||||
|
||||
# syslog_mirror_console: when syslog is true, also echo log output to the
|
||||
# console. Useful during staging when you want both. In production on a
|
||||
# headless server, set to false to avoid redundant output.
|
||||
syslog_mirror_console = true
|
||||
|
||||
# audit_on: master switch for the auditing micro-service. When true, BEDS
|
||||
# records an audit trail for every declared auditable operation. The template
|
||||
# controls what is audited — this flag is the global override. Set false
|
||||
# during development to reduce noise.
|
||||
audit_on = false
|
||||
|
||||
# journal_on: master switch for the journaling micro-service. When true, BEDS
|
||||
# records a journal entry for every destructive operation (create, update,
|
||||
# delete) on collections that declare journaling=true. Set false during
|
||||
# development to reduce noise.
|
||||
journal_on = false
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# NODE IDENTITY
|
||||
# =============================================================================
|
||||
|
||||
[id]
|
||||
|
||||
# env_name: the name of this environment. Used in log output, routing keys,
|
||||
# and the env-aware IPL error handling (non-fatal failures in non-production
|
||||
# environments). Must be one of: development | qa | production
|
||||
env_name = "production"
|
||||
version = "1.0"
|
||||
|
||||
# version: the BEDS framework version running on this node. Used in the node
|
||||
# self-identification record and log output. Match this to your git tag.
|
||||
version = "1.0"
|
||||
|
||||
# wbid: your 2-character corporate identifier. Prepended to every MongoDB
|
||||
# collection name to namespace your data. Example: wbid "ms" + collection
|
||||
# "Users" = "msUsers". Choose something meaningful and keep it consistent
|
||||
# across all nodes in your cluster.
|
||||
wbid = "ms"
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# RABBITMQ BROKER SERVICES
|
||||
# =============================================================================
|
||||
#
|
||||
# BEDS is AMQP-first. Every data operation flows through RabbitMQ. No
|
||||
# component in the application layer touches a database directly — ever.
|
||||
# The broker layer is the heart of the framework.
|
||||
#
|
||||
# TOPOLOGY NOTE:
|
||||
# --------------
|
||||
# In a homelab or single-server setup, all nodes share one RabbitMQ instance.
|
||||
# In production, you typically run RabbitMQ in a cluster. BEDS connects to
|
||||
# a single broker endpoint per node role — if you're running a RabbitMQ
|
||||
# cluster, point this at your load balancer or a HAProxy frontend, not
|
||||
# directly at a cluster node.
|
||||
#
|
||||
# VHOST CONVENTION:
|
||||
# -----------------
|
||||
# Use a separate vhost per environment to keep traffic isolated:
|
||||
# prod_ / prod → production
|
||||
# qa_ / qa → QA / staging
|
||||
# dev_ / dev → development
|
||||
#
|
||||
# The queue_tag prefix is prepended to every queue name so queues from
|
||||
# different environments can coexist on the same broker without collision.
|
||||
# =============================================================================
|
||||
|
||||
[broker_services]
|
||||
|
||||
# queue_tag: prefix applied to every queue name. Keeps envs isolated on a
|
||||
# shared broker. Example: "prod_rec.read", "dev_rec.read"
|
||||
queue_tag = "prod_"
|
||||
|
||||
# vhost: the RabbitMQ virtual host for this environment. Create one vhost
|
||||
# per env in the RabbitMQ management UI and grant your BEDS user access.
|
||||
vhost = "prod"
|
||||
|
||||
# timer_violation: milliseconds before a broker round-trip is flagged as
|
||||
# a slow operation. Violations are logged as warnings. Tune to your
|
||||
# expected p95 latency. 3000ms is conservative for production.
|
||||
timer_violation = 3000
|
||||
|
||||
# records_per_xfer: maximum records returned in a single broker response.
|
||||
# Acts as a circuit breaker against runaway fetch queries. Override per
|
||||
# collection in the template if you need larger transfers (e.g. migrations).
|
||||
records_per_xfer = 5000
|
||||
|
||||
# keepalive: enables TCP keepalive on broker connections. Always true in
|
||||
# production — brokers behind a firewall or NAT will drop idle connections
|
||||
# without this.
|
||||
keepalive = true
|
||||
|
||||
# heartbeat: AMQP heartbeat interval in seconds. RabbitMQ will close a
|
||||
# connection that misses two consecutive heartbeats. 60 seconds is the
|
||||
# recommended default. Do not set below 30.
|
||||
heartbeat = 60
|
||||
|
||||
# use_ssl: enables TLS for broker connections. Set true in production if
|
||||
# your RabbitMQ instance is not on localhost or a trusted private network.
|
||||
use_ssl = false
|
||||
|
||||
# cert_path: path to TLS certificates when use_ssl = true. Ignored when
|
||||
# use_ssl = false. Do not change this path unless you have a specific reason.
|
||||
cert_path = "/etc/rabbitmq"
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Broker node: app_server
|
||||
# -----------------------------------------------------------------------------
|
||||
# This is the primary application broker — the one your appServer node
|
||||
# connects to for all client-facing CRUD operations.
|
||||
#
|
||||
# SINGLE BROKER INSTANCE (homelab / development):
|
||||
# host = "localhost"
|
||||
# port = 5672
|
||||
#
|
||||
# REMOTE BROKER (separate server):
|
||||
# host = "192.168.1.50" # or DNS name: rmq.internal
|
||||
# port = 5672
|
||||
#
|
||||
# RABBITMQ CLUSTER (point at HAProxy or load balancer — NOT a cluster node):
|
||||
# host = "rmq-lb.internal"
|
||||
# port = 5672
|
||||
#
|
||||
# rpi: Records Per Interval — throttle applied to this broker's fetch rate.
|
||||
# Prevents a single broker from overwhelming the database. 50 is a
|
||||
# conservative default; tune upward once you have baseline metrics.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
[broker_services.app_server]
|
||||
host = "localhost"
|
||||
port = 5672
|
||||
api_port = 15672
|
||||
user = "beds"
|
||||
pass = "changeme"
|
||||
rpi = 50
|
||||
host = "localhost"
|
||||
port = 5672
|
||||
api_port = 15672 # RabbitMQ management UI port — used for health checks
|
||||
user = "beds"
|
||||
pass = "changeme" # override in your env file — never commit real passwords
|
||||
rpi = 50
|
||||
|
||||
# Instance counts control how many concurrent broker tasks BEDS spawns per
|
||||
# role. Scale these up as your throughput grows. A good starting point is
|
||||
# 2 read brokers for every 1 write broker, since reads typically outnumber
|
||||
# writes by a wide margin.
|
||||
#
|
||||
# r_broker: read brokers — handle all non-destructive fetch queries
|
||||
# w_broker: write brokers — handle all create / update / delete operations
|
||||
# m_broker: migration brokers — handle bulk data migration events (0 = disabled)
|
||||
|
||||
[broker_services.app_server.instances]
|
||||
r_broker = 2
|
||||
w_broker = 2
|
||||
m_broker = 0
|
||||
m_broker = 0 # enable only during active data migrations
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# MONGODB (REC) SERVICES
|
||||
# =============================================================================
|
||||
#
|
||||
# REC (Record) collections live in MongoDB. BEDS uses MongoDB for document
|
||||
# storage — schema-flexible, high-throughput, append-friendly collections
|
||||
# like logs, events, user profiles, and audit records.
|
||||
#
|
||||
# One rec_services entry per BEDS node role that needs MongoDB access.
|
||||
# In a single-node homelab setup you'll have one entry. In a distributed
|
||||
# cluster you'll have one per service (app_server, admin, segundo, tercero)
|
||||
# pointing at different databases or even different MongoDB instances.
|
||||
#
|
||||
# TOPOLOGY OPTIONS:
|
||||
# -----------------
|
||||
#
|
||||
# 1. STANDALONE (homelab / development) — simplest setup, single mongod:
|
||||
#
|
||||
# [rec_services.app_server]
|
||||
# host = "localhost"
|
||||
# port = 27017
|
||||
# user = "beds"
|
||||
# pass = "yourpassword"
|
||||
# database = "beds_app"
|
||||
# use_ssl = false
|
||||
#
|
||||
# 2. REMOTE STANDALONE (mongod on a separate server):
|
||||
#
|
||||
# [rec_services.app_server]
|
||||
# host = "192.168.1.60" # or mongohost.internal
|
||||
# port = 27017
|
||||
# user = "beds"
|
||||
# pass = "yourpassword"
|
||||
# database = "beds_app"
|
||||
# use_ssl = true # strongly recommended over a network
|
||||
#
|
||||
# 3. REPLICA SET — 3-node minimum, provides automatic failover.
|
||||
# Connect to the primary or use a connection string in the adapter.
|
||||
# Point BEDS at the primary for now; the full replica set URI is
|
||||
# handled at the adapter layer (not yet implemented):
|
||||
#
|
||||
# [rec_services.app_server]
|
||||
# host = "mongo-primary.internal"
|
||||
# port = 27017
|
||||
# user = "beds"
|
||||
# pass = "yourpassword"
|
||||
# database = "beds_app"
|
||||
# use_ssl = true
|
||||
#
|
||||
# 4. SHARDED CLUSTER — mongos router sits in front of the shards.
|
||||
# Connect BEDS to the mongos endpoint, not to individual shards.
|
||||
# The cluster topology is transparent to BEDS:
|
||||
#
|
||||
# [rec_services.app_server]
|
||||
# host = "mongos.internal" # the mongos router — NOT a shard node
|
||||
# port = 27019 # mongos default port is 27019
|
||||
# user = "beds"
|
||||
# pass = "yourpassword"
|
||||
# database = "beds_app"
|
||||
# use_ssl = true
|
||||
#
|
||||
# TIP: Want to run your admin node on a separate MongoDB database?
|
||||
# Just add a second entry:
|
||||
#
|
||||
# [rec_services.admin]
|
||||
# host = "localhost"
|
||||
# port = 27017
|
||||
# database = "beds_admin" # separate DB, same mongod
|
||||
# ...
|
||||
# =============================================================================
|
||||
|
||||
[rec_services.app_server]
|
||||
host = "localhost"
|
||||
port = 27017
|
||||
user = "beds"
|
||||
pass = "changeme"
|
||||
pass = "changeme" # override in your env file
|
||||
database = "beds_app"
|
||||
use_ssl = false
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# MARIADB (REL) SERVICES
|
||||
# =============================================================================
|
||||
#
|
||||
# REL (Relational) collections live in MariaDB. BEDS uses MariaDB for
|
||||
# structured relational data — anything that benefits from SQL joins,
|
||||
# transactions, or strict schema enforcement.
|
||||
#
|
||||
# Each rel_services entry has a master (required) and an optional secondary
|
||||
# (read replica). BEDS routes write operations to the master and can route
|
||||
# reads to the secondary to distribute load. Secondary failure is non-fatal
|
||||
# — BEDS logs a warning and continues with master-only operation.
|
||||
#
|
||||
# TOPOLOGY OPTIONS:
|
||||
# -----------------
|
||||
#
|
||||
# 1. STANDALONE (homelab / development) — single MariaDB instance.
|
||||
# Set master and omit secondary, or point secondary at the same host
|
||||
# to keep the config structure consistent:
|
||||
#
|
||||
# [rel_services.app_server.master]
|
||||
# host = "localhost"
|
||||
# port = 3306
|
||||
# user = "beds"
|
||||
# pass = "yourpassword"
|
||||
# database = "beds_app"
|
||||
#
|
||||
# # secondary is optional — comment out if you have only one instance
|
||||
# # [rel_services.app_server.secondary]
|
||||
# # host = "localhost"
|
||||
# # ...
|
||||
#
|
||||
# 2. PRIMARY + READ REPLICA — the most common production topology.
|
||||
# MariaDB replication is asynchronous; secondary reads may be slightly
|
||||
# behind primary writes. BEDS does not guarantee read-after-write
|
||||
# consistency when reads are routed to the secondary:
|
||||
#
|
||||
# [rel_services.app_server.master]
|
||||
# host = "db-primary.internal"
|
||||
# port = 3306
|
||||
# user = "beds"
|
||||
# pass = "yourpassword"
|
||||
# database = "beds_app"
|
||||
#
|
||||
# [rel_services.app_server.secondary]
|
||||
# host = "db-replica.internal" # read replica — receives binlog from master
|
||||
# port = 3306
|
||||
# user = "beds_readonly" # read-only user is good practice here
|
||||
# pass = "yourpassword"
|
||||
# database = "beds_app"
|
||||
#
|
||||
# 3. GALERA CLUSTER — multi-master synchronous replication.
|
||||
# All nodes accept writes. Point master at one node and secondary at
|
||||
# another, or use a ProxySQL / HAProxy frontend and point both at it:
|
||||
#
|
||||
# [rel_services.app_server.master]
|
||||
# host = "galera-node1.internal" # or proxysql.internal
|
||||
# port = 3306
|
||||
# user = "beds"
|
||||
# pass = "yourpassword"
|
||||
# database = "beds_app"
|
||||
#
|
||||
# [rel_services.app_server.secondary]
|
||||
# host = "galera-node2.internal"
|
||||
# port = 3306
|
||||
# user = "beds"
|
||||
# pass = "yourpassword"
|
||||
# database = "beds_app"
|
||||
#
|
||||
# 4. SEPARATE DATABASE PER NODE ROLE — mirrors the PHP production setup
|
||||
# where admin, segundo, and tercero each had their own database:
|
||||
#
|
||||
# [rel_services.app_server.master]
|
||||
# database = "beds_app"
|
||||
#
|
||||
# [rel_services.admin.master]
|
||||
# database = "beds_admin"
|
||||
#
|
||||
# [rel_services.segundo.master]
|
||||
# database = "beds_warehouse"
|
||||
#
|
||||
# TIP: In a homelab running everything on one box, all four entries can
|
||||
# point at localhost:3306 with different database names. MariaDB handles
|
||||
# the namespace separation — BEDS just needs a valid connection.
|
||||
# =============================================================================
|
||||
|
||||
[rel_services.app_server.master]
|
||||
host = "localhost"
|
||||
port = 3306
|
||||
user = "beds"
|
||||
pass = "changeme" # override in your env file
|
||||
database = "beds_app"
|
||||
|
||||
[rel_services.app_server.secondary]
|
||||
host = "localhost"
|
||||
port = 3306
|
||||
user = "beds"
|
||||
pass = "changeme" # override in your env file
|
||||
database = "beds_app"
|
||||
use_ssl = false
|
||||
Reference in New Issue
Block a user