- Configure workspace Git repository with comprehensive .gitignore - Add Odoo as submodule for ERP reference code - Include documentation: SETUP.md, GIT-STRUCTURE.md - Add gitignore templates for projects (backend, frontend, database) - Structure supports independent repos per project/subproject level Workspace includes: - core/ - Reusable patterns, modules, orchestration system - projects/ - Active projects (erp-suite, gamilit, trading-platform, etc.) - knowledge-base/ - Reference code and patterns (includes Odoo submodule) - devtools/ - Development tools and templates - customers/ - Client implementations template 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
385 lines
11 KiB
Markdown
385 lines
11 KiB
Markdown
# Estructura de Features Frontend
|
|
|
|
**Versión:** 1.1.0
|
|
**Última Actualización:** 2025-11-29
|
|
**Aplica a:** apps/frontend/src/features/
|
|
|
|
---
|
|
|
|
## Resumen
|
|
|
|
El frontend de GAMILIT organiza la funcionalidad en "features" - módulos autocontenidos que agrupan componentes, hooks, stores y servicios relacionados con un dominio específico.
|
|
|
|
---
|
|
|
|
## Features Disponibles (12 total)
|
|
|
|
| Feature | Ubicación | Descripción |
|
|
|---------|-----------|-------------|
|
|
| **admin** | `features/admin/` | Panel administrativo |
|
|
| **assignments** | `features/assignments/` | Tareas asignadas a estudiantes |
|
|
| **auth** | `features/auth/` | Login, registro, recuperación de contraseña |
|
|
| **content** | `features/content/` | Gestión de contenido educativo |
|
|
| **exercises** | `features/exercises/` | Visualización y resolución de ejercicios |
|
|
| **gamification** | `features/gamification/` | Logros, rangos, ML Coins, leaderboard |
|
|
| **mechanics** | `features/mechanics/` | 23 mecánicas de ejercicios organizadas por módulo |
|
|
| **missions** | `features/missions/` | Misiones diarias y semanales |
|
|
| **notifications** | `features/notifications/` | Centro de notificaciones |
|
|
| **progress** | `features/progress/` | Seguimiento de progreso del estudiante |
|
|
| **social** | `features/social/` | Aulas, equipos, retos (en `apps/`) |
|
|
| **teacher** | `features/teacher/` | Portal del docente (en `apps/`) |
|
|
|
|
---
|
|
|
|
## Estructura Estándar de una Feature
|
|
|
|
```
|
|
features/ejemplo/
|
|
├── components/ # Componentes React específicos
|
|
│ ├── EjemploCard.tsx
|
|
│ ├── EjemploList.tsx
|
|
│ ├── EjemploForm.tsx
|
|
│ └── index.ts # Barrel exports
|
|
├── hooks/ # Custom hooks
|
|
│ ├── useEjemplo.ts
|
|
│ ├── useEjemploMutation.ts
|
|
│ └── index.ts
|
|
├── services/ # API calls
|
|
│ ├── ejemplo.service.ts
|
|
│ └── index.ts
|
|
├── stores/ # Zustand stores (si aplica)
|
|
│ ├── ejemplo.store.ts
|
|
│ └── index.ts
|
|
├── types/ # TypeScript types/interfaces
|
|
│ ├── ejemplo.types.ts
|
|
│ └── index.ts
|
|
├── utils/ # Utilidades específicas
|
|
│ └── ejemplo.utils.ts
|
|
├── pages/ # Páginas de la feature (si tiene rutas)
|
|
│ └── EjemploPage.tsx
|
|
└── index.ts # Barrel export principal
|
|
```
|
|
|
|
---
|
|
|
|
## Ejemplos de Features
|
|
|
|
### auth/
|
|
|
|
```
|
|
features/auth/
|
|
├── components/
|
|
│ ├── LoginForm.tsx
|
|
│ ├── RegisterForm.tsx
|
|
│ ├── ForgotPasswordForm.tsx
|
|
│ └── PasswordStrengthIndicator.tsx
|
|
├── hooks/
|
|
│ ├── useAuth.ts # Estado de autenticación
|
|
│ ├── useLogin.ts # Mutación de login
|
|
│ └── useRegister.ts # Mutación de registro
|
|
├── services/
|
|
│ └── auth.service.ts # Llamadas a API
|
|
├── stores/
|
|
│ └── auth.store.ts # Zustand store para auth
|
|
├── types/
|
|
│ ├── auth.types.ts # LoginDto, UserResponse, etc.
|
|
│ └── index.ts
|
|
└── index.ts
|
|
```
|
|
|
|
### gamification/
|
|
|
|
```
|
|
features/gamification/
|
|
├── components/
|
|
│ ├── AchievementCard.tsx
|
|
│ ├── AchievementList.tsx
|
|
│ ├── RankBadge.tsx
|
|
│ ├── XpProgressBar.tsx
|
|
│ ├── MlCoinsDisplay.tsx
|
|
│ ├── LeaderboardTable.tsx
|
|
│ └── ComodinCard.tsx
|
|
├── hooks/
|
|
│ ├── useUserStats.ts
|
|
│ ├── useAchievements.ts
|
|
│ ├── useLeaderboard.ts
|
|
│ ├── useComodines.ts
|
|
│ └── usePurchaseComodin.ts
|
|
├── services/
|
|
│ ├── gamification.service.ts
|
|
│ ├── achievements.service.ts
|
|
│ └── leaderboard.service.ts
|
|
├── types/
|
|
│ ├── user-stats.types.ts
|
|
│ ├── achievement.types.ts
|
|
│ ├── rank.types.ts
|
|
│ └── comodin.types.ts
|
|
└── index.ts
|
|
```
|
|
|
|
### exercises/
|
|
|
|
```
|
|
features/exercises/
|
|
├── components/
|
|
│ ├── ExerciseRenderer.tsx # Renderiza según tipo
|
|
│ ├── ExerciseProgress.tsx
|
|
│ ├── FeedbackDisplay.tsx
|
|
│ └── mechanics/ # Componentes por mecánica
|
|
│ ├── TimelineExercise.tsx
|
|
│ ├── FillInBlankExercise.tsx
|
|
│ ├── TrueFalseExercise.tsx
|
|
│ ├── WordSearchExercise.tsx
|
|
│ └── ... (23 tipos)
|
|
├── hooks/
|
|
│ ├── useExercise.ts
|
|
│ ├── useSubmitAnswer.ts
|
|
│ └── useExerciseTimer.ts
|
|
├── services/
|
|
│ └── exercises.service.ts
|
|
└── types/
|
|
├── exercise.types.ts
|
|
└── answer.types.ts
|
|
```
|
|
|
|
### mechanics/ (NUEVO v1.1)
|
|
|
|
Feature que contiene las 23 mecánicas de ejercicios organizadas por módulo curricular.
|
|
|
|
```
|
|
features/mechanics/
|
|
├── index.ts # Barrel export de todas las mecánicas
|
|
├── shared/ # Componentes compartidos entre mecánicas
|
|
│ ├── FeedbackModal.tsx
|
|
│ ├── TimerDisplay.tsx
|
|
│ └── ScoreDisplay.tsx
|
|
├── auxiliar/ # Mecánicas auxiliares
|
|
│ ├── CrucigramaExercise/
|
|
│ ├── SopaLetrasExercise/
|
|
│ └── ...
|
|
├── module1/ # Mecánicas del Módulo 1
|
|
│ ├── TimelineExercise/
|
|
│ ├── FillInBlankExercise/
|
|
│ ├── TrueFalseExercise/
|
|
│ └── ...
|
|
├── module2/ # Mecánicas del Módulo 2
|
|
│ ├── CauseEffectMatching/
|
|
│ ├── DetectiveTextual/
|
|
│ └── ...
|
|
├── module3/ # Mecánicas del Módulo 3
|
|
├── module4/ # Mecánicas del Módulo 4
|
|
└── module5/ # Mecánicas del Módulo 5
|
|
```
|
|
|
|
**Nota:** Cada mecánica tiene su propia carpeta con:
|
|
- Componente principal (`*.tsx`)
|
|
- Types locales (`types.ts`)
|
|
- Estilos específicos (si aplica)
|
|
|
|
### missions/ (NUEVO v1.1)
|
|
|
|
Feature para misiones diarias y semanales.
|
|
|
|
```
|
|
features/missions/
|
|
├── store/
|
|
│ └── missionsStore.ts # Zustand store para misiones
|
|
├── MIGRATION-GUIDE.md # Guía de migración desde API deprecated
|
|
└── (componentes migrados desde gamification/missions/)
|
|
```
|
|
|
|
**Nota:** Los types de Mission están en `@features/gamification/missions/types/missionsTypes.ts` (SSOT).
|
|
|
|
### assignments/ (NUEVO v1.1 - P1-002)
|
|
|
|
Feature para tareas asignadas a estudiantes.
|
|
|
|
```
|
|
features/assignments/
|
|
└── store/
|
|
└── studentAssignmentsStore.ts # Zustand store para assignments de estudiante
|
|
```
|
|
|
|
**API:** `@services/api/studentAssignmentsAPI.ts`
|
|
**Página:** `@apps/student/pages/AssignmentsPage.tsx`
|
|
|
|
---
|
|
|
|
## Patrones de Componentes
|
|
|
|
### Componente con Hook de Datos
|
|
|
|
```typescript
|
|
// features/gamification/components/AchievementList.tsx
|
|
import { useAchievements } from '../hooks/useAchievements';
|
|
import { AchievementCard } from './AchievementCard';
|
|
|
|
export const AchievementList: React.FC = () => {
|
|
const { data: achievements, isLoading, error } = useAchievements();
|
|
|
|
if (isLoading) return <LoadingSpinner />;
|
|
if (error) return <ErrorMessage error={error} />;
|
|
|
|
return (
|
|
<div className="grid grid-cols-2 gap-4">
|
|
{achievements?.map((achievement) => (
|
|
<AchievementCard key={achievement.id} achievement={achievement} />
|
|
))}
|
|
</div>
|
|
);
|
|
};
|
|
```
|
|
|
|
### Componente Presentacional
|
|
|
|
```typescript
|
|
// features/gamification/components/RankBadge.tsx
|
|
import { MayaRank } from '../types/rank.types';
|
|
|
|
interface RankBadgeProps {
|
|
rank: MayaRank;
|
|
size?: 'sm' | 'md' | 'lg';
|
|
showLabel?: boolean;
|
|
}
|
|
|
|
export const RankBadge: React.FC<RankBadgeProps> = ({
|
|
rank,
|
|
size = 'md',
|
|
showLabel = true,
|
|
}) => {
|
|
const sizeClasses = {
|
|
sm: 'w-8 h-8',
|
|
md: 'w-12 h-12',
|
|
lg: 'w-16 h-16',
|
|
};
|
|
|
|
return (
|
|
<div className="flex items-center gap-2">
|
|
<img
|
|
src={rank.iconUrl}
|
|
alt={rank.name}
|
|
className={sizeClasses[size]}
|
|
/>
|
|
{showLabel && <span className="font-medium">{rank.name}</span>}
|
|
</div>
|
|
);
|
|
};
|
|
```
|
|
|
|
---
|
|
|
|
## Barrel Exports
|
|
|
|
### feature/index.ts
|
|
|
|
```typescript
|
|
// features/gamification/index.ts
|
|
|
|
// Components
|
|
export { AchievementCard } from './components/AchievementCard';
|
|
export { AchievementList } from './components/AchievementList';
|
|
export { RankBadge } from './components/RankBadge';
|
|
export { XpProgressBar } from './components/XpProgressBar';
|
|
export { MlCoinsDisplay } from './components/MlCoinsDisplay';
|
|
|
|
// Hooks
|
|
export { useUserStats } from './hooks/useUserStats';
|
|
export { useAchievements } from './hooks/useAchievements';
|
|
export { useLeaderboard } from './hooks/useLeaderboard';
|
|
|
|
// Types
|
|
export type { UserStats, Achievement, MayaRank } from './types';
|
|
```
|
|
|
|
### Uso en otros lugares
|
|
|
|
```typescript
|
|
// Importar desde la feature
|
|
import { RankBadge, useUserStats } from '@/features/gamification';
|
|
|
|
// NO importar archivos internos directamente
|
|
// import { RankBadge } from '@/features/gamification/components/RankBadge'; ❌
|
|
```
|
|
|
|
---
|
|
|
|
## Comunicación Entre Features
|
|
|
|
### Usando Stores Compartidos
|
|
|
|
```typescript
|
|
// En gamification: actualizar stats después de logro
|
|
const { refetchStats } = useUserStats();
|
|
await grantAchievement(achievementId);
|
|
refetchStats();
|
|
```
|
|
|
|
### Usando Eventos
|
|
|
|
```typescript
|
|
// features/exercises/hooks/useSubmitAnswer.ts
|
|
import { useQueryClient } from '@tanstack/react-query';
|
|
|
|
export const useSubmitAnswer = () => {
|
|
const queryClient = useQueryClient();
|
|
|
|
return useMutation({
|
|
mutationFn: submitAnswer,
|
|
onSuccess: (result) => {
|
|
// Invalidar queries de otras features
|
|
queryClient.invalidateQueries({ queryKey: ['user-stats'] });
|
|
queryClient.invalidateQueries({ queryKey: ['achievements'] });
|
|
},
|
|
});
|
|
};
|
|
```
|
|
|
|
---
|
|
|
|
## Páginas y Rutas
|
|
|
|
Las páginas de cada feature se registran en el router principal:
|
|
|
|
```typescript
|
|
// src/router/index.tsx
|
|
import { DashboardPage } from '@/features/dashboard/pages/DashboardPage';
|
|
import { ExercisePage } from '@/features/exercises/pages/ExercisePage';
|
|
import { AchievementsPage } from '@/features/gamification/pages/AchievementsPage';
|
|
|
|
const routes = [
|
|
{ path: '/dashboard', element: <DashboardPage /> },
|
|
{ path: '/exercises/:id', element: <ExercisePage /> },
|
|
{ path: '/achievements', element: <AchievementsPage /> },
|
|
];
|
|
```
|
|
|
|
---
|
|
|
|
## Buenas Prácticas
|
|
|
|
1. **Feature = Dominio**: Una feature por dominio de negocio
|
|
2. **Autocontenida**: Cada feature debe funcionar independientemente
|
|
3. **Barrel exports**: Usar index.ts para exponer API pública
|
|
4. **No imports cruzados internos**: Usar exports públicos entre features
|
|
5. **Colocalizar tests**: `__tests__/` junto a lo que prueban
|
|
6. **Types propios**: Cada feature define sus propios tipos
|
|
7. **Hooks para lógica**: Extraer lógica a custom hooks
|
|
|
|
---
|
|
|
|
## Ver También
|
|
|
|
- [ESTRUCTURA-SHARED.md](./ESTRUCTURA-SHARED.md) - Código compartido
|
|
- [STATE-MANAGEMENT.md](./STATE-MANAGEMENT.md) - Zustand y React Query
|
|
- [COMPONENTES-UI.md](./COMPONENTES-UI.md) - Componentes de UI base
|
|
- [TYPES-CONVENTIONS.md](./TYPES-CONVENTIONS.md) - Convenciones de Types (SSOT)
|
|
|
|
---
|
|
|
|
## Changelog
|
|
|
|
| Versión | Fecha | Cambios |
|
|
|---------|-------|---------|
|
|
| 1.1.0 | 2025-11-29 | Añadidas features: mechanics, missions, assignments |
|
|
| 1.0.0 | 2025-11-28 | Versión inicial |
|