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(())
}