# ANÁLISIS DETALLADO: PÁGINA DE ACHIEVEMENTS - STUDENT PORTAL **Fecha:** 2026-01-10 **Proyecto:** Gamilit **Componente:** /achievements (Student Portal) **Estado:** EN ANÁLISIS --- ## ÍNDICE 1. [Resumen Ejecutivo](#1-resumen-ejecutivo) 2. [Arquitectura del Sistema](#2-arquitectura-del-sistema) 3. [Análisis Frontend](#3-análisis-frontend) 4. [Análisis Backend](#4-análisis-backend) 5. [Análisis Base de Datos](#5-análisis-base-de-datos) 6. [Análisis de Tipos e Interfaces](#6-análisis-de-tipos-e-interfaces) 7. [Flujo de Datos Completo](#7-flujo-de-datos-completo) 8. [Problemas Identificados](#8-problemas-identificados) 9. [Dependencias y Relaciones](#9-dependencias-y-relaciones) 10. [Seeds e Integración](#10-seeds-e-integración) 11. [Recomendaciones](#11-recomendaciones) --- ## 1. RESUMEN EJECUTIVO ### 1.1 Descripción General El sistema de Achievements es una funcionalidad de gamificación que permite a los estudiantes: - Ver todos los logros disponibles en el sistema - Rastrear su progreso hacia cada logro - Reclamar recompensas (ML Coins, XP) al completar logros - Filtrar y buscar logros por categoría, rareza y estado ### 1.2 Rutas y Archivos Principales | Capa | Ruta Principal | |------|----------------| | **Página Frontend** | `/home/isem/workspace-v1/projects/gamilit/apps/frontend/src/pages/AchievementsPage.tsx` | | **Componentes Student** | `/home/isem/workspace-v1/projects/gamilit/apps/frontend/src/apps/student/components/achievements/` | | **Controller Backend** | `/home/isem/workspace-v1/projects/gamilit/apps/backend/src/modules/gamification/controllers/achievements.controller.ts` | | **Service Backend** | `/home/isem/workspace-v1/projects/gamilit/apps/backend/src/modules/gamification/services/achievements.service.ts` | | **DDL Achievements** | `/home/isem/workspace-v1/projects/gamilit/apps/database/ddl/schemas/gamification_system/tables/03-achievements.sql` | | **DDL User Achievements** | `/home/isem/workspace-v1/projects/gamilit/apps/database/ddl/schemas/gamification_system/tables/04-user_achievements.sql` | | **Seeds Dev** | `/home/isem/workspace-v1/projects/gamilit/apps/database/seeds/dev/gamification_system/` | ### 1.3 Endpoints API | Método | Endpoint | Descripción | |--------|----------|-------------| | GET | `/api/v1/gamification/achievements` | Obtener todos los achievements | | GET | `/api/v1/gamification/achievements/:id` | Obtener achievement específico | | GET | `/api/v1/gamification/users/:userId/achievements` | Obtener achievements del usuario | | GET | `/api/v1/gamification/users/:userId/achievements/summary` | Resumen estadístico | | POST | `/api/v1/gamification/users/:userId/achievements/:achievementId/claim` | Reclamar recompensas | --- ## 2. ARQUITECTURA DEL SISTEMA ### 2.1 Diagrama de Capas ``` ┌─────────────────────────────────────────────────────────────────────────┐ │ FRONTEND (React + Vite) │ ├─────────────────────────────────────────────────────────────────────────┤ │ pages/AchievementsPage.tsx │ │ ├── GamifiedHeader │ │ ├── AchievementFilter │ │ ├── AchievementCard (grid) │ │ └── AchievementModal │ ├─────────────────────────────────────────────────────────────────────────┤ │ Hooks │ Store (Zustand) │ │ ├── useAuth │ └── achievementsStore.ts │ │ ├── useUserGamification │ ├── achievements[] │ │ └── useAchievementsEnhanced │ ├── stats │ │ │ └── actions │ ├─────────────────────────────────────────────────────────────────────────┤ │ API Layer │ │ ├── achievementsAPI.ts (features/gamification) │ │ └── gamificationApi (shared services) │ └─────────────────────────────────────────────────────────────────────────┘ │ ▼ HTTP ┌─────────────────────────────────────────────────────────────────────────┐ │ BACKEND (NestJS) │ ├─────────────────────────────────────────────────────────────────────────┤ │ Controllers │ │ └── achievements.controller.ts │ ├─────────────────────────────────────────────────────────────────────────┤ │ Services │ │ └── achievements.service.ts │ │ ├── findAll() │ │ ├── getAllUserAchievements() │ │ ├── grantAchievement() │ │ ├── claimRewards() │ │ └── meetsConditions() │ ├─────────────────────────────────────────────────────────────────────────┤ │ Entities │ │ ├── achievement.entity.ts │ │ ├── user-achievement.entity.ts │ │ └── user-stats.entity.ts │ └─────────────────────────────────────────────────────────────────────────┘ │ ▼ TypeORM ┌─────────────────────────────────────────────────────────────────────────┐ │ DATABASE (PostgreSQL) │ ├─────────────────────────────────────────────────────────────────────────┤ │ Schema: gamification_system │ │ ├── achievements (tabla maestra) │ │ ├── user_achievements (progreso usuario) │ │ ├── achievement_categories (metadatos UI) │ │ └── user_stats (estadísticas gamificación) │ ├─────────────────────────────────────────────────────────────────────────┤ │ Funciones SQL │ │ ├── check_and_award_achievements() │ │ └── claim_achievement_reward() │ ├─────────────────────────────────────────────────────────────────────────┤ │ Triggers │ │ └── trg_achievement_unlocked (otorga XP/coins, crea notificación) │ └─────────────────────────────────────────────────────────────────────────┘ ``` --- ## 3. ANÁLISIS FRONTEND ### 3.1 AchievementsPage.tsx - Componente Principal **Ubicación:** `/apps/frontend/src/pages/AchievementsPage.tsx` #### Estados Gestionados | Estado | Tipo | Propósito | |--------|------|-----------| | `allAchievements` | `Achievement[]` | Lista de todos los logros del sistema | | `userAchievements` | `UserAchievement[]` | Progreso del usuario en cada logro | | `summary` | `AchievementSummary | null` | Estadísticas resumidas | | `isLoadingAchievements` | `boolean` | Loading para logros del sistema | | `isLoadingUserData` | `boolean` | Loading para datos del usuario | | `error` | `string | null` | Mensajes de error | | `filter` | `AchievementFilterType` | Filtros activos (categoría, estado, búsqueda, orden) | | `selectedAchievement` | `Achievement | null` | Logro seleccionado para modal | | `isModalOpen` | `boolean` | Control de visibilidad del modal | #### Hooks Utilizados ```typescript const { user, logout } = useAuth(); const { gamificationData } = useUserGamification(user?.id); ``` #### Llamadas a API 1. **Carga inicial de achievements:** ```typescript useEffect(() => { const data = await gamificationApi.getAllAchievements(); setAllAchievements(data); }, []); ``` 2. **Carga de datos del usuario:** ```typescript useEffect(() => { const [userAchData, summaryData] = await Promise.all([ gamificationApi.getUserAchievements(user.id), gamificationApi.getAchievementSummary(user.id).catch(() => null), ]); }, [user?.id]); ``` 3. **Reclamar recompensas:** ```typescript const handleClaimRewards = async (achievementId: string) => { const updatedAchievement = await gamificationApi.claimAchievement(user.id, achievementId); // Update optimista del estado local }; ``` #### Lógica de Negocio (useMemo) 1. **Combinación de datos:** Merge de `allAchievements` + `userAchievements` usando Map 2. **Filtrado:** Por categoría → estado → búsqueda (case-insensitive) 3. **Ordenamiento:** Por nombre, progreso, fecha o rareza 4. **Separación:** Achievements visibles vs. ocultos (isHidden && status === 'locked') 5. **Cálculo de Summary:** Fallback local si API no devuelve summary ### 3.2 Componentes del Student Portal | Componente | Archivo | Propósito | |------------|---------|-----------| | `AchievementsPageHeader` | `AchievementsPageHeader.tsx` | Hero section con estadísticas visuales | | `AchievementFilters` | `AchievementFilters.tsx` | Controles de filtrado (categoría, rareza, estado, búsqueda) | | `AchievementGrid` | `AchievementGrid.tsx` | Grid responsivo de cards | | `AchievementStatistics` | `AchievementStatistics.tsx` | Panel de analytics y breakdown | | `AchievementDetailModal` | `AchievementDetailModal.tsx` | Modal de detalle con navegación | | `AchievementCard` | `features/gamification/social/components/` | Card individual reutilizable | ### 3.3 Hook useAchievementsEnhanced **Ubicación:** `/apps/frontend/src/apps/student/hooks/useAchievementsEnhanced.ts` Proporciona: - Filtrado avanzado con debounce (300ms) - Ordenamiento múltiple - Navegación entre achievements (prev/next) - Persistencia de filtros en localStorage - Cálculo de estadísticas detalladas --- ## 4. ANÁLISIS BACKEND ### 4.1 achievements.controller.ts **Ubicación:** `/apps/backend/src/modules/gamification/controllers/achievements.controller.ts` #### Endpoints Implementados | Decorador | Ruta | Método Service | |-----------|------|----------------| | `@Get('achievements')` | `/api/v1/gamification/achievements` | `findAll(includeSecret)` | | `@Get('achievements/:id')` | `/api/v1/gamification/achievements/:id` | `findById(id)` | | `@Get('users/:userId/achievements')` | `/api/v1/gamification/users/:userId/achievements` | `getAllUserAchievements(userId)` | | `@Get('users/:userId/achievements/summary')` | `/api/v1/gamification/users/:userId/achievements/summary` | `getUserAchievementStats(userId)` | | `@Post('users/:userId/achievements/:achievementId')` | POST grant | `grantAchievement(userId, dto)` | | `@Post('users/:userId/achievements/:achievementId/claim')` | POST claim | `claimRewards(userId, achievementId)` | | `@Patch('achievements/:id')` | PATCH toggle | `updateAchievementStatus(id, isActive)` | ### 4.2 achievements.service.ts **Ubicación:** `/apps/backend/src/modules/gamification/services/achievements.service.ts` #### Métodos Principales | Método | Descripción | |--------|-------------| | `findAll(includeSecret)` | Obtiene achievements activos (opcionalmente secretos) | | `findById(id)` | Obtiene achievement por ID con NotFoundException | | `getAllUserAchievements(userId)` | Obtiene todos los achievements con progreso del usuario | | `grantAchievement(userId, dto)` | Otorga/actualiza progreso de un achievement | | `claimRewards(userId, achievementId)` | Reclama recompensas (valida completado y no reclamado) | | `meetsConditions(userId, userStats, conditions)` | Evalúa si se cumplen condiciones de un achievement | | `detectAndGrantEarned(userId)` | Detecta y otorga automáticamente achievements | | `getUserAchievementStats(userId)` | Calcula estadísticas de achievements del usuario | #### Tipos de Condiciones Soportadas (meetsConditions) | Tipo | Evaluación | |------|------------| | `exercise_completion` | `userStats.exercises_completed >= requirements.exercises_completed` | | `streak` | `userStats.current_streak >= requirements.consecutive_days` | | `module_completion` | Query a `progress_tracking.module_progress` | | `all_modules_completion` | `modules_completed >= X && average_score >= Y` | | `perfect_score` | `userStats.perfect_scores >= requirements.perfect_exercises` | | `skill_mastery` | `userStats.perfect_scores >= 10` | | `exploration` | `modules_completed > 0 || exercises_completed >= 5` | | `social` | Query a `social_features.classroom_members/friendships` | | `special` | `first_login` check | | `module_first_exercise` | Query por `module_code` | | `exercise_score` | Query por `exercise_type` y `min_score` | | `exercise_repetition` | Conteo de ejercicios con score mínimo | | `exercise_speed` | Tiempo de completación | | `content_analysis` | Análisis de contenido | | `module_average_score` | Promedio por módulo | --- ## 5. ANÁLISIS BASE DE DATOS ### 5.1 Tabla: gamification_system.achievements **Ubicación DDL:** `/apps/database/ddl/schemas/gamification_system/tables/03-achievements.sql` #### Columnas Principales | Columna | Tipo | Default | Descripción | |---------|------|---------|-------------| | `id` | UUID | `gen_random_uuid()` | PK | | `tenant_id` | UUID | NULL | Multi-tenant | | `name` | TEXT | - | Nombre del achievement | | `description` | TEXT | NULL | Descripción | | `icon` | TEXT | `'trophy'` | Icono/emoji | | `category` | ENUM | - | achievement_category | | `rarity` | TEXT | `'common'` | common/rare/epic/legendary | | `difficulty_level` | ENUM | `'beginner'` | Nivel de dificultad | | `conditions` | JSONB | `{type, requirements}` | Condiciones para desbloquear | | `rewards` | JSONB | `{xp, ml_coins, badge}` | Recompensas | | `ml_coins_reward` | INTEGER | 0 | ML Coins (duplicado de rewards) | | `is_secret` | BOOLEAN | false | Si está oculto | | `is_active` | BOOLEAN | true | Si está activo | | `is_repeatable` | BOOLEAN | false | Si es repetible | | `order_index` | INTEGER | 0 | Orden en UI | | `points_value` | INTEGER | 0 | XP (duplicado de rewards) | #### Índices - `idx_achievements_active` - WHERE is_active = true - `idx_achievements_category` - Por categoría - `idx_achievements_conditions_gin` - GIN para JSONB - `idx_achievements_secret` - WHERE is_secret = true ### 5.2 Tabla: gamification_system.user_achievements **Ubicación DDL:** `/apps/database/ddl/schemas/gamification_system/tables/04-user_achievements.sql` #### Columnas Principales | Columna | Tipo | Default | Descripción | |---------|------|---------|-------------| | `id` | UUID | `gen_random_uuid()` | PK | | `user_id` | UUID | - | FK a profiles | | `achievement_id` | UUID | - | FK a achievements | | `progress` | INTEGER | 0 | Progreso actual | | `max_progress` | INTEGER | 100 | Progreso máximo | | `is_completed` | BOOLEAN | false | Si está completado | | `completion_percentage` | NUMERIC(5,2) | 0.00 | Porcentaje (0-100) | | `completed_at` | TIMESTAMPTZ | NULL | Fecha de completación | | `notified` | BOOLEAN | false | Si se notificó | | `viewed` | BOOLEAN | false | Si se vio la notificación | | `rewards_claimed` | BOOLEAN | false | Si reclamó recompensas | | `rewards_received` | JSONB | `{}` | Detalle de recompensas | | `progress_data` | JSONB | `{}` | Datos de progreso | | `milestones_reached` | TEXT[] | NULL | Hitos alcanzados | #### Constraints - `UNIQUE (user_id, achievement_id)` - Un usuario no puede duplicar logro - `FK user_id → auth_management.profiles(id) ON DELETE CASCADE` - `FK achievement_id → gamification_system.achievements(id) ON DELETE CASCADE` ### 5.3 ENUM: achievement_category **Valores:** `progress`, `streak`, `completion`, `social`, `special`, `mastery`, `exploration`, `collection`, `hidden` ### 5.4 Trigger: trg_achievement_unlocked **Evento:** AFTER INSERT OR UPDATE en user_achievements **Acciones:** 1. Verifica si `is_completed = true` 2. Otorga XP a `user_stats.total_xp` 3. Otorga ML Coins con row lock 4. Crea notificación en `notifications.notifications` 5. Marca `notified = true` --- ## 6. ANÁLISIS DE TIPOS E INTERFACES ### 6.1 Tipos Canónicos (SSOT) **Ubicación:** `/apps/frontend/src/shared/types/achievement.types.ts` ```typescript type AchievementCategory = 'progress' | 'streak' | 'completion' | 'social' | 'special' | 'mastery' | 'exploration' | 'collection' | 'hidden' type AchievementStatus = 'locked' | 'in_progress' | 'earned' | 'claimed' enum AchievementType { BADGE = 'badge', MILESTONE = 'milestone', SPECIAL = 'special', RANK_PROMOTION = 'rank_promotion', } interface Achievement { id: string; name: string; description: string; icon: string; category: AchievementCategory; type: AchievementType; conditions: AchievementConditionsType; rewards: AchievementReward; isHidden: boolean; rarity?: 'common' | 'rare' | 'epic' | 'legendary'; // ... más campos } interface UserAchievement { id: string; userId: string; achievementId: string; progress: number; earnedAt?: string; claimedAt?: string; achievement: Achievement; status: AchievementStatus; } ``` ### 6.2 Mapeo Backend → Frontend | Backend (snake_case) | Frontend (camelCase) | Transformación | |---------------------|----------------------|----------------| | `name` | `title` | Mapeo directo | | `ml_coins_reward` | `mlCoinsReward` | `rewards?.ml_coins ?? ml_coins_reward` | | `points_value` | `xpReward` | `rewards?.xp ?? points_value` | | `is_secret` | `isHidden` | Mapeo + categoría | | `is_completed` | `isUnlocked` | Mapeo directo | | `completed_at` | `unlockedAt` | Parse a Date | | `completion_percentage` | Parseado | `parseFloat()` - **¡Backend devuelve string!** | --- ## 7. FLUJO DE DATOS COMPLETO ``` Usuario abre /achievements │ ▼ ┌────────────────────────────────────────────┐ │ AchievementsPage.tsx - useEffect (mount) │ │ ├── gamificationApi.getAllAchievements() │ │ └── gamificationApi.getUserAchievements() │ │ gamificationApi.getAchievementSummary()│ └────────────────────────────────────────────┘ │ ▼ HTTP GET ┌────────────────────────────────────────────┐ │ achievements.controller.ts │ │ ├── @Get('achievements') │ │ └── @Get('users/:userId/achievements') │ └────────────────────────────────────────────┘ │ ▼ ┌────────────────────────────────────────────┐ │ achievements.service.ts │ │ ├── findAll() - QueryBuilder │ │ └── getAllUserAchievements() - Repository │ └────────────────────────────────────────────┘ │ ▼ TypeORM ┌────────────────────────────────────────────┐ │ PostgreSQL │ │ ├── gamification_system.achievements │ │ └── gamification_system.user_achievements │ └────────────────────────────────────────────┘ │ ▼ Response ┌────────────────────────────────────────────┐ │ Frontend - Transformación │ │ ├── mapToFrontendAchievement() │ │ └── useMemo combinedAchievements │ └────────────────────────────────────────────┘ │ ▼ Render ┌────────────────────────────────────────────┐ │ UI Components │ │ ├── AchievementCard (grid) │ │ ├── AchievementModal (detalle) │ │ └── AchievementStatistics (analytics) │ └────────────────────────────────────────────┘ ``` --- ## 8. PROBLEMAS IDENTIFICADOS ### 8.1 CRÍTICOS 🔴 | ID | Problema | Ubicación | Impacto | |----|----------|-----------|---------| | **P1** | Función `claim_achievement_reward()` usa columnas inexistentes (`reward_claimed_at`) | DDL functions | Función SQL falla al ejecutarse | | **P2** | Store usa `\|\|` en lugar de `??` para recompensas (0 es falsy) | achievementsStore.ts:172 | Recompensas de 0 podrían fallar | | **P3** | Backend `completion_percentage` es STRING, no se parsea en Store | achievementsStore | Tipo incorrecto en runtime | ### 8.2 IMPORTANTES 🟡 | ID | Problema | Ubicación | Impacto | |----|----------|-----------|---------| | **P4** | Duplicación de `ml_coins_reward` (columna y JSONB `rewards`) | DDL + Backend | Inconsistencia potencial | | **P5** | Duplicación de `points_value` (columna) vs `rewards.xp` | DDL + Backend | Inconsistencia potencial | | **P6** | Alias conflictivo `Achievement` en achievementsTypes.ts | Types | Confusión de tipos | | **P7** | `unlockedAt` es `string` vs `Date` inconsistente | Múltiples archivos | Bugs de tipo | | **P8** | Category mapping incompleto (falta 'streak', 'exploration') | achievementsAPI.ts | Categorías mal mapeadas | | **P9** | ENUM vs Tabla para categorías (2 valores no en tabla) | DDL | Integridad referencial | ### 8.3 MENORES 🟢 | ID | Problema | Ubicación | Impacto | |----|----------|-----------|---------| | **P10** | `rarity` es TEXT no ENUM | DDL achievements | Podría tener valores inválidos | | **P11** | Múltiples timestamps (earnedAt, claimedAt, unlockedAt) | Types | Documentación faltante | --- ## 9. DEPENDENCIAS Y RELACIONES ### 9.1 Dependencias de Tablas ``` gamification_system.achievements ├── FK created_by → auth_management.profiles(id) └── FK tenant_id → auth_management.tenants(id) gamification_system.user_achievements ├── FK user_id → auth_management.profiles(id) └── FK achievement_id → gamification_system.achievements(id) gamification_system.user_stats └── FK user_id → auth_management.profiles(id) ``` ### 9.2 Dependencias de Servicios (Backend) El `AchievementsService` realiza queries cruzadas a: - `progress_tracking.module_progress` - `progress_tracking.exercise_submissions` - `educational_content.modules` - `educational_content.exercises` - `social_features.classroom_members` - `social_features.friendships` ### 9.3 Dependencias Frontend ``` AchievementsPage ├── useAuth (auth context) ├── useUserGamification (React Query) ├── gamificationApi (axios client) ├── GamifiedHeader (shared component) ├── AchievementFilter (student component) ├── AchievementCard (feature component) └── AchievementModal (shared component) ``` --- ## 10. SEEDS E INTEGRACIÓN ### 10.1 Seeds de Achievement Categories **Archivo:** `/apps/database/seeds/dev/gamification_system/01-achievement_categories.sql` | Nombre | Icono | Orden | |--------|-------|-------| | Progreso | 🎯 | 1 | | Racha | 🔥 | 2 | | Completación | ✅ | 3 | | Maestría | 👑 | 4 | | Exploración | 🔍 | 5 | | Social | 👥 | 6 | | Especial | ⭐ | 7 | ### 10.2 Seeds de Achievements **Archivo:** `/apps/database/seeds/dev/gamification_system/04-achievements.sql` **Total:** 20 achievements de demostración | Categoría | Cantidad | Ejemplo | |-----------|----------|---------| | Progress | 5 | "Primeros Pasos" (1 ejercicio) → "Maestro de Lectura" (200 ejercicios) | | Streak | 3 | "Racha 3 Días" → "Racha 30 Días" | | Completion | 4 | "Módulo 1 Completado" → "Completista Total" | | Mastery | 3 | "Perfeccionista" (10 ejercicios 100%) | | Exploration | 2 | "Explorador Curioso" | | Social | 2 | "Compañero de Aula" | | Special | 1 | "Primera Visita" | ### 10.3 Seeds de User Achievements **Archivo:** `/apps/database/seeds/dev/gamification_system/08-user_achievements.sql` **Usuarios de Demo:** 7 usuarios con achievements pre-asignados para testing --- ## 11. RECOMENDACIONES ### 11.1 Correcciones Críticas (Inmediato) 1. **Reparar función SQL `claim_achievement_reward()`:** - Cambiar `reward_claimed_at` por `rewards_claimed` (boolean) - Usar `completed_at` para timestamp 2. **Corregir Store con nullish coalescing:** ```typescript // ANTES mlCoinsReward: ach.rewards?.ml_coins || ach.ml_coins_reward || 0, // DESPUÉS mlCoinsReward: ach.rewards?.ml_coins ?? ach.ml_coins_reward ?? 0, ``` 3. **Parsear completion_percentage en Store:** ```typescript completionPercentage: typeof ach.completion_percentage === 'string' ? parseFloat(ach.completion_percentage) : ach.completion_percentage, ``` ### 11.2 Mejoras de Consistencia (Corto Plazo) 4. **Unificar fuente de recompensas:** - Definir `rewards` JSONB como SSOT - Deprecar columnas `ml_coins_reward` y `points_value` 5. **Estandarizar timestamps:** - Definir `unlockedAt` como campo canónico - Siempre como ISO string en API responses 6. **Completar mapeo de categorías:** ```typescript const categoryMap = { 'streak': 'streak', 'exploration': 'exploration', 'collection': 'collection', // ... completar }; ``` ### 11.3 Mejoras Estructurales (Mediano Plazo) 7. **Convertir `rarity` a ENUM** 8. **Sincronizar ENUM achievement_category con tabla achievement_categories** 9. **Agregar índices para queries comunes del frontend** 10. **Documentar flujo de datos end-to-end** --- ## APÉNDICE A: ARCHIVOS ANALIZADOS ### Frontend - `/apps/frontend/src/pages/AchievementsPage.tsx` - `/apps/frontend/src/apps/student/components/achievements/*.tsx` - `/apps/frontend/src/apps/student/hooks/useAchievementsEnhanced.ts` - `/apps/frontend/src/features/gamification/social/api/achievementsAPI.ts` - `/apps/frontend/src/features/gamification/social/store/achievementsStore.ts` - `/apps/frontend/src/shared/types/achievement.types.ts` ### Backend - `/apps/backend/src/modules/gamification/controllers/achievements.controller.ts` - `/apps/backend/src/modules/gamification/services/achievements.service.ts` - `/apps/backend/src/modules/gamification/entities/achievement.entity.ts` - `/apps/backend/src/modules/gamification/entities/user-achievement.entity.ts` - `/apps/backend/src/modules/gamification/dto/achievements/*.ts` ### Database - `/apps/database/ddl/schemas/gamification_system/tables/03-achievements.sql` - `/apps/database/ddl/schemas/gamification_system/tables/04-user_achievements.sql` - `/apps/database/ddl/schemas/gamification_system/tables/10-achievement_categories.sql` - `/apps/database/ddl/schemas/gamification_system/enums/achievement_category.sql` - `/apps/database/ddl/schemas/gamification_system/functions/check_and_award_achievements.sql` - `/apps/database/ddl/schemas/gamification_system/functions/claim_achievement_reward.sql` - `/apps/database/ddl/schemas/gamification_system/triggers/01-trg_achievement_unlocked.sql` - `/apps/database/seeds/dev/gamification_system/*.sql` --- **Documento generado:** 2026-01-10 **Analista:** Claude (Arquitecto Técnico) **Siguiente Fase:** Planeación basada en análisis detallado