尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证制作者的介绍仅有上面的一句话。 更多详情请阅读仓库 README。 仓库 README ↗
正在加载完整 README。
查看完整 README ↗Panel interno para centralizar la relacion con clientes: seguimiento de los grupos de WhatsApp, solicitudes de alta y reclamos. Esta pensado para sumarse al portal actual como un grupo "CRM" en la barra lateral (igual que "VENDEDOR").
Problema. La planilla que llena el bot de WhatsApp no la mira nadie si no se presiona por los grupos; los reclamos se reenvian por Telegram y se pierden entre mensajes; las altas se evaluan a mano y sin prioridad.
Menu principal
| Seccion | Que resuelve |
|---|---|
| Resumen | Inicio + tablero en uno: chats sin responder, demoras, reclamos que esperan a gerencia, altas para priorizar, cierre del dia por WhatsApp y graficos por hito / encargado / vendedor. |
| Seguimiento de clientes | La cola priorizada que lee la planilla del bot. Al marcar "respondido" hay que elegir como quedo (resuelto, derivado, escalado, espera al cliente…) y opcionalmente la relacion (buena / regular / en riesgo) y una observacion. Todo queda en el historial del cliente (ficha del cliente). Si gerencia indico algo sobre un reclamo, se ve en la fila. |
| Solicitudes de alta | Formulario publico de 4 pasos (/formularios/alta) con 8 documentos y firma. Cada solicitud se clasifica por cuanto completo el formulario (A completa, B casi completa, C incompleta, D muy incompleta) y se ordena por las mas completas. Link a Nosis con el CUIT. Aprobar / rechazar y armar el mail de respuesta. Importar Excel y Plantillas de mail son subsecciones. |
| Reclamos | Panel de gerencia que reemplaza Telegram: reclamos de WhatsApp (hito "Reclamo") y formularios FOR-03. En cada reclamo se indica la accion para el vendedor; con "Ofrecer producto sustituto" se escribe que producto ofrecer. Estados: esperando gerencia → indicado/en gestion → respondido al cliente. |
Resumen diario. GET /api/resumen-diario devuelve el mensaje de cierre del
dia (finalizadas, sin responder, demoras de 1+ dia, reclamos sin indicar,
clientes en riesgo) y el link wa.me para enviarlo. En el MVP se envia desde
el boton del Resumen; el envio automatico queda para la tarea programada de la
PC interna (la misma del bot).
Fuera del MVP (siguiente iteracion): bot de Telegram, envio automatico por WhatsApp Business API, login/roles del portal, formularios FOR-03 reales, catalogo real para los sustitutos y escritura en la planilla de produccion (falta la service account).
SEGUIMIENTO_ACCESO="publico").DB_BACKEND="demo")..data/*.json. Borrar esa carpeta deja la demo como nueva..env.example: RESUMEN_WHATSAPP_NUMERO, APP_URL, PORTAL_USUARIO.Desplegable (o en Seguimiento) una columna Link grupo WhatsApp con el link de invitacion (https://chat.whatsapp.com/...). Sin link, el boton copia el nombre del grupo y abre WhatsApp Web.Con DB_BACKEND="demo" hay seis formularios ficticios, uno por clasificacion
del formulario FOR-03 Rev04, con el detalle de cliente, comprobantes,
productos, evaluacion de Calidad, acciones correctivas y cierre. No se importan
PDFs ni adjuntos. La integracion con la fuente real queda pendiente.
Herramienta interna del equipo comercial: importa las solicitudes de alta que llegan del formulario de Acrobat, permite aprobarlas o rechazarlas y arma el mail de respuesta listo para pegar en el cliente de correo.
El MVP guarda los datos en una planilla de Google. La capa de acceso a datos
esta detras de una interfaz (src/lib/db/repositorio.ts), asi que pasar a
Postgres mas adelante no toca ninguna pantalla.
La app entra a la planilla con una service account, no con tu usuario. Eso permite que la planilla quede privada y que el servidor no tenga que pedirte login cada vez.
.env:
client_email → GOOGLE_SERVICE_ACCOUNT_EMAILprivate_key → GOOGLE_PRIVATE_KEY (copiala tal cual, con los \n)client_email como Editor. Sin
este paso la API responde 403.Copiar .env.example a .env y completar:
DB_BACKEND="sheets"GOOGLE_SHEETS_ID: el id de la planilla (esta en su URL, entre /d/ y /edit).GOOGLE_SERVICE_ACCOUNT_EMAIL y GOOGLE_PRIVATE_KEY.npm install
npm run dev
Entrar a http://localhost:3000. Las hojas Solicitudes y Plantillas se crean
solas en la planilla la primera vez que la app las necesita, con sus
encabezados y las dos plantillas por defecto.
Las columnas son exactamente las del modelo Prisma, para que migrar sea copiar columna por columna.
Hoja Solicitudes
| Columna | Contenido |
|---|---|
id | UUID generado por la app |
nombre | Nombre del cliente |
email | Clave unica: por aca se identifica cada solicitud |
datos | JSON con el resto de las columnas del formulario |
estado | PENDIENTE, APROBADO o RECHAZADO |
fechaImportacion | ISO 8601 |
fechaDecision | ISO 8601, vacio mientras este pendiente |
usuarioDecisor | Vacio en esta demo sin usuarios |
Hoja Plantillas
| Columna | Contenido |
|---|---|
id | UUID generado por la app |
tipo | aprobado o rechazado |
asunto | Admite placeholders |
cuerpoHtml | HTML con {{nombre}}, {{usuario}}, etc. |
headerImg | URL de la imagen de encabezado (opcional) |
headerAlt | Texto alternativo del encabezado |
footerImg | URL de la imagen de pie (opcional) |
footerAlt | Texto alternativo del pie |
Se puede editar a mano, con cuidado: la columna
datostiene que seguir siendo JSON valido yestadouno de los tres valores.
DATABASE_URL.npm run db:migrate — el schema.prisma ya esta escrito.DB_BACKEND="postgres".No hay que tocar pantallas ni route handlers: importan de
@/lib/db/solicitudes y @/lib/db/plantillas, que eligen la implementacion
por import dinamico segun DB_BACKEND.
| Comando | Para que sirve |
|---|---|
npm run dev | Levanta la app en modo desarrollo |
npm run build | Build de produccion (corre TypeScript y ESLint) |
npm run typecheck | Solo chequeo de tipos |
npm run db:migrate | Migraciones de Prisma (solo backend Postgres) |
npm run db:studio | Explorador visual de la base Postgres |
src/app — rutas. (dashboard) es el panel de acceso directo,
api los route handlers.src/components — componentes agrupados por pantalla, mas ui/ con los
basicos propios (no usamos libreria de componentes).src/lib — logica agrupada por dominio:
db/ acceso a datos: repositorio.ts define el contrato, sheets/ la
implementacion activa, postgres/ la futura, y solicitudes.ts /
plantillas.ts son la fachada que usan las pantallas,import/ parseo y normalizacion de planillas,email/ armado del HTML y copiado al portapapeles,utils/ helpers de HTML, strings y fechas.Los chats del bot se leen de la pestaña Seguimiento de
CONSULTA SERVICIO CLIENTE - 2026:
SEGUIMIENTO_BACKEND="sheets"
SEGUIMIENTO_SHEETS_ID="1Bo5zBqgO2QTIjzob_PSnKaMeQ5BHzFdVd5scV035X54"
SEGUIMIENTO_HOJA="Seguimiento"
SEGUIMIENTO_ACCESO="publico"
SEGUIMIENTO_FILA_INICIO=""
En Vercel, cargar estas variables en los entornos correspondientes y volver a desplegar.
Si el seguimiento ya usa Postgres con sincronización, conservar SEGUIMIENTO_BACKEND="postgres":
la importación usa el mismo lector.
La columna grillo contiene el código y nombre del cliente. También se admiten
Cliente, Grupo / Cliente y Razón social; las columnas se ubican por nombre,
incluso si cambia su orden. Columna 2 se ignora. Las fechas pueden ser números
de serie o texto como 9/25/2026.
Desplegable es la fuente de los datos comerciales actuales: lista de precios,
clasificación, vendedor, situación y grupos de WhatsApp. MaestroCliente
complementa actividad, condiciones de pago, crédito y deuda. Los clientes se
vinculan por código, nombre o coincidencia exacta con cualquiera de sus dos
grupos de WhatsApp. Si un grupo corresponde a varios clientes, se necesita
el código o el nombre para asignarlo.
Al tocar el nombre se abre /clientes/[codigo], con actividad, categoría,
condición de pago, límite de crédito, lista de precio, clasificación de ventas
y grupos de WhatsApp, incluso si el cliente todavía no tiene consultas.
Situación, deuda y estado de cuenta se muestran como un único dato: se conservan
las alertas de ambas hojas y se omite OK cuando hay una advertencia de deuda.
La observación inicial viene de Desplegable; cada conversación finalizada la
reemplaza con su resultado y comentario. Reabrir o agregar una nota conserva
el último cierre. Las siguientes sincronizaciones no pisan esa observación.
En Postgres lo mantiene la migración 003_ficha_clientes.sql; en Sheets se
combina la ficha con el historial persistido por la app.
Las consultas sin coincidencia aparecen como Otros · <nombre del grupo> y
con clasificación Otros. Se conserva el mensaje completo y se recupera el
grupo de prefijos del bot como [SIN MATCH] Grupo DP ...: ... o DP ...: ...
cuando la columna de WhatsApp está vacía. Si no figura un grupo, se conserva
el texto del cliente como referencia; si tampoco figura, se muestra Otros.
En modo público la aplicación lee Sheets y guarda las gestiones en su almacén;
para escribir directamente en Sheets, quitar SEGUIMIENTO_ACCESO="publico"
y configurar la service account.
SEGUIMIENTO_FILA_INICIO sigue permitiendo omitir filas históricas; vacío lee desde el inicio.
Los cierres, notas e indicaciones de WhatsApp se identifican por la planilla
de origen. La fuente nueva comienza sin las gestiones generales de la prueba
anterior; no se trasladan automáticamente. El historial simulado solo está
disponible con SEGUIMIENTO_BACKEND="demo".
Si una lectura falla, Resumen conserva las secciones disponibles y muestra un aviso con Reintentar. Seguimiento y Solicitudes mantienen la navegación y muestran el aviso en lugar de una tabla vacía o métricas en cero. Los detalles del error quedan en los logs del servidor. Si falla la sincronización a Postgres, se conservan los registros y se informa el fallo del último intento.
Pruebas del lector: node --test tests/sheets-seguimiento.test.mjs.
Pruebas de separación entre prueba y planillas: node --test tests/seguimiento-origen.test.mjs.
Pruebas de fichas y cierres: node --test tests/clientes-ficha.test.mjs.
Prueba de migración y sincronización en Postgres local:
node --env-file=.env.local --test tests/clientes-postgres.test.mjs.
Esta última crea un esquema aislado dentro de una transacción y revierte todos
los cambios al terminar; necesita la base local iniciada.
/ abre /resumen sin credenciales.
La autenticacion y los roles se rediseñaran en una etapa posterior.src/lib/import/normalize-solicitud.ts
(ALIAS_NOMBRE y ALIAS_EMAIL); hay que validarlos contra un archivo real.background-image en CSS.