En vous promenant sur Beamreactor, nous stockons votre IP 48h pour des raisons de sécurité.

Lecteur Markdown

Knowledge Base › BEAMREACTOR_CMDB

Beamreactor Cmdb

BeamReactor – CMDB (Configuration Management & Message Bus) #

> Version: 1.0

> Date: 2026.03.24

> Audience: Core developers, plugin developers, system integrators

> Scope: Inter-component communication, component registry, owner management

1. Overview

The CMDB is BeamReactor's backbone for inter-component communication. It provides:

  • A message bus for plugins, LLMs, load balancers, and services to exchange data
  • A component registry to declare and track what's running
  • An owner system for multi-tenant and federated deployments
  • Polling (flag-based) and push (handler callback) delivery modes

| File | Role |

|------|------|

| lib/cmdb/CMDB.class.php | Core class — all static methods |

| lib/cmdb/cmdb.sql | Schema: 4 tables |

Namespace: Beamreactor\CMDB\CMDB

2. Tables

| Table | Purpose |

|-------|---------|

| cmdb_owners | Owners: sites, clients, organisations |

| cmdb_registry | Declared components with dual ownership |

| cmdb_messages | Message bus (the queue) |

| cmdb_subscriptions | Who listens to what |

Installation #

php
use Beamreactor\CMDB\CMDB;

CMDB::install();  // Runs cmdb.sql — idempotent (CREATE IF NOT EXISTS)

3. Owners

Owners represent the entities that control components. A component has two optional owners:

| Role | Field | Meaning |

|------|-------|---------|

| Business | business_owner_id | Client, contract holder, project sponsor |

| Technical | technical_owner_id | Ops team, sysadmin, DevOps |

Owner Types #

| Type | Usage |

|------|-------|

| local | This BeamReactor instance |

| remote | External site / federated node |

| client | End customer / tenant |

| org | Organisation / department |

| system | System-level (cron, scheduler) |

Creating Owners #

php
// Business owner (a client)
$client_id = CMDB::createOwner('client', 'acme-corp', 'ACME Corporation',
    'https://acme.example.com/api',  // remote endpoint
    'admin@acme.com',
    ['contract' => 'PRO-2026', 'sla' => '99.9%'],  // metadata
    3  // trust level (high)
);

// Technical owner (ops team)
$ops_id = CMDB::createOwner('local', 'devops-team', 'DevOps Team');

Owner Methods #

| Method | Returns | Description |

|--------|---------|-------------|

| createOwner($type, $name, ...) | int\|false | Create or update an owner (upsert) |

| getOwner(int $id) | array\|false | Get owner by ID (decodes metadata JSON) |

| findOwner($type, $name) | array\|false | Find owner by type + name |

| listOwners(?$type, ?$status) | array | List owners with optional filters |

| setOwnerStatus($id, $status) | int | Change status: active, suspended, revoked, pending |

| getOwnedComponents($id, $role) | array | List components for an owner (business/technical/any) |

Inter-Site Authentication #

Owners can hold an API key for remote authentication:

php
// Generate and set (store the plain key, only the hash is saved)
$api_key = bin2hex(random_bytes(32));
CMDB::setOwnerApiKey($owner_id, $api_key);

// Verify later
if (CMDB::verifyOwnerApiKey($owner_id, $incoming_key))
{
    // Authenticated
}

Keys are hashed with Argon2ID. The plain key is never stored.

Trust Levels #

| Level | Meaning |

|-------|---------|

| 1 | Maximum trust (internal core) |

| 3 | High trust (known partner) |

| 5 | Standard (default) |

| 7 | Low trust (new/unverified) |

| 9 | Minimal trust (sandboxed) |

4. Registry

Every component (plugin, LLM, service, load balancer) should register itself on startup.

Registering a Component #

php
CMDB::register(
    'plugin',                          // type
    'xchange',                         // name
    '1.0.0',                           // version
    'Marketplace plugin',              // description
    ['trading', 'rating', 'messaging'],// capabilities
    ['max_photos' => 5],              // config
    $client_id,                        // business owner
    $ops_id                            // technical owner
);

Component Types #

| Type | Usage |

|------|-------|

| plugin | BeamReactor plugin |

| llm | LLM connector (Aegis, GPT, Claude...) |

| lb | Load balancer instance |

| service | Background service, daemon |

