Proyectos
Cuatro apps en producción. Cada una se eligió para practicar un patrón distinto: cliente-servidor con WebSocket, compartición con control de privacidad, offline-first y OCR en el propio dispositivo.
// juego de palabras en español · estilo Pasapalabra
Juego de vocabulario en castellano: cada carta plantea una regla de letra
(empieza por, contiene o termina en) y el jugador
responde con palabras válidas. Validación tolerante (acentos, espacios, mayúsculas)
y modo multijugador en tiempo real. Ejercicio sobre arquitectura cliente-servidor con
comunicación bidireccional: API REST para datos y WebSocket para partidas.
Frontend
Vue 3
Ionic 8
Capacitor 8
TypeScript strict
Vite 5
vue-i18n
Vitest
Cypress
Backend
Go
PostgreSQL
Redis
REST + WebSocket
JWT passwordless
Infra
VPS
Nginx
systemd
App Store
APK directo
highlights
- Pipeline de normalización determinista: cada respuesta atraviesa la cadena
trim → collapse whitespace → lowercase → strip accents → strip puntuación. La Ñ se preserva como letra distinta del abecedario, no se normaliza a N. La integridad del mazo se valida en carga: regla, target_letter y valid_answers deben ser coherentes.
- Una jugada = trabajo coordinado en BBDD: cada respuesta dispara registro del intento, actualización agregada de estadísticas del jugador autenticado y, en multijugador , emisión del evento a la sala. Las stats se acumulan jugada a jugada: un cierre forzoso de la app no pierde progreso.
- Multijugador vía WebSocket: cada partida es una sala con canal bidireccional persistente. El servidor hace broadcasting de eventos (respuesta acertada, fallida u omitida, fin de turno) a todos los conectados. Redis sostiene presencia online y estado efímero de la sala; PostgreSQL guarda lo durable.
- Backend Go con binario único:
Gin + GORM + PostgreSQL + Redis + JWT HS256 passwordless. Compilación en local y scp al VPS, detrás de Nginx con systemd. Sin Docker en producción. La concurrencia de las salas se sostiene con goroutines.
- Generación de código mediante vibe coding *
// síntesis de voz · listas compartibles
App de repetición por voz: el usuario crea un "loro", una lista de textos que la app
reproduce con síntesis de voz. El modelo se articula en tres bloques
(Inicio + Loro + Cierre): un texto opcional precede a cada elemento y otro
lo cierra, generando combinaciones del tipo "Odio los Lunes por la mañana".
Ejercicio sobre compartición de recursos con control de privacidad, autenticación
passwordless por email y analítica de descargas.
Frontend
Vue 3
Capacitor 6
Vite 4
vue-i18n
axios
jose (JWT)
native-audio
Backend
FastAPI
Uvicorn
SQLAlchemy
PostgreSQL
PyJWT
Pydantic
SMTP / email
Infra
VPS
Nginx
App Store
APK directo
highlights
- TTS con abstracción dual por plataforma: web e iOS usan Web Speech API nativa (
SpeechSynthesisUtterance) con selección de voz del sistema; Android delega a un plugin Capacitor TTS nativo, porque dentro del WebView Android la API web falla. Arriba queda una sola interfaz, speak(text, options), con dos implementaciones detrás.
- Multi-idioma a tres niveles independientes: la UI se traduce con vue-i18n (es/en), cada loro guarda su propio
language en la tabla groups, y el TTS filtra las voces del dispositivo por ese código. Un loro francés se lee con voz francesa aunque la UI esté en castellano.
- Compartición granular con tabla
shared_with: cada loro tiene visibilidad public | private. Los privados se comparten escribiendo emails concretos en una tabla indexada; no hace falta que el destinatario tenga cuenta. El primer login con ese email recupera los loros recibidos. Borrado del padre arrastra texts, shared_with y downloads por cascade delete.
- Backend FastAPI tipado de extremo a extremo:
FastAPI + SQLAlchemy + Pydantic + PostgreSQL + PyJWT. Auth passwordless con código de 6 dígitos por SMTP propio; cada verification_request tiene expires_at y is_used para evitar reuso. La tabla downloads registra cada descarga; el contador agregado download_count vive en groups para queries sin joins.
- Generación de código mediante vibe coding *
// acrónimos y términos más utilizados en cloud · AWS + Azure + GCP · 100% offline
App en castellano para manejar el vocabulario de AWS, Azure y Google Cloud: el que aparece en su documentación y el que preguntan sus certificaciones, incluidas las de IA y machine learning. El glosario es la entidad de primer nivel: 671 términos curados a mano, y el quiz es su capa de evaluación: 1.045 preguntas tipo examen, cada una enlazada al término que la explica. Ejercicio sobre arquitectura offline-first, modelado multi-cloud con tabla de equivalencias entre servicios (S3 ↔ Blob Storage ↔ Cloud Storage), y distribución dual en App Store y APK directo.
Frontend
Vue 3
Ionic 8
Capacitor 8
TypeScript
Pinia
Vite 5
Sass
vue-i18n
Datos
SQLite (bundled)
@capacitor-community/sqlite
sql.js
jeep-sqlite
UUID PKs
Aplicación sin conexión
Sin backend
Sin red
Sin telemetría
Sin tracking
highlights
- Términos utilizados en certificaciones como: AWS CLF-C02 · SAA-C03 · AIF-C01 · MLA-C01 · Azure AZ-900 · GCP ACE.
- 5 subtipos de pregunta: definición, acrónimos, casos de uso, diferenciación entre servicios y «entre nubes» (¿qué es S3 en Azure?).
- SQLite empaquetado en el binario: la base viaja con la app y se copia al almacenamiento del dispositivo en el primer arranque vía
copyFromAssets; a partir de ahí la app no hace ninguna petición de red.
- Distribución dual: App Store para iOS, APK directo para Android. Sin tracking ni analítica de terceros.
- Generación de código mediante vibe coding *
// ayudante de cartones de bingo · 3×9, 4×8 y 3×5 · OCR en el dispositivo · 100% offline
App que ayuda a no perder un cantar: el usuario fotografía sus cartones, la app los lee con el OCR del propio dispositivo y deja el resultado listo para rematarlo de un toque. Durante la partida marca los números cantados y detecta línea y bingo en todos los cartones a la vez. Ejercicio de IA aplicada: OCR nativo (Vision en iOS, ML Kit en Android) a través de un plugin Capacitor propio, y colocación en la rejilla con k-means 1D para las filas y el rango del propio número para la columna. No hay backend ni cuentas de usuario: todo ocurre en el teléfono.
Frontend
Vue 3
Ionic 8
Capacitor 8
TypeScript
Pinia
Vite 5
vue-i18n
Vitest
Playwright
Datos
SQLite
@capacitor-community/sqlite
offline-first
arquitectura hexagonal
Visión y OCR
Vision (iOS)
ML Kit (Android)
plugin nativo propio
k-means 1D
highlights
- El OCR deja un borrador que el usuario corrige: el OCR nativo del sistema rellena entre un 73% y un 87% de las celdas y el resto se remata con un toque sobre la rejilla. La v1 descartó un pipeline completo con OpenCV tras diagnosticar, con una sonda instrumentada en un iPhone real, que su consumo de memoria (>1 GB) supera el límite del WebView de iOS.
- Colocar cada número sin fiarse de la geometría: la fila sale de un k-means 1D sobre la coordenada Y; la columna, del propio número, porque cada columna tiene su rango (1-9, 10-19…). La posición horizontal solo sirve de comprobación. En la variante 3×5 densa, que no tiene rangos por columna, la columna vuelve al k-means con k = 5. El número de serie del cartón se descarta como outlier.
- Dominio como lógica pura con arquitectura hexagonal: las reglas de cada variante (3×9 con bombo de 90, 4×8 con bombo de 80 y 3×5 densa: números por cartón, rangos por columna, detección de línea y bingo) no dependen de Vue, de SQLite ni del OCR. Más de 850 tests automáticos (Vitest + Playwright) y 12 ADRs documentando cada decisión.
- Distribución dual verificable: App Store para iOS y APK directo para Android, con las huellas SHA-256 del fichero (
CheckBingo_2.0.0.apk, 74.862.513 bytes) y del certificado de firma publicadas en la web.
- Generación de código mediante vibe coding *