erp-construccion/docs/00-vision-general/ARQUITECTURA-SAAS.md

42 KiB
Raw Permalink Blame History

Arquitectura SaaS Multi-tenant - ERP Construcción

Versión: 2.0 SaaS Fecha: 2025-11-17 Modelo: SaaS Multi-tenant B2B


📋 Resumen Ejecutivo

De desarrollo a medida → Plataforma SaaS

El sistema evoluciona de un ERP a medida a una plataforma SaaS multi-tenant tipo SAP Cloud, donde:

Un solo código base sirve a múltiples empresas constructoras Módulos activables por cliente según su plan de suscripción Portal de administración para gestionar tenants, usuarios y configuraciones Marketplace de extensiones para customizaciones específicas sin tocar el core Onboarding automatizado en minutos vs semanas de implementación Pricing por módulos con planes Básico/Profesional/Enterprise


🏗️ Arquitectura Multi-tenant

Modelo de Aislamiento

Enfoque: Row-Level Security (RLS) con discriminador constructora_id

┌─────────────────────────────────────┐
│   Capa de Aplicación (Stateless)   │
│                                     │
│  ┌─────────┐  ┌─────────┐         │
│  │  API 1  │  │  API 2  │  ...    │
│  └─────────┘  └─────────┘         │
└──────────────┬──────────────────────┘
               │
┌──────────────▼──────────────────────┐
│        PostgreSQL Database          │
│                                     │
│  ┌──────────────────────────────┐  │
│  │ Schema: constructoras        │  │
│  │  - constructoras (tenant)    │  │
│  │  - user_constructoras        │  │
│  └──────────────────────────────┘  │
│                                     │
│  ┌──────────────────────────────┐  │
│  │ Schema: projects             │  │
│  │  - projects                  │  │
│  │    ├─ constructora_id (FK)   │  │  ← Discriminador
│  │    └─ RLS Policy             │  │
│  │  - budgets                   │  │
│  │    ├─ constructora_id (FK)   │  │
│  │    └─ RLS Policy             │  │
│  └──────────────────────────────┘  │
│                                     │
│  ┌──────────────────────────────┐  │
│  │ Schema: auth_management      │  │
│  │  - profiles                  │  │
│  │    ├─ constructora_id (FK)   │  │
│  │    └─ RLS Policy             │  │
│  └──────────────────────────────┘  │
│                                     │
│  Contexto por sesión:              │
│  app.current_constructora_id = X   │
│  app.current_user_role = Y         │
└─────────────────────────────────────┘

Ventajas:

  • Escalabilidad ilimitada (millones de constructoras)
  • Migraciones simples (un solo schema por dominio)
  • Queries cross-tenant posibles (analytics globales)
  • Menor overhead de gestión y mantenimiento
  • 90% de reutilización de código de GAMILIT
  • Aislamiento lógico robusto mediante RLS policies

Mitigación de riesgos:

  • Seguridad: RLS policies a nivel de BD (no bypasseable desde aplicación)
  • Performance: Índices en constructora_id (sin degradación)
  • Compliance: Audit logging detallado por constructora
  • Testing: Tests de aislamiento en CI/CD (validar RLS)

Identificación de Constructora (Tenant)

1. Por Subdominio:

https://constructora-abc.erp-construccion.com  → constructora: constructora-abc
https://viviendas-xyz.erp-construccion.com     → constructora: viviendas-xyz

2. Por JWT Claim (principal):

// Token JWT contiene
{
  "userId": "uuid-...",
  "constructoraId": "uuid-abc-123",
  "role": "engineer",
  "email": "usuario@constructora-abc.com"
}

3. Por Header HTTP (API externa):

GET /api/projects
Host: api.erp-construccion.com
X-Constructora-ID: uuid-abc-123
Authorization: Bearer <JWT>

Middleware de Constructora Resolver:

// apps/backend/src/middleware/constructora-resolver.middleware.ts

export class ConstructoraResolverMiddleware implements NestMiddleware {
  constructor(
    private constructoraService: ConstructoraService,
    private dataSource: DataSource
  ) {}

  async use(req: Request, res: Response, next: NextFunction) {
    // Extraer constructora desde:
    // 1. JWT claim (más común, ya autenticado)
    const constructoraId = req.user?.constructoraId;

    // 2. Header (para APIs externas)
    const headerConstructoraId = req.headers['x-constructora-id'];

    // 3. Subdomain (UX amigable, requiere lookup)
    let subdomain = null;
    if (req.hostname.includes('erp-construccion.com')) {
      subdomain = req.hostname.split('.')[0];
    }

    const finalConstructoraId = constructoraId || headerConstructoraId;

    if (!finalConstructoraId && !subdomain) {
      throw new UnauthorizedException('Constructora not identified');
    }

    // Validar que constructora existe y está activa
    let constructora;
    if (subdomain) {
      constructora = await this.constructoraService.findBySubdomain(subdomain);
    } else {
      constructora = await this.constructoraService.findById(finalConstructoraId);
    }

    if (!constructora || !constructora.active) {
      throw new UnauthorizedException('Invalid or inactive constructora');
    }

    // Verificar que usuario tiene acceso a esta constructora
    if (req.user?.userId) {
      const hasAccess = await this.constructoraService.userHasAccess(
        req.user.userId,
        constructora.id
      );
      if (!hasAccess) {
        throw new ForbiddenException('User does not have access to this constructora');
      }
    }

    // Inyectar en contexto de request
    req.constructora = constructora;

    // ⭐ CRÍTICO: Configurar contexto RLS en la sesión de BD
    await this.setRLSContext(constructora.id, req.user?.role);

    next();
  }