| core | BeamReactor core component |

Registry Methods #

| Method | Returns | Description |

|--------|---------|-------------|

| register($type, $name, ...) | int\|false | Register component (upsert) |

| getComponent($type, $name) | array\|false | Get component with owner info (JOIN) |

| listComponents(?$type, ?$status) | array | List with optional filters |

| hasCapability($type, $name, $cap) | bool | Check if component declares a capability |

| setStatus($type, $name, $status) | int | Update status |

| heartbeat($type, $name) | int | Update last_heartbeat timestamp |

| getStaleComponents($minutes) | array | Find components with no heartbeat since N minutes |

Component Identifier Format #

Components are referenced as type:name strings throughout the message bus:

php
$id = CMDB::componentId('plugin', 'xchange');  // "plugin:xchange"
$parts = CMDB::parseComponentId($id);           // ['type' => 'plugin', 'name' => 'xchange']

5. Messages

The message bus uses a simple queue with flags and priorities.

Sending a Message #

php
CMDB::send(
    'plugin:xchange',       // source
    'plugin:messaging',     // target
    'xchange.first_contact',// channel
    [                        // payload (JSON)
        'buyer_id'   => 42,
        'seller_id'  => 7,
        'product_id' => 123,
        'message'    => 'Interested in your item'
    ],
    'notify',               // action (optional)
    CMDB::PRIORITY_NORMAL,  // priority (optional, default 5)
    3600,                   // TTL in seconds (optional, null = permanent)
    42                      // user_id (optional)
);

Request/Response Pattern #

For tracked exchanges with automatic correlation:

php
// Sender: create a request
$req = CMDB::request('plugin:xchange', 'plugin:messaging', 'xchange.first_contact', [
    'buyer_id' => 42,
    'seller_id' => 7,
]);
// $req = ['message_id' => 15, 'correlation_id' => 'a3f8...']

// Receiver: reply to it
CMDB::reply($req['message_id'], ['status' => 'conversation_opened']);

// Sender: check for responses
$responses = CMDB::getResponses($req['correlation_id'], 'plugin:xchange');

Polling (Receiver Side) #

php
// Get all pending messages
$messages = CMDB::poll('plugin:messaging');

// Filter by channel pattern
$messages = CMDB::poll('plugin:messaging', 'xchange.%');

// Quick checks
if (CMDB::hasPending('plugin:messaging'))
{
    $count = CMDB::countPending('plugin:messaging');
}

poll() automatically marks messages as READ and sets status to delivered.

Priority Constants #

| Constant | Value | Use |

|----------|-------|-----|

| PRIORITY_CRITICAL | 1 | System failure, security alert |

| PRIORITY_HIGH | 3 | Needs prompt attention |

| PRIORITY_NORMAL | 5 | Default |

| PRIORITY_LOW | 7 | Background / informational |

| PRIORITY_IDLE | 9 | Cleanup, analytics |

Messages are delivered in priority order (1 first), then by creation date.

6. Flags

Old-school bitfield system for message state tracking.

Flag Constants #

| Constant | Value | Meaning |

|----------|-------|---------|

| FLAG_READ | 1 | Message has been seen |

| FLAG_ACK | 2 | Receiver acknowledged |

| FLAG_PROCESSED | 4 | Action completed |

| FLAG_ERROR | 8 | Processing failed |

| FLAG_EXPIRED | 16 | TTL exceeded |

Usage #

php
// Set a flag
CMDB::setFlag($message_id, CMDB::FLAG_READ);

// Set multiple flags at once
CMDB::setFlag($message_id, CMDB::FLAG_ACK | CMDB::FLAG_PROCESSED);

// Clear a flag
CMDB::clearFlag($message_id, CMDB::FLAG_ERROR);

// Check flags (on a fetched message)
if (CMDB::hasFlag($msg['flags'], CMDB::FLAG_ACK))
{
    // Already acknowledged
}

// Shorthand: acknowledge = ACK + PROCESSED + status update
CMDB::acknowledge($message_id);

// Shorthand: mark as failed with error info
CMDB::fail($message_id, 'Connection timeout to remote API');

7. Subscriptions

Components can subscribe to message channels for push or poll delivery.

Subscribing #

php
// Poll mode (default) — component fetches messages with poll()
CMDB::subscribe('plugin:messaging', 'xchange.*');

