Arquitectura de un SaaS B2B en España: decisiones que nadie documenta
Las decisiones que importan no están en los tutoriales
La mayoría de los recursos técnicos sobre SaaS explican cómo construir features. Muy pocos explican cómo tomar las decisiones de arquitectura que afectan a todo lo demás: multitenancy, autenticación, observabilidad, cumplimiento normativo, diseño de API. Son decisiones que, tomadas mal al principio, cuestan meses de refactor después —cuando el producto ya tiene clientes, cuando el equipo ya tiene inercia, cuando cada cambio requiere coordinación con usuarios reales.
Llevamos tres productos propios en producción (Race+, Aedevita, Nexen) y hemos construido o rescatado decenas de proyectos de cliente. Lo que sigue son las decisiones que más veces hemos tenido que tomar, y lo que hemos aprendido de tomarlas en contextos distintos: salud regulada, plataformas omnicanal, software de cara a administración pública.
Multitenancy: por qué en salud elegimos aislamiento por esquema
Hay tres modelos principales para aislar datos entre clientes en un SaaS: base de datos compartida con columna tenant_id y row-level security, esquemas separados dentro de la misma instancia, o bases de datos completamente separadas. Cada uno tiene implicaciones distintas de coste, complejidad operativa, performance y, sobre todo, riesgo de fuga de datos entre clientes.
Para Nexen, nuestra plataforma omnicanal, elegimos esquemas separados por tenant en PostgreSQL. Es un término medio deliberado: una sola instancia gestionada —menos coste operativo que múltiples instancias—, pero con aislamiento real de datos a nivel de esquema. Las migraciones son más complejas porque hay que ejecutarlas en todos los esquemas, y las consultas cross-tenant para analytics requieren un orquestador adicional, pero la ganancia en seguridad y en capacidad de backup/restore por tenant justifica esa complejidad.
Para Race+, donde gestionamos datos clínicos de pacientes bajo RGPD reforzado por la legislación sanitaria específica, la decisión fue aún más conservadora: evaluamos row-level security con tenant_id y la descartamos. La razón no fue técnica —RLS en PostgreSQL funciona bien— sino de modelo de riesgo. En salud, un bug en una política RLS, una migración mal aplicada, o un developer que ejecute una query sin filtro pueden exponer datos entre hospitales distintos. Con aislamiento por esquema, el propio motor de la base de datos hace imposible ese error: una consulta ejecutada contra el esquema del hospital A no puede ver los datos del hospital B aunque el desarrollador lo intente.
La otra razón es conversacional. En las reuniones con responsables de seguridad hospitalarios, "sus datos están en un esquema exclusivo al que solo se accede con un rol específico de aplicación" es una frase que cierra conversaciones. "Sus datos están en una tabla compartida con filtrado por tenant_id" abre media hora de preguntas adicionales, todas legítimas.
La trampa de la autenticación propia
Casi todos los proyectos empiezan con la misma asunción: la autenticación es un componente pequeño, lo hacemos nosotros rápido. Seis meses después, el sistema tiene JWTs gestionados a mano con rotación dudosa, un flujo de recuperación de contraseña con bugs conocidos, ningún soporte para SSO corporativo, y un equipo que evita tocar ese código porque "funciona, más o menos".
Lo hemos vivido en primera persona. En un proyecto temprano construimos nuestra propia autenticación con la excusa del control total. Cuando un cliente enterprise pidió SAML con su IdP corporativo, la estimación del trabajo fue de seis semanas. Cuando otro pidió MFA obligatoria por política interna, tres semanas más. Cuando llegó la auditoría ISO 27001, descubrimos que el logging de eventos de acceso no cumplía los requisitos y tuvimos que reconstruirlo. La migración posterior a un proveedor gestionado costó más que lo que habría costado usar uno desde el día cero.
Las decisiones de arquitectura de los primeros tres meses condicionan los siguientes tres años del producto.
Nuestra regla ahora es no construir auth propia. Usamos un proveedor gestionado —Auth0, Supabase Auth, Cognito o Keycloak self-hosted según el caso— desde el primer día. El coste mensual es asumible y las funciones que necesitarás en seis meses (MFA, SSO SAML, OIDC, sesiones multi-dispositivo, auditoría de accesos, password policies configurables por tenant) ya están construidas y probadas. El único caso donde la auth propia tiene sentido es si el modelo de identidad es radicalmente específico del dominio y no se puede mapear a primitivos estándar. En muchos años de trabajo, no lo hemos encontrado.
Observabilidad desde el primer día: el incidente que lo cambió todo
La observabilidad es el componente que siempre se pospone y siempre se lamenta haber pospuesto. "La añadimos cuando lo necesitemos" precede invariablemente a una madrugada de debugging a ciegas cuando algo falla en producción.
En un proyecto de los primeros años tuvimos un incidente que convertimos en doctrina interna. Un cliente reportó que ciertos usuarios veían datos desactualizados de forma intermitente. Sin trazas distribuidas ni logs estructurados, tardamos más de tres horas en reconstruir el flujo: revisando logs en tres servicios distintos, correlacionando manualmente por timestamps aproximados, y finalmente localizando un problema de invalidación de caché entre una réplica de lectura y la primaria. Con observabilidad básica —correlation IDs en cada petición, logs JSON con contexto, una traza distribuida por request— el diagnóstico habría tomado cinco minutos.
Desde entonces, nuestra práctica estándar es tres capas desde el primer deploy. Métricas de infraestructura (CPU, memoria, latencia de base de datos, cola de mensajes). Trazas distribuidas para seguir una petición de extremo a extremo a través de todos los servicios que atraviesa. Logs estructurados en JSON con trace_id, tenant_id y user_id en todos los eventos, filtrables y agregables. En GCP usamos Cloud Monitoring, Cloud Trace y Cloud Logging; para proyectos más complejos, OpenTelemetry con un backend externo como Grafana Tempo o Datadog.
El aspecto más importante no es qué herramienta usar, sino la disciplina de instrumentar el código desde el principio. Los logs que ayudan a diagnosticar problemas son los que alguien decidió escribir antes de que hubiera un problema.
RGPD sanitario: las tres cosas que casi todo el mundo hace mal
El RGPD es conocido. Lo que es menos conocido es cómo afecta de forma específica a los datos de salud (categoría especial según el artículo 9), y hay tres cosas que vemos mal implementadas con frecuencia.
La primera es la base legitimadora. Muchos equipos asumen que basta con obtener el consentimiento del paciente. Para aplicaciones en contextos clínicos, el consentimiento no suele ser la base adecuada —puede retirarse en cualquier momento y el tratamiento tiene que cesar—, sino la prevista en el artículo 9.2.h: tratamiento necesario para fines de asistencia sanitaria bajo secreto profesional. Documentar esto correctamente en el Registro de Actividades de Tratamiento es crítico para cualquier auditoría posterior.
La segunda es el derecho de supresión. Un sistema que mezcla datos de muchos pacientes sin separación clara no puede responder a una solicitud de supresión sin efectos colaterales. El diseño de la base de datos tiene que permitir borrar los datos de un paciente concreto sin corromper estadísticas ni romper integridad referencial. Eso requiere pensar en foreign keys con ON DELETE SET NULL, snapshots anonimizados para analytics, y procedimientos documentados.
La tercera es la cadena de subprocesadores. Si el sistema envía datos a una API externa —un proveedor de LLMs, un servicio de OCR, una herramienta de analytics—, ese proveedor se convierte en subprocesador y requiere un DPA firmado. Muchos equipos tienen contratos con su proveedor cloud principal y olvidan los subprocesadores que introduce una integración nueva. El departamento legal lo descubre normalmente en el peor momento.
Diseño de API: interna vs externa desde el día uno
El SaaS B2B serio termina teniendo API pública. Los clientes enterprise siempre integran con su ERP, su CRM o sus herramientas internas, y si esa integración requiere trabajo manual, el cliente acaba facturándolo como coste del producto.
La decisión que más impacto ha tenido en nuestros proyectos fue tratar la API pública como un producto de primera clase desde el diseño inicial, no como un añadido. Eso implica varias cosas. OpenAPI desde el primer endpoint, con el schema versionado junto al código. Versionado explícito en la URL (/v1/) desde la primera release, con un proceso de deprecación definido antes de tener algo que deprecar. Separación estricta entre la API interna —que el frontend propio consume y puede romper con cada release— y la API externa, que tiene compromisos de estabilidad.
Un SaaS B2B sin API pública bien versionada no es un producto serio para clientes enterprise.
La consecuencia práctica es que algunos endpoints existen dos veces —uno interno, uno público— con schemas ligeramente distintos. Parece duplicación pero no lo es: son contratos distintos con consumidores distintos. Cuando Nexen empezó a integrar con el ecosistema de GLS Spain, la API ya estaba diseñada para soportar autenticación por cliente, rate limiting por tenant, y webhooks para eventos asíncronos. Eso redujo el tiempo de cada nueva integración de semanas a días.
PostgreSQL el 90% de las veces, y cuándo mirar otra cosa
Nuestra base de datos por defecto es PostgreSQL. Es madura, tiene extensiones que cubren la mayoría de los casos (JSONB para payloads flexibles, pgvector para embeddings, PostGIS para geodatos), y el ecosistema de herramientas de backup, replicación y observabilidad es incomparable.
Las excepciones que hemos encontrado son pocas. Para workloads analíticos con miles de millones de eventos y agregaciones complejas, BigQuery o ClickHouse son alternativas. Para búsqueda full-text a escala, hemos usado Elasticsearch o Meilisearch. Para almacenamiento de logs y series temporales, backends dedicados como Loki o InfluxDB.
El patrón que recomendamos: empezar con PostgreSQL, instrumentar bien las queries, y cuando una carga específica muestre patrones que Postgres no resuelve bien, evaluar si vale la pena añadir un sistema dedicado para esa carga. No empezar con cinco bases de datos porque la arquitectura de referencia de una conferencia las tenía. Cada base de datos adicional es complejidad operativa que hay que justificar con datos, no con aspiración.
Estas decisiones no son glamurosas. No dan titulares en conferencias. Pero son las que determinan si un producto SaaS puede escalar, mantenerse y cumplir con la regulación sin crisis constantes. Tomarlas bien al principio es la forma más efectiva de invertir tiempo de arquitectura.
¿Quieres llevar esto a tu empresa?
Cuéntanos tu proyecto y te ayudamos a encontrar la solución tecnológica adecuada.
Hablar con nuestro equipo