workspace-v1/orchestration/analisis/ANALISIS-ERRORES-GAMIFICATION-SUMMARY-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

7.9 KiB

ANALISIS DETALLADO - ERRORES EN GAMIFICATION SUMMARY ENDPOINTS

Fecha: 2026-01-10 Proyecto: Gamilit Estado: EN ANALISIS Conventional Commits: fix(gamification): correct profile lookup in user stats validation


1. RESUMEN DE ERRORES

# Endpoint Codigo Error Archivo Origen
ERR-GAM-001 GET /gamification/users/:userId/summary 500 user_stats_user_id_fkey FK violation user-stats.service.ts:329
ERR-GAM-002 GET /gamification/users/:userId/achievements/summary 404 Resource not found achievements.service.ts:803

Usuario afectado: cccccccc-cccc-cccc-cccc-cccccccccccc (Carlos Herrera - admin_teacher)


2. ANALISIS DETALLADO - ERR-GAM-001

2.1 Traza del Error

1. Frontend → GET /api/v1/gamification/users/cccccccc-.../summary
2. user-stats.controller.ts:158 → getUserGamificationSummary(userId)
3. user-stats.service.ts:320 → getUserGamificationSummary(userId)
4. user-stats.service.ts:325 → findByUserId(userId) → NotFoundException
5. user-stats.service.ts:329 → create(userId) ← ERROR AQUI
6. user-stats.service.ts:86 → validateProfileExists(userId)
7. user-stats.service.ts:51-53 → profileRepo.findOne({ where: { user_id: userId } })
                                                        ↑ INCORRECTO

2.2 Causa Raiz

El método validateProfileExists busca por columna incorrecta.