// Push mode — handler is called immediately when a matching message arrives
CMDB::subscribe('plugin:messaging', 'xchange.first_contact', 'push',
    'plugins/messaging/handlers/cmdb_push.handler.php'
);

// Both modes
CMDB::subscribe('plugin:monitoring', 'llm.*', 'both',
    'plugins/monitoring/handlers/cmdb_push.handler.php',
    null,  // source filter (null = all sources)
    3      // priority_min: only priority 1-3
);

Push Handlers #

Push handler files are included when a matching message is sent. They receive:

| Variable | Type | Description |

|----------|------|-------------|

| $cmdb_push_message_id | int | ID of the message that triggered the push |

| $cmdb_push_subscriber | string | Subscriber component ID |

php
<?php
// plugins/messaging/handlers/cmdb_push.handler.php
use Beamreactor\CMDB\CMDB;

$msg = CMDB::getMessage($cmdb_push_message_id);

if ($msg && $msg['channel'] === 'xchange.first_contact')
{
    // Create internal conversation between buyer and seller
    $payload = $msg['payload'];
    // ... create_conversation($payload['buyer_id'], $payload['seller_id']);

    CMDB::acknowledge($cmdb_push_message_id);
}
?>

Channel Patterns #

Subscriptions support wildcard matching:

| Pattern | Matches |

|---------|---------|

| xchange.* | xchange.first_contact, xchange.rating, etc. |

| llm.health | Only llm.health |

| *.error | xchange.error, llm.error, etc. |

Subscription Methods #

| Method | Returns | Description |

|--------|---------|-------------|

| subscribe($subscriber, $pattern, ...) | int\|false | Subscribe (upsert) |

| unsubscribe($subscriber, $pattern) | int | Remove subscription |

| getSubscriptions($subscriber) | array | List active subscriptions |

8. Maintenance

TTL Expiration #

Messages with a ttl have an expires_at computed at creation. Expired messages must be swept:

php
// Run periodically (cron / scheduler)
$expired = CMDB::expireMessages();

Purge Old Messages #

php
// Delete processed/expired/failed messages older than 30 days
$deleted = CMDB::purge(30);

Stale Component Detection #

php
// Components that haven't sent a heartbeat in 30 minutes
$stale = CMDB::getStaleComponents(30);

foreach ($stale as $component)
{
    CMDB::setStatus($component['component_type'], $component['component_name'], 'degraded');
}

9. Typical Plugin Integration

A plugin registers itself and subscribes during its initialization (conf/{name}.conf.php or autoload):

php
use Beamreactor\CMDB\CMDB;

// Register
CMDB::register('plugin', 'xchange', '1.0.0', 'Marketplace', ['trading', 'rating']);

// Subscribe to responses
CMDB::subscribe('plugin:xchange', 'xchange.*', 'push',
    'plugins/xchange/handlers/cmdb_push.handler.php'
);

// Heartbeat (if the plugin runs as a service)
CMDB::heartbeat('plugin', 'xchange');

Sending Inter-Plugin Messages #

php
// xchange triggers a messaging conversation
CMDB::send('plugin:xchange', 'plugin:messaging', 'xchange.first_contact', [
    'buyer_id'   => $buyer_id,
    'seller_id'  => $seller_id,
    'product_id' => $product_id,
    'subject'    => 'Interested in: ' . $product_title,
]);

Receiving Messages #

php
// In a handler or cron job
$messages = CMDB::poll('plugin:xchange', 'messaging.%');

foreach ($messages as $msg)
{
    // Process
    CMDB::acknowledge($msg['id']);
}

10. Migrations

The CMDB includes a full SQL migration system. Each component (plugin, lib, core) can have versioned SQL files that are tracked, checksummed, and never replayed.

File Convention #

text
plugins/xchange/sql/migrations/001_initial.sql
plugins/xchange/sql/migrations/002_add_trades_table.sql
plugins/xchange/sql/migrations/003_add_rating_index.sql
lib/cmdb/sql/migrations/001_initial.sql

Files must be named with a sortable prefix. They are executed in alphabetical order.

Optional Description Header #

Place a description in the first SQL comment line:

sql
-- Description: Add trades table and buyer/seller indexes
CREATE TABLE IF NOT EXISTS xchange_trades ( ... );

Running Migrations #

