workspace-v1/orchestration/analisis/PLAN-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

11 KiB

PLAN DE IMPLEMENTACIÓN: CORRECCIONES ACHIEVEMENTS PAGE

Fecha: 2026-01-10 Proyecto: Gamilit Componente: /achievements (Student Portal) Basado en: ANALISIS-ACHIEVEMENTS-PAGE-2026-01-10.md Estado: EN PLANEACIÓN


RESUMEN DE PROBLEMAS IDENTIFICADOS

Críticos (Deben corregirse)

ID Problema Prioridad
P1 Función SQL claim_achievement_reward() usa columnas inexistentes 🔴 CRÍTICO
P2 Store usa || en lugar de ?? para recompensas 🔴 CRÍTICO
P3 completion_percentage es STRING, no se parsea en Store 🔴 CRÍTICO

Importantes (Deberían corregirse)

ID Problema Prioridad
P4 Duplicación de ml_coins_reward 🟡 IMPORTANTE
P5 Duplicación de points_value vs rewards.xp 🟡 IMPORTANTE
P6 Alias conflictivo Achievement en achievementsTypes.ts 🟡 IMPORTANTE
P7 unlockedAt es string vs Date inconsistente 🟡 IMPORTANTE
P8 Category mapping incompleto 🟡 IMPORTANTE

PLAN DE CORRECCIONES

FASE A: Correcciones Críticas de Base de Datos

A.1 Reparar función claim_achievement_reward()

Archivo: /apps/database/ddl/schemas/gamification_system/functions/claim_achievement_reward.sql

Cambios requeridos:

  1. Cambiar referencia a v_user_achievement.reward_claimed_at por v_user_achievement.rewards_claimed
  2. Usar v_user_achievement.completed_at para verificar timestamp
  3. Extraer XP de v_achievement.rewards->>'xp' en lugar de v_achievement.xp_reward

Verificación:

  • Función compila sin errores
  • Test de reclamar recompensa funciona
  • No se puede reclamar dos veces

FASE B: Correcciones Críticas de Frontend

B.1 Corregir achievementsStore.ts - Operador nullish

Archivo: /apps/frontend/src/features/gamification/social/store/achievementsStore.ts

Líneas a modificar: ~165-180

Cambios:

// ANTES
mlCoinsReward: ach.rewards?.ml_coins || ach.ml_coins_reward || 0,
xpReward: ach.rewards?.xp || 0,

// DESPUÉS
mlCoinsReward: ach.rewards?.ml_coins ?? ach.ml_coins_reward ?? 0,
xpReward: ach.rewards?.xp ?? ach.points_value ?? 0,

Verificación:

  • Achievements con 0 ML Coins muestran correctamente
  • Achievements con 0 XP muestran correctamente
  • No hay errores en consola

B.2 Parsear completion_percentage en Store

Archivo: /apps/frontend/src/features/gamification/social/store/achievementsStore.ts

Cambios:

// Agregar transformación al mapear achievements
completionPercentage: typeof ach.completion_percentage === 'string'
  ? parseFloat(ach.completion_percentage)
  : ach.completion_percentage ?? 0,

Verificación:

  • Porcentaje se muestra correctamente como número
  • Progress bars funcionan con valores decimales

FASE C: Mejoras de Consistencia de Tipos

C.1 Completar mapeo de categorías

Archivo: /apps/frontend/src/features/gamification/social/api/achievementsAPI.ts

Función: mapCategory()

Cambios:

function mapCategory(backendCategory: string): FrontendCategory {
  const categoryMap: Record<string, FrontendCategory> = {
    'educational': 'progress',
    'progress': 'progress',
    'streak': 'streak',           // ← AGREGAR
    'mastery': 'mastery',
    'skill': 'mastery',
    'social': 'social',
    'hidden': 'hidden',
    'special': 'hidden',
    'exploration': 'exploration', // ← AGREGAR
    'collection': 'collection',   // ← AGREGAR
    'completion': 'completion',   // ← AGREGAR
    'missions': 'progress',
  };
  return categoryMap[backendCategory.toLowerCase()] ?? 'progress';
}

Verificación:

  • Todas las categorías de la BD se mapean correctamente
  • Filtros de categoría funcionan
  • Badges de categoría muestran correctamente

C.2 Estandarizar timestamp unlockedAt

Archivos a revisar:

  • /apps/frontend/src/features/gamification/social/types/achievementsTypes.ts
  • /apps/frontend/src/shared/types/achievement.types.ts

Cambios:

  1. Definir unlockedAt como campo canónico (siempre string | undefined)
  2. Eliminar duplicados (earnedAt, claimedAt si no se usan)
  3. Documentar en comentarios

Verificación:

  • TypeScript no muestra errores de tipo
  • Fechas se formatean correctamente en UI

FASE D: Validación de Seeds

D.1 Verificar consistencia de seeds con DDL

Archivos a verificar:

  • /apps/database/seeds/dev/gamification_system/01-achievement_categories.sql
  • /apps/database/seeds/dev/gamification_system/04-achievements.sql
  • /apps/database/seeds/dev/gamification_system/08-user_achievements.sql