  private async setRLSContext(constructoraId: string, role?: string) {
    // Establecer variables de sesión para RLS policies
    await this.dataSource.query(`
      SELECT
        set_config('app.current_constructora_id', $1, true),
        set_config('app.current_user_role', $2, true)
    `, [constructoraId, role || 'guest']);
  }
}

Políticas RLS en Base de Datos:

-- Ejemplo: Tabla projects.projects
CREATE POLICY "projects_select_own_constructora" ON projects.projects
    FOR SELECT
    TO authenticated
    USING (
        constructora_id::text = current_setting('app.current_constructora_id', true)
    );

CREATE POLICY "projects_insert_own_constructora" ON projects.projects
    FOR INSERT
    TO authenticated
    WITH CHECK (
        constructora_id::text = current_setting('app.current_constructora_id', true)
    );

-- Similar para UPDATE y DELETE

Contexto RLS por Request

Interceptor NestJS (aplicado globalmente):

// apps/backend/src/interceptors/set-rls-context.interceptor.ts

@Injectable()
export class SetRlsContextInterceptor implements NestInterceptor {
  constructor(private dataSource: DataSource) {}

  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const request = context.switchToHttp().getRequest();
    const user = request.user;
    const constructora = request.constructora;

    if (!constructora?.id) {
      // Contexto público o sin autenticación
      return next.handle();
    }

    // Establecer contexto RLS al inicio del request
    return from(
      this.dataSource.query(`
        SELECT
          set_config('app.current_constructora_id', $1, true),
          set_config('app.current_user_id', $2, true),
          set_config('app.current_user_role', $3, true)
      `, [
        constructora.id,
        user?.userId || null,
        user?.role || 'guest'
      ])
    ).pipe(
      switchMap(() => next.handle()),
      // El contexto se limpia automáticamente al finalizar la transacción
    );
  }
}

// Registro global en main.ts
app.useGlobalInterceptors(new SetRlsContextInterceptor(dataSource));

Funciones Helper en PostgreSQL:

-- apps/database/ddl/schemas/public/functions/

-- Obtener constructora del contexto actual
CREATE OR REPLACE FUNCTION public.get_current_constructora_id()
RETURNS UUID AS $$
BEGIN
  RETURN current_setting('app.current_constructora_id', true)::UUID;
EXCEPTION
  WHEN OTHERS THEN
    RETURN NULL;
END;
$$ LANGUAGE plpgsql STABLE;

-- Obtener user_id del contexto actual
CREATE OR REPLACE FUNCTION public.get_current_user_id()
RETURNS UUID AS $$
BEGIN
  RETURN current_setting('app.current_user_id', true)::UUID;
EXCEPTION
  WHEN OTHERS THEN
    RETURN NULL;
END;
$$ LANGUAGE plpgsql STABLE;

-- Obtener rol del contexto actual
CREATE OR REPLACE FUNCTION public.get_current_user_role()
RETURNS TEXT AS $$
BEGIN
  RETURN current_setting('app.current_user_role', true);
EXCEPTION
  WHEN OTHERS THEN
    RETURN 'guest';
END;
$$ LANGUAGE plpgsql STABLE;

-- Verificar si usuario tiene acceso a constructora
CREATE OR REPLACE FUNCTION public.user_has_access_to_constructora(
  p_user_id UUID,
  p_constructora_id UUID
)
RETURNS BOOLEAN AS $$
BEGIN
  RETURN EXISTS (
    SELECT 1
    FROM auth_management.user_constructoras
    WHERE user_id = p_user_id
      AND constructora_id = p_constructora_id
      AND active = true
  );
END;
$$ LANGUAGE plpgsql STABLE;

Ventajas de este enfoque:

  • Un solo pool de conexiones (eficiente)
  • Contexto por request, no por conexión
  • Compatible con transacciones
  • Fácil de testear (mock del contexto)
  • Reutilización directa de código GAMILIT

🎛️ Portal de Administración SaaS

Roles del Portal

Rol Descripción Accesos
Super Admin Administrador de la plataforma Todos los tenants, configuración global
Tenant Admin Administrador de empresa cliente Su tenant, usuarios, módulos, configuración
Support Soporte técnico Ver datos, ayudar clientes (no modificar)
Billing Facturación y cobranza Ver uso, generar facturas, suspender por falta de pago

Funcionalidades del Portal

1. Gestión de Tenants

Dashboard Principal:

Tenant Plan Usuarios Módulos Activos Estado MRR Acciones
constructora-abc Enterprise 45/50 15/18 🟢 Activo $1,500 Ver · Editar · Facturar
viviendas-xyz Profesional 18/25 10/18 🟢 Activo $750 Ver · Editar · Facturar
obras-norte Básico 8/10 6/18 🟡 Prueba $0 Ver · Editar · Convertir
desarrollos-sur Enterprise 12/100 18/18 🔴 Suspendido $2,000 Ver · Editar · Reactivar

Métricas Globales:

  • Total tenants: 234
  • Activos: 198 (84.6%)
  • En prueba: 28 (12%)
  • Suspendidos: 8 (3.4%)
  • MRR Total: $156,780
  • Usuarios totales: 4,523

2. Onboarding de Nuevo Tenant

Flujo Automatizado (5 minutos):

onboarding_steps:
  - step: 1
    name: "Registro inicial"
    fields:
      - company_name: "Constructora ABC SA de CV"
      - rfc: "CABC850101AAA"
      - industry: "Construcción de vivienda"
      - employees_count: "50-100"
      - subdomain: "constructora-abc"  # Auto-sugerido
      - admin_email: "admin@constructora-abc.com"
      - admin_name: "Juan Pérez"
      - phone: "+52 442 123 4567"
    duration: "2 min"

  - step: 2
    name: "Selección de plan"
    options:
      - plan: "Básico"
        price: "$399/mes"
        users: "10"
        modules: "6 módulos core"
      - plan: "Profesional"  # ← Seleccionado
        price: "$799/mes"
        users: "25"
        modules: "12 módulos"
      - plan: "Enterprise"
        price: "$1,499/mes"
        users: "100"
        modules: "Todos (18)"
    duration: "1 min"

  - step: 3
    name: "Configuración de módulos"
    modules_selected:
      - MAI-001: "Fundamentos" (incluido)
      - MAI-002: "Proyectos" (incluido)
      - MAI-003: "Presupuestos" (incluido)
      - MAI-004: "Compras" (incluido)
      - MAI-005: "Control de Obra" (incluido)
      - MAI-006: "Reportes" (incluido)
      - MAI-007: "RRHH" ($100/mes adicional)
      - MAI-008: "Estimaciones" (incluido)
      - MAI-009: "Calidad" ($50/mes adicional)
      - MAI-010: "CRM" (incluido)
    duration: "1 min"

  - step: 4
    name: "Provisioning automático"
    actions:
      - "Crear registro en tabla constructoras.constructoras"
      - "Generar UUID único para constructora"
      - "Crear usuario admin con relación a constructora"
      - "Insertar registro en user_constructoras (rol admin)"
      - "Activar módulos seleccionados (feature flags)"
      - "Configurar subdomain DNS (CNAME a aplicación)"
      - "Generar datos seed (catálogos base)"
      - "Generar datos demo (opcional)"
      - "Enviar email de bienvenida con credenciales"
    duration: "< 1 min (background job)"

  - step: 5
    name: "Primer login"
    url: "https://constructora-abc.erp-construccion.com"
    credentials:
      - email: "admin@constructora-abc.com"
      - temp_password: "xxxxxx" (cambiar en primer login)
    welcome_tour: true
    sample_data: true
    duration: "Inmediato"

total_time: "5 minutos"
status: "✅ Tenant activo"

3. Configuración de Módulos por Tenant

Panel de Módulos:

┌─────────────────────────────────────────────────────┐
│ Módulos Activos: constructora-abc (Plan Profesional)│
├─────────────────────────────────────────────────────┤
│                                                     │
│  FASE 1: ALCANCE INICIAL                           │
│  ┌─────────────────────────────────────┐           │
│  │ ✅ MAI-001 Fundamentos       Incluido│ [●]      │
│  │ ✅ MAI-002 Proyectos          Incluido│ [●]      │
│  │ ✅ MAI-003 Presupuestos       Incluido│ [●]      │
│  │ ✅ MAI-004 Compras            Incluido│ [●]      │
│  │ ✅ MAI-005 Control de Obra    Incluido│ [●]      │
│  │ ✅ MAI-006 Reportes           Incluido│ [●]      │
│  │ ✅ MAI-007 RRHH              +$100/mes│ [●]      │
│  │ ✅ MAI-008 Estimaciones       Incluido│ [●]      │
│  │ ⚪ MAI-009 Calidad           +$50/mes │ [ ]  ←   │
│  │ ✅ MAI-010 CRM                Incluido│ [●]      │
│  │ ⚪ MAI-011 INFONAVIT         +$75/mes │ [ ]      │
│  │ ⚪ MAI-012 Contratos         +$75/mes │ [ ]      │
│  │ ⚪ MAI-013 Administración    Incluido │ [ ]      │
│  └─────────────────────────────────────┘           │
│                                                     │
│  FASE 2: ENTERPRISE                                │
│  ┌─────────────────────────────────────┐           │
│  │ ⚪ MAE-014 Finanzas          +$200/mes│ [ ]      │
│  │ ⚪ MAE-015 Activos           +$150/mes│ [ ]      │
│  │ ⚪ MAE-016 DMS               +$100/mes│ [ ]      │
│  └─────────────────────────────────────┘           │
│                                                     │
│  FASE 3: AVANZADA                                  │
│  ┌─────────────────────────────────────┐           │
│  │ ⚪ MAA-017 HSE + IA          +$300/mes│ [ ]      │
│  └─────────────────────────────────────┘           │
│                                                     │
│  Subtotal Plan Profesional:        $799/mes        │
│  Add-ons activados:                 +$100/mes      │
│  ─────────────────────────────────────────         │
│  Total mensual:                     $899/mes        │
│                                                     │
│  [Guardar Cambios]  [Vista Previa]                 │
└─────────────────────────────────────────────────────┘

