# OQI-002: Modulo Educativo

**Estado:** ✅ Implementado
**Fecha:** 2025-12-05
**Modulo:** `apps/backend/src/modules/courses`

---

## Descripcion

Sistema de cursos educativos con:
- Categorias de cursos
- Cursos con niveles de dificultad
- Modulos dentro de cada curso
- Lecciones con contenido multimedia
- Sistema de progreso del usuario

---

## Arquitectura

```
┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│    Frontend     │────▶│  NestJS API     │────▶│   PostgreSQL    │
│  /courses/*     │     │  /courses/*     │     │ education schema│
└─────────────────┘     └─────────────────┘     └─────────────────┘
```

---

## Endpoints

| Metodo | Ruta | Descripcion | Auth |
|--------|------|-------------|------|
| GET | `/courses` | Listar cursos (paginado) | - |
| GET | `/courses/:id` | Detalle de curso | - |
| POST | `/courses` | Crear curso | Admin |
| PATCH | `/courses/:id` | Actualizar curso | Admin |
| DELETE | `/courses/:id` | Eliminar curso | Admin |
| GET | `/courses/categories` | Listar categorias | - |
| POST | `/courses/categories` | Crear categoria | Admin |

---

## Entidades

### Category

```typescript
@Entity({ name: 'categories', schema: 'education' })
class Category {
  id: string;           // UUID
  name: string;         // "Trading Basico"
  slug: string;         // "trading-basico"
  description?: string;
  color?: string;       // "#3B82F6"
  iconName?: string;    // "chart-line"
  sortOrder: number;    // Para ordenar
  isActive: boolean;
  createdAt: Date;
  updatedAt: Date;
}
```

### Course

```typescript
@Entity({ name: 'courses', schema: 'education' })
class Course {
  id: string;
  categoryId: string;
  title: string;          // "Introduccion al Trading"
  slug: string;           // "introduccion-trading"
  subtitle?: string;
  description: string;
  thumbnailUrl?: string;
  level: DifficultyLevel; // beginner | intermediate | advanced | expert
  status: PublishStatus;  // draft | published | archived
  price?: number;         // null = gratis
  discountPrice?: number;
  isFree: boolean;
  isFeatured: boolean;
  durationMinutes?: number;
  sortOrder: number;
  publishedAt?: Date;
  createdAt: Date;
  updatedAt: Date;
}
```

### Module

```typescript
@Entity({ name: 'modules', schema: 'education' })
class Module {
  id: string;
  courseId: string;
  title: string;         // "Fundamentos del Mercado"
  description?: string;
  sortOrder: number;
  isActive: boolean;
  createdAt: Date;
  updatedAt: Date;
}
```

### Lesson

```typescript
@Entity({ name: 'lessons', schema: 'education' })
class Lesson {
  id: string;
  moduleId: string;
  title: string;         // "Que es el Trading"
  slug: string;
  type: LessonType;      // video | article | quiz | exercise
  content?: string;      // Contenido markdown/HTML
  videoUrl?: string;
  durationMinutes?: number;
  sortOrder: number;
  isFree: boolean;       // Preview gratuito
  isActive: boolean;
  createdAt: Date;
  updatedAt: Date;
}
```

---

## Niveles de Dificultad

| Nivel | Label ES | Color |
|-------|----------|-------|
| beginner | Principiante | Verde |
| intermediate | Intermedio | Azul |
| advanced | Avanzado | Naranja |
| expert | Experto | Rojo |

---

## Query Parameters

### GET /courses

| Param | Tipo | Descripcion |
|-------|------|-------------|
| page | number | Pagina (default: 1) |
| limit | number | Items por pagina (default: 10, max: 100) |
| categoryId | uuid | Filtrar por categoria |
| level | string | Filtrar por nivel |
| isFree | boolean | Solo cursos gratuitos |
| isFeatured | boolean | Solo destacados |
| status | string | Estado de publicacion |
| search | string | Buscar en titulo/descripcion |
| sortBy | string | Campo para ordenar |
| sortOrder | asc/desc | Direccion de orden |

---

## Respuesta Paginada

```json
{
  "data": [
    {
      "id": "uuid",
      "title": "Introduccion al Trading",
      "level": "beginner",
      "price": 29.99,
      "isFree": false,
      "thumbnailUrl": "https://...",
      "durationMinutes": 180,
      "category": {
        "id": "uuid",
        "name": "Trading Basico"
      }
    }
  ],
  "meta": {
    "page": 1,
    "limit": 10,
    "total": 45,
    "totalPages": 5
  }
}
```

---

## Flujo de Compra

```
1. Usuario ve catalogo de cursos
2. Selecciona curso de pago
3. Redirige a checkout (Stripe)
4. Pago exitoso -> webhook actualiza acceso
5. Usuario puede ver contenido completo
```

---

## Frontend

### Pagina de Cursos

```typescript
// apps/frontend/src/pages/Courses.tsx
function Courses() {
  const [courses, setCourses] = useState<Course[]>([]);
  const [categories, setCategories] = useState<Category[]>([]);
  const [selectedCategory, setSelectedCategory] = useState('');

  // Carga cursos con filtros
  // Muestra grid de cards
  // Paginacion
}
```

### Servicio

```typescript
// apps/frontend/src/services/courses.ts
export const coursesService = {
  getCourses(params: CourseQueryParams): Promise<PaginatedResponse<Course>>,
  getCourse(id: string): Promise<Course>,
  getCategories(): Promise<Category[]>,
};
```

---

## Archivos

```
apps/backend/src/modules/courses/
├── dto/
│   ├── course.dto.ts
│   ├── module.dto.ts
│   └── lesson.dto.ts
├── entities/
│   ├── category.entity.ts
│   ├── course.entity.ts
│   ├── module.entity.ts
│   └── lesson.entity.ts
├── courses.controller.ts
├── courses.service.ts
└── courses.module.ts

apps/frontend/src/
├── pages/
│   └── Courses.tsx
└── services/
    └── courses.ts
```

---

## Proximas Mejoras

- [ ] Progreso del usuario por leccion
- [ ] Sistema de quizzes
- [ ] Certificados de finalizacion
- [ ] Reviews y ratings
- [ ] Busqueda full-text

---

*Documentacion generada: 2025-12-05*
