Proyectos

Proyecto 01 · App + IA + Infraestructura

CertEngine

Practicar para certificaciones técnicas es ineficiente. Los simulacros existentes tienen preguntas fijas, no se adaptan a tu nivel, y dependen de servicios externos. CertEngine genera exámenes de práctica con IA — corriendo completamente en mi propio servidor con GPU.

En producción FastAPI + React RAG + pgvector Ollama local SM-2 · Google OAuth

// origen

Empezó como un problema propio

Preparando mis certificaciones de n8n y Power Platform, probé varios simulacros disponibles. Todos tenían el mismo problema: un banco fijo de preguntas que no cambia, sin diagnóstico de en qué dominio estás más débil, y sin explicaciones que realmente enseñen por qué una respuesta es incorrecta.

La solución obvia era construir algo que generara preguntas nuevas en base a mi desempeño. Y mientras lo hacía, me interesó más el problema técnico de fondo: cómo conectar un LLM a un corpus de documentación real de certificaciones para que las preguntas generadas sean relevantes, no alucinadas.

CertEngine empezó para resolver mi propio problema. Terminó siendo el ejercicio más completo de desarrollo full-stack con IA que he hecho — y corre en producción en el mismo homelab donde experimento con el resto de las herramientas.

// arquitectura

Cómo está construido

Browser / PWA
  └── CloudFlared Tunnel
        └── Traefik
              └── certengine-web (Nginx + React SPA)
                    └── /api/* → certengine-api (FastAPI + Uvicorn :8000)
                                        ├── stack_postgres (PostgreSQL 16 + pgvector)
                                        │     └── schema: certengine
                                        ├── stack_redis (cache + job queue)
                                        │     └── certengine-worker (RQ Worker)
                                        └── stack_ollama (Qwen 2.5 7B · RTX 3070)
                                              └── RAG pipeline + explicaciones SSE

Nginx hace proxy de /api/* al backend.
Todo corre en stack_net — la misma red Docker del homelab.

CertEngine no tiene su propio servidor — usa la infraestructura compartida del homelab. stack_postgres, stack_redis y stack_ollama son los mismos containers que usan Gitea, Outline y GlitchTip. Eso reduce la huella de RAM y simplifica el backup: pg_dump incluye todos los schemas en un solo comando.

// stack

El stack completo

Capa Tecnología
Backend FastAPI 0.115 + Python 3.12 (async nativo)
ORM SQLAlchemy 2.0 async + Alembic 1.13
Validación Pydantic v2
Auth python-jose + passlib + Google OAuth (authlib)
Queue Redis + RQ workers (generate_questions_task)
Frontend React 18 + Vite 5 + TypeScript 5
Estilos TailwindCSS + shadcn/ui
Data fetch TanStack Query v5
Router React Router v6
PWA vite-plugin-pwa 0.20
Base de datos PostgreSQL 16 (stack_postgres compartido)
Vector search pgvector 0.7 (embeddings opcionales)
LLM Ollama · Qwen 2.5 7B Q4_K_M · RTX 3070

// decisiones

8 decisiones con trade-off documentado

Decisión Elegí Por qué Trade-off
FastAPI sobre Django FastAPI Async nativo para llamadas a Ollama (3–10s de latencia). OpenAPI auto-generado sirve como spec para el desarrollo. Más explícito que Django para APIs puras. Menos "baterías incluidas". Más responsabilidad en el desarrollador para configurar auth, ORM y middleware.
React + Vite sobre Next.js React + Vite CertEngine no necesita SEO — es una SPA de uso privado. Next.js agrega SSR, App Router y RSC que son complejidad innecesaria para este caso. Si en el futuro se quiere una landing pública con SEO, habría que migrar o agregar una página estática separada.
RQ sobre Celery RQ Los jobs son pocos y predecibles: generar preguntas, scraping de certificaciones. Celery agrega beat scheduler y múltiples queues innecesarios para este volumen. RQ es menos escalable. Si el volumen crece a 50+ jobs concurrentes, habría que migrar a Celery.
SM-2 sobre FSRS SM-2 Bien documentado, funciona para 100–500 tarjetas. FSRS es más preciso pero requiere datos de entrenamiento del usuario para calibrarse — no disponibles en el MVP. SM-2 es menos preciso en memoria a largo plazo. Migrar a FSRS posible en v2 sin cambiar el schema.
BeautifulSoup sobre Playwright BeautifulSoup Las páginas de Microsoft Learn y Google Cloud renderizan en server-side. Sin browser headless. ~0.5s por página vs. ~3–5s de Playwright solo para inicializar. Si algún proveedor migra a SPA sin SSR, habría que agregar PlaywrightScraper como alternativa.
JWT en httpOnly cookies httpOnly cookies Mitiga XSS — JavaScript del frontend no puede leer el token. Más seguro que localStorage donde cualquier script inyectado puede acceder. Mayor complejidad con CORS y SameSite policy. Requiere configurar el proxy nginx para pasar cookies.
pgvector como opcional pgvector (NULL = sin embedding) Permite búsqueda semántica cuando el embedding está presente. Si es NULL, la funcionalidad principal no se ve afectada — es una mejora, no un prerequisito. Generar embeddings requiere correr un modelo adicional (nomic-embed-text). Deuda técnica intencional.
Ollama local sobre API externa Ollama + RTX 3070 Privacidad total — los datos no salen del servidor. 83 tok/s vs. ~8 tok/s en CPU. Sin dependencia de APIs externas de pago. El modelo local (Qwen 2.5 7B) es menos capaz que GPT-4 o Claude. Requiere hardware específico para inferencia aceptable.

// aprendizajes

Lo que no sabía antes de construir esto

01

El cuello de botella de RAG no es el modelo

Es la calidad del contexto que le pasas. Preguntas generadas con scraping limpio son radicalmente mejores que las generadas con texto sin procesar. La diferencia no está en el prompt — está en el input.

02

Async en FastAPI no es magia, es disciplina

Una sola función síncrona bloqueante en el path crítico puede cancelar todos los beneficios de async. Aprender a detectarlas fue la curva más empinada del proyecto.

03

pgvector como opcional desde el día 0 fue correcto

Haber diseñado la feature como degradable evitó bloquear el desarrollo del core mientras el pipeline de embeddings no estaba listo. Es un patrón que voy a replicar: diseñar features como mejoras opcionales, no como dependencias.

CertEngine corre en la misma infraestructura del homelab.