workspace-v1/orchestration/analisis/ANALISIS-ACHIEVEMENTS-PAGE-2026-01-10.md
rckrdmrd e56e927a4d [MAINT-001] docs(orchestration): Actualizacion directivas SIMCO, perfiles y documentacion
Cambios incluidos:
- INDICE-DIRECTIVAS-WORKSPACE.yml actualizado
- Perfiles de agentes: PERFIL-ML.md, PERFIL-SECURITY.md
- Directivas SIMCO actualizadas:
  - SIMCO-ASIGNACION-PERFILES.md
  - SIMCO-CCA-SUBAGENTE.md
  - SIMCO-CONTEXT-ENGINEERING.md
  - SIMCO-CONTEXT-RESOLUTION.md
  - SIMCO-DELEGACION-PARALELA.md
- Inventarios actualizados: DEVENV-MASTER, DEVENV-PORTS
- Documentos de analisis agregados:
  - Analisis y planes de fix student portal
  - Analisis scripts BD
  - Analisis achievements, duplicados, gamification
  - Auditoria documentacion gamilit
  - Backlog discrepancias NEXUS
  - Planes maestros de resolucion
- Reportes de ejecucion agregados
- Knowledge base gamilit README actualizado
- Referencia submodulo gamilit actualizada (commit beb94f7)

Validaciones:
- Plan validado contra directivas SIMCO-GIT
- Dependencias verificadas
- Build gamilit: EXITOSO
2026-01-10 04:51:28 -06:00

30 KiB

ANÁLISIS DETALLADO: PÁGINA DE ACHIEVEMENTS - STUDENT PORTAL

Fecha: 2026-01-10 Proyecto: Gamilit Componente: /achievements (Student Portal) Estado: EN ANÁLISIS


ÍNDICE

  1. Resumen Ejecutivo
  2. Arquitectura del Sistema
  3. Análisis Frontend
  4. Análisis Backend
  5. Análisis Base de Datos
  6. Análisis de Tipos e Interfaces
  7. Flujo de Datos Completo
  8. Problemas Identificados
  9. Dependencias y Relaciones
  10. Seeds e Integración
  11. Recomendaciones

1. RESUMEN EJECUTIVO

1.1 Descripción General

El sistema de Achievements es una funcionalidad de gamificación que permite a los estudiantes:

  • Ver todos los logros disponibles en el sistema
  • Rastrear su progreso hacia cada logro
  • Reclamar recompensas (ML Coins, XP) al completar logros
  • Filtrar y buscar logros por categoría, rareza y estado

1.2 Rutas y Archivos Principales

Capa Ruta Principal
Página Frontend /home/isem/workspace-v1/projects/gamilit/apps/frontend/src/pages/AchievementsPage.tsx
Componentes Student /home/isem/workspace-v1/projects/gamilit/apps/frontend/src/apps/student/components/achievements/
Controller Backend /home/isem/workspace-v1/projects/gamilit/apps/backend/src/modules/gamification/controllers/achievements.controller.ts
Service Backend /home/isem/workspace-v1/projects/gamilit/apps/backend/src/modules/gamification/services/achievements.service.ts
DDL Achievements /home/isem/workspace-v1/projects/gamilit/apps/database/ddl/schemas/gamification_system/tables/03-achievements.sql
DDL User Achievements /home/isem/workspace-v1/projects/gamilit/apps/database/ddl/schemas/gamification_system/tables/04-user_achievements.sql
Seeds Dev /home/isem/workspace-v1/projects/gamilit/apps/database/seeds/dev/gamification_system/

1.3 Endpoints API

Método Endpoint Descripción
GET /api/v1/gamification/achievements Obtener todos los achievements
GET /api/v1/gamification/achievements/:id Obtener achievement específico
GET /api/v1/gamification/users/:userId/achievements Obtener achievements del usuario
GET /api/v1/gamification/users/:userId/achievements/summary Resumen estadístico
POST /api/v1/gamification/users/:userId/achievements/:achievementId/claim Reclamar recompensas

2. ARQUITECTURA DEL SISTEMA

2.1 Diagrama de Capas

