Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Conectores de datos externos — contrato v1
El sistema no se conecta directo a las bases de datos de los clientes. En cada servidor origen se instala un conector: una API HTTP de solo lectura que expone tablas elegidas. El sistema habla siempre el mismo contrato, sin importar la tecnología de origen (FoxPro, SQL Server, Excel…).
| Conector | Carpeta | Estado |
|---|---|---|
| FoxPro (DBF/FPT/CDX) | foxpro/ |
1.1.0 |
Reglas que todo conector debe cumplir
- Solo lectura. Únicamente
GET; cualquier otro método →405. Nunca escribe en el origen. - Token Bearer (
Authorization: Bearer <token>). El conector guarda solo el SHA-256; el sistema guarda el token cifrado (AES-256-GCM). Se admiten varios hashes para rotar sin cortar. - Lista de IPs permitidas (backend del sistema), en el conector y en el firewall del servidor.
- El administrador del origen decide qué sale: tablas permitidas, campos permitidos y campos
denegados (sueldos, claves…). Lo no permitido no existe para el sistema (
404/400). - Sin SQL ni rutas libres: tablas y campos se validan contra la lista real del origen.
- Protege al origen: límite de peticiones por minuto, lecturas simultáneas, tamaño de página
y tiempo máximo por petición. Responde
429/503en vez de cargar el servidor. - Log de acceso sin tokens ni valores buscados (pueden ser datos personales).
Endpoints
| Método y ruta | Respuesta |
|---|---|
GET /v1/health |
{ ok, connector, contract: "v1", version, time } |
GET /v1/sources |
{ sources: [{ id, name }] } — carpetas/bases configuradas |
GET /v1/sources/:source/tables |
{ tables: [{ name, records, fields, version, modifiedAt }] } |
GET /v1/sources/:source/tables/:table/schema |
{ table, records, version, modifiedAt, fields: [{ name, type, size, decimals }] } |
GET /v1/sources/:source/tables/:table/rows |
{ table, version, modifiedAt, maxRecno, total, offset, limit, fields, rows } |
Parámetros de rows:
fields=A,Bcolumnas a devolver (por defecto todas las permitidas).limit(1…máximo del conector, def. 100) yoffsetpara paginar.q=textoyqFields=A,B: contiene, sin distinguir mayúsculas ni tildes.eq.CAMPO=valor: igualdad exacta (sin distinguir mayúsculas). Se pueden combinar varios.includeDeleted=1: incluye los registros marcados como borrados (_deleted).- Sincronización incremental (v1.1):
afterRecno=Ndevuelve solo lo agregado después del registro N;changedField=CAMPO&changedSince=valorsolo lo modificado después de ese valor (campo de fecha/hora del origen, comparado tal como lo devuelve el conector). Con ambos, basta cumplir uno. La respuesta traemaxRecnopara guardar como próximoafterRecno. Una sincronización completa periódica recoge los borrados.
Cada fila trae _recno (posición en el origen). version cambia cuando el origen se modifica:
el sistema la compara para saber si hace falta volver a sincronizar.
Tipos de dato en JSON: texto recortado (vacío → null), números, booleanos, fecha YYYY-MM-DD,
fecha-hora ISO 8601.
Errores: { error: "mensaje" } con 400 parámetro inválido, 401 token, 403 IP, 404
fuente/tabla, 405 método, 423 tabla bloqueada en el origen, 429 exceso de peticiones,
503 conector ocupado, 500 error interno (detalle solo en el log del conector).