Mejoras de sesion: estabilizacion, IA, Nexus Yonke y marketplace B2B
Some checks failed
CI / lint-and-test (3.11) (push) Has been cancelled
CI / lint-and-test (3.13) (push) Has been cancelled

- F0 blindaje: Redis/Celery, pg_hba sin trust LAN, secretos a env 600, backups, webhook auth, jobs muertos
- F1 caja: bugs POS, reembolsos al corte, apartados, CFDI, topes de descuento en cotizacion/apartado
- F2/F7 IA de catalogo: autocategorizacion, dedup de SKUs con embeddings, OCR de facturas, descripciones, claves SAT, limpieza de fitment
- F3 IA en el flujo: vision Yonke, preguntas MeLi, venta cruzada, anomalias, sinonimos, busqueda semantica (rerank/embeddings)
- F4/F8 escala y cartera: /metrics+Prometheus+Grafana, pool, score de credito, churn, metricas multi-tenant
- Nexus Yonke (M1-M6): modelo de datos 1-de-1, alta por donador, vitrina publica, MeLi usado, consignacion, garantia por dias, reportes, etiquetas
- Marketplace B2B entre yonkes (catalogo + pedidos cross-tenant)
- Seguridad: auth en /api/admin/* (35 endpoints), alertas por tenant
- Migraciones v4.27/v4.28; timers expire-demos y rollup-metrics
This commit is contained in:
2026-10-12 00:57:31 +00:00
parent f2d4558b80
commit a386ca5b4a
165 changed files with 31313 additions and 2203 deletions

View File

@@ -0,0 +1,106 @@
# Auditoría #2 — Mejoras y IA no conversacional (post F0–F4)
> **Fecha:** 11-oct-2026 · **Base:** 5 investigaciones nuevas con evidencia en `archivo:línea`, SQL real y estado del host.
> **Contexto:** segunda pasada **sobre el estado ya mejorado** (F0–F4 hechos). Busca la capa que falta, incluidas **regresiones** y **puntos ciegos** de la primera pasada.
---
## 0. Resumen ejecutivo
La primera pasada dejó una base sólida, pero esta segunda encontró **regresiones y puntos ciegos**:
**Corregido YA en esta pasada:**
1. **Redis caído otra vez** (18:31 UTC): `redis.conf` hacía `bind 127.0.0.1 172.17.0.1`; si `docker0` no está arriba, **Redis muere en bucle** ("Cannot assign requested address") y con él **todo Celery** (fitment, publicación MeLi en lote, webhook). → Arreglado (`bind 127.0.0.1 ::1`) + `vm.overcommit_memory=1` + `reset-failed`; Celery vivo.
2. **30 de 35 endpoints `/api/admin/*` SIN auth** (solo `tenants*`/`users*` la tenían): `DELETE /api/admin/parts`, `POST /api/admin/import/<type>`, `upload-image`, `export/<type>`… expuestos. → Guard global `before_request` que exige token **ADMIN** en **toda** la superficie; verificado 401.
**Lo demás que falta** (priorizado):
- **MeLi sigue "inerte"**: 52 publicaciones de Rached con `inventory_id=NULL` (0/52), 31 órdenes pagadas sin convertir, `module_marketplace=false`, sync congelado desde el 11-jun, 0 imágenes. No es la API: es el **mapeo SKU→inventario + imágenes**.
- **Template de tenant congelado en 32 tablas** (un tenant real tiene ~91): funciona solo porque el alta aplica v1.1→v4.27 sobre un template *desactualizado* → frágil.
- **Flags de módulo inconsistentes** (`*_enabled` en dashboard vs `module_*` en POS): activar MercadoLibre/WhatsApp en el panel **no** se refleja en el POS.
- **Yonke construido y vacío**: sin flag de módulo, sin link de navegación, sin plan asignable, 0 piezas.
- **Lealtad sin cerrar el ciclo** (acumula pero no se puede canjear con descuento real).
- **Backups**: sin offsite, sin retención (7.2 GB), **sin alerta de backup**; y `expire_demos.py` no está cableado a ningún timer.
- **Reset de demo no limpia PII** (clientes/conversaciones quedan).
- **La IA de embeddings está construida pero SIN usar**: `semantic_search.embed()/find_similar()` **no tienen un solo caller** → es la palanca más barata para media docena de mejoras.
---
## 1. Regresiones / puntos ciegos operativos (con evidencia)
| # | Hallazgo | Evidencia | Estado |
|---|---|---|---|
| 1 | **Redis muere por `bind` a docker0** | `redis-server.log:847` `Cannot assign requested address 172.17.0.1`; `redis.conf:88` | ✅ arreglado |
| 2 | **32 endpoints `/api/admin/*` sin auth** | `dashboard/server.py` (35 rutas, 3 con ADMIN) | ✅ arreglado (guard global) |
| 3 | **Admin de catálogo roto (500)** | `/api/admin/stats`,`/groups` → 500 (tablas `parts`/`part_categories` retiradas, `server.py:2716-2743`) | pendiente |
| 4 | **Backups Oct 2–10 inexistentes** + sin offsite + sin retención + **sin alerta de backup** | `backups/`; `BACKUP_S3_BUCKET` sin set | parcial (timer ya corre) |
| 5 | **`expire_demos.py` sin timer** | grep `systemd/`=0 | pendiente |
| 6 | **Template congelado (32 tablas) + drift** (`sale_payments` ausente) | `tenant_template` 32 vs tenant real 91 | pendiente |
| 7 | **Reset de demo deja PII** (no trunca `customers`,`whatsapp_messages`,`wa_*`,`audit_log`) | `manager/services/tenant_service.py:188-240` | pendiente |
| 8 | **14 DB `tenant_*` huérfanas** (6 con PII de prueba) vs 8 registradas | `pg_database` | pendiente |
| 9 | **Flags de módulo inconsistentes** | dashboard escribe `meli_enabled`, POS lee `module_meli` (`config_bp.py:1269`), manager usa `module_*` | pendiente |
| 10 | **Manager sin nginx/TLS/2FA; auditoría vacía; bug de comparación de versiones** (`"v4.9">="v4.10"`) | `manager/services/migration_service.py:82` | pendiente |
| 11 | **Sin TLS en el host, sin firewall; `5432`/`5003` en 0.0.0.0** | `ss -tlnp`; `iptables -S` ACCEPT | pendiente (decisión) |
| 12 | **`nexus` comparte rol en TODAS las DB; sin roles por tenant** | `has_database_privilege`=t | pendiente |
| 13 | **nginx del repo difiere del vivo** (falta bloque wildcard de tenants; sobra `nexus_quart`/`login2`) | `nginx/nexus-pos.conf` vs `/etc/nginx/...` | pendiente |
| 14 | **Sin analytics/tracking** en la cara pública (cero GA/GTM/pixel) | grep = 0 | pendiente |
| 15 | **`i18n.js` muerto** (fuerza `es`, cero `t()`), `*.min.js` desactualizados | `i18n.js:322` | pendiente |
| 16 | **Aislamiento multi-tenant por proceso**: 8 workers × N tenants × pool; sin PgBouncer; scans cross-tenant O(n) | `tenant_db.py`, `marketplace_external_bp.py:113` | pendiente |
| 17 | **Token del webhook de Alertmanager en claro en el repo** | `docker/alertmanager/alertmanager.yml` | pendiente |
---
## 2. MeLi / Yonke / WhatsApp — estado real y brechas
**MercadoLibre (Rached):** 52 listings, **`inventory_id` 0/52**, 31 órdenes `paid` sin convertir (`nexus_sale_id` NULL), `sync_errors` 52/52 (jun-11), `last_sync_at` 2026-06-11, 0 imágenes, `module_marketplace=false`. Bloqueo operativo = **mapear SKU→inventario + subir imágenes + encender el módulo**.
Ausente comercialmente (0 refs en código): **descripción de anuncio**, **facturación automática al convertir** (usa `_create_sale_manual` que salta el hook de CFDI/contabilidad), **persistir comisión/rentabilidad**, variaciones, `catalog_listing`/`price_to_win`, promociones, reputación, **SLA de preguntas** (4 sin responder, una de febrero), multi-cuenta, backoff de rate-limit (429).
**Yonke:** código completo (M1–M6), **0 datos**. Falta: flag `module_yonke` (no existe), link en navegación, plan asignable desde admin, tenant piloto, exposición pública de usados, categorías ML de usados, botón "publicar usado" en la UI.
**WhatsApp:** 8 bridges vivos + WA CRM (`:3010`) pero `module_whatsapp=false` en todos, WA CRM sin cablear (secret placeholder), **0 mensajes**; y el flujo WA **no escribe actividades en el CRM** (aunque sí factura pedidos).
---
## 3. IA no conversacional — la siguiente ola (con prontitud de datos)
### 3.1 La palanca infrautilizada
`pos/services/semantic_search.py` tiene `embed()` (4096 dims), `find_similar()`, `cosine_similarity()`, `rerank()` — **el rerank está integrado y el resto NO tiene un solo caller**. Es la base más barata para: matching, dedup, alternativas, limpieza de fitment, búsqueda semántica de bodega y respuestas de compatibilidad.
### 3.2 Priorizado por impacto/esfuerzo
| Prio | Oportunidad | Punto de integración | Datos (real) | Enfoque | Esfuerzo |
|---|---|---|---|---|---|
| **1** | **Ligar inventario→catálogo a escala** (habilita casi todo) | `sku_matcher.py:82,138`; endpoint `/inventory/match-catalog` | 355k items sin ligar; 17,246 catálogo; 406,393 xrefs | exact+interchange (ya) **+ embeddings** en el fallback de nombres (hoy `difflib`) | M |
| **2** | **Enriquecer catálogo: descripciones e imágenes** | `catalog_import_service.py:14`; `image_scraper.py:55` | 95% de `inventory.description` vacío; 0/17,246 `supplier_catalog` con imagen/desc; hay imágenes en los Excel de `data/` | LLM para descripción ES; cargar imágenes de proveedor + visión para validar | S–M |
| **3** | **"Alternativas / piezas similares" (feature muerta)** | `catalog_service._get_alternatives:1859`; `dashboard/server.py:1915` | `supplier_catalog_interchange` (406k) + catálogo 17k | reconstruir sobre interchange + `find_similar()` (hoy consulta tablas TecDoc retiradas → vacío) | M |
| **4** | **Anuncios MeLi: título + descripción + categoría** | `marketplace_external_service.build_item_payload:237`; `meli_service.search_categories:280` | nombre/marca/compat/donor | LLM (categoría vía `domain_discovery`) + descripción | S–M |
| **5** | **Claves SAT de productos** (`clave_prod_serv`/`clave_unidad` 100% vacías) | `cfdi_builder.py:178`; `cfdi_facturapi_builder.py:83` | nombre/categoría/marca de 170k | reglas + LLM → CFDI correcto | S |
| **6** | **Persistir comisión/rentabilidad por listing** | `marketplace_listings` (nuevas columnas); `_calculate_meli_net_price:387` (ya calcula, no guarda) | listings + costo | guardar fee/net/costo → margen por publicación | S |
| **7** | **Facturación automática al convertir orden MeLi** | `convert_order_to_sale`/`_create_sale_manual:1759` (salta `pos_engine` CFDI) | órdenes MeLi | enrutar por `process_sale` o encolar CFDI | S |
| **8** | **Extracción de pedidos desde WhatsApp (texto/voz/foto)** | `whatsapp_bp.py:376` (hoy menú rígido) | `whisper_local` (voz), `part_vision`/`invoice_ocr` (foto), catálogo | LLM/NER → cotización borrador | M–L |
| **9** | **Limpieza de fitment ruidoso** | `qwen_fitment.py:113,298`; `inventory_vehicle_compat.py:322` | 41.5M filas (estrada ~131/pieza; `qwen` 99.5%) | apagar `qwen` por defecto en bulk-import + scorear ruido con embeddings/rerank | M |
| **10** | **Búsqueda semántica de bodega** (150,778 items, multi-vendedor) | `peer_service`, `catalog_service.get_bodega_availability:2562` | 150k con nombre/SKU | embeddings + rerank (offline) | M |
| **11** | **Métricas de negocio por tenant + anomalías multi-tenant + salud de cartera** | master rollup diario; `anomaly_detector.py` (intra-tenant) | por definir | rollup + z-score entre tenants | M |
| **12** | **Dedup/normalización con embeddings** | `sku_matcher.match_name:82` | estrada: 6,121 grupos de `name` duplicado | `find_similar()` clustering | M |
### 3.3 No vale la pena todavía (cold-start honesto)
- **Forecast de demanda por SKU, elasticidad/precios, predicción de quiebre, fraude/anomalías por SKU, churn/scoring por cliente**: hay **~70 líneas de venta en toda la plataforma** y **0 compras**. `cross_sell` estadístico y `anomaly_detector` se auto-marcan en `cold_start`. Dejar **diseñado, no invertir** hasta tener miles de transacciones por tenant.
- **IA de ops**: triage de logs con LLM y agrupación de alertas con ML = **overkill** (volumen KB/día, 1 receiver). Lo útil es **sin IA**: alerta de backup/celery/tenant caído y `predict_linear` para disco.
---
## 4. Roadmap propuesto
| Fase | Foco | Entregable verificable |
|---|---|---|
| **F5 — Cerrar lo crítico (2-3 días)** | Redis estable (hecho) · auth admin (hecho) · admin catálogo sin 500 · `expire_demos` a timer · unificar flags de módulo · reset de demo con PII · limpiar DB huérfanas · alerta de backup | 0 endpoint admin sin auth; módulos coherentes dashboard↔POS; alerta de backup llega |
| **F6 — MeLi de verdad (1 sem)** | Mapear los 52 listings → inventario · pipeline de imágenes · encender `module_marketplace` y `module_yonke` · publicar con descripción/categoría · persistir comisión · facturación automática al convertir | Publicar SKU con imagen desde el POS → vender en ML → orden convertida + CFDI encolado |
| **F7 — IA de catálogo (2 sem)** | Ligado masivo con embeddings · descripciones + imágenes · "alternativas/similares" funcional · SAT keys · limpieza de fitment | ≥70% de items ligados a catálogo; alternativas devuelven resultados; fitment por pieza < 20 filas |
| **F8 — Escala y cartera (2-3 sem)** | PgBouncer + pool · métricas de negocio por tenant + anomalías multi-tenant + salud de cartera · analytics en la cara pública · Yonke piloto · WA CRM por negocio · TLS/firewall/roles | panel de cartera; 30+ tenants sin agotar conexiones; 1 tenant Yonke en producción |
---
## 5. Métricas de éxito
- **Confiabilidad:** 0 servicios en bucle; backups diarios verificados + offsite; alertas que llegan.
- **Cierre:** 0 endpoints `/api/admin/*` sin auth; flags de módulo coherentes.
- **MeLi:** 100% de listings con `inventory_id`; >0 órdenes convertidas + facturadas; publicaciones con imagen y descripción.
- **IA de catálogo:** % items ligados a catálogo (0→≥70%); tiempo de alta de anuncio; búsquedas sin resultado.