Al activar/desactivar módulos:

  • Se ejecuta migration específica del módulo
  • Se actualizan permisos de usuarios
  • Se calcula nuevo pricing
  • Se notifica a tenant admin
  • Cambios efectivos en <5 minutos

4. Gestión de Usuarios por Tenant

Vista de Tenant Admin:

Usuario Email Rol Módulos Último acceso Estado Acciones
Juan Pérez admin@const-abc.com Admin Todos Hace 2 hrs 🟢 Activo Editar · Desactivar
María López maria@const-abc.com Engineer 8 módulos Hace 1 día 🟢 Activo Editar · Desactivar
Pedro Martínez pedro@const-abc.com Resident 6 módulos Hace 3 hrs 🟢 Activo Editar · Desactivar
... ... ... ... ... ... ...

Usuarios: 18 / 25 (72% de capacidad)

[+ Invitar Usuario] [Importar CSV] [Exportar]


5. Configuración de Tenant

Categorías de configuración:

General:

  • Nombre de empresa
  • Logo (usado en reportes y emails)
  • Zona horaria
  • Idioma (ES/EN)
  • Moneda (MXN/USD)

Personalización:

  • Colores de marca (primary, secondary)
  • Email remitente personalizado
  • Dominio custom (opcional): erp.constructora-abc.com

Seguridad:

  • 2FA obligatorio (sí/no)
  • Política de contraseñas
  • Sesiones concurrentes
  • IP whitelisting

Integraciones:

  • SAP/CONTPAQi (credenciales)
  • WhatsApp Business API
  • SMS provider
  • Storage (AWS S3 / Azure Blob)

Facturación:

  • Método de pago
  • Datos fiscales
  • Historial de facturas
  • Uso mensual

💳 Modelo de Pricing

Planes Base

Plan Precio/mes Usuarios Módulos Incluidos Almacenamiento Soporte
Básico $399 USD 10 6 core 10 GB Email (48h)
Profesional $799 USD 25 12 módulos 50 GB Email + Chat (24h)
Enterprise $1,499 USD 100 Todos (18) 200 GB Dedicado (4h)
Enterprise Plus Custom Ilimitado Todos + Custom Ilimitado Dedicado (1h)

Módulos Add-on (por módulo/mes)

Módulo Precio/mes Disponible en
MAI-007 RRHH Avanzado $100 Todos los planes
MAI-009 Calidad y Postventa $50 Profesional+
MAI-011 INFONAVIT $75 Profesional+
MAI-012 Contratos $75 Profesional+
MAE-014 Finanzas $200 Enterprise
MAE-015 Activos $150 Enterprise
MAE-016 DMS $100 Profesional+
MAA-017 HSE + IA $300 Enterprise

Usuarios Adicionales

Plan Precio/usuario/mes
Básico $20 USD
Profesional $15 USD
Enterprise $10 USD

Cálculo de Ejemplo

Constructora ABC (Plan Profesional):

Plan Profesional base:             $799/mes
  - 25 usuarios incluidos
  - 12 módulos

Add-ons activados:
  + MAI-007 RRHH                   $100/mes
  + MAI-011 INFONAVIT              $75/mes

Usuarios adicionales:
  + 5 usuarios × $15               $75/mes

Almacenamiento adicional:
  + 20 GB × $2/GB                  $40/mes

─────────────────────────────────────────
Total mensual:                     $1,089/mes
Anual (15% descuento):             $11,107/año ($925/mes)

Costos de Contratación Inicial (One-Time)

Además de la suscripción mensual, existe un costo único de implementación inicial que cubre:

Migración de datos desde sistemas legacy (Excel, ERP anterior, etc.) Capacitación a usuarios (sesiones remotas + material) Adaptación al negocio (configuración de workflows, catálogos, permisos) Implementaciones dentro de configuraciones (reportes personalizados, dashboards, etc.)


Paquetes de Onboarding

Paquete Precio Usuarios Registros a Migrar Horas Capacitación Horas Configuración Ideal para
Starter $2,500 USD <10 <5,000 4 horas 8 horas Empresas pequeñas con datos simples
Profesional $7,500 USD 10-50 <50,000 12 horas 20 horas Empresas medianas con procesos establecidos
Enterprise $15,000 USD 50-100 <200,000 24 horas 40 horas Constructoras grandes con ERP previo
Enterprise Plus Custom 100+ Ilimitado Custom Custom Corporativos multinacionales

