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:
2026-04-04 15:41:28 -07:00
parent 2ce87710ff
commit 2a9afe7d77
19 changed files with 1798 additions and 12 deletions

View File

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