Multi-tenancy support for Rust applications
| Tier | identity |
| Role | unclassified (baselined) |
| Path | crates/identity/tenant |
| Edition | 2021 |
| Targets | identity_tenant, pg_runtime_contract, pg_tenant_ctx, tenant_ctx |
| Public items | 109 across 3 modules |
| Tests | 68 |
What it is for
Multi-tenancy support for Rust applications.
This crate provides library crates for building multi-tenant applications with support for different isolation strategies.
Capabilities
InMemoryTenantResolver
Multi-tenancy support for Rust applications.
| Item |
|---|
pub struct InMemoryTenantResolver |
InMemoryTenantResolver :: fn new() -> Self |
InMemoryTenantResolver :: fn register(& self, tenant : & Tenant) |
InMemoryTenantResolver :: fn resolve_by_domain(& self, domain : & str) -> Option <Uuid> |
InMemoryTenantResolver :: fn resolve_by_subdomain(& self, subdomain : & str) -> Option <Uuid> |
InMemoryTenantResolver :: fn resolve_by_header(& self, value : & str) -> Option <Uuid> |
InMemoryTenantResolver :: fn resolve_by_path(& self, segment : & str) -> Option <Uuid> |
IsolationStrategy
Multi-tenancy support for Rust applications.
| Item |
|---|
pub enum IsolationStrategy |
IsolationStrategy :: fn fmt(& self, f : & mut std::fmt::Formatter <'_>) -> std::fmt::Result |
MemberStatus
Multi-tenancy support for Rust applications.
| Item |
|---|
pub enum MemberStatus |
MemberStatus :: fn fmt(& self, f : & mut std::fmt::Formatter <'_>) -> std::fmt::Result |
MemberStatus :: fn has_access(& self) -> bool |
MemberStatus :: fn is_terminal(& self) -> bool |
Result
Multi-tenancy support for Rust applications.
| Item |
|---|
pub type Result<T>: std::result::Result <T, TenantError> |
fn validate_slug(slug : & str) -> Result <()> |
Tenant:Tenant
Multi-tenancy support for Rust applications.
| Item |
|---|
pub struct Tenant |
Tenant:activate
Multi-tenancy support for Rust applications.
| Item |
|---|
Tenant :: fn activate(& mut self) -> Result <()> |
Tenant:deactivate
Multi-tenancy support for Rust applications.
| Item |
|---|
Tenant :: fn deactivate(& mut self) -> Result <()> |
Tenant:effective
Multi-tenancy support for Rust applications.
| Item |
|---|
Tenant :: fn effective_schema(& self) -> & str |
Tenant:get
Multi-tenancy support for Rust applications.
| Item |
|---|
Tenant :: fn get_setting <T : for <'de> Deserialize <'de>>(& self, key : & str) -> Option <T> |
Tenant:is
Multi-tenancy support for Rust applications.
| Item |
|---|
Tenant :: fn is_accessible(& self) -> bool |
Tenant:new
Multi-tenancy support for Rust applications.
| Item |
|---|
Tenant :: fn new(slug : impl Into <String>, name : impl Into <String>) -> Self |
Tenant:suspend
Multi-tenancy support for Rust applications.
| Item |
|---|
Tenant :: fn suspend(& mut self, reason : impl Into <String>) -> Result <()> |
Tenant:with
Multi-tenancy support for Rust applications.
| Item |
|---|
Tenant :: fn with_tier(mut self, tier : TenantTier) -> Self |
Tenant :: fn with_isolation(mut self, isolation : IsolationStrategy) -> Self |
Tenant :: fn with_domain(mut self, domain : impl Into <String>) -> Self |
Tenant :: fn with_additional_domain(mut self, domain : impl Into <String>) -> Self |
Tenant :: fn with_setting(mut self, key : impl Into <String>, value : impl Serialize) -> Self |
TenantContext
Multi-tenancy support for Rust applications.
| Item |
|---|
pub struct TenantContext |
TenantContext :: fn from_tenant(tenant : & Tenant) -> Self |
TenantContext :: fn with_data(mut self, key : impl Into <String>, value : impl Serialize) -> Self |
TenantError
Multi-tenancy support for Rust applications.
| Item |
|---|
pub enum TenantError |
TenantFeatures
Multi-tenancy support for Rust applications.
| Item |
|---|
pub struct TenantFeatures |
TenantFeatures :: fn is_enabled(& self, feature : & str) -> bool |
TenantFeatures :: fn enable(& mut self, feature : impl Into <String>) |
TenantFeatures :: fn disable(& mut self, feature : impl Into <String>) |
TenantFeatures :: fn get_config <T : for <'de> Deserialize <'de>>(& self, feature : & str) -> Option <T> |
TenantMember
Multi-tenancy support for Rust applications.
| Item |
|---|
pub struct TenantMember |
TenantMember :: fn new(tenant_id : Uuid, user_id : Uuid, role : TenantRole) -> Self |
TenantMember :: fn new_invited(tenant_id : Uuid, user_id : Uuid, role : TenantRole, invited_by : Uuid, invite_token : String, expires_in_days : i64,) -> Self |
TenantMember :: fn has_access(& self) -> bool |
TenantMember :: fn is_pending(& self) -> bool |
TenantMember :: fn is_invite_valid(& self) -> bool |
TenantMember :: fn accept(& mut self) |
TenantMember :: fn remove(& mut self) |
TenantMember :: fn change_role(& mut self, role : TenantRole) |
TenantMember :: fn regenerate_invite(& mut self, invite_token : String, expires_in_days : i64) |
TenantMember :: fn tenant_id(& self) -> Uuid |
TenantQuotas
Multi-tenancy support for Rust applications.
| Item |
|---|
pub struct TenantQuotas |
TenantQuotas :: fn default() -> Self |
TenantQuotas :: fn unlimited() -> Self |
TenantQuotas :: fn is_exceeded(& self, quota : & str, current : u64) -> bool |
TenantQuotas :: fn with_custom_quota(mut self, name : impl Into <String>, limit : u64) -> Self |
TenantResolver
Multi-tenancy support for Rust applications.
| Item |
|---|
pub trait TenantResolver |
TenantRole
Multi-tenancy support for Rust applications.
| Item |
|---|
pub enum TenantRole |
TenantRole :: fn fmt(& self, f : & mut std::fmt::Formatter <'_>) -> std::fmt::Result |
TenantRole :: fn has_permission(self, target : TenantRole) -> bool |
TenantScoped
Multi-tenancy support for Rust applications.
| Item |
|---|
pub trait TenantScoped |
TenantStatus
Multi-tenancy support for Rust applications.
| Item |
|---|
pub enum TenantStatus |
TenantStatus :: fn fmt(& self, f : & mut std::fmt::Formatter <'_>) -> std::fmt::Result |
TenantStatus :: fn is_accessible(& self) -> bool |
TenantStatus :: fn is_terminal(& self) -> bool |
TenantStatus :: fn can_transition_to(& self, target : TenantStatus) -> bool |
TenantTier
Multi-tenancy support for Rust applications.
| Item |
|---|
pub enum TenantTier |
TenantTier :: fn fmt(& self, f : & mut std::fmt::Formatter <'_>) -> std::fmt::Result |
TenantUsage
Multi-tenancy support for Rust applications.
| Item |
|---|
pub struct TenantUsage |
TenantUsage :: fn check_quotas(& self, quotas : & TenantQuotas) -> Vec <String> |
verb:accept
Repository functions for tenant models.
| Item |
|---|
async fn accept_invitation(pool : & PgPool, invite_token : & str,) -> Result <Option <TenantMember>, TenantError> |
verb:create
Repository functions for tenant models.
| Item |
|---|
async fn create_tenant(pool : & PgPool, name : & str, slug : & str) -> Result <Uuid, TenantError> |
async fn create_member(pool : & PgPool, tenant_id : Uuid, user_id : Uuid, role : TenantRole,) -> Result <TenantMember, TenantError> |
async fn create_invited_member(pool : & PgPool, tenant_id : Uuid, user_id : Uuid, role : TenantRole, invited_by : Uuid, expires_in_days : i64,) -> Result <TenantMember, TenantError> |
verb:generate
Repository functions for tenant models.
| Item |
|---|
fn generate_invite_token() -> String |
verb:get
Repository functions for tenant models.
| Item |
|---|
async fn get_tenant_by_id(pool : & PgPool, tenant_id : Uuid,) -> Result <Option <Tenant>, TenantError> |
async fn get_tenant_by_slug(pool : & PgPool, slug : & str) -> Result <Option <Tenant>, TenantError> |
async fn get_member(pool : & PgPool, tenant_id : Uuid, user_id : Uuid,) -> Result <Option <TenantMember>, TenantError> |
async fn get_member_by_token(pool : & PgPool, invite_token : & str,) -> Result <Option <TenantMember>, TenantError> |
async fn get_member_role(pool : & PgPool, tenant_id : Uuid, user_id : Uuid,) -> Result <Option <TenantRole>, TenantError> |
verb:is
Repository functions for tenant models.
| Item |
|---|
async fn is_active_member(pool : & PgPool, tenant_id : Uuid, user_id : Uuid,) -> Result <bool, TenantError> |
verb:list
Repository functions for tenant models.
| Item |
|---|
async fn list_members(pool : & PgPool, tenant_id : Uuid,) -> Result <Vec <TenantMember>, TenantError> |
async fn list_tenants_for_user(pool : & PgPool, user_id : Uuid,) -> Result <Vec <(Uuid, TenantRole)>, TenantError> |
verb:remove
Repository functions for tenant models.
| Item |
|---|
async fn remove_member(pool : & PgPool, tenant_id : Uuid, user_id : Uuid,) -> Result <(), TenantError> |
verb:update
Repository functions for tenant models.
| Item |
|---|
async fn update_member_role(pool : & PgPool, tenant_id : Uuid, user_id : Uuid, new_role : TenantRole,) -> Result <(), TenantError> |
MembershipDetail
Repository functions for tenant models.
| Item |
|---|
pub struct MembershipDetail |
async fn list_membership_details(pool : & PgPool, user_id : Uuid,) -> Result <Vec <MembershipDetail>, TenantError> |
MemberService
Service layer for tenant operations.
| Item |
|---|
pub struct MemberService<'a> |
MemberService<'a>
Service layer for tenant operations.
| Item |
|---|
MemberService<'a> :: fn new(pool : & 'a PgPool) -> Self |
MemberService<'a> :: async fn invite(& self, tenant_id : Uuid, user_id : Uuid, role : TenantRole, invited_by : Uuid, expires_in_days : i64,) -> Result <TenantMember, TenantError> |
MemberService<'a> :: async fn accept_invitation(& self, invite_token : & str,) -> Result <Option <TenantMember>, TenantError> |
MemberService<'a> :: async fn get(& self, tenant_id : Uuid, user_id : Uuid,) -> Result <Option <TenantMember>, TenantError> |
MemberService<'a> :: async fn list(& self, tenant_id : Uuid) -> Result <Vec <TenantMember>, TenantError> |
MemberService<'a> :: async fn list_tenants_for_user(& self, user_id : Uuid,) -> Result <Vec <(Uuid, TenantRole)>, TenantError> |
MemberService<'a> :: async fn update_role(& self, tenant_id : Uuid, user_id : Uuid, new_role : TenantRole, changed_by : Uuid,) -> Result <(), TenantError> |
MemberService<'a> :: async fn remove(& self, tenant_id : Uuid, user_id : Uuid, removed_by : Uuid,) -> Result <(), TenantError> |
MemberService<'a> :: async fn is_active_member(& self, tenant_id : Uuid, user_id : Uuid,) -> Result <bool, TenantError> |
MemberService<'a> :: async fn get_role(& self, tenant_id : Uuid, user_id : Uuid,) -> Result <Option <TenantRole>, TenantError> |
TenantService
Service layer for tenant operations.
| Item |
|---|
pub struct TenantService<'a> |
TenantService<'a>
Service layer for tenant operations.
| Item |
|---|
TenantService<'a> :: fn new(pool : & 'a PgPool) -> Self |
TenantService<'a> :: async fn create_with_owner(& self, name : & str, slug : & str, owner_user_id : Uuid,) -> Result <(Uuid, TenantMember), TenantError> |
TenantService<'a> :: async fn get_by_id(& self, tenant_id : Uuid) -> Result <Option <Tenant>, TenantError> |
TenantService<'a> :: async fn get_by_slug(& self, slug : & str) -> Result <Option <Tenant>, TenantError> |
tenant_ctx (other)
Tenant context for row-level-security policies (Sprint 3.2 D1, B-039).
| Item |
|---|
pub const GUC_NAME: & str |
pub const SYSTEM_SCOPE: & str |
async fn bind_raw_value <'c, E>(executor : E, value : & str) -> Result <(), sqlx::Error> where E : sqlx::Executor <'c, Database = sqlx::Postgres>, |
TenantScope
Tenant context for row-level-security policies (Sprint 3.2 D1, B-039).
| Item |
|---|
pub enum TenantScope |
TenantScope :: fn for_row_tenant(tenant : Option <Uuid>) -> Self |
TenantScope :: fn see_all_if_global(is_global : bool) -> Self |
TenantScope :: fn is_see_all(self) -> bool |
TenantScope :: fn guc_value(self) -> String |
async fn bind_scope <'c, E>(executor : E, scope : TenantScope) -> Result <(), sqlx::Error> where E : sqlx::Executor <'c, Database = sqlx::Postgres>, |
How to use it
No examples/ target and no doctest in this crate's rustdoc. The tests listed under Verification are the closest executable usage.
Module structure
identity_tenant
reposervicetenant_ctx
flowchart TD n_identity_tenant["identity_tenant"] n_identity_tenant --> n_repo["repo"] n_identity_tenant --> n_service["service"] n_identity_tenant --> n_tenant_ctx["tenant_ctx"]
Public surface
`crate root`
| Item | What it is |
|---|---|
pub enum TenantError | Errors that can occur with tenant operations. |
pub type Result<T>: std::result::Result <T, TenantError> | Result type for tenant operations. |
fn validate_slug(slug : & str) -> Result <()> | Validates a tenant slug |
pub enum IsolationStrategy | Tenant isolation strategy. |
IsolationStrategy :: fn fmt(& self, f : & mut std::fmt::Formatter <'_>) -> std::fmt::Result | — |
pub enum TenantStatus | Tenant status. |
TenantStatus :: fn fmt(& self, f : & mut std::fmt::Formatter <'_>) -> std::fmt::Result | — |
TenantStatus :: fn is_accessible(& self) -> bool | Returns true if the tenant can be accessed. |
TenantStatus :: fn is_terminal(& self) -> bool | Returns true if the tenant is in a terminal state. |
TenantStatus :: fn can_transition_to(& self, target : TenantStatus) -> bool | Returns true if the tenant can transition to the target status. |
pub enum TenantTier | Tenant tier/plan. |
TenantTier :: fn fmt(& self, f : & mut std::fmt::Formatter <'_>) -> std::fmt::Result | — |
pub enum TenantRole | Role of a member within a tenant. |
TenantRole :: fn fmt(& self, f : & mut std::fmt::Formatter <'_>) -> std::fmt::Result | — |
pub enum MemberStatus | Status of a tenant membership. |
MemberStatus :: fn fmt(& self, f : & mut std::fmt::Formatter <'_>) -> std::fmt::Result | — |
MemberStatus :: fn has_access(& self) -> bool | Returns true if the member has access to the tenant. |
MemberStatus :: fn is_terminal(& self) -> bool | Returns true if this is a terminal state. |
TenantRole :: fn has_permission(self, target : TenantRole) -> bool | Returns true if this role has permission over the target role. |
pub struct TenantMember | A member of a tenant. |
TenantMember :: fn new(tenant_id : Uuid, user_id : Uuid, role : TenantRole) -> Self | Creates a new active tenant member (direct add, no invite). |
TenantMember :: fn new_invited(tenant_id : Uuid, user_id : Uuid, role : TenantRole, invited_by : Uuid, invite_token : String, expires_in_days : i64,) -> Self | Creates a new invited member (pending acceptance). |
TenantMember :: fn has_access(& self) -> bool | Returns true if the member has access to the tenant. |
TenantMember :: fn is_pending(& self) -> bool | Returns true if the invite is pending. |
TenantMember :: fn is_invite_valid(& self) -> bool | Returns true if the invite token is still valid. |
TenantMember :: fn accept(& mut self) | Accepts the invitation, activating the membership. |
TenantMember :: fn remove(& mut self) | Removes the member (soft delete). |
TenantMember :: fn change_role(& mut self, role : TenantRole) | Changes the member's role. |
TenantMember :: fn regenerate_invite(& mut self, invite_token : String, expires_in_days : i64) | Regenerates the invite token with a new expiry. |
pub struct Tenant | A tenant in the system. |
Tenant :: fn new(slug : impl Into <String>, name : impl Into <String>) -> Self | Creates a new tenant. |
Tenant :: fn with_tier(mut self, tier : TenantTier) -> Self | Sets the tenant tier. |
Tenant :: fn with_isolation(mut self, isolation : IsolationStrategy) -> Self | Sets the isolation strategy. |
Tenant :: fn with_domain(mut self, domain : impl Into <String>) -> Self | Sets the primary domain. |
Tenant :: fn with_additional_domain(mut self, domain : impl Into <String>) -> Self | Adds an additional domain. |
Tenant :: fn with_setting(mut self, key : impl Into <String>, value : impl Serialize) -> Self | Sets a setting value. |
Tenant :: fn activate(& mut self) -> Result <()> | Activates the tenant |
Tenant :: fn suspend(& mut self, reason : impl Into <String>) -> Result <()> | Suspends the tenant |
Tenant :: fn deactivate(& mut self) -> Result <()> | Deactivates the tenant |
Tenant :: fn is_accessible(& self) -> bool | Returns true if the tenant is accessible. |
Tenant :: fn get_setting <T : for <'de> Deserialize <'de>>(& self, key : & str) -> Option <T> | Gets a setting value. |
Tenant :: fn effective_schema(& self) -> & str | Gets the effective schema name. |
pub struct TenantQuotas | Tenant quota limits. |
TenantQuotas :: fn default() -> Self | — |
TenantQuotas :: fn unlimited() -> Self | Creates unlimited quotas. |
TenantQuotas :: fn is_exceeded(& self, quota : & str, current : u64) -> bool | Checks if a quota limit is exceeded. |
TenantQuotas :: fn with_custom_quota(mut self, name : impl Into <String>, limit : u64) -> Self | Sets a custom quota. |
pub struct TenantContext | Tenant context for request processing. |
TenantContext :: fn from_tenant(tenant : & Tenant) -> Self | Creates a new tenant context from a tenant. |
TenantContext :: fn with_data(mut self, key : impl Into <String>, value : impl Serialize) -> Self | Sets context data. |
pub trait TenantResolver | Tenant resolver trait for identifying tenants from requests. |
pub struct InMemoryTenantResolver | In-memory tenant resolver for testing |
InMemoryTenantResolver :: fn new() -> Self | Creates a new resolver. |
InMemoryTenantResolver :: fn register(& self, tenant : & Tenant) | Registers a tenant |
InMemoryTenantResolver :: fn resolve_by_domain(& self, domain : & str) -> Option <Uuid> | — |
InMemoryTenantResolver :: fn resolve_by_subdomain(& self, subdomain : & str) -> Option <Uuid> | — |
InMemoryTenantResolver :: fn resolve_by_header(& self, value : & str) -> Option <Uuid> | — |
InMemoryTenantResolver :: fn resolve_by_path(& self, segment : & str) -> Option <Uuid> | — |
pub struct TenantUsage | Tenant usage statistics. |
TenantUsage :: fn check_quotas(& self, quotas : & TenantQuotas) -> Vec <String> | Checks if any quota is exceeded. |
pub struct TenantFeatures | Tenant feature flags. |
TenantFeatures :: fn is_enabled(& self, feature : & str) -> bool | Checks if a feature is enabled. |
TenantFeatures :: fn enable(& mut self, feature : impl Into <String>) | Enables a feature. |
TenantFeatures :: fn disable(& mut self, feature : impl Into <String>) | Disables a feature. |
TenantFeatures :: fn get_config <T : for <'de> Deserialize <'de>>(& self, feature : & str) -> Option <T> | Gets feature configuration. |
pub trait TenantScoped | Trait for entities that belong to a tenant |
TenantMember :: fn tenant_id(& self) -> Uuid | — |
`repo`
| Item | What it is |
|---|---|
async fn create_tenant(pool : & PgPool, name : & str, slug : & str) -> Result <Uuid, TenantError> | Create a new tenant in the database. |
async fn get_tenant_by_id(pool : & PgPool, tenant_id : Uuid,) -> Result <Option <Tenant>, TenantError> | Get a tenant by ID. |
async fn get_tenant_by_slug(pool : & PgPool, slug : & str) -> Result <Option <Tenant>, TenantError> | Get a tenant by slug. |
async fn create_member(pool : & PgPool, tenant_id : Uuid, user_id : Uuid, role : TenantRole,) -> Result <TenantMember, TenantError> | Create a new tenant member (direct add, immediately active). |
async fn create_invited_member(pool : & PgPool, tenant_id : Uuid, user_id : Uuid, role : TenantRole, invited_by : Uuid, expires_in_days : i64,) -> Result <TenantMember, TenantError> | Create an invited tenant member (pending acceptance). |
async fn get_member(pool : & PgPool, tenant_id : Uuid, user_id : Uuid,) -> Result <Option <TenantMember>, TenantError> | Get a member by tenant and user. |
async fn get_member_by_token(pool : & PgPool, invite_token : & str,) -> Result <Option <TenantMember>, TenantError> | Get a member by invite token. |
async fn list_members(pool : & PgPool, tenant_id : Uuid,) -> Result <Vec <TenantMember>, TenantError> | List all active members for a tenant. |
async fn list_tenants_for_user(pool : & PgPool, user_id : Uuid,) -> Result <Vec <(Uuid, TenantRole)>, TenantError> | List tenants for a user (where user is an active member). |
pub struct MembershipDetail | One active membership with the tenant's display fields — for a tenant switcher / login response (Sprint 0.55 US-0.55.8b) |
async fn list_membership_details(pool : & PgPool, user_id : Uuid,) -> Result <Vec <MembershipDetail>, TenantError> | List the user's active memberships with tenant display fields, ordered by tenant name |
async fn accept_invitation(pool : & PgPool, invite_token : & str,) -> Result <Option <TenantMember>, TenantError> | Accept an invitation (set status to active). |
async fn update_member_role(pool : & PgPool, tenant_id : Uuid, user_id : Uuid, new_role : TenantRole,) -> Result <(), TenantError> | Update member role. |
async fn remove_member(pool : & PgPool, tenant_id : Uuid, user_id : Uuid,) -> Result <(), TenantError> | Remove a member (set status to removed). |
async fn is_active_member(pool : & PgPool, tenant_id : Uuid, user_id : Uuid,) -> Result <bool, TenantError> | Check if user is an active member of tenant. |
async fn get_member_role(pool : & PgPool, tenant_id : Uuid, user_id : Uuid,) -> Result <Option <TenantRole>, TenantError> | Get the role of a user in a tenant. |
fn generate_invite_token() -> String | Generate a secure random invite token. |
`service`
| Item | What it is |
|---|---|
pub struct TenantService<'a> | Service for managing tenants (households). |
TenantService<'a> :: fn new(pool : & 'a PgPool) -> Self | Create a new tenant service. |
TenantService<'a> :: async fn create_with_owner(& self, name : & str, slug : & str, owner_user_id : Uuid,) -> Result <(Uuid, TenantMember), TenantError> | Create a new tenant with the creator as owner |
TenantService<'a> :: async fn get_by_id(& self, tenant_id : Uuid) -> Result <Option <Tenant>, TenantError> | Get a tenant by ID. |
TenantService<'a> :: async fn get_by_slug(& self, slug : & str) -> Result <Option <Tenant>, TenantError> | Get a tenant by slug. |
pub struct MemberService<'a> | Service for managing tenant members. |
MemberService<'a> :: fn new(pool : & 'a PgPool) -> Self | Create a new member service. |
MemberService<'a> :: async fn invite(& self, tenant_id : Uuid, user_id : Uuid, role : TenantRole, invited_by : Uuid, expires_in_days : i64,) -> Result <TenantMember, TenantError> | Invite a user to a tenant |
MemberService<'a> :: async fn accept_invitation(& self, invite_token : & str,) -> Result <Option <TenantMember>, TenantError> | Accept an invitation by token. |
MemberService<'a> :: async fn get(& self, tenant_id : Uuid, user_id : Uuid,) -> Result <Option <TenantMember>, TenantError> | Get a member by tenant and user. |
MemberService<'a> :: async fn list(& self, tenant_id : Uuid) -> Result <Vec <TenantMember>, TenantError> | List all members of a tenant. |
MemberService<'a> :: async fn list_tenants_for_user(& self, user_id : Uuid,) -> Result <Vec <(Uuid, TenantRole)>, TenantError> | List all tenants a user is an active member of. |
MemberService<'a> :: async fn update_role(& self, tenant_id : Uuid, user_id : Uuid, new_role : TenantRole, changed_by : Uuid,) -> Result <(), TenantError> | Update a member's role |
MemberService<'a> :: async fn remove(& self, tenant_id : Uuid, user_id : Uuid, removed_by : Uuid,) -> Result <(), TenantError> | Remove a member from a tenant |
MemberService<'a> :: async fn is_active_member(& self, tenant_id : Uuid, user_id : Uuid,) -> Result <bool, TenantError> | Check if user is an active member of tenant. |
MemberService<'a> :: async fn get_role(& self, tenant_id : Uuid, user_id : Uuid,) -> Result <Option <TenantRole>, TenantError> | Get the role of a user in a tenant. |
`tenant_ctx`
| Item | What it is |
|---|---|
pub const GUC_NAME: & str | The Postgres GUC the RLS policies in 002_audit_hardening.sql read |
pub const SYSTEM_SCOPE: & str | The scope bound for a tenant_id IS NULL write (migration 006) |
pub enum TenantScope | The tenant scope a transaction runs under |
TenantScope :: fn for_row_tenant(tenant : Option <Uuid>) -> Self | The scope for writing a row whose tenant_id is tenant |
TenantScope :: fn see_all_if_global(is_global : bool) -> Self | The only path to cross-tenant breadth |
TenantScope :: fn is_see_all(self) -> bool | Whether this scope grants cross-tenant read breadth |
TenantScope :: fn guc_value(self) -> String | The string bound to GUC_NAME |
async fn bind_scope <'c, E>(executor : E, scope : TenantScope) -> Result <(), sqlx::Error> where E : sqlx::Executor <'c, Database = sqlx::Postgres>, | Bind scope for the remainder of the current transaction |
async fn bind_raw_value <'c, E>(executor : E, value : & str) -> Result <(), sqlx::Error> where E : sqlx::Executor <'c, Database = sqlx::Postgres>, | Bind an already-resolved GUC value for the current transaction |
Re-exports. Exported here, defined elsewhere.
| Export | Defined in |
|---|---|
TenantId | tenant_id::TenantId |
Boundary
Reaches into foundation.
Shares tier identity with 7 other crates: identity-auth, identity-identifiers, identity-impersonation, identity-parties, identity-party-places, identity-rbac, identity-user-prefs.
_What this crate deliberately does NOT own is a judgment. No committed registry records one for it, so none is stated here._
Where it sits
| Tier (ontology) | identity |
| Architectural role (taxonomy) | unclassified (baselined) |
| Location | crates/identity/tenant |
| Vocabulary in force (lexicon) | current |
Tier flow. Which tiers this crate's own edges cross.
flowchart LR n_identity["identity"] --> n_foundation["foundation"]
Dependencies
Runtime, in this workspace.
| Crate | Tier | Optional | Only on |
|---|---|---|---|
| `foundation-basemodels` | foundation | no | always |
Runtime, from outside the workspace.
| Crate | Requirement | Features | Optional | Only on |
|---|---|---|---|---|
chrono | ^0.4 | serde | no | always |
hex | ^0.4 | — | no | always |
rand | ^0.8 | — | no | always |
regex | ^1 | — | no | always |
serde | ^1 | derive | no | always |
serde_json | ^1 | — | no | always |
sqlx | ^0.8 | runtime-tokio, postgres, chrono, uuid, json | no | always |
thiserror | ^2 | — | no | always |
uuid | ^1 | v4, v7, serde, js | no | always |
Development, from outside the workspace.
| Crate | Requirement | Features | Optional | Only on |
|---|---|---|---|---|
tokio | ^1 | full | no | always |
Build. None.
Depended on by. 10 workspace crates.
Signal flow — what reaches this crate, and what it reaches.
flowchart LR n_application_audit_log["application-audit-log"] -->|uses| SELF n_application_auth["application-auth"] -->|uses| SELF n_application_dlp["application-dlp"] -->|uses| SELF n_application_rbac["application-rbac"] -->|uses| SELF n_application_tenant["application-tenant"] -->|uses| SELF n_domain_legal_matter["domain-legal-matter"] -->|uses| SELF n_infrastructure_tenant_pool["infrastructure-tenant-pool"] -->|uses| SELF n_operations_control_plane["operations-control-plane"] -->|uses| SELF n_platform_privacy_scan_api["platform-privacy-scan-api"] -->|uses| SELF n_tools_sighting_measure["tools-sighting-measure"] -->|uses| SELF SELF["identity-tenant"] SELF -->|runtime| n_foundation_basemodels["foundation-basemodels"] classDef self fill:#1f883d,stroke:#1f883d,color:#fff; class SELF self;
Feature flags
No Cargo features are defined: every capability is unconditional, so no consumer can receive a half-wired crate.
Targets
| Kind | Name | Source |
|---|---|---|
| lib | identity_tenant | `src/lib.rs` |
| test | pg_runtime_contract | `tests/pg_runtime_contract.rs` |
| test | pg_tenant_ctx | `tests/pg_tenant_ctx.rs` |
| test | tenant_ctx | `tests/tenant_ctx.rs` |
Error model
| Error type | Named by |
|---|---|
TenantError | Result, accept_invitation, create_invited_member, create_member, create_tenant, get_member, … (16 total) |
Operational characteristics
| Property | Evidence |
|---|---|
| async public surface | yes |
| async runtime | none detected |
| database access | yes |
| network I/O | none detected |
| unsafe code | none detected |
| environment variables | none detected |
No unsafe block, unsafe fn, unsafe impl or unsafe trait was found by the parser anywhere in this crate's source.
Configuration
No environment variable is read with a literal name anywhere in this crate. A variable whose key is computed at run time cannot be listed here, and is not claimed to be absent.
Related capabilities
10 workspace crates depend on this one: application-audit-log, application-auth, application-dlp, application-rbac, application-tenant, domain-legal-matter, infrastructure-tenant-pool, operations-control-plane, platform-privacy-scan-api, tools-sighting-measure.
Verification
| Kind | Count |
|---|---|
| Unit tests | 50 |
| Integration tests | 18 |
| Examples | 0 |
| Doctests | 0 |
Evidence by module. How often each public module is named by something executable.
| Module | Tests | Examples | Consumers |
|---|---|---|---|
crate root | 17 | 0 | 26 |
repo | 17 | 0 | 3 |
service | 2 | 0 | 1 |
tenant_ctx | 5 | 0 | 13 |
What the tests establish, by name:
a_bound_tenant_can_write_and_read_its_own_rows—tests/pg_runtime_contract.rsa_system_write_can_append_a_tenantless_row_without_read_breadth—tests/pg_runtime_contract.rscontext_does_not_survive_onto_the_next_request—tests/pg_runtime_contract.rstenant_a_cannot_read_or_write_tenant_b—tests/pg_runtime_contract.rswithout_tenant_context_the_contract_fails_closed_and_loudly—tests/pg_runtime_contract.rsa_bound_scope_is_visible_inside_its_transaction—tests/pg_tenant_ctx.rsa_committed_scope_does_not_leak_to_the_next_checkout—tests/pg_tenant_ctx.rsa_rolled_back_scope_also_does_not_leak—tests/pg_tenant_ctx.rsthe_unresolved_scope_binds_a_value_matching_no_tenant—tests/pg_tenant_ctx.rsa_global_actor_may_widen_and_it_is_the_only_path_to_see_all—tests/tenant_ctx.rsa_non_global_actor_cannot_widen_to_see_all—tests/tenant_ctx.rsa_scoped_tenant_binds_its_own_id—tests/tenant_ctx.rsa_tenant_scope_round_trips_through_an_optional_tenant_id—tests/tenant_ctx.rsonly_the_primitive_binds_the_tenant_guc—tests/tenant_ctx.rsscoped_and_system_scopes_are_never_see_all—tests/tenant_ctx.rssystem_write_no_longer_has_to_take_see_all_breadth—tests/tenant_ctx.rsthe_guc_name_has_exactly_one_definition—tests/tenant_ctx.rsunresolved_binds_a_value_that_matches_no_tenant_row—tests/tenant_ctx.rstest_custom_quotas—src/lib.rstest_in_memory_resolver—src/lib.rstest_isolation_strategy_display—src/lib.rstest_member_status_default—src/lib.rstest_member_status_display—src/lib.rstest_tenant_activate—src/lib.rstest_tenant_context_from_tenant—src/lib.rstest_tenant_deactivate—src/lib.rstest_tenant_domains—src/lib.rstest_tenant_effective_schema—src/lib.rstest_tenant_error_display—src/lib.rstest_tenant_features—src/lib.rs- _… 38 more_
Documentation coverage
| Measure | Documented | Total |
|---|---|---|
| Public items with rustdoc | 98 | 109 |
Public modules with a //! block | 3 | 3 |
pie showData
title Public items with rustdoc
"Documented" : 98
"No rustdoc detected" : 11
Metrics
| Metric | Value |
|---|---|
| Rust source files | 5 |
| Source lines | 2406 |
| Code lines | 1690 |
| Public API items | 109 |
| Public modules | 3 |
| Tests | 68 |
| Examples | 0 |
| Cargo features | 0 |
| Direct runtime dependencies | 10 |
| Workspace reverse dependencies | 10 |
pie showData
title Public API by kind
"constant" : 2
"enum" : 7
"function" : 19
"method" : 68
"struct" : 10
"trait" : 2
"type alias" : 1
pie showData
title Rust source composition
"Code" : 1690
"Blank or comment" : 716
Generation
Rendered by tools-corpus corpus readme from repository evidence alone, renderer schema 2, lexicon current. No model, network service or database was consulted. Regenerate with tools-corpus corpus readme --write; verify with --check.