Épale
Ícono de la aplicación para Android e iOS (fuente de flutter_launcher_icons)

épale

Fintech · 2025 — 2026

Chatea. Paga. Sin salir de la conversación.

Mensajería cifrada y pagos en el mismo chat. La misma burbuja donde escribes es la que envía dinero, solicita un cobro o muestra el recibo de la transacción.

App móvil de mensajería y pagos2025 — 2026En desarrollo activo (versión 0.10.7+109, rama de trabajo AS-fix/-improvements)

Desarrollo móvil Flutter: arquitectura por features, módulo de pagos/KYC y sincronización offline

Producto privado en desarrollo: el código y la ficha de tienda todavía no son públicos.

M

Mariana Ruiz

Escribiendo...

¿Me pasas lo del almuerzo?

Dale, ¿te lo mando por aquí?

¿No tienes que abrir el banco?

No. Se paga en el mismo chat.

Pago

Bs. 1.250,00

SubtotalBs. 1.225,00
Comisión Bancaria (2%)Bs. 25,00
≈ 6,94 $Almuerzo del viernes
Ver detalle
9:41
Escribe un mensaje...
01 / El ida y vuelta

Salir del chat cuesta dinero

?

el problema

En Venezuela, pagar a otra persona significa salir del chat, abrir el banco, copiar datos, hacer la transferencia y volver a la conversación a mandar una captura como comprobante. Ese ida y vuelta rompe la conversación, genera errores de tipeo en cédulas y cuentas, y deja el 'recibo' como una imagen que nadie puede verificar. A eso se suma que un mensajero con dinero adentro necesita algo que las apps de chat comunes no piden: identidad verificada, PIN, biometría, cifrado del historial y funcionamiento con conectividad intermitente.

9:38

la solución

Épale convierte el pago en un tipo de mensaje más. Desde el menú '+' del chat se elige 'Pago' o 'Solicitar pago', se abre una hoja con monto en doble moneda (Bs y USD a tasa BCV), subtotal, comisión bancaria y total, se confirma con PIN, biometría u OTP, y el resultado queda como una burbuja de pago dentro de la conversación, con su estado (pendiente, en proceso, exitoso, rechazado, fallido) y su detalle consultable. Alrededor de eso se construyó lo que hace viable ese flujo: KYC obligatorio antes del primer pago, QR de cobro cifrados con AES-256-GCM y prefijo propio EPQ1, pagos agendados con recordatorio, historial de transacciones y ajustes de seguridad, todo sobre una base de datos local cifrada y un motor de mensajes que tolera la pérdida de conexión.

9:41

Épale
02 / Lo que la sostiene

Ocho piezas que hacen viable un chat con dinero dentro

El pago vive dentro del chat

Los tipos de mensaje receipt_payment y receive_payment son ciudadanos de primera clase del pipeline: se emiten por Socket.IO, se guardan en la tabla payments de la base local y se pintan como una burbuja con monto, concepto, comisión y equivalente en dólares.

Billetera con KYC, PIN y biometría

La sección Pagos exige identidad verificada: escaneo del documento con reconocimiento de texto ML Kit, prueba de vida facial con retos (sonreír, parpadear, girar la cabeza, acercarse) y confirmación de cada operación con PIN o local_auth.

QR de cobro cifrado extremo a extremo

Cada QR de cobro se serializa y cifra con AES-256-GCM (IV aleatorio de 12 bytes, prefijo EPQ1) antes de convertirse en imagen, así un lector genérico no puede interpretar ni alterar el payload de pago.

Historial local cifrado con SQLCipher

Nueve tablas (chats, mensajes, contactos, reacciones, pagos, mensajes de IA, perfil, metadata, contactos no registrados) viven en una SQLite cifrada cuya clave de 32 bytes se genera por dispositivo con Random.secure() y se guarda en el almacenamiento seguro del sistema.

Diseñado para conexión intermitente

El socket mantiene una cola de emisiones pendientes que se drena al reconectar, workmanager sincroniza mensajes en segundo plano y la base local es la fuente de verdad de la UI, de modo que la app se usa igual sin señal.

Mensajes de una sola vista

El modo 'Una vista' abre imágenes, videos y audios en un visor que bloquea capturas de pantalla con screen_protector y se apoya en el sensor de proximidad, marcando el mensaje como visto al cerrarlo.

Asistente Épale integrado

Un módulo de chat con IA, con su propia instancia de Dio y su tabla de mensajes, resuelve dudas sobre el uso de la app y consultas generales desde una pestaña de conversaciones aparte.

