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

9.8 KiB

FASE 3: PLAN DE CORRECCIÓN - DUPLICADOS ACHIEVEMENTS SYSTEM

Fecha: 2026-01-10 Proyecto: Gamilit Basado en: ANALISIS-DUPLICADOS-ACHIEVEMENTS-2026-01-10.md Estado: EN PLANEACIÓN


1. DECISIONES ARQUITECTÓNICAS

1.1 Modelo de Distribución de Recompensas

DECISIÓN: Implementar modelo de Claim-to-Earn (reclamar para ganar)

Acción Qué sucede Quién distribuye
Achievement desbloqueado Solo marca is_completed = true Backend service
Achievement reclamado Distribuye XP + ML Coins SQL function

Justificación:

  • Permite UX de "reclamar recompensa" (más satisfactorio)
  • Evita dar recompensas automáticas si usuario no las ve
  • Consistent con misiones y ejercicios que también usan "claim"

1.2 API Unificada

DECISIÓN: Mantener gamification.api.ts como API principal, deprecar duplicados en achievementsAPI.ts

Justificación:

  • gamification.api.ts ya usa transformers externos (mejor mantenibilidad)
  • Consolidar en /lib/api/ para acceso global
  • achievementsAPI.ts tiene mappers inline que duplican transformer

1.3 Hook de Definiciones

DECISIÓN: Deprecar /hooks/useAchievements.ts (450 líneas hardcodeadas)

Justificación:

  • Las definiciones deben venir del backend
  • El hook /features/gamification/social/hooks/useAchievements.ts usa el store correctamente
  • La detección automática la debe hacer el backend (ya implementada en detectAndGrantEarned)

2. PLAN DE CORRECCIÓN POR PROBLEMA

2.1 P-DUP-001: Backend NO Distribuye Recompensas

Severidad: 🔴 CRÍTICO

Archivo a modificar: /apps/backend/src/modules/gamification/services/achievements.service.ts

Cambio propuesto: Llamar a función SQL claim_achievement_reward en lugar de solo marcar flag

// ANTES (líneas 745-759):
async claimRewards(userId: string, achievementId: string): Promise<UserAchievement> {
  const userAchievement = await this.checkProgress(userId, achievementId);
  // validaciones...
  userAchievement.rewards_claimed = true;
  return this.userAchievementRepo.save(userAchievement);
}

// DESPUÉS:
async claimRewards(userId: string, achievementId: string): Promise<{
  userAchievement: UserAchievement;
  xp_granted: number;
  coins_granted: number;
}> {
  // Llamar función SQL que distribuye recompensas
  const result = await this.dataSource.query(
    `SELECT * FROM gamification_system.claim_achievement_reward($1, $2)`,
    [userId, achievementId]
  );

  if (!result[0].success) {
    throw new BadRequestException(result[0].message);
  }

  // Obtener userAchievement actualizado
  const userAchievement = await this.checkProgress(userId, achievementId);

  return {
    userAchievement,
    xp_granted: result[0].xp_granted,
    coins_granted: result[0].coins_granted,
  };
}

Dependencias:

  • Función SQL claim_achievement_reward debe estar actualizada ( Ya corregida)
  • Controller debe actualizarse para manejar nuevo retorno

2.2 P-DUP-002: SQL Puede Dar DOBLE Recompensa

Severidad: 🔴 CRÍTICO

Archivos a modificar:

  1. /apps/database/ddl/schemas/gamification_system/functions/check_and_award_achievements.sql

Cambio propuesto: Remover distribución de recompensas de check_and_grant_achievements - solo debe marcar is_completed, no dar XP/Coins

-- ANTES (líneas 111-118):
UPDATE gamification_system.user_stats
SET
    total_xp = COALESCE(total_xp, 0) + v_xp_reward,
    ml_coins = v_new_balance,
    achievements_earned = COALESCE(achievements_earned, 0) + 1,
    updated_at = NOW()
WHERE user_id = p_user_id;

-- Registrar transaccion de coins
INSERT INTO gamification_system.ml_coins_transactions (...)

-- DESPUÉS:
UPDATE gamification_system.user_stats
SET
    achievements_earned = COALESCE(achievements_earned, 0) + 1,
    updated_at = NOW()
WHERE user_id = p_user_id;

-- NO registrar transacción - se hará en claim_achievement_reward

Impacto:

  • El desbloqueo automático ya no dará recompensas
  • Las recompensas solo se dan al reclamar

2.3 P-DUP-003: Hook con Definiciones Hardcodeadas

Severidad: 🔴 CRÍTICO

Archivo a deprecar: /apps/frontend/src/hooks/useAchievements.ts

Acción: Agregar comentario de deprecación y redireccionar a hook correcto

/**
 * @deprecated Use useAchievements from '@/features/gamification/social/hooks/useAchievements'
 * Este hook contiene definiciones hardcodeadas que están desactualizadas.
 * La detección de achievements se hace en el backend (achievements.service.detectAndGrantEarned)
 */

Alternativa: Si se necesita auto-detection en frontend, llamar endpoint:

// En lugar de polling local, usar endpoint del backend
const result = await apiClient.post(`/gamification/users/${userId}/achievements/detect`);

