Modelo de datos¶
Postgres. Django ORM. El payload crudo de cada fuente se guarda en JSONB tal como llegó.
Por qué guardar el crudo
Reprocesar el normalizador sobre el histórico sin volver a descargar es una operación que se va a necesitar cada vez que se mejore una regla. Sin el crudo guardado, cada mejora cuesta una recarga completa contra APIs con cuota.
Diagrama¶
erDiagram
fuentes ||--o{ ingestas : "produce"
ingestas ||--o{ avisos : "contiene"
fuentes ||--o{ avisos : "origina"
proyectos ||--o{ avisos : "agrupa"
proyectos ||--o{ proyecto_versiones : "historial"
avisos ||--o{ decisiones : "evaluado en"
avisos ||--o{ documentos : "adjunta"
radares }o--|| paises : "ubicado en"
adjudicaciones }o--|| empresas : "ganada por"
fuentes {
int id PK
varchar nombre
varchar carril
varchar tipo
text endpoint
jsonb params
varchar cadencia
bool activo
timestamptz ultimo_ok
text watermark
}
ingestas {
int id PK
int fuente_id FK
timestamptz iniciada
varchar estado
int registros
text error
}
avisos {
int id PK
int fuente_id FK
varchar id_nativo
varchar hash
varchar escalon
varchar categoria_adquisicion
timestamptz fecha_limite_utc
int proyecto_id FK
jsonb crudo
}
proyectos {
int id PK
varchar id_nativo
varchar pais
varchar estado
jsonb crudo
timestamptz visto_por_ultima_vez
}
decisiones {
int id PK
int aviso_id FK
varchar decision
varchar codigo_razon
bool automatica
}
Tablas¶
fuentes¶
Registro de fuentes. Agregar una fuente es insertar una fila, no editar el orquestador.
| Campo | Tipo | Descripción |
|---|---|---|
nombre |
varchar | Identificador legible |
carril |
varchar | A, B, C — una fuente puede alimentar varios, se usa fila por carril |
tipo |
varchar | api_json, api_sql, rss, scrape, busqueda |
endpoint |
text | URL base |
metodo |
varchar | GET / POST |
params |
jsonb | Parámetros de la consulta |
cadencia |
varchar | diaria, semanal |
idioma, pais |
varchar | Para consultas multilingües y por país |
activo |
bool | Apagar una fuente sin borrarla |
watermark |
text | Última fecha o token procesado |
ultimo_ok |
timestamptz | Última corrida con resultados |
ingestas¶
Una fila por corrida por fuente. Es la base de la observabilidad.
avisos — carriles A y C¶
Append-only. Clave de deduplicación: fuente_id + id_nativo.
hash es un hash del contenido normalizado, aparte del ID. Sirve para detectar
modificaciones —prórroga de plazo, adenda— y reportarlas como cambio, no como aviso
nuevo.
crudo guarda el payload de la fuente sin tocar.
proyectos y proyecto_versiones — carril B¶
Upsert, no append. Cada corrida compara el snapshot nuevo contra la última versión y
guarda una fila en proyecto_versiones solo si cambió algo.
Lo que se reporta es el diff
El reporte del carril B muestra transiciones de estado, no filas nuevas. Un proyecto que sigue igual desde hace tres meses no aparece.
decisiones¶
Toda evaluación, incluidos los descartes automáticos.
Campos: aviso_id, fecha, decision (bid / no_bid / ignorar), codigo_razon,
quien, nota_libre, automatica.
Es el activo de largo plazo
En un año habrá un par de cientos de decisiones etiquetadas y se podrán revisar patrones a mano. Vale más que el modelo que no vamos a poder entrenar.
documentos¶
PDF descargados y su texto extraído. Se guarda el texto para no volver a descargar ni re-extraer.
Clave de caché: hash del archivo. El scoring con LLM también se cachea por ese hash.
radares, paises, empresas, adjudicaciones¶
El mapa de base instalada. Se pueblan en fase 3 desde WRD y desde el histórico de adjudicaciones del BID y el Banco Mundial.
Vista derivada clave: países con dos o más fabricantes distintos en el parque.
Reglas transversales¶
- Todas las fechas en
timestamptzen UTC, más el string original de la fuente en un campo aparte - Ningún campo de fecha límite es obligatorio: los avisos generales y las EOI frecuentemente no la traen
- Índice de texto completo de Postgres sobre
documentos.texto