Caso de estudio · Producto e ingeniería
Alcorte Alemán
Operar una carnicería de 50 años a través de WhatsApp
Arquitecto e ingeniero único · Definición de producto, diseño del sistema, implementación, incorporación del operador
Fase 0 cerrada, Fase A1 en curso
Un sistema de gestión de pedidos con IA diseñado en torno a una sola restricción: el operador nunca abrirá un panel.
De un vistazo
- Cliente
- Alcorte Alemán — carnicería familiar, Ciudad de México, más de 50 años de operación
- Rol
- Arquitecto e ingeniero único — definición de producto, diseño del sistema, implementación, incorporación del operador
- Escala
- Más de 120 productos en catálogo, más de 1000 clientes
- Problem
- Digitalizar la toma de pedidos y la operación diaria sin pedirle a un operador de toda la vida que cambie su forma de trabajar
- Enfoque
- WhatsApp como la interfaz completa — para los clientes y para el dueño del negocio
- Stack
- WhatsApp Business API → Meta webhooks → Vercel (Next.js) → Anthropic Claude → Supabase (Postgres + RLS)
- Status
- Fase 0 cerrada, Fase A1 en curso. Pipeline de extremo a extremo en producción; conjunto de herramientas del operador validado contra datos reales
- Repository
- Privado, con 2FA obligatorio. Producción en Vercel
El problema
La mayoría del software para pequeños negocios falla del mismo modo: da por hecho que el dueño aprenderá una interfaz nueva. El dueño lleva más de cincuenta años al frente de esta carnicería. Conoce sus productos, sus márgenes, su clientela habitual y sus proveedores mejor de lo que podría hacerlo cualquier sistema. Lo que no tiene es una hora al día para aprender un panel de administración — y cerca de una hora diaria es el techo honesto del tiempo que puede dedicar a interactuar con cualquier sistema.
El negocio recibe un volumen moderado de pedidos diarios, sobre todo de personas que cocinan en casa y ocasionalmente de restaurantes. Los pedidos llegan por teléfono y por mensaje de WhatsApp. Nada queda registrado. Los precios viven en la cabeza del dueño y en hojas escritas a mano. Los tiempos de entrega se estiman por intuición. Funciona — hasta que deja de escalar, o hasta que la única persona que tiene el conocimiento no está disponible.
La solución obvia es un panel web con una cola de pedidos y un catálogo de productos. La solución obvia habría quedado abandonada en una semana.
El replanteamiento
Invertí el requerimiento. En lugar de “construir un panel de administración y enseñarle al dueño a usarlo”, el encargo pasó a ser:
Si el dueño alguna vez tiene que abrir un navegador para operar su negocio, el proyecto fracasó.
WhatsApp no es un canal añadido al producto. Es la superficie del producto — para los clientes que hacen pedidos y para el dueño que configura el sistema. Cambiar un precio, marcar un corte como agotado y pedir el resumen del día ocurren en la misma aplicación de mensajería que ya tiene abierta todo el día.
Esta única restricción determinó cada una de las decisiones de arquitectura que siguen.
Principios de diseño
Quedaron fijados antes de escribir una línea de código, y cada decisión posterior se contrastó contra ellos.
Configuración WhatsApp-first
Toda configuración del sistema debe poder modificarla el operador con un mensaje de chat. Esto se apoya en una tabla vendor_settings en lugar de variables de entorno o configuración fija en el código — si un valor puede cambiar, debe poder cambiarse desde un teléfono.
Lenguaje operativo, nunca jerga estratégica
El sistema le habla al dueño como lo haría un buen empleado: en términos concretos y del día a día. Nunca “tasa de conversión”, “ROI” ni “NPS”. “Diecisiete pedidos hoy, faltan tres por entregar” es una frase sobre la que puede actuar. “Tasa de cumplimiento 82 %” no lo es.
Nunca inventar datos del negocio
El bot no debe afirmar un precio, una zona de entrega ni un dato de la historia del negocio que no pueda respaldar con la base de datos. Esto se aplica como restricción dura en el system prompt, no como recomendación — un precio equivocado que suena plausible es peor que ninguna respuesta, porque se convierte en una promesa que el negocio tiene que cumplir.
Automatización sólo después de lo manual
Nada corre sin supervisión hasta que los datos lo justifiquen. El modo automático se habilita sólo cuando se acumula señal de alta confianza; todo paso automatizable se entrega primero como un botón que alguien presiona.
Sincronizar la preparación con la llegada
La carne preparada demasiado pronto se deteriora; preparada demasiado tarde retiene al repartidor. Los cálculos de tiempo son realistas en lugar de optimistas, y se acompañan de comunicación proactiva cuando se desfasan.
Aprendizaje pasivo a partir de las escalaciones
Cada vez que el sistema entrega una conversación a una persona, ese intercambio se convierte en conocimiento recuperable (RAG) en lugar de un fallo desechado. El sistema mejora como subproducto de su uso, sin un flujo de etiquetado que alguien tenga que mantener.
Diseñar temprano la arquitectura contable, implementarla tarde
La facturación fiscal mexicana (CFDI) es un problema resuelto en teoría y doloroso en la práctica, y la decisión entre autofacturación y un contador externo no me corresponde. El esquema la contempla; la funcionalidad espera.
Arquitectura
vendor_id mediante un helper get_vendor_id(), de modo que el esquema es multi-inquilino desde el primer día. Reconstruido para este caso de estudio.Por qué esta forma
El handler del webhook no tiene estado y corre en Vercel, así que no hay servidor que un equipo de una sola persona deba mantener vivo. El estado vive en Supabase con row-level security por vendor_id — la arquitectura es multi-inquilino desde el primer día aunque atienda a un solo negocio, porque añadir multi-inquilino después es una reescritura y anticiparlo es una cláusula WHERE.
La capa agéntica
En lugar de un clasificador rígido de intenciones, el manejo de mensajes ejecuta un bucle agéntico completo: el modelo recibe el mensaje junto con un UserContext y decide qué herramientas invocar. Esto importa porque los mensajes reales de un carnicero no son comandos bien formados. “El sirloin súbelo a 320” y “ya no hay arrachera” son ambos cambios de configuración, expresados como habla.
Identidad y permisos
El sistema distingue clientes de operadores consultando el número entrante contra una tabla operators, lo que produce un UserContext que acompaña toda la petición. Se exponen seis herramientas, separadas por nivel de permiso:
get_product
search_products
list_products_summary
update_product_price
set_product_availability
get_today_summary
El control de permisos es defensa en profundidad: el conjunto de herramientas que se ofrece al modelo se filtra por contexto y cada herramienta privilegiada revalida a quien la invoca antes de ejecutarse. Confiar sólo en el prompt para que un cliente no cambie precios no es un modelo de seguridad: es una esperanza. Un mensaje de un número desconocido no puede alcanzar una ruta de escritura aunque se convenza al modelo de intentarlo.
Cada cambio de precio escribe en price_history con changed_via: "whatsapp_tool", de modo que una edición hecha por chat es tan auditable como una hecha por cualquier otra interfaz.
La cadena de escalación
La realidad operativa es que el bot no resolverá todo, y el modo de fallo de un asistente de IA sin salida es un cliente frustrado.
- Dueño
- →
- Encargado de turno
- →
- Personal adicional
- →
- dev_backup · no removible
La escalación va dueño → encargado de turno → personal adicional → yo como dev_backup no removible. El operador puede configurar la cadena, con una excepción: el último eslabón no se puede eliminar.
Un sistema que puede configurarse hasta un estado en el que nadie escucha es un sistema que tarde o temprano quedará configurado así.
Lo que se entregó
Fase 0 — cimientos (cerrada)
- Tabla
vendor_settingscon diez valores por defecto, entregada como migración001_vendor_settings.sql, siguiendo el patrón de RLS existente en lugar de introducir un segundo. - Integración con la Meta WhatsApp Business API mediante un token permanente de System User acotado a
whatsapp_business_messagingywhatsapp_business_management. - Pipeline de extremo a extremo confirmado en producción: WhatsApp → Meta → Vercel → Claude → WhatsApp.
Fase A1 — herramientas del operador (en curso)
- Seis herramientas agénticas con el bucle completo, resolución de identidad vía
UserContexty el control de permisos descrito arriba. - Tres pruebas de validación, todas aprobadas contra infraestructura real en lugar de mocks:
- Identificación del operador por consulta de número telefónico
- Consulta en vivo del precio de un producto contra Supabase
- Modificación de precio con audit trail confirmado en
price_history
Artefacto de incorporación del operador
Llevar cincuenta años de conocimiento del negocio no documentado a una base de datos es un problema de entrevista, no de ingeniería. Produje cinco documentos de entrevista en PDF estructurados para el dueño, con un sistema de codificación de tres colores:
- Verde — borradores de respuesta que yo había prellenado, para que él confirmara o corrigiera
- Ámbar — datos propios del negocio que sólo él conoce, en blanco de forma deliberada
- Gris — datos internos de precios excluidos a propósito de la base de conocimiento del bot
Prellenar los campos verdes convirtió una tarea de página en blanco en una tarea de revisión. Marcar explícitamente los campos grises hizo que la frontera entre “el bot puede decir esto” y “esto es interno” fuera una decisión tomada una sola vez, en papel, en lugar de rediscutirse en cada revisión del prompt.
Problemas de ingeniería que vale la pena describir
Un solo carácter invisible tumbó la autenticación
La integración con la API fallaba con errores de autenticación aunque la credencial era, a simple vista, correcta. La causa fue un carácter Unicode no imprimible (clase U+2028) introducido al copiar y pegar en la variable de entorno. Sobrevivió a toda revisión visual porque es, por definición, invisible. Solución: sanear las credenciales antes de pasarlas a cualquier constructor de un SDK — .replace(/[^\x21-\x7E]/g, '') — y tratar la higiene de las variables de entorno como un asunto de primer orden y no como un detalle posterior de configuración. La lección general: cuando una credencial es “evidentemente correcta” y aun así falla, deje de leerla y empiece a inspeccionar sus bytes.
Los tokens temporales son una trampa que uno mismo se tiende
El segundo error bloqueante fue un token de la API de WhatsApp expirado — el resultado habitual de seguir una guía de inicio rápido. Un token permanente de System User con activos y permisos asignados explícitamente hay que configurarlo de forma deliberada, y el costo de no hacerlo es un sistema que funciona en desarrollo y muere en silencio en producción, semanas después, en el peor momento.
El filtrado de arreglos en Postgres tiene aquí exactamente una forma correcta
Los alias de producto se almacenan como text[] (un corte de carne tiene muchos nombres, y los clientes los usan todos). El filtrado requiere aliases.cs.{value} dentro de una sola llamada .or() — encadenar dos llamadas .or() produce una consulta que se ve correcta y devuelve resultados equivocados. Decisiones de esquema relacionadas que moldearon las herramientas: base_unit es un enum unit_type, el borrado lógico usa deleted_at, y los cambios de disponibilidad deben escribir tanto availability_updated_at como availability_updated_by para preservar la integridad de la auditoría.
Las barreras de seguridad van en el system prompt, no en la base de conocimiento
Dos restricciones se elevaron deliberadamente de “contenido” a “regla dura”: nunca dar consejo médico ni nutricional; y las decisiones de crédito o fiado son una regla de negocio estructurada, ligada a customers.credit_limit_cents, y no algo que el bot recite desde texto libre. Una carnicería que da crédito informal sostiene con ello una relación comercial real y de peso. Equivocarse cuesta dinero y confianza, así que la regla se aplica en el código y en el esquema, no en lenguaje que se le pide recordar al modelo.
Cómo se organizó el trabajo
El proyecto corre sobre tres canales deliberadamente separados, porque mezclarlos degrada los tres:
- Canal de arquitectura — estrategia, definición de fases y decisiones de diseño abiertas. Lento, por escrito, con las decisiones registradas.
- Canal de depuración — diagnóstico de errores, lectura de capturas de pantalla, correcciones a nivel de código. Rápido, desechable.
- Ejecución local — Claude Code sobre el repositorio.
Las sesiones de planeación preceden a la construcción y las fases se definen formalmente antes de empezar la implementación. El trabajo avanza en pasos revisables y sujetos a aprobación, con puntos de verificación por captura de pantalla, no en lotes de código sin revisar.
Roadmap
- A2.1
- Bot de cara al cliente
- A2.2
- Inteligencia y observabilidad — análisis de embudo, registro de conversaciones
- A3
- Costos, márgenes, estadísticas
- Operación
- Operación diaria en vivo con la cadena de escalación configurable
- Decisión
- Punto de control estratégico tras 3–6 meses de datos reales, presentado en términos operativos
- Logística
- Integración de reparto externo (Uber Direct, iVoy, Rappi Cargo) detrás de una abstracción Provider, primero manual mediante botones en el panel
- B
- IA de voz — Vapi.ai como opción principal, ElevenLabs en evaluación. El dueño aceptó grabar su voz para clonarla
- C
- Comercio electrónico completo
- D
- Contabilidad — pendiente de la decisión del contador sobre la autofacturación CFDI
La fase Decisión es la que señalaría como la marca del diseño. Hay un punto de control, meses adelante, en el que se revisan los datos acumulados y la hoja de ruta puede cambiar de dirección — y los materiales de esa revisión se especifican desde ahora en términos operativos, porque una presentación estratégica llena de gráficas de embudo sería un documento que la persona a la que va dirigido no puede usar.
Lo que demuestra este proyecto
Arquitectura guiada por la restricción
“Sin panel” no es una limitación que haya que sortear; es la especificación. Tomarla en serio produjo un sistema más limpio que la versión que se habría cubierto con un panel de administración web que nadie abre.
Disciplina de integración en producción
WhatsApp Business API, el modelo de tokens de Meta, Vercel, Supabase RLS y un modelo con tool calling, conectados de extremo a extremo y validados contra datos en vivo — incluidos los fallos poco vistosos (caracteres invisibles, tokens que expiran) que separan una demo de algo que funciona un martes por la mañana.
Seguridad como estructura, no como instrucción
Los permisos se aplican mediante filtrado por contexto y validación en cada herramienta. Los audit trails los escribe la propia ruta de escritura. El modelo nunca es la última línea de defensa.
Diseñar en serio para un operador no técnico
PDFs de entrevista codificados por color, vocabulario operativo, un respaldo de escalación no removible y la decisión explícita de posponer la contabilidad hasta que opine el contador. Lo difícil de este proyecto nunca fue el bucle de tool calling.
Construir para un negocio que ya funciona
Un negocio de cincuenta años no necesita que lo disrumpan. Necesita que las partes que viven en la cabeza de una sola persona se vuelvan duraderas, sin cambiar la forma en que esa persona trabaja. Ese es un problema más acotado y más interesante que partir de cero.