diff --git a/docs/nueva-instancia.md b/docs/nueva-instancia.md index 1f0f544..bd33a28 100644 --- a/docs/nueva-instancia.md +++ b/docs/nueva-instancia.md @@ -45,7 +45,7 @@ cd /root/skeen-proyecto/infra/provision | `--puerto` | — | Puerto HTTP de Odoo; longpolling usa `puerto+3`. | | `--db` | `_odoo` | Nombre de la base de datos. | | `--db-role` | `` | Rol PostgreSQL. Por defecto se crea uno propio con password nueva; `--db-role skeen` usa el rol compartido (ver abajo). | -| `--pack` | `generico` | Giro para glosario y demo: `generico`, `spa`, `clinica`, `derma`. | +| `--pack` | `clinica` | Giro para glosario y demo: `clinica`, `spa`, `estetica`, `dental`, `custom`. | | `--demo` | off | Siembra servicios, clientes, empleados, citas, paquetes y monedero de ejemplo. | | `--demo-limpia` | off | Corre `demo_limpiar.py` al final (deja la instancia sin datos demo). | | `--dominio-lan` | — | Puerto LAN extra en el vhost (p. ej. `8881` → `http://:8881`). | @@ -120,19 +120,18 @@ lo referencian se carguen). `must_change_password = True`. - Oculta WACRM en `skeen.menu_roles` (salvo `--con-wacrm`). -Y **solo si existen en runtime** siembra los parámetros/modelos del nuevo -sistema de configuración (otro cambio en curso): +Y siembra los parámetros/modelos del sistema de configuración (los detecta en +runtime): | Qué | Cómo lo detecta | Qué siembra | |---|---|---| -| Glosario | llave `ir.config_parameter` `skeen.glosario` **o** modelo `skeen.glosario` | `pack` elegido | +| Glosario | llave `ir.config_parameter` `skeen.glosario` | `pack` elegido | | `skeen.clinic.settings` | el modelo existe | nombre, `url_publica = https://`, horario 08:00–19:00, moneda MXN | | `skeen.sucursal` | el modelo existe | 1 sucursal default con el nombre del negocio | | `skeen.service.category` | el modelo existe | semilla de categorías del pack | Lo que no exista se reporta como `TODO` en la salida y **no aborta** el -provisioning. Cuando ese cambio esté desplegado, una corrida nueva ya lo -siembra; para una instancia ya creada, se puede re-ejecutar solo el +provisioning. Para una instancia ya creada se puede re-ejecutar solo el post-install: ```bash diff --git a/docs/producto/README.md b/docs/producto/README.md new file mode 100644 index 0000000..b6a50cd --- /dev/null +++ b/docs/producto/README.md @@ -0,0 +1,21 @@ +# Documentación de producto SKEEN + +Índice de la documentación de producto: qué es cada documento y para quién es. +Para el detalle técnico de instalación y arquitectura, ver `docs/` (raíz). + +| Documento | Para quién | Qué encontrarás | +|---|---|---| +| [`venta-y-demo.md`](venta-y-demo.md) | Comercial | Qué es el producto, a qué giros aplica, diferenciadores, cómo hacer una demo, modelo de licenciamiento y precios sugeridos, y qué no incluye todavía. | +| [`configuracion-cliente.md`](configuracion-cliente.md) | Instalador / operador | Puesta en marcha de una instancia desde la interfaz: identidad, terminología, idioma, operación, catálogo, impuestos, reservas, recursos, usuarios y permisos, notificaciones, membresías, compras, comisiones, formularios, tickets, licencia, API, webhooks y PWA. Checklist de arranque. | +| [`licencias.md`](licencias.md) | Comercial / integrador | Planes, módulos y límites, modos aviso/bloqueo, formato de la clave firmada, herramienta del vendedor y endpoints de licencia. | +| [`api-terceros.md`](api-terceros.md) | Integrador | API pública `/skeen/api/v1/*`: autenticación, claves con alcances, endpoints y su gestión desde Configuración → API. | +| [`webhooks.md`](webhooks.md) | Integrador | Webhooks salientes: modelos, catálogo de eventos, firma HMAC, reintentos, endpoints y UI. | +| [`operacion-instancia.md`](operacion-instancia.md) | Operador / soporte | Backups automáticos verificados por instancia, panel/CLI multi-instancia, restauración y diagnóstico. | +| [`limitaciones-y-pendientes.md`](limitaciones-y-pendientes.md) | Todo el equipo | Deuda técnica y huecos conocidos, priorizados, con impacto y qué habría que hacer. | + +Documentos de instalación (fuera de `producto/`): + +| Documento | Para quién | Qué encontrarás | +|---|---|---| +| [`../nueva-instancia.md`](../nueva-instancia.md) | Instalador | Provisioning automatizado de una instancia white-label nueva. | +| [`../segunda-instancia.md`](../segunda-instancia.md) | Instalador | Procedimiento manual y caso `clinica2` (referencia). | diff --git a/docs/producto/api-terceros.md b/docs/producto/api-terceros.md index 4374fe1..af36524 100644 --- a/docs/producto/api-terceros.md +++ b/docs/producto/api-terceros.md @@ -45,9 +45,10 @@ comparación es en tiempo constante). | `POST /skeen/api/v1/patient_balance` | `pacientes.read` | | `POST /skeen/api/v1/wallet_redeem` | `monedero.write` | | `GET/POST /skeen/api/v1/services` | `servicios.read` | +| `GET /skeen/api/v1/health` | (público, sin credencial) | Una clave sin el alcance recibe **HTTP 403** con mensaje claro. La clave legacy -no tiene restricción de alcance. +no tiene restricción de alcance. `/health` no requiere credencial. Las respuestas son **JSON plano** (no JSON-RPC): códigos 200 correctos, `401/403` para clave ausente/inválida o sin alcance. diff --git a/docs/producto/configuracion-cliente.md b/docs/producto/configuracion-cliente.md index e62d7ac..67d80d0 100644 --- a/docs/producto/configuracion-cliente.md +++ b/docs/producto/configuracion-cliente.md @@ -8,11 +8,18 @@ primer usuario admin) usa el script de provisioning: ver [`nueva-instancia.md`](../nueva-instancia.md). Esta guía empieza cuando la instancia ya está levantada y con sesión de administrador. +La configuración vive en `Configuración` (panel con pestañas). El administrador +ve todas; gerencia ve un subconjunto (no ve la pestaña Clínica con los datos de +la instancia, ni Catálogos, API o Auditoría; en Licencia solo consulta el +estado). Salvo donde se diga lo contrario, cada bloque tiene un interruptor de +encendido y **apagado por defecto**: mientras no se active, la instancia se +comporta como una instalación base. + --- ## 1. Identidad de la clínica -**Configuración → Clínica → Identidad** +**Configuración → Clínica** (sección de identidad) | Qué | Efecto | |---|---| @@ -22,100 +29,344 @@ instancia ya está levantada y con sesión de administrador. | Color primario / acento | Se aplican en vivo sobre los 3 temas; vacío = tema original | | URL pública | Base para enlaces de pago, correos y el enlace de reservas | +La marca es **por instancia y no vive en el código**: sale del parámetro +`skeen.clinic.brand` (API `/skeen/frontend/v1/brand`). Por eso una misma build del frontend sirve a +varias clínicas white-label sin recompilar. + ## 2. Terminología (giro del negocio) **Configuración → Terminología** -Elige el pack según el negocio y ajusta cualquier término a mano: +Elige el pack según el negocio y ajusta cualquier término a mano. El glosario +tiene **24 términos** configurables (singular y plural de paciente, cita, visita, +expediente, médico, personal, sucursal, cabina/sala, servicio, paquete, receta y +tratamiento). -| Pack | Paciente | Cita | Visita | Expediente | Médico | Cabina | -|---|---|---|---|---|---|---| -| Clínica (default) | Paciente | Cita | Visita | Expediente | Médico | Cabina | -| Spa / Wellness | Cliente | Reserva | Sesión | Ficha | Terapeuta | Sala | -| Estética | Cliente | Cita | Sesión | Ficha | Especialista | Cabina | -| Dental | Paciente | Cita | Consulta | Expediente | Odontólogo | Consultorio | +| Término | Clínica (default) | Spa / Wellness | Estética | Dental | +|---|---|---|---|---| +| Paciente | Paciente | Cliente | Cliente | Paciente | +| Cita | Cita | Reserva | Cita | Cita | +| Visita | Visita | Sesión | Sesión | Consulta | +| Expediente | Expediente | Ficha | Ficha | Expediente | +| Médico | Médico | Terapeuta | Especialista | Odontólogo | +| Cabina / sala | Cabina | Sala | Cabina | Consultorio | +| Servicio | Servicio | Servicio | Servicio | Tratamiento | +| Receta | Receta | Recomendación | Receta | Receta | +| Tratamiento | Tratamiento | Tratamiento | Tratamiento | Procedimiento | El pack cambia menús, títulos, botones, estados y también los mensajes de -notificación y el portal público de reservas. +notificación y el portal público de reservas. El pack `custom` parte de Clínica +y aplica solo los ajustes manuales. -## 3. Operación +## 3. Idioma de la interfaz -**Configuración → Clínica (datos y horarios)** +**Menú de usuario → idioma** o **Configuración → Clínica** (selector ES/EN). + +- El selector cambia el idioma de toda la interfaz a **Español** o **English**. +- El idioma es **por navegador** (se guarda en el navegador del equipo), no por + clínica ni por usuario; dos equipos pueden ver idiomas distintos. +- La i18n y el glosario conviven: el **glosario** define el *vocabulario del + negocio* (paciente↔cliente, cita↔reserva) y **solo existe en español**; en + inglés se usa un mapa base equivalente. El **idioma** traduce el resto del + texto. En español manda el término del pack configurado. + +## 4. Operación + +**Configuración → Clínica** (datos y horarios) - Teléfono, email, dirección, sitio web, RFC, nota de ticket. -- **Horario de apertura y cierre**: define la rejilla de la agenda (default 08:00–19:00). -- Zona horaria y moneda base. +- **Horario de apertura y cierre**: define la rejilla de la agenda (default + 08:00–19:00). +- Zona horaria (default `America/Tijuana`) y moneda base (default `MXN`). -**Configuración → Sucursales**: alta de sedes (nombre, código, dirección, teléfono) -y cuál es la predeterminada. Cada cita pertenece a una sucursal. Las sucursales con -histórico no se borran: se desactivan. +**Configuración → Sucursales**: alta de sedes (nombre, código, dirección, +teléfono) y cuál es la predeterminada. Cada cita pertenece a una sucursal. Las +sucursales con histórico no se borran: se desactivan (quedan archivadas). Vienen +dos de ejemplo (Rosarito predeterminada y Tijuana). -**Configuración → Categorías de servicios**: las 4 categorías base (Consulta, -Tratamiento, Procedimiento, Paquete) se pueden renombrar y se pueden crear más -(p. ej. "Depilación", "Faciales"). Las de sistema no se borran. +**Configuración → Categorías**: las 4 categorías base (Consulta, Tratamiento, +Procedimiento, Paquete) se pueden renombrar y se pueden crear más (p. ej. +"Depilación", "Faciales"). Las de sistema no se borran. -## 4. Catálogo y precios +## 5. Catálogo y precios -- **Servicios**: nombre, categoría, precio, duración (define el tamaño del bloque en - la agenda), paquete y tasa de impuesto. +- **Servicios**: nombre, categoría, precio, duración (define el tamaño del bloque + en la agenda), paquete y tasa de impuesto. - **Inventario**: artículos, consumibles (con caducidad, que bloquea la venta al vencer) y su tasa de impuesto. -- Los precios se editan en Servicios / Inventario; el POS y la agenda los toman de ahí. +- Los precios se editan en Servicios / Inventario; el POS y la agenda los toman + de ahí. -## 5. Impuestos +## 6. Impuestos **Configuración → Clínica → Impuestos** (apagado por defecto) -- Activar impuestos, nombre (p. ej. IVA), tasa por defecto y catálogo de tasas. -- `Precios incluyen impuesto`: si el precio capturado ya trae impuesto, el sistema lo - desglosa automáticamente. +- Activar impuestos, nombre (default `IVA`), tasa por defecto (default `0`) y + catálogo de tasas (default `0, 8, 16`). +- `Precios incluyen impuesto`: si el precio capturado ya trae impuesto, el + sistema lo desglosa automáticamente. - Con impuestos activos: desglose en POS, tickets, estado de cuenta y reporte **Reportes → Impuestos** (por mes, servicio y sucursal, exportable). -## 6. Reservas en línea (portal del cliente) +## 7. Reservas en línea (portal del cliente) **Configuración → Reservas en línea** (apagado por defecto) -- Activar el portal y compartir el enlace `/reservar` de la clínica (el propio panel - muestra el enlace listo para copiar). -- Opciones: título y descripción visibles al cliente, confirmación manual o - automática de la cita reservada, permitir elegir especialista, permitir elegir - sucursal, máximo de días a futuro, anticipación mínima, teléfono de contacto, - mensaje de confirmación y política de cancelación (si el cliente puede cancelar y - con cuántas horas de anticipación). -- El cliente recibe un enlace propio para consultar o cancelar su cita. Las reservas - que llegan por el portal se distinguen en la agenda. +- Activar el portal y compartir el enlace `/reservar` de la clínica (el propio + panel muestra el enlace listo para copiar). +- Opciones (con sus valores por defecto entre paréntesis): título y descripción + visibles al cliente, confirmación manual o automática (`requiere_confirmacion` + = sí), permitir elegir especialista (sí), permitir elegir sucursal (no), máximo + de días a futuro (60), anticipación mínima en horas (2), teléfono de contacto, + mensaje de confirmación y política de cancelación (permitir cancelar = sí, + hasta 24 h antes). +- El cliente recibe un enlace propio para consultar o cancelar su cita. Las + reservas que llegan por el portal se distinguen en la agenda. -## 7. Usuarios, roles y permisos +## 8. Recursos (cabinas, salas y equipos) -**Configuración → Usuarios**: alta de usuarios, rol, menús visibles y, para agenda, -las 5 acciones específicas (consultar, agendar, editar, eliminar, generar visitas). +**Configuración → Recursos** (apagado por defecto) + +Sirve para agendar **recursos físicos** además del médico: cabinas, salas, +consultorios o equipos. Con el módulo apagado la agenda se ve igual que siempre +y no se valida nada. + +- **Catálogo** (`skeen.recurso`): nombre, código, tipo (Cabina / Sala / + Consultorio / Equipo / Otro), activo, secuencia, sucursales donde aplica + (vacío = todas), capacidad, costo por hora, color y notas. Vienen dos recursos + semilla (Cabina y Consultoría). +- **Opciones del bloque** (defaults): activo (no), `validar_solape` (sí), + `obligatorio_al_agendar` (no), `permitir_multiples` (sí), `mostrar_en_agenda` + (sí), `filtrar_como_doctores` (sí). +- **Asignación**: en el modal de la cita se eligen uno o varios recursos. +- **Validación de solape**: con `validar_solape` encendido el sistema impide dos + citas en el mismo recurso a la misma hora e informa con qué cita choca. También + respeta los bloqueos del recurso. +- **Bloqueos por recurso**: un bloqueo de agenda puede ser de un médico, de un + recurso o de ambos (`skeen.cita.bloqueo`): fecha, todo el día o rango horario, + motivo y serie (grupo). +- **Vista por recurso**: la agenda puede mostrar el recurso en la tarjeta y + ofrecer el filtro por recurso junto al de doctores. El reporte + **Reportes → Recursos** muestra ocupación e ingresos estimados por recurso. + +## 9. Usuarios, roles y permisos + +**Configuración → Usuarios**: alta de usuarios, rol, menús visibles y, para +agenda, las acciones específicas (consultar, agendar, editar, mover, eliminar, +generar visitas, ver todas, bloquear). **Configuración → Roles**: tres pestañas: -1. **Roles**: crear roles propios del negocio (p. ej. Terapeuta, Estilista, - Recepción de fin de semana), renombrar, ajustar jerarquía y activar/desactivar. -2. **Permisos**: 43 permisos por acción agrupados en 9 módulos, con botones - todo/ninguno. El backend los hace cumplir aunque el usuario manipule la interfaz. + +1. **Roles**: crear roles propios del negocio (p. ej. Terapeuta, Recepción de + fin de semana), renombrar, ajustar jerarquía y activar/desactivar. Vienen 10 + roles base (admin, médico, recepción, enfermería, cosmetología, psicóloga, + farmacia, gerencia, marketing, lectura). +2. **Permisos**: **71 permisos por acción agrupados en 16 grupos** (Agenda, + Recursos, Pacientes, Visitas, Ventas, Inventario, Servicios, Reportes, + WhatsApp, Notificaciones, Formularios, Membresías, Compras, Comisiones, + Configuración, Plataforma), con botones todo/ninguno. El backend los hace + cumplir aunque el usuario manipule la interfaz. 3. **Menús**: qué sección ve cada rol. Recomendación: partir del rol más parecido, ajustar y guardar. -## 8. Notificaciones +## 10. Notificaciones **Configuración → Notificaciones** (apagado por defecto, con modo prueba) -- Recordatorios automáticos antes de la cita (varias ventanas: 2 h, 24 h, 1 semana…), - confirmación al reservar en línea, felicitación de cumpleaños, seguimiento - post-visita y recuperación de pacientes que no se presentaron. -- Canales: WhatsApp y correo. Plantillas editables con vista previa. -- **Modo prueba**: registra lo que se habría enviado sin contactar a nadie — - úsalo para revisar textos antes de encenderlo. -- Historial de notificaciones enviadas por paciente y por cita, con reintento. +- Recordatorios automáticos antes de la cita (ventanas configurables de hasta + 168 h; default 24 h y 2 h), confirmación al reservar en línea, felicitación de + cumpleaños, seguimiento post-visita (horas configurable) y recuperación de + pacientes que no se presentaron. +- Canales: WhatsApp, correo o ambos (default WhatsApp). Plantillas editables con + vista previa y variables (`{nombre}`, `{cita}`, `{servicio}`, `{fecha}`, + `{hora}`, `{doctor}`, `{sucursal}`, `{telefono}`, `{enlace}`, `{formulario}` y + las de membresía `{plan}`, `{membresia}`, `{monto}`, `{sesiones}`, `{periodo}`). +- **Modo prueba** (default): registra lo que se habría enviado sin contactar a + nadie — úsalo para revisar textos antes de encenderlo. +- **Configuración → Notificaciones enviadas**: historial por paciente y por + cita, con reintento. -## 9. Tickets y documentos +## 11. Membresías + +**Configuración → Membresías** (apagado por defecto) y **Membresías** (menú). + +Una membresía **no es un paquete**: es un plan recurrente con vigencia, +sesiones incluidas, cobro periódico, congelamiento y renovación. + +- **Planes** (`skeen.membresia.plan`): precio y moneda, periodicidad (semanal, + mensual, trimestral, semestral, anual), sesiones incluidas por periodo (0 = + ilimitadas), servicios y categorías incluidos, descuento en servicios no + incluidos, cargo de inscripción, meses mínimos, permite congelamiento, + sucursales y servicio con el que se cobra. +- **Opciones del bloque** (defaults): activo (no), `dias_aviso_renovacion` + (`[7, 1]`), `permitir_congelamiento` (sí), `dias_max_congelamiento_anio` (30), + `renovacion_automatica_default` (no), `descuento_porcentaje_default` (0), + `permitir_pausa_pago` (no), `generar_cargo_al_renovar` (sí), `dias_gracia` (5). +- **Alta**: la membresía recibe folio `MEM-` y calcula su periodo actual, próximo + cobro y fin de compromiso. +- **Cobro**: genera una venta y un pago normales (aparece en cortes de caja como + cualquier venta). También cobra la inscripción la primera vez. +- **Consumo desde POS/expediente**: el consumo de sesiones **no se descuenta en + silencio**; el POS o la cita llaman explícitamente a "usar sesión de + membresía". Al cancelar una cita que usó una sesión, la sesión se libera. +- **Congelamiento**: se congela con rango y motivo, respetando el tope anual; al + descongelar se corre el fin de periodo y el próximo cobro. +- **Renovación**: manual (avanza el periodo y genera el cargo si aplica) o + automática por cron. +- **Vencimientos y avisos**: un cron diario marca vencidas (con días de gracia), + envía avisos de renovación en cada ventana y descongela al terminar la ventana. +- **Reporte**: **Membresías → reporte** con ingreso recurrente por periodo. + +## 12. Compras y proveedores + +**Configuración → Compras** (apagado por defecto) y **Compras** (menú). + +- **Proveedores**: sobre el contacto (`res.partner`) con marca propia de + proveedor, días de crédito, contacto de compras, banco, cuenta/CLABE y notas. + Un proveedor con historial no se borra: se desactiva. +- **Órdenes de compra** (`skeen.compra`): folio `OC-`, proveedor, líneas de + artículo, moneda (MXN/USD), descuento e impuesto por línea. Estados: Borrador → + Enviada → Recibida parcial / Recibida → Cancelada. Cancelar solo se permite si + no hubo recepciones (si ya entró mercancía se usa una baja/ajuste). +- **Recepción total o parcial**: cada recepción es acumulativa; al recibir se + carga inventario (movimiento tipo compra) y se puede capturar lote y + caducidad. +- **Costo promedio**: al recibir se recalcula el costo promedio ponderado del + artículo y se guarda el último costo (si `actualizar_costo_promedio` está + encendido). +- **Pagos a proveedor**: egresos separados de los cobros a pacientes (no + aparecen en corte de caja ni en estado de cuenta del paciente). +- **Cuentas por pagar**: saldo por proveedor y reporte con antigüedad. +- **Reportes**: **Reportes → Compras** y margen por artículo (contra costo + promedio y precio de venta sin impuesto). +- **Opciones del bloque** (defaults): activo (no), `actualizar_costo_promedio` + (sí), `permitir_recepcion_parcial` (sí), `requiere_autorizacion` (no), + `dias_credito_default` (0), `margen_minimo_alerta` (0), + `permitir_compras_sin_orden` (no). + +## 13. Comisiones + +**Configuración → Comisiones** (apagado por defecto), **Reportes → Comisiones** +y **Liquidaciones** (menú). + +Con el módulo apagado se conserva el reporte de comisiones de siempre (porcentaje +plano por empleado). Al encenderlo se usa el motor de reglas. + +- **Reglas** (`skeen.comision.regla`): alcance global, por categoría, por + servicio, por artículo, por plan de membresía o por paquete; tipo porcentaje, + monto fijo o escalonado por metas; prioridad; dirigidas a un empleado, a un + tipo de staff (doctor/cosmetóloga) o a todos; vigencia; y base propia opcional. + La regla ganadora se decide por prioridad, luego por especificidad (artículo > + servicio > membresía/paquete > categoría > global) y luego por + empleado > tipo de staff > genérica. Sin ninguna regla aplicable se usa el + porcentaje de comisión del empleado (respaldo de compatibilidad). +- **Base**: `cobrado` (default, sobre lo efectivamente pagado) o `vendido` + (subtotal de la línea). Opcionalmente suma impuestos y resta la parte devuelta. +- **Escalonados**: el porcentaje se decide con la venta total del periodo del + empleado y se aplica a cada línea cubierta. +- **Metas y bonos** (`skeen.comision.meta`): por empleado y periodo (`AAAA-MM` o + `mensual`), monto objetivo y bono fijo o porcentaje sobre la venta. +- **Ajustes** manuales firmados (+/−), que suman o restan a la liquidación. +- **Liquidaciones**: se generan por empleado y periodo; al generarlas el desglose + queda **congelado** (ya no cambia aunque después se editen reglas o precios). + Estados Borrador → Pagada, o Borrador → Cancelada (una pagada no se cancela: + se registra un ajuste). Folio `LIQ-`. +- **Opciones del bloque** (defaults): activo (no), `base` (`cobrado`), + `incluir_impuestos` (no), `neto_de_devoluciones` (sí), + `comisionar_membresias` (sí), `comisionar_paquetes` (sí), `comisionar_productos` + (sí), `permitir_ajustes_manuales` (sí), `dia_corte` (1), `redondeo` (2 + decimales), `pago_minimo` (0). + +## 14. Formularios y consentimientos + +**Configuración → Formularios** y, en el expediente del paciente, la pestaña de +formularios. + +- **Plantillas** (`skeen.formulario.plantilla`): tipo consentimiento informado, + nota de expediente, encuesta o autorización; con campo de **texto legal**, + requerir firma y/o foto, duración estimada y asociación opcional a sucursales + y servicios. Las plantillas se **versionan**: cada respuesta guarda la versión + con la que se llenó. +- **Tipos de campo** (12): texto, texto largo, número, fecha, selección, + multiselección, casilla, escala, firma, foto, archivo y consentimiento. Los + campos de foto/archivo pueden marcarse como antes / después / otro, lo que + arma la **galería antes/después** del expediente. +- **Envío**: por WhatsApp, correo o enlace. El enlace es un token firmado (HMAC, + vigencia 180 días) y deja de servir al llenarse. +- **Llenado por el paciente**: página pública `/formulario/` (también + funciona en el celular) con firma capturada como PNG (hasta 3 MB) y fotos + (hasta 5 MB cada una, máximo 10). El sistema valida campos obligatorios, firma + y fotos requeridas. +- **Historial**: respuestas por paciente con canal, fecha, firma y fotos. + +## 15. Tickets y documentos **Configuración → Tickets**: ancho (58/80 mm), fuente, logo y qué secciones se -imprimen (incluida la de impuestos). Se aplica al ticket de venta y al de reimpresión. +imprimen (incluida la de impuestos). Se aplica al ticket de venta y al de +reimpresión. Los perfiles de ticket son **por instancia**, con defaults neutros: +una instancia nueva no arrastra datos de SKEEN. + +## 16. Licencia + +**Configuración → Licencia** (admin; gerencia también ve el estado). + +Cada instancia white-label puede llevar una **licencia firmada** que decide qué +módulos incluye y sus límites de uso. Sin licencia aplicada el sistema se comporta +con todas las funciones habilitadas. + +- **Planes**: `basico`, `profesional`, `enterprise` y `custom`. + - Básico: agenda, pacientes, POS, inventario y reportes. + - Profesional: Básico + WhatsApp, notificaciones, reservas en línea y recursos. + - Enterprise: todos los módulos. + - Custom: lo que diga la clave. +- **Módulos gateables** (controlables por licencia): WhatsApp, notificaciones, + reservas en línea, recursos, membresías, compras, comisiones y formularios. + Login, agenda, pacientes, POS, inventario, reportes y configuración **nunca** se + bloquean. +- **Límites**: usuarios, sucursales, citas del mes y almacenamiento (MB). `0` = + sin límite. +- **Modo**: `aviso` (default; solo advierte y registra en el log) o `bloqueo` + (oculta menús, responde 403 en los endpoints del módulo y aplica los límites). +- **Cómo aplicar una clave**: pegar la clave `SKN1...` en Configuración → Licencia + y guardar. La clave se verifica contra la firma y la vigencia; si es inválida o + vencida responde 400 y no sobrescribe la licencia previa. Un campo vacío quita + la licencia y vuelve a habilitar todo. El detalle del formato de la clave, la + herramienta del vendedor y los endpoints está en + [`licencias.md`](licencias.md). + +## 17. API para terceros + +**Configuración → API** (admin). Gestión de claves con alcances (*scopes*), +vencimiento y revocación, sobre la API pública `/skeen/api/v1/*` que consume +Hermes. La clave se muestra una sola vez al crearla. Alcances disponibles: +`citas.read`, `citas.write`, `pacientes.read`, `servicios.read` y +`monedero.write`. El detalle está en [`api-terceros.md`](api-terceros.md). + +## 18. Webhooks + +**Configuración → Webhooks** (admin/gerencia). Notificación de eventos de la +clínica hacia sistemas externos, con patrón outbox + reintentos + bitácora y +firma HMAC de cada entrega. Sin webhooks activos no se emite ni se envía nada. +El catálogo de eventos, la verificación de la firma y los endpoints están en +[`webhooks.md`](webhooks.md). + +## 19. PWA (instalable en tablet y celular) + +El panel es una **aplicación web instalable** (PWA), sin tienda de aplicaciones. + +- **Instalar**: abrir el panel en el navegador del dispositivo. En Android/Chrome + aparece el aviso "Instalar aplicación"; en iPhone/Safari se usa "Compartir → + Añadir a pantalla de inicio" (el aviso trae la guía de iOS). +- **Comportamiento offline**: un service worker precachea el *app shell* y los + assets con hash. La navegación es *network-first* (un deploy nuevo se ve al + primer refresh); si no hay red se sirve la última copia del shell o una página + `offline.html`. Las llamadas al API (`/api/*`) y cualquier petición con + credenciales **nunca** se cachean. +- **Limitación**: los iconos y el nombre del manifest son **fijos por build** + ("Panel Clínico" e iconos genéricos). No cambian con la marca de la instancia; + cambiarlos requiere recompilar el frontend. La marca visual (nombre, logos, + colores) sí es por instancia y no requiere build. --- @@ -123,25 +374,44 @@ imprimen (incluida la de impuestos). Se aplica al ticket de venta y al de reimpr - [ ] Identidad: nombre, logos, colores, URL pública. - [ ] Terminología: pack del giro + ajustes finos. -- [ ] Horarios, zona horaria, sucursales, categorías. +- [ ] Idioma de la interfaz (si el cliente no trabaja en español). +- [ ] Horarios, zona horaria, moneda, sucursales, categorías. - [ ] Catálogo de servicios con precios y duraciones. -- [ ] Inventario y consumibles (caducidades). +- [ ] Inventario y consumibles (caducidades y costos reales). - [ ] Impuestos (tasa por defecto + tasas por servicio/artículo). - [ ] Usuarios y roles/permisos. +- [ ] Recursos (si la agenda depende de cabinas/salas/equipos). +- [ ] Membresías (si vende planes recurrentes). +- [ ] Compras y proveedores (si controla abasto y margen). +- [ ] Comisiones (reglas, metas y liquidaciones). +- [ ] Formularios y consentimientos. - [ ] Reservas en línea (activar y difundir el enlace). - [ ] Notificaciones en modo prueba → revisar textos → encender. - [ ] Tickets: formato y secciones. +- [ ] Licencia: aplicar la clave del plan contratado. +- [ ] API / Webhooks si se integra con terceros. - [ ] Confirmar que las credenciales del admin se cambiaron. ## Estado del producto por fases +Todas las fases están **entregadas**. + | Fase | Alcance | Estado | |---|---|---| | 1 | Capa de configuración (terminología, sucursales, categorías, ajustes, colores, horarios, URLs de pago), defaults neutros, provisioning de instancias | Entregado | -| 2.1 | Roles y permisos editables (43 permisos) | Entregado | +| 2.1 | Roles y permisos editables | Entregado | | 2.2 | Impuestos configurables | Entregado | | 2.3 | Portal público de reservas en línea | Entregado | -| 2.4 | Recordatorios y notificaciones automáticas | En curso | -| 2.5 | Consentimientos y formularios digitales con fotos | Pendiente | -| 2.6 | Membresías y suscripciones | Pendiente | -| 3 | Recursos en agenda, compras/proveedores, comisiones por reglas, PWA, i18n, API keys/webhooks, panel multi-cliente | Pendiente | +| 2.4 | Recordatorios y notificaciones automáticas | Entregado | +| 2.5 | Formularios digitales y consentimientos con firma y fotos | Entregado | +| 2.6 | Membresías y suscripciones | Entregado | +| 3.1 | Recursos físicos en la agenda | Entregado | +| 3.2 | Compras y proveedores | Entregado | +| 3.3 | Comisiones por reglas y liquidación | Entregado | +| 3.4 | PWA instalable y branding por instancia | Entregado | +| 3.5 | Licenciamiento por plan, API keys gestionables y webhooks | Entregado | +| 3.6 | i18n español/inglés | Entregado | +| Operación | Backups automáticos verificados y panel/CLI multi-instancia | Entregado | + +Los pendientes y limitaciones conocidos (los que aún no están cerrados) viven en +[`limitaciones-y-pendientes.md`](limitaciones-y-pendientes.md). diff --git a/docs/producto/limitaciones-y-pendientes.md b/docs/producto/limitaciones-y-pendientes.md new file mode 100644 index 0000000..d50c597 --- /dev/null +++ b/docs/producto/limitaciones-y-pendientes.md @@ -0,0 +1,216 @@ +# Limitaciones y pendientes conocidos + +Lista honesta y priorizada de la deuda técnica y los huecos del producto, con su +impacto. Cada punto dice qué pasa, a quién afecta y qué habría que hacer. Se +actualiza a medida que se cierran. + +Prioridad: **Alta** = riesgo o función prometida que no está; **Media** = afecta +la operación o la venta de algún cliente; **Baja** = deuda de orden. + +--- + +## Prioridad alta + +### 1. Firma de licencias simétrica (HMAC) + +**Qué pasa:** la clave de licencia se firma con HMAC-SHA256 y la clave del +vendedor debe estar presente en la instancia para validarla (parámetro +`skeen.licencia.vendor_key`, entorno o `/root/.skeen-licencias/vendor.key`). Al +ser simétrica, un cliente con acceso al servidor puede leerla y **generar sus +propias licencias** (módulos y límites a su gusto). + +**A quién afecta:** al negocio (se pierde el control comercial del licenciamiento). + +**Qué habría que hacer:** migrar a **firma asimétrica** (el vendedor firma con +clave privada; la instancia solo lleva la pública para verificar). Mientras +tanto, mantener la clave del vendedor fuera de las instancias de cliente en un +despliegue real. + +### 2. Llaves embebidas en `webhook-bridge.js` + +**Qué pasa:** `/root/skeen-proyecto/hermes/hermes/webhook-bridge.js` trae llaves +como *fallback* embebidas en el código (proveedor de IA, Hermes y WACRM). Cualquiera +con acceso al repo las ve. + +**A quién afecta:** seguridad (las llaves pueden filtrarse y usarse). + +**Qué habría que hacer:** retirar los valores por defecto, exigir variables de +entorno y **rotar** las llaves expuestas. No es tarea de la documentación: es un +riesgo a sanear en el código. + +### 3. Asistente de IA de WhatsApp (Sofía/Hermes) en reparación + +**Qué pasa:** la herramienta del asistente para consultar y agendar estaba rota: +faltaba `ODOO_API_KEY`, el sandbox de `execute_code` estaba bloqueado y había +*rate limit* del proveedor. La bandeja y los leads de WhatsApp sí funcionan. + +**A quién afecta:** al cliente que espera el bot autónomo de WhatsApp. + +**Qué habría que hacer:** cerrar el arreglo (clave, sandbox y límite del +proveedor) y **actualizar esta sección a "resuelto" con la fecha**. No afirmar +que ya funciona mientras no se valide de punta a punta. + +### 4. Clave legacy de la API con todos los alcances + +**Qué pasa:** la API pública acepta la *clave legacy* de Hermes +(`skeen.api.legacy_key`, default en el código `skeen_api_key_2026`), que **no +tiene restricción de alcances**. Si una instancia conserva el valor por defecto, +cualquiera que lo conozca tiene acceso total a la API. + +**A quién afecta:** seguridad de la API. + +**Qué habría que hacer:** confirmar que el parámetro se rotó en cada instancia y +que no conserva el valor por defecto; usar claves con alcance para las +integraciones nuevas. + +### 5. Un límite de licencia excedido responde 500 en vez de 400 + +**Qué pasa:** al superar un límite (`usuarios_max`, `sucursales_max`, +`citas_mes_max`, `almacenamiento_mb`) el backend lanza un error de negocio con +mensaje claro, pero los controladores lo devuelven como **HTTP 500** en lugar de +400. + +**A quién afecta:** a los integradores (el código de estado no distingue "te +pasaste del límite" de "algo se rompió"). + +**Qué habría que hacer:** capturar el error de límite en los controladores y +responder **400** con el mensaje. + +--- + +## Prioridad media + +### 6. Secciones nuevas sin QA visual manual + +**Qué pasa:** en la instancia de pruebas las secciones Licencia / API / Webhooks, +Comisiones y Compras se verificaron por API y por build, pero **no se recorrieron +a mano** en el navegador. + +**A quién afecta:** riesgo de detalles de usabilidad (textos, estados, formatos) +no detectados. + +**Qué habría que hacer:** una pasada manual por esas pestañas de Configuración y +sus páginas (Compras, Liquidaciones) en un entorno con datos. + +### 7. Precios reales del inventario en $0 + +**Qué pasa:** los ~170 artículos del inventario histórico siguen con precio de +venta `$0` (verificado: 171 de 171 en la base principal). + +**A quién afecta:** POS (vendería en $0), reportes de margen y de ventas. + +**Qué habría que hacer:** capturar los precios con el cliente (carga masiva o +manual) antes de usar márgenes y de vender productos. + +### 8. Huecos del histórico migrado + +**Qué pasa:** + +- **799 folios de venta** ($1.29M, 2.5% del cobrado) no se importaron porque sus + pacientes nunca se migraron a Odoo (documentado en + `docs/migracion-concentrado.md`). +- **Citas históricas sin médico:** el import dejó `doctor_id` vacío en las citas + que no pudo resolver. `docs/migracion-concentrado.md` cifra en ~8,350 las + asociadas a los doctores fantasma (ids legacy 34–39/44/51), pero hoy la base + tiene **~27,500 citas con `legacy_id` y sin médico**, así que el total sin + resolver es mayor que esa cifra. +- **139 filas todo-$0** (sesiones de paquete) también omitidas. + +**A quién afecta:** a los reportes históricos (por médico, ingresos y comisiones +retroactivas) y a la conciliación con el legacy. + +**Qué habría que hacer:** definir con el cliente si se resuelven los médicos de +ese histórico (mapeo manual o heurística), recuperar los 799 folios si aparecen +los pacientes, y **actualizar la cifra de citas sin médico** en el doc de +migración para que no se contradiga con la base. + +### 9. Cobertura de i18n incompleta + +**Qué pasa:** la internacionalización cubre las superficies principales y las +páginas públicas, pero quedan sin traducir varias pantallas secundarias (Visitas, +Consultas, Servicios, Médicos, Paquetes, Ventas, Mis ventas, Pagos, Monedero, +Tickets, Cortes, Inventario, Compras, Liquidaciones, Membresías, Chat/WACRM y +los paneles internos de Configuración) y los textos de impresión. Además el +idioma es **por navegador** (no se persiste por clínica ni por usuario): +`clinic-settings.idioma_default` no se guarda. + +**A quién afecta:** a los clientes que trabajan en inglés. + +**Qué habría que hacer:** ir traduciendo las pantallas secundarias por prioridad +y, si se quiere, persistir el idioma por clínica o por usuario. + +### 10. Glosario solo en español + +**Qué pasa:** el glosario (vocabulario de negocio) es por clínica y **solo existe +en español**; en inglés se usa un mapa base equivalente, no el término +personalizado del cliente. + +**A quién afecta:** clientes que configuran términos propios y trabajan en inglés. + +**Qué habría que hacer:** decidir si hace falta glosario por idioma; hoy es una +limitación de diseño aceptada. + +### 11. El pack demo "dental" siembra servicios de dermatología/estética + +**Qué pasa:** en `postinstall_clinica.py`, los servicios de demo del pack +`dental` son de otro giro ("Consulta dermatológica", "Peeling químico", +"Depilación láser"…). Un demo dental muestra el catálogo equivocado. + +**A quién afecta:** demos y arranques de clientes dentales. + +**Qué habría que hacer:** reemplazar ese set por servicios dentales reales (y +verificar los demás packs). + +### 12. Alcanzabilidad de la instancia de pruebas + +**Qué pasa:** `clinica.consultoria-as.com` puede no ser alcanzable desde fuera +hasta que se agregue el *hostname* en el túnel de Cloudflare (el túnel es +administrado remotamente). El acceso LAN siempre funciona. + +**A quién afecta:** demos y QA remotos. + +**Qué habría que hacer:** agregar el *ingress* en el dashboard de Cloudflare y +verificar la URL pública. + +--- + +## Prioridad baja + +### 13. Retención de backups frente a más instancias + +**Qué pasa:** la retención es por instancia (14 diarios / 8 semanales / 6 +mensuales); cada cliente nuevo suma un juego de backups y disco. + +**A quién afecta:** al operador de la VPS. + +**Qué habría que hacer:** revisar el espacio antes de sumar clientes y ajustar +`RETAIN_*` en `backup.env` si es necesario. La verificación de restauración se +auto-omite si no hay espacio. + +### 14. Rotación del nombre del *manifest* / iconos de la PWA + +**Qué pasa:** el manifest de la PWA usa nombre e iconos **fijos por build** +("Panel Clínico"); no toman la marca de la instancia. + +**A quién afecta:** presentación (al instalar la app el icono/nombre no es el del +cliente). + +**Qué habría que hacer:** si se quiere icono por cliente, generar un manifest por +instancia en el despliegue; hoy se acepta como limitación (la marca dentro del +panel sí es por instancia). + +--- + +## Corregido en esta pasada de documentación + +Para que no vuelva a citarse como pendiente: + +- `docs/producto/configuracion-cliente.md` decía "43 permisos por acción + agrupados en 9 módulos": el catálogo actual es de **71 permisos en 16 grupos**. +- La tabla "Estado del producto por fases" marcaba las fases 2.4–2.6 y 3 como + pendientes: **todas están entregadas**. +- `docs/nueva-instancia.md` listaba `--pack` con `generico` por defecto y los + valores `generico, spa, clinica, derma`: los reales son default `clinica` y + `clinica, spa, estetica, dental, custom`. +- `docs/producto/api-terceros.md` no listaba el endpoint `/skeen/api/v1/health` + (público, sin credencial). Se agregó. diff --git a/docs/producto/venta-y-demo.md b/docs/producto/venta-y-demo.md new file mode 100644 index 0000000..0ea376d --- /dev/null +++ b/docs/producto/venta-y-demo.md @@ -0,0 +1,178 @@ +# Venta y demo + +Guía comercial corta para presentar y vender el producto. Los detalles técnicos +y de configuración están en el resto de `docs/producto/`. + +## Qué es + +Un **software de gestión para clínicas y negocios de bienestar**: agenda, +expediente del paciente, punto de venta, inventario, cobros y reportes, con +WhatsApp integrado. Es un producto **multi-giro configurable** y **white-label**: +la marca, el idioma del negocio (terminología) y los módulos activos se ajustan +por cliente sin tocar código, y cada cliente corre en su **propia instancia** +con sus propios datos y dominio. + +## A qué giros aplica + +El giro se elige con un *pack* de terminología; cambiar de giro es configuración, +no desarrollo. + +| Giro | Terminología (ejemplo) | Notas | +|---|---|---| +| Clínica médica | Paciente, Cita, Médico, Expediente | Pack por defecto. | +| Spa / wellness | Cliente, Reserva, Terapeuta, Sesión, Sala | Agendas por recurso (salas). | +| Estética | Cliente, Cita, Especialista, Ficha, Cabina | Combinable con membresías. | +| Dental | Paciente, Cita, Odontólogo, Consulta, Consultorio | Cualquier término se puede editar a mano. | + +## Diferenciadores + +- **Multi-giro configurable**: un solo producto para clínica, spa, estética o + dental; terminología, categorías y sucursales se ajustan por cliente. +- **Agenda con recursos**: cabinas, salas, consultorios y equipos con validación + de solape, bloqueos por recurso y vista/filtro por recurso. +- **Expediente con firma y fotos**: consentimientos y formularios digitales + firmados por el paciente desde su celular, con galería antes/después. +- **Membresías**: planes recurrentes con sesiones incluidas, cobro, congelamiento + y avisos de renovación (distinto de los paquetes de sesiones prepagados). +- **Comisiones por reglas**: porcentaje, monto fijo o escalonado por metas; base + vendido/cobrado; metas con bonos; liquidaciones con recibo. +- **Compras y proveedores**: órdenes de compra, recepción total/parcial, costo + promedio, lotes/caducidades, cuentas por pagar y margen por artículo. +- **WhatsApp integrado**: bandeja, leads y asistente con IA (ver limitaciones: + el asistente está en reparación). +- **Reservas en línea**: portal público de auto-agendado para el paciente, con + enlace propio para consultar o cancelar. +- **PWA**: se instala en tablet o celular como una app, con arranque offline. +- **Multi-instancia**: cada cliente con su dominio, secretos y base de datos + aislados, sobre el mismo código. +- **Licenciamiento por plan**: qué módulos y cuántos usuarios/sucursales/citas + incluye cada cliente, con modo aviso o bloqueo. + +## Cómo hacer una demo + +El escenario ideal es una **instancia demo desechable** con datos de ejemplo, +porque los datos se marcan y se pueden borrar sin afectar a nadie. + +### 1. Preparar la instancia demo + +```bash +cd /root/skeen-proyecto/infra/provision + +# Simular primero (no escribe nada) +./provision_clinica.py \ + --slug demo-cliente --nombre "Demo Cliente" \ + --dominio demo.consultoria-as.com --puerto 8071 --db demo_cliente_odoo \ + --pack clinica --demo --dry-run + +# Ejecutar de verdad +./provision_clinica.py \ + --slug demo-cliente --nombre "Demo Cliente" \ + --dominio demo.consultoria-as.com --puerto 8071 --db demo_cliente_odoo \ + --pack clinica --demo +``` + +- `--pack` elige el giro del demo: `clinica`, `spa`, `estetica`, `dental` o + `custom` (default `clinica`). +- Las credenciales quedan en + `/root/backups/demo-cliente-credenciales-.txt` (chmod 600): dominio, + acceso LAN y la contraseña del admin del frontend (forzará cambio al primer + login). +- Para publicar el dominio hay que agregar el *ingress* en el dashboard de + Cloudflare (Zero Trust → Networks → Tunnels), igual que cualquier instancia + nueva; mientras tanto se usa el acceso LAN. + +### 2. Qué datos trae el demo (`--demo`) + +Coherentes con el pack elegido y marcados para poder limpiarlos: + +- ~10 servicios con precio y duración (`DEMO-` en el código). +- 15 pacientes de ejemplo. +- 3 empleados (`doctor`, `doctor`, `cosmetologa`) con comisión configurada. +- 20 citas repartidas en la semana actual (estados pendiente/confirmada). +- 3 paquetes, con una compra de paquete a un paciente. +- Saldo de monedero para 5 pacientes. + +Los ids se guardan en el parámetro `skeen.demo.ids`. Para borrar el demo y +entregar la instancia limpia: + +```bash +/root/odoo-venv/bin/python /root/skeen-proyecto/infra/provision/demo_limpiar.py \ + --conf /root/demo-cliente-odoo.conf --db demo_cliente_odoo +``` + +(o volver a provisionar con `--demo-limpia`). + +> La instancia de pruebas `clinica.consultoria-as.com` es la segunda instancia +> **white-label** y no trae datos `DEMO-`: si la usas para demo, ten en cuenta que +> sus datos son reales de esa clínica. Revisa que sea alcanzable desde fuera (el +> hostname debe estar en el túnel de Cloudflare). + +### 3. Guion sugerido (15–20 min) + +1. **Login y marca**: muestra el nombre, el logo y los colores del cliente + (todo configurable). +2. **Dashboard**: vistazo general del día. +3. **Agenda**: arrastra una cita, muéstrala por médico y por recurso (cabina/sala), + abre un bloqueo de agenda. +4. **Paciente y expediente**: alta rápida, historial, formulario de consentimiento + con firma y foto antes/después. +5. **Punto de venta**: cobra un servicio, aplica descuento, muestra el ticket y el + desglose de impuestos. +6. **Membresías**: cobra un periodo y consume una sesión desde el POS. +7. **Recursos / Compras / Comisiones**: según el interés del cliente (ocupación + por cabina, orden de compra con recepción, liquidación de comisiones con + recibo). +8. **Reservas en línea**: abre `/reservar` en el celular y agenda como paciente. +9. **Notificaciones**: muestra el modo prueba y el historial. +10. **PWA**: instala el panel en el celular (o muestra el aviso de instalación). +11. **Configuración → Licencia**: explica el plan y los límites. + +## Modelo de licenciamiento y precios sugeridos + +Cada instancia lleva una **licencia firmada** con un plan y sus límites. Planes: + +| Plan | Incluye | Para quién | +|---|---|---| +| Básico | Agenda, pacientes, POS, inventario, reportes | Consultorio pequeño. | +| Profesional | Básico + WhatsApp, notificaciones, reservas en línea, recursos | Clínica/spa en operación. | +| Enterprise | Todos los módulos (membresías, compras, comisiones, formularios…) | Negocio multi-sucursal. | +| Custom | Lo que se acuerde | Casos especiales. | + +Además se pueden fijar topes de usuarios, sucursales, citas por mes y +almacenamiento. El detalle técnico está en [`licencias.md`](licencias.md). + +> **Precios sugeridos (ejemplo, no oficiales).** Son puntos de partida para +> cotizar en MXN mensuales; ajústalos a tu mercado y a los límites de cada +> cliente. La puesta en marcha (provisioning, marca, migración de catálogo y +> capacitación) suele cobrarse aparte. +> +> | Plan | Sugerido / mes | +> |---|---| +> | Básico | $1,500 – $2,000 | +> | Profesional | $2,500 – $3,500 | +> | Enterprise | $4,000 – $6,000 | +> | Custom | A medida | +> +> Extras a cotizar aparte: WhatsApp con número propio, migración de histórico, +> capacitación y soporte ampliado. + +## Qué no incluye todavía + +Sé honesto en las demos; el detalle y el plan de corrección está en +[`limitaciones-y-pendientes.md`](limitaciones-y-pendientes.md). En resumen: + +- **El asistente de IA de WhatsApp (Sofía/Hermes) está en reparación**: su + herramienta para consultar y agendar estaba rota. La bandeja y los leads de + WhatsApp sí funcionan; no prometas el bot autónomo hasta que se cierre el + arreglo. +- **La firma de licencias es simétrica (HMAC)**: en un despliegue real la clave + del vendedor no debería vivir en las instancias de cliente; se recomienda + migrar a firma asimétrica. +- **La i18n cubre las pantallas principales**; quedan sin traducir varias + pantallas secundarias y los textos de impresión. El idioma es por navegador. +- **Los precios reales del inventario histórico siguen en $0** (~170 artículos): + hay que capturarlos con el cliente antes de usar reportes de margen. +- **Hay huecos en el histórico migrado**: folios de venta y citas sin médico que + no se pudieron importar o resolver. +- **Sin facturación fiscal / CFDI**: los impuestos son configurables, pero no hay + motor de facturación electrónica.