BookinglyTech News
Software

PennyRush parsea extractos bancarios en memoria y no guarda el fichero

El proyecto abre su contrato de privacidad en el repositorio: cero almacenamiento de objetos en la v1, solo persisten los campos de cada transacción.

3 min de lecturaDev.to0 vistas

PennyRush es un gestor de finanzas personales con una decisión de diseno poco habitual: no conserva el extracto bancario. La app es Android nativo en Kotlin y Jetpack Compose, con una web en Next.js, y las dos hablan con un unico backend Supabase. El contrato de privacidad esta escrito en el repositorio y es estrecho a proposito: en la v1 no hay almacenamiento de objetos. El fichero se lee en memoria, se convierte en transacciones candidatas y el cliente lo descarta; no pasa por disco, ni por un bucket, ni por analitica, ni por logs. Lo unico que sobrevive son los campos de la actividad guardada: importe, fecha, comercio, nota, tipo y categoria.

Si no puedes quedarte el fichero, tienes que ser bueno sacandole la estructura en el momento. La importacion de CSV ocurre entera en el dispositivo y es rules-based. El parser rechaza ficheros vacios y hace una comprobacion binaria: si mas del 5% de los primeros 4KB no es imprimible, asume que le han pasado un PDF o una imagen y pide una hoja de calculo. Hay topes de 5MB y 20.000 lineas para que un fichero enorme o mal formado no cuelgue la importacion. Despues busca la fila de cabecera en vez de asumir la primera: puntua cada linea segun si tiene una columna con pinta de fecha, otra de dinero (amount, debit, credit, withdrawal, deposit) y otra de descripcion (narration, particulars, payee, memo). Cada banco las nombra a su manera, asi que el emparejamiento es difuso a proposito.

Con la cabecera fija, mapea los indices, resuelve el caso de debito y credito en columnas separadas -el debito va a negativo, el credito se queda positivo- y parsea fila a fila. Los importes tragan con simbolos de moneda, separadores de miles, prefijos como Rs., INR o USD y parentesis contables para los negativos. Las fechas se prueban contra una lista de formatos habituales antes de caer al ISO. Las filas con fechas fuera de rango, mas de 50 anos atras o 10 hacia adelante, o con importes absurdos, se saltan y se cuentan.

OCR y limpieza de descripciones

El escaneo de recibos usa el reconocedor de texto de ML Kit en el propio telefono. El texto se extrae localmente y se construye un borrador editable antes de guardar; el reconocedor se cierra en cuanto acierta, falla o se cancela la corrutina. Si la lectura sale vacia o con poca confianza, sigue habiendo borrador, con aviso.

MerchantExtractor clasifica primero el tipo de operacion (UPI, tarjeta, transferencia, cajero, nomina, factura) con patrones de palabras clave y luego intenta recuperar el comercio real: parte la cadena por separadores, tira los tokens que parecen numeros de referencia, VPA o digitos puros, descarta palabras ruido como UPI, NEFT, REF o PAYTM y puntua lo que queda favoreciendo letras y penalizando digitos. Encima de eso, una tabla de palabras clave mapea comercios a categorias: Swiggy y Zomato caen en Food, Uber y Ola en Transport, Netflix y Spotify en Entertainment. Ingresos y transferencias se resuelven por signo y tipo, no por texto.

Lo que cuesta

Todo esto es determinista y legible, y tambien tiene un techo. Las tablas cubren bien bancos y comercios indios comunes y degradan a «Other» en el resto, asi que la primera importacion desde un banco raro pedira correcciones a mano. Y como el fichero original no se conserva, no hay forma de volver a parsearlo mas tarde con un algoritmo mejor. El autor lo asume: prefiere un extractor que se lee de una sentada antes que una caja negra que se quede con los extractos para mejorar sola.

Ahi esta lo aprovechable para quien disena sistemas que tocan datos sensibles. La historia de privacidad no es una politica que haya que creerse, es una forma que el codigo tiene: el fichero existe solo durante los milisegundos que tarda en leerse. Queda por ver si el enfoque aguanta cuando entre en juego el parseo asistido por modelo, que el repositorio deja apuntado pero no implementado.