workspace-v1/projects/gamilit/docs/01-fase-alcance-inicial/EAI-003-gamificacion/requerimientos/RF-GAM-004-economia-ml-coins.md
Adrian Flores Cortes 967ab360bb Initial commit: Workspace v1 with 3-layer architecture
Structure:
- control-plane/: Registries, SIMCO directives, CI/CD templates
- projects/: Gamilit, ERP-Suite, Trading-Platform, Betting-Analytics
- shared/: Libs catalog, knowledge-base

Key features:
- Centralized port, domain, database, and service registries
- 23 SIMCO directives + 6 fundamental principles
- NEXUS agent profiles with delegation rules
- Validation scripts for workspace integrity
- Dockerfiles for all services
- Path aliases for quick reference

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-23 00:35:19 -06:00

23 KiB

RF-GAM-004: Economía de ML Coins (Maya Learning Coins)

📋 Metadata

Campo Valor
ID RF-GAM-004
Módulo 02 - Gamificación
Título Economía de ML Coins (Maya Learning Coins)
Prioridad Alta
Estado Implementado
Versión 2.1 (DB-099: tenant_id support)
Fecha Creación 2025-11-08
Última Actualización 2025-11-11 (DB-099)
Autor Database Team
Stakeholders Product Owner, UX Team, Backend Team, Frontend Team, Game Designer

🔗 Referencias

Implementación DDL

🗄️ Tablas Relacionadas:

  1. gamification_system.user_stats

    • Ubicación: apps/database/ddl/schemas/gamification_system/tables/user_stats.sql
    • Propósito: Almacena balance actual de ML Coins y totales históricos
    • Columnas clave:
      • ml_coins (INTEGER): Balance actual de ML Coins
      • ml_coins_earned_total (INTEGER): Total histórico ganado
      • ml_coins_spent_total (INTEGER): Total histórico gastado
  2. gamification_system.ml_coins_transactions

    • Ubicación: apps/database/ddl/schemas/gamification_system/tables/05-ml_coins_transactions.sql
    • Propósito: Registro completo de todas las transacciones de ML Coins
    • Columnas clave:
      • id (UUID): ID único de transacción
      • user_id (UUID): Usuario que realiza la transacción
      • tenant_id (UUID): NUEVO DB-099 - ID del tenant (multi-tenancy support)
      • amount (INTEGER): Monto de la transacción (con multiplicador aplicado)
      • balance_before (INTEGER): Balance antes de la transacción
      • balance_after (INTEGER): Balance después de la transacción
      • transaction_type (ENUM): Tipo de transacción (14 tipos)
      • multiplier (NUMERIC): Multiplicador aplicado (ej: 1.25x por rango)
      • metadata (JSONB): Información adicional (base_amount, rank, etc.)
      • created_at (TIMESTAMPTZ): Timestamp de la transacción

🗄️ ENUM Canónico:

  • Ubicación: apps/database/ddl/schemas/gamification_system/enums/transaction_type.sql
  • Tipo: gamification_system.transaction_type
  • Valores: 14 tipos (7 earned, 3 spent, 4 admin)

🗄️ Funciones SQL:

  1. award_ml_coins(user_id, amount, transaction_type, description, reference_id, reference_type)
    • Ubicación: apps/database/ddl/schemas/gamification_system/functions/award_ml_coins.sql
    • Propósito: Otorgar ML Coins al usuario aplicando multiplicador de rango
    • Validaciones:
      • Obtiene rango actual del usuario
      • Aplica multiplicador según rango Maya (1.00x - 2.00x)
      • Actualiza balance con FOR UPDATE (previene race conditions)
      • Registra transacción con metadata completa

Especificación Técnica

📘 Documento ET Relacionado:

Documentos Relacionados


📖 Descripción General

Propósito

El sistema de ML Coins (Maya Learning Coins) es la moneda virtual principal de la plataforma Gamilit. Proporciona:

  • Motivación económica: Los estudiantes ganan coins por actividades de aprendizaje
  • Sistema de recompensas: Progresión tangible y medible
  • Economía de recursos escasos: Decisiones estratégicas sobre cómo gastar coins
  • Gamificación profunda: Feedback inmediato por logros

