Aplicación web logística SaaS multi-tenant
Documento consolidado para desarrollar una aplicación web especializada en manejo logístico, inventario, almacenes, cotizaciones, pedidos, fabricación, picking, despacho, usuarios, roles, permisos y PWA, usando Node.js + MySQL en servidor compartido.
1. Enfoque general del proyecto
La aplicación debe nacer como un SaaS logístico multi-tenant para empresas que manejan inventario, almacenes, pedidos, fabricación, cotización y despacho.
El punto diferencial será que el sistema no tratará todos los productos igual. Cada producto podrá tener un perfil de control logístico.
- Producto simple
- Producto serializado
- Producto con lote
- Producto con vencimiento
- Producto con variantes
- Pack
- Producto compuesto por fórmula
- Producto fabricado bajo proceso
- Producto con control mixto
Ejemplos
| Producto | Control requerido |
|---|---|
| Laptop | Número de serie |
| Medicamento | Lote + vencimiento |
| Pernos | Lote / medidas / fabricación |
| Camiseta | Talla + color |
| Kit de instalación | Pack |
| Anclaje químico | Fórmula / fabricación |
| Caja de productos | Pack / unidad / caja |
2. Estructura recomendada del proyecto
Estructura preparada para crecer, pero manteniendo simplicidad para un solo programador. Incluye módulos de usuarios, roles, permisos e invitaciones para los suscriptores.
logistica-saas/
│
├── app.js
├── server.js
├── package.json
├── .env
├── .env.example
├── README.md
│
├── docs/
│ ├── 00-PROJECT-VISION.md
│ ├── 01-ARCHITECTURE.md
│ ├── 02-MULTI-TENANCY.md
│ ├── 03-DATABASE-STANDARDS.md
│ ├── 04-MODULES-SCOPE.md
│ ├── 05-PRODUCT-CONTROL-MODEL.md
│ ├── 06-INVENTORY-WORKFLOW.md
│ ├── 07-ANCHORS-MANUFACTURING.md
│ ├── 08-PHOENIX-UI-GUIDE.md
│ ├── 09-PWA-GUIDE.md
│ ├── 10-CODEX-INSTRUCTIONS.md
│ ├── 11-ROADMAP.md
│ └── 12-USERS-ROLES-PERMISSIONS.md
│
├── src/
│ ├── config/
│ │ ├── app.config.js
│ │ ├── db.config.js
│ │ ├── auth.config.js
│ │ ├── upload.config.js
│ │ └── subscription.config.js
│ │
│ ├── database/
│ │ ├── connection.js
│ │ ├── migrations/
│ │ │ ├── 001_create_tenants.sql
│ │ │ ├── 002_create_users.sql
│ │ │ ├── 003_create_subscriptions.sql
│ │ │ ├── 004_create_products.sql
│ │ │ ├── 005_create_warehouses.sql
│ │ │ ├── 006_create_inventory.sql
│ │ │ ├── 007_create_quotes_orders.sql
│ │ │ ├── 008_create_manufacturing.sql
│ │ │ ├── 009_create_dispatch.sql
│ │ │ ├── 010_create_audit_logs.sql
│ │ │ └── 011_create_users_roles_permissions.sql
│ │ │
│ │ └── seeds/
│ │ ├── seed_plans.sql
│ │ ├── seed_roles.sql
│ │ ├── seed_permissions.sql
│ │ ├── seed_countries.sql
│ │ ├── seed_currencies.sql
│ │ └── seed_tax_rates.sql
│ │
│ ├── core/
│ │ ├── errors/
│ │ │ ├── AppError.js
│ │ │ └── errorHandler.js
│ │ │
│ │ ├── helpers/
│ │ │ ├── asyncHandler.js
│ │ │ ├── date.helper.js
│ │ │ ├── money.helper.js
│ │ │ ├── pagination.helper.js
│ │ │ └── tenant.helper.js
│ │ │
│ │ ├── middlewares/
│ │ │ ├── auth.middleware.js
│ │ │ ├── tenant.middleware.js
│ │ │ ├── subscription.middleware.js
│ │ │ ├── permission.middleware.js
│ │ │ ├── validate.middleware.js
│ │ │ ├── csrf.middleware.js
│ │ │ ├── rateLimit.middleware.js
│ │ │ └── audit.middleware.js
│ │ │
│ │ ├── services/
│ │ │ ├── audit.service.js
│ │ │ ├── file.service.js
│ │ │ ├── mail.service.js
│ │ │ ├── notification.service.js
│ │ │ └── sequence.service.js
│ │ │
│ │ └── validators/
│ │ └── common.validator.js
│ │
│ ├── modules/
│ │ ├── auth/
│ │ │ ├── auth.routes.js
│ │ │ ├── auth.controller.js
│ │ │ ├── auth.service.js
│ │ │ ├── auth.model.js
│ │ │ └── auth.validator.js
│ │ │
│ │ ├── tenants/
│ │ │ ├── tenants.routes.js
│ │ │ ├── tenants.controller.js
│ │ │ ├── tenants.service.js
│ │ │ ├── tenants.model.js
│ │ │ └── tenants.validator.js
│ │ │
│ │ ├── subscriptions/
│ │ │ ├── subscriptions.routes.js
│ │ │ ├── subscriptions.controller.js
│ │ │ ├── subscriptions.service.js
│ │ │ └── subscriptions.model.js
│ │ │
│ │ ├── users/
│ │ │ ├── users.routes.js
│ │ │ ├── users.controller.js
│ │ │ ├── users.service.js
│ │ │ ├── users.model.js
│ │ │ └── users.validator.js
│ │ │
│ │ ├── roles/
│ │ │ ├── roles.routes.js
│ │ │ ├── roles.controller.js
│ │ │ ├── roles.service.js
│ │ │ ├── roles.model.js
│ │ │ ├── permissions.service.js
│ │ │ └── roles.validator.js
│ │ │
│ │ ├── settings/
│ │ │ ├── settings.routes.js
│ │ │ ├── settings.controller.js
│ │ │ ├── settings.service.js
│ │ │ └── settings.model.js
│ │ │
│ │ ├── customers/
│ │ │ ├── customers.routes.js
│ │ │ ├── customers.controller.js
│ │ │ ├── customers.service.js
│ │ │ └── customers.model.js
│ │ │
│ │ ├── suppliers/
│ │ │ ├── suppliers.routes.js
│ │ │ ├── suppliers.controller.js
│ │ │ ├── suppliers.service.js
│ │ │ └── suppliers.model.js
│ │ │
│ │ ├── products/
│ │ │ ├── products.routes.js
│ │ │ ├── products.controller.js
│ │ │ ├── products.service.js
│ │ │ ├── products.model.js
│ │ │ ├── productControls.service.js
│ │ │ ├── productVariants.service.js
│ │ │ ├── productPacks.service.js
│ │ │ └── products.validator.js
│ │ │
│ │ ├── warehouses/
│ │ │ ├── warehouses.routes.js
│ │ │ ├── warehouses.controller.js
│ │ │ ├── warehouses.service.js
│ │ │ ├── warehouses.model.js
│ │ │ └── locations.service.js
│ │ │
│ │ ├── inventory/
│ │ │ ├── inventory.routes.js
│ │ │ ├── inventory.controller.js
│ │ │ ├── inventory.service.js
│ │ │ ├── inventory.model.js
│ │ │ ├── stock.service.js
│ │ │ ├── kardex.service.js
│ │ │ ├── lot.service.js
│ │ │ ├── serial.service.js
│ │ │ └── expiration.service.js
│ │ │
│ │ ├── quotes/
│ │ │ ├── quotes.routes.js
│ │ │ ├── quotes.controller.js
│ │ │ ├── quotes.service.js
│ │ │ ├── quotes.model.js
│ │ │ └── quotePricing.service.js
│ │ │
│ │ ├── orders/
│ │ │ ├── orders.routes.js
│ │ │ ├── orders.controller.js
│ │ │ ├── orders.service.js
│ │ │ └── orders.model.js
│ │ │
│ │ ├── purchases/
│ │ │ ├── purchases.routes.js
│ │ │ ├── purchases.controller.js
│ │ │ ├── purchases.service.js
│ │ │ └── purchases.model.js
│ │ │
│ │ ├── manufacturing/
│ │ │ ├── manufacturing.routes.js
│ │ │ ├── manufacturing.controller.js
│ │ │ ├── manufacturing.service.js
│ │ │ ├── manufacturing.model.js
│ │ │ ├── anchors.service.js
│ │ │ ├── formulas.service.js
│ │ │ └── operations.service.js
│ │ │
│ │ ├── picking/
│ │ │ ├── picking.routes.js
│ │ │ ├── picking.controller.js
│ │ │ ├── picking.service.js
│ │ │ └── picking.model.js
│ │ │
│ │ ├── dispatch/
│ │ │ ├── dispatch.routes.js
│ │ │ ├── dispatch.controller.js
│ │ │ ├── dispatch.service.js
│ │ │ └── dispatch.model.js
│ │ │
│ │ ├── currencies/
│ │ │ ├── currencies.routes.js
│ │ │ ├── currencies.controller.js
│ │ │ ├── currencies.service.js
│ │ │ └── currencies.model.js
│ │ │
│ │ ├── taxes/
│ │ │ ├── taxes.routes.js
│ │ │ ├── taxes.controller.js
│ │ │ ├── taxes.service.js
│ │ │ └── taxes.model.js
│ │ │
│ │ ├── reports/
│ │ │ ├── reports.routes.js
│ │ │ ├── reports.controller.js
│ │ │ ├── reports.service.js
│ │ │ └── reports.model.js
│ │ │
│ │ └── pwa/
│ │ ├── pwa.routes.js
│ │ ├── pwa.controller.js
│ │ └── push.service.js
│ │
│ ├── routes/
│ │ ├── web.routes.js
│ │ ├── api.routes.js
│ │ └── index.js
│ │
│ └── views/
│ ├── layouts/
│ │ ├── main.ejs
│ │ ├── auth.ejs
│ │ └── blank.ejs
│ │
│ ├── partials/
│ │ ├── head.ejs
│ │ ├── navbar.ejs
│ │ ├── sidebar.ejs
│ │ ├── footer.ejs
│ │ ├── flash.ejs
│ │ └── breadcrumbs.ejs
│ │
│ ├── auth/
│ │ ├── login.ejs
│ │ ├── register.ejs
│ │ └── forgot-password.ejs
│ │
│ ├── dashboard/
│ │ └── index.ejs
│ │
│ ├── users/
│ │ ├── index.ejs
│ │ ├── create.ejs
│ │ ├── edit.ejs
│ │ ├── show.ejs
│ │ └── invite.ejs
│ │
│ ├── roles/
│ │ ├── index.ejs
│ │ ├── create.ejs
│ │ ├── edit.ejs
│ │ └── permissions.ejs
│ │
│ ├── products/
│ │ ├── index.ejs
│ │ ├── create.ejs
│ │ ├── edit.ejs
│ │ └── show.ejs
│ │
│ ├── warehouses/
│ ├── inventory/
│ ├── quotes/
│ ├── orders/
│ ├── purchases/
│ ├── manufacturing/
│ ├── picking/
│ ├── dispatch/
│ ├── settings/
│ └── errors/
│ ├── 403.ejs
│ ├── 404.ejs
│ └── 500.ejs
│
├── public/
│ ├── phoenix/
│ │ ├── css/
│ │ ├── js/
│ │ ├── img/
│ │ └── vendors/
│ │
│ ├── app/
│ │ ├── css/
│ │ │ └── custom.css
│ │ ├── js/
│ │ │ ├── main.js
│ │ │ ├── pwa.js
│ │ │ └── forms.js
│ │ └── img/
│ │
│ ├── manifest.json
│ ├── service-worker.js
│ └── offline.html
│
├── storage/
│ ├── uploads/
│ ├── exports/
│ ├── temp/
│ └── logs/
│
├── scripts/
│ ├── migrate.js
│ ├── seed.js
│ ├── create-admin.js
│ ├── create-tenant.js
│ └── backup-db.js
│
└── tests/
├── auth.test.js
├── tenant.test.js
├── users.test.js
├── roles.test.js
├── products.test.js
└── inventory.test.js
3. Criterio de arquitectura
Para un solo programador, evita crear demasiadas capas al inicio. La estructura por módulo debe ser consistente.
module/\n├── module.routes.js\n├── module.controller.js\n├── module.service.js\n├── module.model.js\n└── module.validator.js
| Archivo | Responsabilidad |
|---|---|
| routes.js | Define URLs y middlewares. |
| controller.js | Recibe request, responde vistas o JSON. |
| service.js | Contiene lógica de negocio. |
| model.js | Ejecuta consultas SQL parametrizadas. |
| validator.js | Valida datos de entrada. |
products.controller.js
No debe hacer SQL directo.
products.service.js
Resuelve reglas de negocio: serie, lote, vencimiento, pack, fórmula y fabricación.
products.model.js
Solo debe consultar MySQL usando SQL parametrizado.
4. Principios multi-tenant
Como usarás base de datos compartida, todas las tablas operativas deben tener
tenant_id.
- products
- warehouses
- inventory_stock
- inventory_movements
- customers
- quotes
- orders
- purchases
- manufacturing_orders
- dispatches
- users
- roles
tenant_id nunca debe venir del frontend.
Flujo correcto
req.tenant = {\n id: user.tenant_id,\n plan_id: user.plan_id,\n modules: ['inventory', 'quotes', 'dispatch']\n};
5. Usuarios, roles y permisos para suscriptores
Cada suscriptor debe poder ingresar a su cuenta y administrar sus propios usuarios internos, roles y permisos. Esta funcionalidad debe estar completamente aislada por tenant.
Módulos involucrados
users
Gestión de usuarios internos del suscriptor: crear, invitar, editar, bloquear, reactivar, asignar rol y consultar accesos.
roles
Gestión de perfiles y permisos por tenant. Permite definir qué puede hacer cada usuario en la aplicación.
Roles base sugeridos
| Rol | Uso recomendado |
|---|---|
| owner | Propietario de la cuenta. Control total del tenant, suscripción, usuarios, roles y configuración. |
| admin | Administrador interno. Gestiona operación, usuarios y configuración autorizada. |
| supervisor | Supervisa inventario, pedidos, fabricación, picking y despacho. |
| sales | Crea clientes, cotizaciones y pedidos. |
| warehouse_manager | Administra almacenes, ubicaciones, stock y ajustes autorizados. |
| inventory_operator | Registra ingresos, salidas, transferencias y movimientos permitidos. |
| picking_operator | Prepara pedidos y confirma picking. |
| dispatch_operator | Gestiona rutas, despachos, evidencias y entregas. |
| manufacturing_operator | Gestiona órdenes de fabricación y avance de operaciones. |
| accounting_viewer | Consulta reportes comerciales y documentos sin modificar operación. |
| readonly | Solo lectura. |
Permisos iniciales
Formato recomendado: module.action.
- products.view
- products.create
- products.update
- products.delete
- inventory.view
- inventory.adjust
- inventory.transfer
- quotes.create
- quotes.approve
- orders.confirm
- purchases.create
- manufacturing.start
- manufacturing.finish
- picking.prepare
- dispatch.close
- reports.view
- users.manage
- roles.manage
- settings.manage
Restricción por plan
Un usuario no puede recibir permisos sobre módulos que el plan del tenant no tenga habilitados.
Si el plan no incluye fabricación, ningún rol debe poder usar permisos manufacturing.*.
Flujo para invitar usuario
Flujo de login con roles
Tablas sugeridas
CREATE TABLE users (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
tenant_id BIGINT NOT NULL,
name VARCHAR(160) NOT NULL,
email VARCHAR(190) NOT NULL,
password_hash VARCHAR(255) NOT NULL,
status ENUM('invited','active','blocked','disabled') DEFAULT 'active',
last_login_at DATETIME NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NULL,
deleted_at DATETIME NULL,
UNIQUE KEY uq_users_tenant_email (tenant_id, email),
INDEX idx_users_tenant (tenant_id)
);
CREATE TABLE roles (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
tenant_id BIGINT NOT NULL,
code VARCHAR(80) NOT NULL,
name VARCHAR(120) NOT NULL,
description VARCHAR(255) NULL,
is_system TINYINT(1) DEFAULT 0,
is_active TINYINT(1) DEFAULT 1,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY uq_roles_tenant_code (tenant_id, code),
INDEX idx_roles_tenant (tenant_id)
);
CREATE TABLE permissions (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
module_code VARCHAR(80) NOT NULL,
action_code VARCHAR(80) NOT NULL,
permission_key VARCHAR(160) NOT NULL,
description VARCHAR(255) NULL,
UNIQUE KEY uq_permissions_key (permission_key)
);
CREATE TABLE role_permissions (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
tenant_id BIGINT NOT NULL,
role_id BIGINT NOT NULL,
permission_id BIGINT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY uq_role_permission (tenant_id, role_id, permission_id),
INDEX idx_role_permissions_tenant (tenant_id)
);
CREATE TABLE user_roles (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
tenant_id BIGINT NOT NULL,
user_id BIGINT NOT NULL,
role_id BIGINT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY uq_user_role (tenant_id, user_id, role_id),
INDEX idx_user_roles_tenant (tenant_id)
);
CREATE TABLE user_invitations (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
tenant_id BIGINT NOT NULL,
email VARCHAR(190) NOT NULL,
token_hash VARCHAR(255) NOT NULL,
role_id BIGINT NULL,
status ENUM('pending','accepted','expired','cancelled') DEFAULT 'pending',
expires_at DATETIME NOT NULL,
created_by BIGINT NOT NULL,
accepted_at DATETIME NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
INDEX idx_user_invitations_tenant (tenant_id),
INDEX idx_user_invitations_email (tenant_id, email)
);
Auditoría obligatoria
- Crear usuario.
- Invitar usuario.
- Cambiar rol.
- Bloquear usuario.
- Reactivar usuario.
- Eliminar usuario.
- Cambiar password.
- Inicio de sesión.
- Cierre de sesión.
- Login fallido.
6. Sin Redis al inicio: alternativa simple
Como empezarás en servidor compartido sin Redis, usa MySQL para funciones operativas básicas.
- Sesiones
- Revocación de tokens
- Rate limit básico
- Cola simple de tareas
- Auditoría
- Jobs pendientes
Tablas recomendadas
user_sessions\nrevoked_tokens\nrate_limit_logs\napp_jobs\naudit_logs
Evolución futura
| Función inicial con MySQL | Evolución futura con Redis |
|---|---|
| user_sessions | Redis sessions |
| revoked_tokens | Redis blacklist |
| rate_limit_logs | Redis rate limit |
| app_jobs | BullMQ |
| locks por DB | Redis locks |
| cache simple por tabla | Redis cache |
7. Modelo base de productos
El producto debe tener un campo principal: control_type.
simple\nserial\nlot\nexpiration\nlot_expiration\nvariant\npack\nformula\nmanufactured\nmixed
Tablas principales
products\nproduct_variants\nproduct_pack_items\nproduct_formula_items\nproduct_control_rules\nproduct_units\nproduct_categories\nproduct_brands
Ejemplo de tabla products
CREATE TABLE products (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
tenant_id BIGINT NOT NULL,
sku VARCHAR(80) NOT NULL,
name VARCHAR(180) NOT NULL,
description TEXT NULL,
control_type ENUM(
'simple',
'serial',
'lot',
'expiration',
'lot_expiration',
'variant',
'pack',
'formula',
'manufactured',
'mixed'
) NOT NULL DEFAULT 'simple',
base_unit_id BIGINT NULL,
category_id BIGINT NULL,
brand_id BIGINT NULL,
has_variants TINYINT(1) DEFAULT 0,
has_serial_control TINYINT(1) DEFAULT 0,
has_lot_control TINYINT(1) DEFAULT 0,
has_expiration_control TINYINT(1) DEFAULT 0,
is_pack TINYINT(1) DEFAULT 0,
is_formula TINYINT(1) DEFAULT 0,
is_manufactured TINYINT(1) DEFAULT 0,
cost_price DECIMAL(15,4) DEFAULT 0,
sale_price DECIMAL(15,4) DEFAULT 0,
currency_id BIGINT NULL,
tax_profile_id BIGINT NULL,
is_active TINYINT(1) DEFAULT 1,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NULL,
UNIQUE KEY uq_products_tenant_sku (tenant_id, sku),
INDEX idx_products_tenant (tenant_id),
INDEX idx_products_control_type (tenant_id, control_type)
);
8. Inventario multi-almacén y ubicaciones
Debes separar almacén, zona, rack, columna, nivel, posición, stock y movimiento kardex.
Tablas sugeridas
warehouses\nwarehouse_zones\nwarehouse_locations\ninventory_stock\ninventory_movements\ninventory_lots\ninventory_serials\ninventory_expirations\nstock_reservations
Ubicación logística
Almacén Lima\n└── Zona A\n └── Rack R01\n └── Columna C03\n └── Nivel N02\n └── Posición P05
Tabla sugerida
CREATE TABLE warehouse_locations (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
tenant_id BIGINT NOT NULL,
warehouse_id BIGINT NOT NULL,
zone_code VARCHAR(50) NULL,
rack_code VARCHAR(50) NULL,
column_code VARCHAR(50) NULL,
level_code VARCHAR(50) NULL,
position_code VARCHAR(50) NULL,
full_code VARCHAR(150) NOT NULL,
max_weight DECIMAL(15,4) NULL,
max_volume DECIMAL(15,4) NULL,
is_active TINYINT(1) DEFAULT 1,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY uq_location_code (tenant_id, warehouse_id, full_code),
INDEX idx_location_tenant (tenant_id)
);
9. Flujo operativo principal
Estados sugeridos
Cotización
draft\nsent\naccepted\nrejected\nexpired\nconverted_to_order
Pedido
draft\nconfirmed\nwaiting_stock\nin_purchase\nin_manufacturing\nready_for_picking\npicking\npacked\ndispatched\ndelivered\ncancelled
Fabricación
planned\nin_cutting\nin_beveling\nin_stamping\nin_bending\nin_packaging\nfinished\ncancelled
Despacho
pending\nassigned_route\nin_transit\ndelivered\nfailed\nreturned
10. Módulo especializado para pernería y anclajes
Este módulo será clave para diferenciarte.
Debe permitir cotizar y controlar fabricación de anclajes considerando:
- Tipo de anclaje
- Material
- Diámetro
- Longitud
- Rosca
- Acabado
- Cantidad
- Merma
- Corte
- Biselado
- Estampado
- Doblez
- Galvanizado o acabado
- Empaque
- Despacho
Tablas sugeridas
anchor_quote_items\nmanufacturing_orders\nmanufacturing_order_items\nmanufacturing_operations\nmanufacturing_operation_logs\nproduct_formulas\nproduct_formula_items
Operaciones base
cutting\nbeveling\nthreading\nstamping\nbending\nwelding\nsurface_treatment\npackaging\nquality_control\ndispatch_preparation
Cálculo de cotización de anclaje
Costo de material\n+ Costo de merma\n+ Costo por operación\n+ Costo de empaque\n+ Costo de despacho\n+ Margen\n+ Impuesto si aplica\n= Precio final
11. Multi-moneda e impuestos
Debes tener configuración por tenant.
Tablas sugeridas
countries\ncurrencies\nexchange_rates\ntax_profiles\ntenant_tax_settings\ntenant_currency_settings\nprice_lists\nprice_list_items
Configuración importante por cliente
Moneda principal\nMoneda secundaria\nPaís\nTasa de impuesto\nLista de precios incluye impuesto: sí/no\nRedondeo de precios\nCantidad de decimales
| País | Configuración ejemplo |
|---|---|
| Perú | Moneda base: PEN. Impuesto: IGV 18%. Precios incluyen impuesto: Sí o No. |
| México | Moneda base: MXN. Impuesto: IVA 16%. Precios incluyen impuesto: Sí o No. |
12. PWA
Archivos necesarios
public/manifest.json\npublic/service-worker.js\npublic/offline.html\npublic/app/js/pwa.js
Funciones iniciales
- Instalable en escritorio y móvil.
- Página offline básica.
- Cache de assets.
- Cache de vistas principales.
- Preparado para push notifications.
- Íconos por tamaño.
13. Archivos .md para guiar a CODEX/COMEX
Estos archivos deben crearse dentro de /docs. Incluyen todo el alcance técnico, reglas de desarrollo y el nuevo módulo de usuarios, roles y permisos.
00-PROJECT-VISION.mdver contenido
# Visión del Proyecto
## Nombre provisional
Logística SaaS Multi-Tenant
## Objetivo
Desarrollar una aplicación web SaaS especializada en gestión logística, inventario, almacenes, cotizaciones, pedidos, fabricación y despacho para empresas de habla hispana.
## Stack obligatorio
- Node.js
- Express
- MySQL
- EJS con template Phoenix
- PWA
- Servidor compartido al inicio
- Sin Redis en la primera etapa
## Principio principal
El sistema debe diferenciarse por manejar productos con distintos perfiles de control logístico:
- Simple
- Por número de serie
- Por lote
- Por vencimiento
- Por lote y vencimiento
- Con variantes
- Pack
- Compuesto por fórmula
- Fabricado
- Mixto
## Enfoque de desarrollo
El proyecto será desarrollado por un solo programador, por lo tanto:
- La estructura debe ser simple.
- Los módulos deben ser claros.
- Evitar sobreingeniería.
- Evitar microservicios al inicio.
- Mantener separación entre rutas, controladores, servicios, modelos y vistas.
## Mercado objetivo
Empresas importadoras, distribuidoras, mayoristas técnicos, almacenes, empresas de pernería, ferretería técnica, alimentos, medicinas, hardware, repuestos y productos con trazabilidad logística.
## Diferenciador
El sistema no solo registra stock. Debe entender cómo se controla cada producto y adaptar el flujo operativo según el tipo de producto.
01-ARCHITECTURE.mdver contenido
# Arquitectura General
## Patrón principal
Aplicación monolítica modular con Node.js + Express.
## Renderizado
Usar EJS para render server-side e integrar el template Phoenix.
## Base de datos
Usar MySQL con base de datos compartida para todos los tenants.
## Multi-tenancy
Todas las tablas operativas deben incluir tenant_id.
El tenant_id nunca debe venir del frontend.
El tenant_id se obtiene desde el usuario autenticado.
## Capas por módulo
Cada módulo debe seguir esta estructura:
- routes.js
- controller.js
- service.js
- model.js
- validator.js
## Responsabilidades
### Routes
Define rutas, middlewares y permisos.
### Controller
Recibe la solicitud HTTP y devuelve vista o JSON.
### Service
Contiene reglas de negocio.
### Model
Ejecuta consultas SQL parametrizadas.
### Validator
Valida entradas del usuario.
## Reglas
- No hacer SQL en controllers.
- No leer tenant_id desde formularios.
- No duplicar lógica de negocio en vistas.
- No colocar lógica sensible en el frontend.
- Todas las consultas operativas deben filtrar por tenant_id.
- Todas las operaciones críticas deben registrar auditoría.
## Preparación para crecimiento
En la primera etapa se usará MySQL para sesiones, revocación, jobs y rate limit básico.
En una etapa futura se podrá incorporar Redis para:
- Cache
- Sesiones
- Rate limit
- Colas
- Locks
02-MULTI-TENANCY.mdver contenido
# Multi-Tenancy y Seguridad
## Modelo elegido
Base de datos compartida con tenant_id en todas las tablas operativas.
## Regla crítica
El tenant_id nunca debe provenir del frontend, formularios, query params ni body.
## Resolución del tenant
El tenant se resuelve después del login usando la relación entre usuario y empresa tenant.
Flujo:
1. Usuario ingresa credenciales.
2. Se valida usuario.
3. Se obtiene tenant_id desde la tabla users.
4. Se valida que el tenant esté activo.
5. Se valida que la suscripción esté activa.
6. Se cargan rol y permisos.
7. Se genera sesión/JWT.
8. tenant_id queda disponible en req.tenant.
## Middleware obligatorio
Toda ruta protegida debe usar:
- auth.middleware.js
- tenant.middleware.js
- subscription.middleware.js
- permission.middleware.js cuando aplique
## Consultas SQL
Toda consulta sobre datos del cliente debe incluir:
WHERE tenant_id = ?
## Prohibido
- Aceptar tenant_id desde el frontend.
- Construir SQL con concatenación de strings.
- Mostrar datos de otro tenant.
- Ejecutar acciones sin validar permisos.
- Saltar auditoría en operaciones críticas.
## Auditoría
Registrar:
- tenant_id
- user_id
- acción
- módulo
- recurso afectado
- IP
- user agent
- fecha y hora
03-DATABASE-STANDARDS.mdver contenido
# Estándares de Base de Datos
## Motor
MySQL.
## Convenciones
- Tablas en plural: products, warehouses, orders.
- Campos en snake_case.
- Llaves primarias: id BIGINT AUTO_INCREMENT.
- Todas las tablas operativas deben tener tenant_id.
- Usar created_at, updated_at y deleted_at cuando aplique.
- Preferir soft delete para registros importantes.
## Campos base por tabla operativa
- id
- tenant_id
- created_at
- updated_at
- deleted_at
- is_active
## Índices obligatorios
Toda tabla con tenant_id debe tener índice por tenant_id.
Ejemplo:
INDEX idx_products_tenant (tenant_id)
Cuando aplique, usar índices compuestos:
UNIQUE KEY uq_products_tenant_sku (tenant_id, sku)
## Seguridad SQL
- Todas las consultas deben ser parametrizadas.
- No concatenar valores del usuario.
- Validar datos antes de llegar al modelo.
- Paginar listados grandes.
## Migraciones
Cada cambio estructural debe agregarse como archivo SQL dentro de:
src/database/migrations
Formato:
001_create_tenants.sql
002_create_users.sql
003_create_products.sql
## Seeds
Los datos iniciales deben ir en:
src/database/seeds
04-MODULES-SCOPE.mdver contenido
# Alcance de Módulos
## Módulos base
### Auth
Login, logout, sesiones, recuperación de contraseña y validación de usuario.
### Tenants
Registro de empresas cliente, datos fiscales, país, moneda y configuración general.
### Subscriptions
Planes, módulos habilitados, estado de suscripción y restricciones.
### Users
Usuarios por tenant, invitaciones, activación, bloqueo, cambio de rol y administración de acceso interno del suscriptor.
### Roles
Roles y permisos por tenant. Debe permitir que cada suscriptor cree perfiles como administrador, supervisor, vendedor, almacenero, operador de picking, despacho y consulta.
### Settings
Configuración de moneda, impuesto, idioma, listas de precios y preferencias.
### Customers
Clientes comerciales del tenant.
### Suppliers
Proveedores.
### Products
Catálogo de productos con perfil de control logístico.
### Warehouses
Almacenes y ubicaciones.
### Inventory
Stock, kardex, lotes, series, vencimientos y reservas.
### Quotes
Cotizaciones a clientes.
### Orders
Pedidos confirmados.
### Purchases
Órdenes de compra para abastecimiento.
### Manufacturing
Fabricación de productos y anclajes.
### Picking
Preparación de pedidos.
### Dispatch
Rutas, despachos, evidencias y cierre de entrega.
### Currencies
Monedas y tipos de cambio.
### Taxes
Configuración de impuestos a las ventas.
### Reports
Reportes operativos.
### PWA
Manifest, service worker, offline básico y preparación para push notifications.
## Regla de simplicidad
No crear módulos que no serán usados en la primera versión.
Cada módulo debe tener una finalidad concreta.
05-PRODUCT-CONTROL-MODEL.mdver contenido
# Modelo de Control de Productos
## Objetivo
Permitir que cada producto defina cómo debe ser controlado en inventario, ventas, compras, fabricación y despacho.
## Tipos de control
- simple
- serial
- lot
- expiration
- lot_expiration
- variant
- pack
- formula
- manufactured
- mixed
## Producto simple
Solo controla cantidad.
Ejemplo:
- Tornillo estándar
- Caja genérica
- Consumible simple
## Producto serializado
Cada unidad tiene número de serie único.
Ejemplo:
- Laptop
- Electrodoméstico
- Equipo electrónico
## Producto por lote
Control por lote de fabricación.
Ejemplo:
- Pernos
- Insumos industriales
- Productos químicos
## Producto con vencimiento
Control por fecha de vencimiento.
Ejemplo:
- Medicinas
- Alimentos
- Productos perecibles
## Producto con lote y vencimiento
Control combinado.
Ejemplo:
- Medicamentos
- Alimentos industriales
## Producto con variantes
Producto base con opciones.
Ejemplo:
- Color
- Talla
- Modelo
- Medida
- Acabado
## Pack
Producto comercial formado por varios productos.
Ejemplo:
- Kit de instalación
- Combo promocional
## Producto por fórmula
Producto compuesto que consume insumos según una receta o fórmula.
Ejemplo:
- Anclaje químico
- Mezcla
- Producto fabricado con componentes
## Producto fabricado
Producto que requiere proceso productivo.
Ejemplo:
- Anclaje cortado, biselado, doblado y empacado.
## Reglas
El sistema debe validar el control requerido antes de permitir movimientos de inventario.
Si el producto es serializado, no puede ingresar stock sin serie.
Si el producto usa lote, no puede ingresar stock sin lote.
Si el producto vence, no puede ingresar stock sin vencimiento.
Si el producto es pack, debe validar componentes.
Si el producto es fórmula, debe validar insumos.
06-INVENTORY-WORKFLOW.mdver contenido
# Flujo de Inventario
## Objetivo
Controlar stock multi-almacén, ubicaciones, kardex, lotes, series, vencimientos y reservas.
## Flujo de ingreso
1. Se registra compra, fabricación o ajuste.
2. Se identifica producto.
3. Se valida tipo de control.
4. Se registra lote, serie o vencimiento si corresponde.
5. Se asigna almacén y ubicación.
6. Se actualiza stock.
7. Se registra kardex.
8. Se registra auditoría.
## Flujo de salida
1. Se confirma pedido.
2. Se valida disponibilidad.
3. Se reserva stock.
4. Se genera picking.
5. Se confirma retiro físico.
6. Se descuenta stock.
7. Se registra kardex.
8. Se prepara despacho.
## Kardex
Todo movimiento debe registrar:
- tenant_id
- product_id
- warehouse_id
- location_id
- movement_type
- quantity
- unit_cost
- reference_type
- reference_id
- user_id
- created_at
## Tipos de movimiento
- purchase_in
- manufacturing_in
- sale_out
- transfer_in
- transfer_out
- adjustment_in
- adjustment_out
- return_in
- damaged_out
## Regla
Nunca modificar stock sin registrar kardex.
07-ANCHORS-MANUFACTURING.mdver contenido
# Módulo de Fabricación de Anclajes
## Objetivo
Permitir cotizar y controlar fabricación de anclajes y productos técnicos similares.
## Procesos considerados
- Corte
- Biselado
- Roscado
- Estampado
- Doblez
- Soldadura
- Tratamiento superficial
- Control de calidad
- Empaque
- Preparación para despacho
## Datos para cotizar
- Tipo de producto
- Material
- Diámetro
- Longitud
- Cantidad
- Unidad de medida
- Merma esperada
- Costo de material
- Costo por operación
- Costo de empaque
- Costo de despacho
- Margen
- Impuesto
## Fórmula general
Precio final =
Costo material
+ Costo merma
+ Costo operaciones
+ Costo empaque
+ Costo despacho
+ Margen
+ Impuesto si aplica
## Estados de fabricación
- planned
- in_cutting
- in_beveling
- in_threading
- in_stamping
- in_bending
- in_packaging
- quality_control
- finished
- cancelled
## Regla
Una fabricación debe poder consumir inventario de insumos y generar ingreso de producto terminado.
08-PHOENIX-UI-GUIDE.mdver contenido
# Guía de Interfaz con Template Phoenix
## Objetivo
Integrar el template Phoenix con EJS de forma ordenada y mantenible.
## Ubicación de assets
Los archivos originales del template deben colocarse en:
public/phoenix
Los estilos propios de la aplicación deben colocarse en:
public/app/css/custom.css
Los scripts propios deben colocarse en:
public/app/js
## Layouts
Usar layouts EJS:
- main.ejs para panel principal
- auth.ejs para login y registro
- blank.ejs para páginas especiales
## Partials
Usar partials para:
- head
- navbar
- sidebar
- footer
- breadcrumbs
- mensajes flash
## Reglas
- No modificar directamente archivos originales del template salvo necesidad.
- Personalizar desde custom.css.
- No duplicar sidebar en cada vista.
- No colocar lógica compleja en EJS.
- Las vistas solo deben mostrar datos preparados por el controller.
## Menú principal inicial
- Dashboard
- Clientes
- Proveedores
- Productos
- Almacenes
- Inventario
- Cotizaciones
- Pedidos
- Compras
- Fabricación
- Picking
- Despachos
- Reportes
- Configuración
- Usuarios
- Roles y permisos
09-PWA-GUIDE.mdver contenido
# Guía PWA
## Objetivo
Permitir que la aplicación sea instalable y tenga funcionamiento offline básico.
## Archivos requeridos
- public/manifest.json
- public/service-worker.js
- public/offline.html
- public/app/js/pwa.js
## Funciones iniciales
- Instalación en escritorio y móvil.
- Cache de assets principales.
- Página offline.
- Preparación para futuras notificaciones push.
## No incluir en primera etapa
- Inventario offline completo.
- Sincronización compleja.
- Conflictos de stock offline.
## Motivo
El inventario requiere consistencia fuerte. Permitir movimientos offline puede generar errores de stock si no existe una estrategia robusta de sincronización.
## Primera versión recomendada
- Login online.
- Operación online.
- Dashboard y páginas base cacheadas.
- Página offline informativa.
10-CODEX-INSTRUCTIONS.mdver contenido
# Instrucciones para CODEX/COMEX
## Rol esperado
Actuar como asistente de desarrollo para una aplicación SaaS logística multi-tenant construida con Node.js, Express, MySQL, EJS y template Phoenix.
## Reglas obligatorias
- No usar PHP.
- No usar frameworks frontend complejos.
- No usar Redis en la primera etapa.
- No crear microservicios.
- No omitir tenant_id en tablas operativas.
- No aceptar tenant_id desde frontend.
- No hacer SQL sin parámetros.
- No colocar lógica de negocio en vistas EJS.
- No crear archivos innecesarios.
- No permitir que un usuario administre usuarios de otro tenant.
- No permitir que un rol tenga permisos sobre módulos no incluidos en el plan activo del tenant.
## Estructura por módulo
Cada módulo debe seguir:
module.routes.js
module.controller.js
module.service.js
module.model.js
module.validator.js
## Comentario obligatorio al inicio de cada archivo
Cada archivo generado debe iniciar con un comentario que explique:
- Nombre del archivo.
- Módulo al que pertenece.
- Responsabilidad.
- Si maneja datos multi-tenant.
Ejemplo:
/**
* Archivo: products.service.js
* Módulo: Products
* Responsabilidad: Contiene la lógica de negocio para productos.
* Multi-tenant: Sí. Toda operación debe recibir tenant_id desde req.tenant.
*/
## Estilo de código
- Código claro.
- Funciones pequeñas.
- Comentarios útiles.
- Manejo de errores con asyncHandler.
- Validación antes de llegar al modelo.
- Consultas SQL parametrizadas.
- Paginación en listados.
## Prioridad de desarrollo
1. Base Express + EJS + Phoenix.
2. Conexión MySQL.
3. Auth.
4. Multi-tenancy.
5. Suscripciones.
6. Usuarios y roles.
7. Productos.
8. Almacenes.
9. Inventario.
10. Cotizaciones.
11. Pedidos.
12. Fabricación de anclajes.
13. Picking.
14. Despacho.
15. Reportes.
16. PWA.
## Criterio principal
Construir primero una versión funcional simple antes de agregar automatizaciones avanzadas.
11-ROADMAP.mdver contenido
# Roadmap de Desarrollo
## Etapa 1: Base técnica
- Crear proyecto Node.js.
- Configurar Express.
- Configurar EJS.
- Integrar template Phoenix.
- Configurar MySQL.
- Crear estructura modular.
- Crear layout principal.
- Crear dashboard inicial.
## Etapa 2: Seguridad y multi-tenancy
- Login.
- Logout.
- Sesiones.
- Middleware de autenticación.
- Middleware de tenant.
- Middleware de suscripción.
- Roles y permisos.
- Usuarios por tenant.
- Invitaciones de usuarios.
- Auditoría.
## Etapa 3: Configuración del tenant
- Datos de empresa.
- País.
- Moneda.
- Impuesto.
- Preferencia de precios con o sin impuesto.
- Idioma.
- Plan activo.
## Etapa 4: Catálogo de productos
- Categorías.
- Marcas.
- Unidades.
- Productos.
- Tipos de control.
- Variantes.
- Packs.
- Fórmulas.
## Etapa 5: Almacenes e inventario
- Almacenes.
- Ubicaciones.
- Stock.
- Kardex.
- Lotes.
- Series.
- Vencimientos.
- Reservas.
## Etapa 6: Clientes, proveedores y compras
- Clientes.
- Contactos.
- Proveedores.
- Órdenes de compra.
- Ingreso de mercadería.
## Etapa 7: Cotizaciones y pedidos
- Cotización.
- Conversión a pedido.
- Validación de stock.
- Reserva de inventario.
- Estado del pedido.
## Etapa 8: Fabricación de anclajes
- Cotización técnica.
- Fórmulas.
- Operaciones.
- Orden de fabricación.
- Consumo de insumos.
- Producto terminado.
## Etapa 9: Picking y despacho
- Lista de picking.
- Confirmación de preparación.
- Packing.
- Rutas.
- Despacho.
- Evidencia de entrega.
## Etapa 10: Reportes y PWA
- Reportes de stock.
- Reportes de rotación.
- Reportes de pedidos.
- Reportes de despacho.
- Manifest.
- Service worker.
- Offline básico.
12-USERS-ROLES-PERMISSIONS.mdver contenido
# Usuarios, Roles y Permisos por Suscriptor
## Objetivo
Permitir que cada suscriptor administre sus propios usuarios internos, roles y permisos, sin afectar ni visualizar usuarios de otros tenants.
## Principio multi-tenant
Cada usuario pertenece a un tenant.
Cada rol pertenece a un tenant.
Cada permiso asignado debe validarse dentro del tenant actual.
El tenant_id nunca debe venir del formulario.
## Tablas principales
- users
- roles
- permissions
- role_permissions
- user_roles
- user_invitations
- user_sessions
- password_resets
- audit_logs
## Roles base sugeridos
- owner
- admin
- supervisor
- sales
- warehouse_manager
- inventory_operator
- picking_operator
- dispatch_operator
- manufacturing_operator
- accounting_viewer
- readonly
## Criterio de roles
### owner
Usuario propietario de la cuenta del suscriptor.
Puede administrar empresa, suscripción, usuarios, roles, permisos, configuración y todos los módulos habilitados por el plan.
### admin
Administrador interno del tenant.
Puede administrar operaciones, usuarios y configuración, pero no necesariamente cambiar datos críticos de facturación o suscripción.
### supervisor
Supervisa operaciones, pedidos, inventario, fabricación, picking y despacho.
### sales
Crea clientes, cotizaciones y pedidos.
### warehouse_manager
Administra almacenes, ubicaciones, stock y ajustes autorizados.
### inventory_operator
Registra movimientos, ingresos, salidas y transferencias según permisos.
### picking_operator
Visualiza pedidos asignados, prepara picking y confirma preparación.
### dispatch_operator
Gestiona rutas, despachos, evidencias y entregas.
### manufacturing_operator
Gestiona órdenes de fabricación y avance de operaciones.
### accounting_viewer
Consulta reportes comerciales y documentos, sin modificar operación.
### readonly
Solo lectura.
## Matriz de permisos inicial
Los permisos deben tener formato:
module.action
Ejemplos:
- products.view
- products.create
- products.update
- products.delete
- inventory.view
- inventory.adjust
- inventory.transfer
- quotes.create
- quotes.approve
- orders.confirm
- purchases.create
- manufacturing.start
- manufacturing.finish
- picking.prepare
- dispatch.close
- reports.view
- users.manage
- roles.manage
- settings.manage
## Restricción por plan
Un usuario no puede recibir permisos sobre módulos que el plan del tenant no tenga habilitados.
Ejemplo:
Si el plan no incluye manufacturing, ningún rol del tenant debe poder usar:
- manufacturing.view
- manufacturing.create
- manufacturing.start
- manufacturing.finish
## Flujo para invitar usuario
1. Owner/Admin ingresa nombre, email y rol.
2. Sistema valida que el email no exista dentro del mismo tenant.
3. Sistema crea invitación con token temporal.
4. Usuario recibe enlace.
5. Usuario define password.
6. Sistema activa usuario.
7. Sistema registra auditoría.
## Flujo de login
1. Usuario ingresa email y password.
2. Se valida credencial.
3. Se valida usuario activo.
4. Se obtiene tenant_id desde users.
5. Se valida tenant activo.
6. Se valida suscripción activa.
7. Se cargan roles y permisos.
8. Se genera sesión/JWT.
9. Se registra acceso.
## Middleware requerido
- auth.middleware.js valida sesión/JWT.
- tenant.middleware.js resuelve tenant desde usuario autenticado.
- subscription.middleware.js valida plan activo y módulos habilitados.
- permission.middleware.js valida permisos específicos por ruta.
- audit.middleware.js registra acciones sensibles.
## Regla crítica
La gestión de usuarios debe estar completamente aislada por tenant.
Un owner de un tenant no puede ver, crear, editar, bloquear ni eliminar usuarios de otro tenant.
## Auditoría obligatoria
Registrar cuando:
- Se crea usuario.
- Se invita usuario.
- Se cambia rol.
- Se bloquea usuario.
- Se reactiva usuario.
- Se elimina usuario.
- Se cambia password.
- Se inicia sesión.
- Se cierra sesión.
- Se falla login.
14. Plan de implementación recomendado
Fase 1 — Base mínima funcional
Objetivo: tener la aplicación corriendo con Phoenix, login y dashboard.
app.js\nserver.js\nconnection.js\nlayouts EJS\npartials EJS\nlogin\ndashboard\nmiddleware de errores\nmiddleware auth básico
No empieces por inventario. Primero necesitas una base sólida.
Fase 2 — Multi-tenant real
tenants\nusers\nroles\npermissions\nrole_permissions\nuser_roles\nuser_invitations\nsubscriptions\nplans\nplan_modules\naudit_logs
- Un usuario pertenece a un tenant.
- Un tenant tiene una suscripción.
- Una suscripción activa habilita módulos.
- Cada request protegida debe tener
req.tenant. - Roles y permisos deben validarse por tenant.
Fase 3 — Configuración comercial del tenant
countries\ncurrencies\nexchange_rates\ntax_profiles\ntenant_settings\nprice_lists
El cliente debe poder definir país, moneda principal, impuesto, precios con o sin impuesto, idioma, decimales y redondeo.
Fase 4 — Productos
Este será el núcleo diferencial.
1. Producto simple\n2. Producto con variantes\n3. Producto con lote\n4. Producto con vencimiento\n5. Producto serializado\n6. Pack\n7. Fórmula\n8. Fabricado\n9. Control mixto
No intentes implementar todos los controles en la primera pantalla. Usa pestañas o secciones.
Datos generales\nControl logístico\nPrecios\nVariantes\nPack / Fórmula\nInventario
Fase 5 — Almacenes
warehouses\nwarehouse_zones\nwarehouse_locations
Primera versión: almacén, código de ubicación, descripción y estado. Luego agregas rack, columna, nivel y posición.
Fase 6 — Inventario
inventory_stock\ninventory_movements\ninventory_lots\ninventory_serials\nstock_reservations
Ingreso\nSalida\nAjuste\nTransferencia\nReserva\nLiberación de reserva
Fase 7 — Cotización y pedido
quotes\nquote_items\norders\norder_items
Fase 8 — Compras y abastecimiento
purchase_orders\npurchase_order_items\ngoods_receipts\ngoods_receipt_items
Debe cubrir pedido de compra, recepción, ingreso a inventario y registro de lote, serie o vencimiento si aplica.
Fase 9 — Fabricación de anclajes
manufacturing_orders\nmanufacturing_order_items\nmanufacturing_operations\nmanufacturing_operation_logs\nproduct_formulas\nproduct_formula_items\nanchor_quote_items
Primera versión: cotizar anclaje, crear orden de fabricación, registrar etapas, consumir insumos e ingresar producto terminado.
Fase 10 — Picking y despacho
picking_lists\npicking_items\ndispatches\ndispatch_items\ndispatch_routes\ndelivery_evidence
Fase 11 — PWA
- manifest.json
- service-worker.js
- offline.html
- pwa.js
Primera meta: la app se puede instalar y muestra una página offline.
15. MVP recomendado
Para monetizar antes, no intentes cubrir todo desde el inicio.
MVP 1
Login\nMulti-tenant\nSuscripción básica\nUsuarios\nRoles simples\nClientes\nProveedores\nProductos\nTipos de control logístico\nAlmacenes\nUbicaciones\nStock\nKardex\nCotizaciones\nPedidos\nPWA básica
MVP 2
Compras\nReservas de stock\nPicking\nDespacho\nReportes
MVP 3
Fabricación de anclajes\nFórmulas\nEtapas productivas\nCosteo avanzado
MVP 4
Notificaciones push\nAPI pública\nIntegraciones\nDashboards avanzados\nRedis\nColas\nWorkers
16. Recomendación final de orden real
No desarrolles por módulos visibles primero. Desarrolla por dependencia técnica.
1. Base Express + EJS + Phoenix\n2. MySQL + migraciones\n3. Auth\n4. Tenant middleware\n5. Suscripciones\n6. Usuarios / roles\n7. Configuración del tenant\n8. Productos\n9. Almacenes\n10. Inventario\n11. Clientes / proveedores\n12. Cotizaciones\n13. Pedidos\n14. Compras\n15. Picking\n16. Despacho\n17. Fabricación de anclajes\n18. Reportes\n19. PWA
Ese será el punto que diferencie la aplicación frente a sistemas más genéricos.