312 lines
6.3 KiB
Markdown
312 lines
6.3 KiB
Markdown
|
|
# CLARA y MARGARET - Agentes de Ingesta
|
||
|
|
|
||
|
|
**Versión:** 5.0
|
||
|
|
**Fecha:** 2024-12-24
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Resumen
|
||
|
|
|
||
|
|
| Aspecto | CLARA | MARGARET |
|
||
|
|
|---------|-------|----------|
|
||
|
|
| Servidor | DECK (72.62.1.113) | CORP (92.112.181.188) |
|
||
|
|
| Puerto | 5051 | 5051 |
|
||
|
|
| Dominio | Personal | Empresarial |
|
||
|
|
| Base de datos | tzzr | corp |
|
||
|
|
| Tabla log | clara_log | margaret_log |
|
||
|
|
| Bucket R2 | deck | corp |
|
||
|
|
| Estado | Operativo | Operativo |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Arquitectura
|
||
|
|
|
||
|
|
```
|
||
|
|
PACKET (App móvil)
|
||
|
|
│
|
||
|
|
│ POST /ingest
|
||
|
|
│ Content-Type: multipart/form-data
|
||
|
|
│ X-Auth-Key: {h_instancia}
|
||
|
|
│
|
||
|
|
▼
|
||
|
|
┌─────────────────────────────────────────┐
|
||
|
|
│ CLARA (Personal) / MARGARET (Corp) │
|
||
|
|
│ │
|
||
|
|
│ 1. Validar h_instancia │
|
||
|
|
│ 2. Calcular h_entrada (SHA-256) │
|
||
|
|
│ 3. Subir archivos a R2 │
|
||
|
|
│ 4. Insertar en log (inmutable) │
|
||
|
|
│ 5. Estado: 'recibido' │
|
||
|
|
│ 6. Responder con h_entrada │
|
||
|
|
└─────────────────────────────────────────┘
|
||
|
|
│
|
||
|
|
▼
|
||
|
|
ALFRED / JARED (siguiente paso)
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Endpoint de Ingesta
|
||
|
|
|
||
|
|
### Request
|
||
|
|
|
||
|
|
```http
|
||
|
|
POST /ingest HTTP/1.1
|
||
|
|
Host: deck.example.com:5051
|
||
|
|
Content-Type: multipart/form-data
|
||
|
|
X-Auth-Key: {h_instancia}
|
||
|
|
|
||
|
|
--boundary
|
||
|
|
Content-Disposition: form-data; name="tipo"
|
||
|
|
|
||
|
|
documento
|
||
|
|
--boundary
|
||
|
|
Content-Disposition: form-data; name="archivo"; filename="doc.pdf"
|
||
|
|
Content-Type: application/pdf
|
||
|
|
|
||
|
|
{binary data}
|
||
|
|
--boundary--
|
||
|
|
```
|
||
|
|
|
||
|
|
### Response
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"success": true,
|
||
|
|
"h_entrada": "a1b2c3d4e5f6...",
|
||
|
|
"estado": "recibido",
|
||
|
|
"timestamp": "2024-12-24T12:00:00Z"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Cálculo de h_entrada
|
||
|
|
|
||
|
|
```python
|
||
|
|
import hashlib
|
||
|
|
import json
|
||
|
|
|
||
|
|
def calcular_h_entrada(h_instancia, tipo, contenido_bytes, timestamp):
|
||
|
|
"""
|
||
|
|
Calcula el hash único de entrada.
|
||
|
|
|
||
|
|
h_entrada = SHA-256(h_instancia:tipo:sha256(contenido):timestamp)
|
||
|
|
"""
|
||
|
|
hash_contenido = hashlib.sha256(contenido_bytes).hexdigest()
|
||
|
|
|
||
|
|
data = f"{h_instancia}:{tipo}:{hash_contenido}:{timestamp}"
|
||
|
|
|
||
|
|
return hashlib.sha256(data.encode()).hexdigest()
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Schema: clara_log / margaret_log
|
||
|
|
|
||
|
|
```sql
|
||
|
|
CREATE TABLE clara_log (
|
||
|
|
id BIGSERIAL PRIMARY KEY,
|
||
|
|
h_entrada VARCHAR(64) UNIQUE NOT NULL,
|
||
|
|
h_instancia VARCHAR(64) NOT NULL,
|
||
|
|
tipo VARCHAR(50) NOT NULL,
|
||
|
|
contenido_url TEXT, -- locker://deck/{h_entrada}/archivo
|
||
|
|
contenido_hash VARCHAR(64), -- SHA-256 del contenido
|
||
|
|
metadata JSONB,
|
||
|
|
estado VARCHAR(20) DEFAULT 'recibido',
|
||
|
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||
|
|
processed_at TIMESTAMPTZ,
|
||
|
|
processed_by VARCHAR(50) -- 'alfred' o 'manual'
|
||
|
|
);
|
||
|
|
|
||
|
|
-- margaret_log tiene schema idéntico
|
||
|
|
CREATE TABLE margaret_log (
|
||
|
|
id BIGSERIAL PRIMARY KEY,
|
||
|
|
h_entrada VARCHAR(64) UNIQUE NOT NULL,
|
||
|
|
h_instancia VARCHAR(64) NOT NULL,
|
||
|
|
tipo VARCHAR(50) NOT NULL,
|
||
|
|
contenido_url TEXT,
|
||
|
|
contenido_hash VARCHAR(64),
|
||
|
|
metadata JSONB,
|
||
|
|
estado VARCHAR(20) DEFAULT 'recibido',
|
||
|
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||
|
|
processed_at TIMESTAMPTZ,
|
||
|
|
processed_by VARCHAR(50)
|
||
|
|
);
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Estados del Log
|
||
|
|
|
||
|
|
| Estado | Descripción |
|
||
|
|
|--------|-------------|
|
||
|
|
| recibido | Ingesta completada, pendiente procesamiento |
|
||
|
|
| procesando | ALFRED/JARED está procesando |
|
||
|
|
| enviado_mason | Enviado a MASON para enriquecimiento |
|
||
|
|
| consolidado | Procesado por FELDMAN |
|
||
|
|
| error | Error en procesamiento |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Almacenamiento en R2
|
||
|
|
|
||
|
|
### Estructura de URLs
|
||
|
|
|
||
|
|
```
|
||
|
|
locker://deck/{h_entrada}/archivo.ext
|
||
|
|
locker://corp/{h_entrada}/archivo.ext
|
||
|
|
```
|
||
|
|
|
||
|
|
### Implementación
|
||
|
|
|
||
|
|
```python
|
||
|
|
import boto3
|
||
|
|
|
||
|
|
def subir_a_r2(bucket, h_entrada, archivo_bytes, filename):
|
||
|
|
"""Sube archivo a Cloudflare R2."""
|
||
|
|
|
||
|
|
s3 = boto3.client(
|
||
|
|
's3',
|
||
|
|
endpoint_url='https://7dedae6030f5554d99d37e98a5232996.r2.cloudflarestorage.com',
|
||
|
|
aws_access_key_id=R2_ACCESS_KEY,
|
||
|
|
aws_secret_access_key=R2_SECRET_KEY
|
||
|
|
)
|
||
|
|
|
||
|
|
key = f"{h_entrada}/{filename}"
|
||
|
|
|
||
|
|
s3.put_object(
|
||
|
|
Bucket=bucket,
|
||
|
|
Key=key,
|
||
|
|
Body=archivo_bytes
|
||
|
|
)
|
||
|
|
|
||
|
|
return f"locker://{bucket}/{key}"
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Validación de h_instancia
|
||
|
|
|
||
|
|
```python
|
||
|
|
def validar_instancia(h_instancia):
|
||
|
|
"""
|
||
|
|
Valida que h_instancia exista y esté activa.
|
||
|
|
|
||
|
|
TODO: Implementar tabla de instancias activas.
|
||
|
|
Actualmente: Validación básica de formato.
|
||
|
|
"""
|
||
|
|
if not h_instancia:
|
||
|
|
return False
|
||
|
|
|
||
|
|
if len(h_instancia) != 64:
|
||
|
|
return False
|
||
|
|
|
||
|
|
# TODO: Consultar tabla de instancias
|
||
|
|
return True
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Tipos de Ingesta Soportados
|
||
|
|
|
||
|
|
| Tipo | Descripción | Extensiones |
|
||
|
|
|------|-------------|-------------|
|
||
|
|
| documento | Documentos | pdf, doc, docx |
|
||
|
|
| imagen | Imágenes | jpg, png, gif |
|
||
|
|
| audio | Audio | mp3, wav, m4a |
|
||
|
|
| video | Video | mp4, mov |
|
||
|
|
| texto | Texto plano | txt, md |
|
||
|
|
| json | Datos estructurados | json |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Configuración
|
||
|
|
|
||
|
|
### Variables de Entorno
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# CLARA (.env en /opt/clara/)
|
||
|
|
DB_HOST=localhost
|
||
|
|
DB_PORT=5432
|
||
|
|
DB_NAME=tzzr
|
||
|
|
DB_USER=clara
|
||
|
|
DB_PASSWORD=****
|
||
|
|
|
||
|
|
R2_ENDPOINT=https://7dedae6030f5554d99d37e98a5232996.r2.cloudflarestorage.com
|
||
|
|
R2_ACCESS_KEY=****
|
||
|
|
R2_SECRET_KEY=****
|
||
|
|
R2_BUCKET=deck
|
||
|
|
|
||
|
|
# MARGARET (.env en /opt/margaret/)
|
||
|
|
DB_HOST=localhost
|
||
|
|
DB_PORT=5432
|
||
|
|
DB_NAME=corp
|
||
|
|
DB_USER=margaret
|
||
|
|
DB_PASSWORD=****
|
||
|
|
|
||
|
|
R2_BUCKET=corp
|
||
|
|
```
|
||
|
|
|
||
|
|
### Docker Compose
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
# CLARA
|
||
|
|
version: '3.8'
|
||
|
|
services:
|
||
|
|
clara:
|
||
|
|
container_name: clara-clara
|
||
|
|
image: tzzr/clara:latest
|
||
|
|
ports:
|
||
|
|
- "5051:5051"
|
||
|
|
env_file:
|
||
|
|
- .env
|
||
|
|
restart: unless-stopped
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Diferencias CLARA vs MARGARET
|
||
|
|
|
||
|
|
| Aspecto | CLARA | MARGARET |
|
||
|
|
|---------|-------|----------|
|
||
|
|
| Uso | Personal | Empresarial |
|
||
|
|
| Volumen | Bajo | Alto |
|
||
|
|
| Privacidad | Máxima | Compartida (empresa) |
|
||
|
|
| Integración | ALFRED | JARED → MASON → FELDMAN |
|
||
|
|
| Backup | deck bucket | corp bucket |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Seguridad
|
||
|
|
|
||
|
|
### Actual
|
||
|
|
- Autenticación por h_instancia
|
||
|
|
- Comunicación HTTP (sin TLS interno)
|
||
|
|
- .env con permisos 644 (**CRÍTICO: cambiar a 600**)
|
||
|
|
|
||
|
|
### Recomendado
|
||
|
|
- TLS interno con certificados
|
||
|
|
- Rate limiting
|
||
|
|
- Validación de tipos MIME
|
||
|
|
- Escaneo antivirus (ClamAV)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Monitoreo
|
||
|
|
|
||
|
|
### Logs
|
||
|
|
```bash
|
||
|
|
# CLARA
|
||
|
|
docker logs clara-clara -f
|
||
|
|
|
||
|
|
# MARGARET
|
||
|
|
docker logs margaret-margaret -f
|
||
|
|
```
|
||
|
|
|
||
|
|
### Métricas Sugeridas
|
||
|
|
- Ingestas por minuto
|
||
|
|
- Tamaño promedio de archivos
|
||
|
|
- Tiempo de procesamiento
|
||
|
|
- Errores por tipo
|