# 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. 2. 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. 3. 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 4. 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. 2. 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. 3. 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 4. 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. 5. 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) 6. 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ó. 7. 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 8. 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. 9. 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. 10. 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. 11. 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 12. Documentos relacionados docs/vistas_aleph.md → vistas y joins derivados docs/documentos_proyecto.md → dosieres, agendas, archivos docs/ingest.md → reglas generales de ingesta