// CODIGO ACTUAL (INCORRECTO) - user-stats.service.ts:51-53
private async validateProfileExists(userId: string): Promise<Profile> {
  const profile = await this.profileRepo.findOne({
    where: { user_id: userId },  // ← BUSCA profiles.user_id = userId
  });

Problema:

  • La FK en user_stats es: REFERENCES auth_management.profiles(id)
  • Esto significa que user_stats.user_id debe contener un profiles.id (PK)
  • El método busca profiles.user_id = userId, pero profiles.user_id es una FK a auth.users
  • La búsqueda no encuentra el profile porque el ID es un profiles.id, no un profiles.user_id

2.3 Estructura de Datos Relevante

-- auth_management.profiles
id uuid PRIMARY KEY,          -- PK del profile (ej: cccccccc-cccc-...)
user_id uuid,                 -- FK → auth.users (puede ser null)

-- gamification_system.user_stats
user_id uuid NOT NULL,        -- FK → profiles.id (NO profiles.user_id)
CONSTRAINT user_stats_user_id_fkey FOREIGN KEY (user_id)
    REFERENCES auth_management.profiles(id) ON DELETE CASCADE

2.4 Flujo Correcto vs Incorrecto

FLUJO INCORRECTO (actual):
userId = 'cccccccc-...' (profiles.id)
→ SELECT * FROM profiles WHERE user_id = 'cccccccc-...'
→ No encuentra (porque user_id es FK a auth.users, no el PK)
→ Lanza NotFoundException (pero debería retornar profile)
→ Si pasara, intentaría INSERT INTO user_stats(user_id) VALUES('cccccccc-...')
→ FK falla porque busca profiles.id = 'cccccccc-...' y no lo encuentra por la query incorrecta

FLUJO CORRECTO (esperado):
userId = 'cccccccc-...' (profiles.id)
→ SELECT * FROM profiles WHERE id = 'cccccccc-...'
→ Encuentra el profile
→ INSERT INTO user_stats(user_id) VALUES('cccccccc-...')
→ FK valida correctamente profiles.id = 'cccccccc-...'

3. ANALISIS DETALLADO - ERR-GAM-002

3.1 Traza del Error

1. Frontend → GET /api/v1/gamification/users/cccccccc-.../achievements/summary
2. achievements.controller.ts:343 → getAchievementSummary(userId)
3. achievements.service.ts:793 → getUserAchievementStats(userId)
4. achievements.service.ts:799-801 → userStatsRepo.findOne({ where: { user_id: userId } })
5. achievements.service.ts:803-805 → throw NotFoundException (user stats not found)

3.2 Causa Raiz

Dependencia transitiva del ERR-GAM-001.

El método getUserAchievementStats depende de que exista un registro en user_stats:

// achievements.service.ts:799-805
const userStats = await this.userStatsRepo.findOne({
  where: { user_id: userId },
});

if (!userStats) {
  throw new NotFoundException(`User stats not found for ${userId}`);
}

Como el ERR-GAM-001 impide crear registros en user_stats, este endpoint también falla.

3.3 Por qué retorna 404 en lugar de mensaje personalizado

El NotFoundException en NestJS retorna:

{
  "statusCode": 404,
  "message": "User stats not found for cccccccc-..."
}

Pero el frontend muestra "Resource not found" que es el handler genérico del apiClient.


4. DEPENDENCIAS IDENTIFICADAS

4.1 Archivos que usan validateProfileExists

Archivo Método Línea Impacto
user-stats.service.ts create() 86 Directo - causa ERR-GAM-001

4.2 Archivos que dependen de user_stats existente

Archivo Método Línea Impacto
achievements.service.ts getUserAchievementStats() 799 Transitivo - causa ERR-GAM-002
achievements.service.ts detectAndGrantEarned() 310 Transitivo
user-stats.service.ts findByUserId() 68 Transitivo
user-stats.controller.ts getUserStats() 91 Transitivo
user-stats.controller.ts getUserRank() 206 Transitivo

4.3 Frontend afectado

Archivo Hook/Función Endpoint
gamificationAPI.ts:116 getUserGamificationSummary() /summary
gamification.api.ts:154 getAchievementSummary() /achievements/summary
useUserGamification.ts:55 queryFn /summary
AchievementsPage.tsx:98 loadUserData() /achievements/summary

5. FK VERIFICATION

5.1 DDL de user_stats (líneas 164-165)

-- apps/database/ddl/schemas/gamification_system/tables/01-user_stats.sql
CONSTRAINT user_stats_user_id_fkey FOREIGN KEY (user_id)
    REFERENCES auth_management.profiles(id) ON DELETE CASCADE

5.2 DDL de profiles (líneas 48, 52)

-- apps/database/ddl/schemas/auth_management/tables/03-profiles.sql
CONSTRAINT profiles_pkey PRIMARY KEY (id),
CONSTRAINT profiles_user_id_key UNIQUE (user_id),  -- FK a auth.users

5.3 Confirmación de la FK

La FK user_stats_user_id_fkey referencia profiles(id) que es el PK, NO profiles(user_id) que es FK a auth.users.


6. SOLUCION PROPUESTA

6.1 Corrección en user-stats.service.ts

Cambiar de:

private async validateProfileExists(userId: string): Promise<Profile> {
  const profile = await this.profileRepo.findOne({
    where: { user_id: userId },
  });

A:

private async validateProfileExists(userId: string): Promise<Profile> {
  const profile = await this.profileRepo.findOne({
    where: { id: userId },  // Buscar por PK (id) en lugar de FK (user_id)
  });

6.2 Impacto de la Corrección

Archivo Cambio Requerido
user-stats.service.ts Línea 52: { user_id: userId }{ id: userId }

No se requieren cambios en:

  • Base de datos (DDL correcto)
  • Frontend (usa el profile.id correcto)
  • Otros servicios (dependen de user_stats que se creará correctamente)

7. VALIDACION PRE-CORRECCION

7.1 Verificar que el profile existe

SELECT id, user_id, email, role
FROM auth_management.profiles
WHERE id = 'cccccccc-cccc-cccc-cccc-cccccccccccc';

Resultado esperado: 1 fila con Carlos Herrera

7.2 Verificar user_stats no existe

SELECT * FROM gamification_system.user_stats
WHERE user_id = 'cccccccc-cccc-cccc-cccc-cccccccccccc';

Resultado esperado: 0 filas (por eso intenta crear)


8. RIESGOS

Riesgo Probabilidad Mitigación
Otros métodos usan user_id incorrectamente Baja Grep exhaustivo realizado
Tests fallan después del cambio Media Actualizar mocks si es necesario
Nomenclatura confusa userId vs profile.id Alta Agregar comentario aclaratorio

Elaborado por: Claude (Arquitecto Técnico) Fecha: 2026-01-10 Próximo paso: FASE 3 - Planeación