Gestionando Tablas Managed
Esta guia muestra los flujos completos de la API de Managed Tables: provisionamiento del banco, creacion manual, upload de archivos con inferencia de schema, y CRUD de filas.
Cuando usar: cuando tu aplicacion necesita almacenar datos estructurados propios de la company (planillas, datos de calculo, listas operacionales) sin depender de un banco externo. Cuando no usar: si quieres exponer una visualizacion guardada como API (usa Data API).
Pre-requisitos​
- JWT del console (login normal — no usa API key).
- Permisos IAM asignados:
managed-tables:list,managed-tables:create,managed-tables:update,managed-tables:deletemanaged-tables:upload,managed-tables:data-read,managed-tables:data-write
- Roles managed que ya agregan todo:
ConnectionManager,DataEngineer.
Vision general de los flujos​
Workflow 1: Provisionamiento​
Cada company debe provisionar su area de almacenamiento una unica vez. Idempotente — llamadas subsiguientes devuelven el estado existente.
export TOKEN="eyJ..."
export API_BASE_URL="http://localhost:3100"
# 1. Verifica estado
curl "$API_BASE_URL/api/v1/managed-tables/status" \
-H "Authorization: Bearer $TOKEN"
# → { "provisioned": false, "connection_id": null }
# 2. Provisiona (idempotente)
curl -X POST "$API_BASE_URL/api/v1/managed-tables/provision" \
-H "Authorization: Bearer $TOKEN"
# → { "provisioned": true, "connection_id": "507f..." }
Workflow 2: Creacion manual de tabla​
Usalo cuando ya conoces el schema. No requiere archivo.
# 1. Crear tabla
curl -X POST "$API_BASE_URL/api/v1/managed-tables" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"display_name": "ventas_mensuales",
"columns": [
{ "name": "producto", "display_name": "Producto", "type": "text", "nullable": false },
{ "name": "valor", "display_name": "Valor", "type": "decimal", "nullable": true },
{ "name": "fecha_venta", "display_name": "Fecha", "type": "date", "nullable": false }
]
}'
# Respuesta:
# { "_id": "507f...", "display_name": "ventas_mensuales", "columns": [...], ... }
# 2. Insertar filas
curl -X POST "$API_BASE_URL/api/v1/managed-tables/507f.../data" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"rows": [
{ "producto": "Camisa", "valor": 89.90, "fecha_venta": "2026-01-15" },
{ "producto": "Pantalon", "valor": 159.90, "fecha_venta": "2026-01-15" }
]
}'
# → 201 { "inserted": 2 }
display_namey nombre de columna coinciden con^[a-z_][a-z0-9_]*$.display_namees unico por company entre tablas activas.- Conflicto devuelve
400conerror_code: MANAGED_TABLE_DUPLICATE_NAME.
Workflow 3: Upload de archivo (CSV/Excel/ZIP)​
Flujo de 2 pasos con inferencia de schema. La API procesa el archivo de forma asincrona y el cliente confirma el schema antes de la insercion final.
Etapa 1 — upload​
curl -X POST "$API_BASE_URL/api/v1/managed-tables/upload" \
-H "Authorization: Bearer $TOKEN" \
-F "files=@ventas_2026.csv"
# → 201 { "job_id": "abc123", "status": "queued" }
Limites: hasta 10 archivos por llamada, 100MB total. Acepta .csv, .xlsx, .xls, .zip (zip es descomprimido automaticamente).
Etapa 2 — polling del estado​
curl "$API_BASE_URL/api/v1/managed-tables/upload-jobs/abc123" \
-H "Authorization: Bearer $TOKEN"
Estados que vas a observar (en orden):
| Estado | Significado | Accion del cliente |
|---|---|---|
queued | Esperando procesamiento | Continuar polling |
analisando | API procesando archivo | Mostrar spinner |
waiting_confirm | Schema inferido listo | Renderizar UI de confirmacion con inferred_schema |
inserting | Insercion en curso | Mostrar progreso (progress.processed_rows) |
done | Tabla creada/actualizada | Redirigir a user_table_id |
failed | Error | Mostrar error |
Cuando status === "waiting_confirm", el body contiene:
{
"status": "waiting_confirm",
"inferred_schema": {
"suggested_table_name": "ventas_2026",
"columns": [
{ "name": "producto", "display_name": "Producto", "type": "text", "nullable": false },
{ "name": "valor", "display_name": "Valor", "type": "decimal", "nullable": true }
],
"sample_rows": [{ "producto": "Camisa", "valor": "89.90" }],
"total_row_count_estimate": 1500
}
}
Etapa 3 — confirmar schema​
El usuario puede editar nombres de columna, tipos y display_name de la tabla antes de confirmar:
curl -X POST "$API_BASE_URL/api/v1/managed-tables/upload-jobs/abc123/confirm" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"display_name": "ventas_2026",
"columns": [
{ "name": "producto", "display_name": "Producto", "type": "text", "nullable": false },
{ "name": "valor", "display_name": "Valor", "type": "decimal", "nullable": true }
]
}'
# → 200 { "status": "inserting" }
Continua polling hasta status === "done". El user_table_id en el job apunta a la tabla creada.
Workflow 4: Append/Replace en tabla existente​
Anexa nuevas filas a una tabla ya creada (o sustituye todo el contenido).
# Append en tabla existente
curl -X POST "$API_BASE_URL/api/v1/managed-tables/507f.../upload" \
-H "Authorization: Bearer $TOKEN" \
-F "files=@ventas_febrero.csv" \
-F "mode=append"
# Replace (sustituye todo)
curl -X POST "$API_BASE_URL/api/v1/managed-tables/507f.../upload" \
-H "Authorization: Bearer $TOKEN" \
-F "files=@ventas_completo.csv" \
-F "mode=replace"
display_namede la tabla existente es reusado — el regex^[a-z_][a-z0-9_]*$no se aplica (soporta tablas legacy).- Schema confirmado debe coincidir con el schema de la tabla existente — columnas extras causan falla en el insert.
replacees atomico — todo el contenido es sustituido en una unica operacion (sin estado parcial visible).
Workflow 5: CRUD de filas​
Operaciones punto-a-punto sobre las filas de una tabla.
# Listar (paginado)
curl "$API_BASE_URL/api/v1/managed-tables/507f.../data?page=1&per_page=50&sort_by=-fecha_venta" \
-H "Authorization: Bearer $TOKEN"
# → { "total": 1500, "quantity": 50, "records": [{ "id": "uuid", "producto": "X", ... }] }
# Insertar
curl -X POST "$API_BASE_URL/api/v1/managed-tables/507f.../data" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ "rows": [{ "producto": "Z", "valor": 50 }] }'
# Actualizar fila
curl -X PUT "$API_BASE_URL/api/v1/managed-tables/507f.../data/<rowId>" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ "valor": 99.90 }'
# Eliminar
curl -X DELETE "$API_BASE_URL/api/v1/managed-tables/507f.../data/<rowId>" \
-H "Authorization: Bearer $TOKEN"
# → 204 No Content
rowId es el identificador interno de la fila (generalmente UUID generado en el insert). Aparece como id en cada item de records.
Workflow 6: Soft-delete de la tabla​
Listados (GET /v1/managed-tables) ya excluyen tablas archivadas, asi que la tabla desaparece inmediatamente. Restauracion no es expuesta por la API — abre un ticket de soporte si necesitas revertir.
Tipos de columna soportados​
| Tipo | PostgreSQL DDL | Ejemplo |
|---|---|---|
text | TEXT | "abc" |
integer | BIGINT | 42 |
decimal | NUMERIC | 89.90 |
boolean | BOOLEAN | true |
date | DATE | "2026-01-15" |
datetime | TIMESTAMPTZ | "2026-01-15T10:30:00Z" |
Tratamiento de errores​
| HTTP | Codigo | Causa comun | Accion |
|---|---|---|---|
| 400 | MANAGED_TABLE_DUPLICATE_NAME | display_name ya existe activo | Pedir otro nombre al usuario |
| 400 | - | Banco no provisionado | Llamar POST /provision antes |
| 400 | - | Job no esta en waiting_confirm | Continuar polling antes de confirmar |
| 401 | - | JWT ausente/expirado | Refresh token |
| 403 | - | Sin permiso IAM | Verificar el role del usuario |
| 404 | - | Tabla/fila/job inexistente | Releer estado del recurso |
| 422 | - | Schema invalido (regex, tipo, campo obligatorio) | Mostrar error especifico al usuario |
| 500 | - | Error interno | Retry con backoff; loguear request_id |
Buenas practicas​
- No llames
POST /provisionen loop — es idempotente, pero cada llamada es mas costosa. VerificaGET /statusprimero. - Polling con backoff exponencial — empieza en 1s, duplica hasta 10s. Job de upload puede llevar segundos a minutos dependiendo del tamano.
- Muestra
progress.processed_rows / progress.total_rowsduranteinsertingpara feedback al usuario en archivos grandes. - Valida el tamano de los archivos en el frontend antes del upload — backend rechaza >100MB total.
- Reusa
mode=appendpara uploads incrementales; no crees nueva tabla cada vez. - Para queries customizadas sobre las tablas managed, exponlas como Visualization y publicalas via Data API. Managed Tables no expone SQL libre.
Referencia completa​
Para el contrato detallado de cada endpoint (todos los campos, status codes, ejemplos de error), ve Managed Tables API Reference.