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

435 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
id: "ET-SAAS-021"
title: "Especificacion Tecnica MLM (Multi-Level Marketing)"
type: "TechnicalSpec"
status: "Implemented"
priority: "P1"
module: "mlm"
version: "1.0.0"
created_date: "2026-02-03"
updated_date: "2026-02-03"
story_points: 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:**
```json
// Unilevel
{"max_width": null, "max_depth": 10}
// Binary
{"spillover": "left_first" | "weak_leg" | "balanced"}
// Matrix
{"width": 3, "depth": 7}
```
**Level rates:**
```json
[
{"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:**
```json
{
"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
```sql
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
```sql
-- 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
```typescript
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
```typescript
// 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
```sql
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`