# Nexus POS — Resumen de Fases Implementadas **Fecha:** 2026-06-11 **Versión DB:** v4.1 **Tests:** 73/73 pasando (pytest) **Commit:** `2b73c2c` --- ## FASE 1-2: Fundamentos (pre-existente) - ✅ CFDI 4.0 con Facturapi - ✅ VIN Decoder (NHTSA) - ✅ Lookup por placas mexicanas - ✅ Carrito unificado multi-bodega - ✅ Cotizaciones digitales → WhatsApp - ✅ Auth JWT + roles ## FASE 3: Multi-sucursal + Alertas + Garantías | Feature | Archivos | Endpoints | |---------|----------|-----------| | **Multi-sucursal** | `inventory_engine.py`, `inventory_bp.py` | `GET /pos/api/inventory/stock-by-branch`, `POST /pos/api/inventory/transfers`, `POST /pos/api/inventory/sync-prices` | | **Alertas de Reorden** | `reorder_engine.py` | `POST /pos/api/inventory/generate-alerts`, `GET /pos/api/inventory/reorder-alerts`, `PUT /pos/api/inventory/reorder-alerts/:id/acknowledge`, `PUT /pos/api/inventory/reorder-alerts/:id/resolve`, `GET /pos/api/inventory/reorder-suggest-po` | | **Garantías / RMA** | `warranty_engine.py`, `warranty_bp.py` | `POST /pos/api/warranties`, `GET /pos/api/warranties`, `GET /pos/api/warranties/:id`, `GET /pos/api/customers/:id/warranties`, `POST /pos/api/warranty-claims`, `PUT /pos/api/warranty-claims/:id/resolve`, `PUT /pos/api/warranty-claims/:id/close` | ## FASE 4: Infraestructura + Escalabilidad | Feature | Archivos | Infra | |---------|----------|-------| | **Redis Cache** | `redis_stock_cache.py`, `inventory_engine.py` | Redis 8.0.2, TTL 300s, fallback a PostgreSQL | | **Multi-moneda** | `currency.py`, `pos_engine.py`, `cfdi_builder.py` | MXN base, USD soporte, contabilidad siempre en MXN | | **Proveedores + POs** | `supplier_engine.py`, `supplier_bp.py` | 11 endpoints: CRUD proveedores + workflow PO completo | | **Meilisearch** | `meili_search.py`, `catalog_service.py`, `sync_meilisearch.py` | Docker, 1.5M+ partes indexadas, búsqueda 4ms | | **Metabase KPIs** | `setup_metabase.py`, `docker-compose.metabase.yml` | Docker v0.53, dashboard auto-generado | ## FASE 5: CRM + Service Orders + Imágenes | Feature | Archivos | Capacidades | |---------|----------|-------------| | **CRM Mejorado** | `crm_engine.py`, `crm_bp.py` | Activities timeline, tags de segmentación, loyalty program (bronze/silver/gold/platinum), analytics (LTV, churn risk, categorías favoritas) | | **Imágenes de Partes** | `image_service.py`, `image_bp.py` | Upload multipart/URL, resize 1200px, thumbnail 300x300, WebP, bulk import | | **Órdenes de Servicio** | `service_order_engine.py`, `service_order_bp.py` | Kanban: received→diagnosis→waiting_parts→repair→quality_check→ready→delivered, items (refacciones), labor (mano de obra), historial de status | | **WhatsApp** | `whatsapp_service.py`, `whatsapp_bp.py` | Webhook Baileys, AI chatbot, cotizaciones, voz, imágenes | | **Flotillas** | `fleet_bp.py` | CRUD vehículos, maintenance schedules, logs, alerts, stats | | **BNPL stub** | `bnpl_engine.py` | Arquitectura APLAZO/Kueski/Clip | | **ERP Sync stub** | `erp_sync_engine.py` | Arquitectura Aspel/Contpaqi/SAP/Odoo | ## FASE 6: Notificaciones + Ahorro + Logística + API Pública | Feature | Archivos | Capacidades | |---------|----------|-------------| | **Notificaciones** | `notification_engine.py`, `notification_bp.py` | Templates por evento+canal, dispatch automático (push/WhatsApp/email/in-app), logs con estados, eventos: low_stock, order_ready, maintenance_due, new_sale, po_received, reorder_alert, warranty_expiring | | **Reportes de Ahorro** | `savings_engine.py`, `savings_bp.py` | Campo `retail_price` en inventory, cálculo automático en checkout, reporte por cliente (LTV ahorro, desglose mensual), reporte global (top clientes, promedio por orden) | | **Logística + Tracking** | `logistics_engine.py`, `logistics_bp.py` | 6 couriers pre-cargados (DHL, FedEx, Estafeta, 99min, Uber, Pickup), envíos vinculados a ventas/SO/PO, tracking URL auto-generada, historial de estatus | | **API Pública** | `public_api_engine.py`, `public_api_bp.py` | API keys seguras (SHA-256), scopes (read/write/admin), rate limiting por minuto/día con headers, logging de requests, endpoints: `/api/v1/health`, `/api/v1/catalog/search`, `/api/v1/catalog/parts/:id` | ## FASE 7: Performance Optimización | Sub-fase | Archivos | Optimizaciones | |----------|----------|----------------| | **7a — Quick Wins Frontend** | `nginx/nexus-pos.conf`, `pos/templates/*.html`, `pos/static/js/catalog.js` | gzip nginx, `defer` en scripts, fix `innerHTML +=` (8 lugares), event delegation cart, AbortController, sessionStorage cache years/brands | | **7b — DB Performance** | `pos/tenant_db.py`, `pos/services/inventory_engine.py`, `pos/services/pos_engine.py`, `pos/migrations/v3.2_db_performance.sql` | Connection pooling (`psycopg2.pool`), tabla `inventory_stock_summary` + triggers O(1), fix N+1 `process_sale`, índices críticos | | **7c — Redis + Gthread** | `pos/services/catalog_service.py`, `pos/gunicorn.conf.py` | `_classify_cache` en Redis (hit 6%→80%), vehicle info cache en `smart_search()`, gunicorn `gthread` (4 workers × 4 threads) | | **7d — Lazy Load + Minify** | `pos/static/js/catalog.js`, `nginx/nexus-pos.conf`, `scripts/minify-assets.sh` | `loading="lazy"` en imágenes, minificación auto-serve vía nginx, cache warming script | | **7e — CSS Inline Extraction** | `scripts/extract-inline-css.py`, 28 templates HTML, 28 archivos `.css`/`.min.css` | CSS inline extraído de 15 templates POS + 13 templates Dashboard a archivos externos, minificación, nginx auto-serve | **Impacto acumulado FASE 7:** - Transferencia: -40–60% - TTI: -200–500ms - Stock lookups: O(n) → O(1) - Ventas 20 ítems: 21 queries → 1 query - Cache hit rate: 6% → 80%+ ## Opción C — Consolidación Técnica (COMPLETADA) | Item | Estado | Commit | |------|--------|--------| | **C1: MV `part_vehicle_preview`** | ✅ En producción, refresh automático vía systemd timer (03:00 UTC) | `f893391` | | **C2: Cache warming script** | ✅ Autónomo con auto-sudo fallback, args CLI | `f893391` | | **C3: CSS dinámico residual** | ✅ `sidebar.js` → `sidebar.css`, `pos-utils.js` → `common.css` | `042acd6` | | **C4: Load testing script** | ✅ `scripts/load_test.py` con `locust` | `042acd6` | | **C5: Docs audit** | ✅ `FASES_IMPLEMENTADAS.md`, `performance_audit_2026.md` | `042acd6` | ## Opción A — Arquitectura Avanzada (COMPLETADA) | Item | Estado | Commit | |------|--------|--------| | **A1: `orjson` como JSON provider** | ✅ Hereda `DefaultJSONProvider`, fix indent en `pos_bp.py` | `a1be8dd` | | **A2: Virtual scroll** | ✅ `inventory.js`, `customers.js`, `fleet.js` | `a1be8dd` | | **A3: Celery worker queue** | ✅ `celery_app.py`, `tasks.py`, `tasks_bp.py`, systemd service activo | `a1be8dd` | | **A4: Quart + asyncpg PoC** | ✅ `async_catalog.py` en puerto 5002, benchmark script | `a1be8dd` | | **A5: Particionamiento `vehicle_parts`** | ✅ Script `partition_vehicle_parts.py` listo (HASH 16 particiones, dry-run) | `a1be8dd` | ## IA por Voz — Chalán de Nexus (COMPLETADA) | Componente | Estado | |------------|--------| | **STT (Speech-to-Text)** | ✅ POS + Dashboard público, `es-MX`, auto-send, animación micrófono | | **TTS (Text-to-Speech)** | ✅ Botón 🔊 en burbujas de IA, `speechSynthesis`, preferencia guardada en `localStorage` | | **Cobertura templates POS** | ✅ 14/14 templates tienen chat widget | | **Dashboard público** | ✅ Chat público con voz completa (sin cámara) | ## QWEN 3.6 AI Vehicle Fitment (COMPLETADA) | Componente | Archivo | Descripción | |------------|---------|-------------| | **Servicio QWEN** | `pos/services/qwen_fitment.py` | Consulta API OpenAI-compatible (`qwen3.6`) con part_number + name + brand; parsea JSON robusto (vehicles/confidence/notes); valida contra `model_year_engine` | | **Integración Inventario** | `pos/blueprints/inventory_bp.py` | `create_item()` llama QWEN después de TecDoc auto-match; inserta en `inventory_vehicle_compat` con `source='qwen_ai'` | | **UI** | `pos/static/js/inventory.js`, `pos/templates/inventory.html` | Toast muestra count de vehículos asignados por IA; tabla de compatibilidad muestra columna "Origen" | | **Retry / Fallback** | `qwen_fitment.py` | 3 reintentos ante respuesta vacía; fallback sin filtro de motor (descripciones de motor rara vez coinciden entre QWEN y TecDB); búsqueda parcial de modelo (`%Corolla%`) para nombres TecDoc | **Flujo:** 1. Usuario crea ítem de inventario (part_number, name, brand) 2. TecDoc auto-match ejecuta primero (si hay coincidencia exacta) 3. QWEN 3.6 recibe los datos y devuelve lista de vehículos compatibles en JSON 4. Cada vehículo se busca en la DB maestra (fuzzy match por modelo, fallback sin motor) 5. Los `model_year_engine_id` válidos se insertan en `inventory_vehicle_compat` con `source='qwen_ai'` 6. Frontend muestra toast: "27 vehículo(s) asignado(s) por IA" **Fail-safe:** Si QWEN no está configurado o la API falla, el ítem se crea normalmente; la asignación de vehículos se omite silenciosamente. --- ## Infraestructura Desplegada | Servicio | Versión | Puerto | Estado | |----------|---------|--------|--------| | PostgreSQL | 17 | 5432 | ✅ Optimizado (8GB shared_buffers, 64MB work_mem, 8GB max_wal_size) | | Redis | 8.0.2 | 6379 | ✅ Stock cache + classify cache | | Meilisearch | v1.12 | 7700 | ✅ 1,546,976 documentos | | Metabase | v0.53 | 3000 | ✅ Dashboard ID 2 | | Nginx | — | 80/443 | ✅ gzip, cache 6M, auto-serve .min | | Gunicorn POS | — | 5001 | ✅ systemd `nexus-pos.service`, gthread 4×4 | | Gunicorn Dashboard | — | 5000 | ✅ systemd `nexus.service` | | Quart Catalog | — | 5002 | ✅ systemd `nexus-quart.service`, hypercorn | | Celery | — | — | ✅ 4 prefork workers, broker redis://localhost:6379/1 | | Prometheus | v2.51 | 9090 | ✅ Docker, node/postgres/redis exporters | | Grafana | v10.4 | 3001 | ✅ Docker, auto-provisioned Prometheus datasource | --- ## Variables de Entorno Requeridas ```bash # Base MASTER_DB_URL=postgresql://user:pass@host/nexus_autoparts TENANT_DB_URL_TEMPLATE=postgresql://user:pass@host/{db_name} POS_JWT_SECRET=<32+ bytes hex> # Redis REDIS_URL=redis://localhost:6379/0 REDIS_ENABLED=true REDIS_STOCK_TTL=300 # Meilisearch MEILI_URL=http://localhost:7700 MEILI_API_KEY=nexus-master-key-change-me MEILI_ENABLED=true # Multi-moneda DEFAULT_CURRENCY=MXN EXCHANGE_RATE_USD_MXN=17.5 # WhatsApp (opcional) WHATSAPP_BRIDGE_URL=http://localhost:21465 WHATSAPP_BRIDGE_KEY= # AI (opcional) OPENROUTER_API_KEY= # QWEN AI Fitment (opcional) QWEN_API_URL=https://api.nan.builders/v1 QWEN_API_KEY= QWEN_MODEL=qwen3.6 # Metabase (opcional) METABASE_DB_PASS= METABASE_URL=http://localhost:3000 ``` --- ## ✅ Completados recientemente | # | Mejora | Fecha | Commit | |---|--------|-------|--------| | — | **Particionar `vehicle_parts` en producción** | 2026-04-26 | `f24f25e` | | — | **Quart async catalog en producción** | 2026-04-26 | `b829e4f` | | — | **Arreglar `scripts/minify-assets.sh`** | 2026-04-26 | `b829e4f` | | — | **Dashboard outage fix (env vars + static files)** | 2026-04-26 | `27cb4ee` | | — | **IA por Voz (STT + TTS) en POS y Dashboard** | 2026-04-26 | `afb3b24` | | — | **Fix chat.js null reference (`chatTtsToggle`)** | 2026-04-29 | `44c3a6c` | | — | **Optimizar PostgreSQL config + restart** | 2026-04-29 | — | | — | **Cache warming systemd timer** | 2026-04-29 | `c766571` | | — | **Monitoreo Prometheus + Grafana** | 2026-04-29 | `4b3b0f8` | | — | **PWA install prompt** | 2026-04-29 | `3b8224d` | | — | **Playwright E2E tests** | 2026-04-29 | `c4db5e7` | | — | **Dashboard in-app charts** | 2026-04-29 | `12989e3` | | — | **Stubs BNPL / ERP / WhatsApp Cloud / Supplier Portal** | 2026-04-29 | `2cfe4b3` | | — | **nexus-pos.service systemd** | 2026-04-29 | `c766571` | | — | **QWEN 3.6 AI Vehicle Fitment** | 2026-04-29 | `623c57b` | ## FASE 7: Precios de Proveedor + Multi-sucursal + Factura Global **Commit:** `2b73c2c` (2026-06-11) ### 7.1 Lista de Precios de Proveedor | Feature | Archivos | Capacidades | |---------|----------|-------------| | **Precios por proveedor** | `supplier_catalog_prices` (master DB) | Precio, moneda, vigencia (effective_from/to), activo/inactivo | | **Upload masivo** | `supplier_catalog_bp.py` | CSV/Excel con supplier_name, sku, price, currency | | **Visualización** | `catalog.js`, `catalog_service.py` | `supplier_price` + `supplier_currency` en tarjetas y búsqueda | | **Endpoints** | `supplier_catalog_bp.py` | `GET/POST/PUT/DELETE /pos/api/supplier-catalog/prices/*` | ### 7.2 Multi-sucursal Completo | Feature | Archivos | Capacidades | |---------|----------|-------------| | **Schema migration v4.0** | `v4.0_multi_branch.sql` | `inventory.branch_id=NULL` (catálogo compartido), tabla `inventory_stock` | | **Datos fiscales por sucursal** | `branches` (tenant DB) | `rfc`, `razon_social`, `regimen_fiscal`, `codigo_postal`, `serie_cfdi`, `folio_inicial`, `licencia_fiscal`, `certificado_pem`, `llave_pem`, `is_main` | | **Sincronización de stock** | Trigger `trg_update_inventory_stock` | `inventory_operations` → `inventory_stock` automático | | **Backend branches** | `config_bp.py` | CRUD completo con campos fiscales, validación de única sucursal `is_main` | | **Backend inventario** | `inventory_bp.py`, `inventory_engine.py`, `pos_bp.py` | Stock por sucursal vía `inventory_stock`, catálogo compartido, verificación de stock en POS | | **Backend facturación** | `invoicing_bp.py` | CFDI usa datos fiscales de la sucursal de la venta (`_get_issuer_config`) | | **Frontend config** | `config.html`, `config.js` | Modal de sucursal expandido con todos los campos fiscales, edición inline | ### 7.3 Factura Global Mensual | Feature | Archivos | Capacidades | |---------|----------|-------------| | **Schema migration v4.1** | `v4.1_global_invoice.sql` | `global_invoice_sales`, `sales.global_invoiced_at` | | **Builder CFDI global** | `cfdi_builder.py` | `build_global_invoice_xml()` con `InformacionGlobal` SAT-compliant (`Periodicidad="04"`) | | **Servicio** | `global_invoice.py` | Agrupa ventas PUE ≤$2,000 sin CFDI individual del mes/año solicitado | | **Endpoints** | `invoicing_bp.py` | `POST /global-invoice`, `GET /global-invoice/`, `GET /global-invoice/eligible-sales` | | **Frontend** | `invoicing.html`, `invoicing.js` | Botón "Factura Global" con modal de año/mes + vista previa de ventas elegibles | --- ## Mejoras Pendientes (Roadmap Actualizado) ### 🔴 Crítico — Deuda Técnica *Sin items críticos pendientes.* ### 🟠 Alto — Features de Negocio (requieren integración con terceros) | # | Mejora | Descripción | Esfuerzo | Notas | |---|--------|-------------|----------|-------| | 1 | **WhatsApp Business API (Meta Cloud) real** | Migrar de Baileys a Meta Cloud API. Requiere verificación de cuenta Meta, Business Manager, número de teléfono verificado. | 2-3 semanas | Stub creado (`whatsapp_cloud_bp.py`) | | 2 | **BNPL real** | Integrar APLAZO/Kueski/Clip con credenciales de sandbox/producción. | 2 semanas | Stub creado (`bnpl_bp.py`) | | 3 | **ERP Sync real** | Conectar Aspel/CONTPAQi/SAP/Odoo vía API o archivos de intercambio. | 2-3 semanas | Stub creado (`erp_bp.py`) | | 4 | **Mercado Libre / Amazon sync** | Publicar inventario de bodegas en marketplaces. API de ML Seller + Amazon SP-API. | 3 semanas | En progreso (ML Seller API vinculada) | ### 🟡 Medio — Diferenciadores | # | Mejora | Descripción | Esfuerzo | |---|--------|-------------|----------| | 5 | **App móvil nativa (Capacitor)** | Wrap del POS como app iOS/Android. Camera nativa, push notifications, biometrics. | 3-4 semanas | | 6 | **Crédito basado en comportamiento** | Evaluación automática de línea de crédito por historial de pagos del cliente. | 2 semanas | | 7 | **Programa de embajadores** | Referidos con recompensas, tracking de conversiones. | 1 semana | ### 🟢 Bajo — Polish | # | Mejora | Descripción | |---|--------|-------------| | 8 | **Backup automatizado** | Último backup 2026-04-27. Automatizar con cron + S3/GCS. | | 9 | **Grafana dashboards predefinidos** | Actualmente solo datasource auto-provisionado. Falta crear dashboards JSON para PostgreSQL, Redis, Gunicorn. | | 10 | **Alertas Prometheus** | Alertmanager para notificaciones cuando PostgreSQL, Redis o Gunicorn fallen. | | 11 | **Tests E2E adicionales** | Playwright: checkout, búsqueda de catálogo, flujo de inventario. | | 12 | **Service Worker mejorado** | Background sync real para carrito offline, notificaciones push. | --- ## Backup Último backup: `/home/Autopartes/backups/nexus_backup_20260427_045859.tar.gz` (1.3 GB)