¿Lista el MVP para lanzar y empezar a monetizar hoy?
Evaluación integral de las 7 áreas del sistema (tienda amrstore + WhatsApp CRM + infraestructura Hostinger) realizada con 7 agentes especializados en paralelo, con evidencia de código verificada línea por línea por el orquestador antes de publicar. Veredicto: el producto puede lanzarse HOY si se cierran los 7 puntos del Gap MVP — ninguno requiere más de unas horas de trabajo — porque el bot ya vende, el precio ya es correcto y la estabilidad crítica ya fue parcheada.
f5705f7 «MVP critical fixes — 12 blockers resolved» se aplicó en caliente (11:36 COT) mientras los agentes auditar,
resolviendo 6 hallazgos CRITICAL de seguridad. Todos los estados de este informe fueron re-verificados con grep contra el código actual antes de publicar.
Resumen Ejecutivo
Sí, se puede lanzar hoy, con la siguiente lectura de riesgo: el sistema funciona (bot cotiza, cierra, detecta loops,
entrega productos digitales, panel operativo, alertas Slack) y los bugs que arruinaban dinero — precio $10.000 vs $12.000, detalle 404,
loop pidiendo correo — ya están corregidos y desplegados en producción (commit 8d9efc8 + fixes posteriores).
Lo que impide un «GO» plano son 7 gaps de negocio/operación, no de feature:
(1) no existe mecanismo de cobro verificable — el cliente paga manual con foto de comprobante;
(2) notifyPaymentPending() nunca se dispara → cuando el bot dice «te paso los datos de pago», nadie recibe alerta;
(3) login sin rate-limit ni hash, (4) webhook Meta sin firma HMAC, (5) PII/márgenes expuestos en endpoints públicos,
(6) la suite de tests no cubre el bot (15/15 es una señal parcialmente vacía), (7) el deploy correctivo de hoy + migración 002 deben aplicarse en Hostinger.
Ninguno de los 7 excede unas horas. Con eso cerrado, el MVP entra a producción con control de calidad razonable y se puede empezar a cobrar el día 1; el roadmap de 2 semanas convierte «cobro manual» en «cobro con link».
Gap MVP — 7 puntos para lanzar HOY (antes de las ventas)
-
1. Aplicar en Hostinger
migration_002_mvp_fixes.sql+ desplegar los archivos def5705f7/8575fc3(y los de este informe). Sin esto, producción corre con código sin parchar y schema incompleto (web_leads, manual_takeover, índices). -
2. Cablear
AdminNotifier::notifyPaymentPending()enWebhookHandler(~3 líneas): cuando la respuesta contenga la frase de cierre «Te comparto los datos de pago», dispara Slack + push a la cola GoPlay. Es la pieza que convierte conversación en dinero. - 3. Link/QR de pago en el mensaje de cierre: Wompi Payment Links (PSE/tarjeta/Nequi) o QR Nequi+Bancolombia con monto exacto. Elimina el paso «espera, te paso los datos».
-
4. Registro mínimo de pedido: tabla/JSON
orders(phone, producto, monto, estado, created_at)escrito al cierre → conciliación sin leer el chat a mano. -
5. Endurecer login + webhooks:
password_hash/password_verify+rateLimit()(ya existe enadmin-amrtech.php) enlogin.php; firmaX-Hub-Signature-256conhash_hmacen el puentewhatsapp-webhook.php. -
6. Cerrar fugas de datos: auth en
GET /api/telemetry(teléfonos/IPs), quitarbuyPrice(154 ocurrencias) dedata/products.json, quitar consumer keys de WooCommerce del JS público, protegerdata/en.htaccess. -
7. Pausa de red y velocidad: timeout 8 s → 15 s en
whatsapp-webhook.php:326,CURLOPT_TIMEOUTenVectorService(2 líneas, hoy = ∞), confirmar backup del día +php -l+ suite antes de subir.
Hallazgos Consolidados (verificados en código)
whatsapp-crm/public/auth.php:18
Evidencia original: $crm_password = "admin"; sin hash ni rate-limit. Estado actual: reemplazado por getenv('CRM_PASSWORD') con fail-fast si falta (commit f5705f7).
ABIERTO: login.php:6 sigue comparando en plano y sin rateLimit() ni session_regenerate_id() → ver Gap #5.
whatsapp-crm/public/index.php:212,219
La impresión de texto ya usa escHtml() (:205, fix parcial), pero los botones «Aprender» siguen interpolando
decodeURIComponent('${escapedText}') dentro de onclick: encodeURIComponent no escapa apóstrofes → un mensaje de cliente con ' rompe la cadena JS e inyecta código.
Fix: dejar de usar atributos onclick inline; adjuntar listeners con addEventListener + dataset.
whatsapp-crm/src/AIService.php:474 · api.php:1133
No hay tabla orders/payments, ni endpoint de pago, ni link Wompi/Nequi: el bot cierra con «Te comparto los datos de pago en un momento»
(regla 11/15: prohibido enviar datos de pago) y Anderson responde a mano; orders_count cuenta clics, no ventas. Cero conciliación, cero facturación.
Fix: Gap #3 + #4 (links de pago + tabla mínima de pedidos).
whatsapp-crm/src/AdminNotifier.php:44
notifyPaymentPending() (Slack «CIERRE DE VENTA — envía datos de pago» + push a cola GoPlay) no tiene ni un call site
en todo el repo; solo están cableados notifyEscalation y notifyConsulting. Impacto: venta moribunda en silencio + cola de entrega siempre vacía.
Fix: Gap #2.
install.php usa SQL obsoleto
whatsapp-crm/public/install.php:32 · db/init.sql vs init-full.sql
install.php sigue ejecutando init.sql (26 líneas, sin wamid/lead_data/channel/índices); web_leads no tenía CREATE TABLE y
conversations carecía de manual_takeover/manual_takeover_at. Estado: migración 002 ya incluye web_leads + columnas + índices (fix en caliente),
pero la ruta install.php sigue apuntando al SQL viejo → una instalación nueva quedaría rota.
Fix: que install.php ejecute init-full.sql + migraciones, y eliminar init.sql.
whatsapp-webhook.php:326 · WebhookHandler.php:323-331
El puente cURL espera 8 s; el CRM dormía hasta 4 s + 1 s/burbuja + cascada LLM de 4 modelos × 22 s timeout = respuestas perdidas
(el dedupe casta el reintento a silencio). Estado: delay acotado a 1 s máximo (f5705f7) + fix del modelo Groq inválido (openai/gpt-oss-120b → llama-3.3-70b-versatile).
ABIERTO: timeout 8→15 s del puente, presupuesto duro de la cascada (8-10 s/ intento) y timeout en VectorService → Gap #7.
tests/run_all_tests.php:66,90,248
Desglose real: php -l solo de la raíz (22 archivos; 36 de whatsapp-crm/ nunca se lintean), 3 tests tautológicos de dominios,
4 unitarias reales de Dropshipping, 2 checks de red. Cero imports de whatsapp-crm/src/*. Ningún test detecta el bug de precio $10.000 vs $12.000, el loop de correo, ni el detalle 404.
Fix: lint recursivo + paridad publicSellPrice + guard anti-correo + EmergencyBrake (ver roadmap).
whatsapp-webhook.php (0 hash_hmac)
Cualquiera puede POSTear mensajes falsos al bot (o farmear tu token si va por query string). Nota: meta-webhook.php del CRM sí valida HMAC — el hueco está en el puente de WA.
api.php:1084 · data/products.json (154 × buyPrice)
GET /api/telemetry devuelve teléfonos de referidos, audit logs e IPs/UA sin token; products.json público incluye buyPrice/margin → riesgo Ley 1581 + tus costos a la vista de la competencia.
middleware-frontend/assets/js/app.js:185
consumer_key=ck_…&consumer_secret=cs_… visibles para cualquier visitante → rotar claves y mover la llamada al servidor.
VectorService con curl sin timeout (=∞)
whatsapp-crm/src/VectorService.php:19-42,79-114
0 ocurrencias de CURLOPT_TIMEOUT: un host de OpenAI/Pinecone lento congela el webhook indefinidamente (peor que toda la cascada). Fix: 3 líneas.
WebhookHandler.php:180 · whatsapp-webhook.php:134
El wamid se persiste antes de generar la respuesta (y el puente marca el mensaje como visto antes de llamar al CRM): si el intento 1 se pasa de timeout, el intento 2 se descarta → silencio definitivo.
ContactRepository.php:38-48 · index.php:683
1 JOIN + subconsulta correlacionada por contacto, sin LIMIT, cada 3 s: con 200 conversaciones ≈ 4.060 queries/min por panel abierto en MySQL compartido.
amrstore.php:1096 · index.php:8-11
El grid genera href="/?id=…" pero ningún archivo procesa $_GET['id'] → cada «Ver producto» re-entrega 310 KB + ~95 imágenes en vez de la ficha. Conversión directa perdida.
amrstore.php:576 · amrstore/producto.php:255
Botón primario «Ver productos» (blanco sobre #0ea5e9 = 2.77:1) y CTA «Pedir por WhatsApp» (3.30:1) — inlegibles para baja visión. Fix: gradiente desde #0369a1 (6.3:1) y fondo #15803d.
index.php:638-641 · amrstore.php:1155-1157
Los contactos son <div onclick> sin tabindex/role/keydown (2.1.1 Keyboard) y los 3 inputs del formulario de referidos solo tienen placeholder, cero <label for> (3.3.2) → bloquea lectores de pantalla en el formulario de conversión.
Makefile al destino equivocado y sin rollback
Makefile:120,129
rsync … public_html/ con --delete apunta a la raíz, no a whatsapp-crm/main/ donde vive el CRM → puede crear un árbol muerto o borrar el productivo con su .env. Usar el flujo scp verificado que ya opera el equipo.
CONTEXT-OPENCODE.md:143-148 · webhook.php:41
AutoResponder/WAHA sobre un número personal: batería/internet/baneo = 0 ventas. Existe meta-webhook.php (Cloud API) como canal alterno — activarlo es el failover barato.
get_chat muestra los 100 mensajes más antiguos
MessageRepository.php:16-22 · get_chat.php:25
ORDER BY id ASC LIMIT 100: en chats >100 msgs el panel nunca muestra el final (incoherente con getRecentHistoryForAI, que usa DESC).
scripts/monitor-setup.sh:25-29 · backup-hostinger.sh:12
El health check espera 401/503 (se obtiene aunque la BD/LLM estén caídas), los backups viven en el mismo servidor (sin offsite) y el restore nunca se probó. AdminNotifier::sendSlack falla en silencio si falta SLACK_WEBHOOK_URL.
CatalogService.php:254 · amrstore.php:1098 · producto.php:169 · productos-dropi.php:412
El bot ya usa CatalogService::publicSellPrice() (verificado: $10.000 → $12.000), pero la landing y otros scripts tienen copias propias → divergencia futura garantizada sin test de paridad.
WebhookHandler.php:375 · AIService.php:316
Ambos corregidos en f5705f7: mensaje genérico al cliente y modelo llama-3.3-70b-versatile.
aria-hidden en iconos
amrstore.php:469,1114,1128
75 imágenes S3 promedio 251 KB para cajas de 380 px, sin Cache-Control → LCP > 2.5 s en 4G; FontAwesome + Google Fonts bloquean pintura (~300-600 ms).
Fortalezas del Sistema (las 7 áreas coinciden)
publicSellPrice() con techo mil, reglas de discrepancia en el prompt y
verificación en vivo ($10.000 → $12.000 en bot y landing).
admin-amrtech.php con rate limit + 2FA, webhook Meta con HMAC, src/ protegido, hash_equals para tokens.
messages.wamid, (direction, created_at), contacts.phone — dedupe y anti-loop no hacen full scan.
lang, landmarks header/main/footer, jerarquía h1→h2→h3, alt descriptivos, rel="noopener", escaping con htmlspecialchars, targets ≥44 px.
Roadmap 2 Semanas — Pulir sobre la marcha y monetizar
Makefile.orders, primer pago end-to-end medido.notifyPaymentPending activo, prueba de que los webhooks (Ventas/Garantías/Stock) están vivos, falla ruidosa si falta config.VectorService, dedup en AutoResponder, límite en webhook.php, polling del panel a 5-10 s./api/telemetry, buyPrice fuera del JSON público, rotar claves Woo.Metodología
7 agentes especializados ejecutados en paralelo (Seguridad, Calidad PHP, Base de Datos, Rendimiento, QA, Accesibilidad WCAG 2.2,
Arquitectura & MVP), cada uno en modo solo-lectura sobre el repositorio, con salida estructurada obligatoria (veredicto GO/GO-CON-FIXES/NO-GO + hallazgos con
archivo:línea + fortalezas + gap). Los 6 hallazgos CRITICAL más graves fueron re-verificados manualmente con grep/sed contra el código real
por el orquestador (password, XSS, install sin auth, claves Woo, firma Meta, schema de conversations), y se detectó que el commit f5705f7 resolvía
6 blockers en caliente durante la auditoría — por lo que cada hallazgo lleva estado RESUELTO/ABIERTO según el código al momento de publicar.
Limitaciones declaradas: verificación estática (sin pentest dinámico, sin pen-testing de sesión) · los conteos de líneas corresponden
al HEAD 8575fc3 · la suite de pruebas no se ejecutó como parte de esta auditoría (se ejecuta en el paso de deploy) · no se midieron Lighthouse reales en 4G
(las cifras de rendimiento provienen del análisis de código y mediciones curl/CLI).