┌─────────────────────────────────────────────────────────────────────────┐
│                           FRONTEND (React + Vite)                        │
├─────────────────────────────────────────────────────────────────────────┤
│  pages/AchievementsPage.tsx                                              │
│    ├── GamifiedHeader                                                    │
│    ├── AchievementFilter                                                 │
│    ├── AchievementCard (grid)                                            │
│    └── AchievementModal                                                  │
├─────────────────────────────────────────────────────────────────────────┤
│  Hooks                          │  Store (Zustand)                       │
│  ├── useAuth                    │  └── achievementsStore.ts              │
│  ├── useUserGamification        │      ├── achievements[]                │
│  └── useAchievementsEnhanced    │      ├── stats                         │
│                                 │      └── actions                       │
├─────────────────────────────────────────────────────────────────────────┤
│  API Layer                                                               │
│  ├── achievementsAPI.ts (features/gamification)                          │
│  └── gamificationApi (shared services)                                   │
└─────────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼ HTTP
┌─────────────────────────────────────────────────────────────────────────┐
│                           BACKEND (NestJS)                               │
├─────────────────────────────────────────────────────────────────────────┤
│  Controllers                                                             │
│  └── achievements.controller.ts                                          │
├─────────────────────────────────────────────────────────────────────────┤
│  Services                                                                │
│  └── achievements.service.ts                                             │
│      ├── findAll()                                                       │
│      ├── getAllUserAchievements()                                        │
│      ├── grantAchievement()                                              │
│      ├── claimRewards()                                                  │
│      └── meetsConditions()                                               │
├─────────────────────────────────────────────────────────────────────────┤
│  Entities                                                                │
│  ├── achievement.entity.ts                                               │
│  ├── user-achievement.entity.ts                                          │
│  └── user-stats.entity.ts                                                │
└─────────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼ TypeORM
┌─────────────────────────────────────────────────────────────────────────┐
│                        DATABASE (PostgreSQL)                             │
├─────────────────────────────────────────────────────────────────────────┤
│  Schema: gamification_system                                             │
│  ├── achievements (tabla maestra)                                        │
│  ├── user_achievements (progreso usuario)                                │
│  ├── achievement_categories (metadatos UI)                               │
│  └── user_stats (estadísticas gamificación)                              │
├─────────────────────────────────────────────────────────────────────────┤
│  Funciones SQL                                                           │
│  ├── check_and_award_achievements()                                      │
│  └── claim_achievement_reward()                                          │
├─────────────────────────────────────────────────────────────────────────┤
│  Triggers                                                                │
│  └── trg_achievement_unlocked (otorga XP/coins, crea notificación)       │
└─────────────────────────────────────────────────────────────────────────┘

3. ANÁLISIS FRONTEND

3.1 AchievementsPage.tsx - Componente Principal

Ubicación: /apps/frontend/src/pages/AchievementsPage.tsx

Estados Gestionados

Estado Tipo Propósito
allAchievements Achievement[] Lista de todos los logros del sistema
userAchievements UserAchievement[] Progreso del usuario en cada logro
summary `AchievementSummary null`
isLoadingAchievements boolean Loading para logros del sistema
isLoadingUserData boolean Loading para datos del usuario
error `string null`
filter AchievementFilterType Filtros activos (categoría, estado, búsqueda, orden)
selectedAchievement `Achievement null`
isModalOpen boolean Control de visibilidad del modal

Hooks Utilizados

const { user, logout } = useAuth();
const { gamificationData } = useUserGamification(user?.id);

Llamadas a API

  1. Carga inicial de achievements:

    useEffect(() => {
      const data = await gamificationApi.getAllAchievements();
      setAllAchievements(data);
    }, []);
    
  2. Carga de datos del usuario:

    useEffect(() => {
      const [userAchData, summaryData] = await Promise.all([
        gamificationApi.getUserAchievements(user.id),
        gamificationApi.getAchievementSummary(user.id).catch(() => null),
      ]);
    }, [user?.id]);
    
  3. Reclamar recompensas:

    const handleClaimRewards = async (achievementId: string) => {
      const updatedAchievement = await gamificationApi.claimAchievement(user.id, achievementId);
      // Update optimista del estado local
    };
    

Lógica de Negocio (useMemo)

  1. Combinación de datos: Merge de allAchievements + userAchievements usando Map
  2. Filtrado: Por categoría → estado → búsqueda (case-insensitive)
  3. Ordenamiento: Por nombre, progreso, fecha o rareza
  4. Separación: Achievements visibles vs. ocultos (isHidden && status === 'locked')
  5. Cálculo de Summary: Fallback local si API no devuelve summary

