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
587 lines
12 KiB
Markdown
587 lines
12 KiB
Markdown
# C2: Guía de Sincronización Backend → Frontend
|
|
|
|
**Fecha:** 2026-01-10
|
|
**Estado:** DOCUMENTADO
|
|
**Objetivo:** Elevar coherencia Backend→Frontend de 28.2% a 75%+
|
|
|
|
---
|
|
|
|
## Estado Actual
|
|
|
|
```
|
|
DTOs Backend: 124 total
|
|
Types Frontend: 35 implementados
|
|
Coverage: 28.2%
|
|
DTOs Faltantes: 89 (71.8%)
|
|
```
|
|
|
|
---
|
|
|
|
## Prioridad 1: Interfaces Críticas Faltantes
|
|
|
|
### 1.1 UserStats (CRÍTICO - Gamification Core)
|
|
|
|
**Backend:** `apps/backend/src/modules/gamification/entities/user-stats.entity.ts`
|
|
**Frontend a crear:** `apps/frontend/src/shared/types/gamification.types.ts`
|
|
|
|
```typescript
|
|
// Estructura requerida (40 propiedades)
|
|
export interface UserStats {
|
|
id: string;
|
|
user_id: string;
|
|
tenant_id?: string;
|
|
|
|
// Level & XP
|
|
level: number;
|
|
total_xp: number;
|
|
xp_to_next_level: number;
|
|
|
|
// Maya Rank System
|
|
current_rank: MayaRank;
|
|
rank_progress: number;
|
|
|
|
// ML Coins
|
|
ml_coins: number;
|
|
ml_coins_earned_total: number;
|
|
ml_coins_spent_total: number;
|
|
|
|
// Streaks
|
|
current_streak: number;
|
|
max_streak: number;
|
|
streak_started_at?: string;
|
|
last_activity_date?: string;
|
|
|
|
// Progress
|
|
exercises_completed: number;
|
|
exercises_correct: number;
|
|
modules_completed: number;
|
|
achievements_earned: number;
|
|
missions_completed: number;
|
|
|
|
// Rankings
|
|
global_rank_position?: number;
|
|
class_rank_position?: number;
|
|
|
|
// Time tracking
|
|
total_time_spent_seconds: number;
|
|
average_session_duration_seconds: number;
|
|
|
|
// Detailed stats
|
|
accuracy_rate: number;
|
|
fastest_completion_seconds?: number;
|
|
comodines_used_total: number;
|
|
hints_used_total: number;
|
|
|
|
// Social
|
|
friends_count: number;
|
|
challenges_won: number;
|
|
challenges_lost: number;
|
|
|
|
// Metadata
|
|
metadata?: Record<string, unknown>;
|
|
created_at: string;
|
|
updated_at: string;
|
|
}
|
|
|
|
export type MayaRank =
|
|
| 'ajaw'
|
|
| 'nacom'
|
|
| 'ah_kin'
|
|
| 'halach_uinic'
|
|
| 'kukul_kan';
|
|
```
|
|
|
|
**Esfuerzo:** 2 horas
|
|
**Impacto:** Desbloquea toda la UI de gamificación
|
|
|
|
---
|
|
|
|
### 1.2 Module Interface Completa
|
|
|
|
**Backend:** `apps/backend/src/modules/educational/entities/module.entity.ts`
|
|
**Frontend a actualizar:** `apps/frontend/src/shared/types/educational.types.ts`
|
|
|
|
**Propiedades a agregar (31 faltantes):**
|
|
|
|
```typescript
|
|
export interface Module {
|
|
// Existentes...
|
|
|
|
// Gamification (AGREGAR)
|
|
xp_reward: number;
|
|
ml_coins_reward: number;
|
|
|
|
// Academic (AGREGAR)
|
|
grade_levels: string[];
|
|
subjects: string[];
|
|
competencies: string[];
|
|
|
|
// Maya Rank (AGREGAR)
|
|
maya_rank_required?: MayaRank;
|
|
maya_rank_granted?: MayaRank;
|
|
|
|
// Versioning (AGREGAR)
|
|
version: number;
|
|
version_notes?: string;
|
|
reviewed_by?: string;
|
|
reviewed_at?: string;
|
|
|
|
// Metadata (AGREGAR)
|
|
settings?: ModuleSettings;
|
|
metadata?: Record<string, unknown>;
|
|
is_featured: boolean;
|
|
is_demo_module: boolean;
|
|
demo_duration_seconds?: number;
|
|
|
|
// Prerequisites (AGREGAR)
|
|
prerequisite_modules?: string[];
|
|
prerequisite_achievements?: string[];
|
|
|
|
// Statistics (AGREGAR)
|
|
completion_rate?: number;
|
|
average_score?: number;
|
|
total_attempts?: number;
|
|
}
|
|
|
|
export interface ModuleSettings {
|
|
allow_skip: boolean;
|
|
show_hints: boolean;
|
|
time_limit_seconds?: number;
|
|
max_attempts?: number;
|
|
}
|
|
```
|
|
|
|
**Esfuerzo:** 1.5 horas
|
|
|
|
---
|
|
|
|
### 1.3 ExerciseType Enum Completo
|
|
|
|
**Backend:** Definido en múltiples lugares
|
|
**Frontend a actualizar:** `apps/frontend/src/shared/types/educational.types.ts`
|
|
|
|
```typescript
|
|
export enum ExerciseType {
|
|
// Comprensión lectora
|
|
CRUCIGRAMA = 'crucigrama',
|
|
LINEA_TIEMPO = 'linea_tiempo',
|
|
SOPA_LETRAS = 'sopa_letras',
|
|
MAPA_CONCEPTUAL = 'mapa_conceptual',
|
|
EMPAREJAMIENTO = 'emparejamiento',
|
|
|
|
// Pensamiento crítico
|
|
DETECTIVE_TEXTUAL = 'detective_textual',
|
|
CONSTRUCCION_HIPOTESIS = 'construccion_hipotesis',
|
|
PREDICCION_NARRATIVA = 'prediccion_narrativa',
|
|
PUZZLE_CONTEXTO = 'puzzle_contexto',
|
|
RUEDA_INFERENCIAS = 'rueda_inferencias',
|
|
|
|
// Argumentación
|
|
TRIBUNAL_OPINIONES = 'tribunal_opiniones',
|
|
DEBATE_DIGITAL = 'debate_digital',
|
|
ANALISIS_FUENTES = 'analisis_fuentes',
|
|
PODCAST_ARGUMENTATIVO = 'podcast_argumentativo',
|
|
MATRIZ_PERSPECTIVAS = 'matriz_perspectivas',
|
|
|
|
// Media literacy
|
|
VERIFICADOR_FAKE_NEWS = 'verificador_fake_news',
|
|
INFOGRAFIA_INTERACTIVA = 'infografia_interactiva',
|
|
QUIZ_TIKTOK = 'quiz_tiktok',
|
|
NAVEGACION_HIPERTEXTUAL = 'navegacion_hipertextual',
|
|
ANALISIS_MEMES = 'analisis_memes',
|
|
|
|
// Escritura creativa
|
|
DIARIO_INTERACTIVO = 'diario_interactivo',
|
|
RESUMEN_VISUAL = 'resumen_visual',
|
|
COMPRENSION_AUDITIVA = 'comprension_auditiva',
|
|
COLLAGE_PRENSA = 'collage_prensa',
|
|
TEXTO_MOVIMIENTO = 'texto_movimiento',
|
|
CALL_TO_ACTION = 'call_to_action',
|
|
|
|
// Nuevos (sincronizar con DB)
|
|
CAPSULA_TIEMPO = 'capsula_tiempo',
|
|
COLLAGE_DIGITAL = 'collage_digital',
|
|
DIARIO_MULTIMEDIA = 'diario_multimedia',
|
|
COMIC_DIGITAL = 'comic_digital',
|
|
VIDEO_CARTA = 'video_carta',
|
|
VERDADERO_FALSO = 'verdadero_falso',
|
|
COMPLETAR_ESPACIOS = 'completar_espacios',
|
|
}
|
|
```
|
|
|
|
**Componentes a actualizar:**
|
|
- Exercise renderer switch/case
|
|
- Exercise type selector
|
|
- Exercise preview component
|
|
- Exercise analytics dashboard
|
|
|
|
**Esfuerzo:** 1-2 horas
|
|
|
|
---
|
|
|
|
### 1.4 Admin Module Types
|
|
|
|
**Backend DTOs (24 total):** `apps/backend/src/modules/admin/dto/`
|
|
**Frontend a crear:**
|
|
- `apps/frontend/src/shared/types/admin.types.ts`
|
|
- `apps/frontend/src/lib/api/admin.api.ts`
|
|
|
|
```typescript
|
|
// admin.types.ts
|
|
export interface OrganizationDto {
|
|
id: string;
|
|
name: string;
|
|
slug: string;
|
|
settings: OrganizationSettings;
|
|
is_active: boolean;
|
|
created_at: string;
|
|
updated_at: string;
|
|
}
|
|
|
|
export interface UserDetailsDto {
|
|
id: string;
|
|
email: string;
|
|
first_name: string;
|
|
last_name: string;
|
|
role: UserRole;
|
|
organization_id?: string;
|
|
is_active: boolean;
|
|
last_login_at?: string;
|
|
created_at: string;
|
|
}
|
|
|
|
export interface SystemHealthDto {
|
|
status: 'healthy' | 'degraded' | 'down';
|
|
database: HealthCheck;
|
|
cache: HealthCheck;
|
|
storage: HealthCheck;
|
|
uptime_seconds: number;
|
|
version: string;
|
|
}
|
|
|
|
export interface HealthCheck {
|
|
status: 'up' | 'down';
|
|
latency_ms: number;
|
|
last_check: string;
|
|
}
|
|
|
|
// ... 20 DTOs más (ver backend)
|
|
```
|
|
|
|
**Esfuerzo:** 3 horas
|
|
|
|
---
|
|
|
|
## Prioridad 2: Interfaces Incompletas
|
|
|
|
### 2.1 Achievement Interface
|
|
|
|
**Propiedades a agregar (13 faltantes):**
|
|
|
|
```typescript
|
|
export interface Achievement {
|
|
// Existentes...
|
|
|
|
// AGREGAR:
|
|
ml_coins_reward: number;
|
|
xp_reward: number;
|
|
difficulty_level: DifficultyLevel;
|
|
unlock_message?: string;
|
|
locked_message?: string;
|
|
is_secret: boolean; // Renombrar de isHidden
|
|
is_repeatable: boolean;
|
|
max_completions?: number;
|
|
cooldown_hours?: number;
|
|
prerequisites?: string[];
|
|
trigger_type: AchievementTrigger;
|
|
trigger_config: Record<string, unknown>;
|
|
tier: AchievementTier;
|
|
}
|
|
|
|
export type AchievementTrigger =
|
|
| 'exercise_completion'
|
|
| 'streak_milestone'
|
|
| 'xp_threshold'
|
|
| 'rank_promotion'
|
|
| 'social_action';
|
|
|
|
export type AchievementTier = 'bronze' | 'silver' | 'gold' | 'platinum';
|
|
```
|
|
|
|
**Esfuerzo:** 1 hora
|
|
|
|
---
|
|
|
|
### 2.2 Classroom Interface
|
|
|
|
**Propiedades a agregar (16 faltantes):**
|
|
|
|
```typescript
|
|
export interface Classroom {
|
|
// Existentes...
|
|
|
|
// AGREGAR:
|
|
grade_level: string;
|
|
section?: string;
|
|
subject: string;
|
|
academic_year: string;
|
|
schedule?: ClassroomSchedule;
|
|
meeting_url?: string;
|
|
max_students: number;
|
|
current_students: number;
|
|
is_active: boolean;
|
|
settings: ClassroomSettings;
|
|
modules_assigned: string[];
|
|
start_date?: string;
|
|
end_date?: string;
|
|
cover_image_url?: string;
|
|
description?: string;
|
|
metadata?: Record<string, unknown>;
|
|
}
|
|
|
|
export interface ClassroomSchedule {
|
|
days: DayOfWeek[];
|
|
start_time: string; // HH:mm
|
|
end_time: string;
|
|
timezone: string;
|
|
}
|
|
|
|
export interface ClassroomSettings {
|
|
allow_late_submissions: boolean;
|
|
show_leaderboard: boolean;
|
|
notify_teacher_on_completion: boolean;
|
|
}
|
|
```
|
|
|
|
**Esfuerzo:** 1 hora
|
|
|
|
---
|
|
|
|
### 2.3 ExerciseSubmission Interface
|
|
|
|
**Propiedades a agregar (10 faltantes):**
|
|
|
|
```typescript
|
|
export interface ExerciseSubmission {
|
|
// Existentes...
|
|
|
|
// AGREGAR:
|
|
comodines_used: ComodinUsage[];
|
|
hint_used: boolean;
|
|
hints_count: number;
|
|
ml_coins_spent: number;
|
|
time_spent_seconds: number;
|
|
attempt_number: number;
|
|
status: SubmissionStatus;
|
|
started_at: string;
|
|
graded_at?: string;
|
|
graded_by?: string; // 'auto' | user_id
|
|
}
|
|
|
|
export interface ComodinUsage {
|
|
comodin_type: string;
|
|
used_at: string;
|
|
}
|
|
|
|
export type SubmissionStatus =
|
|
| 'in_progress'
|
|
| 'submitted'
|
|
| 'graded'
|
|
| 'expired';
|
|
|
|
// NOTA: Remover attempt_id que no existe en backend
|
|
```
|
|
|
|
**Esfuerzo:** 45 minutos
|
|
|
|
---
|
|
|
|
## Prioridad 3: Módulos Sin Cobertura (0%)
|
|
|
|
### 3.1 Missions Module
|
|
|
|
**Backend DTOs:** 3
|
|
**Archivos a crear:**
|
|
- `apps/frontend/src/shared/types/missions.types.ts`
|
|
|
|
```typescript
|
|
export interface Mission {
|
|
id: string;
|
|
name: string;
|
|
description: string;
|
|
mission_type: MissionType;
|
|
target_value: number;
|
|
current_progress: number;
|
|
rewards: MissionRewards;
|
|
expires_at?: string;
|
|
is_completed: boolean;
|
|
completed_at?: string;
|
|
}
|
|
|
|
export type MissionType =
|
|
| 'daily'
|
|
| 'weekly'
|
|
| 'special'
|
|
| 'event';
|
|
|
|
export interface MissionRewards {
|
|
xp: number;
|
|
ml_coins: number;
|
|
achievement_id?: string;
|
|
}
|
|
```
|
|
|
|
### 3.2 Notifications Module
|
|
|
|
**Backend DTOs:** 4
|
|
**Archivos a crear:**
|
|
- `apps/frontend/src/shared/types/notifications.types.ts`
|
|
|
|
```typescript
|
|
export interface Notification {
|
|
id: string;
|
|
user_id: string;
|
|
type: NotificationType;
|
|
title: string;
|
|
message: string;
|
|
data?: Record<string, unknown>;
|
|
is_read: boolean;
|
|
created_at: string;
|
|
read_at?: string;
|
|
}
|
|
|
|
export type NotificationType =
|
|
| 'achievement_unlocked'
|
|
| 'mission_completed'
|
|
| 'level_up'
|
|
| 'friend_request'
|
|
| 'classroom_announcement'
|
|
| 'system';
|
|
```
|
|
|
|
### 3.3 Powerups/Comodines Module
|
|
|
|
**Backend DTOs:** 4
|
|
**Archivos a crear:**
|
|
- `apps/frontend/src/shared/types/powerups.types.ts`
|
|
|
|
```typescript
|
|
export interface Comodin {
|
|
id: string;
|
|
name: string;
|
|
description: string;
|
|
comodin_type: ComodinType;
|
|
cost_ml_coins: number;
|
|
effect_config: ComodinEffect;
|
|
icon_url?: string;
|
|
is_active: boolean;
|
|
}
|
|
|
|
export type ComodinType =
|
|
| 'fifty_fifty'
|
|
| 'extra_time'
|
|
| 'hint'
|
|
| 'skip_question'
|
|
| 'double_xp';
|
|
|
|
export interface ComodinEffect {
|
|
duration_seconds?: number;
|
|
magnitude?: number;
|
|
target?: string;
|
|
}
|
|
|
|
export interface ComodinInventory {
|
|
user_id: string;
|
|
comodin_id: string;
|
|
quantity: number;
|
|
acquired_at: string;
|
|
}
|
|
```
|
|
|
|
### 3.4 Content Module
|
|
|
|
**Backend DTOs:** 6
|
|
**Similar a educational pero para contenido estático**
|
|
|
|
**Esfuerzo total módulos:** ~9 horas
|
|
|
|
---
|
|
|
|
## Checklist de Implementación
|
|
|
|
### Fase 1: Interfaces Críticas (4-6 horas)
|
|
- [ ] Crear `gamification.types.ts` con UserStats
|
|
- [ ] Actualizar Module interface
|
|
- [ ] Completar ExerciseType enum
|
|
- [ ] Crear `admin.types.ts`
|
|
|
|
### Fase 2: Interfaces Incompletas (3 horas)
|
|
- [ ] Actualizar Achievement interface
|
|
- [ ] Actualizar Classroom interface
|
|
- [ ] Actualizar ExerciseSubmission interface
|
|
|
|
### Fase 3: Módulos Faltantes (9 horas)
|
|
- [ ] Crear `missions.types.ts`
|
|
- [ ] Crear `notifications.types.ts`
|
|
- [ ] Crear `powerups.types.ts`
|
|
- [ ] Crear content types
|
|
|
|
### Fase 4: API Clients (3 horas)
|
|
- [ ] Crear `admin.api.ts`
|
|
- [ ] Crear `missions.api.ts`
|
|
- [ ] Crear `notifications.api.ts`
|
|
- [ ] Crear `powerups.api.ts`
|
|
|
|
---
|
|
|
|
## Métricas Objetivo
|
|
|
|
| Métrica | Actual | Post-Fase 1 | Post-Fase 3 |
|
|
|---------|--------|-------------|-------------|
|
|
| DTOs implementados | 35 | 60 | 95 |
|
|
| Coverage | 28.2% | 48% | 77% |
|
|
| Interfaces críticas | 0/4 | 4/4 | 4/4 |
|
|
| Módulos cubiertos | 5/9 | 6/9 | 9/9 |
|
|
|
|
---
|
|
|
|
## Notas de Naming Consistency
|
|
|
|
### Convención Recomendada
|
|
|
|
Para mantener consistencia con backend NestJS:
|
|
|
|
1. **Propiedades:** `snake_case` (coincide con DB y backend)
|
|
2. **Types/Interfaces:** `PascalCase`
|
|
3. **Enums:** `SCREAMING_SNAKE_CASE` para values, `PascalCase` para type
|
|
|
|
### Transformaciones Automáticas
|
|
|
|
Considerar implementar interceptor/transformer:
|
|
|
|
```typescript
|
|
// api-client.ts
|
|
import { snakeToCamel, camelToSnake } from './utils';
|
|
|
|
export const apiClient = {
|
|
get: async <T>(url: string): Promise<T> => {
|
|
const response = await fetch(url);
|
|
const data = await response.json();
|
|
return snakeToCamel(data) as T;
|
|
},
|
|
post: async <T>(url: string, body: unknown): Promise<T> => {
|
|
const response = await fetch(url, {
|
|
method: 'POST',
|
|
body: JSON.stringify(camelToSnake(body)),
|
|
});
|
|
return snakeToCamel(await response.json()) as T;
|
|
},
|
|
};
|
|
```
|
|
|
|
---
|
|
|
|
**Documentado por:** Documentation-Architect (Fase C2)
|
|
**Fecha:** 2026-01-10
|
|
**Próximo paso:** Entregar a NEXUS-FRONTEND para implementación
|