POS Farmaeconomica
Un punto de venta que se diseñó después de escuchar, no antes.
- Electron
- React
- TypeScript
- SQLite
- Drizzle ORM
- Vite

El problema
El plan original daba por hecho un lector de código de barras, impresión térmica obligatoria y una lista de precios lista para importar. La entrevista con la dueña desarmó las tres: no tienen pistola, casi nadie pide recibo, y los precios no están en ningún archivo —están marcados en la caja de cada producto—. Su verdadero problema, dicho dos veces, era otro: no encontrar el producto.
La solución
Se reescribió el alcance alrededor de ese dolor. La búsqueda dejó de fallar por una tilde, el precio se pide durante la venta —así el catálogo se llena vendiendo, sin una carga inicial que nadie iba a hacer—, y la impresora salió del proyecto en vez de comprarse. Lo demás se construyó en etapas cortas, cada una revisada por la dueña antes de seguir.
Arquitectura
- 01
Electron con SQLite local y migraciones versionadas: todo el negocio vive en un archivo que cabe en una USB, sin servidor ni cuenta que renovar.
- 02
Los repositorios reciben la conexión por parámetro y no importan nada de Electron, así que la lógica de negocio se prueba desde la terminal sin abrir la aplicación.
- 03
Columna de búsqueda normalizada sin tildes, reconstruida al arrancar: escribir «acetaminofen» encuentra «Acetaminofén», que era exactamente lo que antes no pasaba.
- 04
La venta es una sola transacción: cabecera, ítems, descuento de lotes por FEFO y movimientos de inventario. No existe forma de que el stock quede a medio actualizar.
- 05
El PIN se verifica en el proceso principal y el hash nunca cruza el IPC: la interfaz jamás recibe algo que se pueda comparar por su cuenta.
- 06
Instalador NSIS que no pide administrador y que al desinstalar deja la base de datos intacta.
Stack
- Electron
- React
- TypeScript
- SQLite
- Drizzle ORM
- Vite
Retos técnicos
El error más caro estaba en el brief, no en el código
Antes de seguir construyendo se hizo una entrevista de dieciocho preguntas a la dueña. Esa hora canceló una etapa completa —impresión térmica y cajón monedero, con hardware que había que comprar—, tumbó la suposición del lector de códigos y movió al primer lugar algo que no estaba ni en la lista: la búsqueda. Todo el orden de trabajo posterior salió de ahí.
Un catálogo que se llena vendiendo
Como los precios están marcados en la caja del producto y los proveedores los cambian cada quince días, cualquier carga inicial nacía desactualizada. La venta pide el precio la primera vez que se vende algo y lo recuerda. El programa funciona con el catálogo incompleto desde el primer día, que era la condición para que lo usaran mientras seguían con el cuaderno.
Dos caminos distintos para el mismo respaldo
Copiar el archivo mientras la base está abierta produce respaldos rotos; hacerlo al cerrar no sirve si el equipo nunca se apaga. Con la aplicación abierta se usa la copia en línea de SQLite, que no bloquea la venta, y después se aplana el WAL para que quede un solo archivo llevable a una USB. Al cerrar se cierra primero la base y ahí sí se copia el archivo. El «último respaldo» se calcula de la fecha de los archivos, porque el de cierre ocurre con la base ya cerrada y no podría anotarse a sí mismo.
Resultados
- Estado
- Nueve etapas construidas y verificadas, con instalador
- Alcance
- Venta, inventario por lotes, importación, caja y respaldos
- Pendiente
- Firma de código para distribuirlo sin advertencias de Windows