← Volver a proyectos

SaaS multi-tenant para clínicas veterinarias, construido con arquitectura dirigida con IA. Pre-revenue; listo para producción; en modo mantenimiento.

Rol: Arquitecto de Producto y Software (proyecto independiente) Periodo: ago 2026 – presente Estado: production

TypeScriptNestJSNext.jsPostgreSQLPrismaPlaywright AI: Claude CodeAI: ElevenLabsAI: Playwright
137

Tablas de datos modeladas: toda la operación de la clínica, no solo la agenda

Un solo producto cubre agenda, expedientes, inventario, facturación y más, así que la clínica no necesita varias herramientas

Contados en el esquema, 2026-10-13

96

Cambios versionados de la base de datos (migraciones)

Cada cambio a la estructura de datos queda registrado y es repetible, así que el producto puede seguir evolucionando

Contadas en disco, 2026-10-13

107

Pruebas automáticas de extremo a extremo que recorren flujos reales

Los cambios se prueban contra flujos reales antes de llegar a una clínica

Contados en disco, 2026-10-13

722

Operaciones de la API que otros sistemas pueden llamar

Las integraciones (contabilidad, mensajería, socios) tienen una superficie lista para conectarse

Contados en el código de la API, 2026-10-13

Arquitectura

ARQUITECTURA / VETNOVA 01 Cliente web Next.js, 5 idiomas 02 API REST NestJS, 722 rutas 03 Contexto de tenant en cada petición 04 Seguridad por fila rol de BD sin dueño 05 Smoke tests 107 scripts 06 Cron jobs 28 jobs, con locks 07 PostgreSQL Prisma, 137 modelos RLS falla cerrado: un WHERE olvidado no puede filtrar datos de otra clínica.
Arquitectura de VetNova: cliente, API, contexto de tenant, seguridad por fila y PostgreSQL.

Contexto

VetNova es un SaaS multi-tenant para clínicas veterinarias: agenda de citas, expedientes clínicos, recetas, inventario, punto de venta, facturación electrónica fiscal de México (CFDI 4.0), portal para dueños de mascotas, notificaciones por WhatsApp y correo, API pública y cinco idiomas de interfaz. El primer commit es del 14 de agosto de 2026. Está en producción desde el 7 de septiembre y congelado desde el 21 de septiembre: ahora toca marketing y soporte, no funciones nuevas. Es pre-revenue: listo para producción, sin cliente que pague todavía. Entre el producto y su primer ingreso hay trámites legales y fiscales, no ingeniería.

Partí de un estudio de mercado de clínicas veterinarias de la Ciudad de México (agosto de 2026): contra un expediente clínico genérico y a favor de retención y visibilidad financiera. El alcance sigue esa línea.

Mi rol

  • Decidí: el alcance del producto, el modelo de datos multi-tenant, la estrategia de aislamiento, lo que se deja fuera a propósito (colas de trabajo, app móvil nativa a favor de una app web instalable) y cuándo dejar de construir.
  • Verifiqué: el comportamiento contra la base de datos y los 107 scripts de smoke, las rondas de QA pantalla por pantalla y cada cifra de la documentación contra el disco.
  • Delegué a la IA: la implementación. Claude Code escribe el código bajo mis especificaciones y reglas, y yo reviso cada cambio; puedo leer, depurar y explicar cualquier parte.

Investigación

Tres investigaciones dieron forma a la construcción. El estudio de mercado fijó el alcance. Una revisión del stack frente al equipo real (una persona dirigiendo a un agente de IA) favoreció un stack aburrido y fácil de contratar: TypeScript, NestJS, Prisma, Next.js y PostgreSQL en un monorepo con pnpm. Y comparé tres motores de voz sintética a oído y por licencia, y medí el costo real del de pago en vez de creerle a su documentación (un tutorial de tres minutos costó 613 créditos, no los 1,227 que sugería).

Decisiones

