ALEPH — Arquitectura y contrato técnico

  1. ¿Para qué existe aleph.md?

aleph.md no es un manual de usuario ni un tutorial paso-a-paso.

Es un documento de arquitectura y contrato técnico que responde a estas preguntas clave:

¿Dónde está ALEPH en el código?

¿Cuál es la única forma correcta de conectarse a ALEPH?

¿Cómo se accede a los datos (online vs offline)?

Cómo funciona la ingesta incremental (snapshot inteligente)

Qué entidades están soportadas y cómo se relacionan

Su función principal es evitar regresiones y evitar duplicación caótica en el futuro.

  1. Qué sí vamos a guardar en aleph.md 2.1. Propósito y alcance (breve)

Una sección corta que deje esto explícito:

ALEPH es el sistema fuente de datos operativos (empresas, proyectos, cotizaciones, contratos). Este módulo define cómo se consulta, cómo se congela y cómo se consume esa información dentro de Prodisys.

Esto sirve para que, dentro de 6 meses, nadie se pregunte:

“¿Por qué hay JSONL aquí?” “¿Por qué no consultamos directo la base?”

2.2. Arquitectura oficial (muy importante)

Aquí se deja claro el contrato:

prodisys/ aleph/ db.py ← conexión y ejecución SQL (único lugar) queries.py ← SQL de negocio (fetch_*) ingest/ ingest_aleph.py ← snapshot incremental snapshots.py ← lectura offline

Y se escribe explícitamente:

❌ Prohibido copiar SQL en notebooks o en la APP

❌ Prohibido crear engines en varios sitios

✅ Toda consulta pasa por queries.py

✅ Toda conexión pasa por db.py

Esto no es burocracia: es control de complejidad futura.

2.3. Conexión a ALEPH (sin credenciales)

Aquí no se ponen contraseñas, solo la responsabilidad del módulo:

Ejemplo de texto:

prodisys.aleph.db es el único responsable de:

crear el SQLAlchemy Engine

reutilizar la conexión (singleton)

ejecutar SQL crudo

Ningún otro módulo crea conexiones directas.

Esto sirve para:

debugging

cambiar DSN en un solo sitio

aislar ALEPH si mañana cambia

2.4. Consultas de negocio (queries.py)

Aquí se documenta qué existe, no el SQL completo:

Función Entidad Fuente fetch_empresas() Empresas EMPRESAS fetch_proyectos() Proyectos PROYECTOS fetch_cotizaciones() Cotizaciones COTIZACIONES fetch_cotiza_proyecto() Relación COTIZA_PROYECTO fetch_contratos() Contratos CONTRATOS

Y se aclara:

Las funciones devuelven listas de dicts

Los nombres de campos ya vienen normalizados

Son reutilizables tanto por la ingesta como por la APP

2.5. Snapshot incremental (el corazón del sistema)

Esta es una de las partes más importantes del documento.

Aquí se explica conceptualmente:

Qué es un snapshot incremental

Qué es un índice por entidad

Qué significa “0 registros escritos”

Ejemplo de explicación clara:

Cada corrida compara el hash del payload actual con el último hash conocido por clave lógica.

Si no hay cambios, no se escribe nada.

Por eso una corrida con:

empresas: 0 registros

significa “no hubo cambios”, no “falló”.

También se documenta la clave lógica por entidad:

Entidad Key lógica Empresa NIT Proyecto id_proyecto Cotización id_cotizacion Proyecto–Cotización id_proyecto__id_cotizacion Contrato id_contrato

Esto es oro para mantenimiento futuro.

2.6. Modo online vs modo offline

Aquí se deja cristalino cómo se consume ALEPH:

Modo online:

from prodisys.aleph.queries import fetch_proyectos

Modo offline:

from prodisys.ingest.snapshots import load_latest_by_key

Y se aclara cuándo usar cada uno:

Online → exploración, dashboards vivos, debugging

Offline → análisis, modelos, joins pesados, histórico

2.7. Qué NO va en aleph.md

Esto es igual de importante:

❌ No va SQL completo ❌ No va lógica de pandas ❌ No va documentación de notebooks ❌ No va análisis de negocio ❌ No va ETL hacia otros sistemas

Eso vive en otros documentos.

  1. Qué problema resuelve este documento

Sin aleph.md, en 6–12 meses pasa esto:

alguien copia SQL en un notebook

otro crea otro engine

otro cambia una columna

el incremental “deja de funcionar”

nadie sabe por qué

Con aleph.md:

hay una única fuente de verdad

hay reglas explícitas

el sistema es explicable

  1. Qué haremos después de aleph.md

Una vez esto quede documentado:

docs/vistas_aleph.md → cómo se construyen vistas (joins, columnas finales)

docs/documentos_proyecto.md → dosieres, agendas, notas, PDFs, escaneos (otro dominio)

ALEPH queda cerrado y estable.

Si quiere, en el próximo mensaje puedo:

escribir la versión final de aleph.md lista para commit, o

revisar su borrador y ajustarlo con lenguaje técnico preciso

Usted decide.

You said: ponga la versión final de aleph.md bien documentado ChatGPT said:

Perfecto. A continuación tiene la versión final y estable de docs/aleph.md, redactada como documento de arquitectura y contrato técnico, lista para commit sin ajustes adicionales.