3.2 Componentes del Student Portal

Componente Archivo Propósito
AchievementsPageHeader AchievementsPageHeader.tsx Hero section con estadísticas visuales
AchievementFilters AchievementFilters.tsx Controles de filtrado (categoría, rareza, estado, búsqueda)
AchievementGrid AchievementGrid.tsx Grid responsivo de cards
AchievementStatistics AchievementStatistics.tsx Panel de analytics y breakdown
AchievementDetailModal AchievementDetailModal.tsx Modal de detalle con navegación
AchievementCard features/gamification/social/components/ Card individual reutilizable

3.3 Hook useAchievementsEnhanced

Ubicación: /apps/frontend/src/apps/student/hooks/useAchievementsEnhanced.ts

Proporciona:

  • Filtrado avanzado con debounce (300ms)
  • Ordenamiento múltiple
  • Navegación entre achievements (prev/next)
  • Persistencia de filtros en localStorage
  • Cálculo de estadísticas detalladas

4. ANÁLISIS BACKEND

4.1 achievements.controller.ts

Ubicación: /apps/backend/src/modules/gamification/controllers/achievements.controller.ts

Endpoints Implementados

Decorador Ruta Método Service
@Get('achievements') /api/v1/gamification/achievements findAll(includeSecret)
@Get('achievements/:id') /api/v1/gamification/achievements/:id findById(id)
@Get('users/:userId/achievements') /api/v1/gamification/users/:userId/achievements getAllUserAchievements(userId)
@Get('users/:userId/achievements/summary') /api/v1/gamification/users/:userId/achievements/summary getUserAchievementStats(userId)
@Post('users/:userId/achievements/:achievementId') POST grant grantAchievement(userId, dto)
@Post('users/:userId/achievements/:achievementId/claim') POST claim claimRewards(userId, achievementId)
@Patch('achievements/:id') PATCH toggle updateAchievementStatus(id, isActive)

4.2 achievements.service.ts

Ubicación: /apps/backend/src/modules/gamification/services/achievements.service.ts

Métodos Principales

Método Descripción
findAll(includeSecret) Obtiene achievements activos (opcionalmente secretos)
findById(id) Obtiene achievement por ID con NotFoundException
getAllUserAchievements(userId) Obtiene todos los achievements con progreso del usuario
grantAchievement(userId, dto) Otorga/actualiza progreso de un achievement
claimRewards(userId, achievementId) Reclama recompensas (valida completado y no reclamado)
meetsConditions(userId, userStats, conditions) Evalúa si se cumplen condiciones de un achievement
detectAndGrantEarned(userId) Detecta y otorga automáticamente achievements
getUserAchievementStats(userId) Calcula estadísticas de achievements del usuario

Tipos de Condiciones Soportadas (meetsConditions)

