Multitenencia
Resumen
Sección titulada «Resumen»Greentic está diseñado desde cero para despliegues multi-tenant. Cada aspecto de la plataforma soporta el aislamiento de tenants, lo que permite que un solo despliegue atienda de forma segura a múltiples organizaciones.
Jerarquía de tenants
Sección titulada «Jerarquía de tenants»Workspace└── Tenant (organization) └── Environment (prod, staging, dev) └── Team (department, group) └── Channel (messaging provider instance) └── Session (user conversation)TenantCtx
Sección titulada «TenantCtx»La estructura TenantCtx fluye a través de todas las operaciones:
pub struct TenantCtx { pub tenant_id: String, pub env_id: String, pub team_id: Option<String>,}Cada llamada a la API, ejecución de flow y acceso a datos está delimitado por un TenantCtx.
Configuración
Sección titulada «Configuración»Definición de tenant
Sección titulada «Definición de tenant»tenant: id: acme name: "ACME Corporation" settings: timezone: "America/New_York" language: "en-US"
environments: - id: prod name: "Production" - id: staging name: "Staging"Definición de team
Sección titulada «Definición de team»team: id: support name: "Customer Support" tenant_id: acme
channels: slack: provider: messaging-slack config: workspace_id: "T123456" channel_id: "C789012"
telegram: provider: messaging-telegram config: chat_id: "-1001234567890"Configuración del bundle
Sección titulada «Configuración del bundle»tenants: acme: name: "ACME Corporation" teams: support: name: "Customer Support" channels: slack: provider: messaging-slack telegram: provider: messaging-telegram
sales: name: "Sales Team" channels: teams: provider: messaging-teams
bigcorp: name: "BigCorp Inc." teams: helpdesk: channels: webchat: provider: messaging-webchatAislamiento de datos
Sección titulada «Aislamiento de datos»Almacenamiento de sesiones
Sección titulada «Almacenamiento de sesiones»Las sesiones se aíslan por contexto de tenant:
sessions/├── acme/│ ├── prod/│ │ ├── support/│ │ │ ├── session_001.cbor│ │ │ └── session_002.cbor│ │ └── sales/│ │ └── session_003.cbor│ └── staging/│ └── support/│ └── session_004.cbor└── bigcorp/ └── prod/ └── helpdesk/ └── session_005.cborAislamiento de estado
Sección titulada «Aislamiento de estado»La memoria de trabajo (state) se delimita por sesión:
// State key formatlet key = format!( "state:{}:{}:{}:{}", tenant_ctx.tenant_id, tenant_ctx.env_id, tenant_ctx.team_id.unwrap_or("default"), session_id);Aislamiento de subjects de NATS
Sección titulada «Aislamiento de subjects de NATS»El enrutamiento de mensajes usa subjects delimitados por tenant:
greentic.messaging.ingress.{env}.{tenant}.{team}.{channel} │ │ │ │ │ │ │ └─ Channel ID (slack, telegram) │ │ └──────── Team ID │ └─────────────── Tenant ID └────────────────────── Environment (prod, staging)Aislamiento de secrets
Sección titulada «Aislamiento de secrets»Los secrets se almacenan y recuperan con alcance de tenant:
// Secret retrieval includes tenant contextlet secret = secrets_client .get_secret(&tenant_ctx, "api_key") .await?;Namespacing de secrets
Sección titulada «Namespacing de secrets»secrets/├── global/ # Platform-wide secrets│ └── signing_key├── acme/ # Tenant: ACME│ ├── slack_bot_token│ ├── openai_api_key│ └── teams/│ └── support/│ └── webhook_secret└── bigcorp/ # Tenant: BigCorp └── telegram_bot_tokenAislamiento de flows
Sección titulada «Aislamiento de flows»Cada tenant puede tener flows y configuraciones diferentes:
name: acme_support_flowversion: "1.0"
# ACME-specific support flownodes: - id: greet type: reply config: message: "Welcome to ACME Support! How can I help?"name: bigcorp_helpdesk_flowversion: "1.0"
# BigCorp-specific helpdesk flownodes: - id: greet type: reply config: message: "BigCorp Helpdesk here. What's your issue?"Control de acceso
Sección titulada «Control de acceso»Acceso desde components
Sección titulada «Acceso desde components»Los components reciben TenantCtx y deben respetar los límites:
impl Guest for MyComponent { fn process(input: Input, ctx: &TenantCtx) -> Output { // Verify tenant has access to requested resource if !has_permission(ctx, &input.resource_id) { return Output::error("Access denied"); }
// Process with tenant scope process_for_tenant(ctx, input) }}Acceso a la API
Sección titulada «Acceso a la API»La API REST aplica alcance por tenant:
GET /api/v1/sessionsAuthorization: Bearer <token>X-Tenant-ID: acmeX-Team-ID: supportModelos de despliegue
Sección titulada «Modelos de despliegue»Single-Tenant
Sección titulada «Single-Tenant»Una instancia de Greentic por tenant:
┌─────────────────┐│ Greentic (ACME) │└─────────────────┘
┌─────────────────┐│ Greentic (BigCorp)│└─────────────────┘Multi-Tenant compartido
Sección titulada «Multi-Tenant compartido»Múltiples tenants sobre infraestructura compartida:
┌───────────────────────────────────┐│ Greentic Instance ││ ┌─────────┐ ┌─────────────────┐││ │ ACME │ │ BigCorp │││ │ (prod) │ │ (prod) │││ └─────────┘ └─────────────────┘││ ┌─────────┐ ┌─────────────────┐││ │ ACME │ │ BigCorp │││ │(staging)│ │ (staging) │││ └─────────┘ └─────────────────┘│└───────────────────────────────────┘Híbrido
Sección titulada «Híbrido»Mezcla de recursos dedicados y compartidos:
┌───────────────────────────────────┐│ Shared Greentic Instance ││ ┌─────────┐ ┌─────────────────┐││ │ Small │ │ Medium │││ │ Tenants │ │ Tenants │││ └─────────┘ └─────────────────┘│└───────────────────────────────────┘
┌───────────────────────────────────┐│ Dedicated: Enterprise Tenant ││ (Custom SLA, dedicated resources)│└───────────────────────────────────┘Buenas prácticas
Sección titulada «Buenas prácticas»- Pasa siempre TenantCtx - Nunca codifiques IDs de tenant de forma fija
- Valida en los límites - Verifica el acceso del tenant a nivel de API y component
- Usa logging con alcance de tenant - Incluye el ID del tenant en todas las entradas de log
- Separa los secrets - Nunca compartas secrets entre tenants
- Prueba el aislamiento - Verifica que un tenant no pueda acceder a los datos de otro
- Monitorea por tenant - Rastrea uso y errores por tenant