尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证制作者的介绍仅有上面的一句话。 更多详情请阅读仓库 README。 仓库 README ↗
正在加载完整 README。
查看完整 README ↗Plataforma SaaS multi-negocio para operar un comercio de punta a punta: pedidos (también desde un mensaje de WhatsApp o por voz, con IA), inventario, despachos, catálogo, proveedores y finanzas. Una sola instalación atiende a varios negocios aislados entre sí.
Dashboard mensual de un negocio de ejemplo. Todas las capturas usan datos ficticios (ver cómo se tomaron).
Sitio en producción: https://koptup-comercio-electronico.vercel.app — abre en la pantalla de ingreso. Un negocio nuevo puede registrarse desde ahí y queda pendiente hasta que el administrador de la plataforma lo aprueba.
koptup Comercio Electrónico está pensado para pequeños y medianos negocios de Colombia que venden por WhatsApp y redes y despachan con mensajería: tiendas que reciben los pedidos por chat y los anotan en hojas de cálculo (la app puede importar esos Excel).
La app cubre el ciclo completo de la operación:
capturar el pedido → validarlo contra el stock → confirmarlo → alistarlo → despacharlo (guía y ruta) → entregarlo → cobrarlo → medir la utilidad.
Dos ideas la definen:
tenant_id y políticas RLS de PostgreSQL.Todo lo que sigue está implementado en este repositorio. Entre paréntesis va el archivo principal, por si quieres revisarlo.
parseClarify.ts): el servidor revisa los datos de despacho obligatorios (nombre, teléfono, dirección y valor) y cada variante (color, talla y la combinación de ambos) contra el inventario en stock. Si falta algo, responde con una pregunta concreta y las opciones disponibles, aunque el modelo haya dicho que el pedido estaba completo.phases.ts): Confirmado → En alistamiento → Alistado → Despachado → Entregado, más Pagado, Devolución y Cancelado. La base de datos rechaza cualquier otro estado.createOrderWithCode.ts y migración 013).OrderReceipt.tsx)./api/ai/assistant): crear pedidos, agregar o buscar inventario, consultar pedidos y catálogo, cambiar estados, registrar devoluciones, productos defectuosos, costos y gastos, crear o editar productos, ajustar o mover stock, revisar alertas, reimprimir guías y generar reportes en Excel.matching.ts): si un nombre coincide con cero o con varios registros, el asistente pide precisión en vez de tocar la fila equivocada./api/ai/parse-inventory) y foto por ítem.inventorySync.ts).gpt-4o-mini y sugiere sus datos (/api/ai/analyze-product)./catalog/<slug> con la marca, foto y precio de los productos activos; el QR se descarga desde Configuración.src/lib/shipping/): el admin la elige en Administración; hay un adaptador para la API de Interrapidísimo y un modo sandbox. Al pasar un pedido a "Despachado" se crea la guía y se guarda el número de seguimiento; el webhook /api/shipping/webhook (secreto comparado en tiempo constante y rate limit por IP) actualiza el tracking y puede marcar el pedido como entregado.crypto.ts).Módulo opcional por negocio (suppliers/page.tsx, migración 016) para quien vende productos de varios proveedores:
Cinco agentes basados en reglas (deterministas y con pruebas, sin llamadas a un modelo) revisan los datos del negocio (src/lib/agents/):
| Agente | Qué revisa |
|---|---|
| Auditor | Errores de negocio e inconsistencias |
| QA | Integridad de los datos (estados, fechas, rangos) |
| Inventario | Quiebres de stock, compras recomendadas y productos sin rotación |
| Financiero | Utilidad, margen y dinero pendiente de liquidar |
| Comercial | Productos estrella, productos sin ventas y combos |
El motor de automatizaciones (engine.ts) convierte los hallazgos en alertas accionables ("Generar orden de compra", "Revisar reposición"). Se ejecutan a demanda o con Vercel Cron.
Cuatro roles (permissions.ts):
| Rol | Alcance | Pantalla de inicio |
|---|---|---|
superadmin | La plataforma: todos los negocios, sus usuarios, planes, cobros y métricas globales | Plataforma |
admin | Administra su negocio: equipo, invitaciones, auditoría, licencia y configuración. No opera pedidos ni inventario | Administración |
member | Opera el negocio: pedidos, asistente, inventario, productos, despacho, proveedores y agentes | Dashboard |
viewer | El negocio en modo lectura | Dashboard |
Módulos activables y renombrables por negocio (modules.ts); por ejemplo, un taller de motos ve "Ventas" y "Catálogo" donde otro ve "Pedidos" y "Productos".
Registro con aprobación (migración 017): un negocio nuevo se registra y espera la aprobación del superadmin; un empleado se une con el enlace de invitación del negocio y espera la aprobación de su admin. Un cron borra los rechazados a los 30 días.
Auditoría de las acciones sensibles (pagos, planes, usuarios, negocios).
| Plan | Tope de productos | Precio mensual (COP) |
|---|---|---|
| Free | 50 | $0 |
| Pro | 500 | $49.900 |
| Enterprise | Ilimitado | $149.900 |
Hoy el superadmin asigna planes y registra pagos desde la pantalla Plataforma. El cobro en línea con Stripe está implementado (checkout y webhook idempotente, migración 015), pero mientras no se configuren sus llaves la pantalla "Mi licencia" lo muestra como "En desarrollo".
Importación de pedidos y datos desde Excel/CSV (/api/import) y exportación a Excel de dashboard, pedidos, inventario y productos (/api/export).
En el celular (diseño mobile-first con barra inferior):
Salvo la pantalla de ingreso (tomada del sitio en producción), las capturas se tomaron con la app corriendo en local contra PostgreSQL 16 + PostgREST, después de aplicar supabase-schema.sql y todas las migraciones del repositorio, con datos 100 % ficticios: negocios inventados ("Casa Pantufla Demo", "Moto Repuestos Demo", etc.), clientes y teléfonos de ejemplo. Las respuestas del modelo de lenguaje vinieron de un stub local de la API de OpenAI; la validación contra inventario y las búsquedas las hizo el servidor real de la app. Ninguna captura contiene datos de clientes reales. En las del celular, el negocio de ejemplo tenía siete opciones de menú, y la captura de Agentes es un recorte de esa pantalla.
flowchart LR
U["Navegador<br/>Next.js App Router<br/>mobile-first"]
N["Next.js en Vercel<br/>proxy.ts + rutas /api"]
DB[("Supabase<br/>PostgreSQL + RLS")]
AI["OpenAI<br/>gpt-4o-mini"]
TR["Transportadora<br/>Interrapidísimo o sandbox"]
ST["Stripe<br/>opcional"]
CR["Vercel Cron"]
U -- "cookie httpOnly con JWT de sesión" --> N
U -- "supabase-js con guard por tenant<br/>y JWT con tenant_id" --> DB
N -- "service role acotado al tenant" --> DB
N -- "prompts con respuesta JSON" --> AI
N -- "guías y tracking" --> TR
N -- "checkout y webhook" --> ST
CR -- "agentes y purga de rechazados" --> N
supabase-js.src/app/api/* para lo que no debe hacerse desde el navegador: IA, login, administración, plataforma, facturación, transportadora, importación y exportación, y crons.supabase-schema.sql y los cambios en 17 migraciones incrementales (migrations/, de la 002 a la 018).Cada fila de negocio lleva tenant_id, y el aislamiento tiene tres capas:
withTenant): envuelve el cliente de Supabase para que toda consulta a una tabla de negocio se filtre por el tenant y todo insert inyecte su tenant_id. En el servidor el tenant se resuelve en cada request desde la sesión (tenantServer.ts); sin sesión válida, la ruta responde 401.SUPABASE_JWT_SECRET configurada, el servidor firma para el navegador un JWT con el claim tenant_id y las políticas exigen tenant_id = jwt_tenant_id(). Las tablas tenants, users, charges, alerts y audit_log no tienen política para la llave anónima: solo el servidor las lee.La marca y la configuración de cada negocio (nombre, logo, colores, categorías, módulos, etiquetas del menú y prompt de IA) parten de tenants.config.ts y se pueden sobrescribir por negocio en la columna tenants.config (jsonb, migración 012). Un negocio creado en caliente arranca con una configuración genérica neutra.
jose en la cookie httpOnly koptup-session (30 días) y contraseñas con bcrypt (auth.ts).users: un usuario desactivado o no aprobado pierde la sesión y siempre rige su rol actual.proxy.ts redirige a /login las rutas protegidas sin cookie, y cada rol aterriza en su pantalla de inicio.| Tabla | Para qué |
|---|---|
tenants | Negocios: plan, licencia, estado, origen (manual o auto-registro), código de invitación, config y transportadora |
users | Usuarios por negocio con rol y estado de aprobación |
products | Catálogo: código, costo, precio, categoría, proveedor e imagen |
inventory | Stock por canasta y variante, estado Bueno/Malo y proveedor de ingreso |
orders | Un pedido por fila: cliente, detalle, montos, pagos, estado/fase, envío, guía y tracking, proveedor y costo congelados |
suppliers | Proveedores con plazo de pago y día de corte |
expenses | Gastos del negocio por categoría |
settings | Ajustes por negocio (p. ej. la API key de IA propia) |
charges | Pagos de licencia, con índice único por evento de Stripe |
alerts | Alertas persistidas de los agentes |
audit_log | Bitácora de acciones sensibles |
sequenceDiagram
actor P as Persona
participant UI as Chat en el navegador
participant API as /api/ai/parse-order
participant LLM as OpenAI gpt-4o-mini
participant DB as Supabase
P->>UI: Pega el mensaje de WhatsApp o lo dicta
UI->>API: Mensaje y contexto de la conversación
API->>DB: Catálogo e inventario en stock del negocio
API->>LLM: Prompt del negocio con el catálogo en stock
LLM-->>API: JSON con cliente, valor y líneas de producto
API->>API: decideClarification valida datos y variantes
alt Falta un dato o la variante no está en stock
API-->>UI: Pregunta concreta con las opciones disponibles
P->>UI: Responde y se repite el ciclo
else Pedido completo
API-->>UI: Pedido normalizado para confirmar
P->>UI: Confirmar
UI->>DB: Inserta el pedido con código único por negocio
end
El monto se normaliza en el servidor (no se confía en el número que devuelve el modelo), y si la respuesta del modelo llega cortada o no es JSON válido, el usuario recibe un mensaje en lugar de un error.
npm run validate (scripts/validate.mjs) es la verificación previa al despliegue: tsc, ESLint, pruebas unitarias, estructura de las migraciones, políticas de seguridad (RLS declarada, sin llaves embebidas en el código, AUTH_SECRET documentada), que las rutas API usen el cliente acotado al tenant y, de forma opcional, las pruebas E2E (--e2e). Si algo falla, termina con código distinto de 0.
| Capa | Tecnología |
|---|---|
| Frontend | Next.js 16 (App Router, Turbopack), React 19, TypeScript 5 |
| Estilos | Tailwind CSS 4, íconos lucide-react, manifest PWA |
| Datos | Supabase: PostgreSQL + PostgREST + RLS (@supabase/supabase-js) |
| IA | OpenAI gpt-4o-mini (texto e imagen) con respuestas en JSON |
| Voz | Web Speech API del navegador (es-CO) |
| Autenticación | JWT propio con jose + bcryptjs |
| Gráficas | Recharts |
| Excel y QR | exceljs, qrcode |
| Pagos | Stripe (suscripciones, opcional) |
| Pruebas | Vitest + happy-dom (unitarias), Playwright (E2E) |
| Despliegue | Vercel + Vercel Cron |
.nvmrc con la versión 20).git clone https://github.com/ronalc90/koptup-comercio-electronico.git
cd koptup-comercio-electronico
npm ci
cp .env.example .env.local
Completa .env.local (el propio .env.example explica cada variable):
| Variable | ¿Obligatoria? | Para qué sirve |
|---|---|---|
NEXT_PUBLIC_SUPABASE_URL | Sí | URL del proyecto de Supabase |
NEXT_PUBLIC_SUPABASE_ANON_KEY | Sí | Llave anónima de Supabase |
SUPABASE_SERVICE_ROLE_KEY | Sí | Operaciones del servidor (login, administración, plataforma, crons). Sin ella, el servidor usa la llave anónima y esas rutas fallan |
AUTH_SECRET | En producción | Firma los JWT de sesión; mínimo 32 caracteres (openssl rand -hex 32) |
SUPABASE_JWT_SECRET | Sí, si aplicas la migración 003 | JWT secret del proyecto: el servidor firma con él el token con tenant_id que usa el navegador para pasar la RLS estricta |
OPENAI_API_KEY | No | IA global; cada negocio puede poner la suya en Configuración |
CRON_SECRET | No | Autoriza los crons de Vercel |
SUPABASE_ACCESS_TOKEN | No | Solo para aplicar SQL con npm run db:exec |
STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, STRIPE_PRICE_PRO, STRIPE_PRICE_ENTERPRISE | No | Cobro en línea de licencias. Sin ellas, el pago queda desactivado |
El código también lee
SHIPPING_ENC_KEYySHIPPING_WEBHOOK_SECRET(integración con transportadora) yAUTH_STRICT_SECRET(hace que la app no arranque en producción siAUTH_SECRETes débil). Aún no están en.env.example; agrégalas si usas esas funciones.
En el SQL Editor de Supabase ejecuta supabase-schema.sql y después, en orden, los archivos de migrations/ (de 002_multi_tenant.sql a 018_supplier_intake_order_phases_shipping.sql). Las migraciones están escritas para poder re-ejecutarse sin romper nada. La 003 activa la RLS estricta por negocio: a partir de ella el navegador solo lee datos si SUPABASE_JWT_SECRET está configurada. Si prefieres la terminal, con SUPABASE_ACCESS_TOKEN en .env.local:
npm run db:exec supabase-schema.sql
npm run db:exec migrations/002_multi_tenant.sql
# … y así hasta la 018
Opcionalmente, scripts/seed-bodega-demo.sql crea un negocio de demostración con proveedores, productos, inventario y pedidos.
Seguridad: la migración 002 y el seed de demostración crean usuarios iniciales cuyas contraseñas aparecen en el propio SQL. Cámbialas o desactiva esos usuarios antes de exponer cualquier entorno.
npm run dev # http://localhost:3000
Para un build de producción: npm run build && npm run start. También hay Dockerfile y docker-compose.yml que levantan npm run dev en un contenedor usando .env.local.
| Comando | Qué hace |
|---|---|
npm run dev | Servidor de desarrollo |
npm run build / npm run start | Build de producción y servirlo |
npm run lint | ESLint |
npm run typecheck | tsc --noEmit |
npm test / npm run test:watch | Pruebas unitarias (Vitest) |
npm run test:e2e:install / npm run test:e2e | Instalar Chromium para Playwright y correr las E2E |
npm run validate | Gate de validación previo al despliegue |
npm run db:exec <archivo.sql> | Ejecutar SQL en Supabase mediante la Management API |
Unitarias (Vitest). Viven junto al código (*.test.ts) y cubren la lógica pura: aclaración de pedidos, fases, permisos, planes, facturación, agentes, automatizaciones, cálculos de proveedores, transportadora, JWT de Supabase, registro, rate limit y utilidades. Al momento de escribir esto son 289 pruebas en 26 archivos, todas en verde.
npm test
E2E (Playwright). Smoke de login y redirecciones, navegación autenticada, modales de ayuda, la vista de pedidos, el flujo conversacional de "Pedido IA" (con la ruta de IA simulada) y los reportes de proveedores. Las pruebas autenticadas se omiten si no hay credenciales.
npm run test:e2e:install # solo la primera vez
MERAKI_E2E_USER=<usuario> MERAKI_E2E_PASSWORD=<contraseña> npm run test:e2e
# Contra un despliegue ya publicado:
MERAKI_E2E_BASE_URL=https://<tu-deploy>.vercel.app npm run test:e2e
Sin MERAKI_E2E_BASE_URL, Playwright compila y levanta la app con npm run build && npm run start.
El sitio corre en Vercel: https://koptup-comercio-electronico.vercel.app.
SUPABASE_SERVICE_ROLE_KEY y AUTH_SECRET).vercel.json programa dos crons, que se autorizan con CRON_SECRET:
/api/cron/run-agents: todos los días a las 08:00 UTC, ejecuta los agentes y guarda las alertas./api/cron/purge-rejected: todos los días a las 03:00 UTC, borra los registros rechazados hace más de 30 días./api/billing/webhook (guía) y el de la transportadora a /api/shipping/webhook.main suma más de 130 commits entre abril y julio de 2026.tsc, ESLint y las 289 pruebas unitarias pasan, y las pantallas de las capturas funcionan contra una base local con todas las migraciones aplicadas.npm run validate marca hoy un fallo en el chequeo 6: cuatro rutas recientes (auth/register, orders/phase, orders/tracking y shipping/webhook) usan el service client con filtro manual por tenant y aún no están en la lista de excepciones del gate.docs/ROADMAP.md.docs/ARCHITECTURE_MULTITENANT.md: arquitectura multi-tenant, modelo de amenaza y ruta de endurecimiento.docs/RUNBOOK_HARDENING.md: procedimientos de seguridad y tabla de permisos por rol.docs/STRIPE_SETUP.md: cómo configurar los pagos.docs/ROADMAP.md: fases del producto.PROVEEDORES_ENTREGA.md: diseño y entrega del módulo de proveedores.AGENTS.md: esta versión de Next.js trae cambios importantes; antes de programar, consulta node_modules/next/dist/docs/.Ronald Cipagauta