Contexto

Los ML Coins son el núcleo del sistema de gamificación de Gamilit:

  1. Se ganan completando ejercicios, módulos, achievements, rachas, etc.
  2. Se multiplican según el rango Maya del usuario (1.00x - 2.00x)
  3. Se gastan en comodines (power-ups), pistas, reintentos
  4. Se rastrean con historial completo de transacciones

🎯 Objetivos del Sistema

Objetivos Primarios

  1. Incentivar el aprendizaje activo

    • Recompensar inmediatamente actividades educativas
    • Crear ciclo de feedback positivo
    • Motivar a completar contenido
  2. Promover progresión y maestría

    • Mayores recompensas por contenido difícil
    • Multiplicadores por rango premian veteranos
    • Balance entre nuevos y experimentados
  3. Habilitar toma de decisiones estratégicas

    • Recursos escasos requieren planificación
    • Decisión: ¿guardar o gastar?
    • Enseña administración de recursos

Objetivos Secundarios

  1. Crear economía sostenible

    • Balance entre earning y spending
    • Prevenir inflación de coins
    • Evitar acumulación excesiva
  2. Facilitar análisis y métricas

    • Trackear engagement por tipo de actividad
    • Identificar usuarios en riesgo
    • Optimizar recompensas basado en datos

📊 Flujos de ML Coins

1. Earning (Ganancia de Coins)

1.1 Por Actividad Educativa

Ejercicios Completados (earned_exercise)

  • Monto base: 5-50 ML Coins (según dificultad)
  • Multiplicador: Según rango Maya (1.00x - 2.00x)
  • Trigger: Al completar ejercicio exitosamente
  • Ejemplo:
    • Estudiante Ajaw (1.00x) completa ejercicio medio (20 coins)
    • Recibe: 20 * 1.00 = 20 ML Coins
    • Estudiante K'uk'ulkan (2.00x) completa mismo ejercicio
    • Recibe: 20 * 2.00 = 40 ML Coins

Módulos Completados (earned_module)

  • Monto base: 100-300 ML Coins (según módulo)
  • Multiplicador: Según rango Maya
  • Trigger: Al completar 100% de ejercicios del módulo
  • Ejemplo:
    • Módulo "Comprensión Literal" = 150 coins base
    • Nacom (1.25x): 150 * 1.25 = 188 ML Coins

Achievements Desbloqueados (earned_achievement)

  • Monto base: 50-500 ML Coins (según rareza)
    • Común: 50 coins
    • Raro: 100 coins
    • Épico: 250 coins
    • Legendario: 500 coins
  • Multiplicador: Según rango Maya
  • Trigger: Al cumplir condiciones del achievement

1.2 Por Progresión y Engagement

Subida de Rango (earned_rank)

  • Monto: 100-1000 ML Coins (según rango alcanzado) IMPLEMENTADO
    • Ajaw → Nacom: 100 coins (al alcanzar 500 XP)
    • Nacom → Ah K'in: 250 coins (al alcanzar 1,000 XP)
    • Ah K'in → Halach Uinic: 500 coins (al alcanzar 1,500 XP)
    • Halach Uinic → K'uk'ulkan: 1,000 coins (al alcanzar 2,250 XP)
  • Multiplicador: NO aplica (recompensa fija)
  • Trigger: Al alcanzar XP requerido para nuevo rango

Racha de Días (earned_streak)

  • Monto: 10-100 ML Coins (según días consecutivos)
    • 3 días: 10 coins
    • 7 días: 25 coins
    • 14 días: 50 coins
    • 30 días: 100 coins
  • Multiplicador: Según rango Maya
  • Trigger: Al mantener racha activa

Login Diario (earned_daily)

  • Monto: 50 ML Coins
  • Multiplicador: Según rango Maya
  • Trigger: Primer login del día
  • Límite: 1 vez por día

Bonus Especial (earned_bonus)

  • Monto: Variable (definido por evento)
  • Multiplicador: Según rango Maya
  • Trigger: Eventos especiales, promociones, desafíos
  • Ejemplo: "Semana de la Lectura" +200 coins por completar módulo

