EMA Vault expone 44 módulos API bajo el worker Hono, organizados
por dominio operativo (negocio, finanzas, producto, sistema) y con
verificación de permisos a nivel módulo vía canRead y canWrite.
La autorización se aplica en cada handler en lugar de a través de
una decorator global, lo que permite que cada endpoint declare su
propio set de roles permitidos sin acoplar el resto del módulo.
Cuatro layers de autenticación cubren los contextos posibles —staff
con JWT Supabase, llamadas worker-a-worker con header de plataforma,
webhooks de GitHub con HMAC, y rutas explícitamente públicas— y los
cinco roles RBAC distribuyen los permisos sobre el resto.
Layer Cómo funciona Mounting publicSin credenciales rutas explícitas antes de authMiddleware supabaseJWT Supabase + vault_users.is_active=true app.use("/api/*", authMiddleware)platform-keyHeader X-Platform-Key mount antes de authMiddleware webhook-sigHMAC verification (/api/github/webhook) mount antes de authMiddleware
Rol Bypass Módulos default adminSí — bypass todos los checksTodo technicalNo producto, infra, audit, wiki, equipo commercialNo pipeline, contratos, directorio, catálogo, pricing financeNo finanzas, facturación electrónica, MRR, obligaciones viewerNo lectura limitada
Tabla vault_permissions(role, module, can_read, can_write) — admin
configura granular.
Método Path Notas GET /api/healthLiveness probe GET /api/configBootstrap: Supabase URL + anon key GET /auth/me(con JWT — retorna user + permissions) GET /auth/callbackOAuth Google redirect POST /api/github/webhookHMAC verified — sync issues POST /api/internal/tenantsX-Platform-Key — endpoint interno reservado
Módulo Path Rol mínimo Pipeline / Leads /api/leads/* · /api/pipeline/*commercial, admin Assessments /api/assessments/*commercial, admin Lead-EMI conversations /api/lead-emi-conversations/*commercial, admin
Módulo Path Rol mínimo Tenants (clientes) /api/tenants/*commercial, finance, admin Provisioning POST /api/tenants/:id/provisionadmin Clientes (DEPRECATED) /api/clients/*redirige a tenants Organizations /api/organizations/*commercial, admin Directorio (people) /api/directory/*commercial, admin Equipo Vault /api/vault-team/*admin
Módulo Path Rol mínimo Contratos /api/contracts/*commercial, finance, admin Catálogo /api/catalog/*commercial, admin Catálogo costos /api/catalog/costs/*finance, admin Catálogo pricing /api/catalog/pricing/*finance, admin Productos catalog /api/products-catalog/*commercial, admin Pricing tool /api/pricing-tool/*commercial, finance, admin
Módulo Path Rol mínimo Finance entries /api/finance/*finance, admin Invoices (interna) /api/invoices/*finance, admin Fiscal config (facturación electrónica) /api/fiscal/*finance, admin MRR /api/mrr/*finance, admin Exchange rates /api/exchange/*finance, admin Obligaciones /api/obligations/*finance, admin
Módulo Path Rol mínimo Productos (catálogo) /api/products/*technical, admin Cross-product GET /api/products/cross/issuesGET /api/products/cross/recenttechnical, admin Producto sub-pages /api/products/:slug/*technical, admin GitHub sync /api/products/:slug/github-synctechnical, admin Releases /api/products/:slug/releases/*technical, admin Roadmap /api/products/:slug/layers/*technical, admin Tech stack /api/products/:slug/tech-stack/*technical, admin Quality /api/quality/*technical, admin
Módulo Path Rol mínimo Editorial posts /api/editorial/*commercial, admin Wiki /api/wiki/*technical, admin Documentos /api/documents/*technical, admin Brand /api/brand/*commercial, admin
Módulo Path Rol mínimo Checklist /api/checklist/*admin, technical Time tracking /api/time/*technical, admin Notifications /api/notifications/*(todos) Infra /api/infra/*technical, admin Dashboard /api/dashboard/*(todos — read-only) KPIs /api/kpis/*(todos — read-only) Análisis /api/analysis/*admin, technical Changelog /api/changelog/*technical, admin
Módulo Path Rol mínimo Audit log /api/audit/*admin Vault permissions /api/vault-permissions/*admin Vault roles /api/vault-roles/*admin
Módulo Path Rol mínimo EMI proxy chat POST /api/emi/chat(todos) — auditado EMI access check GET /api/emi/access(todos) EMI access admin /api/emi-access/*admin EMI analytics /api/emi-analytics/*admin
Módulo Path Rol mínimo AI proposal POST /api/ai/proposalcommercial, admin AI contract summary POST /api/ai/contractcommercial, finance, admin AI summary POST /api/ai/summary(todos con write en módulo origen)
Módulo Path Rol mínimo Well metrics overview GET /api/well/metrics/overview(todos read) Well metrics retention GET /api/well/metrics/retention(todos read) Well metrics streaks GET /api/well/metrics/streaks(todos read) Well metrics pillars GET /api/well/metrics/pillars(todos read) Well metrics daily GET /api/well/metrics/daily(todos read)
Helper en src/client/lib/api.ts que retorna JSON parseado
directamente:
const tenants = await apiFetch < Tenant [] > ( ' /api/tenants ' );
// tenants es Tenant[] directamente, no Response
Helper en src/client/lib/auth.ts:
import { canRead, canWrite } from ' ../lib/auth ' ;
if ( canRead ( ' finance ' )) {
Filtra navItems del sidebar dinámicamente.
Mount order matters : rutas públicas ANTES de authMiddleware
en index.ts. Cross-product /cross/* ANTES de /:slug/*.
Permisos en handler : usar canRead(c, 'module') /
canWrite(c, 'module') desde el contexto.
Audit log para mutations críticas — el audit_trigger() SQL
cubre 12 tablas, pero para acciones cross-product (provisioning)
loggear manual en /api/audit/*.
CSP whitelist — si llamás a un dominio externo nuevo,
actualizar connect-src en security-headers.ts.
Rate limiting — Vault es internal, no implementa rate-limit
per-user (asume staff trusted). Aplicar solo a endpoints públicos
(/api/github/webhook).
# Listar todos los routes mounted
grep -n " app.route " src/index.ts
# Verificar canRead/canWrite usage
grep -rn " canRead\|canWrite " src/api/
# Ver módulos en vault_permissions
SELECT DISTINCT module FROM emavault.vault_permissions ORDER BY module ;