- 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
33 lines
1.8 KiB
JavaScript
33 lines
1.8 KiB
JavaScript
const { chromium } = require('playwright');
|
|
const { execSync } = require('child_process');
|
|
const JWT_SECRET = execSync("grep -oP 'POS_JWT_SECRET=\\K.*' /etc/systemd/system/nexus-pos.service | head -1").toString().trim();
|
|
function tok() {
|
|
const h = { alg: 'HS256', typ: 'JWT' };
|
|
const now = Math.floor(Date.now()/1000);
|
|
const p = { tenant_id: 32, employee_id: 1, name: 'Audit', role: 'owner', branch_id: 1,
|
|
max_discount_pct: 100, permissions: ['*'], device_id: 'a', type: 'pos_access', exp: now+900, iat: now };
|
|
const b64 = o => Buffer.from(JSON.stringify(o)).toString('base64url');
|
|
const crypto = require('crypto');
|
|
return b64(h)+'.'+b64(p)+'.'+crypto.createHmac('sha256', JWT_SECRET).update(b64(h)+'.'+b64(p)).digest('base64url');
|
|
}
|
|
(async () => {
|
|
const browser = await chromium.launch();
|
|
const page = await browser.newPage();
|
|
const errs = [];
|
|
page.on('pageerror', e => errs.push(String(e).slice(0,120)));
|
|
page.on('console', m => { if (m.type()==='error' && !/favicon|404|net::ERR|sourcemap/i.test(m.text())) errs.push(m.text().slice(0,120)); });
|
|
await page.addInitScript(t => {
|
|
localStorage.setItem('pos_token', t);
|
|
localStorage.setItem('pos_employee', JSON.stringify({id:1,name:'Audit',role:'owner'}));
|
|
localStorage.setItem('pos_tenant_id','32');
|
|
document.cookie='pos_role=owner; path=/pos; SameSite=Lax';
|
|
}, tok());
|
|
for (const p of ['/pos/fleet','/pos/supplier-catalog','/pos/historical-sales','/pos/diagrams']) {
|
|
errs.length = 0;
|
|
const resp = await page.goto('http://localhost:5001'+p, {waitUntil:'load', timeout:20000}).catch(e=>null);
|
|
await page.waitForTimeout(2000);
|
|
console.log((errs.length?'✗ ':'✓ ') + p + ' [' + (resp?resp.status():'?') + ']' + (errs.length? ' → '+errs[0]:''));
|
|
}
|
|
await browser.close();
|
|
})();
|