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
6.5 KiB
PLAN DE CORRECCION - ERRORES GAMIFICATION SUMMARY
Fecha: 2026-01-10
Proyecto: Gamilit
Estado: EN PLANEACION
Referencia: ANALISIS-ERRORES-GAMIFICATION-SUMMARY-2026-01-10.md
Conventional Commits: fix(gamification): correct profile lookup by id instead of user_id
0. RESUMEN EJECUTIVO
Problema
Error 500 y 404 en endpoints de gamificación /summary debido a búsqueda incorrecta de profile.
Causa Raíz
El método validateProfileExists busca por profiles.user_id (FK a auth.users) en lugar de profiles.id (PK referenciado por user_stats FK).
Solución
Cambiar la búsqueda de { user_id: userId } a { id: userId } en user-stats.service.ts:52.
Impacto
- Backend: 1 archivo, 1 línea de código
- Base de datos: Ninguno
- Frontend: Ninguno
1. ARCHIVOS A MODIFICAR
1.1 Cambio Principal
| ID | Archivo | Línea | Cambio |
|---|---|---|---|
| CORR-GAM-001 | apps/backend/src/modules/gamification/services/user-stats.service.ts |
52 | Cambiar user_id por id |
1.2 Código Actual vs Nuevo
ANTES (líneas 50-62):
private async validateProfileExists(userId: string): Promise<Profile> {
const profile = await this.profileRepo.findOne({
where: { user_id: userId }, // INCORRECTO
});
if (!profile) {
throw new NotFoundException(
`Profile not found for user ${userId}. User may not be properly initialized. ` +
`Please ensure the user registration process completed successfully.`
);
}
return profile;
}
DESPUÉS (líneas 50-67):
/**
* P0-001: Verifica que el perfil existe antes de operaciones de gamificación
*
* CORR-GAM-001: Corregido para buscar por profiles.id (PK) en lugar de
* profiles.user_id (FK a auth.users). La FK user_stats_user_id_fkey
* referencia profiles(id), no profiles(user_id).
*
* @param userId - El ID del profile (profiles.id), NO el ID de auth.users
* @returns Profile si existe
* @throws NotFoundException si el perfil no existe
*/
private async validateProfileExists(userId: string): Promise<Profile> {
// CORR-GAM-001: Buscar por id (PK) no por user_id (FK a auth.users)
const profile = await this.profileRepo.findOne({
where: { id: userId },
});
if (!profile) {
throw new NotFoundException(
`Profile not found for id ${userId}. User may not be properly initialized. ` +
`Please ensure the user registration process completed successfully.`
);
}
return profile;
}
2. DEPENDENCIAS VERIFICADAS
2.1 Archivos que llaman validateProfileExists
# Grep realizado - Solo 1 llamada:
user-stats.service.ts:86 → this.validateProfileExists(userId)
Conclusión: Solo el método create() usa validateProfileExists, no hay otros consumidores.
2.2 Archivos que serán corregidos automáticamente
Una vez que validateProfileExists funcione correctamente, los siguientes endpoints funcionarán:
| Endpoint | Archivo | Estado Actual | Estado Post-Fix |
|---|---|---|---|
GET /users/:id/summary |
user-stats.controller.ts | 500 | 200 OK |
GET /users/:id/achievements/summary |
achievements.controller.ts | 404 | 200 OK |
GET /users/:id/stats |
user-stats.controller.ts | 404 | 200 OK |
GET /users/:id/rank |
user-stats.controller.ts | 404 | 200 OK |
2.3 Base de Datos
| Objeto | Cambio Requerido |
|---|---|
user_stats tabla |
Ninguno - DDL correcto |
user_stats_user_id_fkey FK |
Ninguno - apunta a profiles(id) correctamente |
profiles tabla |
Ninguno - estructura correcta |
2.4 Frontend
| Archivo | Cambio Requerido |
|---|---|
gamificationAPI.ts |
Ninguno - envía profile.id correcto |
gamification.api.ts |
Ninguno - envía profile.id correcto |
useUserGamification.ts |
Ninguno |
AchievementsPage.tsx |
Ninguno |
3. PLAN DE EJECUCION
Paso 1: Validar que profile existe en BD
SELECT id, user_id, email, display_name, role
FROM auth_management.profiles
WHERE id = 'cccccccc-cccc-cccc-cccc-cccccccccccc';
Paso 2: Aplicar corrección CORR-GAM-001
Modificar apps/backend/src/modules/gamification/services/user-stats.service.ts:
- Línea 52:
{ user_id: userId }→{ id: userId } - Agregar comentario explicativo con ID CORR-GAM-001
Paso 3: Verificar compilación TypeScript
cd apps/backend && npx tsc --noEmit
Paso 4: Probar endpoints manualmente
# Endpoint 1: Summary
curl -X GET http://localhost:3006/api/v1/gamification/users/cccccccc-cccc-cccc-cccc-cccccccccccc/summary \
-H "Authorization: Bearer <token>"
# Endpoint 2: Achievements Summary
curl -X GET http://localhost:3006/api/v1/gamification/users/cccccccc-cccc-cccc-cccc-cccccccccccc/achievements/summary \
-H "Authorization: Bearer <token>"
4. VALIDACION POST-CORRECCION
4.1 Verificar user_stats creado
SELECT id, user_id, level, total_xp, ml_coins, current_rank
FROM gamification_system.user_stats
WHERE user_id = 'cccccccc-cccc-cccc-cccc-cccccccccccc';
Resultado esperado: 1 fila con valores iniciales (level=1, total_xp=0, ml_coins=100)
4.2 Verificar respuesta de endpoints
| Endpoint | Código Esperado | Respuesta Esperada |
|---|---|---|
/summary |
200 | { userId, level, totalXP, mlCoins, rank, ... } |
/achievements/summary |
200 | { total_available, completed, completion_percentage, unclaimed_rewards } |
5. ROLLBACK
Si algo sale mal:
// Revertir línea 52 de user-stats.service.ts
where: { id: userId } // → revertir a:
where: { user_id: userId }
Y eliminar el registro de user_stats creado:
DELETE FROM gamification_system.user_stats
WHERE user_id = 'cccccccc-cccc-cccc-cccc-cccccccccccc';
6. MENSAJE DE COMMIT
fix(gamification): correct profile lookup by id instead of user_id
CORR-GAM-001: The validateProfileExists method was searching for profiles
using profiles.user_id (FK to auth.users) instead of profiles.id (PK).
The FK user_stats_user_id_fkey references profiles(id), so when creating
user_stats records, we must validate the profile exists by its PK (id),
not by its FK to auth.users (user_id).
This fixes:
- Error 500 on GET /gamification/users/:userId/summary
- Error 404 on GET /gamification/users/:userId/achievements/summary
Refs: ANALISIS-ERRORES-GAMIFICATION-SUMMARY-2026-01-10.md
Elaborado por: Claude (Arquitecto Técnico) Fecha: 2026-01-10 Próximo paso: FASE 4 - Validación del Plan