2.4 P-DUP-004: APIs Duplicadas

Severidad: 🟡 IMPORTANTE

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

Cambio propuesto: Deprecar métodos duplicados y re-exportar desde gamification.api.ts

// ANTES:
export const claimAchievementRewards = async (...) => { ... };

// DESPUÉS:
/**
 * @deprecated Use gamificationApi.claimAchievement from '@/lib/api/gamification.api'
 */
export const claimAchievementRewards = gamificationApi.claimAchievement;

Archivos que consumen achievementsAPI.ts:

  • achievementsStore.ts - Actualizar imports

2.5 P-DUP-005: Transformers Inconsistentes

Severidad: 🟡 IMPORTANTE

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

Cambio propuesto: Remover mappers inline y usar transformer externo

// ANTES (líneas 382-411):
export const mapToFrontendAchievement = (...) => { ... };

// DESPUÉS:
import { transformAchievement, transformUserAchievement } from
  '@/features/gamification/achievements/utils/achievementTransformer';

// Re-export para compatibilidad
export { transformAchievement as mapToFrontendAchievement };

2.6 P-DUP-006: Schema Mismatch Admin

Severidad: 🟢 MENOR

Archivo a modificar: /apps/backend/src/modules/admin/services/admin-progress.service.ts

Cambio propuesto: Actualizar query SQL para usar campos correctos

-- ANTES:
SELECT
  ua.id, ua.achievement_id, a.name, a.description, a.category, a.tier,
  a.xp_reward, a.ml_coins_reward, a.icon_url,
  ua.unlocked_at, ua.progress_current, ua.progress_required

-- DESPUÉS:
SELECT
  ua.id, ua.achievement_id, a.name, a.description, a.category,
  a.difficulty_level as tier,  -- Mapear difficulty_level a tier
  COALESCE((a.rewards->>'xp')::INTEGER, a.points_value, 0) as xp_reward,
  a.ml_coins_reward, a.icon as icon_url,
  ua.completed_at as unlocked_at,  -- Usar completed_at
  ua.progress as progress_current,  -- Usar progress
  ua.max_progress as progress_required  -- Usar max_progress

3. ORDEN DE EJECUCIÓN

Fase A: Correcciones SQL (Base de datos)

Orden Archivo Cambio Dependencias
A.1 check_and_award_achievements.sql Remover distribución de rewards Ninguna

Fase B: Correcciones Backend (NestJS)

Orden Archivo Cambio Dependencias
B.1 achievements.service.ts Llamar SQL function en claimRewards A.1 completado
B.2 achievements.controller.ts Actualizar response type B.1 completado
B.3 admin-progress.service.ts Fix schema mismatch Ninguna

Fase C: Correcciones Frontend (React)

Orden Archivo Cambio Dependencias
C.1 achievementsAPI.ts Deprecar y usar transformer Ninguna
C.2 achievementsStore.ts Actualizar imports C.1 completado
C.3 /hooks/useAchievements.ts Agregar deprecation notice Ninguna

4. VALIDACIONES REQUERIDAS

4.1 Antes de Ejecutar

  • Backup de base de datos
  • Verificar que no hay usuarios en proceso de claim
  • Tests existentes pasan

4.2 Durante Ejecución

  • Cada cambio SQL aplicado con \df para verificar
  • Build de backend exitoso después de cada cambio
  • Build de frontend exitoso después de cada cambio

4.3 Después de Ejecutar

  • Test E2E: Usuario desbloquea achievement → NO recibe rewards automático
  • Test E2E: Usuario reclama achievement → SÍ recibe rewards
  • Test: Intentar reclamar dos veces → Error apropiado
  • Test: Dashboard admin muestra datos correctos

5. ROLLBACK PLAN

Si falla Fase A (SQL):

-- Restaurar check_and_award_achievements.sql desde git
git checkout HEAD~1 -- apps/database/ddl/schemas/gamification_system/functions/check_and_award_achievements.sql
-- Re-ejecutar script de creación de función

Si falla Fase B (Backend):

# Restaurar archivos modificados
git checkout HEAD~1 -- apps/backend/src/modules/gamification/services/achievements.service.ts
git checkout HEAD~1 -- apps/backend/src/modules/gamification/controllers/achievements.controller.ts
npm run build

Si falla Fase C (Frontend):

# Restaurar archivos modificados
git checkout HEAD~1 -- apps/frontend/src/features/gamification/social/
npm run build

6. ESTIMACIÓN DE IMPACTO

Métrica Antes Después
Archivos modificados - 7
Líneas cambiadas - ~150
Funciones deprecadas - 3
Tests requeridos - 4 E2E

7. DOCUMENTOS RELACIONADOS

Documento Estado
ANALISIS-DUPLICADOS-ACHIEVEMENTS-2026-01-10.md Completado
PLAN-DUPLICADOS-ACHIEVEMENTS-2026-01-10.md Actual
VALIDACION-PLAN-DUPLICADOS-2026-01-10.md Pendiente

Planeado por: Claude (Arquitecto Técnico) Fecha: 2026-01-10 Estado: FASE 3 COMPLETADA - Pendiente FASE 4 (Validación)