Tres idiomas y seis temas

1.562 claves traducidas a español, inglés y portugués, más cuatro paletas (turquesa, verde, azul, morado) en variante clara y oscura que el usuario elige desde ajustes de tema.

03 / De la burbuja al dinero

La burbuja se despega y abre la billetera

Dentro del mismo módulo viven el QR cifrado, las cuentas vinculadas y el comprobante del pago.

EPQ1·AES-256-GCM

favorita

**** 4417

Cuenta vinculada

Bs. · Banesco

comprobante

Bs. 1.250,00

Mariana Ruiz

Ref. EP-2409183

07/09/2026 · 9:41

QR cifrado

Payload AES-256-GCM con IV de 12 bytes y prefijo EPQ1 en base64url.

Cuentas vinculadas

Cuenta favorita preseleccionada y comisión bancaria desglosada.

Comprobante

Ticket con recorte perforado: referencia, fecha y destinatario.

El repositorio, en cifras

710

archivos Dart

~142k

líneas de código

7

módulos de features

58

rutas en go_router

45

pantallas

143

providers de Riverpod

9

tablas SQLCipher (esquema v30)

15

tipos de evento Socket.IO

12

tipos de mensaje soportados

3

idiomas (es, en, pt)

1.562

claves de traducción

18

pruebas E2E con Patrol

04 / El candado

El historial vive cifrado en el propio teléfono

La base local es la fuente de verdad de la interfaz, así que también es el sitio donde hay que poner el candado.

SQLCipher, clave por dispositivo

9 tablas y esquema en la versión 30. La clave de 32 bytes se genera una sola vez con Random.secure() y se guarda en flutter_secure_storage: nunca está en el código ni en el servidor.

AES-256-GCM en los QR de cobro

IV aleatorio de 12 bytes, base64url y prefijo EPQ1. Un lector genérico sólo ve una cadena opaca que no puede interpretar ni alterar.

PIN, biometría y OTP

Cada operación de dinero se confirma con PIN de 4 dígitos, local_auth o un código de un solo uso autocompletado con smart_auth.

Mensajes de una sola vista

El visor seguro bloquea capturas con screen_protector, se apoya en el sensor de proximidad y marca el contenido como visto al cerrarse.

sqflite_sqlcipher · flutter_secure_storage · encrypt · local_auth · screen_protector

05 / Arquitectura

Siete módulos, tres capas cada uno

Pasa el cursor por un módulo para seguir su columna: cada feature atraviesa dominio, infraestructura y presentación sin saltarse ninguna.

domainentidades · contratos · casos de usoinfrastructuredatasources · mappers · Dio · Socket.IO · SQLCipherpresentationpantallas · widgets · 143 providers Riverpodauthchatpaymentsai_chatcamerahomesharedsocket.io · 15 eventos · cola de emisiones pendientes

Clean Architecture por features. Cada módulo (auth, chat, payments, ai_chat, camera, home, shared) se divide en domain (entidades, contratos de repositorio y casos de uso, sin imports de framework), infrastructure (implementaciones, datasources remotos y locales, mappers y errores propios) y presentation (pantallas, widgets y providers de Riverpod). La navegación es un go_router único con 58 rutas y redirecciones que fuerzan la secuencia registro → OTP → perfil → home. La capa de red usa tres instancias de Dio (API, almacenamiento con timeouts largos y servicio de IA) con refresco automático de token ante un 401 y verificación de conectividad previa. El tiempo real corre sobre Socket.IO autenticado con Bearer, con 15 tipos de evento y una cola de emisiones pendientes que se drena al reconectar. La persistencia es SQLite cifrada con SQLCipher (9 tablas, versión de esquema 30) con streams por chatId para actualizar la UI, y las credenciales y claves viven en flutter_secure_storage. Las dependencias se registran con get_it + injectable generados por build_runner, y la configuración de entorno (API, socket, almacenamiento, servicio de IA y KYC) llega por flutter_dotenv.

06 / Las pantallas

Seis pantallas, una sola conversación

Recreadas en HTML y CSS con los colores, los textos y la disposición reales de la app. Arrastra para recorrerlas.

Mensajes

Buscar...
TodosBorradoresNo leídos (3)Grupos (2)
M

Mariana Ruiz

Escribiendo...

9:412
G

Grupo Familia

🖼 Foto

9:12
C

Carlos Medina

🧾 Pago #1042

8:571
A

Andreína P.

Borrador: nos vemos a las 6

Ayer
L