2. Spending (Gasto de Coins)

2.1 Comodines (Power-ups)

Pistas Contextuales (spent_powerup - pistas)

  • Costo: -15 ML Coins
  • Beneficio: Muestra 2-3 pistas sobre respuesta correcta
  • Límite: 3 por ejercicio
  • Uso estratégico: Para ejercicios difíciles sin perder intento

Visión Lectora (spent_powerup - vision_lectora)

  • Costo: -25 ML Coins
  • Beneficio: Resalta pasajes clave del texto
  • Límite: 1 por ejercicio
  • Uso estratégico: Para textos largos y complejos

Segunda Oportunidad (spent_powerup - segunda_oportunidad)

  • Costo: -40 ML Coins
  • Beneficio: Permite reintento sin penalización de XP
  • Límite: 1 por ejercicio
  • Uso estratégico: Para ejercicios críticos

2.2 Ayudas Adicionales

Pista Simple (spent_hint)

  • Costo: -10 ML Coins
  • Beneficio: Pista contextual individual
  • Límite: Ilimitado (costoso)

Reintento de Ejercicio (spent_retry)

  • Costo: -20 ML Coins
  • Beneficio: Reiniciar ejercicio fallado
  • Límite: Ilimitado

3. Administrativo y Sistema

Ajuste Manual (admin_adjustment)

  • Monto: Variable (+ o -)
  • Propósito: Correcciones, compensaciones, regalos
  • Autorización: Solo administradores
  • Ejemplo: Compensar bug que afectó a usuarios

Reembolso (refund)

  • Monto: Positivo (devolución)
  • Propósito: Devolver coins por compra errónea o bug
  • Trigger: Solicitud de usuario o detección automática

Bonus General (bonus)

  • Monto: Positivo
  • Propósito: Bonos del sistema no categorizados
  • Ejemplo: Recompensa por participar en beta testing

Bonus de Bienvenida (welcome_bonus)

  • Monto: +100 ML Coins
  • Propósito: Dar capital inicial a nuevos usuarios
  • Trigger: Registro de nueva cuenta (una sola vez)

🔢 Economía y Balance

Multiplicadores por Rango Maya

⚠️ NOTA IMPORTANTE (2025-11-19): Los multiplicadores ML Coins descritos aquí están PENDIENTES DE IMPLEMENTACIÓN.

Rango Nivel Multiplicador ML Coins (Documentado) Multiplicador XP (Implementado) Estado
Ajaw 1 1.00x 1.00x XP: Implementado
Nacom 2 1.25x (+25%) 1.10x (+10%) ML: No implementado
Ah K'in 3 1.50x (+50%) 1.15x (+15%) ML: No implementado
Halach Uinic 4 1.75x (+75%) 1.20x (+20%) ML: No implementado
K'uk'ulkan 5 2.00x (+100%) 1.25x (+25%) ML: No implementado

Estado Actual:

  • Multiplicadores XP: Implementados y funcionales (1.00x - 1.25x)
  • Multiplicadores ML Coins: Documentados pero NO implementados en DB v2.0
  • Bonus ML Coins (único por promoción): Implementados (100-1000 ML)

Funcionalidad NO Implementada:

-- ❌ Esta columna NO existe en la tabla maya_ranks:
ml_coins_multiplier NUMERIC(3,2)

-- ✅ Lo que SÍ existe:
ml_coins_bonus INTEGER  -- Bonus único al promover
xp_multiplier NUMERIC(3,2)  -- Multiplicador XP

Decisión Pendiente: Product Owner debe decidir si implementar multiplicadores ML Coins o simplificar economía manteniendo solo bonus únicos.

Ver:

Earning vs Spending Estimado

Earning Típico (Usuario Activo - Ajaw 1.00x):

  • 10 ejercicios/día: 10 * 20 = 200 coins
  • 1 módulo/semana: 150 coins
  • 1 achievement/semana: 100 coins
  • Login diario: 50 coins
  • Total semanal: ~1,300 ML Coins

