Manual de arquitectura

perla

Cómo está construido el producto. Documento vivo para el equipo que lo está levantando. Ocho secciones: un mapa, una introducción y seis capítulos.

v1 · Abril 2026 8 secciones multi-tenant · agente · WhatsApp
00 El Plan
00

El Plan

Este es el primer documento que cualquier integrante del equipo debería leer antes de entrar al manual. Es el mapa que explica cómo está pensada la arquitectura de PERLA, por qué está dividida así, y dónde encontrar cada cosa.

La metáfora: pensar el producto como una obra

Construir PERLA es como construir un edificio. No alcanza con tener una buena idea visual ni con conocer los materiales: hay que poder explicar cómo se traduce esa idea en planos, instalaciones, sistema constructivo, especificaciones técnicas y cronograma de obra. Cada capa tiene su lenguaje y su responsable, pero todas hablan del mismo proyecto.

Por eso este manual está dividido en seis capítulos, cada uno equivalente a una capa de un proyecto de arquitectura. Un capítulo no se entiende del todo sin los anteriores, pero cada uno tiene autonomía suficiente para que el responsable de ese frente pueda trabajarlo sin tener que leer todo el resto cada vez.

Por qué construimos así (la apuesta)

PERLA no es un asistente de turnos para un negocio individual. Es la apuesta opuesta a la del mercado actual: mientras la competencia (Lidia, AgentlyX, TurnoFácil, entre otras) vende automatizaciones personalizadas a cada cliente por entre $40.000 y $100.000 ARS por mes, PERLA propone una inteligencia central compartida que cualquier negocio puede contratar por una fracción de ese precio. La economía estimada es de tipo comodity (USD 10-20 por mes por negocio) con margen 4-6× sobre el costo operativo (estimado en USD 50/mes para 1000 turnos agendados).

Esa apuesta de modelo determina toda la arquitectura que viene después. Un sistema multi-tenant real, un agente único compartido entre todos los negocios, un contrato de herramientas estable, una base de datos aislada por tenant — cada decisión técnica del manual existe para sostener esa apuesta. Si cambiara el modelo (por ejemplo: ofrecer instancias dedicadas tipo premium), la arquitectura tendría que cambiar con él. Por eso este párrafo debería leerse antes de los capítulos: explica el por qué antes que el cómo.

Estructura del manual

ArchivoRolQué resuelveEstado
01_ARQUITECTURAIntroducciónVocabulario común, principios de diseño, vista panorámica, cómo leer el manualescrito
02_PROGRAMACapítulo 2 — ProgramaDefine los cuatro perfiles que usan PERLA y qué puede hacer cada unoescrito
03_CIRCULACIONESCapítulo 3 — Plantas y circulacionesCómo el sistema identifica al tenant, al rol y a la conversación en cursoescrito
04_INSTALACIONESCapítulo 4 — InstalacionesDefine las entidades del producto y cómo se relacionanescrito
05_CONSTRUCCIONCapítulo 5 — Sistema constructivoDefine el stack técnico, infraestructura, permisos y observabilidadescrito
06_PLIEGOSCapítulo 6 — Legajo EjecutivoContratos formales: herramientas del agente, system prompts, adaptersescrito
07_CRONOGRAMACapítulo 7 — Cronograma y oficiosRoles, decisiones, cadencia y proceso del equipoparcial

La asignación de personas a cada capítulo se define en el Capítulo 7, no en este índice. Acá solo aparecen los frentes; quién toma cada uno se discute en equipo.

Orden de dependencia

Los capítulos no son una lista plana: cada uno apoya en los anteriores. El orden lógico de construcción es:

Programa  →  Instalaciones  →  Circulaciones  →  Legajo  →  Construcción  →  Cronograma
(quiénes)    (qué existe)      (cómo entran)     (cómo hablan) (con qué)      (cuándo)

Se pueden trabajar en paralelo si hay distintos interlocutores en distintos frentes. Cada capítulo tiene un perfil de oficio asociado:

  • Programa se cierra con quien tenga estudiados los flujos conversacionales reales del usuario
  • Instalaciones se cierra con quien lleve la base de datos
  • Construcción se cierra con quien sea responsable del repo de producción
  • Circulaciones, Legajo y Cronograma se cierran al final, con el feedback que vino de los otros tres frentes

Lo que el manual NO incluye

PERLA tiene varias capas más allá de su arquitectura técnica. Algunas ya están cerradas y solo se referencian; otras están en construcción y viven en otros documentos. Ninguna entra al manual porque mezclaría lenguajes y responsabilidades.

TemaDónde vivePor qué afuera
Marca y voz_Deploy_PERLA_BRAND_GUIDE/Ya cerrada. Es del producto, no de la construcción.
Modelo de negociopendientePricing, costos, GTM. Es del producto.
Casos de uso conversacionales01_INFRA/SPEC_v0.mdEs input para el Capítulo 2, no parte del manual.
Roadmap operativo01_INFRA/INFRA_A4.mdEs operativo, no estructural. Cambia mes a mes.

Reglas del manual

  • Cada capítulo es un solo archivo canónico. Si cambia, se versiona con sufijo _v2, _v3. Las versiones anteriores se guardan en _versions/.
  • Cuando un capítulo se considera cerrado, pasa a "ley del proyecto" y solo cambia con discusión explícita del equipo.
  • Si un capítulo necesita citar a otro, se cita explícito ("según Capítulo 3, sección 2") y no se duplica información.
  • Las seis capas del manual son fijas. Si surge contenido nuevo, se ubica como sub-sección dentro del capítulo que corresponda. No se inventa un capítulo extra.
  • Toda mención al sistema usa la palabra agente, nunca bot. La distinción es deliberada y se explica en la introducción.

Estado actual del producto

Agente Nanatka v2.0 funcionando en n8n.ticketsport.com.ar · dos tenants reales (SURI, NUDO) · canal Telegram operativo · canal WhatsApp pendiente · siete issues conocidos documentados en STATE.md.

01 Arquitectura — introducción
01

Arquitectura — introducción

Sobre este manual

Este manual describe cómo está construido PERLA, no qué es ni a quién se vende. Es el mapa que necesitamos los seis para hablar el mismo idioma cuando discutimos producto, código, base de datos o estrategia.

Está organizado en seis capítulos, cada uno en un archivo independiente. Cada capítulo responde a una pregunta distinta sobre el sistema. Se pueden leer en orden o saltar al que corresponde según en qué frente esté trabajando cada uno.

Una nota sobre vocabulario

En este manual — y en todos los documentos del proyecto — hablamos de agente, no de bot.

La distinción es deliberada. Un bot es una automatización rígida que sigue un árbol de decisiones predefinido. Un agente es una inteligencia que entiende intención, decide qué herramientas usar y conduce una conversación con criterio. PERLA es lo segundo. Esa diferencia es la apuesta central del producto y se sostiene en cada decisión técnica que viene a continuación.

Otras dos palabras que aparecen en todo el manual y conviene fijar acá:

  • Tenant — cada negocio individual registrado en PERLA. Una peluquería, una clínica de estética, un consultorio. PERLA es multi-tenant: una sola plataforma atiende a muchos tenants simultáneamente, manteniendo sus datos completamente aislados entre sí.
  • Paciente — la persona que recibe el servicio, sea en una clínica, una peluquería, un consultorio o un centro de estética. No implica que PERLA sea solo para salud. La palabra se sostiene porque captura mejor que "cliente" la naturaleza de la interacción (alguien que reserva tiempo con un profesional para recibir atención personal).

Principios de diseño

Cinco decisiones que están detrás de cada parte del manual. Si en algún momento se discute una sub-decisión técnica, primero hay que verificar si choca con alguno de estos principios. Si choca, se discute el principio explícitamente. Si no, se respeta.

  1. Agente, no bot. El sistema usa function calling sobre herramientas, no un árbol de decisiones predefinido. El loop de invocación de herramientas es ilimitado, no tope de dos rondas.
  2. Un núcleo, N tenants. Multi-tenant real con aislamiento a nivel de base de datos. El identificador de sesión combina tenant y teléfono. Nunca se levanta una instancia separada por negocio.
  3. El contrato son las herramientas. El agente no sabe consultas SQL ni protocolos de canal. Solo sabe invocar herramientas con un contrato definido. Cambiar de canal (Telegram a WhatsApp), de modelo de IA o de base de datos no debería tocar al agente.
  4. El prototipo valida, la producción robusta produce. El prototipado y la validación rápida de hipótesis se hacen en herramientas de bajo nivel de fricción (hoy: n8n). La producción robusta vive en código (hoy: TypeScript con Cloudflare Workers). Nunca al revés.
  5. Doble entrada, mismo agente. El sistema atiende a pacientes y a owners con el mismo agente, distinguidos en el routing (no son dos sistemas distintos). Las herramientas con permisos elevados (cancelar, reprogramar, modificar configuración) confirman siempre antes de ejecutar.

Vista panorámica

Para tener una imagen mental rápida del sistema completo:

  Canal (WhatsApp / Telegram)
          │
   ┌──────▼──────┐
   │   ENTRADA   │  recibe el mensaje del usuario
   │  + ROUTING  │  resuelve tenant + rol + estado de conversación
   └──────┬──────┘
          │
   ┌──────▼──────┐
   │   AGENTE    │  cerebro · entiende intención · decide qué hacer
   │             │  loop ilimitado de invocaciones a herramientas
   └──────┬──────┘
          │  function calling
   ┌──────▼──────┐
   │ HERRAMIENTAS│  contrato cerrado · interfaz entre agente y datos
   │             │  consultar disponibilidad · agendar · cancelar · reprogramar
   └──────┬──────┘
          │
   ┌──────▼──────┐
   │    DATOS    │  base aislada por tenant (multi-tenant)
   │             │  transacciones seguras · agenda como tabla, no como calendario
   └─────────────┘

