Saltar al contenido
Omar Dev Sampayo
Volver a proyectos

Caso de estudio · Proyecto propio · Retail · Repostería

Una vez más · Gestión

Inventario, ventas y finanzas para un negocio real de repostería

Cliente
Negocio de galletas y repostería en México
Rol
Product Owner y Full-Stack Developer
Periodo
Sep 2026 – hoy
Estado
En producción · uso diario
pruebas automatizadas (170+ de integración y 88 E2E)
300+
líneas de TypeScript sin contar pruebas
~17,500
migraciones de base de datos con permisos escritos a mano
27
Pantalla de inicio del sistema de gestión de Una vez más, con accesos rápidos, resumen de ventas y productos por agotarse; las cifras están ocultas.

Contexto

Una vez más es un negocio real de galletas y repostería en México. Llevaba compras, inventario y ventas en un Excel: no había usuarios ni permisos, no se sabía cuánta mercancía traía cada vendedora y la utilidad real no se veía.

Lo diseñé, construí, desplegué y lo opero. El primer commit es del 21 de septiembre de 2026, y en pocas semanas el sistema ya estaba en producción, usado a diario por el dueño y sus vendedoras. Conserva las reglas de cálculo del Excel, como la gasolina de cada compra repartida entre las piezas, y agrega lo que faltaba.

Funcionalidades

  • Compras: cada compra es un viaje a un proveedor, con el costo de la gasolina prorrateado por pieza.
  • Inventario por ubicación: el almacén y una ubicación por vendedora, con traspasos, mermas, ajustes, conteo físico y un kardex inmutable de movimientos.
  • Costo promedio ponderado móvil por producto: la utilidad de cada venta se calcula con el costo que tenía el producto en ese momento.
  • Punto de venta móvil: la vendedora cobra desde su celular, solo con la mercancía que trae, con pagos mixtos (efectivo, transferencia y tarjeta). La comisión de la terminal se calcula sola.
  • Cobro por transferencia: la CLABE se valida con su dígito verificador y la vendedora puede mostrar el QR bancario en pantalla.
  • Devoluciones con reembolso parcial, incluida la parte de la comisión que regresa la terminal.
  • Comisiones de vendedoras sobre la utilidad, con saldo por pagar y registro de pagos.
  • Finanzas: gastos por categoría, aportaciones y retiros de socios contados aparte de la utilidad, estado de resultados y «Dónde está el dinero», el saldo por bolsa.
  • Reportes por día, producto, vendedora, canal y método de pago; corte de caja; simulador de precio; exportación a CSV y a Excel con gráficas.
  • Catálogo con IA: fotos procesadas en el servidor (redimensionadas y sin metadatos GPS) y fichas de producto generadas con la API de OpenAI.
  • Sitio web público alimentado por una API de solo lectura y cacheada, que publica la disponibilidad (disponible, últimas piezas, agotado), nunca las existencias exactas.

Un modelo contable correcto

Lo más delicado del proyecto no es la interfaz sino que los números cuadren. El modelo cubre el costo promedio ponderado, el prorrateo de gasolina, las comisiones de terminal y de vendedoras, las devoluciones parciales, el capital de socios separado de la utilidad y los saldos por bolsa de dinero.

Todas las cuentas de dinero viven en un paquete compartido y se hacen con decimal exacto (big.js, nunca number). La API y el frontend llaman a las mismas funciones, así que siempre dan el mismo número. El modelo está probado contra los números del Excel original.

Arquitectura

  • Monorepo con npm workspaces y TypeScript estricto de punta a punta.
  • Backend: NestJS, Drizzle ORM y PostgreSQL 18, con validación con Zod, errores estructurados en español e idempotencia en todos los documentos (ventas, compras y gastos).
  • Frontend: Angular 22 con componentes standalone, signals, httpResource y OnPush, y Angular Material 3 con tema propio. Está pensado primero para el celular.
  • Infraestructura: Docker Compose en un VPS. Cloudflare Tunnel evita que la app abra puertos a internet, Cloudflare Access hace de login (la API valida su JWT) y R2 guarda las imágenes y los respaldos.
  • CI/CD: GitHub Actions corre lint y pruebas y construye una imagen etiquetada por commit en GHCR. Se despliega por SHA exacto, nunca latest, con migraciones automáticas al arrancar.

Seguridad y datos

  • Defensa en capas: Cloudflare Access para entrar y permisos por rol con un guard que niega por omisión toda ruta que no declare su permiso. La API filtra costos y márgenes según el rol: un vendedor nunca los recibe.
  • Tres roles de Postgres separados (dueño, app y lectura del sitio). La app no puede borrar ni reescribir el kardex, y los permisos van en migraciones escritas a mano.
  • El sitio público nunca toca la base de datos. Descarté a propósito exponer Postgres por el túnel.
  • Respaldos diarios con pg_dump, cifrados con rclone crypt en un bucket con retención bloqueada, y con un procedimiento de restauración probado.
  • Bitácora de auditoría de los cambios sensibles y servidor endurecido: SSH solo con llave, fail2ban y firewall que niega por omisión.

Calidad

Tipo Herramienta Alcance
Unitarias Vitest Los tres paquetes del monorepo
Integración Testcontainers 170+ pruebas de la API contra PostgreSQL 18 real
End-to-end Playwright 88 pruebas, en escritorio y celular
Accesibilidad axe WCAG 2.1 AA en cada pantalla, como requisito

Cómo lo trabajé

Soy el dueño del producto: decido qué se construye y en qué orden. Desarrollo con apoyo de un agente de IA (Claude Code) y apruebo cada paso a producción.

Stack

  • Angular 22
  • NestJS
  • Drizzle ORM
  • PostgreSQL 18
  • Zod
  • big.js
  • Docker Compose
  • Cloudflare Tunnel
  • Cloudflare Access
  • Cloudflare R2
  • GitHub Actions
  • Vitest
  • Testcontainers
  • Playwright