- src/brokers/: pool manager, r_broker (rec.read), w_broker (rec.write), BrokerPayload struct, BrokerError type - src/core/: NamasteCore trait — fetch/write/update/delete interface, stubs - IPL step 6: spawns rBroker + wBroker pools after exchange declaration - tests/broker_pool_test.rs: integration tests for pool spawn (skip if broker down) - BrokerPayload unit tests + doctest in payload.rs - Added futures-lite, serde_json to Cargo.toml - README.md, CLAUDE.md, wiki updated to reflect new structure and status Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
9.2 KiB
CLAUDE.md — BEDS Rust Rewrite
This file provides guidance to Claude Code when working in this repository.
What This Project Is
BEDS (Back End Data System) is a Rust rewrite of a proven PHP microservice backend framework (codenamed Namaste). The PHP version ran 952 days in production without error, handled 40,000+ transactions per second on a single node, and demonstrated ~200ms round-trip latency from Baja California to West Virginia for destructive CRUD operations fanning out into dozens of concurrent DB calls.
This is not a greenfield project. The architecture is proven. The Rust rewrite exists to:
- Eliminate PHP memory leak workarounds (planned broker obsolescence via SIGCHLD)
- Dramatically increase throughput (5-10x expected)
- Enable single binary deployment with no runtime dependency
- Protect IP through compilation
- Add an AI-driven database object generation layer
Core Architecture Principles
Never violate these — they are the product:
- AMQP-first — all data access flows through RabbitMQ message brokers. No direct database connections from the application layer. Ever.
- Database agnostic — the framework supports MySQL/MariaDB and MongoDB through a unified trait/factory pattern. No database-specific logic leaks into the broker or factory layers.
- DBA-owned schema — developers never write queries. All data access goes through named database objects (views, stored procedures, functions). The application layer calls template names, not SQL.
- Template-driven CRUD — each data domain is a Rust struct implementing the
NamasteCoretrait. Adding a domain means adding a struct. Nothing else changes. - Single codebase, config-driven nodes — all service nodes run the same binary. Node role (appServer, admin, segundo, tercero) is determined entirely by startup configuration.
Project Structure
rustybeds/
├── src/
│ ├── brokers/
│ │ ├── mod.rs # Pool manager — spawn_r/w_broker_pool()
│ │ ├── error.rs # BrokerError type
│ │ ├── payload.rs # BrokerPayload — AMQP message body struct
│ │ ├── r_broker.rs # rBroker task — rec.read consume loop
│ │ └── w_broker.rs # wBroker task — rec.write consume loop
│ ├── core/
│ │ └── mod.rs # NamasteCore trait — unified CRUD interface (stub)
│ ├── config/
│ │ ├── mod.rs # load() + load_from() — layered TOML config
│ │ └── structs.rs # Typed config structs (serde Deserialize)
│ ├── services/
│ │ ├── mod.rs # Groups external service transport modules
│ │ ├── amqp/
│ │ │ ├── mod.rs # validate() — TCP reachability pre-flight
│ │ │ ├── connection.rs # AmqpConnection — auth + exchange declare
│ │ │ └── error.rs # AmqpError type
│ │ ├── mongo/
│ │ │ └── mod.rs # validate_all() — TCP reachability
│ │ └── mariadb/
│ │ └── mod.rs # validate_all() — master/secondary pattern
│ ├── lib.rs # Public API surface for integration test harness
│ ├── logging.rs # tracing + journald + console mirror init
│ └── main.rs # async ipl() sequence + #[tokio::main] main()
├── config/
│ ├── beds.toml # Base config — checked in, no credentials
│ ├── env_dev.toml # Dev overrides — gitignored
│ ├── env_qa.toml # QA overrides — gitignored
│ └── env_prod.toml # Prod overrides — gitignored
├── templates/
│ ├── example_rec.toml # Canonical self-documenting REC template
│ └── mst_logger_rec.toml # Logger collection template (msLogs)
├── tests/
│ ├── broker_pool_test.rs # rBroker + wBroker pool integration tests
│ ├── common/mod.rs # Shared test helpers — load_test_config()
│ └── fixtures/
│ └── beds_test.toml # Canonical test config fixture
├── Cargo.toml
└── CLAUDE.md
Planned additions (not yet implemented)
src/
├── core/
│ ├── factory.rs # Template name → NamasteCore dispatch
│ └── meta.rs # Request metadata parsing
└── adapters/
├── mysql.rs # gacPDO equivalent
└── mongodb.rs # gacMongoDB equivalent
Key Rust Mappings from PHP
| PHP | Rust |
|---|---|
gaaNamasteCore abstract class |
NamasteCore trait |
gacMongoDB, gacPDO |
Structs implementing NamasteCore |
gacFactory::grabWidget() |
Match/dispatch returning Box<dyn NamasteCore> |
| Broker process pool | tokio::spawn task pool |
| SIGCHLD/planned obsolescence | Eliminated — Tokio tasks don't leak |
| XML config layering | TOML with environment override file |
.class.inc template files |
Rust modules in src/templates/ |
gasResourceManager |
Connection pool via sqlx/deadpool |
NamasteCore Trait Interface
The core CRUD interface in src/core/mod.rs. Every template struct implements this:
pub trait NamasteCore {
fn template_id(&self) -> &'static str;
fn fetch(&self, params: HashMap<String, Value>) -> impl Future<Output = Result<Vec<HashMap<String, Value>>, String>> + Send;
fn write(&self, data: HashMap<String, Value>) -> impl Future<Output = Result<HashMap<String, Value>, String>> + Send;
fn update(&self, params: HashMap<String, Value>, data: HashMap<String, Value>) -> impl Future<Output = Result<u64, String>> + Send;
fn delete(&self, params: HashMap<String, Value>) -> impl Future<Output = Result<u64, String>> + Send;
}
Data in/out is always HashMap<String, Value> in user-facing field names. Templates own schema translation. Callers never provide primary keys on writes — the template generates a GUID.
BrokerPayload — AMQP Message Body
The JSON body carried by all broker messages (src/brokers/payload.rs):
{ "template": "usr", "data": { "first_name": "joe", "status": "active" } }
The AMQP type message property carries the operation (fetch, write, update, delete, ping, shutdown). The body carries the template identifier and data payload.
Dependencies (Cargo.toml)
[dependencies]
tokio = { version = "1", features = ["full"] }
lapin = "2" # AMQP/RabbitMQ
sqlx = { version = "0.7", features = ["mysql", "runtime-tokio-native-tls"] }
mongodb = "2" # MongoDB async driver
serde = { version = "1", features = ["derive"] }
serde_json = "1"
config = "0.14" # TOML config management
thiserror = "1"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
tracing-journald = "0.3"
Service Nodes
All nodes run the same binary. Startup config determines role:
| Node | Role | Brokers |
|---|---|---|
| appServer | Main application | rBroker, wBroker, mBroker |
| admin | Administration | adminBrokerIn/Out, adminLogsBroker, adminSyslogBroker, adminGraphBroker |
| segundo | Warehouse/cool storage | whBroker, cBroker |
| tercero | User management | uBroker, sBroker |
Scaling Model
- Horizontal — increase broker count in config when node has available resources
- Vertical — add nodes to broker pool when a node saturates
- Hot-swap — nodes can be replaced without touching application code; broker pool absorbs the change
AI Admin Layer (Planned — Phase 2)
A DBA describes a data domain in natural language. The AI layer generates:
- Database schema (table/collection definitions)
- Views and stored procedures/functions
- BEDS template struct implementing
NamasteCore - API documentation (markdown)
This is the primary market differentiator. No competitor combines database-agnostic transport + AMQP broker layer + DBA-enforced schema gatekeeping + AI-driven object generation.
Development Conventions
- All errors use
thiserror— no.unwrap()in production paths - All database operations are async — no blocking calls on the Tokio runtime
- Broker tasks are supervised — a failed task is logged and replaced, not silently dropped
- Config is loaded once at startup and passed as shared state — no runtime config reads
- One template per file in
src/templates/— file name matches domain name
Performance Baseline
The PHP implementation achieved:
- 40,000+ tp/s single node
- ~200ms round-trip Baja → West Virginia with dozens of concurrent DB fanout calls
- 952 days continuous production uptime
The Rust rewrite must meet or exceed these numbers. Run benchmarks before any architectural change that touches the broker pool or factory dispatch path.
Prior Art
The PHP implementation lives in the namaste repository. Refer to it for:
- Domain template patterns (
classes/templates/*.class.inc) - Config structure (
config/namaste.xml) - Error catalog (
common/errorCatalog.php) - DB catalog (
common/dbCatalog.php) - Schema definitions (
schema/pdo/)
Do not copy PHP code into this repository. Use it as architectural reference only.