Cada uno de los cinco bloques de este diagrama tiene su lugar en el manual:

  • Entrada + Routing vive en el Capítulo 3 (Plantas y circulaciones)
  • Agente y Herramientas se especifican en el Capítulo 6 (Legajo Ejecutivo)
  • Datos se describen en el Capítulo 4 (Instalaciones)
  • La infraestructura completa que sostiene los cinco bloques está en el Capítulo 5 (Sistema constructivo)
  • Quiénes consumen todo este sistema se describe en el Capítulo 2 (Programa)

Cómo leer este manual

Para entender el manual alcanza con leer las descripciones que cada capítulo abre. Para implementar lo que cada uno define hace falta abrir los anexos técnicos (tool contracts, schemas, prompts, etc).

Cada capítulo está escrito en tres partes:

  1. Una pregunta-gancho que abre el capítulo y resume qué problema se está resolviendo.
  2. Una descripción del concepto, con suficiente detalle para que un miembro del equipo no técnico pueda seguirla.
  3. Tres aclaraciones operativas: qué incluye el capítulo, qué deliberadamente no incluye, y por qué importa para el resto del sistema.

Cuando un capítulo se considera cerrado, pasa a ser "ley del proyecto" y solo cambia con discusión explícita del equipo. Las versiones anteriores quedan archivadas en _versions/.

Lo que el manual NO describe

Las decisiones de marca (cómo se ve, cómo habla), las decisiones de negocio (cuánto sale, a quién se vende) y los casos de uso conversacionales específicos viven en otros documentos. Acá hablamos solo de cómo está hecho. El mapa completo de qué está adentro y qué está afuera vive en la sección 00 · El Plan.

02 Programa
02

Programa

¿Quiénes usan PERLA y qué hacen adentro?

Antes de pensar en código, base de datos o flujos, necesitamos un mapa claro de las personas que interactúan con el sistema. PERLA no es un producto con un solo tipo de usuario: tiene cuatro perfiles distintos, cada uno con sus propios objetivos, su propia manera de entrar al sistema y su propia conversación con él.

Este capítulo define esos cuatro perfiles, qué puede hacer cada uno, qué no puede hacer, y cómo es la experiencia desde su lado. Es el punto de partida de todo el resto: las funciones que el agente tenga que cumplir, las pantallas que necesitemos mostrar y las reglas del sistema se derivan directamente de acá.

Los cuatro perfiles

PERLA convive con cuatro perfiles distintos. Tres son personas reales (paciente, owner, equipo de El Nudo) y uno es una superficie técnica (dashboard). Cada perfil tiene su propia lista de cosas que puede y no puede hacer, su propia manera de entrar al sistema, y sus propios casos límite que el sistema tiene que resolver con criterio.

Una aclaración de vocabulario antes de avanzar: decimos "paciente" como término genérico para la persona que recibe el servicio, sea en una clínica, una peluquería, un consultorio o un centro de estética. No implica que PERLA sea solo para salud. La palabra se sostiene porque captura mejor que "cliente" la naturaleza de la interacción.

1. El paciente

Es la persona que llega buscando un turno o información sobre un servicio. No sabe — ni le importa — que detrás hay tecnología compartida con otros negocios. Su relación con PERLA es a través de un solo canal: WhatsApp.

Qué puede hacer

  • Consultar qué servicios ofrece el negocio y detalles sobre los mismos (en caso de querer profundizar)
  • Pedir una recomendación describiendo el problema que necesita resolver ("me corté el pelo hace una semana, ¿puedo teñirme igual?") y recibir una sugerencia de servicio
  • Consultar la disponibilidad de horarios y profesionales
  • Agendar un turno nuevo
  • Consultar qué turnos tiene agendados
  • Reprogramar o cancelar un turno propio
  • Hacer una consulta que excede el catálogo y obtener una respuesta escalada al owner

Qué NO puede hacer

  • Ver agenda, datos o turnos de otros pacientes
  • Acceder a información financiera o reportes del negocio
  • Modificar servicios, precios o profesionales del negocio
  • Agendar turnos a nombre de otra persona

Cómo entra al sistema

  • Por un link o un código QR que el negocio publica en sus redes, su tarjeta o su local
  • Por un mensaje espontáneo al número de PERLA mencionando con qué negocio quiere comunicarse
  • Por una conversación previa con algún tenant que el sistema retoma automáticamente

Casos especiales

  • Escritura en frío. El paciente llega sin link y sin historial previo. El sistema le pregunta con qué negocio quiere comunicarse y confirma con la dirección física antes de avanzar.
  • Pregunta fuera de scope. El paciente pide algo que el catálogo no contempla. El agente reconoce que no puede responder solo, le avisa al paciente que lo consulta, escala la pregunta al owner por WhatsApp, espera su respuesta, y vuelve al paciente con la respuesta del owner.
  • Mismo paciente, varios negocios. Un paciente puede ser cliente de varios tenants simultáneamente. Cada conversación es independiente: no comparten memoria ni estado.

2. El owner

Es el dueño o dueña del negocio. Necesita gestionar agenda, equipo, servicios, precios y comunicación con sus pacientes. PERLA debe permitirle hacer todo eso desde WhatsApp, con la misma naturalidad con la que le hablaría a una secretaria humana — incluida la posibilidad de operar por audio en lugar de texto.

Qué puede hacer

  • Todo lo que puede hacer un paciente (puede agendarse a sí mismo en su propio gabinete)
  • Consultar la agenda del día, la semana o cualquier rango definido
  • Cancelar turnos en batch ("cancelame todo lo de mañana a la mañana")
  • Bloquear horarios de un profesional ante una ausencia o un imprevisto
  • Modificar o reprogramar el turno de cualquier paciente
  • Agregar, modificar o desactivar servicios y sus precios
  • Agregar o desactivar profesionales y sus disponibilidades horarias
  • Responder consultas escaladas que el agente le derivó desde un paciente
  • Consultar reportes simples del negocio ("¿cuántos turnos tuve esta semana?")

Qué NO puede hacer

  • Ejecutar acciones destructivas sin confirmación explícita previa
  • Acceder a datos de otros tenants
  • Modificar configuración crítica del sistema (lógica del agente, reglas globales)
  • Operar como otro owner

Cómo entra al sistema

  • Por mensaje directo al número de PERLA, sin necesidad de link ni código
  • El sistema lo reconoce por su número de teléfono cruzándolo contra la lista de owners y operadores autorizados de su tenant

Casos especiales

  • Owner como paciente de su propio negocio. La dueña de un salón quiere agendarse un masaje en su propio gabinete. El sistema distingue por contexto: si entró por un link de cliente, modo paciente; si escribió directo al número, modo owner. Si la situación es ambigua, pregunta antes de decidir.
  • Múltiples owners por tenant. Un negocio puede tener más de una persona con permisos de owner u operador. Cada una entra con su propio número y opera con los mismos permisos (o con permisos limitados, si el dueño principal así lo configuró).
  • Confirmación obligatoria. Toda acción que modifique o elimine datos exige confirmación verbal o textual antes de ejecutarse. Si el owner dice "cancelá todo lo de mañana", el agente primero lista los turnos afectados y recién después de un "sí, dale" explícito ejecuta las cancelaciones.

3. El dashboard

No es una persona, es una superficie. Es la ventana web que el owner (o un empleado autorizado) puede usar cuando quiere ver, filtrar o configurar cosas con más detalle del que cabe en una conversación. Es opcional: todo lo que hace el dashboard también lo puede hacer el agente por WhatsApp. La idea no es sustituir al agente sino complementarlo para situaciones donde una pantalla ayuda más que un mensaje.

Para qué sirve

  • Visualizar la agenda con más detalle (vistas por día, semana, profesional)
  • Hacer cambios masivos cómodos (importar listas de servicios, configurar disponibilidades complejas)
  • Ver métricas y reportes con gráficos
  • Configurar reglas de negocio que requieren formularios (templates de mensajes, integraciones, parámetros avanzados)

Para qué NO sirve

  • No es la fuente de verdad. Las acciones se ejecutan en la misma base de datos a la que llega el agente. Lo que se cambia en uno se ve en el otro al instante.
  • No es obligatorio. Un owner puede operar PERLA sin abrir nunca el dashboard.
  • No es para pacientes. El paciente nunca interactúa con el dashboard.

Quién entra

  • El owner del tenant
  • Empleados u operadores autorizados, con permisos definidos por el owner

4. El equipo de El Nudo

Es la organización detrás de PERLA. No usa el sistema desde adentro como si fuera un usuario más: lo opera, lo monitorea y lo mejora desde el backend. Su relación con PERLA es la de quien construye y mantiene la infraestructura.

Qué puede hacer

  • Acceder a logs y métricas de uso del sistema completo
  • Intervenir manualmente cuando algo se rompe (resetear sesiones, corregir datos, escalar a un humano)
  • Configurar parámetros globales que no pertenecen a un tenant en particular
  • Cruzar datos anonimizados entre tenants para mejorar el agente y descubrir patrones de uso
  • Onboardear y desactivar tenants

Qué NO hace

  • No interactúa con el sistema vía WhatsApp como si fuera un owner o un paciente
  • No interviene en conversaciones individuales sin un protocolo claro que defina cuándo y cómo
  • No comparte datos identificables de un tenant con otro

Cómo accede

  • Vía herramientas internas del backend (consola de la base de datos, panel de operaciones, alertas automáticas)
  • Acceso privilegiado a toda la infraestructura del sistema

Lo que este capítulo NO incluye

  • El detalle técnico de cómo se identifica a cada perfil (eso es del Capítulo 3)
  • El listado exhaustivo de cada mensaje posible que puede mandar un paciente (eso vive en SPEC_v0.md)
  • Las funciones específicas que el agente debe ejecutar (eso es del Capítulo 6)

Por qué este capítulo importa

Sin un mapa claro de roles, terminamos construyendo un agente que intenta servir a todos al mismo tiempo y termina sirviendo mal a todos. Cada decisión técnica — desde cómo guardamos las conversaciones hasta qué información pedimos primero — depende de saber a quién le estamos hablando.

