8 min de lectura

Cómo construí FunerariaCloud: un SaaS multi-tenant con cumplimiento SARLAFT

La arquitectura detrás de un SaaS para funerarias en Colombia: multi-tenancy, contratos de previsión exequial con firma digital, y qué implica construir cumplimiento SARLAFT dentro del producto.

El problema que no vi hasta que empecé a construir

Cuando arranqué FunerariaCloud pensé que era un CRUD con esteroides: contratos, clientes, facturas. Ya había construido dashboards de gestión antes. Lo que no dimensioné al principio es que una funeraria en Colombia no vende un servicio puntual — vende planes de previsión exequial, contratos financieros a largo plazo con pagos mensuales durante años, a veces décadas, antes de que el servicio se preste.

Nota

No es "vendí un servicio, cerré la venta". Es gestión de cartera, seguimiento de pagos recurrentes, y — porque maneja flujos de dinero de terceros a largo plazo — cae directo bajo la lupa de la normativa colombiana contra lavado de activos: SARLAFT.

Qué es SARLAFT y por qué le importa a un desarrollador

SARLAFT (Sistema de Administración del Riesgo de Lavado de Activos y Financiación del Terrorismo) es el marco regulatorio colombiano que obliga a ciertos sectores — financiero, y por extensión negocios que manejan contratos de pago recurrente a largo plazo como las funerarias con planes de previsión — a tener controles sobre el origen de los fondos y la trazabilidad de las operaciones.

Para el software esto significa que ciertas cosas no pueden ser un afterthought. En términos generales, un sistema que conviva con esta normativa necesita poder:

  • Registrar quién hizo qué y cuándo sobre cada contrato (trazabilidad completa, no solo el estado actual)
  • Conservar evidencia auditable de cada operación, no solo mostrar un resumen
  • Identificar el origen de los fondos en operaciones de valor significativo
  • Tener un canal para marcar y reportar operaciones inusuales
Ojo

SARLAFT no es un checkbox que se marca una vez en el onboarding. Es una obligación continua de monitoreo y reporte. El software tiene que sostenerlo en el tiempo, no solo declararlo en una pantalla de configuración.

La decisión de arquitectura: multi-tenant desde el día uno

FunerariaCloud está pensado para vender a múltiples funerarias, no para una sola. Eso significa multi-tenancy real: cada funeraria opera como una organización aislada — datos, usuarios y configuración separados — pero todas comparten la misma base de código y la misma infraestructura.

FunerariaCloud — una sola aplicación
Las Nieves
tenant_id: las-nieves
Funeraria B
tenant_id: funeraria-b
Funeraria C
tenant_id: funeraria-c
Base de datos compartida — aislada por tenant_id
Una instancia por funeraria

Cada cliente nuevo significa un deploy nuevo, una base de datos nueva, y un fix que hay que replicar N veces a mano. No escala más allá de un puñado de clientes.

Multi-tenant con tenant_id

Una sola base de código y una sola infraestructura. Un fix se despliega una vez y llega a todos los clientes al mismo tiempo.

En la práctica, esto se traduce en que prácticamente ninguna query a la base de datos puede ignorar el tenant actual. Así se ve el patrón simplificado (no es el código exacto de producción, es la idea):

schema.ts (simplificado)
export const contracts = pgTable("contracts", {
  id: uuid("id").primaryKey().defaultRandom(),
  tenantId: uuid("tenant_id").notNull().references(() => tenants.id),
  clientId: uuid("client_id").notNull(),
  planId: uuid("plan_id").notNull(),
  status: contractStatus("status").notNull().default("pending"),
  createdAt: timestamp("created_at").notNull().defaultNow(),
});

// Ninguna query a "contracts" puede saltarse el tenant actual
export function getContracts(tenantId: string) {
  return db
    .select()
    .from(contracts)
    .where(eq(contracts.tenantId, tenantId));
}

Los módulos que terminaron siendo necesarios

Más allá del núcleo de gestión de contratos y previsión exequial, terminé construyendo firma digital de contratos, un módulo contable completo, y un log de auditoría que registra cada login y cada acción sobre un contrato — exactamente el tipo de trazabilidad que SARLAFT exige.

audit-log.ts (simplificado)
export const auditLog = pgTable("audit_log", {
  id: uuid("id").primaryKey().defaultRandom(),
  tenantId: uuid("tenant_id").notNull(),
  userId: uuid("user_id").notNull(),
  action: text("action").notNull(),
  // "LOGIN" | "LOGOUT" | "REQUEST_SIGNATURE" | "CONTRACT_UPDATED" ...
  targetId: uuid("target_id"),
  metadata: jsonb("metadata"),
  createdAt: timestamp("created_at").notNull().defaultNow(),
});

También terminé agregando gestión de flota (vehículos y mantenimiento) y CRM con páginas memoriales online — cosas que no estaban en el plan original, pero que aparecieron al diseñar contra el día a día real de una funeraria:

  • Firma digital de contratos
  • Módulo contable completo (libro diario, balance, bancos, cartera)
  • Log de auditoría (login, firma, cambios de contrato)
  • Gestión de flota y mantenimiento de vehículos
  • CRM y páginas memoriales online

Dónde está hoy

Tip

FunerariaCloud está en desarrollo activo — no es un caso de éxito con métricas de tracción, es la arquitectura real detrás de un producto que estamos construyendo ahora mismo. Lo compartimos así, sin inflar números que no existen, porque un caso de estudio honesto vale más que una tabla de métricas inventadas.

Si estás en el sector funerario en Colombia y esto te suena a un problema que tenés, o si necesitás construir un SaaS que tenga que convivir con una regulación real — SARLAFT, HABEAS DATA, DIAN, la que sea — desde el diseño y no como parche al final, hablemos.

¿Listo para iniciar tu proyecto?

Hablemos sobre cómo podemos ayudarte a construir tu producto, con una solución técnica que resista el mundo real.

Contáctanos