8.8 KiB
8.8 KiB
VAULT MIGRATION PLAN - Multi-Tenant Structure
Hierarchy
tenant (cluster/deployment) ← INFRASTRUCTURE
└── org (customer organization)
├── bot
└── user
tenant ≠ org
- tenant = deployment cluster (dev, staging, prod)
- org = customer organization inside a tenant
VAULT PATH STRUCTURE
gbo/
├── tenants/ # PER-TENANT (cluster/deployment)
│ └── {tenant_id}/ # dev, staging, prod
│ ├── infrastructure/ # TENANT INFRASTRUCTURE
│ │ ├── tables/ # host, port, username, password
│ │ ├── drive/ # host, port, accesskey, secret
│ │ ├── cache/ # host, port, password
│ │ ├── email/ # smtp host, port, user, pass
│ │ ├── directory/ # Zitadel url
│ │ ├── llm/ # LLM endpoint
│ │ └── models/ # Model server url
│ │
│ └── config/ # Tenant settings
│ ├── name
│ ├── domain
│ └── settings
│
├── orgs/ # PER-ORGANIZATION (customer)
│ └── {org_id}/
│ ├── bots/
│ │ └── {bot_id}/
│ │ ├── email/ # Bot email credentials
│ │ ├── whatsapp/
│ │ ├── llm/ # Bot-specific LLM override
│ │ └── api-keys/
│ │
│ └── users/
│ └── {user_id}/
│ ├── email/ # User email credentials
│ └── oauth/
│
└── system/ # GLOBAL FALLBACK
├── jwt/secret
├── tables/ # Fallback if tenant not set
├── drive/
├── cache/
├── email/
├── llm/
├── directory/
├── security/
├── alm/
├── cloud/
└── app/
│ │ │ │ │ ├── smtp-port
│ │ │ │ │ ├── smtp-user
│ │ │ │ │ ├── smtp-password
│ │ │ │ │ ├── imap-host
│ │ │ │ │ ├── imap-port
│ │ │ │ │ ├── imap-user
│ │ │ │ │ └── imap-password
│ │ │ │ │
│ │ │ │ ├── whatsapp/ # Bot WhatsApp
│ │ │ │ │ ├── phone-number-id
│ │ │ │ │ ├── business-account-id
│ │ │ │ │ └── api-key
│ │ │ │ │
│ │ │ │ ├── llm/ # Bot-specific LLM (override)
│ │ │ │ │ ├── provider
│ │ │ │ │ ├── model
│ │ │ │ │ └── api-key
│ │ │ │ │
│ │ │ │ └── api-keys/
│ │ │ │ ├── openai
│ │ │ │ ├── anthropic
│ │ │ │ └── custom/
│ │ │ │
│ │ │ └── {bot_id2}/
│ │ │ └── ...
│ │ │
│ │ └── users/
│ │ ├── {user_id}/
│ │ │ ├── email/ # User email credentials
│ │ │ │ ├── imap-host
│ │ │ │ ├── imap-port
│ │ │ │ ├── imap-user
│ │ │ │ ├── imap-password
│ │ │ │ ├── smtp-host
│ │ │ │ ├── smtp-port
│ │ │ │ ├── smtp-user
│ │ │ │ └── smtp-password
│ │ │ │
│ │ │ └── oauth/
│ │ │ ├── google/
│ │ │ │ ├── client-id
│ │ │ │ └── client-secret
│ │ │ ├── microsoft/
│ │ │ │ ├── client-id
│ │ │ │ └── client-secret
│ │ │ └── github/
│ │ │ ├── client-id
│ │ │ └── client-secret
│ │ │
│ │ └── {user_id2}/
│ │ └── ...
│ │
│ └── {org_id2}/
│ └── ...
│
├── system/ # SYSTEM-WIDE (includes ALM/deployment)
│ ├── jwt/
│ │ └── secret
│ ├── tables/ # Database
│ │ ├── host
│ │ ├── port
│ │ ├── database
│ │ ├── username
│ │ └── password
│ ├── drive/ # Storage
│ │ ├── accesskey
│ │ └── secret
│ ├── cache/
│ │ └── url
│ ├── email/ # Global SMTP fallback
│ │ ├── smtp-host
│ │ ├── smtp-port
│ │ ├── smtp-user
│ │ ├── smtp-password
│ │ └── smtp-from
│ ├── llm/ # Global LLM defaults
│ │ ├── url
│ │ ├── model
│ │ └── providers/
│ │ └── openai/
│ │ └── api-key
│ ├── models/ # Model serving
│ │ └── url
│ ├── directory/ # Zitadel
│ │ └── config
│ ├── security/
│ │ ├── require-auth
│ │ └── anonymous-paths
│ ├── alm/ # ALM/Deployment (Forgejo)
│ │ ├── url
│ │ ├── token
│ │ └── default-org
│ ├── cloud/ # Cloud providers (AWS, etc)
│ │ ├── access-key
│ │ ├── secret-key
│ │ ├── region
│ │ └── s3-endpoint
│ └── app/ # Application config
│ ├── url
│ ├── environment
│ └── disable-tls
ENV VARS → VAULT MAPPING
| Current ENV | Vault Path | Scope |
|---|---|---|
JWT_SECRET |
gbo/system/jwt/secret |
system |
LLM_KEY |
gbo/system/llm/providers/openai/api-key |
system |
OPENAI_API_KEY |
gbo/system/llm/providers/openai/api-key |
system |
SMTP_HOST |
gbo/system/email/smtp-host |
system |
SMTP_USER |
gbo/system/email/smtp-user |
system |
SMTP_PASS |
gbo/system/email/smtp-password |
system |
SMTP_FROM |
gbo/system/email/smtp-from |
system |
FORGEJO_URL |
gbo/system/alm/url |
system |
FORGEJO_TOKEN |
gbo/system/alm/token |
system |
FORGEJO_DEFAULT_ORG |
gbo/system/alm/default-org |
system |
AWS_ACCESS_KEY_ID |
gbo/system/cloud/access-key |
system |
AWS_SECRET_ACCESS_KEY |
gbo/system/cloud/secret-key |
system |
AWS_REGION |
gbo/system/cloud/region |
system |
S3_ENDPOINT |
gbo/system/cloud/s3-endpoint |
system |
ZITADEL_ISSUER_URL |
gbo/system/directory/zitadel-issuer |
system |
ZITADEL_CLIENT_ID |
gbo/system/directory/zitadel-client-id |
system |
REQUIRE_AUTH |
gbo/system/security/require-auth |
system |
ANONYMOUS_PATHS |
gbo/system/security/anonymous-paths |
system |
APP_URL |
gbo/system/app/url |
system |
BOTSERVER_ENV |
gbo/system/app/environment |
system |
LLM_URL |
gbo/system/llm/url |
system |
LLM_MODEL |
gbo/system/llm/model |
system |
BOTMODELS_URL |
gbo/system/models/url |
system |
CODE PATTERNS
Get Bot Email (tenant → bot)
async fn get_bot_email(state: &AppState, org_id: Uuid, bot_id: Uuid) -> Result<BotEmail> {
// Try per-bot Vault path first
let path = format!("gbo/tenants/{}/bots/{}/email", org_id, bot_id);
if let Ok(creds) = state.secrets.get_secret(&path).await {
return Ok(BotEmail::from_vault(creds));
}
// Fallback: system SMTP
let system = state.secrets.get_secret("gbo/system/email").await?;
Ok(BotEmail::from_system(system))
}
Get User Email (tenant → user)
async fn get_user_email(state: &AppState, org_id: Uuid, user_id: Uuid) -> Result<UserEmail> {
let path = format!("gbo/tenants/{}/users/{}/email", org_id, user_id);
state.secrets.get_secret(&path).await
}
Get Bot LLM (tenant → bot, with system fallback)
async fn get_bot_llm(state: &AppState, org_id: Uuid, bot_id: Uuid) -> Result<LlmConfig> {
// Bot-specific override
let bot_path = format!("gbo/tenants/{}/bots/{}/llm", org_id, bot_id);
if let Ok(config) = state.secrets.get_secret(&bot_path).await {
return Ok(LlmConfig::from_vault(config));
}
// System default
state.secrets.get_secret("gbo/system/llm").await
}