03 Plantas y circulaciones
03

Plantas y circulaciones

¿Cómo entra cada persona al sistema y cómo sabemos quién es?

Cuando una persona escribe un mensaje a PERLA, antes de que el agente pueda contestar nada útil, el sistema necesita resolver tres preguntas: a qué negocio le está hablando, con qué rol entra esa persona, y si ya hay una conversación previa que tenemos que retomar. A este conjunto de decisiones lo llamamos routing: el camino que sigue un mensaje desde que llega hasta que el agente lo responde.

Es importante entender desde el principio que el routing no lo decide el agente. Lo decide el código, antes de que el agente vea el mensaje. Esta separación es deliberada y es uno de los principios de diseño de PERLA: las decisiones que pueden resolverse con lógica determinística (consultar una tabla, comparar un código, verificar un permiso) no se delegan al modelo de lenguaje. El agente recibe el mensaje ya con todo el contexto resuelto y se concentra en lo que sí requiere inteligencia: entender la intención de la persona y responderle bien.

Las tres preguntas del routing

El routing resuelve, en orden, tres preguntas independientes pero conectadas:

  1. ¿A qué negocio le está hablando la persona? — el tenant
  2. ¿Con qué rol entra? — paciente, owner u operador autorizado
  3. ¿Hay una conversación en curso que retomar? — el hilo

Las tres tienen que tener respuesta antes de que el mensaje llegue al agente. Si alguna falla, el sistema no avanza al siguiente paso. Se resuelven en este orden porque cada una depende de la anterior: no se puede saber el rol de una persona sin saber a qué tenant le habla, ni se puede retomar una conversación sin saber a qué tenant pertenece.

1. ¿A qué negocio le está hablando la persona?

PERLA tiene un solo número de WhatsApp para todos los tenants. Cuando alguien escribe, el sistema tiene que averiguar a qué negocio se está dirigiendo antes de poder hacer nada útil. Hay tres caminos posibles, en orden de prioridad:

Camino 1 — Llegó por un link o un QR

El negocio publica un link en sus redes, su tarjeta o su local. Ese link contiene un código identificador del tenant pre-cargado en el mensaje (por ejemplo: "Hola, vengo por SURI"). Cuando el sistema recibe el mensaje, detecta el código en el texto y resuelve el tenant de forma inmediata. Es el camino preferido porque elimina toda ambigüedad.

Camino 2 — Tiene historial previo

La persona ya conversó antes con algún tenant. El sistema tiene registrado ese hilo y, por defecto, asume que la nueva conversación es continuación de la anterior. Pero asumir es peligroso: una persona puede haber conversado primero con una peluquería, después con una odontóloga, y volver a la peluquería al día siguiente. Antes de avanzar, el sistema confirma: "¿Seguimos con Suri Ecotienda?"

Camino 3 — Escribió en frío

La persona llegó sin link y sin historial. El sistema le pregunta directamente con qué negocio quiere comunicarse. A partir de ahí, la respuesta puede tomar tres formas:

  • Match único — el nombre coincide con un solo tenant registrado. El sistema confirma con la dirección física ("¿Suri Ecotienda, Av. San Martín 887?") y avanza.
  • Match ambiguo — el nombre coincide con varios tenants (dos peluquerías llamadas "Style", una en cada barrio). El sistema lista los candidatos con sus direcciones y le pide a la persona que elija.
  • Sin match — el sistema no encontró ningún tenant que coincida. Le pide el link directo del negocio o algún dato adicional para desambiguar.

La dirección física del local es un verificador clave en todo el camino 3. Sin ella, dos negocios con nombres parecidos pueden generar confusiones irrecuperables.

2. ¿Con qué rol entra esta persona?

Una vez resuelto el tenant, el sistema verifica si el número de teléfono que escribió pertenece a algún owner u operador autorizado de ese tenant. Hay tres situaciones posibles:

El número no aparece en la lista de owners

Es un paciente. Se procesa como tal y el mensaje avanza al agente con permisos de cliente, ni más ni menos.

El número aparece como owner u operador

Acá el rol no se puede decidir solo mirando el teléfono: depende del contexto de la conversación.

  • Si la persona vino por un link de cliente, entra en modo paciente. La dueña que se quiere agendar un masaje en su propio salón probablemente pasó por el link público que compartió con sus clientas.
  • Si escribió directo al número de PERLA sin pasar por un link, entra en modo owner. Está operando su negocio, no consumiéndolo.
  • Si hay ambigüedad, el sistema pregunta antes de decidir: "¿Querés gestionar tu negocio o sacar un turno como clienta?"

El número aparece como operador con permisos limitados

No todos los empleados autorizados son owners completos. Un recepcionista puede tener permisos para ver la agenda y agendar turnos, pero no para modificar precios o desactivar profesionales. El sistema carga los permisos efectivos de esa persona antes de pasarle el control al agente.

3. ¿Hay una conversación en curso que retomar?

Las conversaciones por WhatsApp no son atómicas. Una persona puede mandar un mensaje, esperar una hora, y volver con otro. El sistema mantiene un hilo de conversación asociado a la combinación tenant + teléfono — lo que significa que un mismo paciente que conversa con dos tenants distintos tiene dos hilos paralelos totalmente independientes, con memoria separada.

Lo que se preserva en el hilo

  • La memoria de los mensajes anteriores (qué se dijo)
  • El estado intermedio del flujo en curso ("el paciente ya eligió servicio y profesional, falta confirmar horario")
  • Las preferencias declaradas durante la conversación ("prefiero los viernes a la mañana")

Lo que NO se preserva indefinidamente

  • Después de cierto tiempo de inactividad, el hilo se considera cerrado. Si la persona vuelve, el sistema ofrece retomar lo último o empezar de cero. El límite exacto de tiempo es una decisión pendiente (probablemente entre 24 y 48 horas).
  • Si el sistema detecta que la conversación quedó en un estado roto (error técnico, datos inconsistentes, acción incompleta), puede resetear el hilo y pedir empezar de nuevo, avisando al usuario con transparencia.

Garantías que el routing le ofrece al agente

Cuando el agente recibe un mensaje, el routing ya hizo todo el trabajo invisible para que pueda concentrarse en su tarea. Esas garantías son explícitas y forman parte del contrato interno del sistema:

Lock por sesión. Mientras un mensaje se está procesando para una sesión determinada, si llega otro mensaje de la misma persona, el sistema lo encola en lugar de disparar un segundo agente en paralelo. Esto evita dos respuestas incoherentes al mismo tiempo y conflictos sobre el estado de la conversación.

Mensajes apilados. La gente escribe rápido y a menudo manda varios mensajes seguidos antes de que el agente alcance a contestar al primero ("hola... quiero turno... para mañana"). El sistema los agrupa como una sola entrada antes de pasárselos al agente.

Audio y texto se procesan iguales. Si el mensaje viene como audio, antes de pasarlo al agente se transcribe a texto. El agente nunca recibe audio crudo.

Contexto validado. El sistema garantiza que cuando el agente recibe el mensaje, los datos de tenant, rol y permisos están cargados, son válidos y no se contradicen entre sí.

Degradación elegante ante fallas. Si el sistema no puede resolver alguna de las tres preguntas, el usuario recibe un mensaje honesto y comprensible en lugar de un error técnico opaco o un silencio incómodo.


Lo que este capítulo NO incluye

  • El detalle técnico de cómo se almacenan los hilos o los locks (eso es de los Capítulos 4 y 5)
  • Las herramientas que el agente usa una vez que el mensaje le llega (eso es del Capítulo 6)
  • Los flujos conversacionales que ocurren después del routing (eso vive en SPEC_v0.md)

Por qué este capítulo importa

Si el routing falla, el agente no tiene chance de hacer las cosas bien. Le contesta a la persona equivocada con datos del tenant equivocado, o le da permisos de owner a un paciente, o pierde el hilo de la conversación a mitad de un agendamiento. Este capítulo define las garantías mínimas que el sistema debe ofrecerle al agente para que pueda concentrarse en lo que sabe hacer.

04 Instalaciones
04

Instalaciones

¿Qué cosas existen en PERLA y cómo se relacionan entre sí?

Si PERLA fuera un edificio, este capítulo describe las instalaciones: el sistema circulatorio invisible que hace que todo funcione. Negocios, sucursales, profesionales, servicios, turnos, hilos de conversación. Las cosas que existen en el producto, qué información guardamos sobre cada una, y cómo se conectan entre sí.

Este es el lenguaje común del proyecto. Cuando alguien dice "agregamos el campo de seña al appointment", todos tienen que entender qué entidad es esa, qué información guarda, y qué consecuencias tiene tocarla. Sin un mapa explícito y compartido, cada quien construye sobre supuestos distintos y el sistema termina contradiciéndose a sí mismo.

Una nota de vocabulario. En este capítulo decimos entidad para referirnos a cada "cosa" que el sistema reconoce y guarda. Cada entidad se traduce a una o varias tablas en la base de datos (el Capítulo 5 describe el schema técnico con sus treinta y cinco tablas), pero acá hablamos en términos conceptuales.

Una segunda nota, para evitar confusiones. La mayoría de las entidades descritas en este capítulo ya están implementadas en el riel productivo que describe el Capítulo 5. Dos entidades aparecen marcadas como propuesta porque todavía no existen en el schema y hacen falta para sostener flujos que los Capítulos 2 y 3 dan por asumidos.

Las entidades del producto

PERLA agrupa sus entidades en cuatro familias según la función que cumplen. Las primeras tres describen lo que existe en el mundo real (negocios, personas, interacciones). La cuarta describe la conversación con el agente, que también necesita ser persistida para que el sistema funcione.

Familia 1 — El negocio y sus partes

