Skip to main content

05_tenant_hierarchy/
05_tenant_hierarchy.rs

1//! Tenant Hierarchy
2//!
3//! This example demonstrates:
4//! - Creating nested tenant structures (root → department → team)
5//! - Hierarchical tenant IDs
6//! - Querying tenant ancestors and descendants
7//!
8//! Scenario: An organization with departments and teams.
9//!
10//! Run with: `cargo run --example 05_tenant_hierarchy`
11
12use std::sync::Arc;
13use tokio::sync::RwLock;
14use wami::arn::{TenantPath, WamiArn};
15use wami::context::WamiContext;
16use wami::service::TenantService;
17use wami::store::memory::InMemoryWamiStore;
18
19#[tokio::main]
20async fn main() -> Result<(), Box<dyn std::error::Error>> {
21    println!("=== Tenant Hierarchy ===\n");
22
23    let store = Arc::new(RwLock::new(InMemoryWamiStore::default()));
24
25    // Create root context
26    let root_context = WamiContext::builder()
27        .instance_id("123456789012")
28        .tenant_path(TenantPath::single(0)) // Root tenant ID is 0
29        .caller_arn(
30            WamiArn::builder()
31                .service(wami::arn::Service::Iam)
32                .tenant_path(TenantPath::single(0))
33                .wami_instance("123456789012")
34                .resource("user", "admin")
35                .build()?,
36        )
37        .is_root(true)
38        .build()?;
39
40    let tenant_service = TenantService::new(store.clone());
41
42    // === CREATE HIERARCHICAL TENANTS ===
43    println!("Step 1: Creating hierarchical tenant structure...\n");
44
45    // Root: acme-corp
46    println!("Creating root tenant: acme-corp");
47    let root_tenant = tenant_service
48        .create_tenant(
49            &root_context,
50            "acme-corp".to_string(),
51            Some("ACME Corporation".to_string()),
52            None,
53        )
54        .await?;
55    let root_id = root_tenant.id.clone();
56    println!("✓ Created: acme-corp (ID: {})", root_id);
57
58    // Department level: engineering, sales
59    println!("\nCreating department tenants...");
60    let eng_tenant = tenant_service
61        .create_tenant(
62            &root_context,
63            "engineering".to_string(),
64            Some("Engineering Department".to_string()),
65            Some(root_id.clone()),
66        )
67        .await?;
68    let eng_id = eng_tenant.id.clone();
69    println!("✓ Created: acme-corp/engineering (ID: {})", eng_id);
70
71    let sales_tenant = tenant_service
72        .create_tenant(
73            &root_context,
74            "sales".to_string(),
75            Some("Sales Department".to_string()),
76            Some(root_id.clone()),
77        )
78        .await?;
79    let _sales_id = sales_tenant.id.clone();
80    println!("✓ Created: acme-corp/sales (ID: {})", _sales_id);
81
82    // Team level under engineering: backend, frontend
83    println!("\nCreating team tenants under engineering...");
84    let backend_tenant = tenant_service
85        .create_tenant(
86            &root_context,
87            "backend".to_string(),
88            Some("Backend Team".to_string()),
89            Some(eng_id.clone()),
90        )
91        .await?;
92    let backend_id = backend_tenant.id.clone();
93    println!(
94        "✓ Created: acme-corp/engineering/backend (ID: {})",
95        backend_id
96    );
97
98    let frontend_tenant = tenant_service
99        .create_tenant(
100            &root_context,
101            "frontend".to_string(),
102            Some("Frontend Team".to_string()),
103            Some(eng_id.clone()),
104        )
105        .await?;
106    let _frontend_id = frontend_tenant.id.clone();
107    println!(
108        "✓ Created: acme-corp/engineering/frontend (ID: {})",
109        _frontend_id
110    );
111
112    // === QUERY HIERARCHY ===
113    println!("\n\nStep 2: Querying tenant hierarchy...\n");
114
115    // List all tenants
116    let all_tenants = tenant_service.list_tenants().await?;
117    println!("Total tenants created: {}", all_tenants.len());
118    for tenant in &all_tenants {
119        println!("  - {} (ID: {})", tenant.name, tenant.id);
120    }
121
122    // Get ancestors of backend team
123    println!("\nAncestors of 'backend' team:");
124    let backend_ancestors = tenant_service.get_ancestors(&backend_id).await?;
125    println!("  Found {} ancestors", backend_ancestors.len());
126    for ancestor in &backend_ancestors {
127        println!("    ← {} ({})", ancestor.name, ancestor.id);
128    }
129
130    // Get children of engineering department
131    println!("\nChildren of 'engineering' department:");
132    let eng_children = tenant_service.list_child_tenants(&eng_id).await?;
133    println!("  Found {} children", eng_children.len());
134    for child in &eng_children {
135        println!("    → {}", child.name);
136    }
137
138    // Get all descendants of root
139    println!("\nAll descendants of 'acme-corp' (recursive):");
140    let root_descendants = tenant_service.get_descendants(&root_id).await?;
141    println!("  Found {} descendants", root_descendants.len());
142    for descendant in &root_descendants {
143        println!("    → {}", descendant);
144    }
145
146    // === DEMONSTRATE HIERARCHY BENEFITS ===
147    println!("\n\nStep 3: Understanding hierarchy benefits...\n");
148
149    println!("Hierarchy visualization:");
150    println!("acme-corp (root)");
151    println!("├── engineering");
152    println!("│   ├── backend");
153    println!("│   └── frontend");
154    println!("└── sales");
155
156    println!("\n✅ Example completed successfully!");
157    println!("Key takeaways:");
158    println!("- TenantId supports hierarchical structures with .child()");
159    println!("- Ancestors represent the path from tenant to root");
160    println!("- Descendants include all child tenants recursively");
161    println!("- Hierarchies enable organizational modeling and quota inheritance");
162
163    Ok(())
164}