OposApp
Mi Trabajo de Fin de Grado (DAM): app móvil en Flutter que automatiza el seguimiento de convocatorias del BOPA y genera tests de práctica con IA local (Ollama), con privacidad total por diseño.

OposApp es mi Trabajo de Fin de Grado (Desarrollo de Aplicaciones Multiplataforma, curso 2025-2026): una aplicación full-stack que resuelve dos problemas reales del opositor medio en Asturias — los 15-30 minutos diarios perdidos buscando convocatorias a mano y los 50-150 €/mes que cuesta preparar los exámenes en academias tradicionales.
Qué hace
- Seguimiento automático del BOPA — un workflow de n8n rastrea el boletín oficial cada día a las 07:00 y guarda las convocatorias nuevas en PostgreSQL, con filtros por categoría, organismo, fecha y estado, y búsqueda full-text tolerante a erratas.
- Tests con IA local — un modelo en local (Ollama, familia Qwen:
qwen2.5-coderen el plan gratuito y un modelo mayorqwen3en premium) genera tests personalizados en ~11 s mediante un flujo asíncrono (el backend devuelve unsolicitudIdy la app hace polling), sin enviar ningún dato a servicios externos. - Dashboard de progreso — KPIs en tiempo real (tests, aciertos, racha), gráfico de evolución e historial completo.
Arquitectura y stack
La app Flutter (Android 14+, Material Design 3, provider, go_router, Dio + Retrofit) se comunica por REST/JWT con una API Spring Boot 3 · Java 21 en arquitectura por capas estricta. Los datos viven en PostgreSQL 15, con Spring Security (JWT HS512 + BCrypt coste 12), rate limiting con Bucket4j (30 req/min por IP) y documentación OpenAPI/Swagger.
Todo corre autohospedado en un NAS Synology detrás de Caddy (HTTPS automático), con n8n para el scraping y Ollama para la IA. Cero dependencias de nube de pago.
Un único APK para dos entornos: al arrancar, la app comprueba si el NAS es alcanzable en la red local; si lo es usa la IP directa (más rápido) y, si no, cae automáticamente al dominio HTTPS externo. El mismo binario funciona dentro y fuera de casa sin recompilar.
Funcionamiento clave
- Modo offline con caché local Hive y detección de red (
connectivity_plus): las últimas convocatorias siguen accesibles sin conexión. - Generación asíncrona de tests: el backend devuelve un
solicitudIdal instante y la app hace polling del estado; corrección inmediata con explicación por pregunta y animación de resultado. - Dashboard de progreso con gráficos
fl_chart(evolución, aciertos, racha) e historial. - Panel de administración (rol
ROLE_ADMIN): usuarios, estado de servicios (PostgreSQL, Ollama), registro de auditoría y métricas de scraping.
Privacidad por diseño (RGPD)
- IA 100% local: sin servicios de terceros, sin salida de datos de la infraestructura propia.
- Consentimiento opt-in explícito con registro de timestamp, borrado total de cuenta (Art. 17) y exportación del perfil en JSON (Art. 20).
Seguridad
- JWT HS512 stateless (7 días), validado en cada petición.
- BCrypt (coste 12) — contraseñas nunca en texto plano.
- Bucket4j contra abuso, Bean Validation en todos los DTOs y JPA/Hibernate (imposible inyección SQL).
- Panel de administración restringido a red local del NAS (LAN / WireGuard) + rol
ROLE_ADMIN.
Rendimiento medido
- Listado de 200 convocatorias: 187 ms (objetivo < 500 ms).
- Generación de test con IA (10 preguntas): 11,3 s (objetivo < 15 s).
- Login con verificación BCrypt: 312 ms.
Contexto académico
TFG del ciclo DAM (2025-2026). Tutores: Delio Tolivia Cadrecha (PIDAM) y Mario Álvarez Fernández (PDAW). Publicado como código abierto bajo licencia MIT.