template-saas/docs/02-especificaciones/ET-SAAS-021-mlm.md
Adrian Flores Cortes 2825b3d5fd
Some checks are pending
CI / Backend CI (push) Waiting to run
CI / Frontend CI (push) Waiting to run
CI / Security Scan (push) Waiting to run
CI / CI Summary (push) Blocked by required conditions
docs: Add ET-SAAS-018 to ET-SAAS-022 technical specifications
- ET-SAAS-018-sales.md: Sales pipeline/CRM module
- ET-SAAS-019-portfolio.md: Product catalog module
- ET-SAAS-020-commissions.md: Commissions system
- ET-SAAS-021-mlm.md: Multi-Level Marketing module
- ET-SAAS-022-goals.md: Goals and objectives system
- Update _MAP.md with all 9 specifications

All specs document:
- Data model (DDL, enums, tables)
- Backend architecture (endpoints, services)
- Security (RLS, RBAC permissions)
- Frontend status and hooks
- Module integrations

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 13:14:48 -06:00

12 KiB
Raw Blame History

id title type status priority module version created_date updated_date story_points
ET-SAAS-021 Especificacion Tecnica MLM (Multi-Level Marketing) TechnicalSpec Implemented P1 mlm 1.0.0 2026-02-03 2026-02-03 13

ET-SAAS-021: Especificacion Tecnica - MLM (Multi-Level Marketing)

Metadata

  • Codigo: ET-SAAS-021
  • Modulo: MLM
  • Version: 1.0.0
  • Estado: Implementado (Backend)
  • Fecha: 2026-02-03
  • Basado en: SAAS-021

1. Resumen Ejecutivo

1.1 Estado Actual

Sistema MLM con backend implementado, UI pendiente.

Capacidad Estado Notas
Structures SI Unilevel, Binary, Matrix
Ranks SI Rangos con requisitos
Nodes SI Arbol de distribuidores
Commissions SI Comisiones multinivel
Bonuses SI Bonos de rango
LTREE SI Consultas eficientes
RLS SI Row Level Security
UI NO Frontend pendiente

1.2 Funcionalidades v1.0

Sistema completo con:

  • 6 Entidades: Structures, Ranks, Nodes, Commissions, Bonuses, RankHistory
  • 4 Tipos de estructura: unilevel, binary, matrix, hybrid
  • 5 Tipos de comision: level, matching, infinity, leadership, pool
  • 4 Tipos de bono: rank_achievement, rank_maintenance, fast_start, pool_share
  • LTREE: Para consultas eficientes de upline/downline

2. Modelo de Datos

2.1 Schema: mlm

Tabla: structures

Campo Tipo Descripcion
id UUID PK
tenant_id UUID FK tenants
name VARCHAR(100) Nombre estructura
description TEXT Descripcion
type ENUM unilevel, binary, matrix, hybrid
config JSONB Configuracion especifica
level_rates JSONB Tasas por nivel
matching_rates JSONB Tasas de matching bonus
is_active BOOLEAN Estado

Configuracion por tipo:

// Unilevel
{"max_width": null, "max_depth": 10}

// Binary
{"spillover": "left_first" | "weak_leg" | "balanced"}

// Matrix
{"width": 3, "depth": 7}

Level rates:

[
  {"level": 1, "rate": 0.10},
  {"level": 2, "rate": 0.05},
  {"level": 3, "rate": 0.03}
]

Tabla: ranks

Campo Tipo Descripcion
id UUID PK
tenant_id UUID FK tenants
structure_id UUID FK structures
name VARCHAR(100) "Silver", "Gold", etc.
level INT 1, 2, 3... (orden)
badge_url VARCHAR(500) Imagen de badge
color VARCHAR(7) Color hex
requirements JSONB Requisitos
bonus_rate DECIMAL(10,4) Tasa de bono adicional
benefits JSONB Beneficios del rango
is_active BOOLEAN Estado

Requisitos ejemplo:

{
  "personal_volume": 1000,
  "group_volume": 10000,
  "direct_referrals": 3,
  "active_legs": 2,
  "rank_in_legs": {"rank_level": 2, "count": 1}
}

Tabla: nodes