Spending Típico:

  • 3 pistas/semana: 3 * 15 = 45 coins
  • 1 visión lectora/semana: 25 coins
  • 1 segunda oportunidad/semana: 40 coins
  • Total semanal: ~110 ML Coins

Balance: +1,190 ML Coins/semana (positivo, permite acumulación)

Objetivo: Usuarios deben poder acumular coins pero sentir que son valiosos (no triviales).


📐 Reglas de Negocio

Regla 1: No Negativos

Descripción: El balance de ML Coins de un usuario nunca puede ser negativo.

Implementación:

  • CHECK constraint en tabla user_stats: ml_coins >= 0
  • Validación en función spend_ml_coins() antes de restar
  • Frontend previene compra si balance insuficiente

Ejemplo:

Usuario tiene: 25 ML Coins
Quiere comprar: Segunda Oportunidad (40 coins)
Resultado: ❌ Transacción rechazada "Balance insuficiente"

Regla 2: Multiplicador se Aplica Solo a Earning

Descripción: El multiplicador de rango Maya se aplica solo a coins ganados, no a gastos.

Implementación:

  • Función award_ml_coins() aplica multiplicador
  • Función spend_ml_coins() usa monto exacto (sin multiplicador)

Ejemplo:

K'uk'ulkan (2.00x) gana 100 coins → Recibe 200 coins
K'uk'ulkan gasta en pista (15 coins) → Paga exactamente 15 coins

Regla 3: Transacciones Atómicas

Descripción: Cada transacción de ML Coins debe ser atómica (todo o nada).

Implementación:

  • Uso de FOR UPDATE para bloquear fila durante transacción
  • Rollback automático si falla cualquier paso
  • Registro de transacción solo si update exitoso

Regla 4: Auditoría Completa

Descripción: Todas las transacciones deben quedar registradas permanentemente.

Implementación:

  • Tabla ml_coins_transactions sin DELETE
  • Metadata JSONB con detalles (base_amount, rank, multiplier)
  • Columnas balance_before y balance_after para auditoría

Regla 5: Redondeo hacia Abajo

Descripción: Montos con decimales se redondean hacia abajo (FLOOR).

Implementación:

v_final_amount := FLOOR(p_amount * v_multiplier);

Ejemplo:

Base: 33 coins
Multiplicador Nacom: 1.25x
Cálculo: 33 * 1.25 = 41.25
Resultado: FLOOR(41.25) = 41 coins

🎮 Casos de Uso

Caso de Uso 1: Estudiante Completa Ejercicio

Actor: Estudiante (usuario autenticado)

Precondiciones:

  • Usuario tiene cuenta activa
  • Usuario tiene rango Maya asignado
  • Ejercicio disponible y no completado previamente

Flujo Principal:

  1. Usuario resuelve ejercicio correctamente
  2. Sistema obtiene rango Maya del usuario
  3. Sistema calcula monto base según dificultad del ejercicio
  4. Sistema aplica multiplicador de rango
  5. Sistema llama award_ml_coins()
  6. Se actualiza balance en user_stats
  7. Se registra transacción en ml_coins_transactions
  8. Frontend muestra notificación: "+20 ML Coins 🪙"

Postcondiciones:

  • Balance de ML Coins incrementado
  • Transacción registrada con tipo earned_exercise
  • Totales históricos actualizados

Caso de Uso 2: Estudiante Compra Comodín

Actor: Estudiante

Precondiciones:

  • Usuario tiene balance suficiente de ML Coins
  • Comodín disponible para compra

Flujo Principal:

  1. Usuario hace clic en "Comprar Pistas (15 coins)"
  2. Frontend verifica balance >= 15
  3. Sistema llama purchase_comodin(user_id, 'pistas', quantity)
  4. Función SQL:
    • Verifica balance con FOR UPDATE
    • Resta 15 ML Coins del balance
    • Incrementa inventario de comodines
    • Registra transacción tipo spent_powerup
  5. Frontend actualiza UI con nuevo balance e inventario