Luis Ferrer

🎙 Nota de voz

Ayer
A

Asistente Épale

¿En qué te ayudo hoy?

Lun
Y

Yudith Rojas

📍 Ubicación

Lun
ChatsPagosPerfil

Mensajes (lista de chats)

Filtros, borradores, fijados y no leídos

M

Mariana Ruiz

Escribiendo...

¿Me pasas lo del almuerzo?

9:38

Va por aquí mismo, no hago transferencia 😌

9:39

Pago

Bs. 1.250,00

SubtotalBs. 1.225,00
Comisión Bancaria (2%)Bs. 25,00
≈ 6,94 $Almuerzo del viernes
Ver detalle
9:41
Solicitud de pago

Bs. 380,00

Cuota del condominio

Pagar
CámaraGaleríaDocumentoContactoPagoSolicitar
Escribe un mensaje...

Conversación con burbuja de pago

El pago como un mensaje más

Pagos

2

QR de Mesa 4

2 códigos QR

Bs.1.250,00

QR Finaliza en 1h 20min

Tasas del día 07/09/2026 valor BCV

USD 36,45

EUR 39,80

Generar QR de cobro

Crea un código QR para recibir un pago.

Pago o cobro por QR

Escanea un QR para pagar o cobrar.

Pagos agendados

Programa pagos a tus contactos de épale.

2

Pago a usuario

Realiza pagos a tus contactos de épale.

Pago de servicios

Realiza pagos de tus servicios.

Cuentas vinculadas

Administre sus cuentas bancarias.

Historial

Transacciones enviadas y recibidas.

Ajustes

Gestione su PIN y autenticación biométrica.

ChatsPagosPerfil

Pagos (centro de la billetera)

QR activos, tasa BCV y accesos

Pago

Monto

Bs.1.250,00
$34,29
SubtotalBs. 1.225,00
Comisión Bancaria (2%)Bs. 25,00
Total:Bs. 1.250,00
Concepto (Opcional)
Banesco · Cuenta favorita
Confirmar pago

Introduce tu PIN

o usa tu huella

Hoja de pago y confirmación

Doble moneda, comisión y PIN

Pago exitoso

Bs. 1.250,00

ReferenciaEP-2409183
Fecha07/09/2026 · 9:41
DestinatarioMariana Ruiz
CuentaBanesco ****4417
ComisiónBs. 25,00
TotalBs. 1.250,00
Compartir comprobante
Animación de carga mientras se envía o sincroniza un mensaje

Comprobante del pago

Ticket con recorte perforado

Verificación de identidad

Paso 3 de 5 · Prueba de vida

Sonríe

Mantén el rostro dentro del óvalo

Parpadea
Gira la cabeza a la izquierda
Sonríe
Acércate un poco
Si falla, se reintenta desde el escaneo de la cédula

Verificación de identidad (KYC + prueba de vida)

Retos de prueba de vida

← arrastra →

Las maquetas reproducen la interfaz real; los datos que muestran son de ejemplo.

07 / Funcionalidades

Todo lo que ya contesta la app

Dieciocho capacidades que hoy están dentro del binario, contadas como lo que son: mensajes de ida y vuelta.

Chats 1:1 y grupales con respuestas, reacciones, menciones, reenvío, mensajes destacados y fijado de hasta 3 chats
Mensajes de texto, imagen, video, audio, archivo, ubicación, contacto, sistema y de 'una sola vista'
Notas de voz con forma de onda, reproductor global flotante y reproducción al oído por sensor de proximidad
Cámara integrada, escáner de documentos, edición de imágenes con dibujo y texto superpuesto, y compresión antes de subir
Registro por teléfono con SMS: envío de código, autocompletado del OTP y creación de perfil
Sincronización de contactos del teléfono, invitaciones por SMS, contactos privados por PIN Épale y por QR
Envío de pagos y solicitudes de cobro desde el propio chat, con concepto y comisión desglosada
Verificación KYC en 5 pasos con escaneo de cédula y prueba de vida facial
Generación de QR de cobro con vencimiento, detalle, edición y compartido por chat
Pago o cobro escaneando el QR de otro usuario
Pagos agendados a contactos, con recordatorio push y ejecución confirmada
Pago de servicios y recargas (Movistar, Digitel, Movilnet, Cantv, SimpleTV) con límites por operador
Cuentas bancarias vinculadas, cuenta favorita, historial de transacciones y ajustes de PIN/biometría
Tasas del día BCV en bolívares y euros, con campos de monto en doble moneda
Chat con el Asistente Épale y lista de conversaciones de IA
Búsqueda global de chats, mensajes y contactos, con filtros Todos / Borradores / No leídos / Grupos
Fondos de chat personalizables, temas de color, dispositivos vinculados, usuarios bloqueados y ajustes de datos y almacenamiento
Notificaciones push con canales separados para mensajes y pagos, badge en el ícono y aviso de actualización de la app
08 / Lo que costó

