Pairfect
Una app para dos: álbum de recuerdos compartido, un mapa de los lugares donde habéis estado, planes y pequeños rituales diarios. Hecha en solitario, junto a un máster a tiempo completo y un trabajo.







De un vistazo
- Rol
- en solitario, arquitectura a release
- Periodo
- 10/2025 a 07/2026, nueve meses
- Líneas de Dart
- unas 78.200 en 266 archivos
- Módulos
- 11
- Cloud Functions
- 24 archivos, unas 3.450 líneas
- Commits
- 493
Mi rol
Todo, en solitario
El problema
Las parejas ya reparten lo que comparten en cinco sitios: las fotos en una app, los planes en otra, las fechas que importan en una tercera y la conversación en otro lugar distinto. Nada de eso está hecho para exactamente dos personas, así que nada se comporta como si esas dos fueran una sola cuenta.
Cómo funciona
- Clean architecture por funcionalidad, cada módulo separado en data, domain y presentation. Las dependencias apuntan hacia dentro, de modo que las reglas de negocio de una funcionalidad no saben que Firestore existe.
- Un backend serverless en Firebase con Auth, Firestore, Storage, Messaging, App Check y Cloud Functions en TypeScript.
- Trabajo de plataforma que va más allá de las pantallas: widgets de inicio en iOS con WidgetKit, descarga de mapas sin conexión y un reproductor de trayectos sobre Mapbox, y suscripciones con RevenueCat donde el derecho es compartido por la pareja.
- Exportación de datos conforme al RGPD y borrado atómico de la cuenta como Cloud Functions, bloqueo biométrico de la app, tokens de emparejamiento de un solo uso validados en servidor, rate limiting y cuotas de almacenamiento.
Stack
Flutter, Dart, Firebase, TypeScript Cloud Functions, RevenueCat, Mapbox, WidgetKit, GitHub Actions.
Lo que me llevo
Dos decisiones que defendería. A las fotos se les quitan los metadatos antes de subirlas, siempre, porque el GPS del EXIF es una dirección de casa y la cabecera del archivo sobrevive a la app. Ese componente es ahora código abierto, como exif_scrubber. Y el bloqueo de la app es una barrera de interfaz, y la documentación lo dice en voz alta: cambia el árbol de widgets y exige biometría para volver, pero no cifra nada y no protege frente a un dispositivo rooteado ni frente a un acceso forense. Escribir esa limitación en el comentario del código me importó más que hacer que la función sonara más fuerte de lo que es.
Resultado
Construida en solitario en nueve meses, desde la arquitectura hasta la interfaz, el backend y una pipeline de publicación automatizada, junto a un máster a tiempo completo y un trabajo.