Tipo Evaluación
exercise_completion userStats.exercises_completed >= requirements.exercises_completed
streak userStats.current_streak >= requirements.consecutive_days
module_completion Query a progress_tracking.module_progress
all_modules_completion modules_completed >= X && average_score >= Y
perfect_score userStats.perfect_scores >= requirements.perfect_exercises
skill_mastery userStats.perfect_scores >= 10
exploration `modules_completed > 0
social Query a social_features.classroom_members/friendships
special first_login check
module_first_exercise Query por module_code
exercise_score Query por exercise_type y min_score
exercise_repetition Conteo de ejercicios con score mínimo
exercise_speed Tiempo de completación
content_analysis Análisis de contenido
module_average_score Promedio por módulo

5. ANÁLISIS BASE DE DATOS

5.1 Tabla: gamification_system.achievements

Ubicación DDL: /apps/database/ddl/schemas/gamification_system/tables/03-achievements.sql

Columnas Principales

Columna Tipo Default Descripción
id UUID gen_random_uuid() PK
tenant_id UUID NULL Multi-tenant
name TEXT - Nombre del achievement
description TEXT NULL Descripción
icon TEXT 'trophy' Icono/emoji
category ENUM - achievement_category
rarity TEXT 'common' common/rare/epic/legendary
difficulty_level ENUM 'beginner' Nivel de dificultad
conditions JSONB {type, requirements} Condiciones para desbloquear
rewards JSONB {xp, ml_coins, badge} Recompensas
ml_coins_reward INTEGER 0 ML Coins (duplicado de rewards)
is_secret BOOLEAN false Si está oculto
is_active BOOLEAN true Si está activo
is_repeatable BOOLEAN false Si es repetible
order_index INTEGER 0 Orden en UI
points_value INTEGER 0 XP (duplicado de rewards)

Índices

  • idx_achievements_active - WHERE is_active = true
  • idx_achievements_category - Por categoría
  • idx_achievements_conditions_gin - GIN para JSONB
  • idx_achievements_secret - WHERE is_secret = true

5.2 Tabla: gamification_system.user_achievements

Ubicación DDL: /apps/database/ddl/schemas/gamification_system/tables/04-user_achievements.sql

Columnas Principales

Columna Tipo Default Descripción
id UUID gen_random_uuid() PK
user_id UUID - FK a profiles
achievement_id UUID - FK a achievements
progress INTEGER 0 Progreso actual
max_progress INTEGER 100 Progreso máximo
is_completed BOOLEAN false Si está completado
completion_percentage NUMERIC(5,2) 0.00 Porcentaje (0-100)
completed_at TIMESTAMPTZ NULL Fecha de completación
notified BOOLEAN false Si se notificó
viewed BOOLEAN false Si se vio la notificación
rewards_claimed BOOLEAN false Si reclamó recompensas
rewards_received JSONB {} Detalle de recompensas
progress_data JSONB {} Datos de progreso
milestones_reached TEXT[] NULL Hitos alcanzados

Constraints

  • UNIQUE (user_id, achievement_id) - Un usuario no puede duplicar logro
  • FK user_id → auth_management.profiles(id) ON DELETE CASCADE
  • FK achievement_id → gamification_system.achievements(id) ON DELETE CASCADE

5.3 ENUM: achievement_category

Valores: progress, streak, completion, social, special, mastery, exploration, collection, hidden

5.4 Trigger: trg_achievement_unlocked

Evento: AFTER INSERT OR UPDATE en user_achievements

Acciones:

  1. Verifica si is_completed = true
  2. Otorga XP a user_stats.total_xp
  3. Otorga ML Coins con row lock
  4. Crea notificación en notifications.notifications
  5. Marca notified = true

6. ANÁLISIS DE TIPOS E INTERFACES

6.1 Tipos Canónicos (SSOT)

Ubicación: /apps/frontend/src/shared/types/achievement.types.ts

type AchievementCategory = 'progress' | 'streak' | 'completion' | 'social' |
                           'special' | 'mastery' | 'exploration' | 'collection' | 'hidden'

type AchievementStatus = 'locked' | 'in_progress' | 'earned' | 'claimed'

enum AchievementType {
  BADGE = 'badge',
  MILESTONE = 'milestone',
  SPECIAL = 'special',
  RANK_PROMOTION = 'rank_promotion',
}

interface Achievement {
  id: string;
  name: string;
  description: string;
  icon: string;
  category: AchievementCategory;
  type: AchievementType;
  conditions: AchievementConditionsType;
  rewards: AchievementReward;
  isHidden: boolean;
  rarity?: 'common' | 'rare' | 'epic' | 'legendary';
  // ... más campos
}

interface UserAchievement {
  id: string;
  userId: string;
  achievementId: string;
  progress: number;
  earnedAt?: string;
  claimedAt?: string;
  achievement: Achievement;
  status: AchievementStatus;
}

6.2 Mapeo Backend → Frontend

Backend (snake_case) Frontend (camelCase) Transformación
name title Mapeo directo
ml_coins_reward mlCoinsReward rewards?.ml_coins ?? ml_coins_reward
points_value xpReward rewards?.xp ?? points_value
is_secret isHidden Mapeo + categoría
is_completed isUnlocked Mapeo directo
completed_at unlockedAt Parse a Date
completion_percentage Parseado parseFloat() - ¡Backend devuelve string!

7. FLUJO DE DATOS COMPLETO

Usuario abre /achievements
         │
         ▼
┌────────────────────────────────────────────┐
│ AchievementsPage.tsx - useEffect (mount)   │
│ ├── gamificationApi.getAllAchievements()   │
│ └── gamificationApi.getUserAchievements()  │
│     gamificationApi.getAchievementSummary()│
└────────────────────────────────────────────┘
         │
         ▼ HTTP GET
┌────────────────────────────────────────────┐
│ achievements.controller.ts                 │
│ ├── @Get('achievements')                   │
│ └── @Get('users/:userId/achievements')     │
└────────────────────────────────────────────┘
         │
         ▼
┌────────────────────────────────────────────┐
│ achievements.service.ts                    │
│ ├── findAll() - QueryBuilder              │
│ └── getAllUserAchievements() - Repository │
└────────────────────────────────────────────┘
         │
         ▼ TypeORM
┌────────────────────────────────────────────┐
│ PostgreSQL                                 │
│ ├── gamification_system.achievements       │
│ └── gamification_system.user_achievements  │
└────────────────────────────────────────────┘
         │
         ▼ Response
┌────────────────────────────────────────────┐
│ Frontend - Transformación                  │
│ ├── mapToFrontendAchievement()            │
│ └── useMemo combinedAchievements          │
└────────────────────────────────────────────┘
         │
         ▼ Render
┌────────────────────────────────────────────┐
│ UI Components                              │
│ ├── AchievementCard (grid)                 │
│ ├── AchievementModal (detalle)             │
│ └── AchievementStatistics (analytics)      │
└────────────────────────────────────────────┘

8. PROBLEMAS IDENTIFICADOS

8.1 CRÍTICOS 🔴

ID Problema Ubicación Impacto
P1 Función claim_achievement_reward() usa columnas inexistentes (reward_claimed_at) DDL functions Función SQL falla al ejecutarse
P2 Store usa || en lugar de ?? para recompensas (0 es falsy) achievementsStore.ts:172 Recompensas de 0 podrían fallar
P3 Backend completion_percentage es STRING, no se parsea en Store achievementsStore Tipo incorrecto en runtime

8.2 IMPORTANTES 🟡

ID Problema Ubicación Impacto
P4 Duplicación de ml_coins_reward (columna y JSONB rewards) DDL + Backend Inconsistencia potencial
P5 Duplicación de points_value (columna) vs rewards.xp DDL + Backend Inconsistencia potencial
P6 Alias conflictivo Achievement en achievementsTypes.ts Types Confusión de tipos
P7 unlockedAt es string vs Date inconsistente Múltiples archivos Bugs de tipo
P8 Category mapping incompleto (falta 'streak', 'exploration') achievementsAPI.ts Categorías mal mapeadas
P9 ENUM vs Tabla para categorías (2 valores no en tabla) DDL Integridad referencial

8.3 MENORES 🟢

ID Problema Ubicación Impacto
P10 rarity es TEXT no ENUM DDL achievements Podría tener valores inválidos
P11 Múltiples timestamps (earnedAt, claimedAt, unlockedAt) Types Documentación faltante

9. DEPENDENCIAS Y RELACIONES

9.1 Dependencias de Tablas

gamification_system.achievements
    ├── FK created_by → auth_management.profiles(id)
    └── FK tenant_id → auth_management.tenants(id)

gamification_system.user_achievements
    ├── FK user_id → auth_management.profiles(id)
    └── FK achievement_id → gamification_system.achievements(id)

gamification_system.user_stats
    └── FK user_id → auth_management.profiles(id)

9.2 Dependencias de Servicios (Backend)

El AchievementsService realiza queries cruzadas a:

  • progress_tracking.module_progress
  • progress_tracking.exercise_submissions
  • educational_content.modules
  • educational_content.exercises
  • social_features.classroom_members
  • social_features.friendships

9.3 Dependencias Frontend

AchievementsPage
├── useAuth (auth context)
├── useUserGamification (React Query)
├── gamificationApi (axios client)
├── GamifiedHeader (shared component)
├── AchievementFilter (student component)
├── AchievementCard (feature component)
└── AchievementModal (shared component)

10. SEEDS E INTEGRACIÓN

10.1 Seeds de Achievement Categories

Archivo: /apps/database/seeds/dev/gamification_system/01-achievement_categories.sql

Nombre Icono Orden
Progreso 🎯 1
Racha 🔥 2
Completación 3
Maestría 👑 4
Exploración 🔍 5
Social 👥 6
Especial 7

10.2 Seeds de Achievements

Archivo: /apps/database/seeds/dev/gamification_system/04-achievements.sql

Total: 20 achievements de demostración

Categoría Cantidad Ejemplo
Progress 5 "Primeros Pasos" (1 ejercicio) → "Maestro de Lectura" (200 ejercicios)
Streak 3 "Racha 3 Días" → "Racha 30 Días"
Completion 4 "Módulo 1 Completado" → "Completista Total"
Mastery 3 "Perfeccionista" (10 ejercicios 100%)
Exploration 2 "Explorador Curioso"
Social 2 "Compañero de Aula"
Special 1 "Primera Visita"

10.3 Seeds de User Achievements

Archivo: /apps/database/seeds/dev/gamification_system/08-user_achievements.sql

Usuarios de Demo: 7 usuarios con achievements pre-asignados para testing


11. RECOMENDACIONES

11.1 Correcciones Críticas (Inmediato)

  1. Reparar función SQL claim_achievement_reward():

    • Cambiar reward_claimed_at por rewards_claimed (boolean)
    • Usar completed_at para timestamp
  2. Corregir Store con nullish coalescing:

    // ANTES
    mlCoinsReward: ach.rewards?.ml_coins || ach.ml_coins_reward || 0,
    
    // DESPUÉS
    mlCoinsReward: ach.rewards?.ml_coins ?? ach.ml_coins_reward ?? 0,
    
  3. Parsear completion_percentage en Store:

    completionPercentage: typeof ach.completion_percentage === 'string'
      ? parseFloat(ach.completion_percentage)
      : ach.completion_percentage,
    

11.2 Mejoras de Consistencia (Corto Plazo)

  1. Unificar fuente de recompensas:

    • Definir rewards JSONB como SSOT
    • Deprecar columnas ml_coins_reward y points_value
  2. Estandarizar timestamps:

    • Definir unlockedAt como campo canónico
    • Siempre como ISO string en API responses
  3. Completar mapeo de categorías:

    const categoryMap = {
      'streak': 'streak',
      'exploration': 'exploration',
      'collection': 'collection',
      // ... completar
    };
    

11.3 Mejoras Estructurales (Mediano Plazo)

  1. Convertir rarity a ENUM
  2. Sincronizar ENUM achievement_category con tabla achievement_categories
  3. Agregar índices para queries comunes del frontend
  4. Documentar flujo de datos end-to-end

APÉNDICE A: ARCHIVOS ANALIZADOS

Frontend

  • /apps/frontend/src/pages/AchievementsPage.tsx
  • /apps/frontend/src/apps/student/components/achievements/*.tsx
  • /apps/frontend/src/apps/student/hooks/useAchievementsEnhanced.ts
  • /apps/frontend/src/features/gamification/social/api/achievementsAPI.ts
  • /apps/frontend/src/features/gamification/social/store/achievementsStore.ts
  • /apps/frontend/src/shared/types/achievement.types.ts

Backend

  • /apps/backend/src/modules/gamification/controllers/achievements.controller.ts
  • /apps/backend/src/modules/gamification/services/achievements.service.ts
  • /apps/backend/src/modules/gamification/entities/achievement.entity.ts
  • /apps/backend/src/modules/gamification/entities/user-achievement.entity.ts
  • /apps/backend/src/modules/gamification/dto/achievements/*.ts

Database

  • /apps/database/ddl/schemas/gamification_system/tables/03-achievements.sql
  • /apps/database/ddl/schemas/gamification_system/tables/04-user_achievements.sql
  • /apps/database/ddl/schemas/gamification_system/tables/10-achievement_categories.sql
  • /apps/database/ddl/schemas/gamification_system/enums/achievement_category.sql
  • /apps/database/ddl/schemas/gamification_system/functions/check_and_award_achievements.sql
  • /apps/database/ddl/schemas/gamification_system/functions/claim_achievement_reward.sql
  • /apps/database/ddl/schemas/gamification_system/triggers/01-trg_achievement_unlocked.sql
  • /apps/database/seeds/dev/gamification_system/*.sql

Documento generado: 2026-01-10 Analista: Claude (Arquitecto Técnico) Siguiente Fase: Planeación basada en análisis detallado