Flujo Alternativo: Balance insuficiente

  1. Frontend muestra error: "ML Coins insuficientes. Necesitas 15, tienes 10"
  2. Sugerencia: "Completa más ejercicios para ganar ML Coins"

Caso de Uso 3: Usuario Sube de Rango

Actor: Sistema (automático)

Precondiciones:

  • Usuario alcanzó XP requerido para nuevo rango

Flujo Principal:

  1. Función check_rank_promotion() detecta promoción
  2. Sistema actualiza user_ranks con nuevo rango
  3. Sistema otorga bonus de rango:
    award_ml_coins(user_id, 250, 'earned_rank', 'Promoción a Ah K''in')
    
  4. Se registra transacción (sin multiplicador - monto fijo)
  5. Frontend muestra celebración: "¡Felicidades! +250 ML Coins por alcanzar Ah K'in"

📊 Métricas y KPIs

Métricas de Usuario

  1. Balance Actual

    • Columna: user_stats.ml_coins
    • Propósito: Mostrar en UI, validar compras
  2. Total Ganado Histórico

    • Columna: user_stats.ml_coins_earned_total
    • Propósito: Leaderboards, achievements
  3. Total Gastado Histórico

    • Columna: user_stats.ml_coins_spent_total
    • Propósito: Análisis de engagement, patrones de gasto

Métricas del Sistema

  1. ML Coins en Circulación

    SELECT SUM(ml_coins) FROM gamification_system.user_stats;
    
    • Propósito: Monitorear inflación, salud económica
  2. Earning por Tipo de Transacción

    SELECT transaction_type, SUM(amount)
    FROM ml_coins_transactions
    WHERE transaction_type LIKE 'earned_%'
    GROUP BY transaction_type;
    
    • Propósito: Identificar fuentes principales de coins
  3. Spending por Tipo

    SELECT transaction_type, SUM(ABS(amount))
    FROM ml_coins_transactions
    WHERE transaction_type LIKE 'spent_%'
    GROUP BY transaction_type;
    
    • Propósito: Entender cómo usuarios gastan coins
  4. Ratio Earning/Spending

    SELECT
      SUM(CASE WHEN amount > 0 THEN amount ELSE 0 END) as total_earned,
      SUM(CASE WHEN amount < 0 THEN ABS(amount) ELSE 0 END) as total_spent,
      (SUM(CASE WHEN amount > 0 THEN amount ELSE 0 END)::FLOAT /
       NULLIF(SUM(CASE WHEN amount < 0 THEN ABS(amount) ELSE 0 END), 0)) as ratio
    FROM ml_coins_transactions;
    
    • Target: Ratio ~5-10x (usuarios ganan mucho más de lo que gastan)
    • Alert: Si ratio < 3x → usuarios gastando demasiado
    • Alert: Si ratio > 20x → coins no tienen valor percibido

🔒 Seguridad y Prevención de Fraude

1. Race Conditions

Problema: Dos transacciones simultáneas pueden causar balance incorrecto.

Solución: Row-level locking con FOR UPDATE

SELECT ml_coins INTO v_current_balance
FROM gamification_system.user_stats
WHERE user_id = p_user_id
FOR UPDATE;

2. Balance Negativo

Problema: Bugs o exploits podrían permitir balance negativo.

Solución:

  • CHECK constraint: ml_coins >= 0
  • Validación en aplicación antes de gastar
  • Transacción atómica (rollback si falla)

3. Duplicación de Recompensas

Problema: Usuario podría reclamar misma recompensa múltiples veces.

Solución:

  • Idempotency keys en reference_id
  • Validación de ejercicio ya completado
  • Achievement solo se otorga una vez (validación en trigger)

4. Admin Abuse

Problema: Admin malintencionado otorga coins ilimitados.

Solución:

  • Audit logging en ml_coins_transactions
  • Alertas automáticas para transacciones admin > 1000 coins
  • Revisión periódica de transacciones tipo admin_adjustment

🧪 Casos de Prueba

Test 1: Award con Multiplicador Ajaw (1.00x)

Input:

award_ml_coins(
  user_id = 'test-user-1',
  amount = 100,
  transaction_type = 'earned_exercise',
  description = 'Test'
);

