Tenant context

Updated Jul 14, 2026

All repository and service operations on tenant-owned data require a RequestContext. This cross-cutting struct carries the tenant identity, distributed tracing identifiers, and the authenticated principal.

use corbusier::context::{
    CausationId, CorrelationId, RequestContext, SessionId, UserId,
};
use corbusier::tenant::TenantId;

fn build_request_context() {
    // Required fields: tenant, correlation, user, session.
    let ctx = RequestContext::new(
        TenantId::new(),
        CorrelationId::new(),
        UserId::new(),
        SessionId::new(),
    );

    // Optional causation ID links the operation to its triggering event.
    let ctx_with_cause = ctx.with_causation_id(CausationId::new());
    assert!(ctx_with_cause.causation_id().is_some());
}

Tenant identity is modelled separately from user identity. The TenantSlug type enforces Domain Name System (DNS)-label-safe formatting: lowercase alphanumeric plus hyphens, 1–63 characters, no leading or trailing hyphens, no consecutive hyphens.

use corbusier::tenant::{Tenant, TenantSlug, TenantStatus};
use corbusier::context::UserId;
use mockable::DefaultClock;

fn create_tenant() -> Result<(), Box<dyn std::error::Error>> {
    let clock = DefaultClock;
    let slug = TenantSlug::new("acme-corp")?;
    let owner = UserId::new();
    let tenant = Tenant::new(slug, "Acme Corporation", owner, &clock)?;

    assert_eq!(tenant.slug().as_str(), "acme-corp");
    assert_eq!(tenant.display_name(), "Acme Corporation");
    assert_eq!(tenant.status(), TenantStatus::Active);
    Ok(())
}