- 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
24 lines
1.0 KiB
JavaScript
24 lines
1.0 KiB
JavaScript
const { chromium } = require('playwright');
|
|
(async () => {
|
|
const browser = await chromium.launch();
|
|
const page = await browser.newPage();
|
|
const pages = [
|
|
['dashboard', 'http://localhost:5000/'],
|
|
['catalog', 'http://localhost:5000/catalog'],
|
|
['tienda (capi)', 'http://localhost:5001/tienda'],
|
|
];
|
|
for (const [name, url] of pages) {
|
|
const errs = [];
|
|
const onErr = (e) => errs.push(String(e).slice(0, 140));
|
|
const onCon = (m) => { if (m.type() === 'error' && !/favicon|net::ERR|404|sourcemap/i.test(m.text())) errs.push(m.text().slice(0, 140)); };
|
|
page.on('pageerror', onErr); page.on('console', onCon);
|
|
try {
|
|
await page.goto(url, { waitUntil: 'load', timeout: 20000 });
|
|
await page.waitForTimeout(2000);
|
|
console.log((errs.length ? '✗ ' : '✓ ') + name, errs.length ? errs.slice(0, 3) : '');
|
|
} catch (e) { console.log('✗✗ ' + name + ' → ' + e.message.slice(0, 100)); }
|
|
page.removeAllListeners('pageerror'); page.removeAllListeners('console');
|
|
}
|
|
await browser.close();
|
|
})();
|