- 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>
198 lines
9.2 KiB
Markdown
198 lines
9.2 KiB
Markdown
# 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:
|
|
1. Eliminate PHP memory leak workarounds (planned broker obsolescence via SIGCHLD)
|
|
2. Dramatically increase throughput (5-10x expected)
|
|
3. Enable single binary deployment with no runtime dependency
|
|
4. Protect IP through compilation
|
|
5. Add an AI-driven database object generation layer
|
|
|
|
## Core Architecture Principles
|
|
|
|
**Never violate these — they are the product:**
|
|
|
|
1. **AMQP-first** — all data access flows through RabbitMQ message brokers. No direct database connections from the application layer. Ever.
|
|
2. **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.
|
|
3. **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.
|
|
4. **Template-driven CRUD** — each data domain is a Rust struct implementing the `NamasteCore` trait. Adding a domain means adding a struct. Nothing else changes.
|
|
5. **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:
|
|
|
|
```rust
|
|
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`):
|
|
|
|
```json
|
|
{ "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)
|
|
|
|
```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:
|
|
1. Database schema (table/collection definitions)
|
|
2. Views and stored procedures/functions
|
|
3. BEDS template struct implementing `NamasteCore`
|
|
4. 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.
|
|
|
|
## Author
|
|
|
|
gramps@llamachile.shop
|