From 32e974db2c5d10612364f819f595f4833d151ff4 Mon Sep 17 00:00:00 2001 From: "Rodrigo Rodriguez (Pragmatismo)" Date: Sun, 15 Mar 2026 10:46:50 -0300 Subject: [PATCH] docs: add Vault migration plan with tenant-first hierarchy --- prompts/pass.md | 201 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 prompts/pass.md diff --git a/prompts/pass.md b/prompts/pass.md new file mode 100644 index 0000000..01e6d0c --- /dev/null +++ b/prompts/pass.md @@ -0,0 +1,201 @@ +# VAULT MIGRATION PLAN - Multi-Tenant Structure + +## Hierarchy (from schema) +``` +tenant/org (org_id) ← TOP LEVEL (tenant) + └── bot (bot_id) + └── user (user_id) ← via sessions +``` + +**Correct path: tenant first** +- `gbo/tenants/{org_id}/bots/{bot_id}/...` +- `gbo/tenants/{org_id}/users/{user_id}/...` + +--- + +## VAULT PATH STRUCTURE + +``` +gbo/ +├── tenants/ # PER-TENANT (org_id = tenant) +│ ├── {org_id}/ +│ │ ├── config/ # Tenant-level settings +│ │ │ ├── name +│ │ │ ├── domain +│ │ │ └── settings +│ │ │ +│ │ ├── bots/ +│ │ │ ├── {bot_id}/ +│ │ │ │ ├── email/ # Bot email credentials +│ │ │ │ │ ├── smtp-host +│ │ │ │ │ ├── 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 { + // 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 { + 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 { + // 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 +} +```