Desglose del Servicio de Onboarding

1. Migración de Datos (30% del tiempo)

Incluye:

  • Análisis de datos fuente (Excel, CSVs, base de datos legacy)
  • Limpieza y normalización de datos
  • Mapping de campos a esquema del ERP
  • Importación automatizada con validaciones
  • Verificación de integridad post-migración

Entregables:

  • Plan de migración documentado
  • Scripts de importación
  • Reporte de validación con discrepancias
  • Backup de datos originales

Datos migrados típicos:

  • Catálogo de clientes/proveedores
  • Proyectos históricos (últimos 2 años)
  • Presupuestos y estimaciones
  • Personal y nóminas
  • Inventarios de almacén
  • Documentos y planos (opcional)

2. Capacitación (25% del tiempo)

Metodología:

  • Sesiones remotas por Zoom/Teams
  • Grabaciones disponibles 1 año
  • Material didáctico en PDF
  • Certificado de participación

Programa:

Sesión Audiencia Duración Contenido
Sesión 1: Administradores Admins de sistema 3 hrs Portal admin, usuarios, módulos, configuración
Sesión 2: Operaciones Residentes de obra, almacén 3 hrs Proyectos, control de obra, compras, inventarios
Sesión 3: Finanzas Contadores, finanzas 2 hrs Presupuestos, estimaciones, reportes financieros
Sesión 4: RRHH Recursos humanos 2 hrs Nóminas, asistencias, incidencias
Sesión 5: Ejecutivos Directores, gerentes 2 hrs Dashboards, analytics, reportes ejecutivos

Material incluido:

  • Manual de usuario por módulo (PDF)
  • Videos tutoriales (10-15 min c/u)
  • FAQs y troubleshooting
  • Acceso a knowledge base

3. Adaptación al Negocio (25% del tiempo)

Configuraciones personalizadas sin código:

Catálogos maestros:

  • Tipos de proyecto específicos (residencial, industrial, etc.)
  • Catálogo de conceptos de obra (partidas estándar)
  • Plantillas de presupuesto por tipo de obra
  • Roles y permisos personalizados
  • Centros de costo / áreas organizacionales

Workflows de aprobación:

  • Flujo de aprobación de compras (niveles, montos)
  • Flujo de estimaciones (revisión, autorización)
  • Flujo de requisiciones de almacén
  • Flujo de incidencias de calidad

Branding:

  • Logo de empresa en sistema
  • Colores corporativos
  • Plantillas de reportes con membrete
  • Emails transaccionales personalizados

4. Implementaciones de Configuración (20% del tiempo)

Desarrollo de reportes y dashboards personalizados:

Reportes custom:

  • Reporte ejecutivo mensual (formato específico del cliente)
  • Reporte de avance de obra para clientes finales
  • Formatos oficiales (INFONAVIT, CFE, etc.)
  • Reporte de rentabilidad por proyecto

Dashboards:

  • Dashboard ejecutivo C-level
  • Dashboard de obra para residentes
  • Dashboard financiero para contadores

Integraciones:

  • Configuración de integración SAP/CONTPAQi
  • Configuración de WhatsApp Business API
  • Configuración de storage (S3/Azure)

Calendario de Implementación

Paquete Starter (2-3 semanas):

Semana 1:
  - Día 1-2: Kickoff + análisis de datos
  - Día 3-4: Migración de datos
  - Día 5: Validación de migración

Semana 2:
  - Día 1-2: Configuración de catálogos y workflows
  - Día 3-4: Capacitación usuarios (2 sesiones)
  - Día 5: Ajustes finales

Semana 3:
  - Día 1-2: Configuración de reportes
  - Día 3: Sesión final y go-live
  - Día 4-5: Soporte post go-live

Paquete Profesional (4-6 semanas):

Semana 1-2: Migración de datos + validación
Semana 3: Configuración avanzada
Semana 4-5: Capacitación (4-5 sesiones)
Semana 6: Reportes custom + go-live

Paquete Enterprise (8-12 semanas):

Semana 1-3: Análisis y migración de datos complejos
Semana 4-6: Configuración enterprise + integraciones
Semana 7-9: Capacitación intensiva (6+ sesiones)
Semana 10-11: Desarrollo de reportes y dashboards
Semana 12: UAT, ajustes y go-live

Soporte Post-Onboarding

Incluido en el onboarding (primeros 30 días):

  • Soporte prioritario vía email/chat
  • Webinars de Q&A semanales
  • Ajustes menores de configuración
  • Resolución de dudas operativas

Posterior (según plan de suscripción):

  • Plan Básico: Email (48h)
  • Plan Profesional: Email + Chat (24h)
  • Plan Enterprise: Soporte dedicado (4h)

Servicios Adicionales (Opcionales)

