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

333 lines
9.8 KiB
Markdown

# 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
```typescript
// 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
```sql
-- 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
```typescript
/**
* @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:
```typescript
// 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
```typescript
// 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
```typescript
// 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
```sql
-- 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):
```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):
```bash
# 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):
```bash
# 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)