diff --git a/docs/02-especificaciones/ET-SAAS-018-sales.md b/docs/02-especificaciones/ET-SAAS-018-sales.md new file mode 100644 index 00000000..14ac04bd --- /dev/null +++ b/docs/02-especificaciones/ET-SAAS-018-sales.md @@ -0,0 +1,289 @@ +--- +id: "ET-SAAS-018" +title: "Especificacion Tecnica Sales Pipeline" +type: "TechnicalSpec" +status: "Implemented" +priority: "P1" +module: "sales" +version: "1.0.0" +created_date: "2026-02-03" +updated_date: "2026-02-03" +story_points: 8 +--- + +# ET-SAAS-018: Especificacion Tecnica - Sistema de Ventas (Sales Pipeline) + +## Metadata +- **Codigo:** ET-SAAS-018 +- **Modulo:** Sales +- **Version:** 1.0.0 +- **Estado:** Implementado +- **Fecha:** 2026-02-03 +- **Basado en:** SAAS-018 + +--- + +## 1. Resumen Ejecutivo + +### 1.1 Estado Actual + +Sistema de ventas completamente implementado con CRM basico. + +| Capacidad | Estado | Notas | +|-----------|--------|-------| +| Pipeline Stages | SI | Etapas configurables por tenant | +| Leads Management | SI | Prospectos con scoring | +| Opportunities | SI | Oportunidades con probabilidad | +| Activities | SI | Llamadas, reuniones, tareas | +| RLS | SI | Row Level Security por tenant | + +### 1.2 Funcionalidades v1.0 + +Sistema CRM con: + +- **4 Entidades**: Pipeline Stages, Leads, Opportunities, Activities +- **Pipeline configurable**: Etapas personalizables por tenant +- **Lead Scoring**: Puntuacion 0-100 automatica +- **Activity Tracking**: Llamadas, reuniones, tareas, emails, notas +- **Conversion Flow**: Lead → Opportunity → Won/Lost + +--- + +## 2. Modelo de Datos + +### 2.1 Schema: sales + +#### Tabla: pipeline_stages +| Campo | Tipo | Descripcion | +|-------|------|-------------| +| id | UUID | PK | +| tenant_id | UUID | FK tenants | +| name | VARCHAR(100) | Nombre de la etapa | +| position | INT | Orden en el pipeline | +| color | VARCHAR(7) | Color hex | +| is_won | BOOLEAN | Etapa de cierre ganado | +| is_lost | BOOLEAN | Etapa de cierre perdido | +| is_active | BOOLEAN | Estado activo | + +#### Tabla: leads +| Campo | Tipo | Descripcion | +|-------|------|-------------| +| id | UUID | PK | +| tenant_id | UUID | FK tenants | +| first_name, last_name | VARCHAR(100) | Nombre completo | +| email, phone | VARCHAR | Contacto | +| company, job_title | VARCHAR | Empresa | +| source | ENUM | website, referral, cold_call, event, advertisement, social_media, other | +| status | ENUM | new, contacted, qualified, unqualified, converted | +| score | INT | 0-100 lead scoring | +| assigned_to | UUID | FK users | +| converted_at | TIMESTAMPTZ | Fecha conversion | +| custom_fields | JSONB | Campos personalizados | + +#### Tabla: opportunities +| Campo | Tipo | Descripcion | +|-------|------|-------------| +| id | UUID | PK | +| tenant_id | UUID | FK tenants | +| name | VARCHAR(255) | Nombre de la oportunidad | +| lead_id | UUID | FK leads (opcional) | +| stage | ENUM | prospecting, qualification, proposal, negotiation, closed_won, closed_lost | +| stage_id | UUID | FK pipeline_stages | +| amount | DECIMAL(15,2) | Valor monetario | +| currency | VARCHAR(3) | Moneda (default USD) | +| probability | INT | 0-100 probabilidad de cierre | +| expected_close_date | DATE | Fecha esperada de cierre | +| assigned_to | UUID | FK users | +| won_at, lost_at | TIMESTAMPTZ | Fechas de cierre | +| lost_reason | VARCHAR(500) | Razon de perdida | + +#### Tabla: activities +| Campo | Tipo | Descripcion | +|-------|------|-------------| +| id | UUID | PK | +| tenant_id | UUID | FK tenants | +| type | ENUM | call, meeting, task, email, note | +| status | ENUM | pending, completed, cancelled | +| subject | VARCHAR(255) | Titulo | +| lead_id / opportunity_id | UUID | Referencia | +| due_date | TIMESTAMPTZ | Fecha limite | +| completed_at | TIMESTAMPTZ | Fecha completado | +| assigned_to | UUID | FK users | +| reminder_at | TIMESTAMPTZ | Recordatorio | + +### 2.2 Enums + +```sql +sales.lead_status: new, contacted, qualified, unqualified, converted +sales.lead_source: website, referral, cold_call, event, advertisement, social_media, other +sales.opportunity_stage: prospecting, qualification, proposal, negotiation, closed_won, closed_lost +sales.activity_type: call, meeting, task, email, note +sales.activity_status: pending, completed, cancelled +``` + +--- + +## 3. Arquitectura Backend + +### 3.1 Estructura de Archivos + +``` +backend/src/modules/sales/ +├── sales.module.ts +├── controllers/ +│ ├── leads.controller.ts +│ ├── opportunities.controller.ts +│ ├── activities.controller.ts +│ └── pipeline-stages.controller.ts +├── services/ +│ ├── leads.service.ts +│ ├── opportunities.service.ts +│ ├── activities.service.ts +│ └── pipeline-stages.service.ts +├── entities/ +│ ├── lead.entity.ts +│ ├── opportunity.entity.ts +│ ├── activity.entity.ts +│ └── pipeline-stage.entity.ts +├── dto/ +│ ├── create-lead.dto.ts +│ ├── update-lead.dto.ts +│ ├── create-opportunity.dto.ts +│ └── ... +└── __tests__/ +``` + +### 3.2 Endpoints API + +#### Leads +| Metodo | Endpoint | Descripcion | +|--------|----------|-------------| +| GET | /sales/leads | Listar leads | +| GET | /sales/leads/:id | Obtener lead | +| POST | /sales/leads | Crear lead | +| PATCH | /sales/leads/:id | Actualizar lead | +| DELETE | /sales/leads/:id | Eliminar lead | +| POST | /sales/leads/:id/convert | Convertir a oportunidad | + +#### Opportunities +| Metodo | Endpoint | Descripcion | +|--------|----------|-------------| +| GET | /sales/opportunities | Listar oportunidades | +| GET | /sales/opportunities/:id | Obtener oportunidad | +| POST | /sales/opportunities | Crear oportunidad | +| PATCH | /sales/opportunities/:id | Actualizar | +| PATCH | /sales/opportunities/:id/stage | Cambiar etapa | +| POST | /sales/opportunities/:id/won | Marcar como ganada | +| POST | /sales/opportunities/:id/lost | Marcar como perdida | +| DELETE | /sales/opportunities/:id | Eliminar | + +#### Activities +| Metodo | Endpoint | Descripcion | +|--------|----------|-------------| +| GET | /sales/activities | Listar actividades | +| GET | /sales/activities/:id | Obtener actividad | +| POST | /sales/activities | Crear actividad | +| PATCH | /sales/activities/:id | Actualizar | +| POST | /sales/activities/:id/complete | Marcar completada | +| DELETE | /sales/activities/:id | Eliminar | + +#### Pipeline Stages +| Metodo | Endpoint | Descripcion | +|--------|----------|-------------| +| GET | /sales/pipeline-stages | Listar etapas | +| POST | /sales/pipeline-stages | Crear etapa | +| PATCH | /sales/pipeline-stages/:id | Actualizar | +| PATCH | /sales/pipeline-stages/reorder | Reordenar | +| DELETE | /sales/pipeline-stages/:id | Eliminar | + +--- + +## 4. Seguridad + +### 4.1 Row Level Security (RLS) + +Todas las tablas tienen RLS habilitado con politicas por tenant_id. + +```sql +-- Ejemplo para leads +CREATE POLICY leads_tenant_isolation ON sales.leads + USING (tenant_id = current_setting('app.tenant_id')::uuid); +``` + +### 4.2 Permisos RBAC + +| Permiso | Descripcion | +|---------|-------------| +| sales:read | Ver leads, oportunidades, actividades | +| sales:write | Crear/editar | +| sales:delete | Eliminar | +| sales:assign | Asignar a usuarios | +| sales:manage | Configurar pipeline | + +--- + +## 5. Integraciones + +### 5.1 Modulos Relacionados + +| Modulo | Integracion | +|--------|-------------| +| users | Asignacion de leads/opportunities | +| notifications | Alertas de actividades | +| audit | Log de cambios | +| commissions | Calculo de comisiones en won | +| goals | Tracking de metas de ventas | + +### 5.2 Eventos Emitidos + +```typescript +// Eventos del modulo sales +LeadCreated, LeadUpdated, LeadConverted +OpportunityCreated, OpportunityStageChanged, OpportunityWon, OpportunityLost +ActivityCreated, ActivityCompleted +``` + +--- + +## 6. Frontend + +### 6.1 Paginas + +| Ruta | Componente | Estado | +|------|------------|--------| +| /dashboard/sales | SalesDashboard | Pendiente | +| /dashboard/sales/leads | LeadsPage | Pendiente | +| /dashboard/sales/opportunities | OpportunitiesPage | Pendiente | +| /dashboard/sales/pipeline | PipelinePage | Pendiente | +| /dashboard/sales/activities | ActivitiesPage | Pendiente | + +### 6.2 Hooks + +```typescript +// frontend/src/hooks/useSales.ts +useLeads, useLead, useCreateLead, useUpdateLead, useDeleteLead, useConvertLead +useOpportunities, useOpportunity, useCreateOpportunity, useUpdateOpportunityStage +useActivities, useCreateActivity, useCompleteActivity +usePipelineStages +``` + +--- + +## 7. Metricas y Dashboard + +### 7.1 KPIs Propuestos + +- Total Leads por periodo +- Conversion Rate (Lead → Opportunity) +- Win Rate (Opportunity → Won) +- Pipeline Value (suma de amounts) +- Average Deal Size +- Sales Velocity (tiempo promedio de cierre) + +--- + +## 8. Referencias + +- DDL: `database/ddl/schemas/sales/` +- Backend: `backend/src/modules/sales/` +- Frontend: `frontend/src/services/sales/` diff --git a/docs/02-especificaciones/ET-SAAS-019-portfolio.md b/docs/02-especificaciones/ET-SAAS-019-portfolio.md new file mode 100644 index 00000000..013523f4 --- /dev/null +++ b/docs/02-especificaciones/ET-SAAS-019-portfolio.md @@ -0,0 +1,318 @@ +--- +id: "ET-SAAS-019" +title: "Especificacion Tecnica Portfolio (Product Catalog)" +type: "TechnicalSpec" +status: "Implemented" +priority: "P1" +module: "portfolio" +version: "1.0.0" +created_date: "2026-02-03" +updated_date: "2026-02-03" +story_points: 8 +--- + +# ET-SAAS-019: Especificacion Tecnica - Portfolio (Catalogo de Productos) + +## Metadata +- **Codigo:** ET-SAAS-019 +- **Modulo:** Portfolio +- **Version:** 1.0.0 +- **Estado:** Implementado +- **Fecha:** 2026-02-03 +- **Basado en:** SAAS-019 + +--- + +## 1. Resumen Ejecutivo + +### 1.1 Estado Actual + +Sistema de catalogo de productos completamente implementado. + +| Capacidad | Estado | Notas | +|-----------|--------|-------| +| Categories | SI | Jerarquicas con arbol | +| Products | SI | Multi-tipo, inventario | +| Variants | SI | Atributos configurables | +| Prices | SI | Multi-moneda, tiered | +| RLS | SI | Row Level Security | + +### 1.2 Funcionalidades v1.0 + +Catalogo completo con: + +- **4 Entidades**: Categories, Products, Variants, Prices +- **Categorias jerarquicas**: Arbol ilimitado con parent_id +- **5 Tipos de producto**: physical, digital, service, subscription, bundle +- **Variantes**: Atributos dinamicos (color, size, etc.) +- **Precios flexibles**: one_time, recurring, usage_based, tiered + +--- + +## 2. Modelo de Datos + +### 2.1 Schema: portfolio + +#### Tabla: categories +| Campo | Tipo | Descripcion | +|-------|------|-------------| +| id | UUID | PK | +| tenant_id | UUID | FK tenants | +| parent_id | UUID | FK categories (jerarquia) | +| name | VARCHAR(100) | Nombre categoria | +| slug | VARCHAR(120) | URL-friendly (unique per tenant) | +| description | TEXT | Descripcion | +| position | INT | Orden dentro del padre | +| image_url | VARCHAR(500) | Imagen | +| color | VARCHAR(7) | Color hex | +| icon | VARCHAR(50) | Icono | +| is_active | BOOLEAN | Estado | +| meta_title, meta_description | VARCHAR/TEXT | SEO | +| custom_fields | JSONB | Campos personalizados | + +#### Tabla: products +| Campo | Tipo | Descripcion | +|-------|------|-------------| +| id | UUID | PK | +| tenant_id | UUID | FK tenants | +| category_id | UUID | FK categories | +| name | VARCHAR(255) | Nombre producto | +| slug | VARCHAR(280) | URL-friendly | +| sku | VARCHAR(100) | Stock Keeping Unit | +| barcode | VARCHAR(100) | Codigo de barras | +| description | TEXT | Descripcion larga | +| short_description | VARCHAR(500) | Descripcion corta | +| product_type | ENUM | physical, digital, service, subscription, bundle | +| status | ENUM | draft, active, inactive, discontinued, out_of_stock | +| base_price | DECIMAL(15,2) | Precio base | +| cost_price | DECIMAL(15,2) | Costo | +| compare_at_price | DECIMAL(15,2) | Precio tachado | +| currency | VARCHAR(3) | Moneda (default USD) | +| track_inventory | BOOLEAN | Trackear inventario | +| stock_quantity | INT | Cantidad en stock | +| low_stock_threshold | INT | Umbral de stock bajo | +| allow_backorder | BOOLEAN | Permitir backorder | +| weight, length, width, height | DECIMAL | Dimensiones | +| images | JSONB | Array de URLs | +| featured_image_url | VARCHAR(500) | Imagen principal | +| tags | JSONB | Array de tags | +| is_visible | BOOLEAN | Visible en frontend | +| is_featured | BOOLEAN | Producto destacado | +| has_variants | BOOLEAN | Tiene variantes | +| variant_attributes | JSONB | Atributos para variantes | + +#### Tabla: variants +| Campo | Tipo | Descripcion | +|-------|------|-------------| +| id | UUID | PK | +| tenant_id | UUID | FK tenants | +| product_id | UUID | FK products | +| sku | VARCHAR(100) | SKU de variante | +| barcode | VARCHAR(100) | Codigo de barras | +| name | VARCHAR(255) | Nombre (e.g., "Rojo - XL") | +| attributes | JSONB | {"color": "red", "size": "XL"} | +| price | DECIMAL(15,2) | Override de precio | +| cost_price | DECIMAL(15,2) | Costo variante | +| stock_quantity | INT | Stock de variante | +| weight | DECIMAL(10,3) | Peso (override) | +| image_url | VARCHAR(500) | Imagen de variante | +| is_active | BOOLEAN | Estado | +| position | INT | Orden | + +#### Tabla: prices +| Campo | Tipo | Descripcion | +|-------|------|-------------| +| id | UUID | PK | +| tenant_id | UUID | FK tenants | +| product_id | UUID | FK products (o variant_id) | +| variant_id | UUID | FK variants (o product_id) | +| price_type | ENUM | one_time, recurring, usage_based, tiered | +| currency | VARCHAR(3) | Moneda | +| amount | DECIMAL(15,2) | Precio | +| compare_at_amount | DECIMAL(15,2) | Precio comparativo | +| billing_period | VARCHAR(20) | day, week, month, year | +| billing_interval | INT | Intervalo (e.g., 1 = mensual) | +| min_quantity, max_quantity | INT | Rango para tiered | +| valid_from, valid_until | TIMESTAMPTZ | Validez | +| priority | INT | Prioridad (0 = default) | +| is_active | BOOLEAN | Estado | + +### 2.2 Enums + +```sql +portfolio.product_type: physical, digital, service, subscription, bundle +portfolio.product_status: draft, active, inactive, discontinued, out_of_stock +portfolio.price_type: one_time, recurring, usage_based, tiered +portfolio.attribute_type: color, size, material, style, capacity, custom +``` + +--- + +## 3. Arquitectura Backend + +### 3.1 Estructura de Archivos + +``` +backend/src/modules/portfolio/ +├── portfolio.module.ts +├── controllers/ +│ ├── categories.controller.ts +│ └── products.controller.ts +├── services/ +│ ├── categories.service.ts +│ └── products.service.ts +├── entities/ +│ ├── category.entity.ts +│ ├── product.entity.ts +│ ├── variant.entity.ts +│ └── price.entity.ts +├── dto/ +│ ├── create-category.dto.ts +│ ├── create-product.dto.ts +│ └── ... +└── __tests__/ +``` + +### 3.2 Endpoints API + +#### Categories +| Metodo | Endpoint | Descripcion | +|--------|----------|-------------| +| GET | /portfolio/categories | Listar (paginado) | +| GET | /portfolio/categories/tree | Arbol jerarquico | +| GET | /portfolio/categories/:id | Obtener | +| POST | /portfolio/categories | Crear | +| PUT | /portfolio/categories/:id | Actualizar | +| DELETE | /portfolio/categories/:id | Eliminar | + +#### Products +| Metodo | Endpoint | Descripcion | +|--------|----------|-------------| +| GET | /portfolio/products | Listar (paginado, filtros) | +| GET | /portfolio/products/:id | Obtener con variantes | +| POST | /portfolio/products | Crear | +| PUT | /portfolio/products/:id | Actualizar | +| PATCH | /portfolio/products/:id/status | Cambiar status | +| POST | /portfolio/products/:id/duplicate | Duplicar | +| DELETE | /portfolio/products/:id | Eliminar | + +#### Variants +| Metodo | Endpoint | Descripcion | +|--------|----------|-------------| +| GET | /portfolio/products/:id/variants | Listar variantes | +| POST | /portfolio/products/:id/variants | Crear variante | +| PATCH | /portfolio/products/:id/variants/:vid | Actualizar | +| DELETE | /portfolio/products/:id/variants/:vid | Eliminar | + +#### Prices +| Metodo | Endpoint | Descripcion | +|--------|----------|-------------| +| GET | /portfolio/products/:id/prices | Listar precios | +| POST | /portfolio/products/:id/prices | Crear precio | +| PATCH | /portfolio/products/:id/prices/:pid | Actualizar | +| DELETE | /portfolio/products/:id/prices/:pid | Eliminar | + +--- + +## 4. Seguridad + +### 4.1 Row Level Security (RLS) + +```sql +-- Aislamiento por tenant +CREATE POLICY categories_tenant_isolation ON portfolio.categories + USING (tenant_id = current_setting('app.tenant_id')::uuid); + +CREATE POLICY products_tenant_isolation ON portfolio.products + USING (tenant_id = current_setting('app.tenant_id')::uuid); +``` + +### 4.2 Permisos RBAC + +| Permiso | Descripcion | +|---------|-------------| +| portfolio:read | Ver catalogo | +| portfolio:write | Crear/editar productos | +| portfolio:delete | Eliminar productos | +| portfolio:publish | Publicar/despublicar | +| portfolio:manage | Configuracion avanzada | + +--- + +## 5. Frontend + +### 5.1 Paginas Implementadas + +| Ruta | Componente | Estado | +|------|------------|--------| +| /dashboard/portfolio | PortfolioPage | Implementado | +| /dashboard/portfolio/products | ProductsPage | Implementado | +| /dashboard/portfolio/categories | CategoriesPage | Implementado | +| /dashboard/portfolio/products/:id | ProductDetailPage | Pendiente | +| /dashboard/portfolio/products/new | ProductFormPage | Pendiente | + +### 5.2 Hooks + +```typescript +// frontend/src/hooks/usePortfolio.ts +useCategories, useCategory, useCategoryTree +useCreateCategory, useUpdateCategory, useDeleteCategory +useProducts, useProduct +useCreateProduct, useUpdateProduct, useDeleteProduct, useDuplicateProduct +useProductVariants, useCreateVariant, useUpdateVariant, useDeleteVariant +useProductPrices, useCreatePrice, useUpdatePrice, useDeletePrice +``` + +--- + +## 6. Integraciones + +### 6.1 Modulos Relacionados + +| Modulo | Integracion | +|--------|-------------| +| sales | Productos en oportunidades | +| commissions | Comisiones por producto/categoria | +| storage | Imagenes de productos | +| audit | Log de cambios | + +### 6.2 Eventos Emitidos + +```typescript +ProductCreated, ProductUpdated, ProductStatusChanged +CategoryCreated, CategoryUpdated +VariantCreated, PriceUpdated +LowStockAlert // Cuando stock < threshold +``` + +--- + +## 7. Filtros y Busqueda + +### 7.1 Filtros Disponibles + +```typescript +interface ProductFilters { + category_id?: string; + product_type?: ProductType; + status?: ProductStatus; + is_visible?: boolean; + is_featured?: boolean; + min_price?: number; + max_price?: number; + search?: string; // Busca en name, sku, description + tags?: string[]; + sort_by?: 'name' | 'price' | 'created_at' | 'stock'; + sort_order?: 'ASC' | 'DESC'; +} +``` + +--- + +## 8. Referencias + +- DDL: `database/ddl/schemas/portfolio/` +- Backend: `backend/src/modules/portfolio/` +- Frontend Services: `frontend/src/services/portfolio/` +- Frontend Hooks: `frontend/src/hooks/usePortfolio.ts` +- Frontend Pages: `frontend/src/pages/dashboard/portfolio/` diff --git a/docs/02-especificaciones/ET-SAAS-020-commissions.md b/docs/02-especificaciones/ET-SAAS-020-commissions.md new file mode 100644 index 00000000..7f1a0073 --- /dev/null +++ b/docs/02-especificaciones/ET-SAAS-020-commissions.md @@ -0,0 +1,375 @@ +--- +id: "ET-SAAS-020" +title: "Especificacion Tecnica Commissions" +type: "TechnicalSpec" +status: "Implemented" +priority: "P1" +module: "commissions" +version: "1.0.0" +created_date: "2026-02-03" +updated_date: "2026-02-03" +story_points: 8 +--- + +# ET-SAAS-020: Especificacion Tecnica - Sistema de Comisiones + +## Metadata +- **Codigo:** ET-SAAS-020 +- **Modulo:** Commissions +- **Version:** 1.0.0 +- **Estado:** Implementado +- **Fecha:** 2026-02-03 +- **Basado en:** SAAS-020 + +--- + +## 1. Resumen Ejecutivo + +### 1.1 Estado Actual + +Sistema de comisiones completamente implementado. + +| Capacidad | Estado | Notas | +|-----------|--------|-------| +| Schemes | SI | Esquemas configurables | +| Assignments | SI | Asignacion usuario-esquema | +| Entries | SI | Entradas de comision | +| Periods | SI | Periodos de pago | +| Dashboard | SI | Metricas y reportes | +| RLS | SI | Row Level Security | + +### 1.2 Funcionalidades v1.0 + +Sistema completo con: + +- **4 Entidades**: Schemes, Assignments, Entries, Periods +- **3 Tipos de esquema**: percentage, fixed, tiered +- **Workflow completo**: pending → approved → paid +- **Periodos de pago**: Ciclos configurables +- **Dashboard**: Metricas por usuario, periodo, esquema + +--- + +## 2. Modelo de Datos + +### 2.1 Schema: commissions + +#### Tabla: schemes +| Campo | Tipo | Descripcion | +|-------|------|-------------| +| id | UUID | PK | +| tenant_id | UUID | FK tenants | +| name | VARCHAR(100) | Nombre del esquema | +| description | TEXT | Descripcion | +| type | ENUM | percentage, fixed, tiered | +| rate | DECIMAL(5,2) | Tasa porcentual (0-100) | +| fixed_amount | DECIMAL(15,2) | Monto fijo | +| tiers | JSONB | [{from, to, rate}] | +| applies_to | ENUM | all, products, categories | +| product_ids | UUID[] | IDs de productos | +| category_ids | UUID[] | IDs de categorias | +| min_amount | DECIMAL(15,2) | Monto minimo para calificar | +| max_amount | DECIMAL(15,2) | Cap maximo por comision | +| is_active | BOOLEAN | Estado | + +**Ejemplo tiers:** +```json +[ + {"from": 0, "to": 1000, "rate": 5}, + {"from": 1001, "to": 5000, "rate": 7}, + {"from": 5001, "to": null, "rate": 10} +] +``` + +#### Tabla: assignments +| Campo | Tipo | Descripcion | +|-------|------|-------------| +| id | UUID | PK | +| tenant_id | UUID | FK tenants | +| user_id | UUID | FK users | +| scheme_id | UUID | FK schemes | +| starts_at | TIMESTAMPTZ | Inicio de vigencia | +| ends_at | TIMESTAMPTZ | Fin de vigencia (null = sin fin) | +| custom_rate | DECIMAL(5,2) | Override de tasa para este usuario | +| is_active | BOOLEAN | Estado | + +#### Tabla: entries +| Campo | Tipo | Descripcion | +|-------|------|-------------| +| id | UUID | PK | +| tenant_id | UUID | FK tenants | +| user_id | UUID | FK users (quien gana) | +| scheme_id | UUID | FK schemes | +| assignment_id | UUID | FK assignments | +| reference_type | VARCHAR(50) | sale, opportunity, order | +| reference_id | UUID | ID del registro origen | +| base_amount | DECIMAL(15,2) | Monto base de la venta | +| rate_applied | DECIMAL(5,2) | Tasa aplicada | +| commission_amount | DECIMAL(15,2) | Comision calculada | +| currency | VARCHAR(3) | Moneda | +| status | ENUM | pending, approved, rejected, paid, cancelled | +| period_id | UUID | FK periods | +| paid_at | TIMESTAMPTZ | Fecha de pago | +| payment_reference | VARCHAR(255) | Referencia externa | +| notes | TEXT | Notas | +| metadata | JSONB | Datos adicionales | +| approved_by | UUID | FK users | +| approved_at | TIMESTAMPTZ | Fecha aprobacion | + +#### Tabla: periods +| Campo | Tipo | Descripcion | +|-------|------|-------------| +| id | UUID | PK | +| tenant_id | UUID | FK tenants | +| name | VARCHAR(100) | "January 2026" | +| starts_at | TIMESTAMPTZ | Inicio del periodo | +| ends_at | TIMESTAMPTZ | Fin del periodo | +| total_entries | INT | Total de entradas | +| total_amount | DECIMAL(15,2) | Monto total | +| currency | VARCHAR(3) | Moneda | +| status | ENUM | open, closed, processing, paid | +| closed_at | TIMESTAMPTZ | Fecha cierre | +| closed_by | UUID | FK users | +| paid_at | TIMESTAMPTZ | Fecha pago | +| paid_by | UUID | FK users | +| payment_reference | VARCHAR(255) | Referencia | +| payment_notes | TEXT | Notas de pago | + +### 2.2 Enums + +```sql +commissions.scheme_type: percentage, fixed, tiered +commissions.applies_to: all, products, categories +commissions.entry_status: pending, approved, rejected, paid, cancelled +commissions.period_status: open, closed, processing, paid +``` + +--- + +## 3. Arquitectura Backend + +### 3.1 Estructura de Archivos + +``` +backend/src/modules/commissions/ +├── commissions.module.ts +├── controllers/ +│ ├── schemes.controller.ts +│ ├── assignments.controller.ts +│ ├── entries.controller.ts +│ ├── periods.controller.ts +│ └── dashboard.controller.ts +├── services/ +│ ├── schemes.service.ts +│ ├── assignments.service.ts +│ ├── entries.service.ts +│ ├── periods.service.ts +│ ├── calculation.service.ts +│ └── dashboard.service.ts +├── entities/ +│ ├── scheme.entity.ts +│ ├── assignment.entity.ts +│ ├── entry.entity.ts +│ └── period.entity.ts +└── dto/ +``` + +### 3.2 Endpoints API + +#### Schemes +| Metodo | Endpoint | Descripcion | +|--------|----------|-------------| +| GET | /commissions/schemes | Listar esquemas | +| GET | /commissions/schemes/active | Solo activos | +| GET | /commissions/schemes/:id | Obtener | +| POST | /commissions/schemes | Crear | +| PUT | /commissions/schemes/:id | Actualizar | +| DELETE | /commissions/schemes/:id | Eliminar | +| POST | /commissions/schemes/:id/duplicate | Duplicar | +| POST | /commissions/schemes/:id/toggle | Activar/desactivar | + +#### Assignments +| Metodo | Endpoint | Descripcion | +|--------|----------|-------------| +| GET | /commissions/assignments | Listar | +| GET | /commissions/assignments/user/:userId | Por usuario | +| GET | /commissions/assignments/user/:userId/active | Esquema activo | +| GET | /commissions/assignments/scheme/:schemeId | Por esquema | +| POST | /commissions/assignments | Asignar | +| PUT | /commissions/assignments/:id | Actualizar | +| DELETE | /commissions/assignments/:id | Remover | +| POST | /commissions/assignments/:id/deactivate | Desactivar | + +#### Entries +| Metodo | Endpoint | Descripcion | +|--------|----------|-------------| +| GET | /commissions/entries | Listar | +| GET | /commissions/entries/pending | Pendientes | +| GET | /commissions/entries/:id | Obtener | +| GET | /commissions/entries/user/:userId | Por usuario | +| GET | /commissions/entries/period/:periodId | Por periodo | +| POST | /commissions/entries/calculate | Calcular comision | +| POST | /commissions/entries/simulate | Simular (sin guardar) | +| PATCH | /commissions/entries/:id/status | Cambiar status | +| POST | /commissions/entries/bulk-approve | Aprobar multiples | +| POST | /commissions/entries/bulk-reject | Rechazar multiples | + +#### Periods +| Metodo | Endpoint | Descripcion | +|--------|----------|-------------| +| GET | /commissions/periods | Listar | +| GET | /commissions/periods/open | Periodo abierto | +| GET | /commissions/periods/:id | Obtener | +| GET | /commissions/periods/:id/summary | Resumen | +| POST | /commissions/periods | Crear | +| POST | /commissions/periods/:id/close | Cerrar | +| POST | /commissions/periods/:id/reopen | Reabrir | +| POST | /commissions/periods/:id/mark-paid | Marcar pagado | + +#### Dashboard +| Metodo | Endpoint | Descripcion | +|--------|----------|-------------| +| GET | /commissions/dashboard | Resumen general | +| GET | /commissions/dashboard/by-user | Por usuario | +| GET | /commissions/dashboard/by-period | Por periodo | +| GET | /commissions/dashboard/top-earners | Top ganadores | +| GET | /commissions/dashboard/me | Mis ganancias | +| GET | /commissions/dashboard/user/:userId | Ganancias de usuario | +| GET | /commissions/dashboard/scheme/:schemeId | Performance de esquema | + +--- + +## 4. Logica de Calculo + +### 4.1 Algoritmo de Calculo + +```typescript +async calculateCommission(dto: CalculateCommissionDto): Promise { + // 1. Obtener asignacion activa del usuario + const assignment = await this.getActiveAssignment(dto.userId); + + // 2. Obtener esquema + const scheme = await this.getScheme(assignment.schemeId); + + // 3. Verificar monto minimo + if (dto.amount < scheme.minAmount) { + throw new Error('Amount below minimum threshold'); + } + + // 4. Calcular tasa segun tipo + let rate: number; + switch (scheme.type) { + case 'percentage': + rate = assignment.customRate ?? scheme.rate; + break; + case 'fixed': + return this.createEntry({ + ...dto, + rateApplied: 0, + commissionAmount: scheme.fixedAmount + }); + case 'tiered': + rate = this.getTieredRate(scheme.tiers, dto.amount); + break; + } + + // 5. Calcular comision + let commissionAmount = dto.amount * (rate / 100); + + // 6. Aplicar cap si existe + if (scheme.maxAmount && commissionAmount > scheme.maxAmount) { + commissionAmount = scheme.maxAmount; + } + + // 7. Crear entrada + return this.createEntry({ + ...dto, + schemeId: scheme.id, + assignmentId: assignment.id, + rateApplied: rate, + commissionAmount + }); +} +``` + +### 4.2 Ejemplo Tiered + +``` +Tiers: [{from:0, to:1000, rate:5}, {from:1001, to:5000, rate:7}, {from:5001, to:null, rate:10}] +Venta: $3,500 + +Calculo: +- Primeros $1,000: $1,000 × 5% = $50 +- Siguientes $2,500: $2,500 × 7% = $175 +- Total comision: $225 +``` + +--- + +## 5. Frontend + +### 5.1 Paginas + +| Ruta | Componente | Estado | +|------|------------|--------| +| /dashboard/commissions | CommissionsDashboard | Pendiente | +| /dashboard/commissions/schemes | SchemesPage | Pendiente | +| /dashboard/commissions/entries | EntriesPage | Pendiente | +| /dashboard/commissions/periods | PeriodsPage | Pendiente | +| /dashboard/commissions/my-earnings | MyEarningsPage | Pendiente | + +### 5.2 Hooks + +```typescript +// frontend/src/hooks/useCommissions.ts +useSchemes, useScheme, useCreateScheme, useUpdateScheme, useDeleteScheme +useAssignments, useUserAssignments, useCreateAssignment +useEntries, usePendingEntries, useCalculateCommission, useUpdateEntryStatus +usePeriods, useOpenPeriod, useClosePeriod, useMarkPeriodPaid +useCommissionsDashboard, useMyEarnings, useTopEarners +``` + +--- + +## 6. Seguridad + +### 6.1 RLS + +```sql +CREATE POLICY schemes_tenant_isolation ON commissions.schemes + USING (tenant_id = current_setting('app.tenant_id')::uuid); + +CREATE POLICY entries_tenant_isolation ON commissions.entries + USING (tenant_id = current_setting('app.tenant_id')::uuid); +``` + +### 6.2 Permisos RBAC + +| Permiso | Descripcion | +|---------|-------------| +| commissions:read | Ver comisiones | +| commissions:write | Crear/editar esquemas | +| commissions:approve | Aprobar comisiones | +| commissions:pay | Marcar como pagadas | +| commissions:manage | Administrar todo | + +--- + +## 7. Integraciones + +| Modulo | Integracion | +|--------|-------------| +| sales | Trigger en OpportunityWon | +| goals | Tracking de metas de comision | +| mlm | Comisiones MLM | +| notifications | Alertas de aprobacion/pago | +| audit | Log de cambios | + +--- + +## 8. Referencias + +- DDL: `database/ddl/schemas/commissions/` +- Backend: `backend/src/modules/commissions/` +- Frontend: `frontend/src/services/commissions/` +- Hooks: `frontend/src/hooks/useCommissions.ts` diff --git a/docs/02-especificaciones/ET-SAAS-021-mlm.md b/docs/02-especificaciones/ET-SAAS-021-mlm.md new file mode 100644 index 00000000..fa8996b9 --- /dev/null +++ b/docs/02-especificaciones/ET-SAAS-021-mlm.md @@ -0,0 +1,434 @@ +--- +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 { + 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` diff --git a/docs/02-especificaciones/ET-SAAS-022-goals.md b/docs/02-especificaciones/ET-SAAS-022-goals.md new file mode 100644 index 00000000..68a2d82e --- /dev/null +++ b/docs/02-especificaciones/ET-SAAS-022-goals.md @@ -0,0 +1,399 @@ +--- +id: "ET-SAAS-022" +title: "Especificacion Tecnica Goals" +type: "TechnicalSpec" +status: "Implemented" +priority: "P1" +module: "goals" +version: "1.0.0" +created_date: "2026-02-03" +updated_date: "2026-02-03" +story_points: 8 +--- + +# ET-SAAS-022: Especificacion Tecnica - Sistema de Metas (Goals) + +## Metadata +- **Codigo:** ET-SAAS-022 +- **Modulo:** Goals +- **Version:** 1.0.0 +- **Estado:** Implementado (Backend) +- **Fecha:** 2026-02-03 +- **Basado en:** SAAS-022 + +--- + +## 1. Resumen Ejecutivo + +### 1.1 Estado Actual + +Sistema de metas con backend implementado, UI pendiente. + +| Capacidad | Estado | Notas | +|-----------|--------|-------| +| Definitions | SI | Definiciones de metas | +| Assignments | SI | Asignaciones usuario/team | +| Progress | SI | Tracking de progreso | +| Milestones | SI | Hitos con notificaciones | +| Auto-tracking | SI | Fuentes automaticas | +| RLS | SI | Row Level Security | +| UI | NO | Frontend pendiente | + +### 1.2 Funcionalidades v1.0 + +Sistema completo con: + +- **4 Entidades**: Definitions, Assignments, ProgressLog, MilestoneNotifications +- **3 Tipos de meta**: target, limit, maintain +- **5 Tipos de metrica**: number, currency, percentage, boolean, count +- **6 Periodos**: daily, weekly, monthly, quarterly, yearly, custom +- **Auto-tracking**: Integracion con sales, billing, commissions + +--- + +## 2. Modelo de Datos + +### 2.1 Schema: goals + +#### Tabla: definitions +| Campo | Tipo | Descripcion | +|-------|------|-------------| +| id | UUID | PK | +| tenant_id | UUID | FK tenants | +| name | VARCHAR(200) | Nombre de la meta | +| description | TEXT | Descripcion | +| category | VARCHAR(100) | Categoria | +| type | ENUM | target, limit, maintain | +| metric | ENUM | number, currency, percentage, boolean, count | +| target_value | DECIMAL(15,2) | Valor objetivo | +| unit | VARCHAR(50) | USD, units, %, etc. | +| period | ENUM | daily, weekly, monthly, quarterly, yearly, custom | +| starts_at | DATE | Fecha inicio | +| ends_at | DATE | Fecha fin | +| source | ENUM | manual, sales, billing, commissions, custom | +| source_config | JSONB | Configuracion de fuente | +| milestones | JSONB | Hitos de progreso | +| status | ENUM | draft, active, paused, completed, cancelled | +| tags | JSONB | Array de tags | + +**Source Config ejemplo:** +```json +{ + "module": "sales", + "entity": "opportunities", + "filter": {"stage": "closed_won"}, + "aggregation": "sum", + "field": "amount" +} +``` + +**Milestones ejemplo:** +```json +[ + {"percentage": 25, "notify": true}, + {"percentage": 50, "notify": true}, + {"percentage": 75, "notify": true}, + {"percentage": 100, "notify": true} +] +``` + +#### Tabla: assignments +| Campo | Tipo | Descripcion | +|-------|------|-------------| +| id | UUID | PK | +| tenant_id | UUID | FK tenants | +| definition_id | UUID | FK definitions | +| assignee_type | ENUM | user, team, tenant | +| user_id | UUID | FK users (si type=user) | +| team_id | UUID | Para futuro modulo de equipos | +| custom_target | DECIMAL(15,2) | Override del target | +| current_value | DECIMAL(15,2) | Valor actual | +| progress_percentage | DECIMAL(5,2) | 0-100% | +| last_updated_at | TIMESTAMPTZ | Ultima actualizacion | +| status | ENUM | active, achieved, failed, cancelled | +| achieved_at | TIMESTAMPTZ | Fecha de logro | +| notes | TEXT | Notas | + +#### Tabla: progress_log +| Campo | Tipo | Descripcion | +|-------|------|-------------| +| id | UUID | PK | +| tenant_id | UUID | FK tenants | +| assignment_id | UUID | FK assignments | +| previous_value | DECIMAL(15,2) | Valor anterior | +| new_value | DECIMAL(15,2) | Nuevo valor | +| change_amount | DECIMAL(15,2) | Diferencia | +| source | ENUM | manual, automatic, import, api | +| source_reference | VARCHAR(200) | ID de transaccion origen | +| notes | TEXT | Notas | +| logged_at | TIMESTAMPTZ | Fecha del log | +| logged_by | UUID | FK users | + +#### Tabla: milestone_notifications +| Campo | Tipo | Descripcion | +|-------|------|-------------| +| id | UUID | PK | +| tenant_id | UUID | FK tenants | +| assignment_id | UUID | FK assignments | +| milestone_percentage | INT | % del hito alcanzado | +| achieved_value | DECIMAL(15,2) | Valor al alcanzar | +| notified_at | TIMESTAMPTZ | Fecha de notificacion | + +### 2.2 Enums + +```sql +goals.goal_type: target, limit, maintain +goals.metric_type: number, currency, percentage, boolean, count +goals.period_type: daily, weekly, monthly, quarterly, yearly, custom +goals.data_source: manual, sales, billing, commissions, custom +goals.goal_status: draft, active, paused, completed, cancelled +goals.assignee_type: user, team, tenant +goals.assignment_status: active, achieved, failed, cancelled +goals.progress_source: manual, automatic, import, api +``` + +--- + +## 3. Tipos de Meta + +### 3.1 Target (Alcanzar objetivo) +- **Descripcion**: Alcanzar un valor especifico +- **Ejemplo**: "Vender $50,000 este mes" +- **Logro**: current_value >= target_value + +### 3.2 Limit (No exceder) +- **Descripcion**: No superar un limite +- **Ejemplo**: "Mantener gastos bajo $10,000" +- **Logro**: current_value <= target_value durante todo el periodo + +### 3.3 Maintain (Mantener valor) +- **Descripcion**: Mantener un valor constante +- **Ejemplo**: "Mantener NPS >= 8.5" +- **Logro**: current_value dentro de rango durante todo el periodo + +--- + +## 4. Arquitectura Backend + +### 4.1 Estructura de Archivos + +``` +backend/src/modules/goals/ +├── goals.module.ts +├── controllers/ +│ ├── definitions.controller.ts +│ ├── assignments.controller.ts +│ ├── progress.controller.ts +│ └── dashboard.controller.ts +├── services/ +│ ├── definitions.service.ts +│ ├── assignments.service.ts +│ ├── progress.service.ts +│ ├── tracking.service.ts +│ └── dashboard.service.ts +├── entities/ +│ ├── definition.entity.ts +│ ├── assignment.entity.ts +│ ├── progress-log.entity.ts +│ └── milestone-notification.entity.ts +└── dto/ +``` + +### 4.2 Endpoints API + +#### Definitions +| Metodo | Endpoint | Descripcion | +|--------|----------|-------------| +| GET | /goals/definitions | Listar | +| GET | /goals/definitions/:id | Obtener | +| POST | /goals/definitions | Crear | +| PUT | /goals/definitions/:id | Actualizar | +| PATCH | /goals/definitions/:id/status | Cambiar status | +| DELETE | /goals/definitions/:id | Eliminar | +| POST | /goals/definitions/:id/duplicate | Duplicar | + +#### Assignments +| Metodo | Endpoint | Descripcion | +|--------|----------|-------------| +| GET | /goals/assignments | Listar | +| GET | /goals/assignments/:id | Obtener | +| GET | /goals/assignments/user/:userId | Por usuario | +| GET | /goals/assignments/definition/:defId | Por definicion | +| POST | /goals/assignments | Crear | +| PUT | /goals/assignments/:id | Actualizar | +| DELETE | /goals/assignments/:id | Eliminar | + +#### Progress +| Metodo | Endpoint | Descripcion | +|--------|----------|-------------| +| GET | /goals/progress/:assignmentId | Historial | +| POST | /goals/progress | Registrar progreso | +| POST | /goals/progress/bulk | Registrar multiples | + +#### Dashboard +| Metodo | Endpoint | Descripcion | +|--------|----------|-------------| +| GET | /goals/dashboard | Resumen general | +| GET | /goals/dashboard/my | Mis metas | +| GET | /goals/dashboard/team/:teamId | Metas del equipo | +| GET | /goals/dashboard/user/:userId | Metas de usuario | +| GET | /goals/dashboard/achieved | Metas logradas | +| GET | /goals/dashboard/at-risk | Metas en riesgo | + +--- + +## 5. Auto-Tracking + +### 5.1 Configuracion de Fuentes + +```typescript +interface SourceConfig { + module: 'sales' | 'billing' | 'commissions'; + entity: string; // 'opportunities', 'invoices', etc. + filter?: Record; // Filtros adicionales + aggregation: 'sum' | 'count' | 'avg' | 'min' | 'max'; + field?: string; // Campo para sum/avg +} +``` + +### 5.2 Ejemplo: Meta de Ventas + +```json +{ + "name": "Ventas Q1 2026", + "type": "target", + "metric": "currency", + "target_value": 100000, + "unit": "USD", + "source": "sales", + "source_config": { + "module": "sales", + "entity": "opportunities", + "filter": {"stage": "closed_won"}, + "aggregation": "sum", + "field": "amount" + } +} +``` + +### 5.3 Flujo de Actualizacion + +```typescript +// Listener para eventos de ventas +@OnEvent('opportunity.won') +async handleOpportunityWon(event: OpportunityWonEvent) { + // 1. Buscar metas con source_config que matchee + const goals = await this.findMatchingGoals({ + module: 'sales', + entity: 'opportunities', + userId: event.opportunity.assignedTo + }); + + // 2. Para cada meta, actualizar progreso + for (const assignment of goals) { + await this.updateProgress(assignment.id, { + changeAmount: event.opportunity.amount, + source: 'automatic', + sourceReference: event.opportunity.id + }); + } +} +``` + +--- + +## 6. Frontend (Pendiente) + +### 6.1 Paginas Propuestas + +| Ruta | Componente | Estado | +|------|------------|--------| +| /dashboard/goals | GoalsDashboard | Pendiente | +| /dashboard/goals/my | MyGoalsPage | Pendiente | +| /dashboard/goals/definitions | DefinitionsPage | Pendiente | +| /dashboard/goals/new | GoalFormPage | Pendiente | +| /dashboard/goals/:id | GoalDetailPage | Pendiente | + +### 6.2 Hooks Existentes + +```typescript +// frontend/src/hooks/useGoals.ts +useDefinitions, useDefinition, useCreateDefinition, useUpdateDefinition +useAssignments, useMyAssignments, useUserAssignments +useAssignmentProgress, useUpdateProgress +useGoalsDashboard, useAchievedGoals, useAtRiskGoals +``` + +--- + +## 7. Seguridad + +### 7.1 RLS + +```sql +CREATE POLICY definitions_tenant_isolation ON goals.definitions + USING (tenant_id = current_setting('app.tenant_id')::uuid); + +CREATE POLICY assignments_tenant_isolation ON goals.assignments + USING (tenant_id = current_setting('app.tenant_id')::uuid); +``` + +### 7.2 Permisos RBAC + +| Permiso | Descripcion | +|---------|-------------| +| goals:read | Ver metas | +| goals:write | Crear/editar metas | +| goals:assign | Asignar metas | +| goals:progress | Actualizar progreso | +| goals:manage | Administrar | + +--- + +## 8. Notificaciones + +### 8.1 Eventos de Notificacion + +| Evento | Trigger | Destinatario | +|--------|---------|--------------| +| goal.milestone_reached | Alcanzar % | Usuario asignado | +| goal.achieved | 100% completado | Usuario + Manager | +| goal.at_risk | <50% y queda poco tiempo | Manager | +| goal.failed | Periodo terminado sin lograr | Manager | + +### 8.2 Ejemplo de Notificacion + +```typescript +interface MilestoneNotification { + type: 'goal.milestone_reached'; + userId: string; + data: { + goalName: string; + milestone: 50; // percentage + currentValue: 25000; + targetValue: 50000; + remainingDays: 15; + }; +} +``` + +--- + +## 9. Integraciones + +| Modulo | Integracion | +|--------|-------------| +| sales | Tracking automatico | +| billing | Tracking de ingresos | +| commissions | Metas de comision | +| notifications | Alertas de hitos | +| audit | Log de cambios | + +--- + +## 10. Referencias + +- DDL: `database/ddl/schemas/goals/` +- Backend: `backend/src/modules/goals/` +- Frontend Services: `frontend/src/services/goals/` +- Frontend Hooks: `frontend/src/hooks/useGoals.ts` diff --git a/docs/02-especificaciones/_MAP.md b/docs/02-especificaciones/_MAP.md index 0796ff41..7e6b29e5 100644 --- a/docs/02-especificaciones/_MAP.md +++ b/docs/02-especificaciones/_MAP.md @@ -4,9 +4,9 @@ title: "Mapa Especificaciones" type: "Index" status: "Published" priority: "P2" -version: "1.0.0" +version: "2.0.0" created_date: "2026-01-10" -updated_date: "2026-01-10" +updated_date: "2026-02-03" --- # _MAP: Especificaciones Tecnicas @@ -14,8 +14,8 @@ updated_date: "2026-01-10" **Carpeta:** docs/02-especificaciones/ **Proposito:** Especificaciones tecnicas detalladas **Estado:** Actualizado -**Sistema:** SIMCO v3.7 -**Ultima actualizacion:** 2026-01-10 +**Sistema:** SIMCO v4.0 +**Ultima actualizacion:** 2026-02-03 --- @@ -23,27 +23,52 @@ updated_date: "2026-01-10" | Metrica | Valor | |---------|-------| -| Total especificaciones | 1 | -| Completadas | 1 | +| Total especificaciones | 9 | +| Implementadas | 9 | --- ## Contenido -| Archivo | Tipo | Estado | Descripcion | -|---------|------|--------|-------------| -| ET-001-file-storage.md | Especificacion Tecnica | Completado | Sistema de almacenamiento de archivos | +| Archivo | Modulo | Estado | Descripcion | +|---------|--------|--------|-------------| +| ET-SAAS-007-notifications-v2.md | notifications | Implementado | Sistema de notificaciones multi-canal | +| ET-SAAS-015-oauth.md | auth | Implementado | Autenticacion OAuth 2.0 | +| ET-SAAS-016-analytics.md | analytics | Implementado | Sistema de analiticas | +| ET-SAAS-017-reports.md | reports | Implementado | Generacion de reportes | +| ET-SAAS-018-sales.md | sales | Implementado | Pipeline de ventas CRM | +| ET-SAAS-019-portfolio.md | portfolio | Implementado | Catalogo de productos | +| ET-SAAS-020-commissions.md | commissions | Implementado | Sistema de comisiones | +| ET-SAAS-021-mlm.md | mlm | Implementado | Multi-Level Marketing | +| ET-SAAS-022-goals.md | goals | Implementado | Sistema de metas | --- ## Estructura de Especificaciones -Las especificaciones tecnicas siguen el formato ET-NNN y documentan: -- Requisitos tecnicos detallados -- Diagramas de arquitectura -- Flujos de datos -- Consideraciones de rendimiento +Las especificaciones tecnicas siguen el formato ET-SAAS-NNN y documentan: + +1. **Resumen Ejecutivo** - Estado actual y propuesta +2. **Modelo de Datos** - Tablas, campos, enums +3. **Arquitectura Backend** - Modulos, endpoints, servicios +4. **Seguridad** - RLS, RBAC, permisos +5. **Frontend** - Paginas, hooks, componentes +6. **Integraciones** - Modulos relacionados +7. **Referencias** - Rutas a codigo fuente --- -**Mantenido por:** Orchestration Team +## Leyenda de Estado + +| Estado | Descripcion | +|--------|-------------| +| Draft | En borrador | +| Proposed | Propuesto para revision | +| Approved | Aprobado, pendiente implementacion | +| Implemented | Implementado en codigo | +| Deprecated | Obsoleto | + +--- + +**Mantenido por:** Claude Opus 4.5 +**Ultima actualizacion:** 2026-02-03