php
// Single component
$result = CMDB::migrate(
    'plugin',                                    // component type
    'xchange',                                   // component name
    'plugins/xchange/sql/migrations',            // migrations directory
    '1.2.0',                                     // current version (optional)
    'admin',                                     // who runs this
    'production'                                 // environment tag
);
// $result = ['applied' => 2, 'skipped' => 1, 'failed' => 0, 'errors' => []]

// All components at once (scans lib/*, plugins/*)
$results = CMDB::migrateAll('deploy-server', 'production');
// $results = ['plugin:xchange' => [...], 'lib:cmdb' => [...], ...]

Checking Status #

php
// What migrations have been applied?
$status = CMDB::getMigrationStatus('plugin', 'xchange');
// Returns: migration_id, version, status, description, statements_count,
//          execution_time_ms, applied_by, environment, batch, applied_at

// What's pending?
$pending = CMDB::getPendingMigrations('plugin', 'xchange', 'plugins/xchange/sql/migrations');
// Returns: ['003_add_rating_index.sql']

Integrity Check #

Detects if migration files were modified after being applied (checksum mismatch) or deleted:

php
$tampered = CMDB::verifyMigrationIntegrity();

foreach ($tampered as $t)
{
    echo $t['component'] . ' / ' . $t['file'] . ': ' . $t['issue'];
    // "plugin:xchange / 001_initial.sql: checksum_mismatch"
}

Behavior #

| Scenario | Behavior |

|----------|----------|

| File already applied | Skipped (checksum verified) |

| New file found | Executed in transaction, recorded |

| Statement fails | Transaction rolled back, status = failed, migration stops |

| File modified after apply | Warning in verifyMigrationIntegrity() |

| File deleted after apply | Reported as file_missing |

Batch Numbers #

All migrations executed in a single migrate() or migrateAll() call share the same batch number. This allows easy rollback identification.

Integration with Deployment #

On devarea.beamreactor.com, after syncing PHP files:

php
// Auto-run all pending migrations
$results = CMDB::migrateAll('devarea-deploy', 'production');

foreach ($results as $component => $r)
{
    if ($r['failed'] > 0)
    {
        // Alert: migration failed for $component
        error_log("Migration failed: $component — " . implode(', ', $r['errors']));
    }
}

11. Architecture Diagram

text
                        ┌─────────────┐
                        │ cmdb_owners │
                        │ (sites,     │
                        │  clients)   │
                        └──────┬──────┘
                   business_owner_id │ technical_owner_id
                               │
┌──────────────┐       ┌──────┴──────┐       ┌───────────────────┐
│   Plugin A   │──send─▶│ cmdb_messages│◀─poll──│    Plugin B       │
│ (xchange)    │       │  (the bus)  │       │ (messaging)       │
└──────────────┘       └──────┬──────┘       └───────────────────┘
       │                      │                        ▲
       │               ┌──────┴──────┐                 │
       └──register────▶│cmdb_registry│    ┌────────────┴──────┐
                       │ (who exists)│    │cmdb_subscriptions │
                       └─────────────┘    │ (who listens)     │
                                          └───────────────────┘

11. Quick Reference

Most Used Methods #

php
// Owners
CMDB::createOwner($type, $name, $display, $url, $email, $meta, $trust);
CMDB::getOwnedComponents($owner_id, 'business');

// Registry
CMDB::register($type, $name, $version, $desc, $caps, $config, $biz_owner, $tech_owner);
CMDB::getComponent($type, $name);
CMDB::hasCapability($type, $name, 'rating');

// Messages
CMDB::send($source, $target, $channel, $payload, $action, $priority, $ttl);
CMDB::poll($target, $channel_filter);
CMDB::request($source, $target, $channel, $payload);
CMDB::reply($message_id, $payload);
CMDB::acknowledge($message_id);
CMDB::fail($message_id, $error);

// Subscriptions
CMDB::subscribe($subscriber, $pattern, 'push', $handler);
CMDB::unsubscribe($subscriber, $pattern);

// Maintenance
CMDB::expireMessages();
CMDB::purge(30);
CMDB::getStaleComponents(30);

// Migrations
CMDB::migrate($type, $name, $dir, $version, $who, $env);
CMDB::migrateAll($who, $env);
CMDB::getMigrationStatus($type, $name);
CMDB::getPendingMigrations($type, $name, $dir);
CMDB::verifyMigrationIntegrity();
de en fr