Servicio Precio Descripción
Capacitación on-site $3,000 USD/día + viáticos Sesiones presenciales en oficinas del cliente
Migración de documentos $0.10 USD/documento Digitalización y clasificación de planos/contratos
Desarrollo de extensión custom $150 USD/hora Funcionalidad no disponible en configuración estándar
Consultoría de procesos $200 USD/hora Optimización de workflows y mejores prácticas
Integración legacy custom Desde $5,000 USD Integración con sistemas propietarios complejos
Auditoría de datos $2,000 USD Validación exhaustiva de integridad de datos migrados

Garantía de Onboarding

Compromiso:

  • Sistema funcional al 100% al término del onboarding
  • Usuarios capacitados y productivos
  • Datos migrados con >98% de precisión

Si no se cumple:

  • Extensión de soporte sin costo hasta lograrlo
  • Reembolso parcial si no se alcanza funcionalidad mínima acordada
  • Consultoría adicional sin cargo

Ejemplo de Presupuesto Completo

Constructora ABC (50 empleados, 15,000 registros, ERP previo):

INVERSIÓN INICIAL (One-time):
  Paquete Profesional Onboarding:     $7,500 USD
    ✓ Migración 15,000 registros
    ✓ 12 horas capacitación (4 sesiones)
    ✓ 20 horas configuración
    ✓ Soporte 30 días post go-live

  Servicios adicionales:
    + Migración 2,000 planos PDF         $200 USD
    + Integración CONTPAQi            $5,000 USD
    ───────────────────────────────────────────
  Subtotal inicial:                  $12,700 USD


SUSCRIPCIÓN MENSUAL:
  Plan Profesional base:                $799/mes
    ✓ 25 usuarios incluidos
    ✓ 12 módulos
    ✓ 50 GB almacenamiento
    ✓ Soporte 24h

  Add-ons activados:
    + MAI-007 RRHH Avanzado             $100/mes
    + MAI-011 INFONAVIT                  $75/mes
    + MAI-012 Contratos                  $75/mes

  Usuarios adicionales:
    + 5 usuarios × $15                   $75/mes
    ───────────────────────────────────────────
  Total mensual:                      $1,124/mes


COSTO TOTAL AÑO 1:
  Inversión inicial:                 $12,700 USD
  Suscripción 12 meses:              $13,488 USD (1,124 × 12)
  ───────────────────────────────────────────
  Total año 1:                       $26,188 USD

COSTO TOTAL AÑOS SUBSECUENTES:
  Suscripción 12 meses:              $13,488 USD/año
  (sin costo de onboarding)


ROI vs ERP Tradicional:
  SAP/Oracle implementación:     $150K-$500K inicial
  SAP/Oracle suscripción:         $50K-$150K/año

  Ahorro año 1:                   $123K-$473K (vs SAP mínimo)
  Payback:                        Inmediato

🔌 Marketplace de Extensiones

Tipos de Extensiones

Tipo Descripción Ejemplo
Integraciones Conectores a sistemas externos Integración con WhatsApp Business, Slack, Zoom
Reportes Custom Plantillas de reportes específicas Reporte para licitaciones CFE, reporte INFONAVIT especial
Módulos Verticales Funcionalidad específica de industria Módulo de Obra Civil Pesada, Módulo de Edificación Alta
Workflows Custom Flujos de aprobación personalizados Workflow de estimaciones 5 niveles
Dashboards Dashboards temáticos Dashboard Ejecutivo C-Level
Templates Plantillas de documentos Contratos tipo, formatos oficiales

Catálogo de Marketplace

┌────────────────────────────────────────────────┐
│  🛒 Marketplace de Extensiones                │
├────────────────────────────────────────────────┤
│                                                │
│  INTEGRACIONES                                 │
│  ┌──────────────────────────────────┐         │
│  │ 📱 WhatsApp Business API         │         │
│  │ Notificaciones automáticas       │         │
│  │ ⭐⭐⭐⭐⭐ (45 reviews)         │         │
│  │ Gratis | [Instalar]              │         │
│  └──────────────────────────────────┘         │
│                                                │
│  ┌──────────────────────────────────┐         │
│  │ 💼 SAP S/4HANA Connector         │         │
│  │ Export de pólizas contables      │         │
│  │ ⭐⭐⭐⭐ (23 reviews)            │         │
│  │ $99/mes | [Instalar]             │         │
│  └──────────────────────────────────┘         │
│                                                │
│  REPORTES CUSTOM                               │
│  ┌──────────────────────────────────┐         │
│  │ 📊 Reporte INFONAVIT EVC         │         │
│  │ Formato oficial actualizado 2025 │         │
│  │ ⭐⭐⭐⭐⭐ (89 reviews)         │         │
│  │ $49 único | [Comprar]            │         │
│  └──────────────────────────────────┘         │
│                                                │
│  MÓDULOS VERTICALES                            │
│  ┌──────────────────────────────────┐         │
│  │ 🏗️ Obra Civil Pesada             │         │
│  │ Puentes, carreteras, presas      │         │
│  │ ⭐⭐⭐⭐ (12 reviews)            │         │
│  │ $299/mes | [Ver Demo]            │         │
│  └──────────────────────────────────┘         │
│                                                │
│  [Explorar Más]  [Mis Extensiones]           │
└────────────────────────────────────────────────┘

