| 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