DecisiónAlternativas descartadasPor qué
Seguridad a nivel de fila (RLS) en PostgreSQL, fijada por petición, con la app conectada como rol que no es dueñoFiltros por tenant en el código; una base de datos por tenantUn where olvidado filtra datos de otra clínica; la RLS falla cerrada. Una base por tenant no escala en Postgres serverless.
Sin Redis ni cola de trabajos; los procesos programados corren dentro de la API (28 cron en 25 archivos, con candados)BullMQ sobre RedisUna pieza más de infraestructura que operar sin volumen que la justifique. El costo se midió y se aceptó: el envío de WhatsApp es un solo intento con timeout corto.
Migraciones SQL escritas a mano y aplicadas solo con deploy; migrate dev no se corre nuncaprisma migrate dev; editar las dos migraciones rotasEl esquema y la base real difieren en 97 detalles cosméticos en 33 tablas, así que migrate dev escribiría una migración de renombrados. Editar migraciones ya aplicadas rompe sus checksums.
Voz de pago con ElevenLabs para los tutoriales, Piper gratis para iterarSolo Kokoro o Piper; XTTS-v2; Edge TTSLos gratis tienen mejor acento mexicano pero prosodia plana. ElevenLabs da tiempos por carácter, o sea subtítulos exactos. XTTS-v2 prohíbe uso comercial; Edge TTS usa un endpoint sin licencia.
Apagar Google Ads a los diez díasDejarlo correr; dejar solo BúsquedaEl 59.3% de los clics eran de Display, que Google activa por omisión; solo 18 de 54 clics venían de intención real de búsqueda. Un canal se juzga por los clics de intención, no por los clics.
No enrutar Claude Code a otros proveedores de modelosProxies de la comunidad mediante ANTHROPIC_BASE_URLTodo el contexto, incluidos datos de clientes que aparecen en un smoke, llegaría a un proveedor ajeno al aviso de privacidad, y los skills y hooks se rompen en silencio.

Validación y QA

La calidad pasa por 107 scripts de smoke de extremo a extremo, más verificaciones de clasificación, de integridad y del banco del asistente, y por rondas de QA escritas con una tabla de hallazgos por ronda (tres rondas para el primer candidato a release). El QA visual corre con Playwright en varios anchos y en tema claro y oscuro.

Arriba del archivo de estado hay tres advertencias que no caducan, y cada una salió de un fallo real. Antes de dar un smoke por rojo, comprobar que la API sirve el código de hoy. Un smoke en verde no prueba corrección fiscal: el modo de pruebas del proveedor de facturación acepta lo que la autoridad fiscal rechazaría. Y una ruta que ningún smoke llama no está probada aunque la suite esté en verde: el endpoint de factura múltiple contestó 409 a todo hasta que un smoke por fin lo llamó.

También recuento. El archivo de estado decía 118 pantallas; el disco dice 117, y 117 es lo que publico.

Resultados

  • 137 modelos de datos, 96 migraciones, 722 decoradores de ruta REST y 117 pantallas, en cinco idiomas (8,597 claves de traducción en 158 namespaces).
  • 125 tablas llevan identificador de tenant y están cubiertas por RLS.
  • En producción desde el 7 de septiembre de 2026; congelado desde el 21 de septiembre; pre-revenue.
  • Diez días de Google Ads no produjeron registros y dejaron un hallazgo sobre cómo leer los datos de un canal.

Qué resuelve y dónde más sirve

Una clínica veterinaria maneja citas, expedientes clínicos, recetas, inventario, ventas y facturas fiscales. VetNova junta todo eso en un solo producto, y la propia base de datos mantiene los datos de cada clínica separados de los de las demás, de modo que un filtro olvidado en el código no puede filtrar expedientes.

Los mismos patrones sirven en otros lugares:

  • Otros negocios de citas y expedientes: clínicas dentales, de fisioterapia o de salud humana necesitan la misma mezcla de agenda, expedientes, inventario y cobro.
  • Cualquier software B2B vendido a muchos clientes: el aislamiento por cliente a nivel de base de datos aplica a CRMs, sistemas escolares o herramientas de RR. HH., donde un cliente nunca debe ver los datos de otro.
  • Negocios que deben emitir facturas fiscales en México: el patrón de integración de facturación electrónica (CFDI 4.0) aplica a comercio, servicios o cualquier sistema de cobro.

Qué haría distinto

Este repositorio no tiene integración continua: las compuertas son locales, y por eso existen las tres advertencias de arriba. Mi siguiente proyecto (REYBER) tiene CI en cada push desde el primer día, y se lo agregaría aquí. También revisaría la configuración de redes por omisión de una campaña de anuncios antes de lanzarla, y no después de una semana de números engañosos. Y ejercitaría el circuito de cobro completo antes de declarar el producto listo: la cuenta de pagos en vivo nunca ha procesado un cargo de extremo a extremo, y dejé ese riesgo documentado.

Evidencia

Versión completa: repositorio privado, disponible bajo solicitud.