Desarrollo de Extensiones

SDK de Extensiones:

// apps/extensions/ejemplo-extension/index.ts

import { Extension, Hook, MenuItem } from '@erp-construccion/sdk';

@Extension({
  id: 'whatsapp-notifier',
  name: 'WhatsApp Notifier',
  version: '1.0.0',
  author: 'ERP Construcción',
  description: 'Envía notificaciones por WhatsApp',
  permissions: ['notifications.send', 'users.read'],
  pricing: {
    type: 'free',
  },
})
export class WhatsAppNotifierExtension {

  // Hook: Se ejecuta cuando se crea una estimación
  @Hook('estimations.created')
  async onEstimationCreated(estimation: Estimation) {
    const tenant = this.context.tenant;
    const users = await this.api.users.findByRole('finance');

    for (const user of users) {
      if (user.phone && user.notificationsEnabled) {
        await this.sendWhatsApp(user.phone, {
          template: 'estimation_created',
          params: {
            estimationNumber: estimation.number,
            amount: estimation.amount,
            project: estimation.project.name,
          },
        });
      }
    }
  }

  // Agregar ítem al menú lateral
  @MenuItem({
    section: 'settings',
    label: 'Configurar WhatsApp',
    icon: 'whatsapp',
    route: '/settings/whatsapp',
  })
  menuItem() {
    return {
      component: WhatsAppSettingsPage,
    };
  }

  private async sendWhatsApp(phone: string, message: any) {
    // Implementación...
  }
}

🔄 Ciclo de Vida del Tenant

Estados de Tenant

stateDiagram-v2
    [*] --> Registering
    Registering --> Trial: Onboarding completado
    Trial --> Active: Pago confirmado
    Trial --> Expired: 14 días sin pago
    Active --> Suspended: Falta de pago
    Suspended --> Active: Pago recibido
    Suspended --> Canceled: 30 días suspendido
    Active --> Canceled: Solicitud de cliente
    Expired --> Active: Pago recibido
    Canceled --> [*]
Estado Descripción Acceso Duración
Registering Alta en proceso No <5 min
Trial Período de prueba Completo 14 días
Active Suscripción activa Completo Indefinido
Suspended Falta de pago Solo lectura Hasta 30 días
Expired Trial vencido Login deshabilitado Hasta reactivación
Canceled Cancelado por cliente o sistema No Soft-delete 90 días

Políticas de Cancelación

Cancelación por Cliente:

  1. Cliente solicita cancelación desde portal
  2. Confirmación con razón (opcional: encuesta)
  3. Export de datos ofrecido (formato SQL/Excel)
  4. Tenant pasa a estado Canceled
  5. Datos retenidos 90 días (compliance)
  6. Eliminación permanente tras 90 días

Suspensión por Falta de Pago:

  1. Intento de cargo fallido (día 1)
  2. Reintento automático (día 3)
  3. Email de recordatorio (día 5)
  4. Último reintento (día 7)
  5. Suspensión (día 8): Solo lectura
  6. Email de suspensión con link de pago
  7. Cancelación automática si no paga en 30 días

🛠️ Gestión de Configuraciones

Niveles de Configuración

1. Global (Platform-level)
   ├── Configuración de infraestructura
   ├── Límites globales
   └── Features flags

2. Tenant-level
   ├── Módulos activados
   ├── Usuarios y permisos
   ├── Branding
   ├── Integraciones
   └── Datos maestros

3. User-level
   ├── Preferencias personales
   ├── Dashboard layout
   └── Notificaciones

Feature Flags

Permiten activar/desactivar funcionalidades sin deploy:

// apps/backend/src/config/feature-flags.service.ts

export class FeatureFlagsService {
  async isFeatureEnabled(
    featureName: string,
    tenantId?: string
  ): Promise<boolean> {
    // 1. Verificar a nivel global
    const globalFlag = await this.getGlobalFlag(featureName);
    if (globalFlag === false) return false;

    // 2. Verificar a nivel tenant (si aplica)
    if (tenantId) {
      const tenantFlag = await this.getTenantFlag(featureName, tenantId);
      if (tenantFlag !== null) return tenantFlag;
    }

    // 3. Default
    return globalFlag;
  }
}

// Uso en controlador
@Get('ai-insights')
@UseGuards(FeatureGuard('ai_risk_prediction'))
async getAIInsights() {
  // Solo accesible si feature está habilitada para el tenant
  // ...
}

Casos de uso:

  • Gradual rollout de nuevas features
  • A/B testing
  • Deprecación controlada de features
  • Habilitación por plan (Enterprise features)

📊 Métricas SaaS

KPIs del Negocio

Métrica Descripción Target
MRR Monthly Recurring Revenue Crecimiento 15% M/M
ARR Annual Recurring Revenue $2M año 1
Churn Rate % de clientes que cancelan <5% mensual
CAC Customer Acquisition Cost <$1,500
LTV Lifetime Value >$18,000 (12× CAC)
Activation Rate % que activan módulos en 7 días >80%
NPS Net Promoter Score >50