Todo lo que pertenece a un tenant. Cada elemento de esta familia siempre está vinculado a un tenant específico y nunca cruza la frontera hacia otro. Se organizan en una cadena anidada: un tenant tiene sucursales, cada sucursal tiene profesionales y reglas de horario, y los servicios se ofrecen en una o varias sucursales.

  • Negocio (tenant). La unidad comercial completa. Tiene un nombre, una identidad, una zona horaria, una configuración de agente (tono, reglas de operación, políticas de cancelación y depósito) y un conjunto de miembros autorizados para gestionarlo.
  • Sucursal (location). Un local físico donde se prestan los servicios. Un negocio puede tener una sola sucursal o varias. Cada sucursal tiene su propia dirección, su propio teléfono, y define los horarios de atención generales del local.
  • Profesional (staff member). Una persona que trabaja en una sucursal prestando servicios o recibiendo clientes. Tiene un nombre, un rol interno, un canal de notificación y un estado.
  • Recurso físico. Un bien reservable que no es una persona — una silla de peluquería, una camilla de masaje, un consultorio. Igual que los profesionales, los recursos se agendan.
  • Servicio. Algo que el negocio ofrece, descrito a alto nivel: "masaje", "perfilado de cejas", "consulta odontológica". Tiene un nombre, una descripción larga, una categoría, y un estado.
  • Variante de servicio. La forma concreta en que un servicio se agenda. Un mismo servicio puede tener varias variantes: "masaje 30 minutos · $X", "masaje 60 minutos · $Y". Cada variante tiene su duración, precio, buffer y política de cancelación.
  • Relación profesional-variante. Dice qué profesional puede ofrecer qué variante de servicio, en qué sucursal. No todos los profesionales hacen todas las variantes.
  • Regla de disponibilidad. Define cuándo un profesional está disponible en una sucursal: "Belén trabaja en la sucursal Centro los jueves de 13:00 a 18:00 y los viernes de 09:00 a 13:00, con slots de 20 minutos".

Familia 2 — Las personas que entran al sistema

Las personas que interactúan con PERLA llegan por dos puertas muy distintas: la puerta conversacional (WhatsApp, Telegram — los pacientes) y la puerta del dashboard (navegador web — owners, operadores, equipo interno). El sistema las modela como entidades separadas porque llegan por canales distintos y se autentican de maneras distintas, aunque físicamente puedan ser la misma persona.

  • Identidad por canal del cliente (customer channel identity). Es la puerta externa por la cual entra un paciente: su número de teléfono en WhatsApp, su usuario en Telegram. Cada canal produce una identidad distinta.
  • Usuario de plataforma (user). Es la identidad de quien accede al dashboard: owner, operador autorizado, miembro del equipo interno. Se autentica con email y password.
  • Membresía (membership). Asocia a un usuario de plataforma con un negocio, especificando su rol: owner, admin, staff. Un mismo usuario puede tener membresías en varios negocios.
  • Perfil del paciente en el negocio. Cuando una identidad por canal agenda con un negocio por primera vez, el sistema crea un perfil que asocia esa identidad con ese negocio: nombre, preferencias, notas, historial.

Sobre la identidad cruzada (cliente y operador a la vez). Una misma persona física puede ser owner de un negocio y paciente de otro. En el riel actual esto no se modela como un único registro unificado: conviven su identidad por canal (como cliente) y su usuario de plataforma (como operador). Cuando el sistema necesita reconocer que una persona está actuando en dos roles al mismo tiempo, lo resuelve en tiempo de routing, no en el modelo de datos. El Capítulo 3 describe cómo.

Familia 3 — Las interacciones operativas

Lo que pasa entre las personas y los negocios. Esta familia es la que más cambia con el uso: cada día entran, se modifican y se cierran cientos de registros.

  • Turno (appointment). Un compromiso entre un paciente, un profesional (o un recurso físico), una sucursal, una fecha y una hora, dentro de un negocio. Tiene un estado que describe en qué etapa del ciclo está.
  • Ítems del turno (appointment items). Un turno no es siempre un único servicio. Una visita al salón puede ser "cejas + tinte + hidratación". Cada ítem es una variante de servicio con su propio profesional, duración y precio.
  • Reserva temporal (booking hold). Cuando una persona empieza a agendar pero todavía no confirmó, el sistema toma el horario por unos minutos. Si la confirmación nunca llega, la reserva expira y el horario vuelve a estar disponible.
  • Recordatorio programado. Un aviso futuro asociado a un turno: "recordarle a Camila 24 horas antes y 2 horas antes". El sistema los crea automáticamente al confirmar el turno y los dispara un proceso en segundo plano.
  • Log de notificación (notification log). Registro histórico de cada notificación saliente que el sistema envió. Permite no duplicar mensajes, reintentar los fallidos, y dejar trazabilidad.
  • Consulta escalada (propuesta — no existe aún en el schema). Cuando un paciente hace una pregunta que excede el catálogo, el agente escala la pregunta al owner: guarda la consulta con su contexto, le avisa al paciente, le manda el mensaje al owner, espera su respuesta, y vuelve al paciente. Este flujo está descripto en el Capítulo 2 como un caso especial, y hoy no tiene entidad persistente. Para que sea robusto hace falta modelarlo como entidad con estado (pendiente, respondida, abandonada).

Familia 4 — La conversación

El sistema necesita recordar lo que ya se dijo para que el agente no pregunte cinco veces lo mismo, para retomar conversaciones interrumpidas, y para tener una base estable sobre la cual confirmar acciones críticas.

  • Hilo de conversación (conversation thread). Un registro abierto entre una identidad de cliente y un negocio a través de un canal específico. Un paciente que habla con dos negocios tiene dos hilos distintos, con memoria separada.
  • Estado de conversación (conversation state). Separado del hilo, guarda el intent actual y los slots ya recolectados. Es el guardaespaldas contra alucinaciones del agente: antes de invocar una herramienta destructiva, el sistema verifica que todos los datos requeridos están completos.
  • Mensajes (messages). El histórico crudo de todos los mensajes intercambiados dentro de un hilo. El agente consulta este historial antes de responder para no perder contexto.

Las reglas que protegen los datos

Las entidades por sí solas no garantizan que el sistema se comporte bien. Hacen falta reglas que el sistema aplica de manera invisible y constante para que nada se corrompa, se mezcle entre negocios, o se pierda.

Aislamiento por tenant, con dos líneas de defensa. Una clínica nunca puede ver los turnos de una peluquería, ni accidentalmente, ni a propósito. La primera línea es Row Level Security: toda consulta pasa por un filtro automático. La segunda línea, más profunda, es un trigger de integridad cruzada: si una tabla tiene una referencia hacia otra, el trigger verifica que ambos registros pertenezcan al mismo tenant antes de permitir la operación.

Integridad referencial. No puede existir un turno sin un servicio asociado, sin un profesional o recurso asignado, sin una sucursal, sin un tenant. Si alguien intenta crear o modificar datos rompiendo estas relaciones, el sistema lo rechaza antes de que el daño ocurra.

Soft delete por defecto. Nada se borra de verdad. Cuando una persona cancela un turno, el turno no desaparece: se marca como cancelado y queda en la base. Esto permite responder preguntas como "¿cuántas cancelaciones tuvimos esta semana?"

Identificadores opacos. Cada registro tiene un identificador único de tipo UUID (una cadena larga sin significado humano). El agente no puede inventar identificadores razonables, no se filtran datos por la URL o el log, y se evitan colisiones entre tenants.

Marcas de tiempo en todo. Cada registro guarda cuándo fue creado y cuándo fue modificado por última vez.

Entidades pendientes y ajustes abiertos

El schema actual está cerca de cerrarse pero hay cuatro frentes abiertos que afectan a este capítulo:

  1. Código corto de negocio. Hoy el tenant se identifica por UUID y por nombre. Para resolver un link o un QR al tenant correcto hace falta un identificador corto y memorable (ej: "SURI"). Pendiente.
  2. Credenciales de canal por tenant. Si cada negocio puede tener su propio número de WhatsApp o su propio bot de Telegram, hace falta definir dónde se guardan sus tokens y credenciales.
  3. Prevención de colisiones en reservas temporales. Falta un constraint que garantice que dos reservas no puedan apuntar al mismo slot del mismo profesional al mismo tiempo.
  4. Consulta escalada como entidad. Descrita en la Familia 3, todavía no existe en el schema. Requiere decisión del equipo.

Lo que este capítulo NO incluye

  • La sintaxis SQL del schema, las migraciones, los tipos de datos exactos y los índices (eso vive en el repo del Capítulo 5)
  • Las decisiones de motor de base de datos y de plataforma de hosting (eso es del Capítulo 5)
  • La lógica de cómo el agente consulta estos datos (eso es del Capítulo 6)
  • Los reportes y métricas que se construyen sobre estos datos (eso vive en el dashboard)

Por qué este capítulo importa

Las entidades son el lenguaje común del proyecto. Si una persona del equipo entiende que un turno siempre tiene un servicio asociado y otra entiende que el servicio es opcional, el sistema termina con datos inconsistentes que no se pueden recuperar. Este capítulo es el contrato de las cosas que existen. Tiene que estar cerrado y compartido antes de que se discutan herramientas, infraestructura o procesos.

05 Sistema constructivo
05

Sistema constructivo

¿Con qué está construido PERLA y cómo se sostiene en producción?

Este capítulo describe el sistema constructivo: las tecnologías concretas con las que está hecho PERLA, cómo se articulan entre sí, y qué garantiza que el edificio no se caiga cuando entran los primeros inquilinos. Es el equivalente a los planos de instalaciones de una obra — define con qué materiales y métodos se construye lo que los capítulos anteriores describieron en abstracto.

La decisión central que atraviesa todo este capítulo es deliberada: PERLA no se construye desde cero. El riel productivo es el que un integrante del equipo viene armando hace meses en su repositorio — una plataforma multi-tenant funcional, con infraestructura decidida, base de datos hardened y dashboard operativo en construcción. Lo que falta es la capa específica del agente. Esta continuidad es una ventaja: el ochenta por ciento del sistema ya está resuelto a nivel profesional. El veinte por ciento restante es lo que tenemos que traducir desde el prototipo.

Los dos caminos