Checklist:

  • Todas las columnas insertadas existen en DDL
  • Tipos de datos coinciden
  • FKs apuntan a registros existentes
  • Valores de ENUM son válidos
  • Estructura de JSONB conditions es correcta
  • Estructura de JSONB rewards es correcta

D.2 Validar datos de user_achievements

Verificar:

  • user_id existe en auth_management.profiles
  • achievement_id existe en gamification_system.achievements
  • progress <= max_progress
  • completion_percentage = (progress / max_progress) * 100
  • Si is_completed = true, entonces completed_at no es NULL

FASE E: Testing End-to-End

E.1 Verificar flujo completo de achievements

Test 1: Carga inicial

  • GET /achievements retorna lista correcta
  • GET /users/:id/achievements retorna progreso
  • GET /users/:id/achievements/summary retorna estadísticas

Test 2: Filtrado y ordenamiento

  • Filtro por categoría funciona
  • Filtro por estado funciona
  • Búsqueda por nombre funciona
  • Ordenamiento por todos los criterios funciona

Test 3: Reclamar recompensas

  • POST claim funciona para achievements completados
  • ML Coins se suman al usuario
  • XP se suma al usuario
  • No se puede reclamar dos veces

Test 4: UI/UX

  • Cards muestran información correcta
  • Modal de detalle muestra progreso
  • Achievements ocultos no se muestran si locked
  • Achievements ocultos se muestran si unlocked

MATRIZ DE ARCHIVOS A MODIFICAR

Archivo Fase Cambio
claim_achievement_reward.sql A Reparar columnas
achievementsStore.ts B ?? operator + parseFloat
achievementsAPI.ts C Category mapping
achievementsTypes.ts C Estandarizar timestamps
achievement.types.ts C Documentar campos canónicos

DEPENDENCIAS ENTRE CORRECCIONES

┌─────────────────────────────────────────────────────────────┐
│                     FASE A (Base de Datos)                  │
│  claim_achievement_reward.sql                                │
└─────────────────────────────────────────────────────────────┘
           │
           │ (Debe completarse primero para que el backend funcione)
           ▼
┌─────────────────────────────────────────────────────────────┐
│                      FASE B (Frontend Store)                │
│  achievementsStore.ts - nullish coalescing                  │
│  achievementsStore.ts - parseFloat                          │
└─────────────────────────────────────────────────────────────┘
           │
           │ (Store corregido antes de tipos)
           ▼
┌─────────────────────────────────────────────────────────────┐
│                      FASE C (Tipos y API)                   │
│  achievementsAPI.ts - category mapping                      │
│  achievementsTypes.ts - estandarizar timestamps             │
└─────────────────────────────────────────────────────────────┘
           │
           │ (Código corregido antes de validar seeds)
           ▼
┌─────────────────────────────────────────────────────────────┐
│                      FASE D (Seeds)                         │
│  Verificar consistencia de datos                            │
└─────────────────────────────────────────────────────────────┘
           │
           ▼
┌─────────────────────────────────────────────────────────────┐
│                      FASE E (Testing)                       │
│  Validación end-to-end                                      │
└─────────────────────────────────────────────────────────────┘

CRITERIOS DE ACEPTACIÓN

Para considerar correcciones COMPLETADAS:

  1. Base de Datos:

    • Función claim_achievement_reward() ejecuta sin errores
    • Trigger trg_achievement_unlocked funciona correctamente
  2. Backend:

    • Todos los endpoints responden correctamente
    • Tipos de datos son correctos en responses
  3. Frontend:

    • No hay errores en consola del navegador
    • TypeScript compila sin errores
    • Datos se muestran correctamente en UI
  4. Seeds:

    • Datos de prueba cargan sin errores
    • Relaciones FK son válidas
  5. Testing:

    • Flujo completo de achievements funciona
    • Reclamar recompensas funciona
    • Filtros y búsqueda funcionan

NOTAS IMPORTANTES

Decisiones de Diseño

  1. Fuente única de verdad para recompensas:

    • Se usará rewards JSONB como SSOT
    • Las columnas ml_coins_reward y points_value se mantienen por compatibilidad
    • Frontend debe leer primero de rewards, luego de columnas
  2. Timestamp canónico:

    • unlockedAt (frontend) = completed_at (backend)
    • Siempre como string ISO 8601
  3. Category mapping:

    • Backend puede enviar cualquier string
    • Frontend mapea a categorías conocidas
    • Default: 'progress'

Riesgos Identificados

  1. Función SQL rota: Actualmente claim_achievement_reward() no funciona. Reclamar recompensas via SQL fallará.

  2. Datos legacy: Pueden existir registros con completion_percentage como string. El frontend debe manejar ambos tipos.

  3. Categorías desconocidas: Si el backend agrega nuevas categorías, el frontend las mostrará como 'progress' hasta actualizar el mapeo.


Documento generado: 2026-01-10 Siguiente Fase: Validación de planeación contra requisitos