El total del pedido queda en $0 cuando saco un ítem del carrito.
Tus operadores reportan errores
con captura, en un click.
Argos es un botón flotante y un panel de admin que se enchufan a cualquier proyecto Next.js. Adiós al “no anda nada” sin contexto.
Pedidos de hoy
mié 29 · 14:07| Pedido | Cliente | Zona | Total | Estado |
|---|---|---|---|---|
| #4818 | M. Duarte | Olivos | $18.400 | entregado |
| #4819 | L. Ferrari | Vicente López | $9.250 | en camino |
| #4820 | J. Bravo | Florida | $26.900 | en camino |
| #4821 | S. Ríos | Olivos | $0 | trabado |
| #4822 | P. Castro | Munro | $12.100 | preparando |
así queda el botón, en todas las pantallas de tu app
Un error reportado sin contexto es un error que no existe.
El operador ve algo raro, te escribe, y arranca el interrogatorio. Para cuando llegás a entender qué pasó, la pantalla ya cambió y nadie se acuerda de nada.
Y todavía no sabés en qué pantalla estaba.
- Fotos
- 2 adjuntas desde la galería
- Pantalla
- /pedidos/4821
- Proyecto
- logistica
- Reportó
- operador · id 3f9a…
- Navegador
- Chrome 131 · macOS
- Cuándo
- hoy, 14:07
Todo eso lo junta Argos solo. El operador solo escribe qué pasó.
Apretá el botón. Es el mismo código que corre en producción.
El 🐛 de acá abajo captura de verdad la pantalla falsa de la izquierda, con la misma librería y las mismas opciones que el kit instalado. El reporte aparece en el panel de la derecha.
Pedidos de hoy
mié 29 · 14:07| Pedido | Cliente | Zona | Total | Estado |
|---|---|---|---|---|
| #4818 | M. Duarte | Olivos | $18.400 | entregado |
| #4819 | L. Ferrari | Vicente López | $9.250 | en camino |
| #4820 | J. Bravo | Florida | $26.900 | en camino |
| #4821 | S. Ríos | Olivos | $0 | trabado |
| #4822 | P. Castro | Munro | $12.100 | preparando |
👁️ Errores reportados
2 sin resolverNo me carga la lista de conversaciones, queda el spinner girando.
Tres pasos, y ninguno requiere entrenar a nadie.
El flujo entero está pensado para que un operador sin conocimientos técnicos lo use bien la primera vez que lo ve.
- 01
El operador aprieta 🐛
Un botón flotante siempre visible, en todas las pantallas. No hay que explicarle nada a nadie: si algo está raro, se aprieta.
- 02
Argos captura y pregunta
Toma la pantalla tal cual se ve (sombras, gradientes, Tailwind v4 incluido), muestra el preview y pide una nota de una línea. Si hace falta, el operador adjunta hasta 5 fotos de su galería.
- 03
Aparece en /errores
El reporte llega al panel de admin con la captura, la nota y todo el contexto técnico. Lo mirás, lo arreglás, lo marcás resuelto.
Chico por fuera, terco por dentro.
Cada decisión del kit está tomada para que entre en cualquier proyecto sin pelearse con nada de lo que ya tenés.
Captura fiel, sin popup
Usa modern-screenshot (serialización SVG foreignObject). Respeta sombras, oklch y CSS moderno. Nada de pedirle permiso de pantalla al navegador.
Hasta 5 fotos adjuntas
A veces el problema no está en la pantalla: está en la impresora, en el paquete o en la moto. El operador adjunta fotos de su galería y se redimensionan en el navegador antes de subirse.
Autocontenido
El botón lleva sus estilos inline. No depende de tu Tailwind, tu design system ni tu librería de toasts. Entra en cualquier Next.js sin fricción.
Capturas privadas
Van a un bucket privado y se sirven solo a admin con URLs firmadas de 1 hora. Una captura puede tener datos de clientes: se trata como tal.
Aislado por proyecto
Cada proyecto tiene su propia tabla y su propio bucket, en su propia Supabase. Nada se comparte, nada se cruza.
Un comando, y actualizable
node install.mjs ../ruta/al/proyecto copia los cuatro archivos y te imprime los pasos finales. El template es la fuente de verdad: mejorás una vez, re-corrés el instalador y tu argos.config.ts nunca se pisa.
Doble candado
Cualquier usuario logueado puede crear un reporte. Solo admin puede listar, ver capturas y resolver. Se define en tu config, con tu esquema de auth.
Local, Docker y Vercel
Los archivos se copian adentro del proyecto, no se linkean. Lo que corre en tu máquina es exactamente lo que se buildea en producción.
Un minuto, cuatro pasos, cero sorpresas.
El instalador copia los archivos adentro del proyecto (no los linkea), así lo que corre en tu máquina es exactamente lo que se buildea en Docker o en Vercel.
Copia los 4 archivos adentro del proyecto y te imprime los pasos finales.
cd "Sistemas/Argos"
node install.mjs "../WhatsApp Infra/whatsapp-dashboard"
npm install modern-screenshotPara actualizar: editás template/ en Sistemas/Argos/ y re-corrés el instalador en cada proyecto. Se re-copian el botón, la API y la página — argos.config.ts nunca se pisa.
El cliente nunca toca la base.
Todo pasa por la API del servidor, que valida quién sos antes de escribir o leer. La tabla tiene RLS habilitado sin policies: para el navegador, sencillamente no existe.
Navegador del operador
- error-report-button.tsx
- modern-screenshot
- captura + nota
API /api/errors
- requireUser()
- requireAdminUser()
- service role
Supabase del proyecto
- tabla error_reports
- bucket privado
- RLS on · 0 policies
Navegador del admin
- /errores
- filtros + lightbox
- resolver / reabrir
Chequeo de admin
- 401 si no está logueado
- 403 si no es admin
- URLs firmadas 1 h
error-screenshots
- public: false
- límite 10 MB
- path por proyecto
Cada proyecto corre su propia copia de este diagrama, contra su propia Supabase. Nada se comparte entre proyectos — aunque cada reporte guarda el campo project por si algún día querés consolidarlos en un panel único.
Cinco archivos. Ni uno de más.
Clickeá cada uno para ver qué hace y un pedazo del código real que se copia a tu proyecto.
src/components/error-report-button.tsxse actualizaBotón fijo abajo a la derecha, visible en todas las pantallas. Al apretarlo captura el body con modern-screenshot, abre un modal con el preview, un campo de nota y un adjuntar fotos (hasta 5, comprimidas en el navegador), y postea a /api/errors. Se auto-excluye de su propia captura con data-error-report-ignore.
const { domToJpeg } = await import("modern-screenshot");
const dataUrl = await domToJpeg(document.body, {
quality: 0.7,
scale: Math.min(window.devicePixelRatio || 1, 1.5),
backgroundColor: getComputedStyle(document.body).backgroundColor,
filter: (node) =>
!(node instanceof HTMLElement &&
node.hasAttribute("data-error-report-ignore")),
});
// Las fotos de la galería se achican antes de viajar:
// 5 fotos de celular sin tocar son ~40 MB de base64.
const scale = Math.min(1, 1400 / Math.max(sw, sh));
ctx.drawImage(bitmap, 0, 0, w, h);
let out = canvas.toDataURL("image/jpeg", quality);Una captura de pantalla es un dato sensible.
Puede tener el chat de un cliente, un teléfono o un total facturado. Argos la trata como tal desde el primer día.
Bucket privado
Ni las capturas ni las fotos adjuntas se sirven públicas. El bucket se crea con public: false y límite de 10 MB por archivo.
URLs firmadas de 1 hora
Cada vez que un admin abre el panel, la API genera links temporales. Se vencen solos.
RLS sin policies
La tabla tiene Row Level Security habilitado y cero policies: el cliente no puede leerla ni escribirla directo.
Todo por service role
El único camino a los datos es la API del servidor, que valida quién sos antes de tocar nada.
Dos niveles de permiso
Crear un reporte: cualquier usuario logueado. Ver, listar y resolver: solo admin.
El botón no se auto-espía
El botón y el modal llevan data-error-report-ignore, así que jamás aparecen dentro de su propia captura.
// El bucket se crea privado la primera vez, solo.
await service.storage.createBucket(BUCKET, {
public: false,
fileSizeLimit: 10 * 1024 * 1024,
});
// Y se sirven con un link que se vence solo.
const { data: signed } = await service.storage
.from(BUCKET)
.createSignedUrl(report.screenshot_path, 3600);Si el reporte llega sin captura (porque falló la serialización o pesaba más de 9 MB), se guarda igual con la nota y el contexto. Nunca se pierde un reporte por culpa de la imagen.
Dónde está mirando Argos hoy.
Relevado sobre el workspace real: 4 sistemas con Argos vivo y el resto listos para el instalador.
| Proyecto | Área | Estado |
|---|---|---|
whatsapp-dashboard La implementación original: acá nació Argos y de acá se extrajo el template. Usa requireOperator / requireAdminOrLocal propios, y la UI va con Tailwind y sonner en vez de estilos inline. | WhatsApp Infra | vivo |
control-turnos Fichaje GPS+WiFi con la PWA del operario. El botón lleva props propias (variant, position, hideOn) para convivir con la barra inferior del celu. | Sistema de Asistencia | vivo |
engine-app Port a JavaScript puro (sin TS, sin src/), con i18n propio y Supabase por REST. Tabla engine_reports y endpoint /api/reports en vez de /api/errors. | LoyalEngine · Daniela | port a mano |
meta-ads-scheduler Port a TypeScript vanilla (sin React). Reportes en logs/error-reports.json y las imágenes en disco, servidas por índice. El panel ya está detrás del basic-auth de Traefik, así que no lleva candado propio. | Meta Ads Center | port a mano |
logistica Next.js + Supabase con operadores en la calle: el candidato número uno para el próximo install. | Logística | pendiente |
kitchco-hq Dashboard RPG + switchboard. Encaja directo con el instalador. | Hermes · Agentes IA | pendiente |
meta-dashboard Next.js 16. Instalación estándar. | Meta Ads Center | pendiente |
sistemas-dashboard · social-hub · kitchcocenter-new Mismo stack, mismo instalador. Van cuando estén en manos de operadores. | Varios | pendiente |
Lo que siempre se pregunta.
El instalador asume Next.js con App Router, Supabase y login. Para lo que no encaja se hace un port a mano: el scheduler de Meta Ads tiene uno en TypeScript vanilla, sin React, que guarda los reportes en JSON local en vez de Supabase. Si mejorás el template, ese cambio hay que llevarlo a mano.
Porque html2canvas se rompe con oklch (o sea, con Tailwind v4) y no dibuja bien las sombras. modern-screenshot serializa el DOM a SVG con foreignObject: sale fiel al CSS moderno y no pide permiso de captura de pantalla al navegador.
Hoy no: cada proyecto tiene su tabla y su bucket, a propósito. Pero cada reporte guarda el campo project, así que la consolidación está preparada para el día que la quieras.
Porque muchas veces el problema no está en la pantalla: la impresora no imprime, el paquete llegó roto, el cartel del local está mal. El operador adjunta hasta 5 fotos de su galería y viajan con el mismo reporte, al mismo bucket privado. Se redimensionan a 1400 px y se comprimen en el navegador, así 5 fotos de celular no se convierten en 40 MB de POST.
El modal se abre igual con un aviso, y el reporte se envía solo con la nota y el contexto. Nunca se pierde el reporte por culpa de la captura.
Editás los archivos de template/ y re-corrés node install.mjs en cada proyecto. Se re-copian el botón, la API y la página; tu argos.config.ts queda intacto.
Cuatro archivos y una dependencia. modern-screenshot se carga con import dinámico: recién baja cuando alguien aprieta el botón, no en el bundle inicial.