Campo Tipo Descripcion
id UUID PK
tenant_id UUID FK tenants
structure_id UUID FK structures
user_id UUID FK users
parent_id UUID FK nodes (padre directo)
sponsor_id UUID FK nodes (patrocinador)
position INT 1=left, 2=right (binary)
path LTREE Ruta materializada
depth INT Profundidad en el arbol
rank_id UUID FK ranks (rango actual)
highest_rank_id UUID FK ranks (maximo alcanzado)
personal_volume DECIMAL(15,2) Volumen personal
group_volume DECIMAL(15,2) Volumen de grupo
direct_referrals INT Referidos directos
total_downline INT Total de linea descendente
total_earnings DECIMAL(15,2) Ganancias totales
status ENUM pending, active, inactive, suspended
joined_at TIMESTAMPTZ Fecha de ingreso
invite_code VARCHAR(20) Codigo de invitacion

Tabla: commissions

Campo Tipo Descripcion
id UUID PK
tenant_id UUID FK tenants
node_id UUID FK nodes (receptor)
source_node_id UUID FK nodes (origen)
type ENUM level, matching, infinity, leadership, pool
level INT Nivel de profundidad
source_amount DECIMAL(15,2) Monto origen
rate_applied DECIMAL(10,4) Tasa aplicada
commission_amount DECIMAL(15,2) Comision final
currency VARCHAR(3) Moneda
period_id UUID FK commissions.periods
source_reference VARCHAR(200) Referencia a transaccion
status ENUM pending, approved, paid, cancelled
paid_at TIMESTAMPTZ Fecha de pago

Tabla: bonuses

Campo Tipo Descripcion
id UUID PK
tenant_id UUID FK tenants
node_id UUID FK nodes
rank_id UUID FK ranks
type ENUM rank_achievement, rank_maintenance, fast_start, pool_share
amount DECIMAL(15,2) Monto del bono
currency VARCHAR(3) Moneda
period_id UUID FK commissions.periods
status ENUM pending, approved, paid, cancelled
paid_at TIMESTAMPTZ Fecha de pago
achieved_at TIMESTAMPTZ Fecha de logro

Tabla: rank_history

Campo Tipo Descripcion
id UUID PK
tenant_id UUID FK tenants
node_id UUID FK nodes
rank_id UUID FK ranks (nuevo rango)
previous_rank_id UUID FK ranks (rango anterior)
personal_volume_at DECIMAL(15,2) Snapshot
group_volume_at DECIMAL(15,2) Snapshot
direct_referrals_at INT Snapshot
achieved_at TIMESTAMPTZ Fecha de logro

2.2 Enums

mlm.structure_type: unilevel, binary, matrix, hybrid
mlm.node_status: pending, active, inactive, suspended
mlm.commission_type: level, matching, infinity, leadership, pool
mlm.commission_status: pending, approved, paid, cancelled
mlm.bonus_type: rank_achievement, rank_maintenance, fast_start, pool_share

3. LTREE para Consultas Eficientes

3.1 Estructura del Path

Ejemplo: root.node1.node2.node3
         └── Ruta desde la raiz hasta el nodo

3.2 Consultas Comunes

-- Obtener todos los ancestros (upline)
SELECT * FROM mlm.nodes WHERE path @> 'root.a.b.c';

-- Obtener todos los descendientes (downline)
SELECT * FROM mlm.nodes WHERE path <@ 'root.a.b.c';

-- Obtener descendientes hasta N niveles
SELECT * FROM mlm.nodes
WHERE path <@ 'root.a.b.c'
  AND nlevel(path) - nlevel('root.a.b.c') <= 3;

-- Obtener hermanos
SELECT * FROM mlm.nodes WHERE subpath(path, 0, -1) = 'root.a.b';

4. Arquitectura Backend

4.1 Estructura de Archivos

backend/src/modules/mlm/
├── mlm.module.ts
├── controllers/
│   ├── structures.controller.ts
│   ├── ranks.controller.ts
│   ├── nodes.controller.ts
│   ├── commissions.controller.ts
│   └── my-network.controller.ts
├── services/
│   ├── structures.service.ts
│   ├── ranks.service.ts
│   ├── nodes.service.ts
│   ├── commissions.service.ts
│   ├── calculation.service.ts
│   └── genealogy.service.ts
├── entities/
│   ├── structure.entity.ts
│   ├── rank.entity.ts
│   ├── node.entity.ts
│   ├── commission.entity.ts
│   ├── bonus.entity.ts
│   └── rank-history.entity.ts
└── dto/

4.2 Endpoints API

Structures

Metodo Endpoint Descripcion
GET /mlm/structures Listar
GET /mlm/structures/:id Obtener
POST /mlm/structures Crear
PUT /mlm/structures/:id Actualizar
DELETE /mlm/structures/:id Eliminar

Ranks

Metodo Endpoint Descripcion
GET /mlm/ranks Listar
GET /mlm/ranks/:id Obtener
POST /mlm/ranks Crear
PUT /mlm/ranks/:id Actualizar
DELETE /mlm/ranks/:id Eliminar
POST /mlm/ranks/evaluate/:structureId Evaluar todos

