Roles y permisos
El modelo: app-to-app, no usuario directo
Sección titulada «El modelo: app-to-app, no usuario directo»EMA Emi no autentica usuarios finales. Asume que el producto cliente ya autenticó al usuario y que la conversación viene firmada con la API key del producto. El control de acceso vive en tres capas:
1. API key (¿qué producto está hablando?)2. App scope (¿qué agentes y tools puede invocar este producto?)3. Tenant scope (¿de qué tenant son los datos accesibles?)Capa 1 — API key
Sección titulada «Capa 1 — API key»Cada producto cliente tiene su propia API key. El header
Authorization: Bearer <key> la identifica:
| API key prefix | Producto | Agente |
|---|---|---|
emi_5bba56a1… | emahealth | SalesAgent |
emi_81dccf8d… | emaclinic | SupportAgent |
emi_66d6c5… | emavault | AnalyticsAgent |
Sin API key válida, la request retorna 401.
Capa 2 — App scope
Sección titulada «Capa 2 — App scope»permissions.ts → APP_SCOPES define qué puede invocar cada producto:
| App | Agentes permitidos | Tools permitidas |
|---|---|---|
| emahealth | sales, fhir | terminology |
| emaclinic | support, fhir, database | aidbox, terminology |
| emavault | analytics, database, documents | supabase-vault, calculator |
Si un cliente intenta invocar algo fuera de su whitelist, el middleware rechaza la request.
Capa 3 — Tenant scope (sólo emaclinic)
Sección titulada «Capa 3 — Tenant scope (sólo emaclinic)»Cuando el producto opera multi-tenant (caso emaclinic), las tools FHIR
deben ser scope-adas por tenant. Por eso emaclinic obliga el header
X-Tenant-Id en cada request a emaemi:
POST /api/chatAuthorization: Bearer emi_81dccf8d…X-Tenant-Id: clinica-auroraSi falta el header, la request retorna 400 con mensaje
X-Tenant-Id header required.
emahealth y emavault no requieren X-Tenant-Id porque no son
multi-tenant en ese sentido.
Diferencia entre usuario autenticado vs anónimo
Sección titulada «Diferencia entre usuario autenticado vs anónimo»- SalesAgent (emahealth): el chatbot del website lo invocan visitantes anónimos. La auth la pone el widget con la API key del producto, no el usuario individual.
- SupportAgent (emaclinic) y AnalyticsAgent (emavault): el
cliente sólo expone Emi a usuarios logueados. El frontend usa
apiFetchpara incluir el token de Supabase en la request al worker proxy del producto, y ese worker es el que llama a emaemi con la API key correcta.
Rate limiting
Sección titulada «Rate limiting»Sin rate limiting explícito por usuario hoy. Los límites operativos vienen de:
- Cloudflare Workers: cuota de la cuenta.
- Anthropic API: rate limits por API key (tokens/minute).
Si un agente abusa, se nota primero en el costo de Anthropic. Phase 2-3 contempla agregar rate limiting a nivel de API key.