Siete problemas y su recibo

reto 01

Los mensajes enviados mientras el teléfono estaba sin señal se perdían o llegaban desordenados al volver la conexión.

cómo se resolvió

La base local cifrada pasó a ser la fuente de verdad: el mensaje se persiste como 'enviando' y se pinta de inmediato, mientras el socket acumula las emisiones en una cola pendiente que se drena al reconectar y workmanager corre una sincronización en segundo plano que reconcilia el historial contra el último id conocido.

reto 02

En la sincronización de mensajes creados por el servidor mientras el usuario estaba offline, el backend omitía el receiverId en los chats 1:1, así que el remitente no podía resolver con quién era la conversación y el mensaje se descartaba sólo de su lado.

cómo se resolvió

El parseo de la respuesta de sincronización ahora deriva el receiverId a partir de los miembros del chat (el miembro distinto al emisor) en chats privados de dos personas, evitando la llamada de creación de chat con id vacío que devolvía 400.

reto 03

Un QR de cobro es un objeto público: cualquiera puede fotografiarlo y un lector genérico podría leer o alterar monto y destinatario.

cómo se resolvió

El payload se cifra con AES-256-GCM usando un IV aleatorio de 12 bytes y se codifica en base64url con el prefijo propio EPQ1, de modo que sólo la app reconoce y descifra el código; un escáner cualquiera sólo ve una cadena opaca.

reto 04

El historial de chat y de pagos queda en el teléfono, un dispositivo que puede perderse o clonarse.

cómo se resolvió

Toda la base SQLite se cifra con SQLCipher y la clave de 32 bytes se genera una sola vez por dispositivo con Random.secure() y se guarda en el almacenamiento seguro del sistema, nunca en el código ni en el servidor.

reto 05

Las solicitudes de pago programadas debían dispararse a una hora exacta aunque la app estuviera cerrada y sin conexión, algo que el cliente no puede garantizar.

cómo se resolvió

Se implementó un motor local de mejor esfuerzo (sondeo cada 30 segundos mientras la app vive, más disparo al volver al primer plano) apoyado en la cola de mensajes pendientes para la durabilidad, y se documentó explícitamente que la ejecución garantizada corresponde al backend, que envía un recordatorio push al vencimiento.

reto 06

Los mensajes de 'una sola vista' pierden todo el sentido si el receptor puede hacer una captura de pantalla.

cómo se resolvió

El visor seguro bloquea capturas con screen_protector mientras está abierto, se apoya en el sensor de proximidad para la reproducción al oído y marca el contenido como visto al cerrarse, dejando la burbuja en estado 'Visto'.

reto 07

Probar de verdad un flujo que mezcla SMS, permisos nativos de contactos y envío de mensajes reales es imposible con tests de widget.

cómo se resolvió

Se montó una suite E2E con Patrol (18 archivos, page objects por pantalla) que corre en un teléfono físico, atraviesa los diálogos nativos del sistema, usa un datasource de autenticación falso para saltarse el SMS real y muestra un HUD en pantalla con el estado de cada paso.

09 / Stack

Con qué está construida

Núcleo

Flutter (SDK >=3.8.0)DartMaterial 3flex_color_schemeflutter_svgintl

Arquitectura y estado

flutter_riverpodgo_routerget_itinjectableequatablefpdartformzlogger

Datos y tiempo real

diosocket_io_clientsqflite_sqlcipherflutter_secure_storageconnectivity_plusworkmanagerflutter_cache_manager

Pagos, identidad y seguridad

encrypt (AES-256-GCM)cryptolocal_authsmart_authmobile_scannerqr_code_scanner_plusqr_fluttergoogle_mlkit_face_detectiongoogle_mlkit_text_recognitioncunning_document_scannerscreen_protectorproximity_sensor

Multimedia

camerajust_audiorecordaudio_waveforms (fork local en packages/)waveform_fluttervideo_playerwechat_assets_pickerimage_cropperflutter_image_compressblurhash_dartpdfxemoji_picker_fluttergal

Firebase y notificaciones

