Cómo está hecho por dentro, y lo que falta
Para quien revisa la seguridad de un proveedor: arquitectura, aislamiento entre clínicas, cifrado, acceso y continuidad. Sin sellos que nadie ha auditado.
- Estado
- Vigente
- Última revisión
- 28 sep 2026
Arquitectura
| Pieza | Qué hace | Dónde |
|---|---|---|
| Servicio | Recibe los mensajes, decide y responde. Sirve también el portal del paciente. | Cloudflare Workers · Red global: cada petición se atiende en el centro de datos más cercano |
| Base de datos | Fichas, conversaciones, citas y registros. | Supabase · UE (Irlanda · aws-eu-west-1) |
| Cola y caché | Guarda cada mensaje hasta procesarlo y los límites de uso. | Upstash · UE (eu-central-1 · eu-west-1) |
| Modelo de lenguaje | Redacta las respuestas; no guarda la base de datos. | OpenAI · Irlanda; trata los datos en EE. UU. con cláusulas contractuales tipo |
| Panel de la clínica | Aplicación aparte que habla con el servicio a través de su API. | Cloudflare Pages |
| Esta web | Información pública; no recibe datos de pacientes. | Vercel · Red global; los datos de la UE se tratan con cláusulas contractuales tipo |
Todos los proveedores y lo que recibe cada uno, en subencargados.
Aislamiento entre clínicas
El servicio entra en la base de datos con la clave de servicio (service_role), que se salta la seguridad por filas de Postgres. Cada consulta del servicio filtra por la clínica en el propio código, y un test y un analizador lo vigilan; la seguridad por filas de la base de datos protege el acceso del panel, no el del servicio. En el panel, la clínica de cada petición sale de la cuenta del usuario, con su sesión verificada, y nunca de lo que envía el navegador. Comprobado en el código
Un analizador revisa cada consulta del servicio a la base de datos y bloquea el cambio si alguna no filtra por clínica. El 27 sep 2026 revisaba 550 consultas, con 0 sin filtro. Comprobado en el código
Además, la base de datos impide por construcción que una cita, una conversación o una derivación de una clínica apunte a un paciente de otra: las claves ajenas incluyen la clínica. Comprobado en el código
Lo que no es
El analizador lee el código: no ve consultas construidas en tiempo de ejecución, y complementa las pruebas de aislamiento, no las sustituye. Nadie ajeno ha auditado este aislamiento, y hay mejoras de endurecimiento abiertas que no detallamos hasta cerrarlas.
Cifrado
- En tránsito: todo va por HTTPS y el servicio obliga al navegador a usarlo siempre (HSTS). Comprobado en el código
- En reposo: Cifrado de disco de la plataforma de Supabase; la clave la gestiona Supabase. Sin verificar
- Por columna: sólo las credenciales de la clínica (el token de WhatsApp y la clave de Cal.com) van cifradas dentro de la base de datos. Comprobado en el código
Lo que conviene saber
Las conversaciones con los pacientes se guardan en texto, sin cifrado por columna. No hay cifrado de «conocimiento cero»: el servicio lee los mensajes porque tiene que contestarlos. Y WhatsApp no llega cifrado de extremo a extremo hasta la clínica: el número y el contenido de cada mensaje de WhatsApp, que Meta descifra en sus servidores.
Acceso
- Panel de la clínica: cada usuario entra con su cuenta y sólo ve su clínica. El panel admite segundo factor de autenticación, pero hoy no lo exige. Según documento interno
- Portal del paciente: se entra con un enlace personal firmado que llega por WhatsApp. Un enlace para consultar caduca a las 24 horas; uno para exportar o borrar los datos, a los 30 minutos, y el primero nunca sirve para lo segundo. Comprobado en el código
- Acceso interno: el fundador tiene acceso a producción y trabaja con agentes de IA de terceros para programar y operar el servicio. Hoy esas herramientas pueden llegar a leer la base de datos de producción. La medida propuesta, pendiente de aprobar y de comprobar, es cerrarles el acceso a los datos de pacientes, no declararlas subencargadas; mientras tanto, lo contamos aquí y en lo que falta por decidir.
Avisos que entran desde fuera
Los servicios que avisan al nuestro firman cada aviso, y la firma se comprueba antes de procesar nada. Comprobado en el código
| Origen | Cómo se verifica |
|---|---|
| WhatsApp (Meta) | Firma HMAC-SHA256 de Meta, comparada en tiempo constante. |
| Stripe | Firma de Stripe con ventana de tiempo, comparada en tiempo constante. |
| Cal.com | Firma HMAC-SHA256, comparada en tiempo constante. |
Continuidad
| Medida | Estado |
|---|---|
| Copia de la base de datos | Copia diaria de la base de datos, la que incluye el plan contratado de Supabase. Según documento interno |
| Recuperación a un punto en el tiempo | No activada. Se activará con la primera clínica de pago. Hasta entonces, si hubiera que restaurar, se perdería como mucho un día. |
| Simulacro de restauración | No hecho. Hay una comprobación automática de que la copia existe y está completa; no la restaura. |
| Vigilancia | Un monitor externo comprueba el servicio cada 5 minutos. Los fallos que el propio servicio registra como críticos disparan un aviso por WhatsApp al fundador, y ese envío deja rastro. El estado, en estado del servicio. |
Vulnerabilidades
Antes de que un cambio llegue a producción, la integración continua pasa estos controles:
| Control | Si falla |
|---|---|
| Busca claves y contraseñas en todo el repositorio en cada cambio. | Bloquea el cambio |
| Cada cambio en la base de datos lleva escrito cómo deshacerlo. | Bloquea el cambio |
| Pruebas de ataque al asistente (manipulación de instrucciones, fugas de datos) según la lista OWASP para modelos de lenguaje. | Bloquea el cambio |
| Análisis estático de seguridad con CodeQL y Semgrep. | Avisa; no bloquea |
Además, en cada cambio corre la batería completa de 15.826 pruebas automáticas (recuento de la integración continua).
Nadie ajeno ha hecho una prueba de intrusión, y el análisis automático no la sustituye. Si encuentras un fallo, cuéntanoslo: divulgación responsable.
Cómo se cambia el servicio
- Los cambios se preparan en ramas y pasan la integración continua antes de fusionarse.
- Fusionar no despliega: el paso del servicio a producción es manual y se hace aparte.
- Los errores que se envían a Sentry pasan antes por un filtro que retira correos, teléfonos, documentos de identidad y enlaces del portal. Es un filtro por patrones: reduce lo que sale, no garantiza que no salga nada.
Qué datos se tratan y durante cuánto tiempo, en datos de pacientes. Qué hace y qué no hace el asistente, en IA y seguridad clínica.