Multi-Tenant Architecture: 5-Level Isolation Model
TL;DR
Multi-Tenant Architecture: 5-Level Isolation Model
“Series: S2 Architecture Overview · Article 5 | Level: Intermediate | Reading Time: 18 min
TL;DR
- coomia-dip uses a Tenant → Org → Space → Project → World 5-level isolation model, where each level has clearly defined resource boundaries and permission scopes. Compared to a flat "tenant-user" two-level model, 5-level isolation better maps the real-world complexity of enterprise organizational structures.
- Data isolation at the Project level is achieved through Doris Database-per-Project for physical isolation, while the World level uses Nessie Branch for logical isolation. The combination ensures absolute cross-tenant isolation and flexible version management within the same project.
- Auto-Provisioning automatically initializes all necessary resources when a new level is created -- Doris databases, Nessie branches, Kafka topics, MinIO buckets -- transforming "submit a ticket and wait 3 days" into "make an API call and wait 3 seconds."
#1. Introduction: Why 5 Levels
Most SaaS platforms have a two-level multi-tenancy model: Tenant and User. This works for simple scenarios, but problems emerge when your customers are large enterprise groups.
Consider a real-world scenario:
Huaneng Group (Tenant)
├── Huaneng International (subsidiary → Org)
│ ├── East China Branch (business unit → Space)
│ │ ├── Smart O&M Project (project → Project)
│ │ │ ├── Production Environment (world → World)
│ │ │ └── Test Environment (world → World)
│ │ └── Carbon Monitoring Project (project → Project)
│ └── South China Branch (business unit → Space)
├── Huaneng Renewables (subsidiary → Org)
│ └── Wind Power Division (business unit → Space)
│ └── Wind Turbine Health Monitoring (project → Project)
└── Huaneng Nuclear (subsidiary → Org)
If you force-fit a two-level model:
- Can East China Branch O&M engineers see South China Branch data? They should not.
- Can test environment data in the Smart O&M Project affect production? Absolutely not.
- Can Huaneng International managers see Huaneng Renewables wind data? Depends on group policy.
A two-level model cannot express these requirements. You either write extensive custom permission logic or accept security gaps. coomia-dip's 5-level isolation model was designed to solve exactly this problem.
#2. The 5-Level Isolation Model in Detail
#2.1 Level Definitions
Level 1: Tenant
│ Highest isolation boundary. Different tenants are completely invisible to each other.
│ Typical mapping: enterprise group, independent company
│
├─ Level 2: Org (Organization)
│ │ Legal entity or independent accounting unit. Different orgs under the same tenant
│ │ are invisible by default and require explicit authorization.
│ │ Typical mapping: subsidiary, business division
│ │
│ ├─ Level 3: Space
│ │ │ Business collaboration unit. Different teams or departments within an org.
│ │ │ Visible by default within the same org; permissions can be refined.
│ │ │ Typical mapping: department, regional branch, business line
│ │ │
│ │ ├─ Level 4: Project
│ │ │ │ Independent data domain. Owns its own Doris Database.
│ │ │ │ Typical mapping: business project, application system
│ │ │ │
│ │ │ ├─ Level 5: World
│ │ │ │ Versioned instance of a project. Nessie Branch isolation.
│ │ │ │ Typical mapping: production env, test env, simulation sandbox
#2.2 Isolation Mechanisms at Each Level
| Level | Isolation Type | Technical Implementation | Cross-Level Visibility |
|---|---|---|---|
| Tenant | Absolute isolation | Independent identity domain + independent encryption keys | Never cross-tenant |
| Org | Strong isolation | Independent permission tree + independent quotas | Requires tenant admin explicit authorization |
| Space | Logical isolation | RBAC role domain + resource labels | Discoverable within same org by default |
| Project | Data isolation | Doris Database-per-Project | Requires Space-level authorization |
| World | Version isolation | Nessie Branch-per-World | Switchable within same Project |
#2.3 WorldContext: The Object That Spans All 5 Levels
In coomia-dip, every gRPC call must carry a WorldContext, which is the runtime representation of the 5-level isolation model:
message WorldContext {
string tenant_id = 1; // Level 1: Tenant
string org_id = 2; // Level 2: Organization
string space_id = 3; // Level 3: Space
string project_id = 4; // Level 4: Project
string world_id = 5; // Level 5: World
// Authentication info
string principal_id = 6; // Current user
repeated string roles = 7; // User role list
map<string, string> claims = 8; // Additional claims (for ABAC)
}
This object is constructed starting from the API Gateway and propagated throughout the entire request chain, ensuring every component knows which isolation level the current operation executes within.
#3. Technical Implementation of Data Isolation
#3.1 Level 4 Isolation: Doris Database-per-Project
Each Project owns an independent Doris Database. This is not using a project_id column to distinguish data within the same database -- that would be logical isolation; this is true physical isolation.
Doris Instance (shared)
├── database: proj_huaneng_ops_001
│ ├── entity_common (object instances)
│ ├── entity_edge (relation instances)
│ ├── entity_event (event records)
│ └── entity_metric (metric data)
│
├── database: proj_huaneng_carbon_002
│ ├── entity_common
│ ├── entity_edge
│ ├── entity_event
│ └── entity_metric
│
├── database: proj_wind_health_003
│ ├── entity_common
│ ├── entity_edge
│ ├── entity_event
│ └── entity_metric
Why Database-per-Project instead of Database-per-Tenant?
Comparison:
Database-per-Tenant:
├── Pros: Simpler management, fewer databases
├── Cons: Different projects under same tenant share a Database
│ → One project's heavy query affects other projects
│ → DDL changes need coordination across all projects in the tenant
│ → Cannot configure independent resource quotas per project
└── Verdict: ❌ Isolation granularity too coarse
Database-per-Project:
├── Pros: Independent resource quotas and performance isolation per project
│ → Heavy queries don't affect other projects
│ → DDL changes only affect the current project
│ → Can scale independently
├── Cons: More databases (but Doris supports thousands of databases)
└── Verdict: ✅ Optimal balance
Database-per-World:
├── Pros: Maximum isolation
├── Cons: Database count explodes (each project may have 10+ Worlds)
│ → Severe resource waste
│ → Cross-World queries become nearly impossible
└── Verdict: ❌ Over-isolation
#3.2 Level 5 Isolation: Nessie Branch-per-World
World-level isolation is achieved through Nessie branches. Nessie is a Git-like data lakehouse catalog manager that works with the Iceberg table format.
Nessie Repository (per Project)
├── Branch: world_production ← Production environment
│ └── Iceberg Tables:
│ ├── entity_common (pointing to Iceberg snapshot S-2024-001)
│ ├── entity_edge (pointing to Iceberg snapshot S-2024-002)
│ └── entity_event (pointing to Iceberg snapshot S-2024-003)
│
├── Branch: world_staging ← Staging environment
│ └── Iceberg Tables:
│ ├── entity_common (pointing to Iceberg snapshot S-2024-004)
│ ├── entity_edge (inherited from production)
│ └── entity_event (inherited from production)
│
├── Branch: world_sandbox_alice ← Alice's sandbox
│ └── Iceberg Tables: (forked from production)
│ └── ...
│
└── Branch: world_whatif_q3 ← Q3 planning simulation
└── Iceberg Tables: (forked from production)
└── ...
Key Properties of Nessie Branches:
- O(1) Creation: Creating a new World only requires creating a Nessie branch, which is a metadata operation taking < 100ms. No data copying required.
- Copy-on-Write: A new World shares all Iceberg data files with its parent World. New data files are only created when writes occur in the new World.
- Mergeable: Modifications in a sandbox can be merged back into production via Nessie Merge, similar to Git merge.
- Time Travel: Each World retains a complete version history, allowing rollback to any point in time.
#3.3 Doris + Nessie Working Together
Read operation routing:
Request arrives → Extract WorldContext
→ project_id → Determine Doris Database
→ world_id → Determine Nessie Branch
Case 1: Real-time data query (hot data)
→ Query Doris Database (project_id)
→ Inject world_id filter in SQL
→ Return results
Case 2: Historical data query / time travel
→ Query Nessie Branch (world_id)
→ Get Iceberg snapshot at specified time
→ Query through Doris Iceberg Catalog
→ Return results
Case 3: Cross-World comparison
→ Query two Nessie Branches simultaneously
→ Compare differences between two Iceberg snapshots
→ Return diff results
#4. Compute Isolation
#4.1 Resource Quota Model
Compute isolation ensures one tenant's/project's workload does not affect others. coomia-dip enforces resource quotas at multiple levels:
Tenant Level Quota:
├── max_orgs: 50
├── max_total_storage: 10TB
├── max_concurrent_queries: 1000
└── max_api_calls_per_minute: 10000
Org Level Quota:
├── max_spaces: 20
├── max_storage: 2TB (cannot exceed Tenant limit)
└── max_concurrent_queries: 200
Space Level Quota:
├── max_projects: 10
└── max_storage: 500GB
Project Level Quota:
├── max_worlds: 20
├── doris_database_size_limit: 100GB
├── max_concurrent_queries: 50
├── max_object_count: 10,000,000
└── max_derived_property_computations_per_minute: 1000
World Level Quota:
├── max_nessie_branch_size: 50GB (Iceberg data)
├── max_concurrent_users: 100
└── max_event_rate: 500/second
#4.2 Query Resource Isolation
Doris's Workload Group feature is used to implement query-level resource isolation:
-- Create Workload Group per Project
CREATE WORKLOAD GROUP proj_huaneng_ops_001
PROPERTIES (
'cpu_share' = '10',
'memory_limit' = '30%',
'max_concurrency' = '50',
'max_queue_size' = '100',
'queue_timeout' = '5000'
);
-- Queries automatically bind to the Workload Group
SET workload_group = 'proj_huaneng_ops_001';
SELECT ... FROM entity_common WHERE ...;
This ensures that even if a project user executes an extremely resource-intensive query, other projects' query performance is unaffected.
#4.3 Reasoning Compute Isolation
Reasoning & Decision Layer (Reasoning & Decision) compute tasks -- rule engine, derived property computation, AI reasoning -- are isolated through Kubernetes namespaces and resource limits:
# One Kubernetes Namespace per Tenant
apiVersion: v1
kind: Namespace
metadata:
name: tenant-huaneng
labels:
coomia-dip/tenant-id: "huaneng"
---
# ResourceQuota limits tenant compute resources
apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-quota
namespace: tenant-huaneng
spec:
hard:
requests.cpu: "32"
requests.memory: "64Gi"
limits.cpu: "64"
limits.memory: "128Gi"
pods: "100"
#5. Permission Inheritance Model
#5.1 Inheritance Direction: Top-Down
Permissions inherit top-down through the 5-level model. Higher-level permissions automatically propagate to lower levels:
Tenant Admin
│ Has full management permissions for all resources under the tenant
│
├── Org Admin
│ │ Has management permissions for all Spaces, Projects, Worlds under the org
│ │ Inherited from Tenant Admin's authorization
│ │
│ ├── Space Admin
│ │ │ Has management permissions for all Projects, Worlds under the space
│ │ │
│ │ ├── Project Member
│ │ │ │ Has operational permissions for all Worlds under the project
│ │ │ │
│ │ │ └── World Viewer
│ │ │ Can only view data in a specific World
#5.2 Permission Override Rules
Rule 1: Higher-level authorization → Lower-level automatic inheritance
Org Admin authorized for OrgA → Automatically has permissions for all Spaces under OrgA
Rule 2: Lower levels can tighten but not expand
Space Admin cannot grant permissions beyond what Org Admin provided
Rule 3: Explicit DENY takes precedence over inherited ALLOW
Even if Org Admin allows access, a Space-level explicit DENY still takes effect
Rule 4: Cross-level authorization requires admin
Adding an Org A user to Org B's Space requires Tenant Admin
Priority chain:
Explicit DENY > Explicit ALLOW > Inherited DENY > Inherited ALLOW > Default DENY
#5.3 RBAC + ABAC Hybrid Model
RBAC handles "what a role can do"; ABAC handles "under what conditions it can do it":
RBAC Role Definitions (customizable per Space):
Role: DataEngineer
Permissions:
- ObjectType.* : READ
- ObjectType.create : ALLOW (limited to data-source types)
- Pipeline.* : READ, WRITE, EXECUTE
- World.switch : ALLOW
Role: DataAnalyst
Permissions:
- ObjectType.* : READ
- DerivedProperty.* : READ, CREATE
- Search.* : READ
- Export.* : ALLOW (limit 1000 rows)
Role: BusinessUser
Permissions:
- Dashboard.* : READ
- Action.execute : ALLOW (limited to approved types)
- World.switch : DENY (can only see production World)
ABAC Policy Examples:
Policy: "sensitive-data-time-restriction"
Condition:
resource.classification == "CONFIDENTIAL"
AND time.hour < 8 OR time.hour > 20
Effect: DENY
Reason: "Confidential data accessible only during business hours"
Policy: "geo-restriction"
Condition:
resource.region != principal.department_region
Effect: DENY
Reason: "Can only access data from your own region"
Policy: "data-volume-limit"
Condition:
request.type == "EXPORT"
AND request.row_count > 10000
AND principal.role != "DataEngineer"
Effect: DENY
Reason: "Non-engineer roles cannot export more than 10,000 rows"
#6. Auto-Provisioning
#6.1 Pain Points of Traditional Processes
The traditional process for creating a new project environment in enterprise platforms typically looks like this:
Day 1: Submit ticket → "Please create a new database instance"
Day 2: DBA approves → Queued waiting
Day 3: DBA creates database → Configures user permissions
Day 4: Submit ticket → "Please create new Kafka Topics"
Day 5: Messaging admin approves → Creates Topics
Day 6: Submit ticket → "Please create MinIO Bucket"
Day 7: Storage admin approves → Creates Bucket
Day 8: Start development → Discover missing Nessie config
Day 9: ...
Total time: 1-2 weeks
People involved: 3-5 different teams
Failure probability: ~30% (some step missed or misconfigured)
#6.2 Auto-Provisioning Architecture
coomia-dip automates this entire process through the Auto-Provisioning mechanism:
Creating a new Project:
API: POST /api/v1/admin/projects
ProjectProvisioner automatically executes:
├── Step 1: Validate quotas (1ms)
│ ├── Check if Project count under Space exceeds limit
│ ├── Check if storage quota is sufficient
│ └── Check if compute resources are allocatable
│
├── Step 2: Create Doris Database (200ms)
│ ├── CREATE DATABASE proj_{tenant}_{name}_{id}
│ ├── CREATE TABLE entity_common (...)
│ ├── CREATE TABLE entity_edge (...)
│ ├── CREATE TABLE entity_event (...)
│ ├── CREATE WORKLOAD GROUP proj_{id} (...)
│ └── GRANT SELECT, INSERT, UPDATE ON proj_{id}.* TO svc_account
│
├── Step 3: Create Nessie Repository (100ms)
│ ├── Create Nessie Namespace
│ ├── Create main Branch (default World)
│ └── Initialize Iceberg table metadata
│
├── Step 4: Create Kafka Topics (300ms)
│ ├── proj_{id}.data-change (data change events, 12 partitions)
│ ├── proj_{id}.audit.access (audit logs, 6 partitions)
│ ├── proj_{id}.audit.mutation (audit logs, 6 partitions)
│ ├── proj_{id}.subscription (subscription routing, 6 partitions)
│ └── proj_{id}.derived-property (derived property cascade, 6 partitions)
│
├── Step 5: Create MinIO Bucket (50ms)
│ ├── Create bucket: proj-{id}
│ ├── Set lifecycle policy
│ └── Configure access policy
│
├── Step 6: Create Redis Namespace (10ms)
│ ├── Configure key prefix: proj:{id}:
│ └── Set memory quota
│
├── Step 7: Initialize metadata (50ms)
│ ├── Register Project metadata in PostgreSQL
│ ├── Create default roles and permissions
│ └── Record provisioning audit log
│
└── Done! Total time: ~800ms
From "submit a ticket, wait 1 week" to "API call, wait 1 second"
#6.3 Rapid World Creation
Creating a new World is even faster than creating a Project because Worlds share the Project's Doris Database:
Creating a new World:
WorldProvisioner automatically executes:
├── Step 1: Validate quotas (1ms)
│ └── Check if World count under Project exceeds limit
│
├── Step 2: Create Nessie Branch (50ms)
│ ├── Fork from source Branch (usually production)
│ └── Pure metadata operation, no data copying
│
├── Step 3: Initialize World context (20ms)
│ ├── Register World metadata
│ └── Create permission records for world_id
│
└── Done! Total time: ~80ms
Creating a new simulation sandbox: 80ms
The sandbox has exactly the same data as production (Copy-on-Write)
Modifications in the sandbox do not affect production
#6.4 Auto-Deprovisioning
When deleting a Project or World, Auto-Deprovisioning automatically cleans up all associated resources:
Deleting a Project:
ProjectDeprovisioner automatically executes:
├── Step 1: Verify no active connections (10ms)
├── Step 2: Create final snapshot to MinIO (async, non-blocking)
├── Step 3: Delete Kafka Topics (200ms)
├── Step 4: Delete Nessie Repository (100ms)
├── Step 5: DROP DATABASE proj_{id} (500ms)
├── Step 6: Clean Redis namespace (10ms)
├── Step 7: Mark MinIO Bucket for expiration (not immediate; auto-cleanup in 30 days)
├── Step 8: Update PostgreSQL metadata (10ms)
└── Step 9: Record cleanup audit log (5ms)
Data retention policy:
- Doris data: Deleted immediately
- MinIO data: Retained 30 days (recoverable)
- Audit logs: Retained per topic retention period
- PostgreSQL metadata: Soft delete, retained 90 days
#7. Cross-Level Queries and Data Sharing
#7.1 Cross-World Queries
Different Worlds within the same Project can be compared, forming the foundation of the "simulation sandbox" feature:
Scenario: Compare data differences between production and sandbox
API: POST /api/v1/ontology/worlds/compare
{
"source_world": "world_production",
"target_world": "world_sandbox_q3",
"object_type": "InventoryItem",
"compare_properties": ["quantity", "reorder_point"]
}
Internal implementation:
1. Get production Nessie Branch → Iceberg snapshot A
2. Get sandbox_q3 Nessie Branch → Iceberg snapshot B
3. Iceberg provides snapshot-level diff:
- Added data files
- Deleted data files
- Modified rows (via position-delete files)
4. Return diff results
#7.2 Cross-Project Data Sharing
Different Projects cannot query each other by default, but specific ObjectTypes can be shared through the DataLink mechanism:
DataLink Definition:
{
"link_name": "shared_equipment_catalog",
"source_project": "proj_asset_management",
"source_object_type": "Equipment",
"target_project": "proj_maintenance",
"exposed_properties": ["name", "location", "model", "install_date"],
"hidden_properties": ["purchase_price", "depreciation"],
"access_mode": "READ_ONLY",
"sync_mode": "REAL_TIME" // Real-time sync via Kafka CDC
}
DataLink ensures:
- The target Project can only see explicitly exposed properties
- Data is provided in read-only mode
- Access still goes through OntologyRuntimeService, subject to permission checks and auditing
- Data lineage automatically records cross-Project dependencies
#7.3 Absolute Cross-Tenant Isolation
Cross-tenant data sharing is absolutely prohibited. No DataLinks, no admin backdoors, no mechanism exists to let Tenant A see Tenant B's data.
Isolation guarantees:
1. Identity isolation: tenant_id in Tenant A's user Token
will never match Tenant B's resource tenant_id
2. Network isolation: gRPC requests from different Tenants carry different TLS certificates
3. Storage isolation: Doris Database names include tenant_id
SQL injection cannot cross Database boundaries (Doris permission control)
4. Cache isolation: Redis key prefixes include tenant_id
Even cache penetration cannot return other tenants' data
5. Audit isolation: tenant_id in audit logs cannot be forged
Extracted from auth Token by API Gateway and injected
#8. Deployment Topologies
#8.1 Small-Scale Deployment (< 10 tenants)
┌─────────────────────────────────────────┐
│ Shared Infrastructure │
│ │
│ ┌─────────┐ ┌──────┐ ┌──────────┐ │
│ │ Doris │ │Kafka │ │PostgreSQL│ │
│ │ (shared) │ │(shared)│ │ (shared) │ │
│ │ │ │ │ │ │ │
│ │ DB: t1p1 │ │ │ │ │ │
│ │ DB: t1p2 │ │ │ │ │ │
│ │ DB: t2p1 │ │ │ │ │ │
│ └─────────┘ └──────┘ └──────────┘ │
│ │
│ ┌──────┐ ┌──────┐ ┌──────────────┐ │
│ │Redis │ │MinIO │ │Nessie+Iceberg│ │
│ │(shared)│ │(shared)│ │ (shared) │ │
│ └──────┘ └──────┘ └──────────────┘ │
│ │
│ Isolation: Database / Branch / Namespace│
└─────────────────────────────────────────┘
#8.2 Large-Scale Deployment (100+ tenants)
┌──────────────────────────────────────────────┐
│ Tenant Group A (Financial Clients) │
│ │
│ ┌─────────┐ ┌──────┐ ┌──────────────┐ │
│ │ Doris │ │Kafka │ │Nessie+Iceberg│ │
│ │ Cluster │ │Cluster│ │ Cluster │ │
│ │(dedicated)│ │(dedicated)│ │(dedicated) │ │
│ └─────────┘ └──────┘ └──────────────┘ │
│ │
│ Features: Independent clusters, physical │
│ isolation, compliance certified │
└──────────────────────────────────────────────┘
┌──────────────────────────────────────────────┐
│ Tenant Group B (Manufacturing, shared) │
│ │
│ ┌─────────┐ ┌──────┐ ┌──────────────┐ │
│ │ Doris │ │Kafka │ │Nessie+Iceberg│ │
│ │ Cluster │ │Cluster│ │ Cluster │ │
│ │ (shared) │ │(shared)│ │ (shared) │ │
│ └─────────┘ └──────┘ └──────────────┘ │
│ │
│ Features: Shared clusters, logical │
│ isolation, cost optimized │
└──────────────────────────────────────────────┘
#8.3 Hybrid Deployment Strategy
Decision Matrix:
┌─────────────────┬──────────────┬───────────────┐
│ Client Type │ Isolation │ Deployment │
├─────────────────┼──────────────┼───────────────┤
│ Finance/Health │ Physical │ Dedicated │
│ Government │ Physical │ Dedicated │
│ Large Mfg │ Hybrid │ Shared+Ded DB │
│ SMB │ Logical │ Shared │
│ Trial/POC │ Logical │ Shared │
└─────────────────┴──────────────┴───────────────┘
#9. Monitoring and Alerting
#9.1 Multi-Tenant Monitoring Dimensions
Level 1 Monitoring (Tenant):
- API calls / minute
- Total storage usage
- Active user count
- Error rate
Level 4 Monitoring (Project):
- Doris Database size
- Query QPS and P99 latency
- Workload Group resource utilization
- Kafka Topic consumption lag
Level 5 Monitoring (World):
- Nessie Branch size
- Active connections
- Event publishing frequency
- Derived property computation queue length
#9.2 Noisy Neighbor Detection
Noisy Neighbor Detection:
Trigger conditions:
1. A Project's Doris query latency > 2x P95
2. A Project's Kafka production rate > 80% of quota
3. A Project's CPU usage > 90% of Workload Group limit
Automatic response:
1. Alert notification → Project owner + platform ops
2. Auto-throttle → Reduce the Project's concurrency limit
3. Query logging → Record queries causing high load
4. Optimization suggestions → Auto-analyze slow queries and suggest indexes
#10. Comparison with Palantir Foundry Multi-Tenancy
| Dimension | Palantir Foundry | coomia-dip |
|---|---|---|
| Isolation levels | 3 (Enrollment → Org → Project) | 5 (+Space +World) |
| Versioning | Dataset-level Transaction | World-level Nessie Branch |
| Data isolation | Shared HDFS + ACL | Database-per-Project |
| Compute isolation | Spark resource pools | Doris Workload Group + K8s Namespace |
| Simulation sandbox | Branch (AIP feature) | World (native support) |
| Auto-provisioning | Enrollment process (manual approval) | API-driven (< 1 second) |
coomia-dip's 5-level model has two more levels than Foundry -- Space and World. Space better maps enterprise internal department structures, while World provides native "simulation sandbox" capability -- something that requires Foundry's AIP (AI Platform) advanced features.
#11. Common Questions and Best Practices
#11.1 When to Create a New Org vs Space
Create a new Org:
- Independent legal entity (subsidiary)
- Needs independent billing
- Requires fully independent admin
- Data not shared by default
Create a new Space:
- Department within the same legal entity
- Shared billing
- May need cross-department collaboration
- Data discoverable within org by default
#11.2 When to Create a New World
Must create a new World:
- Test/staging environment → Avoid affecting production data
- What-if simulation → Modify data without affecting real environment
- Data migration validation → Test Schema changes in sandbox
- Training environment → Provide safe practice space for new users
No need for a new World:
- Simple permission isolation → RBAC/ABAC is sufficient
- Different views/dashboards → Dashboard configuration is sufficient
- Historical data viewing → Time travel (Nessie snapshots) is sufficient
#Key Takeaways
-
The 5-level isolation model maps the real complexity of enterprise organizations. The Tenant → Org → Space → Project → World hierarchy adds 3 critical dimensions beyond a flat "tenant-user" model: Org maps legal entities, Space maps business units, World maps versioned environments. Each additional isolation level provides finer-grained permission management and resource control.
-
The "dual insurance" design for data isolation is key. Doris Database-per-Project provides physical-level data isolation; Nessie Branch-per-World provides logical-level version isolation. The former ensures zero possibility of data leakage between projects; the latter makes multi-version management within a project lightweight and zero-cost (O(1) branch creation, Copy-on-Write data sharing).
-
Auto-Provisioning reduces environment creation from weeks to seconds. Traditional enterprises need 1-2 weeks and coordination among 3-5 teams to create a new project environment. coomia-dip completes creation of Doris Database, Nessie Repository, Kafka Topics, and MinIO Bucket in < 1 second through automated provisioning. This is not just an efficiency improvement -- it changes how teams use environments: from "carefully using scarce environments" to "creating disposable sandboxes on demand."
“Next Article Preview: [S2-06] Event-Driven Architecture: Kafka's 7 Roles -- a deep dive into how Kafka serves 7 distinct roles: CDC, audit, subscription routing, pipeline triggers, derived property cascade, reasoning triggers, and cross-Layer coordination.
Tags: #multi-tenant #isolation #world #nessie #doris #auto-provisioning #rbac #abac #coomia-dip