Skip to content

Plataforma técnica · Orchestrator

API del Orchestrator

API REST

El Orchestrator expone una API REST plana bajo /api/* sobre Node.js + Express. Cada dominio del ecosistema (administración, remuneraciones, operaciones, declaraciones, etc.) tiene un router dedicado en orchestrator/src/routes/ y una página de documentación equivalente en esta sección.

Esta página es el hub de la API: muestra los patrones REST comunes, las convenciones de respuesta y autenticación, y enlaza a cada página de dominio.

Cada request HTTP a la API atraviesa una pipeline determinista: autenticación, autorización RBAC, resolución de tenant, lógica de dominio y respuesta. El middleware de Sevastopol inyecta la cookie sid antes del proxy local, que reenvía al Orchestrator en localhost:8000.

flowchart LR
    A[Solicitud HTTP] --> B[authenticateToken]
    B -->|req.user| C[authorizeRoute · RBAC]
    C -->|permitido| D[getTenantPool]
    D -->|pool| E[Route handler]
    E -->|Service layer| F[Repository]
    F -->|SQL| G[(PostgreSQL)]
    G -->|filas| F --> E -->|JSON snake_case| H[Response]
    C -.->|403| H
    B -.->|401| H

Sevastopol nunca habla directo con localhost:8000. Toda llamada cruza el proxy local en sevastopol/src/pages/api/*, que adjunta la cookie sid y reenvía al Orchestrator. Esto centraliza CSP, headers de seguridad y rotación de credenciales en una sola capa.

sequenceDiagram
    participant I as Island (SolidJS)
    participant AF as authenticatedFetch
    participant API as Sevastopol /api/*
    participant O as Orchestrator
    participant DB as PostgreSQL

    I->>AF: fetch('/api/employees')
    AF->>AF: Adjunta cookie sid
    AF->>API: HTTP request
    API->>O: Reenvía a :8000 con cookie
    O->>O: authenticateToken + authorizeRoute
    O->>DB: Query (tenant pool)
    DB-->>O: Filas
    O-->>API: JSON snake_case
    API-->>AF: Respuesta
    AF-->>I: Datos parseados
  • URLs: kebab-case, prefijo /api, sin versionado en path (la API es interna).
  • Payloads JSON: snake_case, replicando los nombres de columnas para evitar transformación en el frontend.
  • TypeScript interno: camelCase. La conversión ocurre solo en los DTOs de borde.
MecanismoUso
Cookie sid (HttpOnly)Toda mutación y casi toda lectura. Inyectada por el middleware de Sevastopol.
Header X-Internal-TokenEndpoints /api/internal/* consumidos por jean_d_arc en build.
Authorization: BearerReservado para integraciones externas autorizadas (no usado hoy).
CódigoCaso de usoEjemplo
200GET o PUT exitosoRecurso obtenido o actualizado
201POST exitosoRecurso creado
204DELETE exitosoSin contenido
400Entrada inválidaCampos requeridos faltantes, RUT mal formado
401No autorizadoSin cookie sid o JWT inválido
403ProhibidoCookie válida pero rol sin permiso para la ruta
404No encontradoRecurso no existe en el tenant
409ConflictoDuplicado, estado incompatible
500Error internoFallo en DB o lógica no esperado
{
"success": false,
"error": "Mensaje descriptivo",
"code": "VALIDATION_ERROR"
}
CódigoHTTPDescripción
UNAUTHORIZED401Cookie ausente o expirada
FORBIDDEN403Sin permiso RBAC para la ruta
NOT_FOUND404Recurso no existe en el tenant
VALIDATION_ERROR400Payload inválido
INTERNAL_ERROR500Error de servidor

Endpoints que listan recursos aceptan page y limit (default limit=50).

Terminal window
curl -X GET "http://localhost:8000/api/employees?page=2&limit=20" -b cookies.txt
{
"success": true,
"data": [ /* ... */ ],
"pagination": { "page": 2, "limit": 20, "total": 150, "pages": 8 }
}

El Orchestrator es multi-tenant: cada request resuelve un tenant_id desde la sesión y usa getTenantPool(tenantId) para obtener una conexión a la base PostgreSQL del tenant (nostromo_<rut_sin_dv>).

  • Las bases compartidas (nostromo_common, nostromo_command) se acceden con pools dedicados (commonPool, centralPool).
  • Cambiar de tenant requiere PUT /api/tenant y emite un nuevo JWT en la cookie.
  • Ver Mother Database para el modelo de aislamiento por base.