gb/prompts/pass.md

233 lines
8.8 KiB
Markdown

# 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)
```rust
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)
```rust
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)
```rust
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
}
```