Nodes

Metodo Endpoint Descripcion
GET /mlm/nodes Listar
GET /mlm/nodes/:id Obtener
POST /mlm/nodes Crear (registrar en red)
PUT /mlm/nodes/:id Actualizar
PATCH /mlm/nodes/:id/status Cambiar status
GET /mlm/nodes/:id/downline Linea descendente
GET /mlm/nodes/:id/upline Linea ascendente
GET /mlm/nodes/:id/tree Arbol visual

My Network (Usuario autenticado)

Metodo Endpoint Descripcion
GET /mlm/my/dashboard Mi dashboard
GET /mlm/my/network Mi red
GET /mlm/my/earnings Mis ganancias
GET /mlm/my/rank Mi rango actual
POST /mlm/my/invite Generar link de invitacion

Commissions

Metodo Endpoint Descripcion
GET /mlm/commissions Listar
GET /mlm/commissions/:id Obtener
POST /mlm/commissions/calculate Calcular
PATCH /mlm/commissions/:id/status Cambiar status
GET /mlm/commissions/by-level Por nivel

5. Logica de Comisiones

5.1 Algoritmo de Calculo por Nivel

async calculateLevelCommissions(sale: Sale): Promise<Commission[]> {
  const commissions: Commission[] = [];

  // Obtener nodo del vendedor
  const sourceNode = await this.getNodeByUserId(sale.userId);

  // Obtener estructura y tasas
  const structure = await this.getStructure(sourceNode.structureId);
  const levelRates = structure.levelRates;

  // Recorrer upline
  let currentNode = await this.getParentNode(sourceNode.id);
  let level = 1;

  while (currentNode && level <= levelRates.length) {
    const rate = levelRates.find(r => r.level === level)?.rate || 0;

    if (rate > 0 && currentNode.status === 'active') {
      commissions.push({
        nodeId: currentNode.id,
        sourceNodeId: sourceNode.id,
        type: 'level',
        level,
        sourceAmount: sale.amount,
        rateApplied: rate,
        commissionAmount: sale.amount * rate
      });
    }

    currentNode = await this.getParentNode(currentNode.id);
    level++;
  }

  return commissions;
}

5.2 Ejemplo

Estructura: 3 niveles (10%, 5%, 3%)
Venta: $1,000

Usuario D hace venta →
  Nivel 1 (Usuario C): $1,000 × 10% = $100
  Nivel 2 (Usuario B): $1,000 × 5% = $50
  Nivel 3 (Usuario A): $1,000 × 3% = $30

6. Frontend (Pendiente)

6.1 Paginas Propuestas

Ruta Componente Estado
/dashboard/mlm MLMDashboard Pendiente
/dashboard/mlm/network NetworkPage Pendiente
/dashboard/mlm/genealogy GenealogyPage Pendiente
/dashboard/mlm/ranks RanksPage Pendiente
/dashboard/mlm/commissions MLMCommissionsPage Pendiente
/dashboard/mlm/my-network MyNetworkPage Pendiente

6.2 Hooks Existentes

// frontend/src/hooks/useMlm.ts
useStructures, useStructure, useCreateStructure, useUpdateStructure
useRanks, useRank, useCreateRank, useEvaluateRanks
useNodes, useNode, useNodeDownline, useNodeUpline, useNodeTree
useMyDashboard, useMyNetwork, useMyEarnings, useMyRank, useGenerateInviteLink
useMLMCommissions, useCalculateCommissions, useCommissionsByLevel

7. Seguridad

7.1 RLS

CREATE POLICY nodes_tenant_isolation ON mlm.nodes
    USING (tenant_id = current_setting('app.tenant_id')::uuid);

CREATE POLICY commissions_tenant_isolation ON mlm.commissions
    USING (tenant_id = current_setting('app.tenant_id')::uuid);

7.2 Permisos RBAC

Permiso Descripcion
mlm:read Ver red y comisiones
mlm:write Gestionar nodos
mlm:admin Administrar estructuras
mlm:calculate Ejecutar calculos

8. Integraciones

Modulo Integracion
sales Trigger en ventas para comisiones
commissions Periodos compartidos
goals Metas de volumen
notifications Alertas de rango
audit Log de cambios

9. Referencias

  • DDL: database/ddl/schemas/mlm/
  • Backend: backend/src/modules/mlm/
  • Frontend Services: frontend/src/services/mlm/
  • Frontend Hooks: frontend/src/hooks/useMlm.ts