Métricas Técnicas

Métrica Target Monitoreo
Uptime 99.9% StatusPage.io
API Response Time p95 <200ms DataDog
Database Query Time p95 <100ms pg_stat_statements
Onboarding Time <5 min Analytics
Time to First Value <1 hr Mixpanel

🚀 Roadmap SaaS

Fase 1: MVP SaaS (Semanas 1-8)

  • Arquitectura multi-tenant
  • Portal de admin básico
  • Onboarding automatizado
  • 6 módulos core
  • Pricing y billing

Fase 2: Enterprise Features (Semanas 9-16)

  • 12 módulos adicionales
  • Módulos activables dinámicamente
  • Marketplace MVP
  • Extensiones SDK
  • Custom domains

Fase 3: Scale & Growth (Semanas 17-24)

  • IA predictiva
  • Analytics avanzado
  • Integraciones nativas (SAP, WhatsApp)
  • Mobile app completa
  • API pública para partners

Fase 4: Expansión (Semanas 25+)

  • 📋 Marketplace público
  • 📋 White-label para partners
  • 📋 Internacionalización (US, LATAM)
  • 📋 Cumplimiento (SOC2, ISO 27001)

🔐 Seguridad Multi-tenant

Aislamiento de Datos

  1. Row-level security (RLS): Aislamiento lógico mediante políticas PostgreSQL
  2. Columna discriminadora: constructora_id en todas las tablas multi-tenant
  3. Contexto por sesión: app.current_constructora_id configurado por request
  4. API-level validation: Validación de acceso a constructora en middleware
  5. Audit logging: Registro de accesos con constructora_id en cada operación
  6. Testing de aislamiento: Tests automáticos que validan RLS policies

Prevención de Data Leakage

// Guard que previene acceso cross-constructora
@Injectable()
export class ConstructoraGuard implements CanActivate {
  constructor(private constructoraService: ConstructoraService) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const request = context.switchToHttp().getRequest();
    const user = request.user;
    const constructora = request.constructora;

    if (!user || !constructora) {
      throw new UnauthorizedException('User or constructora not identified');
    }

    // Validar que el usuario tiene acceso a esta constructora
    const hasAccess = await this.constructoraService.userHasAccess(
      user.userId,
      constructora.id
    );

    if (!hasAccess) {
      // Intentó acceder a datos de otra constructora
      await this.auditService.logSecurityViolation({
        userId: user.userId,
        attemptedConstructoraId: constructora.id,
        event: 'cross_constructora_access_denied',
        ip: request.ip,
      });

      throw new ForbiddenException('Access denied to this constructora');
    }

    return true;
  }
}

// Uso en controlador
@Controller('projects')
@UseGuards(JwtAuthGuard, ConstructoraGuard)
export class ProjectsController {
  // Todos los endpoints requieren acceso válido a constructora
}

Tests de Aislamiento:

// apps/backend/test/security/rls-isolation.spec.ts

describe('RLS Isolation Tests', () => {
  it('should prevent cross-constructora data access', async () => {
    // Setup: Crear 2 constructoras y usuarios
    const constructoraA = await createConstructora('Constructora A');
    const constructoraB = await createConstructora('Constructora B');

    const userA = await createUser({ constructoraId: constructoraA.id });
    const userB = await createUser({ constructoraId: constructoraB.id });

    // Crear proyecto para constructora A
    const projectA = await createProject({
      name: 'Proyecto A',
      constructoraId: constructoraA.id
    });

    // Login como usuario B
    const tokenB = await loginAs(userB);

    // Intentar acceder a proyecto de constructora A (debe fallar)
    const response = await request(app)
      .get(`/api/projects/${projectA.id}`)
      .set('Authorization', `Bearer ${tokenB}`)
      .expect(403);

    expect(response.body.message).toContain('Access denied');
  });

  it('should enforce RLS at database level', async () => {
    // Setup similar...

    // Intentar query directo con constructora incorrecta en contexto
    await dataSource.query(`
      SELECT set_config('app.current_constructora_id', $1, true)
    `, [constructoraB.id]);

    // Query debe retornar 0 resultados (RLS bloquea)
    const projects = await dataSource.query(`
      SELECT * FROM projects.projects WHERE id = $1
    `, [projectA.id]);

    expect(projects).toHaveLength(0); // RLS bloqueó el acceso
  });
});

📝 Conclusión

Esta arquitectura SaaS multi-tenant permite:

Escalabilidad: De 10 a 10,000 tenants sin cambios arquitectónicos Time-to-market: Onboarding de clientes en minutos Flexibilidad: Módulos activables, extensiones, customización Economía: Costo operativo distribuido, mejor margen Innovación: Feature flags, A/B testing, rollout gradual

Próximo paso: Implementar la transformación en el MVP-APP.md principal.


Generado: 2025-11-17 Versión: 2.0 SaaS Modelo: Multi-tenant B2B SaaS