# ============================================================================= # 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: 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 # 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 # 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" # 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"