Appearance
Available Connections Catalog
Cambio de diseño (2026-04-23,
connections-redesign): el catálogo ahora es gestionable. La tabla antes modelaba 5 filas seed inmutables; ahora modela una entidad CRUD-capaz conslugcanónico,displayNameeditable yauthTypediscriminador. Las conexionesconnections.connectionsreferencian el catálogo vía FKavailable_connection_id.
El módulo connections expone un catálogo de tipos de conexión disponibles. El panel consulta este catálogo para construir el flujo de "elegir integración" sin hardcodear la lista en el frontend.
Nueva forma de la fila
connections.available_connections:
| Columna | Tipo | Restricción | Notas |
|---|---|---|---|
id | uuid | PK, DEFAULT uuidv7() | |
created_at | timestamptz | DEFAULT now() | |
updated_at | timestamptz | DEFAULT now() | |
slug | varchar(64) | NOT NULL, UNIQUE | Identificador canónico (smtp, telegram, gmail, sheets, calendar). Esta es la llave contractual con el código en runtime. |
display_name | varchar(120) | NOT NULL | Nombre human-readable para UI (SMTP, Telegram, Gmail, Google Sheets, Google Calendar). |
auth_type | varchar(32) | NOT NULL | 'credentials' o 'oauth'. Discrimina qué ruta seguir al crear una conexión: formulario de credenciales vs flujo OAuth. |
icon | text | nullable | |
cover | text | nullable | |
description | text | nullable |
La columna
namedel diseño original fue reemplazada porslug(mismo conjunto de valores). Las nuevas columnasdisplay_name,auth_typese poblan desde el registry in-code al hacerPOST /available/seed.
Registry in-code (source of truth)
apps/api/src/modules/connections/domain/registry/available-connections.registry.ts es el contrato runtime entre el código (factories, scopes OAuth, AI tools) y las filas del catálogo. Ver Registry Contract para el detalle.
Los 5 slugs actuales y su authType:
| Slug | displayName | authType | OAuth scopes |
|---|---|---|---|
smtp | SMTP | credentials | — |
telegram | Telegram | credentials | — |
gmail | Gmail | oauth | gmail.send, gmail.modify |
sheets | Google Sheets | oauth | spreadsheets, drive.file, drive.readonly |
calendar | Google Calendar | oauth | calendar, calendar.events |
Endpoints
Todas las rutas están montadas bajo /connections/available/* (el sub-controlador AvailableConnectionsController usa @Controller('available') y el módulo lo monta dentro del prefijo /connections).
GET /connections/available (list)
Devuelve el catálogo completo. Respuesta 200 OK con un array de IAvailableConnectionResponse:
json
[
{
"id": "01958653-0001-7045-8e6e-...",
"slug": "calendar",
"displayName": "Google Calendar",
"authType": "oauth",
"cover": null,
"icon": null,
"description": "Gestión de eventos de Google Calendar vía OAuth.",
"createdAt": "2026-01-01T00:00:00.000Z",
"updatedAt": "2026-01-01T00:00:00.000Z"
}
]- Autenticación:
@Auth()→ JWT requerido. - Policy:
readsobreconnections.connection(cualquier miembro de la org puede leer el catálogo). - Orden: alfabético por
slug.
GET /connections/available/:id (by id)
- Ruta
@Get(':id'). Valida el path conParseUUIDPipe({ version: '7' }). - Error:
404 CONNECTION.CATALOG_ENTRY_NOT_FOUNDsi no existe.
GET /connections/available/:id/form-schema (discovery)
Devuelve el descriptor del formulario que la UI debe renderizar para crear una conexión de este tipo. Para entradas authType = 'credentials' regresa los campos del registry; para authType = 'oauth' regresa { fields: [] }.
json
// Para smtp (credentials)
{
"fields": [
{ "name": "host", "type": "string", "required": true },
{ "name": "port", "type": "number", "required": true },
{ "name": "user", "type": "string", "required": true },
{ "name": "password", "type": "password", "required": true },
{ "name": "secure", "type": "boolean", "required": true }
]
}json
// Para gmail (oauth)
{ "fields": [] }El consumidor detecta el tipo de flujo leyendo authType del GET /available/:id — ver Auth Discovery Flow.
POST /connections/available/seed (platform admin)
Idempotente. Recorre el registry in-code y hace un upsertBySlug por entrada:
- Si el slug no existe en la DB, inserta la fila con
display_name,auth_type,icon,cover,descriptiontomados del registry. - Si existe, refresca los campos "display" (
display_name,icon,cover,description). No sobrescribe customizaciones que el admin haya hecho sobreicon/coversi el registry exponenull— la regla es "el registry es la fuente; valores no-null ganan".
Policy: manage sobre connections.available-connection (reservado a admins de plataforma).
Se espera ejecutar este endpoint después de la migración 1 (ver Connections Redesign Migration Runbook) para poblar los campos derivados del registry.
PUT /connections/available/:id
Permite editar solo campos display (displayName, icon, cover, description). slug y authType son inmutables — la combinación define el contrato de código.
DELETE /connections/available/:id
204 No Contentsi la entrada no está referenciada por ningunaconnections.connections.409 CONNECTION.CATALOG_ENTRY_IN_USEconmetadata: { id, count }si hay conexiones existentes usando esta entrada.
La restricción también se refuerza a nivel DB con un FK ON DELETE RESTRICT — el 409 se devuelve antes de tocar la DB para dar mejor UX.
Policies nuevas (Phase 4 CASL)
Subject connections.available-connection:
| Action | Scope | Quién |
|---|---|---|
read | org | miembros autenticados (se reusa el subject connections.connection para reads) |
manage | platform | platform admin |
update | platform | platform admin |
delete | platform | platform admin |
Relación con connections.connections
Cada fila en connections.connections tiene available_connection_id (NOT NULL, FK). En la respuesta IConnectionResponse, el campo slug se hidrata del catálogo unido — el cliente NUNCA recibe el id del catálogo crudo junto a un slug obsoleto.
Nota histórica: antes del
connections-redesignchange, la tablaconnectionsllevabaprovider(smtp | telegram | google_gmail | google_workspace) ytype. Después del Phase 4 esas columnas se eliminan — verrunbooks/connections-redesign-migration.mdpara el paso-a-paso de migración.
Páginas relacionadas
- Connections Module Overview
- Auth Discovery Flow — cómo la UI decide OAuth vs formulario
- Registry Contract — cómo el registry in-code se mantiene sincronizado con la DB
- Connections Redesign Migration — runbook operativo
- Google Providers — Gmail, Sheets, Calendar