Condiciones:

  • Usuario tiene rango Ajaw (1.00x)
  • Balance inicial: 0

Output Esperado:

  • Balance final: 100 ML Coins
  • ml_coins_earned_total: 100
  • Transacción registrada con amount = 100, multiplier = 1.00

Test 2: Award con Multiplicador K'uk'ulkan (2.00x)

Input:

award_ml_coins(
  user_id = 'test-user-2',
  amount = 100,
  transaction_type = 'earned_module',
  description = 'Test'
);

Condiciones:

  • Usuario tiene rango K'uk'ulkan (2.00x)
  • Balance inicial: 50

Output Esperado:

  • Balance final: 50 + 200 = 250 ML Coins
  • ml_coins_earned_total: 200
  • Transacción con amount = 200, multiplier = 2.00
  • Metadata JSONB: { "base_amount": 100, "rank": "K'uk'ulkan", "multiplier": 2.00, "final_amount": 200 }

Test 3: Spend - Balance Suficiente

Input:

spend_ml_coins(
  user_id = 'test-user-3',
  amount = 15,
  transaction_type = 'spent_hint',
  description = 'Compra de pista'
);

Condiciones:

  • Balance inicial: 100

Output Esperado:

  • Balance final: 85 ML Coins
  • ml_coins_spent_total: 15
  • Transacción con amount = -15 (negativo)

Test 4: Spend - Balance Insuficiente

Input:

spend_ml_coins(
  user_id = 'test-user-4',
  amount = 50,
  transaction_type = 'spent_powerup',
  description = 'Compra de comodín'
);

Condiciones:

  • Balance inicial: 20

Output Esperado:

  • Error: "Insufficient ML Coins balance"
  • Balance sin cambios: 20
  • No se crea transacción

📚 Referencias Técnicas

Base de Datos

  • Tabla principal: gamification_system.user_stats
  • Tabla de transacciones: gamification_system.ml_coins_transactions
  • ENUM: gamification_system.transaction_type
  • Función de award: gamification_system.award_ml_coins()
  • Tests: apps/database/ddl/schemas/gamification_system/functions/tests/test_award_ml_coins.sql

Backend (NestJS)

  • Service: apps/backend/src/modules/gamification/services/ml-coins.service.ts
  • Entity: apps/backend/src/modules/gamification/entities/ml-coins-transaction.entity.ts
  • Controller: apps/backend/src/modules/gamification/controllers/ml-coins.controller.ts
  • DTOs: apps/backend/src/modules/gamification/dto/ml-coins/

Frontend (React)

  • Store: apps/frontend/src/features/gamification/economy/store/economyStore.ts
  • Components: apps/frontend/src/features/gamification/economy/components/
  • Hooks: apps/frontend/src/features/gamification/economy/hooks/useTransactions.ts
  • API: apps/frontend/src/features/gamification/api/gamificationAPI.ts

🔄 Versionado

Versión 2.0 (2025-11-08) - ACTUAL

Cambios:

  • Migrado transaction_type de 10 valores legacy a 14 valores oficiales
  • Agregados: earned_module, earned_streak, earned_daily, earned_bonus, spent_powerup, spent_retry, bonus, welcome_bonus
  • Consolidado multiplicadores de rango Maya (1.00x - 2.00x)
  • Documentación completa creada

Versión 1.0 (2025-10-27) - LEGACY

Características originales:

  • 10 tipos de transacciones
  • Función award_ml_coins() básica sin multiplicadores
  • Sin documentación formal

Criterios de Aceptación

  1. Usuario puede ganar ML Coins por actividades educativas
  2. Multiplicador de rango Maya se aplica correctamente
  3. Usuario puede gastar ML Coins en comodines y ayudas
  4. Balance nunca puede ser negativo
  5. Todas las transacciones quedan registradas
  6. Metadata JSONB contiene información completa
  7. Frontend muestra balance actualizado en tiempo real
  8. Tests SQL pasan al 100%

Creado: 2025-11-08 Aprobado por: Database Team Próxima revisión: 2025-12-01