firebase_corefirebase_messagingfirebase_analyticsflutter_local_notificationsapp_badge_plus

Contactos y telefonía

flutter_contactsphone_numbers_parserflutter_libphonenumbercountry_code_pickersim_readerreceive_sharing_intentshare_plus

Calidad y entrega

patrol (E2E)mocktailflutter_lintsbuild_runnerinjectable_generatorflutter_launcher_iconsflutter_native_splashJenkins

Épale es una app móvil Flutter que une, en una sola conversación, mensajería estilo WhatsApp y pagos reales en bolívares: la misma burbuja donde escribes es la que envía dinero, solicita un cobro o muestra el recibo de la transacción.

El proyecto está construido con Clean Architecture estricta (domain → infrastructure → presentation) sobre 7 módulos de features, 710 archivos Dart y unas 142.000 líneas, con Riverpod para estado, go_router para 58 rutas con redirecciones según sesión, y get_it + injectable para inyección de dependencias generada por código.

La base local es una SQLite cifrada con SQLCipher (9 tablas, migración 30) cuya clave se genera por dispositivo con Random.secure() y vive en el llavero seguro: la app funciona sin conexión y el socket, la cola de emisiones pendientes y el sincronizador en segundo plano reconcilian todo al reconectar.

El módulo de pagos suma verificación de identidad (KYC con escaneo de documento y prueba de vida facial), PIN y biometría, QR de cobro cifrado con AES-256-GCM, pagos agendados, pago a usuario, recargas de servicios y conversión Bs/USD con tasa BCV del día.

Todo el producto está localizado en español, inglés y portugués (1.562 claves de traducción) y cuenta con 18 pruebas E2E Patrol que automatizan el recorrido real en un teléfono físico, incluidos los diálogos nativos de permisos.

Ícono de la moneda Épale, usado en el módulo de pagos

Piezas de marca

Turquesa confiable: el verde azulado de una app financiera seria, suavizado por aguamarinas luminosos (#A9FFF0, #47EBAF) y grises muy claros. Superficies blancas, esquinas redondeadas de 12 px, tipografía sans de sistema y el wordmark 'épale' en minúsculas y trazo redondo sobre el degradado teal.

Wordmark 'épale' en minúsculas, versión clara usada en la pantalla de splash sobre el degradado turquesa
Wordmark 'épale' en minúsculas, versión clara usada en la pantalla de splash sobre el degradado turquesa
Logotipo de Épale en formato webp, el que usan las pantallas internas
Logotipo de Épale en formato webp, el que usan las pantallas internas
Ícono de la aplicación para Android e iOS (fuente de flutter_launcher_icons)
Ícono de la aplicación para Android e iOS (fuente de flutter_launcher_icons)
Variante monocroma blanca del ícono para el splash de Android 12+
Variante monocroma blanca del ícono para el splash de Android 12+
Fondo degradado turquesa del splash, base cromática de toda la marca
Fondo degradado turquesa del splash, base cromática de toda la marca
Degradado oscuro usado como fondo de las pantallas de autenticación
Degradado oscuro usado como fondo de las pantallas de autenticación
Degradado claro para las pantallas de autenticación en tema claro
Degradado claro para las pantallas de autenticación en tema claro
Uno de los doce fondos de conversación que el usuario puede elegir para sus chats
Uno de los doce fondos de conversación que el usuario puede elegir para sus chats
Ícono de la moneda Épale, usado en el módulo de pagos
Ícono de la moneda Épale, usado en el módulo de pagos
Fondo vectorial de la sección del Asistente Épale (chat con IA)
Fondo vectorial de la sección del Asistente Épale (chat con IA)
Ilustración de dispositivos vinculados
Ilustración de dispositivos vinculados
Animación de carga mientras se envía o sincroniza un mensaje
Animación de carga mientras se envía o sincroniza un mensaje
FlutterRiverpodSocket.IOSQLCipherAES-256-GCMKYC + prueba de vidaTasa BCVes · en · ptPatrol E2EFlutterRiverpodSocket.IOSQLCipherAES-256-GCMKYC + prueba de vidaTasa BCVes · en · ptPatrol E2E
é

Mensajería cifrada y pagos en el mismo chat

entregado

Una conversación que, al bajar, se convierte en dinero.

Épale

¿Quieres algo así para tu producto?

Mensajería en tiempo real, base local cifrada, KYC con prueba de vida y pagos dentro del chat: si tu producto necesita mover dinero donde la gente ya está hablando, ése es el terreno que conozco.

Hecho para Venezuela · En desarrollo