Conviven dos entornos con propósitos distintos. No compiten — se alimentan.

PROTOTIPO                          PRODUCCIÓN
n8n + Telegram + Supabase          Cloudflare Workers + WhatsApp + Supabase
validar lógica                     escalar y no caerse
horas                              días
frágil a propósito                 production-grade

n8n es el Figma de la lógica. Se arma un flujo nuevo, se prueba con mensajes reales al agente de test, se documenta lo que funciona, y recién ahí se le pide al equipo de producción que lo implemente en el código real. n8n nunca toca clientes reales. Es el tablero de diseño donde se valida que una idea conversacional es implementable antes de invertir días en codificarla.

El código de Cloudflare es el edificio. Acá va todo lo que tiene que funcionar para negocios reales: escala automática, aislamiento entre tenants, webhooks de WhatsApp, cálculo de disponibilidad, pagos futuros. Lo que llega acá no se experimenta — se ejecuta.

La regla de oro: n8n valida, código produce. Nunca al revés.

El riel productivo

El stack de producción está decidido y en funcionamiento. Cada pieza resuelve un problema específico y fue elegida por razones concretas.

┌─────────────────────────────────────────────────────────┐
│  CLIENTES                                                │
│  WhatsApp Business API · Telegram (para pruebas)        │
└─────────────────────┬───────────────────────────────────┘
                      │ webhook HTTPS
┌─────────────────────▼───────────────────────────────────┐
│  CLOUDFLARE WORKERS                                      │
│  Runtime en el edge global, escala automática            │
│                                                          │
│   ┌──────────┐   ┌──────────┐   ┌─────────────────┐    │
│   │ Adapters │ → │   Core   │ → │   Aplicación    │    │
│   │ Telegram │   │ Routing  │   │ Motor de turnos │    │
│   │ WhatsApp │   │ Identity │   │ Agente + tools  │    │
│   │          │   │ Permisos │   │ Notificaciones  │    │
│   └──────────┘   └────┬─────┘   └────────┬────────┘    │
│                       │                   │             │
│   ┌───────────────────▼───────────────────▼──────────┐ │
│   │  Capa de infraestructura                          │ │
│   │  Drizzle → Hyperdrive → Supabase Postgres         │ │
│   │  Supabase Auth (dashboard)                        │ │
│   │  AI SDK (Gemini / Claude)                         │ │
│   └───────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
                      │
