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

313 lines
11 KiB
Markdown

# 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:**
```typescript
// 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:**
```typescript
// 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:**
```typescript
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