An open API service indexing awesome lists of open source software.

https://github.com/santifer/cv-santiago

Interactive CV with AI chat integration. Built with React 19, TypeScript, Claude API. Chat with my AI avatar about my experience.
https://github.com/santifer/cv-santiago

ai chatbot claude langfuse llm llmops observability portfolio react tailwindcss typescript vercel vite

Last synced: about 1 month ago
JSON representation

Interactive CV with AI chat integration. Built with React 19, TypeScript, Claude API. Chat with my AI avatar about my experience.

Awesome Lists containing this project

README

          

# santifer.io

**[:gb: English](#the-problem)** | **[:es: Español](#es-versión-en-español)**

> Interactive portfolio with AI chatbot (text + voice), agentic RAG, 71 automated evals, LLMOps dashboard, and 6-layer prompt injection defense

[![Live Demo](https://img.shields.io/badge/demo-santifer.io-blue?style=flat-square)](https://santifer.io)
[![Built with Claude Code](https://img.shields.io/badge/built%20with-Claude%20Code-blueviolet?style=flat-square)](https://claude.ai/code)

---


santifer.io in motion

---

## The Problem

Static CVs don't show what you can actually build. A PDF lists skills — it doesn't prove them.

## The Solution

A production-grade interactive portfolio that **demonstrates the skills it describes**: dual-mode AI chatbot (text + voice) with agentic RAG, full LLMOps observability with custom dashboard, 71 automated evals as CI gate, prompt versioning, and a closed-loop that generates tests from production failures.

**Key Features:**
- **AI Chatbot "Santi"** — Text (Claude Sonnet) + Voice (OpenAI Realtime API). Responds in first person as Santiago. Agentic RAG with hybrid search (pgvector + BM25) and Haiku reranking
- **6-Layer Defense** — Keyword detection, canary tokens, fingerprinting, anti-extraction, online safety scoring, adversarial red team. Real-time jailbreak email alerts
- **71 Automated Evals** — 10 categories: factual accuracy, persona, boundaries, quality, safety, language, RAG quality, multi-turn, source badges, voice quality. CI gate on every push
- **LLMOps Dashboard** — Private `/ops` with 8 tabs: Overview, Conversations, Costs, RAG, Security, Evals, Voice, System. Real data from Langfuse + Supabase
- **Closed Loop** — Trace → online scoring → quality < 0.7 → auto-generate test → CI gate blocks deploy
- **Voice Mode** — OpenAI Realtime API, audio-to-audio, shared RAG pipeline, ~$0.25/session
- **6 Published Case Studies** — Bilingual (ES/EN) with JSON-LD, prerendered HTML, cross-linked RAG, and interactive architecture diagrams
- **Interactive Architecture Diagram** — GSAP-animated SVG with narrated audio, pan/zoom, dark mode sync. [Explore it →](https://santifer.io/self-healing-chatbot#architecture)
- **GEO-ready** — `llms.txt`, structured data (JSON-LD), AI crawler-friendly robots.txt

---

## Tech Stack

![React](https://img.shields.io/badge/React_19-61DAFB?style=flat&logo=react&logoColor=black)
![TypeScript](https://img.shields.io/badge/TypeScript-3178C6?style=flat&logo=typescript&logoColor=white)
![Vite](https://img.shields.io/badge/Vite_7-646CFF?style=flat&logo=vite&logoColor=white)
![Tailwind](https://img.shields.io/badge/Tailwind_v4-06B6D4?style=flat&logo=tailwindcss&logoColor=white)
![Claude](https://img.shields.io/badge/Claude_Sonnet-191919?style=flat&logo=anthropic&logoColor=white)
![OpenAI](https://img.shields.io/badge/OpenAI_Realtime-412991?style=flat&logo=openai&logoColor=white)
![Langfuse](https://img.shields.io/badge/Langfuse-000000?style=flat&logoColor=white)
![Supabase](https://img.shields.io/badge/Supabase-3FCF8E?style=flat&logo=supabase&logoColor=white)
![Vercel](https://img.shields.io/badge/Vercel_Edge-000000?style=flat&logo=vercel&logoColor=white)
![Recharts](https://img.shields.io/badge/Recharts-FF6384?style=flat&logoColor=white)

---

## Chatbot Architecture

[![Interactive Architecture Diagram](public/chatbot/diagram-thumbnail.webp)](https://santifer.io/self-healing-chatbot#architecture)
> **[Explore the interactive diagram →](https://santifer.io/self-healing-chatbot#architecture)** 10 phases · narrated audio · zoom + pan

```
User message → FloatingChat.tsx → api/chat.js (Vercel Edge)
├── System prompt (Langfuse registry + fallback)
├── Claude Sonnet (tool_use decision)
├── Agentic RAG (if needed):
│ ├── OpenAI embeddings (text-embedding-3-small)
│ ├── Supabase pgvector (semantic) + full-text (BM25)
│ └── Claude Haiku (reranking + diversification)
├── Claude Sonnet (streaming generation)
├── Langfuse tracing (every span with cost)
└── waitUntil → Haiku scoring (0ms added latency)

Voice mode → useVoiceMode.ts → api/voice-token.js → OpenAI Realtime WebSocket
└── api/rag-search.js (function calling for RAG)
```

### Key Files

| File | Path | Description |
|------|------|-------------|
| Chat edge function | `api/chat.js` | Main chatbot — RAG, tracing, scoring, streaming, defense |
| RAG pipeline | `api/_shared/rag.js` | Hybrid search, reranking, cost tracking, intent classification |
| Prompt management | `api/_shared/prompt.js` | Langfuse prompt registry with file fallback |
| Voice token | `api/voice-token.js` | OpenAI Realtime ephemeral token + rate limiting |
| Voice RAG | `api/rag-search.js` | RAG search for voice mode function calling |
| Voice trace | `api/voice-trace.js` | Voice session tracing with cost estimation |
| Chat widget | `src/FloatingChat.tsx` | React widget — streaming SSE, quick prompts, contact CTA |
| Voice hook | `src/useVoiceMode.ts` | WebSocket management, audio capture, transcript persistence |
| System prompt | `chatbot-prompt.txt` | Fallback prompt (production uses Langfuse v5) |

---

## LLMOps Dashboard (`/ops`)

Private, password-protected dashboard with 8 tabs showing real production data:

| Tab | What it shows | Data source |
|-----|---------------|-------------|
| Overview | KPIs, timelines, donuts, intent distribution | Langfuse traces |
| Conversations | Filter + list + detail with spans, cost, latency, scores | Langfuse traces + observations |
| Costs | Breakdown per component (toolDecision/embedding/reranking/generation/voice) | `trace.metadata.cost` |
| RAG | Activation rate, chunks per article | Langfuse tags + Supabase |
| Security | Defense funnel, safety distribution, jailbreak list | Langfuse tags + scores |
| Evals | Pass rates by category (embedded from real eval reports) | `evals/results/` via build |
| Voice | Sessions, text/voice split, latency P50/P95, cost per minute | Langfuse tags |
| System | Prompt versions, RAG document stats, model pricing | Langfuse prompts API + Supabase |

### Dashboard API Layer

| Endpoint | Path | Description |
|----------|------|-------------|
| Auth | `api/ops/auth.js` | Login (validates `OPS_DASHBOARD_SECRET`) |
| Stats | `api/ops/stats.js` | Aggregated stats, server-side compute from traces |
| Traces | `api/ops/traces.js` | List traces with filters (lang, mode, RAG, jailbreak) |
| Trace detail | `api/ops/trace/[id].js` | Full trace with observations, scores, Langfuse link |
| Evals | `api/ops/evals.js` | Eval results embedded from build |
| Prompts | `api/ops/prompts.js` | Prompt versions from Langfuse |
| RAG stats | `api/ops/rag-stats.js` | Document stats from Supabase |

---

## Evals & Testing

71 automated tests across 10 categories. ~70% deterministic (contains, regex, word count), ~30% LLM-as-Judge (Haiku).

| Category | Tests | Type |
|----------|-------|------|
| factual_accuracy | 9 | Deterministic |
| persona_adherence | 4 | Deterministic |
| boundary_testing | 7 | Deterministic |
| response_quality | 7 | Mixed |
| safety_jailbreak | 7 | Deterministic |
| language_handling | 5 | Deterministic |
| rag_quality | 16 | Mixed |
| multi_turn | 5 | Mixed |
| source_badges | 5 | Deterministic |
| voice_quality | 6 | Mixed |

---

## Scripts & CLI Tools

All scripts live in `scripts/` and run via `npm run`:

### Chatbot Operations
| Command | Script | Description |
|---------|--------|-------------|
| `npm run evals` | `evals/runner.ts` | Run 71 automated evals |
| `npm run adversarial` | `scripts/adversarial-test.ts` | Red team: 20+ auto-generated attacks |
| `npm run chats` | `scripts/chats.ts` | View last 50 conversations from Langfuse |
| `npm run chats -- --full` | `scripts/chats.ts` | Full conversations with messages |
| `npm run chats -- --jailbreak` | `scripts/chats.ts` | Only jailbreak attempts |
| `npm run evaluate-traces` | `scripts/evaluate-traces.ts` | Batch eval with Haiku (quality, safety, intent) |
| `npm run diagnose:rag` | `scripts/diagnose-rag.ts` | RAG quality diagnostic — detects retrieval misses |

### Prompt & RAG Management
| Command | Script | Description |
|---------|--------|-------------|
| `npm run prompt:sync` | `scripts/sync-prompt-to-langfuse.ts` | Sync prompt to Langfuse (hash-based, skip if unchanged) |
| `npm run prompt:regression` | `scripts/prompt-regression.ts` | Compare two prompt versions side by side |
| `npm run rag:sync` | `scripts/export-chunks.ts` + `scripts/ingest-rag.ts` | Re-export articles + ingest to Supabase |

### Contract & Integration Tests
| Command | Script | Description |
|---------|--------|-------------|
| `npm run test:contract` | `tests/ops-contract.test.ts` | Validate trace metadata matches dashboard contract (67 tests) |
| `npm run test:ops` | `tests/ops-dashboard.test.ts` | Test all 7 dashboard API endpoints (102 tests) |

### Build Pipeline
| Command | Script | Description |
|---------|--------|-------------|
| `npm run build` | (chained) | rag:sync → prompt:sync → embed-evals → reddit-stats → tsc → vite → sitemap → validate → prerender |
| — | `scripts/embed-evals.ts` | Parse eval reports → embed in dashboard |
| — | `scripts/generate-sitemap.ts` | Generate sitemap.xml with lastmod |
| — | `scripts/validate-articles.ts` | SEO validation (dates, keywords, OG images) |
| — | `scripts/validate-llms-txt.ts` | Validate llms.txt consistency |
| — | `scripts/prerender.tsx` | SSR prerender all pages with critical CSS |
| — | `scripts/indexnow-ping.ts` | Ping Bing/Yandex on deploy |

---

## Quick Start

```bash
git clone https://github.com/santifer/cv-santiago.git
cd cv-santiago
npm install
npm run dev
```

Open [localhost:5173](http://localhost:5173)

### Environment Variables

```bash
# Core
ANTHROPIC_API_KEY= # Claude API (chatbot)
OPENAI_API_KEY= # Embeddings + Voice

# RAG
SUPABASE_URL= # Supabase project URL
SUPABASE_SERVICE_ROLE_KEY= # Supabase service key

# Observability
LANGFUSE_PUBLIC_KEY= # Langfuse tracing
LANGFUSE_SECRET_KEY= # Langfuse tracing

# Alerts & Dashboard
RESEND_API_KEY= # Jailbreak email alerts
OPS_DASHBOARD_SECRET= # Dashboard password (/ops)
```

---

## Project Structure

```
src/
├── App.tsx # Full CV — all sections
├── FloatingChat.tsx # Chat widget (text mode)
├── useVoiceMode.ts # Voice mode hook (OpenAI Realtime)
├── VoiceOrb.tsx # Voice UI (orb + transcript)
├── GlobalNav.tsx # Navigation with breadcrumbs
├── main.tsx # React Router + lazy loading
├── i18n.ts # Bilingual translations
├── articles/
│ ├── registry.ts # Centralized article config
│ ├── components.tsx # Shared article components
│ └── json-ld.ts # JSON-LD builder
├── ops/ # LLMOps Dashboard
│ ├── OpsDashboard.tsx # Shell + Overview tab
│ ├── OpsAuth.tsx # Login screen
│ ├── types.ts # Shared TypeScript interfaces
│ ├── hooks/ # useOpsApi, useTraces
│ ├── components/ # KpiCard, MetricChart, FilterBar, etc.
│ └── tabs/ # Conversations, Costs, Security, Evals, etc.
├── [Article].tsx # Case study components (5 articles)
└── [article]-i18n.ts # Bilingual content per article

api/
├── chat.js # Main chatbot edge function
├── voice-token.js # Voice ephemeral token + rate limit
├── voice-trace.js # Voice session tracing
├── rag-search.js # RAG for voice function calling
├── _shared/
│ ├── rag.js # RAG pipeline (search, rerank, cost)
│ ├── prompt.js # Prompt versioning (Langfuse)
│ └── ops-auth.js # Dashboard auth helper
└── ops/ # Dashboard API proxy layer
├── auth.js # Login
├── stats.js # Aggregated stats
├── traces.js # Trace list with filters
├── trace/[id].js # Trace detail
├── evals.js # Eval results
├── prompts.js # Prompt versions
└── rag-stats.js # RAG document stats

evals/
├── datasets/ # 10 JSON datasets (71 test cases)
├── assertions.ts # Deterministic assertions
├── llm-judge.ts # LLM-as-Judge (Haiku)
└── runner.ts # Eval runner

scripts/ # See "Scripts & CLI Tools" section above
tests/
├── ops-contract.test.ts # Contract tests (67 assertions)
└── ops-dashboard.test.ts # Dashboard API tests (102 assertions)

chatbot-prompt.txt # System prompt (fallback, prod uses Langfuse)
```

---

## Case Studies

| Article | Slugs | Type |
|---------|-------|------|
| Self-Healing Chatbot | `/chatbot-que-se-cura-solo` `/self-healing-chatbot` | case-study |
| Career-Ops | `/career-ops` `/career-ops-system` | case-study |
| Jacobo AI Agent | `/agente-ia-jacobo` `/ai-agent-jacobo` | case-study |
| Business OS | `/business-os-para-airtable` `/business-os-for-airtable` | case-study |
| Programmatic SEO | `/seo-programatico` `/programmatic-seo` | case-study |
| n8n for PMs | `/n8n-para-pms` `/n8n-for-pms` | collab |
| Santifer iRepair | `/santifer-irepair` `/santifer-irepair-founder` | bridge |

---

## Cost

- **<$0.005 per text conversation** (5 models in the pipeline)
- **~$0.25 per voice session** (OpenAI Realtime)
- **$0 infrastructure** (free tiers: Vercel, Supabase, Langfuse)
- **~$30/month** estimated at 200 conversations/day

---

## License

MIT

---

---

# :es: Versión en Español

> Portfolio interactivo con chatbot IA (texto + voz), RAG agéntico, 71 evals automatizados, dashboard LLMOps y defensa anti-inyección en 6 capas

[![Demo en vivo](https://img.shields.io/badge/demo-santifer.io-blue?style=flat-square)](https://santifer.io)

---


santifer.io en movimiento

---

## El Problema

Los CVs estáticos no demuestran lo que realmente sabes construir. Un PDF lista habilidades — no las prueba.

## La Solución

Un portfolio interactivo de nivel producción que **demuestra las habilidades que describe**: chatbot IA dual (texto + voz) con RAG agéntico, observabilidad LLMOps completa con dashboard custom, 71 evals automatizados como CI gate, versionado de prompts, y un closed-loop que genera tests de fallos en producción.

**Funcionalidades:**
- **Chatbot IA "Santi"** — Texto (Claude Sonnet) + Voz (OpenAI Realtime API). Responde en primera persona como Santiago. RAG agéntico con búsqueda híbrida (pgvector + BM25) y reranking con Haiku
- **Defensa en 6 capas** — Keyword detection, canary tokens, fingerprinting, anti-extraction, online safety scoring, adversarial red team. Alertas de jailbreak por email en tiempo real
- **71 Evals automatizados** — 10 categorías: factual, persona, boundaries, quality, safety, language, RAG, multi-turn, source badges, voice. CI gate en cada push
- **Dashboard LLMOps** — `/ops` privado con 8 pestañas: Overview, Conversations, Costs, RAG, Security, Evals, Voice, System. Datos reales de Langfuse + Supabase
- **Closed Loop** — Traza → scoring online → quality < 0.7 → auto-genera test → CI gate bloquea deploy
- **Modo voz** — OpenAI Realtime API, audio-to-audio, mismo pipeline RAG, ~$0.25/sesión
- **6 Case Studies publicados** — Bilingües (ES/EN) con JSON-LD, HTML prerenderizado, RAG cross-linked y diagramas de arquitectura interactivos
- **Diagrama de Arquitectura Interactivo** — SVG animado con GSAP, audio narrado, pan/zoom, sync dark mode. [Explorar →](https://santifer.io/chatbot-que-se-cura-solo#architecture)
- **GEO-ready** — `llms.txt`, datos estructurados (JSON-LD), robots.txt amigable con crawlers IA

---

## Stack Técnico

![React](https://img.shields.io/badge/React_19-61DAFB?style=flat&logo=react&logoColor=black)
![TypeScript](https://img.shields.io/badge/TypeScript-3178C6?style=flat&logo=typescript&logoColor=white)
![Vite](https://img.shields.io/badge/Vite_7-646CFF?style=flat&logo=vite&logoColor=white)
![Tailwind](https://img.shields.io/badge/Tailwind_v4-06B6D4?style=flat&logo=tailwindcss&logoColor=white)
![Claude](https://img.shields.io/badge/Claude_Sonnet-191919?style=flat&logo=anthropic&logoColor=white)
![OpenAI](https://img.shields.io/badge/OpenAI_Realtime-412991?style=flat&logo=openai&logoColor=white)
![Langfuse](https://img.shields.io/badge/Langfuse-000000?style=flat&logoColor=white)
![Supabase](https://img.shields.io/badge/Supabase-3FCF8E?style=flat&logo=supabase&logoColor=white)
![Vercel](https://img.shields.io/badge/Vercel_Edge-000000?style=flat&logo=vercel&logoColor=white)
![Recharts](https://img.shields.io/badge/Recharts-FF6384?style=flat&logoColor=white)

---

## Arquitectura del Chatbot

[![Diagrama Interactivo de Arquitectura](public/chatbot/diagram-thumbnail.webp)](https://santifer.io/chatbot-que-se-cura-solo#architecture)
> **[Explorar el diagrama interactivo →](https://santifer.io/chatbot-que-se-cura-solo#architecture)** 10 fases · audio narrado · zoom + pan

```
Mensaje → FloatingChat.tsx → api/chat.js (Vercel Edge)
├── System prompt (Langfuse registry + fallback)
├── Claude Sonnet (decisión tool_use)
├── RAG Agéntico (si necesario):
│ ├── OpenAI embeddings (text-embedding-3-small)
│ ├── Supabase pgvector (semántico) + full-text (BM25)
│ └── Claude Haiku (reranking + diversificación)
├── Claude Sonnet (generación streaming)
├── Langfuse tracing (cada span con coste)
└── waitUntil → Haiku scoring (0ms de latencia añadida)

Modo voz → useVoiceMode.ts → api/voice-token.js → OpenAI Realtime WebSocket
└── api/rag-search.js (function calling para RAG)
```

### Archivos Clave

| Archivo | Ruta | Descripción |
|---------|------|-------------|
| Chat edge function | `api/chat.js` | Chatbot principal — RAG, tracing, scoring, streaming, defensa |
| Pipeline RAG | `api/_shared/rag.js` | Búsqueda híbrida, reranking, coste, clasificación de intención |
| Gestión de prompt | `api/_shared/prompt.js` | Langfuse prompt registry con fallback local |
| Token de voz | `api/voice-token.js` | Token efímero OpenAI Realtime + rate limiting |
| RAG voz | `api/rag-search.js` | Búsqueda RAG para function calling de voz |
| Trace voz | `api/voice-trace.js` | Tracing de sesiones de voz con estimación de coste |
| Widget chat | `src/FloatingChat.tsx` | Widget React — streaming SSE, quick prompts, CTA de contacto |
| Hook de voz | `src/useVoiceMode.ts` | Gestión WebSocket, captura audio, persistencia de transcript |
| System prompt | `chatbot-prompt.txt` | Prompt fallback (producción usa Langfuse v5) |

---

## Dashboard LLMOps (`/ops`)

Dashboard privado protegido por contraseña con 8 pestañas mostrando datos reales:

| Pestaña | Qué muestra | Fuente de datos |
|---------|-------------|-----------------|
| Overview | KPIs, timelines, donuts, distribución de intents | Trazas Langfuse |
| Conversations | Filtros + lista + detalle con spans, coste, latencia, scores | Trazas + observaciones |
| Costs | Desglose por componente (toolDecision/embedding/reranking/generation/voice) | `trace.metadata.cost` |
| RAG | Tasa de activación, chunks por artículo | Tags Langfuse + Supabase |
| Security | Funnel de defensa, distribución de safety, lista de jailbreaks | Tags + scores |
| Evals | Pass rates por categoría (embebidos de reports reales) | `evals/results/` via build |
| Voice | Sesiones, split texto/voz, latencia P50/P95, coste por minuto | Tags Langfuse |
| System | Versiones de prompt, stats de documentos RAG, precios de modelos | API prompts Langfuse + Supabase |

---

## Evals y Testing

71 tests automatizados en 10 categorías. ~70% deterministas, ~30% LLM-as-Judge (Haiku).

| Categoría | Tests | Tipo |
|-----------|-------|------|
| factual_accuracy | 9 | Determinista |
| persona_adherence | 4 | Determinista |
| boundary_testing | 7 | Determinista |
| response_quality | 7 | Mixto |
| safety_jailbreak | 7 | Determinista |
| language_handling | 5 | Determinista |
| rag_quality | 16 | Mixto |
| multi_turn | 5 | Mixto |
| source_badges | 5 | Determinista |
| voice_quality | 6 | Mixto |

---

## Scripts y Herramientas CLI

Todos los scripts están en `scripts/` y se ejecutan con `npm run`:

### Operaciones del Chatbot
| Comando | Script | Descripción |
|---------|--------|-------------|
| `npm run evals` | `evals/runner.ts` | Ejecutar 71 evals automatizados |
| `npm run adversarial` | `scripts/adversarial-test.ts` | Red team: 20+ ataques auto-generados |
| `npm run chats` | `scripts/chats.ts` | Ver últimas 50 conversaciones de Langfuse |
| `npm run chats -- --full` | `scripts/chats.ts` | Conversaciones completas con mensajes |
| `npm run chats -- --jailbreak` | `scripts/chats.ts` | Solo intentos de jailbreak |
| `npm run evaluate-traces` | `scripts/evaluate-traces.ts` | Eval batch con Haiku (calidad, seguridad, intención) |
| `npm run diagnose:rag` | `scripts/diagnose-rag.ts` | Diagnóstico de calidad RAG — detecta retrieval misses |

### Gestión de Prompt y RAG
| Comando | Script | Descripción |
|---------|--------|-------------|
| `npm run prompt:sync` | `scripts/sync-prompt-to-langfuse.ts` | Sync prompt a Langfuse (basado en hash, skip si no cambió) |
| `npm run prompt:regression` | `scripts/prompt-regression.ts` | Comparar dos versiones del prompt |
| `npm run rag:sync` | `scripts/export-chunks.ts` + `scripts/ingest-rag.ts` | Re-exportar artículos + ingestar en Supabase |

### Tests de Contrato e Integración
| Comando | Script | Descripción |
|---------|--------|-------------|
| `npm run test:contract` | `tests/ops-contract.test.ts` | Validar que metadata de trazas coincide con contrato del dashboard (67 tests) |
| `npm run test:ops` | `tests/ops-dashboard.test.ts` | Testear los 7 endpoints API del dashboard (102 tests) |

---

## Inicio Rápido

```bash
git clone https://github.com/santifer/cv-santiago.git
cd cv-santiago
npm install
npm run dev
```

Abrir [localhost:5173](http://localhost:5173)

### Variables de Entorno

```bash
# Core
ANTHROPIC_API_KEY= # Claude API (chatbot)
OPENAI_API_KEY= # Embeddings + Voz

# RAG
SUPABASE_URL= # URL del proyecto Supabase
SUPABASE_SERVICE_ROLE_KEY= # Clave de servicio Supabase

# Observabilidad
LANGFUSE_PUBLIC_KEY= # Tracing Langfuse
LANGFUSE_SECRET_KEY= # Tracing Langfuse

# Alertas y Dashboard
RESEND_API_KEY= # Alertas de jailbreak por email
OPS_DASHBOARD_SECRET= # Contraseña del dashboard (/ops)
```

---

## Estructura del Proyecto

```
src/
├── App.tsx # CV completo — todas las secciones
├── FloatingChat.tsx # Widget de chat (modo texto)
├── useVoiceMode.ts # Hook de modo voz (OpenAI Realtime)
├── VoiceOrb.tsx # UI de voz (orbe + transcript)
├── GlobalNav.tsx # Navegación con breadcrumbs
├── main.tsx # React Router + lazy loading
├── i18n.ts # Traducciones bilingües
├── articles/
│ ├── registry.ts # Config centralizada de artículos
│ ├── components.tsx # Componentes compartidos
│ └── json-ld.ts # Builder de JSON-LD
├── ops/ # Dashboard LLMOps
│ ├── OpsDashboard.tsx # Shell + pestaña Overview
│ ├── OpsAuth.tsx # Pantalla de login
│ ├── types.ts # Interfaces TypeScript compartidas
│ ├── hooks/ # useOpsApi, useTraces
│ ├── components/ # KpiCard, MetricChart, FilterBar, etc.
│ └── tabs/ # Conversations, Costs, Security, Evals, etc.
├── [Articulo].tsx # Componentes de case studies (5 artículos)
└── [articulo]-i18n.ts # Contenido bilingüe por artículo

api/
├── chat.js # Edge function principal del chatbot
├── voice-token.js # Token efímero de voz + rate limit
├── voice-trace.js # Tracing de sesiones de voz
├── rag-search.js # RAG para function calling de voz
├── _shared/
│ ├── rag.js # Pipeline RAG (búsqueda, rerank, coste)
│ ├── prompt.js # Versionado de prompt (Langfuse)
│ └── ops-auth.js # Helper de auth del dashboard
└── ops/ # Capa API proxy del dashboard
├── auth.js, stats.js, traces.js, trace/[id].js
├── evals.js, prompts.js, rag-stats.js

evals/
├── datasets/ # 10 datasets JSON (71 test cases)
├── assertions.ts # Assertions deterministas
├── llm-judge.ts # LLM-as-Judge (Haiku)
└── runner.ts # Runner de evaluaciones

scripts/ # Ver sección "Scripts y Herramientas CLI"
tests/
├── ops-contract.test.ts # Tests de contrato (67 assertions)
└── ops-dashboard.test.ts # Tests API del dashboard (102 assertions)

chatbot-prompt.txt # System prompt (fallback, producción usa Langfuse)
```

---

## Case Studies

| Artículo | Slugs | Tipo |
|----------|-------|------|
| Chatbot que se cura solo | `/chatbot-que-se-cura-solo` `/self-healing-chatbot` | case-study |
| Career-Ops | `/career-ops` `/career-ops-system` | case-study |
| Agente IA Jacobo | `/agente-ia-jacobo` `/ai-agent-jacobo` | case-study |
| Business OS | `/business-os-para-airtable` `/business-os-for-airtable` | case-study |
| SEO Programático | `/seo-programatico` `/programmatic-seo` | case-study |
| n8n para PMs | `/n8n-para-pms` `/n8n-for-pms` | collab |
| Santifer iRepair | `/santifer-irepair` `/santifer-irepair-founder` | bridge |

---

## Coste

- **<$0.005 por conversación de texto** (5 modelos en el pipeline)
- **~$0.25 por sesión de voz** (OpenAI Realtime)
- **$0 infraestructura** (free tiers: Vercel, Supabase, Langfuse)
- **~$30/mes** estimado a 200 conversaciones/día

---

## Licencia

MIT

---

## Let's Connect

[![Website](https://img.shields.io/badge/santifer.io-000?style=for-the-badge&logo=safari&logoColor=white)](https://santifer.io)
[![LinkedIn](https://img.shields.io/badge/LinkedIn-0A66C2?style=for-the-badge&logo=linkedin&logoColor=white)](https://linkedin.com/in/santifer)
[![Email](https://img.shields.io/badge/Email-EA4335?style=for-the-badge&logo=gmail&logoColor=white)](mailto:hola@santifer.io)