← Volver a proyectos

Proyecto

JBP — Control de costos para acopio agrícola

Caso de cliente — Agrícola Industrial JBP (noroeste de México): su operación de acopio ahora sabe el margen real de cada viaje y dónde se fugaba el dinero. Sistema a medida para Agrícola Industrial JBP, empresa agroindustrial de acopio en el noroeste de México que compra tomate y chile y lo entrega en plantas industriales. Costea cada viaje contra la orden de compra, separa el margen estimado del real y explica la diferencia por sus dos causas —merma de peso y castigo por calidad—, dinero que antes se fugaba sin que nadie lo midiera. Construido y entregado en solitario; en producción.

En producción — operado por el cliente Trabajo para cliente — bajo contrato (VALC Tech) Fundador e Ingeniero (VALC Tech) — En solitario, de extremo a extremo Repositorio privado — operado por el cliente

Software a medida diseñado, construido y desplegado en solitario bajo contrato para Agrícola Industrial JBP SPR de RI, y operado por el cliente. Publicado con su autorización. El repositorio y todos los datos de negocio son privados; la descripción cubre únicamente arquitectura y decisiones de ingeniería.

Stack

Angular 21TypeScriptTailwind CSS 4PWA (offline-first)FirebaseFirestoreFirebase AuthCloud Functions v2 (Node 22)Firebase StorageFCMFirebase Emulator SuiteVitestGitHub ActionsGCP

Impacto

  • Hizo visible la fuga de margen: el sistema separa margen estimado y real por viaje y atribuye la diferencia a merma o castigo, que es el número con el que el negocio ahora negocia.
  • Permite comparar las dos rutas de acopio —comprar vía proveedor o comprar directo al agricultor pagando corte y flete por separado— en vez de adivinar cuál deja más.
  • Sustituyó el control en hojas de cálculo de cuentas corrientes de proveedores, anticipos y conciliación bancaria entre dos razones sociales y dos cuentas de banco.
  • La captura en campo funciona sin señal: se registra el viaje junto a la báscula y los datos sincronizan cuando vuelve la cobertura.
  • Entregado en producción con despliegue automatizado, así que las correcciones llegan al cliente el mismo día que se integran.

Lo que hice

  • El dinero se guarda en centavos enteros y los pesos en gramos —nunca floats—, porque el negocio entero es una resta de centavos por kilo.
  • Toda operación que toca dinero pasa por callable Cloud Functions idempotentes; la escritura directa del cliente es una excepción deliberada, limitada a la captura offline en campo y acotada por reglas estrictas de Firestore.
  • Control de acceso por roles vía custom claims (administrador, socio, oficina, proveedor, solo lectura), con revocación de tokens al cambiar el rol.
  • El proveedor no ve precios de venta, órdenes de compra ni tarifas de flete: lee una proyección de sus propios viajes mantenida por trigger, forzada por una regla de Firestore con prueba propia, para no exponer el margen por kilo de la empresa.
  • Los totales del tablero salen de documentos de agregados mensuales mantenidos por triggers que recalculan el mes completo en vez de sumar diferencias, porque Firestore puede entregar el mismo evento dos veces y un incremento repetido infla un total sin que nadie lo note.
  • Las fechas de negocio están ancladas a America/Mazatlan y no a UTC: con la zona equivocada, lo capturado después de las 23:00 caía al día siguiente.
  • Nada se borra: soft-delete y bitácora de autor en cada movimiento de dinero.
  • Pirámide de pruebas de cuatro niveles sobre instancias de emulador aisladas —unitarias, 123 casos de reglas de Firestore/Storage y 93 pruebas de Cloud Functions—, de modo que una demostración en vivo sigue corriendo mientras la suite se ejecuta.
  • Módulos entregados: viajes y costeo, dinero y anticipos, actividades por ciclo de cultivo, cobranza, relación contra planta, banco, reportes financieros y catálogos.

Arquitectura

  • Monorepo: apps/web (PWA en Angular) + functions (Cloud Functions v2, TypeScript sobre Node 22)
  • Núcleo de cálculo compartido y sincronizado hacia functions, para que cliente y servidor costeen un viaje con exactamente el mismo código
  • Modelo Firestore multi-entidad: catálogos compartidos entre las dos razones sociales, movimientos siempre acotados por entityId
  • Captura offline-first mediante la persistencia local del SDK de Firestore; las operaciones de dinero van por callables
  • Agregados mantenidos por triggers para los tableros; scripts de rehecho para recalcular históricos
  • Dos instancias de emulador aisladas (desarrollo y pruebas) en rangos de puertos distintos, para que la suite nunca estorbe a una demostración en curso
  • CI/CD con GitHub Actions: los pull requests verifican, los push a main verifican y despliegan

Etiquetas

Custom SoftwareAgritechOffline-firstPWAFirebaseFull Stack