¡¡¡ LOGO POR DEFNIR !!!
Sistema de Punto de Venta (POS) modular.
Permite gestionar inventario, ventas y analíticas con un modelo simple por sucursal.
- Aplicación de escritorio ligera y segura
- Menor consumo de RAM comparado con Electron
- Binarios pequeños y rápidos
- Acceso a hardware local (impresoras, básculas, lectores de código)
- Alto rendimiento y baja latencia
- Concurrencia eficiente
- Seguridad de memoria garantizada por Rust
- Excelente para APIs en tiempo real
- Operación local en cada sucursal
- Permite ventas sin conexión
- Sin dependencia de internet
- Sincronización de datos
- Reportes globales
- Multi-sucursal
- Alta disponibilidad
- Estándar industrial
- Confiable y robusto
- Amplio ecosistema
- Más barato que PostgreSQL
- Escalabilidad horizontal
- Alta tolerancia a fallos
- Ideal para crecimiento SaaS
- Desarrollo rápido de interfaces
- Consistencia visual
- Fácil soporte para tema claro/oscuro
- Diseño moderno y responsivo
- Offline-first con sincronización en la nube
- Multi-sucursal con inventarios independientes
- Sincronización segura y resiliente
- Diseño modular y escalable
- Cajas ilimitadas por sucursal
- Sistema multiusuario con roles
- Escalable por número de SKUs
- Alta de productos nuevos
- Entrada de mercancía (aumenta stock)
- Salida de inventario (ventas, mermas, ajustes)
- Historial de movimientos
- Productos activos/inactivos
- Búsqueda rápida por nombre, código o categoría
- Control de caducidades
- Manejo de productos por peso o fracción
- Alertas de stock bajo
- Soporte para códigos de barras
- Búsqueda rápida de productos
- Escaneo por código de barras
- Venta por unidad, peso o fracción
- Edición de cantidades en carrito
- Cálculo automático de totales
- Eliminación o modificación de productos
- Múltiples métodos de pago
- Cálculo de cambio
- Confirmación de venta
- Generación de ticket
- Historial de transacciones
- Actualización individual o masiva
- Historial de precios
- Soporte para descuentos
- Precios por sucursal
- Apertura y cierre de caja
- Conteo de efectivo
- Detección de diferencias
- Resumen diario
- Historial de cortes
- Ventas diarias
- Ventas por rango de fechas
- Productos más vendidos
- Ingresos por categoría
- Exportación de reportes
- Ingresos diarios
- Ticket promedio
- Productos más vendidos
- Productos con bajo stock
- Productos próximos a caducar
- Stock bajo
- Productos caducados o próximos a caducar
- Diferencias en corte de caja
- Acceso completo
- Gestión de usuarios
- Configuración del sistema
- Inventario
- Reportes y analíticas
- Corte de caja
- Gestión de precios
- Ventas
- Lista de compra
- Acceso limitado al inventario
- Inventario independiente por sucursal
- Reportes individuales
- Usuarios asignados por sucursal
- Catálogo compartido opcional
- Límite base de SKUs por sucursal según plan
- Expansión por bloques adicionales
- Conteo basado en productos activos
- Diseño moderno y minimalista
- Modo claro y oscuro
- Interfaz optimizada para rapidez
- Flujo de venta en pocos pasos
- Control de accesos por rol
- Registro de actividades
- Protección de datos por sucursal
- Reduce errores manuales
- Control total del inventario
- Decisiones basadas en datos
- Escalable para crecimiento del negocio
- Suscripción mensual por sucursal
- SKUs incluidos según plan
- Cajas y usuarios ilimitados
- Escalabilidad sin migraciones
- Creación de modulos personalizados (cotización aparte).
- Prueba gratuita de 14 días en cualquier plan
14 días gratis en los planes:
- Básico Web
- Web Profesional
Ventajas:
- Sin tarjeta de crédito requerida
- Cancelación sin compromiso
$50 MXN / mes por sucursal
Diseñado para negocios muy pequeños que solo necesitan registrar ventas.
| Característica | Detalle |
|---|---|
| Plataforma | Solo Web |
| SKUs incluidos | 100 productos |
| Cajas | 1 |
| Usuarios | Ilimitados |
| Analíticas | No incluidas |
| Reportes | No disponibles |
| Offline | No disponible |
Enfocado a:
- Tiendas pequeñas
- Emprendimientos
- Validación inicial
$200 MXN / mes por sucursal
Para negocios que necesitan control y reportes básicos.
| Característica | Detalle |
|---|---|
| Plataforma | Solo Web |
| SKUs incluidos | 200 productos |
| Cajas | 2 |
| Usuarios | Ilimitados |
| Analíticas | Incluidas |
| Reportes | Dentro de la plataforma |
| Offline | No disponible |
Enfocado a:
- Abarrotes pequeños
- Fruterías
- Carnicerías
$350 MXN / mes por sucursal
Solución completa para negocios que requieren confiabilidad y control total.
| Característica | Detalle |
|---|---|
| Plataforma | Web + Offline |
| SKUs incluidos | 350 productos |
| Cajas | Ilimitadas |
| Usuarios | Ilimitados |
| Analíticas | Avanzadas |
| Reportes | Generación y automatización por correo |
| Offline | Disponible |
| Concepto | Precio |
|---|---|
| SKUs adicionales | +$150 MXN por cada 1,000 SKUs |
Enfocado a:
- Ferreterías
- Carnicerías grandes
- Tiendas con múltiples cajas
Módulos a medida que se integran directamente al sistema
Ejemplos:
- Integración con básculas electrónicas
- Facturación electrónica (CFDI)
- Control de crédito a clientes
- Gestión de proveedores
- Compras automáticas
- Integración con tiendas en línea
- Reportes avanzados personalizados
| Concepto | Precio |
|---|---|
| Desarrollo de módulo | Cotización única |
| Mantenimiento opcional | Desde $100–$200 MXN / mes |
erDiagram
roles ||--o{ role_permissions : grants
permissions ||--o{ role_permissions : belongs_to
users ||--o{ user_roles : has
roles ||--o{ user_roles : assigned
users ||--o{ user_stores : assigned_to
store ||--o{ user_stores : has_staff
store ||--o{ devices : has
store ||--o{ sales : generates
users ||--o{ sales : performs
devices ||--o{ sales : registers
sales ||--o{ sale_items : contains
sales ||--o{ payments : paid_with
store ||--o{ inventory_movements : tracks
products ||--o{ inventory_movements : affects
products ||--o{ product_prices : has
store ||--o{ product_prices : defines
products ||--o{ product_categories : categorized
categories ||--o{ product_categories : groups
store ||--o{ cash_sessions : has
users ||--o{ cash_sessions : operates
devices ||--o{ cash_sessions : uses
%% USERS
users {
int id PK
varchar name
varchar second_name
varchar first_surname
varchar second_surname
varchar email
varchar password
timestamp created_at
timestamp updated_at
}
roles {
int id PK
varchar role_name
timestamp created_at
timestamp updated_at
}
permissions {
int id PK
varchar permission_name
timestamp created_at
timestamp updated_at
}
role_permissions {
int id PK
int role_id FK
int permission_id FK
timestamp created_at
timestamp updated_at
}
user_roles {
int id PK
int user_id FK
int role_id FK
}
%% STORE
store {
int id PK
varchar name
text address
timestamp created_at
timestamp updated_at
}
user_stores {
int id PK
int user_id FK
int store_id FK
timestamp created_at
timestamp updated_at
}
devices {
int id PK
int store_id FK
varchar name
timestamp created_at
}
%% PRODUCTS
products {
int id PK
varchar name
varchar barcode
text description
decimal cost
timestamp created_at
timestamp updated_at
}
product_prices {
int id PK
int product_id FK
int store_id FK
decimal price
}
categories {
int id PK
varchar name
}
product_categories {
int product_id FK
int category_id FK
}
%% INVENTORY
inventory_movements {
int id PK
int product_id FK
int store_id FK
varchar type
decimal quantity
int reference_id
timestamp created_at
}
%% SALES
sales {
int id PK
int store_id FK
int user_id FK
int device_id FK
varchar folio
decimal total
varchar status
timestamp created_at
}
sale_items {
int id PK
int sale_id FK
int product_id FK
decimal quantity
decimal price
decimal subtotal
}
payments {
int id PK
int sale_id FK
varchar method
decimal amount
}
%% CASH
cash_sessions {
int id PK
int store_id FK
int user_id FK
int device_id FK
timestamp opened_at
timestamp closed_at
decimal opening_amount
decimal closing_amount
decimal expected_amount
}
%% CUSTOMERS
customers {
int id PK
varchar name
varchar phone
varchar email
}
DB Diagram
// Permisos individuales del sistema
// (ej: crear venta, editar inventario)
Table permissions {
id int [pk]
permission_name varchar [not null]
created_at timestamp [default: `CURRENT_TIMESTAMP`]
updated_at timestamp
}
// Roles del sistema (Admin, Gerente, Empleado)
Table roles {
id int [pk]
role_name varchar [not null]
created_at timestamp [default: `CURRENT_TIMESTAMP`]
updated_at timestamp
}
// Relación muchos a muchos entre roles y permisos
Table role_permissions {
id int [pk]
role_id int [ref: > roles.id]
permission_id int [ref: > permissions.id]
created_at timestamp [default: `CURRENT_TIMESTAMP`]
updated_at timestamp
}
// Usuarios del sistema (empleados, administradores, etc.)
Table users {
id int [pk]
name varchar [not null]
second_name varchar
first_surname varchar
second_surname varchar
email varchar [not null]
password varchar [not null]
created_at timestamp [default: `CURRENT_TIMESTAMP`]
updated_at timestamp
}
// Relación muchos a muchos entre usuarios y roles
// (permite múltiples roles por usuario)
Table user_roles {
id int [pk]
user_id int [ref: > users.id]
role_id int [ref: > roles.id]
}
// Sucursales del negocio (cada tienda física o ubicación)
Table store {
id int [pk]
name varchar [not null]
address text
created_at timestamp [default: `CURRENT_TIMESTAMP`]
updated_at timestamp
}
// Relación entre usuarios y sucursales
// (dónde puede trabajar cada usuario)
Table user_stores {
id int [pk]
user_id int [ref: > users.id]
store_id int [ref: > store.id]
created_at timestamp [default: `CURRENT_TIMESTAMP`]
updated_at timestamp
}
// Dispositivos o cajas dentro de una sucursal (ej: Caja 1, Caja 2)
Table devices {
id int [pk]
store_id int [ref: > store.id]
name varchar
created_at timestamp [default: `CURRENT_TIMESTAMP`]
}
// Categorías de productos (para organización y reportes)
Table categories {
id int [pk]
name varchar
}
// Catálogo global de productos (sin stock ni precio por sucursal)
Table products {
id int [pk]
name varchar [not null]
barcode varchar [unique]
description text
cost decimal(10,2)
created_at timestamp [default: `CURRENT_TIMESTAMP`]
updated_at timestamp
}
// Precio de productos por sucursal
// (permite diferentes precios por tienda)
Table product_prices {
id int [pk]
product_id int [ref: > products.id]
store_id int [ref: > store.id]
price decimal(10,2)
}
// Relación entre productos y categorías (muchos a muchos)
Table product_categories {
product_id int [ref: > products.id]
category_id int [ref: > categories.id]
}
// Historial de movimientos de inventario
// (fuente real del stock)
Table inventory_movements {
id int [pk]
product_id int [ref: > products.id]
store_id int [ref: > store.id]
type varchar // sale, purchase, adjustment, loss
quantity decimal(10,2)
reference_id int // referencia a venta u operación
created_at timestamp [default: `CURRENT_TIMESTAMP`]
}
// Registro principal de ventas realizadas
Table sales {
id int [pk]
store_id int [ref: > store.id]
user_id int [ref: > users.id]
device_id int [ref: > devices.id]
folio varchar // número de ticket
total decimal(10,2)
status varchar // completed, cancelled
created_at timestamp [default: `CURRENT_TIMESTAMP`]
}
// Detalle de productos vendidos en cada venta
Table sale_items {
id int [pk]
sale_id int [ref: > sales.id]
product_id int [ref: > products.id]
quantity decimal(10,2)
price decimal(10,2)
subtotal decimal(10,2)
}
// Métodos de pago utilizados en una venta
// (permite pagos mixtos)
Table payments {
id int [pk]
sale_id int [ref: > sales.id]
method varchar // cash, card, transfer
amount decimal(10,2)
}
// Sesiones de caja (apertura y cierre de caja por usuario/dispositivo)
Table cash_sessions {
id int [pk]
store_id int [ref: > store.id]
user_id int [ref: > users.id]
device_id int [ref: > devices.id]
opened_at timestamp
closed_at timestamp
opening_amount decimal(10,2)
closing_amount decimal(10,2)
expected_amount decimal(10,2)
}
// Clientes del sistema (para historial, crédito o facturación futura)
Table customers {
id int [pk]
name varchar
phone varchar
email varchar
}
Esto es solo un listado de los endpoints que se necesitarian
Importante por si hay cambios internos que pueden afectar al usuario
/api/v1
Autentica usuario y devuelve token + contexto (stores, roles)
Tablas:
- users
- user_roles
- roles
- user_stores
Notas:
- Validar password
- Devolver stores asignadas
- Ideal incluir device_id si es POS
Obtiene info del usuario autenticado
Tablas:
- users
- user_roles
- roles
- user_stores
Notas:
- Se usa para reconstruir sesión
Cierra sesión
Lista sucursales del usuario
Tablas:
- store
- user_stores
Detalle de sucursal
Tablas:
- store
Lista usuarios de la sucursal
Tablas:
- users
- user_stores
Crear usuario
Tablas:
- users
- user_roles
- user_stores
Notas:
- Asignar rol y sucursal
Editar usuario
Tablas:
- users
- user_roles
Lista cajas de una sucursal
Tablas:
- devices
Crear nueva caja
Tablas:
- devices
Lista catálogo
Tablas:
- products
Crear producto
Tablas:
- products
- product_prices
- product_categories
Editar producto
Tablas:
- products
Búsqueda rápida (nombre o código)
Tablas:
- products
- product_prices
Notas:
- Endpoint MÁS crítico en POS
- Debe ser ultra rápido
Buscar producto por código de barras
Tablas:
- products
- product_prices
Actualizar precio por sucursal
Tablas:
- product_prices
Notas:
- No modificar products
Obtener precios de la sucursal
Tablas:
- product_prices
- products
Listar categorías
Tablas:
- categories
Crear categoría
Tablas:
- categories
Actualizar categorias
Tablas:
- categories
Ajuste manual de inventario
Tablas:
- inventory_movements
Notas:
- Nunca modificar stock directo
- Crear movimiento tipo adjustment
Entrada de mercancía (compra)
Tablas:
- inventory_movements
Notas:
- type = purchase
Registrar merma
Tablas:
- inventory_movements
Notas:
- type = loss
Historial de movimientos
Tablas:
- inventory_movements
Stock actual por producto
Tablas:
- inventory_movements
Notas:
- Calcular SUM dinámico o usar cache
Crear venta completa
Tablas:
- sales
- sale_items
- payments
- inventory_movements
Notas:
- Calcular precios (NO confiar en frontend)
- Generar folio
- Validar stock
- Crear movimientos tipo sale
- Transacción atómica
Listar ventas
Tablas:
- sales
Filtros:
- fecha
- store_id
Detalle de venta
Tablas:
- sales
- sale_items
- payments
Cancelar venta
Tablas:
- sales
- inventory_movements
Notas:
- Revertir inventario
- Marcar status = cancelled
Ver pagos de una venta
Tablas:
- payments
Abrir caja
Tablas:
- cash_sessions
Cerrar caja
Tablas:
- cash_sessions
- sales
Notas:
- Calcular expected_amount basado en ventas
Obtener sesión activa
Tablas:
- cash_sessions
Historial de cortes
Tablas:
- cash_sessions
Listar clientes
Tablas:
- customers
Crear cliente
Tablas:
- customers
Básicos
Ventas del día
Tablas:
- sales
Ventas por rango
Tablas:
- sales
Productos más vendidos
Tablas:
- sale_items
- products
Subir datos locales al servidor
Tablas:
- sales
- inventory_movements
Notas:
- append-only
- usar idempotencia
Descargar cambios del servidor
Tablas:
- products
- product_prices
/sales
/products/search
/cash-sessions/open
/cash-sessions/close
/inventory/adjust
- Ventas = inmutables
- no se editan
- solo cancelar
- Inventario = eventos
- no hay update directo
- todo pasa por movements
- Backend manda
- precios
- totales
- validaciones
- Transacciones SIEMPRE
Especialmente en:
/sales
/sales/cancel
Se organizo un Roadmap a base de colores para que sea de "facil" identificación.
Tener backend corriendo, auth funcional y base del sistema lista.
Sistema de login + sesión
Endpoints:
POST /auth/loginGET /auth/mePOST /auth/logout
Endpoints:
GET /usersPOST /usersPATCH /users/:id
Endpoints:
GET /storesGET /stores/:id
- Aquí definimos JWT + middleware
- No complicarse con permisos aún → solo roles
- Esto desbloquea todo lo demás
Poder crear productos y consultarlos rápido (core del POS)
Endpoints:
GET /productsPOST /productsPATCH /products/:id
Endpoints:
GET /products/search?q=GET /products/barcode/:barcode
Endpoints:
GET /categoriesPOST /categories
Endpoints:
PUT /products/:id/priceGET /stores/:store_id/prices
Este es el endpoint más importante del sistema:
/products/searchOptimízarlo desde el día 1 (índices, LIKE, etc.)
- Aquí aún NO se maneja stock
Tener control real de stock basado en eventos
Endpoints:
POST /inventory/entry(compra)POST /inventory/adjust(ajuste manual)POST /inventory/loss(merma)
Endpoints:
GET /inventory/movementsGET /inventory/stock
- NO guardar stock directo en
products - Todo sale de
inventory_movements
Esto nos salva de:
- bugs
- inconsistencias
- dolores de cabeza
Ya vender en vida real
Endpoint clave:
POST /sales
GET /salesGET /sales/:id
POST /sales/:id/cancel
GET /sales/:id/payments
Este endpoint debe ser transaccional
Validaciones:
- stock
- precios
- totales
Genera:
salesale_itemspaymentsinventory_movements
Controlar dinero real (apertura/cierre)
POST /cash-sessions/open
POST /cash-sessions/:id/close
GET /cash-sessions/current
GET /cash-sessions
- Calcular
expected_amountautomáticamente - Esto conecta ventas + dinero físico
Soportar múltiples cajas por tienda
GET /devicesPOST /devices
- Cada venta debe tener
device_id - Esto habilita: auditoría y multi-caja real
Prepararnos para features futuras (crédito, facturación)
GET /customersPOST /customers
- No sobrepensar por el momento
- Es base para: CFDI, historial, lealtad
Dar valor real al negocio
GET /reports/sales/dailyGET /reports/sales/range
GET /reports/top-products
- Aquí se pueden usar agregaciones SQL
- No necesitamos BI complejo aún
Convertirte en un POS serio
POST /sync/push
GET /sync/pull
Usa:
- timestamps
- versionado
- idempotencia
Modelo: local (SQLite) → cloud → otros dispositivos
Sí, ventas antes que inventario completo, porque:
- podemos simular stock al inicio
- validamos el UX rápido
| Feature | Fase |
|---|---|
| Auth | 0 |
| Productos + búsqueda | 1 |
| Ventas | 3 |
| Caja básica | 4 |
Con eso ya deberiamos poder cobrar algo
- Hacer sync demasiado pronto
- Sobre-diseñar roles/permisos
- Meter reportes complejos temprano
- No hacer transacciones en
/sales - Guardar stock como columna en
products