← Memory
nexuslex.md
# NexusLex — Asistente Legal IA (Navas & Cusi)
## Estado: OPERATIVO (desplegado 10 abr 2026)
- **URL**: `https://navas.alexamigo.com` | **Puerto**: 5040
- **Acceso**: contraseña `01091988` (localStorage, sin JWT)
- **Proposito**: Regalo para bufete Navas & Cusi. Chat RAG sobre derecho bancario espanol.
## Stack
- **Backend**: FastAPI + uvicorn (2 workers) + SQLAlchemy + PostgreSQL
- **RAG**: ChromaDB (PersistentClient) + Gemini Embedding 001 (3072 dims) + OpenAI GPT-5.4-nano (streaming SSE)
- **Frontend**: React 19 + Vite + Tailwind CSS (dark theme dorado/azul marino)
- **Deploy**: systemd `nexuslex.service` + nginx reverse proxy + certbot SSL
## Credenciales
- **DB**: PostgreSQL `nexuslex` / user `nexuslex_user` / pass `NexusLex2026pg` (SIN `!`, dio problemas)
- **Gemini API** (embeddings): `AIzaSyB84Vfxlh12JY-Ni_byuoCnFFlQeWZjoEo`
- **OpenAI API** (LLM): `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`
- **ChromaDB path**: `/home/ubuntu/proyectos-cloud/nexuslex/chromadb_data`
- **Collection**: `boe_bancario`
## Estructura VPS: `/home/ubuntu/proyectos-cloud/nexuslex/`
```
├── backend/
│ ├── main.py # FastAPI app (CORS, routers, SPA serving)
│ ├── config.py # Pydantic settings (.env)
│ ├── models.py # SQLAlchemy: LegalArea, Document, Chunk, Conversation, Message, IngestLog
│ ├── database.py # Engine + SessionLocal + get_db
│ ├── routers/
│ │ ├── chat.py # POST /api/chat (SSE streaming)
│ │ ├── documents.py # GET /api/documents/stats, GET /api/documents
│ │ ├── ingest.py # POST /api/ingest/boe, GET /api/ingest/status
│ │ └── areas.py # GET /api/areas
│ ├── services/
│ │ ├── rag_engine.py # Pipeline: embed query → retrieve 8 chunks → prompt → stream LLM
│ │ ├── chromadb_client.py # ChromaDB wrapper (add_chunks, query_chunks)
│ │ ├── llm_client.py # OpenAI streaming (max_completion_tokens, NO max_tokens)
│ │ ├── embedding_client.py # Gemini embed_texts() + embed_query()
│ │ └── prompt_builder.py # System prompt legal + RAG template
│ ├── ingestion/
│ │ ├── boe_fetcher.py # BOE HTML fetcher (12 law IDs)
│ │ ├── document_processor.py # HTML cleaner + article extractor
│ │ ├── chunker.py # Chunking por articulos (500-1500 chars, overlap 100)
│ │ └── embedder.py # Full pipeline: fetch → process → chunk → embed → ChromaDB
│ ├── requirements.txt
│ └── venv/
├── frontend/
│ ├── src/
│ │ ├── App.tsx # Auth gate (localStorage password check)
│ │ ├── pages/AccessPage.tsx # Input contrasena + gradiente oscuro
│ │ ├── pages/ChatPage.tsx # Chat UI: MessageBubble, CitationBadge, WelcomeScreen, markdown renderer
│ │ ├── hooks/useChat.ts # SSE streaming via fetch + ReadableStream
│ │ └── index.css # Tailwind + custom properties dark theme
│ ├── vite.config.ts
│ └── package.json
├── chromadb_data/ # Persistencia ChromaDB
├── deploy.sh # npm build + systemctl restart
└── .env # Todas las API keys y config
```
## Base legal indexada (9 leyes, 3857 chunks)
1. Ley 5/2019 de Credito Inmobiliario (LCCI)
2. TRLGDCU (defensa consumidores)
3. LEC (procedimientos bancarios)
4. Codigo Civil (obligaciones y contratos)
5. Ley Condiciones Generales de Contratacion
6. Ley Credito al Consumo
7. Ley Servicios de Pago
8. Ley del Mercado de Valores
9. Orden EHA/2899/2011 (transparencia bancaria)
### Leyes NO indexadas (solo PDF en BOE, sin HTML):
- Ley Regulacion Mercado Hipotecario (1981)
- Ley Disciplina e Intervencion Entidades de Credito (1988)
- Ley de Usura / Ley Azcarate (1908)
## DB PostgreSQL — Tablas
- `legal_areas`: 16 areas (solo bancario activo en MVP)
- `documents`: source, source_id, title, document_type, publication_date, legal_area_id, raw_content, content_hash, chunk_count
- `chunks`: document_id, chunk_index, content, section_title (TEXT, no VARCHAR), chromadb_id
- `conversations`: id UUID, title, created_at
- `messages`: conversation_id, role, content, citations JSONB, chunks_used JSONB, tokens_used
- `ingest_logs`: source, status, documents_fetched/new/updated, chunks_created
## Endpoints API
| Metodo | Ruta | Que hace |
|--------|------|----------|
| GET | `/api/health` | Health check |
| POST | `/api/chat` | Chat con SSE streaming + RAG |
| GET | `/api/areas` | Lista areas legales |
| GET | `/api/documents/stats` | Stats: total docs + chunks |
| GET | `/api/documents` | Lista documentos indexados |
| POST | `/api/ingest/boe` | Trigger ingesta BOE (background) |
| GET | `/api/ingest/status` | Ultimo log de ingesta |
## Paleta colores frontend
- Fondos: `#0A0E1A` (principal), `#111827` (cards), `#1F2937` (hover)
- Dorado: `#C9A84C` (acento), `#E5C76B` (hover)
- Azul: `#1E3A5F` (institucional)
- Texto: `#F3F4F6` (principal), `#9CA3AF` (secundario)
## Comandos utiles
```bash
# Restart servicio
sudo systemctl restart nexuslex
sudo systemctl status nexuslex
# Ver logs
sudo journalctl -u nexuslex -f --no-pager
# Re-deploy frontend
cd /home/ubuntu/proyectos-cloud/nexuslex && bash deploy.sh
# Re-ingestar leyes
cd /home/ubuntu/proyectos-cloud/nexuslex && source backend/venv/bin/activate && python -c "
from backend.ingestion.embedder import run_full_ingestion
import asyncio
asyncio.run(run_full_ingestion())
"
# Consultar stats
curl https://navas.alexamigo.com/api/documents/stats
curl https://navas.alexamigo.com/api/health
```
## Errores conocidos y fixes aplicados
1. **Password `!` en PostgreSQL**: el `!` en connection string causa auth failure. Se quito: `NexusLex2026pg`
2. **SQLAlchemy `metadata` reservado**: usar `extra_metadata = Column("metadata", JSON)`
3. **Gemini embedding model**: usar `gemini-embedding-001` (estable), NO `gemini-embedding-exp-03-07`
4. **OpenAI GPT-5.4+**: usar `max_completion_tokens` en vez de `max_tokens`
5. **FastAPI catch-all `/{path:path}`**: debe ir DESPUES de los API routers, y guardia `if full_path.startswith("api/")`
6. **`section_title`**: cambiado de VARCHAR(500) a TEXT (articulos del CC tienen titulos muy largos)
7. **BOE leyes pre-1980**: solo PDF, `clean_boe_html()` devuelve "Texto no disponible" → skip automatico
## Escalabilidad LLM
- Cambiar modelo en `.env`: `LLM_MODEL=gpt-5.4-mini` (mas potente, ~$5/mes)
- Sin cambiar codigo, solo reiniciar servicio
## Posibles mejoras futuras
- Indexar mas leyes (derecho civil, mercantil, fiscal)
- Añadir las 3 leyes que solo tienen PDF (OCR o descarga manual)
- JWT auth real si se comparte con mas gente
- Historial de conversaciones en sidebar
- Exportar conversacion a PDF