Gestión de pedidos, inventario y despachos
Translation pending
CommerceTypeScript · PLpgSQLGitHub @ronalc90OnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
The maker's introduction consists of the line above. Read the repository README for more details. Repository README ↗
Loading the full README.
Read the full 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