ALEPH — Arquitectura, Ingesta y Consumo de Datos

  1. Propósito

ALEPH es el sistema fuente de información operativa para Prodisys. Contiene entidades maestras y transaccionales como:

Empresas

Proyectos

Cotizaciones

Contratos

Relaciones entre proyectos y cotizaciones

Este documento define la forma oficial y única de:

Conectarse a ALEPH

Consultar datos (modo online)

Congelar datos mediante snapshots incrementales (modo offline)

Consumir información en la APP y en notebooks

Su objetivo principal es garantizar estabilidad, trazabilidad y evitar duplicación de lógica.

  1. Principios de diseño

Una sola fuente de verdad para la conexión

Un solo lugar para el SQL

Separación clara entre consulta, ingesta y consumo

Soporte explícito para trabajo online y offline

Ingesta incremental (no snapshots completos repetidos)

Cualquier código que viole estos principios se considera técnicamente incorrecto.

  1. Estructura de módulos prodisys/ aleph/ db.py # conexión y ejecución SQL (único lugar) queries.py # consultas de negocio (fetch_*) ingest/ ingest_aleph.py # snapshot incremental desde ALEPH snapshots.py # lectura de snapshots JSONL

Reglas obligatorias

❌ No se crean engines fuera de db.py

❌ No se ejecuta SQL fuera de queries.py

❌ No se copian credenciales ni DSN en notebooks o scripts

✅ Toda consulta pasa por queries.py

✅ Toda conexión pasa por db.py

  1. Conexión a ALEPH (prodisys.aleph.db)

Este módulo es el único responsable de:

Crear el Engine de SQLAlchemy

Reutilizar la conexión (singleton)

Ejecutar SQL crudo

Conceptualmente:

from prodisys.aleph.db import run_query

Ningún otro módulo debe:

importar sqlalchemy.create_engine

manejar credenciales

abrir conexiones directas

Esto permite cambiar el DSN, driver o entorno en un solo sitio.

  1. Consultas de negocio (prodisys.aleph.queries)

Las consultas a ALEPH están encapsuladas como funciones fetch_*.

Funciones disponibles Función Entidad Tabla fuente fetch_empresas() Empresas EMPRESAS fetch_proyectos() Proyectos PROYECTOS fetch_cotizaciones() Cotizaciones COTIZACIONES fetch_cotiza_proyecto() Relación proyecto–cotización COTIZA_PROYECTO fetch_contratos() Contratos CONTRATOS Contrato de salida

Devuelven List[Dict[str, Any]]

Los nombres de campos vienen normalizados

No aplican lógica de negocio ni joins complejos

Estas funciones son reutilizadas por:

la ingesta (ingest_aleph.py)

la APP

notebooks exploratorios (modo online)

  1. Ingesta incremental (snapshots)

La ingesta desde ALEPH se realiza mediante snapshots incrementales, no copias completas repetidas.

Archivo responsable prodisys/ingest/ingest_aleph.py

Idea central

Cada entidad tiene una clave lógica

Se calcula un hash del payload

Solo se escribe una nueva versión si el contenido cambió

Por eso es normal y esperado que una corrida muestre:

empresas: 0 registros

Esto significa: no hubo cambios, no que la ingesta falló.

  1. Claves lógicas por entidad Entidad Clave lógica Empresa NIT Proyecto id_proyecto Cotización id_cotizacion Proyecto–Cotización id_proyecto__id_cotizacion Contrato id_contrato

Cada clave se indexa en un archivo JSON independiente dentro de:

data/ingest/index_*.json

  1. Formato de los snapshots

Los snapshots se almacenan como JSONL append-only:

{ «source»: «aleph», «entity»: «proyecto», «key»: «A516», «ts»: «2025-12-05T20:20:48Z», «payload»: { … } }

Nunca se sobrescriben versiones anteriores.

  1. Consumo de datos 9.1. Modo online (consulta directa)

Uso típico:

exploración

dashboards vivos

debugging

from prodisys.aleph.queries import fetch_proyectos import pandas as pd

df = pd.DataFrame(fetch_proyectos())

9.2. Modo offline (snapshots congelados)

Uso típico:

análisis

joins pesados

histórico

reproducibilidad

from prodisys.ingest.snapshots import load_latest_by_key from pathlib import Path

BASE = Path(«data/ingest») proyectos = load_latest_by_key(BASE / «aleph_proyectos.jsonl»)

Ambos modos usan el mismo modelo lógico.

  1. Qué NO cubre este módulo

ALEPH no cubre:

documentos (PDF, imágenes, escaneos)

agendas, notas, dosieres

inventarios

visitas técnicas

lógica de negocio avanzada

reporting final

Esos dominios viven en módulos separados.

  1. Estado actual

ALEPH está considerado estable

La estructura es la referencia oficial

Cambios futuros deben respetar este contrato

Cualquier extensión debe:

reutilizar db.py

reutilizar queries.py

mantener compatibilidad con snapshots existentes

  1. Documentos relacionados

docs/vistas_aleph.md → vistas y joins derivados

docs/documentos_proyecto.md → dosieres, agendas, archivos

docs/ingest.md → reglas generales de ingesta