┌─────────────────────▼───────────────────────────────────┐
│  DASHBOARD WEB (mismo deploy, rutas /app/*)              │
│  TanStack Start + shadcn/ui + Tailwind                   │
│  Auth: Supabase Auth con cookies HTTP-only               │
└─────────────────────────────────────────────────────────┘

Las piezas, de afuera hacia adentro

Cloudflare Workers. El runtime donde vive el código. Se enciende cuando llega un mensaje, se apaga cuando termina. No hay servidor que mantener, ni escalamiento que planificar. Pricing por request, no por hora. Limitaciones conocidas: 128 MB de memoria y 30 segundos de CPU por request. Alcanza y sobra para un agente conversacional.

TanStack Start + React. El framework del dashboard web. Corre nativo sobre Workers y resuelve server-side rendering, ruteo por archivos y API routes en la misma aplicación. Elegido sobre Next.js porque no requiere Vercel.

Hono. El router HTTP adentro del Worker. Liviano, tipado, sin dependencias. Pasillo de distribución que recibe cada request y la manda al módulo correcto.

Drizzle ORM. La interface tipada con la base de datos. Cada query es TypeScript compilado a SQL, sin runtime pesado. Elegido sobre Prisma porque Prisma no corre en Workers. El schema TypeScript es la fuente de verdad de la estructura de datos.

Hyperdrive. El pool de conexiones de Cloudflare hacia Postgres. Sin Hyperdrive, cada request abriría una conexión nueva a Supabase y el Postgres se ahogaría con cincuenta tenants. Con Hyperdrive, las conexiones se cachean en el edge. Obligatorio para producción.

Supabase. Base de datos managed + autenticación de dueños + Row Level Security incluido. Postgres real, no una versión lite. Para veinte o más tenants reales, upgrade al plan pago es obligatorio.

AI SDK de Vercel. La interface al modelo. Abstrae Gemini, Claude y OpenAI detrás de la misma API. Cambiar de modelo por rol o por tenant es cambiar una línea. Esta pieza no está en el repo todavía — es lo primero que agregamos.

Qué cambia respecto a un servidor tradicional

Un servidor tradicional siempre está encendido: pagás por hora, se mantiene con SSL, firewall, actualizaciones, backups, y si se cae, se cae para todos. Workers funciona al revés: se enciende cuando hace falta, escala solo, no tiene mantenimiento, y una falla en una instancia no afecta a las demás. Para el modelo del producto, Workers es la elección correcta.

La base de datos como plano estructural

Si el Worker es el sistema nervioso, la base de datos es la columna vertebral. El schema tiene treinta y cinco tablas organizadas en tres capas: plataforma (usuarios, negocios, sucursales, membresías), dominio (servicios, staff, turnos, conversaciones) y security (triggers, políticas).

NEGOCIOS
  └─ locations (sucursales)
       └─ staff_members
            └─ availability_rules (horarios)
       └─ services
            └─ service_variants (duración, precio, buffer)
                 └─ staff_service_variants (quién hace qué)

CLIENTES
  └─ customer_channel_identities (phone por canal)
       └─ conversation_threads (un hilo por canal/negocio)
            └─ conversation_state (intent + slots)
            └─ messages (histórico completo)

TURNOS
  └─ booking_holds (reserva transitoria)
  └─ appointments (turno confirmado)
       └─ appointment_items (servicios dentro del turno)
       └─ notification_logs (recordatorios enviados)

Tres decisiones estructurales importantes:

Multi-tenant real, no por convención. Cada tabla tiene una referencia directa al negocio al que pertenece. Los datos de Suri nunca se mezclan con los de Pepito, y eso está garantizado por código y por base de datos a la vez.

Dos líneas de defensa para el aislamiento. La primera es Row Level Security (RLS). La segunda — más profunda — es un trigger instalado en todas las relaciones cruzadas: si una tabla A tiene una referencia hacia una tabla B, el trigger verifica que ambos registros pertenecen al mismo negocio. Si el código tuviera un bug, la base de datos lo rechaza sola.

Sofisticación preparada para escalar. El schema distingue entre servicio (nombre, categoría) y variante del servicio (duración, precio, buffer). Separa staff de recursos físicos (sillas, salas). Tiene políticas de negocio parametrizables por tenant. Para el MVP algunas columnas quedan vacías, pero la estructura está pensada para soportar peluquerías con diez profesionales y consultorios con dos salas sin reescribir nada.

Lo que el schema todavía no resuelve y hay que completar:

  • Un código corto por negocio que permita resolver el tenant desde un link o un QR.
  • Una tabla de credenciales de canal por tenant (dónde guardar el token del bot de Telegram o las credenciales de WhatsApp Business).
  • Un constraint único adicional en los holds de turno para prevenir una condición de carrera puntual cuando dos clientes pidan el mismo horario en simultáneo.

Ninguna de estas tres es un rediseño. Son ajustes que se incorporan en la próxima migración cuando el equipo confirme el criterio.

Los canales de entrada

El agente recibe mensajes por dos canales distintos. Cada uno tiene reglas propias.

Telegram es el canal de prueba. Crear un bot es gratis, no requiere verificación, el API es simple. Sirve para validar flujos durante desarrollo y para stress testing. No tiene sentido para clientes reales en Argentina.

WhatsApp Business API es el canal de producción. Requiere número de teléfono dedicado, cuenta Meta Business verificada, y aprobación de Meta. Tiene dos restricciones que definen el diseño:

  • Ventana de 24 horas. Si el cliente no escribió en las últimas 24 horas, no se le puede mandar texto libre. Sólo se pueden enviar templates pre-aprobados por Meta. Esto afecta cualquier recordatorio o reprogramación proactiva.
  • Costo por conversación. Meta cobra entre 2 y 5 centavos de dólar por conversación. Las conversaciones iniciadas por el cliente dentro de la ventana de 24 horas son gratuitas hasta las primeras mil al mes.

El sistema soporta que cada negocio tenga su propio número de WhatsApp (plan premium futuro) o que todos los negocios atiendan desde un número central (MVP).

El cerebro del agente

El modelo de lenguaje en este producto no es un chatbot libre. Es un router de intenciones y generador de respuestas naturales. Su trabajo es entender qué quiere el cliente, llamar la herramienta correcta, y formatear la respuesta en lenguaje natural. Nunca inventa datos. Nunca improvisa políticas. Si algo queda fuera de su scope, deriva al humano.

La arquitectura del agente tiene tres piezas:

El modelo. Distinto según el rol. Para el cliente (volumen alto, interacciones simples) se usa un modelo barato y rápido — Gemini Flash o Claude Haiku. Para el dueño (volumen bajo, instrucciones complejas) se usa un modelo más capaz — Claude Sonnet o GPT-4o. Costo estimado: USD 2/mes por negocio en el MVP.

Las herramientas. Funciones tipadas que el modelo puede invocar. Cada una pide los parámetros mínimos, valida contra el schema, ejecuta, y devuelve un resultado estructurado. Son las únicas acciones que el agente puede tomar.

La máquina de estados. Cada conversación tiene un registro de estado con el intent actual y los slots ya recolectados. Esta máquina de estados es el guardaespaldas contra alucinaciones: antes de crear un turno, el sistema verifica que todos los slots requeridos estén completos.

El diseño tiene una implicancia importante: el modelo es reemplazable. Si mañana aparece un LLM mejor, se cambia el proveedor en la configuración del tenant y listo. El sistema no depende de un modelo específico.

Procesos en segundo plano

No todo es pregunta-respuesta. Hay cosas que pasan solas.

Cada 5 minutos   → expirar holds vencidos (liberar slots)
Cada 30 minutos  → revisar turnos próximos y mandar recordatorios
8:00 AM L-V      → enviar resumen del día al dueño
Cada 15 minutos  → reintentar notificaciones fallidas
Diario 3:00 AM   → limpiar sesiones inactivas

Todos estos procesos corren como Cron Triggers de Cloudflare. El Worker se enciende a la hora indicada, ejecuta la tarea, se apaga. Sin servidor corriendo en background.

Las notificaciones proactivas caen fuera de la ventana de 24 horas de WhatsApp la mayoría del tiempo. Por eso se mandan como templates pre-aprobados. Los más críticos para el MVP:

  • Recordatorio de turno (24h antes, 2h antes)
  • Reprogramación proactiva (cuando el dueño cancela)
  • Solicitud de seña (cuando se active MercadoPago)
  • Confirmación inicial tras agendar
  • Mensaje de bienvenida tras onboarding

Seguridad y observabilidad

La seguridad está en tres capas:

En la base de datos. RLS activado en las 35 tablas, con políticas que sólo permiten a miembros de un negocio ver sus propios datos. Trigger de integridad cruzada como segunda línea. Secretos nunca en el código.

En el código. Cada query pasa por funciones que exigen un identificador de negocio explícito. No hay query cruda al Postgres. Los endpoints del dashboard exigen token válido de Supabase Auth. Los webhooks verifican firma del proveedor (Meta firma con HMAC).

En el producto. El agente siempre confirma antes de ejecutar acciones destructivas. Nunca cancela a ciegas. La máquina de estados impide saltos de paso.

La observabilidad se apoya en dos herramientas y una convención:

  • Cloudflare Analytics captura automáticamente requests, errores y latencia.
  • Supabase Dashboard muestra el estado de la base, las queries lentas, las conexiones activas.
  • Logs estructurados en JSON que el equipo escribe adentro del código: cada request deja un rastro con identificador de negocio, de sesión, intent detectado, herramientas invocadas, tiempo de respuesta.

Hay también un canal de alertas: si el agente no responde, si el error rate sube, si la base de datos pierde conexión — un bot auxiliar manda un mensaje por Telegram al equipo.

Cómo se deploya

Hoy, deploy manual con Wrangler. Funciona, pero depende de que alguien se acuerde de ejecutarlo. La meta para producción seria — antes del lanzamiento — es CI/CD automatizado:

commit a main
    ↓
GitHub Actions corre typecheck + tests
    ↓
Si todo pasa → deploy a staging
    ↓
Pruebas manuales mínimas (smoke test)
    ↓
Promoción manual a producción

Esto implica tres cosas que hoy faltan: tests automatizados con Vitest y fixtures, workflow de GitHub Actions, y entorno de staging separado del de producción. Trabajo estimado: una o dos semanas.

Estado actual del sistema constructivo

Lo que está en pie (~80%)

  • Infraestructura Cloudflare + Supabase funcionando.
  • Schema de base de datos diseñado, migrado, con RLS y triggers de aislamiento.
  • Dashboard web en construcción activa: auth, creación inicial de negocio, configuración de tenant.
  • Sistema de skills para agentes IA que documenta las convenciones de cada pieza del stack.
  • Conexiones entre capas (Drizzle ↔ Hyperdrive ↔ Postgres) probadas.

Lo que falta (~20%)

  • Adaptadores para Telegram y WhatsApp Business API.
  • Módulo del agente: AI SDK integrado, system prompts por rol, máquina de estados.
  • Herramientas de reserva: consultar disponibilidad, crear turno, cancelar, reprogramar, operaciones en lote.
  • Handlers de cron para recordatorios y expiración de holds.
  • Transcripción de audio (STT).
  • Testing automatizado y pipeline de CI/CD.
  • Logs estructurados y alertas.

Ajustes que requieren confirmación

  1. Agregar un código corto de negocio para resolver tenant desde links y QRs.
  2. Decidir dónde viven las credenciales de canal por tenant.
  3. Agregar un constraint único parcial en los holds para blindar la condición de carrera.
  4. Implementar la función de resolución de tenant desde número de teléfono como pieza core.

Lo que este capítulo NO incluye

  • La descripción funcional del producto (capítulos Programa, Circulaciones e Instalaciones).
  • El modelo de datos en detalle, tabla por tabla (Capítulo Instalaciones).
  • El diseño de las herramientas que el agente usa y el system prompt por rol (Capítulo Legajo Ejecutivo).
  • La asignación de responsabilidades en el equipo (Capítulo Cronograma).

Por qué este capítulo importa

Las decisiones de stack determinan qué es posible y qué no, cuánto cuesta operar el sistema, y qué tan rápido podemos iterar. Tener este capítulo escrito evita que las decisiones técnicas se tomen sobre la marcha en un chat de WhatsApp, y permite que cualquier nuevo integrante entienda en una sentada cómo está armada la cocina. También permite sostener una conversación profesional con clientes empresariales cuando pregunten "¿dónde vive la data?" — no hay que improvisar la respuesta, está escrita.

06 Legajo Ejecutivo
06

Legajo Ejecutivo

¿Cómo hablan las piezas entre sí?

Este capítulo describe los pliegos del proyecto: los contratos formales que definen cómo se comunica cada parte del sistema con las demás. Qué herramientas tiene disponibles el agente, qué inputs recibe cada una, qué outputs devuelve, qué errores puede levantar. Cómo está escrito el system prompt que le da personalidad y límites. Cómo se traduce un mensaje de WhatsApp al lenguaje interno del sistema. Qué pasa cuando algo falla.

En obra, los pliegos son los documentos que definen con precisión cómo se ejecuta cada parte de la construcción para que distintos oficios puedan colaborar sin malentendidos. El plomero no tiene que leer los planos de estructura para saber qué caño necesita; lee el pliego sanitario. En PERLA cumplen la misma función: son los contratos que permiten que el agente, las herramientas, los adapters de canal y el manejo de errores se construyan y evolucionen por separado sin que se rompa la coherencia del conjunto.

Una nota importante sobre alcance. Los pliegos son contratos, no implementación. Este capítulo define la forma de la conversación entre componentes, no cómo está escrito el código de cada uno. La implementación vive en el repositorio de producción. La voz de marca — los textos exactos que lee el paciente — vive en el Brand Guide. Acá solo definimos la arquitectura de los acuerdos.

Los cinco pliegos

PERLA tiene cinco pliegos formales, y cada uno resuelve una pregunta distinta:

#PliegoPregunta que responde
1Contrato de tools¿Qué puede hacer el agente?
2System prompt¿Quién es el agente y qué límites tiene?
3Adapters de canal¿Cómo se traduce un mensaje al lenguaje interno?
4Política de errores y fuera de scope¿Qué pasa cuando algo falla o excede al agente?
5Protocolo de acciones destructivas¿Cómo se confirma algo que no se puede deshacer?

Los cinco se tienen que leer juntos porque se refuerzan entre sí: un contrato de tools sin un system prompt que lo cite queda huérfano; un system prompt sin política de errores lleva al agente a improvisar cuando las tools fallan; un protocolo de acciones destructivas sin adapters que lo respeten se rompe en el primer mensaje confuso.

Pliego 1 — El contrato de tools

Las tools son la única superficie por la cual el agente actúa sobre el sistema. Si no hay tool para algo, el agente no lo puede hacer — por diseño. Esta restricción es deliberada: todo lo que el agente invoca está tipado, validado y auditable. Lo que no tiene tool es lo que el agente no tiene permitido.

Principios del contrato

El agente no sabe SQL, no sabe canales, no sabe adapters. Solo sabe invocar funciones tipadas con parámetros definidos. La implementación interna de cada tool puede cambiar — consultar otra tabla, usar otra API, cambiar de base de datos — sin que el agente se entere. El contrato es la interfaz.

Cada tool pide los inputs mínimos necesarios. Si falta un dato requerido, la tool rechaza la invocación con un error claro antes de ejecutar. Esto evita que el agente llame a create_appointment con fecha pero sin profesional y el sistema improvise.

Los identificadores son opacos. Toda tool que reciba un identificador como entrada recibe un UUID real (cadena larga sin significado humano), nunca un nombre o una descripción. El agente solo puede obtener UUIDs como salida de otra tool — no los inventa.

Cada tool valida multi-tenancy. Antes de cualquier operación, la tool verifica que los identificadores recibidos pertenezcan al tenant del contexto actual. Un agente en modo cliente de Suri que reciba accidentalmente un UUID de Pepito obtiene un error, no datos cruzados.

Las tools del paciente

Las herramientas disponibles cuando el agente está atendiendo a un paciente son de lectura y escritura limitada, siempre sobre el propio registro del paciente:

  • get_services — devuelve la lista de servicios activos del tenant, con sus variantes (duración, precio, buffer), categorías y descripciones cortas.
  • get_staff_availability — recibe un servicio elegido y devuelve los profesionales que lo ofrecen junto con su disponibilidad en rangos (no slots individuales). El formato de salida es intencionalmente conservador: "Belén, jueves de 13:00 a 18:00; Jazz, viernes de 09:00 a 13:00", no "Belén: 13:00, 13:20, 13:40, 14:00...".
  • create_appointment — crea el turno. Recibe service_id, staff_id, starts_at (ISO 8601 con timezone) y ends_at (calculado a partir de la duración del servicio). Devuelve el turno creado o un error si el slot ya está tomado, si el UUID no es válido, o si hay inconsistencia de tenant.
  • get_active_appointments — devuelve los turnos futuros del paciente en el tenant actual. Base para cancelar o reprogramar.
  • cancel_appointment — cancela un turno del paciente. Recibe el UUID del turno. Devuelve confirmación o error si el turno no existe, ya pasó, o no pertenece al paciente.
  • reschedule_appointment — cambia un turno a otro horario. Internamente ejecuta una operación atómica: cancela el viejo y crea el nuevo. Si la creación del nuevo falla, el viejo no se cancela.

Las tools del owner

Las herramientas del owner son superset de las del paciente (un owner también puede agendarse), más un conjunto propio para gestión. Las más relevantes:

  • list_appointments — recibe un rango de fechas (día, semana, mes) y opcionalmente un profesional o un estado, y devuelve la agenda filtrada.
  • block_staff_slot — bloquea a un profesional en un rango de tiempo (ausencia, feriado, imprevisto). Devuelve además la lista de turnos afectados — paso previo obligatorio antes de cancelar o reprogramar en batch.
  • bulk_cancel_preview y bulk_cancel_execute — dos tools distintas para una sola operación. La primera recibe un rango o un conjunto de turnos y devuelve un resumen del impacto; la segunda recibe un token de confirmación vinculado a un preview válido y ejecuta. Un cancel_preview no ejecuta nada; un cancel_execute sin token previo rechaza la invocación.
  • bulk_reschedule_preview y bulk_reschedule_execute — mismo patrón para reprogramación en batch.
  • add_service, update_service, deactivate_service — gestión del catálogo.
  • add_staff_member, update_staff_availability, deactivate_staff_member — gestión del equipo.
  • get_report — reportes simples (turnos de la semana, cancelaciones, staff más pedido). Devuelve datos agregados, no transaccionales.
  • reply_to_escalated_inquiry — responder una consulta escalada que el agente derivó desde un paciente (ver Pliego 4).

La separación por niveles de riesgo

Las tools se clasifican en cuatro niveles según el impacto de la operación:

NivelTipoEjemploTratamiento
L1Lecturaget_services, list_appointmentsEjecución directa, sin confirmación
L2Escritura simplecreate_appointment, cancel_appointment (un turno)Confirmación del usuario al agente ("¿confirmo?")
L3Escritura múltiplebulk_cancel_preview + execute con tokenPreview obligatorio + confirmación explícita
L4Destructivo masivo"cancelá todo lo de la semana"Preview + delay + token con TTL + logging detallado

Esta clasificación no es una nota al pie — es la forma en que el contrato de tools se protege contra acciones involuntarias. El agente puede pedir un preview cuantas veces quiera; no puede ejecutar una operación L3 o L4 sin un token de confirmación válido emitido por una operación de preview reciente.

Pliego 2 — El system prompt

El system prompt es el documento que define quién es el agente y cómo se comporta. No es literatura — es la especificación operativa del modelo. Un system prompt mal escrito hace que el mejor modelo invente datos, repita pasos, o ejecute acciones sin confirmación. Un system prompt bien escrito hace que un modelo barato se comporte como un profesional.

En PERLA hay dos system prompts distintos: uno para el agente cuando atiende a un paciente y otro para cuando atiende al owner. Comparten estructura — misma anatomía, contratos equivalentes — y se diferencian en el alcance de las tools disponibles y el tono.

Anatomía del system prompt

El system prompt del agente tiene siete secciones. Cada una resuelve un problema específico que, si se omite, el agente termina improvisando.

1. Identidad. "Sos {bot_name}, el asistente virtual de {tenant_name}. Respondés en el idioma y tono definidos por el negocio." Esta sección resuelve quién habla — y explicita que la personalidad no es fija, se configura por tenant. Un mismo agente es "Sara de Suri" con una paciente y "Leo de Pepito" con otra, sin cambiar de modelo ni de código.

2. Contexto de sesión. tenant_id, nombre del usuario, chat ID, fecha actual, zona horaria, reglas del negocio. Se inyectan por request antes de invocar al modelo. El agente recibe el contexto ya resuelto — no lo averigua. Esto es la traducción directa de la promesa del Capítulo 3 ("el agente recibe el mensaje ya con todo el contexto resuelto") al formato del prompt.

3. Flujo de reserva. Es la receta paso a paso para el caso central del producto. Está escrita como una lista numerada con guardias condicionales:

1. Si el usuario NO sabe qué servicio quiere → llamá get_services.
2. Si el usuario YA eligió un servicio → NO vuelvas a llamar get_services.
   Llamá get_staff_availability.
3. Mostrá disponibilidad como RANGOS, NUNCA slots individuales.
4. Cuando confirme día y hora → llamá create_appointment con UUIDs reales.
5. Confirmá con resumen breve.

La redacción condicional ("Si... → ...") no es casualidad. Un flujo escrito como "Primero hacé X, después Y, después Z" lleva al agente a ejecutar los pasos secuencialmente aunque ya no correspondan. La redacción condicional lo obliga a evaluar el estado antes de cada paso.

4. Guardia anti-bucle. Dos reglas que se aprendieron en testing, cuando el agente entraba en loops preguntando cosas que ya había resuelto:

IMPORTANTE: NUNCA repitas un paso que ya se completó. Si ya mostraste
servicios, avanzá. Si ya mostraste horarios, avanzá.

IMPORTANTE: Si ya mostraste los servicios y el usuario eligió uno,
NUNCA vuelvas a listar servicios. Avanzá al siguiente paso.

Esta guardia es importante conceptualmente porque es un caso de aprendizaje de producción incorporado al prompt. El prompt no se diseñó así de entrada; se endureció después de ver al agente entrar en bucles. Es un ejemplo canónico de cómo evoluciona un system prompt.

5. Reglas obligatorias (anti-alucinación). Las cinco reglas que evitan que el agente invente datos:

  • Nunca inventes datos — si no tenés info, consultá la tool correspondiente.
  • Nunca inventes UUIDs — son strings largas sin significado humano; usá solo los que devuelven las tools.
  • Nunca listes horarios individuales, solo rangos.
  • Si create_appointment devuelve error, no digas que el turno está confirmado. Decí que hubo un problema y pedí reintentar.
  • Si el usuario pide algo que no es un servicio del negocio, no lo improvises — decí que no ofrecés ese servicio y mostrá los disponibles.

6. Mapeo de UUIDs para tools de escritura. El prompt le dice al agente cómo construir los parámetros de create_appointment:

- service_id  → campo "id" de la respuesta de get_services
- staff_id    → campo "staff_id" o "staff.id" de get_staff_availability
- starts_at   → ISO 8601 con offset de la timezone del tenant
- ends_at     → starts_at + duration_min del servicio

Este mapeo es explícito porque los nombres de los campos en la respuesta de una tool no son obvios. Sin el mapeo, el modelo tiende a adivinar (usa "uuid" en lugar de "id", o "professional_id" en lugar de "staff_id") y las tools fallan.

7. Formato de respuestas. Máximo 3-4 líneas por bloque. Negritas para nombres de servicios, profesionales y horarios confirmados. Un salto de línea entre bloques. Sin emojis salvo que el tenant lo pida. Esta sección controla la experiencia del paciente sin depender de que el modelo tenga buen gusto. La brevedad es operativa: un mensaje de diez líneas en WhatsApp no se lee, se scrollea.

8. Personalidad por defecto. "Profesional pero cálido, directo, sin relleno." Es el fallback cuando el tenant no definió su propio tono. Si lo definió (por ejemplo: "rioplatense, cálida, directa" para Suri), el system prompt reemplaza esta sección con el tono del tenant.

Lo que el system prompt NO contiene

Deliberadamente, el prompt no contiene lógica de autorización, ni cálculos de disponibilidad, ni manejo de pagos, ni criterios de multi-tenancy. Todo eso vive en las tools o en el routing (Capítulo 3). El prompt solo orquesta la conversación y decide qué tool llamar.

Esta división es deliberada: cualquier lógica que viva en el prompt es opaca, no testeable, y depende del modelo. Cualquier lógica que viva en el código es explícita, testeable y predecible.

Pliego 3 — Los adapters de canal

Un adapter es la pieza que traduce un canal de entrada (WhatsApp, Telegram, cualquier futuro) al lenguaje interno del sistema. El core no sabe si está hablando por WhatsApp o por Telegram — recibe mensajes ya normalizados.

El contrato del adapter

Cada adapter cumple cuatro responsabilidades mínimas:

1. Verificación de autenticidad. Verifica la firma del proveedor para confirmar que el mensaje es genuino. WhatsApp firma con HMAC-SHA256; Telegram firma con el secret del bot. Si la firma no valida, el mensaje se descarta antes de tocar el sistema.

2. Normalización del mensaje entrante. Extrae del payload nativo del proveedor un objeto uniforme con: identificador externo del remitente, texto del mensaje (si es audio, la transcripción), tipo de contenido, timestamp. El agente nunca ve un payload de Meta; ve un objeto normalizado.

3. Transcripción de audio. Si el mensaje es un audio, el adapter lo transcribe a texto antes de pasarlo. El sistema interno trabaja con texto — no con audio crudo.

4. Envío saliente. Cuando el agente produce una respuesta, el adapter la traduce al formato del canal: texto para Telegram, texto o template para WhatsApp según la ventana de 24 horas. Gestiona los reintentos si la API del proveedor falla transitoriamente.

El caso especial de WhatsApp

WhatsApp no es simétrico a Telegram. Las restricciones de Meta (ventana de 24 horas, templates pre-aprobados, costos por conversación) viven dentro del adapter, no se propagan al agente. El agente pide "mandá este mensaje" y el adapter decide: si hay ventana activa, texto libre; si no, el template apropiado con los campos rellenos.

Esta encapsulación es importante por dos razones. Primero, permite que el agente tenga un prompt único que no cambia entre canales. Segundo, cuando WhatsApp cambie sus reglas (que lo hace), se actualiza el adapter una vez y el resto del sistema no se entera.

Garantía del adapter al sistema

Cada mensaje que sale del adapter hacia el core tiene tres certezas:

  • El remitente está autenticado (firma válida).
  • El contenido está normalizado (texto, sin audio crudo).
  • El canal está identificado (el core sabe si vino por WhatsApp o Telegram por si el adapter inverso tiene que responder por el mismo canal).

El core, a su vez, garantiza al adapter que las respuestas que devuelve están listas para enviarse tal cual — ni el core ni el agente tienen que preocuparse por templates ni por HMAC.

Pliego 4 — La política de errores y fuera de scope

No todo sale bien. Este pliego define qué pasa cuando algo falla, y qué pasa cuando el paciente pide algo que el agente no puede resolver.

Errores técnicos

Cuando una tool falla por razones del sistema — base de datos caída, timeout de LLM, servicio externo inaccesible — se aplica una política estricta:

El paciente nunca ve un error técnico. Nunca se muestra un mensaje como "Error 500 de Supabase" ni un stack trace. El paciente ve un mensaje amable: "Disculpá, tuve un problema técnico. ¿Podés repetirme lo que necesitás?".

Los errores son estructurados para el agente. Cuando una tool falla, devuelve un error tipado con código, categoría (transient / permanent) y un mensaje descriptivo para el log. El agente lee el código y el tipo, no el mensaje crudo, y decide qué hacer: reintentar si es transient, derivar si es permanent.

Si una sesión falla dos veces seguidas, se ofrece escalamiento humano. El agente deja de intentar, le dice al paciente "Estoy teniendo problemas. Te paso con el equipo de {tenant}" y marca la conversación para atención humana.

Todo error queda logueado. Con tenant, session, intent, tool invocada, parámetros, y stack si corresponde. Los errores no son invisibles — son la materia prima del diagnóstico.

Fuera de scope: la política de derivación

Cuando el paciente pide algo que el agente no puede resolver, la política es clara: derivar, nunca improvisar.

Hay dos casos distintos:

Caso A — Pregunta fuera de catálogo. El paciente pregunta por un servicio que el tenant no ofrece, o por información que el tenant no publicó ("¿cuánto sale el shampoo orgánico?"). El agente reconoce los límites de su catálogo (que conoce por get_services) y responde con transparencia: "Por ahora solo puedo ayudarte con turnos. Para consultas sobre productos, escribile al equipo de {tenant}.". No inventa un precio, no especula, no improvisa.

Caso B — Consulta escalada al owner. Hay un caso intermedio que el Capítulo 2 describe como consulta escalada: el paciente pregunta algo razonable que el catálogo no cubre, pero que el owner podría responder si se le pregunta ("¿podés hacer un masaje descontracturante con enfoque terapéutico?"). Acá el agente no cierra la conversación — la deriva:

paciente pregunta algo fuera de catálogo pero razonable
    ↓
agente reconoce que excede el catálogo y es escalable
    ↓
le avisa al paciente: "dejame consultar con {tenant}, te aviso"
    ↓
abre una consulta escalada (entidad pendiente — Capítulo 4)
    ↓
le manda el mensaje al owner por su canal
    ↓
espera la respuesta del owner
    ↓
vuelve al paciente con la respuesta transcripta

Este flujo tiene una particularidad crítica: el owner puede tardar horas en contestar. Mientras tanto, el paciente puede volver a escribir, hacer otra pregunta, o insistir. El sistema tiene que preservar el estado de la consulta abierta sin bloquear la conversación para otros temas. Por eso el Capítulo 4 lo nombra como entidad propuesta: hoy el flujo está en el comportamiento del agente, pero la persistencia estructurada todavía no está implementada.

Pliego 5 — Protocolo de acciones destructivas

Las acciones que modifican o eliminan datos exigen un protocolo distinto al de las de lectura. No alcanza con que el agente confirme verbalmente con el usuario — hace falta un mecanismo técnico que impida que el agente ejecute por su cuenta una operación irreversible sin que el sistema se entere.

El patrón preview / execute

Toda operación de nivel L3 o L4 (escritura múltiple o destructiva masiva) se descompone en dos tools:

  • Una tool de preview. Recibe los parámetros de la operación, consulta qué registros serían afectados, y devuelve un resumen más un token de confirmación con tiempo de vida limitado (cinco minutos por default).
  • Una tool de execute. Recibe el token de confirmación y los parámetros originales. Valida que el token existe, que no expiró, que no se usó antes, y que los parámetros coinciden con el preview original. Solo entonces ejecuta.

Un execute sin token previo es rechazado. Un execute con token expirado es rechazado. Un execute con token de una operación distinta es rechazado. Esta cadena es impermeable al agente: aunque el modelo alucine y genere un token falso, la validación del sistema lo rechaza.

El flujo completo, desde la conversación

Owner: "Agnes, cancelame todo lo de mañana a la mañana"
   ↓
agente invoca bulk_cancel_preview(rango: mañana 00:00 a 12:00)
   ↓
preview retorna:
  - 4 turnos afectados (listado)
  - confirmation_token: abc123, expira en 5 min
   ↓
agente presenta al owner:
  "Tenés 4 turnos mañana antes de las 13:00:
    · 09:00 Camila — Perfilado de cejas (Belén)
    · 09:30 Lucía — Limpieza facial (Belén)
    · 10:30 Marta — Masaje (Jazz)
    · 12:00 Sol — Perfilado de cejas (Belén)
   ¿Cancelo los 4 y les ofrezco reprogramar?"
   ↓
owner: "Sí, dale"
   ↓
agente invoca bulk_cancel_execute(token: abc123)
   ↓
execute valida token + ejecuta + registra la operación
   ↓
agente confirma: "Listo. Cancelé los 4 y les avisé para reprogramar."

El flujo parece obvio desde afuera, pero la diferencia con un flujo simple es estructural: si el token no existe o expiró, el agente no puede ejecutar aunque el owner haya dicho que sí. Si el owner dice "sí" pasados seis minutos, el agente tiene que pedir un preview nuevo.

Reglas que no dependen del prompt

El protocolo de acciones destructivas no vive en el system prompt — vive en el código de las tools. Si un prompt hostil intentara convencer al agente de invocar bulk_cancel_execute con un token inventado, la tool lo rechaza. La seguridad no depende de que el modelo obedezca el prompt; depende de que el sistema valide cada input antes de ejecutar.

Entidades involucradas

El Capítulo 4 describe los appointments, booking_holds y notification_logs. El protocolo de acciones destructivas necesita una entidad adicional: el registro de operaciones pendientes con su token, sus parámetros, su TTL y su estado. Esta entidad existe operativamente (es lo que hace posible el patrón preview/execute) pero todavía no está en el modelo formal del Capítulo 4 — es el ajuste más inmediato cuando se cierre el schema.

Frentes abiertos que afectan este capítulo

Los pliegos están completos como contratos formales, pero hay cuatro piezas donde el contrato está definido pero la implementación de respaldo todavía no existe. Estas no son ambigüedades — son tareas con dueño.

  1. Tools del owner en batch (bulk_cancel_preview, bulk_reschedule_preview, etc.). Definidas acá, todavía no implementadas en el agente real. El Capítulo 5 las tiene como parte del 20% pendiente.
  2. La entidad de operaciones pendientes (para el protocolo preview/execute). Descrita acá como necesaria, no está en el schema formal del Capítulo 4. Se incorpora cuando se implementen las tools batch.
  3. La consulta escalada al owner. Descrita como flujo en este capítulo y propuesta como entidad en el Capítulo 4. Hoy el flujo vive en el prompt del agente pero no tiene persistencia estructurada.
  4. Adapter de WhatsApp. Definido acá como contrato, todavía no implementado. Es parte del 20% pendiente del Capítulo 5.

Lo que este capítulo NO incluye

  • Los textos exactos de los mensajes que ve el paciente (voz de marca — vive en el Brand Guide, no en este manual)
  • La implementación interna de cada tool — queries, joins, validaciones concretas (vive en el repositorio de producción, no acá)
  • Los flujos conversacionales completos con variantes por tenant (vive en SPEC_v0.md como input a este capítulo)
  • Los esquemas JSON exactos de request y response de cada tool (son derivados técnicos del contrato — viven como tipos en el código)

Por qué este capítulo importa

Sin contratos formales, el agente improvisa. Sin contratos formales, dos desarrolladores pueden implementar la misma tool de dos maneras incompatibles. Sin contratos formales, no hay manera de testear el sistema porque no hay un comportamiento esperado contra el cual comparar. Y, quizás lo más importante, sin contratos formales no hay manera de que un modelo reemplazable (Gemini Flash hoy, Claude Haiku mañana, GPT-5 Nano pasado) se comporte igual — el contrato es lo que hace que el agente sea una pieza reemplazable en vez de una caja negra específica.

Este capítulo es el que convierte a PERLA de un experimento en un producto. Los cuatro capítulos anteriores describen el edificio; este describe las reglas que hacen que las piezas del edificio se hablen sin malentendidos.

07 Cronograma y oficios
07

Cronograma y oficios

¿Cómo se organiza el equipo para construir esto?

Este capítulo describe el cronograma y los oficios del proyecto: cómo se organiza el equipo que está construyendo PERLA, quién decide qué, en qué orden ocurren las cosas, y cómo se itera cuando algo cambia. Es el equivalente al cronograma de obra y a la asignación de gremios: define el "cómo se hace" del proyecto, no el "qué se construye".

Qué va a contener este capítulo (cuando se escriba)

  • Los roles y responsabilidades por frente, con su zona de decisión clara
  • El principio de iteración: n8n valida lógica rápido, TypeScript produce robusto. Quién prototipa, quién implementa, en qué orden.
  • La cadencia de trabajo: con qué frecuencia se reúne el equipo, qué se discute, qué se decide asincrónico
  • El proceso de cambio: cómo se aprueba una modificación de producto, de arquitectura, de prioridades
  • Las dependencias entre frentes: qué necesita cada frente del otro para poder avanzar

Lo que este capítulo NO va a incluir

  • El backlog de tareas concretas (eso vive en herramientas de gestión, no en el manual)
  • Las fechas exactas de cada milestone (eso cambia mes a mes)
  • La estrategia comercial o de salida al mercado (eso es del modelo de negocio)

Por qué este capítulo importa

Un equipo sin proceso explícito termina pisándose, duplicando trabajo, o peor: dejando huecos enteros sin cubrir porque cada uno asume que lo está haciendo otro. Este capítulo es el que evita que la coordinación dependa de memoria individual o de mensajes sueltos en WhatsApp.