laravel-12-tech-specs/task03-online-courses.md

411 lines
19 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# Техническое задание: Платформа для онлайн-курсов
## 1. Описание проекта
Веб-платформа для публикации и прохождения онлайн-курсов с отслеживанием прогресса студентов и системой тестирования. Проект закрепляет навыки CRUD, вложенных сущностей (курс → уроки → тесты), разграничения прав и совместной работы через Git.
**Команда:** 23 человека
---
## 2. Функциональные требования
### 2.1. Аутентификация и регистрация
- Регистрация, вход, выход (Laravel Breeze)
- Восстановление пароля (опционально)
### 2.2. Каталог курсов
- Просмотр списка доступных курсов с пагинацией
- Фильтрация по категориям
- Детальная страница курса (описание, автор, список уроков, рейтинг)
- Запись на курс (кнопка «Записаться»)
### 2.3. Управление курсами (преподаватель/админ)
- CRUD курсов: название, описание, обложка, категория, уровень сложности
- Вложенный CRUD уроков внутри курса:
- Название урока, порядковый номер, тип (текст/видео)
- Текстовое содержание (WYSIWYG или markdown)
- URL видео (опционально, YouTube/Vimeo embed)
- CRUD тестов/викторин к урокам:
- Вопросы с вариантами ответов
- Один или несколько правильных ответов
- Проходной балл (в процентах)
### 2.4. Прохождение курса (студент)
- Список записанных курсов (личный кабинет)
- Последовательное прохождение уроков
- Отметка урока как пройденного
- Сдача теста после урока (или в конце курса)
- Просмотр результатов теста (правильные/неправильные ответы)
- Прогресс-бар прохождения курса (в процентах)
### 2.5. Панель преподавателя
- Мои курсы (созданные мной)
- Список студентов по каждому курсу
- Прогресс каждого студента
- Статистика: количество курсов, студентов, средний балл
### 2.6. Панель администратора
- Управление пользователями и ролями
- Модерация курсов (скрыть/показать)
- Общая статистика платформы
---
## 3. Структура базы данных
### Таблица `users`
| Поле | Тип | Описание |
|---|---|---|
| id | BIGINT UNSIGNED | Первичный ключ |
| name | VARCHAR(255) | Имя |
| email | VARCHAR(255) | Email (unique) |
| password | VARCHAR(255) | Хеш пароля |
| role | ENUM('admin', 'instructor', 'student') | Роль |
| avatar | VARCHAR(255) \| NULL | Аватар |
| created_at | TIMESTAMP | |
| updated_at | TIMESTAMP | |
### Таблица `categories`
| Поле | Тип | Описание |
|---|---|---|
| id | BIGINT UNSIGNED | Первичный ключ |
| name | VARCHAR(255) | Название категории |
| slug | VARCHAR(255) | URL-идентификатор (unique) |
| created_at | TIMESTAMP | |
| updated_at | TIMESTAMP | |
### Таблица `courses`
| Поле | Тип | Описание |
|---|---|---|
| id | BIGINT UNSIGNED | Первичный ключ |
| title | VARCHAR(255) | Название курса |
| slug | VARCHAR(255) | URL-идентификатор (unique) |
| description | TEXT | Описание |
| cover_image | VARCHAR(255) \| NULL | Обложка курса |
| difficulty_level | ENUM('beginner', 'intermediate', 'advanced') | Уровень |
| instructor_id | BIGINT UNSIGNED | Преподаватель (FK → users) |
| category_id | BIGINT UNSIGNED | Категория (FK → categories) |
| is_published | BOOLEAN | Опубликован ли |
| created_at | TIMESTAMP | |
| updated_at | TIMESTAMP | |
### Таблица `lessons`
| Поле | Тип | Описание |
|---|---|---|
| id | BIGINT UNSIGNED | Первичный ключ |
| course_id | BIGINT UNSIGNED | Курс (FK → courses) |
| title | VARCHAR(255) | Название урока |
| position | INT | Порядковый номер |
| content_type | ENUM('text', 'video') | Тип контента |
| content | TEXT | Содержимое (текст или URL видео) |
| created_at | TIMESTAMP | |
| updated_at | TIMESTAMP | |
### Таблица `quizzes`
| Поле | Тип | Описание |
|---|---|---|
| id | BIGINT UNSIGNED | Первичный ключ |
| lesson_id | BIGINT UNSIGNED | Урок (FK → lessons) |
| title | VARCHAR(255) | Название теста |
| passing_score | INT | Проходной балл (%) |
| created_at | TIMESTAMP | |
| updated_at | TIMESTAMP | |
### Таблица `quiz_questions`
| Поле | Тип | Описание |
|---|---|---|
| id | BIGINT UNSIGNED | Первичный ключ |
| quiz_id | BIGINT UNSIGNED | Тест (FK → quizzes) |
| question | TEXT | Вопрос |
| position | INT | Порядковый номер |
| created_at | TIMESTAMP | |
| updated_at | TIMESTAMP | |
### Таблица `quiz_answers`
| Поле | Тип | Описание |
|---|---|---|
| id | BIGINT UNSIGNED | Первичный ключ |
| question_id | BIGINT UNSIGNED | Вопрос (FK → quiz_questions) |
| answer_text | VARCHAR(255) | Текст ответа |
| is_correct | BOOLEAN | Правильный ли |
| created_at | TIMESTAMP | |
| updated_at | TIMESTAMP | |
### Таблица `course_user` (запись на курс)
| Поле | Тип | Описание |
|---|---|---|
| id | BIGINT UNSIGNED | Первичный ключ |
| course_id | BIGINT UNSIGNED | FK → courses |
| user_id | BIGINT UNSIGNED | FK → users |
| progress | INT | Прогресс в процентах (0100) |
| enrolled_at | TIMESTAMP | Дата записи |
| completed_at | TIMESTAMP \| NULL | Дата завершения |
### Таблица `lesson_progress`
| Поле | Тип | Описание |
|---|---|---|
| id | BIGINT UNSIGNED | Первичный ключ |
| user_id | BIGINT UNSIGNED | FK → users |
| lesson_id | BIGINT UNSIGNED | FK → lessons |
| is_completed | BOOLEAN | Пройден ли |
| completed_at | TIMESTAMP \| NULL | |
### Таблица `quiz_results`
| Поле | Тип | Описание |
|---|---|---|
| id | BIGINT UNSIGNED | Первичный ключ |
| user_id | BIGINT UNSIGNED | FK → users |
| quiz_id | BIGINT UNSIGNED | FK → quizzes |
| score | INT | Набранный балл (%) |
| passed | BOOLEAN | Сдал ли |
| taken_at | TIMESTAMP | Дата прохождения |
---
## 4. Маршруты и контроллеры
```php
// Публичные маршруты
Route::get('/', [CourseController::class, 'index'])->name('courses.index');
Route::get('/courses/{course:slug}', [CourseController::class, 'show'])->name('courses.show');
// Аутентифицированные маршруты
Route::middleware('auth')->group(function () {
// Запись на курс
Route::post('/courses/{course}/enroll', [CourseController::class, 'enroll'])->name('courses.enroll');
// Прохождение курса
Route::prefix('my-courses')->name('my-courses.')->group(function () {
Route::get('/', [StudentCourseController::class, 'index'])->name('index');
Route::get('/{course}', [StudentCourseController::class, 'show'])->name('show');
Route::get('/{course}/lessons/{lesson}', [LessonController::class, 'show'])->name('lessons.show');
Route::post('/{course}/lessons/{lesson}/complete', [LessonController::class, 'complete'])->name('lessons.complete');
// Тесты
Route::get('/{course}/quizzes/{quiz}', [QuizController::class, 'take'])->name('quizzes.take');
Route::post('/{course}/quizzes/{quiz}/submit', [QuizController::class, 'submit'])->name('quizzes.submit');
});
// Преподаватель
Route::prefix('instructor')->name('instructor.')->middleware('can:be-instructor')->group(function () {
Route::resource('courses', InstructorCourseController::class);
Route::resource('courses.lessons', InstructorLessonController::class)->scoped(['courses' => 'course']);
Route::resource('lessons.quizzes', InstructorQuizController::class)->scoped(['lessons' => 'lesson']);
Route::resource('quizzes.questions', InstructorQuestionController::class)->scoped(['quizzes' => 'quiz']);
Route::get('courses/{course}/students', [InstructorCourseController::class, 'students'])->name('courses.students');
Route::get('dashboard', [InstructorDashboardController::class, 'index'])->name('dashboard');
});
// Админка
Route::prefix('admin')->name('admin.')->middleware('can:access-admin-panel')->group(function () {
Route::resource('users', AdminUserController::class);
Route::patch('courses/{course}/toggle-publish', [AdminCourseController::class, 'togglePublish'])->name('courses.publish');
Route::get('dashboard', [AdminDashboardController::class, 'index'])->name('dashboard');
});
});
```
### Контроллеры
- `CourseController` — публичный каталог и запись
- `StudentCourseController` — прохождение курсов студентом
- `LessonController` — просмотр уроков и отметка пройденными
- `QuizController` — прохождение тестов
- `InstructorCourseController` — CRUD курсов преподавателем
- `InstructorLessonController` — CRUD уроков
- `InstructorQuizController` — CRUD тестов
- `InstructorQuestionController` — CRUD вопросов
- `InstructorDashboardController` — панель преподавателя
- `AdminUserController`, `AdminCourseController`, `AdminDashboardController` — админка
---
## 5. Роли, Gates и Policies
### Роли
| Роль | Описание |
|---|---|
| `admin` | Полный доступ, модерация курсов, управление пользователями |
| `instructor` | Создание/редактирование своих курсов, просмотр студентов |
| `student` | Запись на курсы, прохождение уроков и тестов |
### Gates
```php
Gate::define('be-instructor', function (User $user) {
return in_array($user->role, ['admin', 'instructor']);
});
Gate::define('access-admin-panel', function (User $user) {
return $user->role === 'admin';
});
```
### Policies
**CoursePolicy:**
- `view` — все (если опубликован), автор или admin (если не опубликован)
- `create` — instructor или admin
- `update`, `delete` — автор курса или admin
- `enroll` — student (не записан на этот курс)
**LessonPolicy:**
- `view` — студент, записанный на курс, или преподаватель/admin
- `create`, `update`, `delete` — преподаватель курса или admin
**QuizPolicy:**
- `view` — студент, записанный на курс, или преподаватель/admin
- `take` — студент, записанный на курс
- `create`, `update`, `delete` — преподаватель курса или admin
**QuizResultPolicy:**
- `view` — владелец результата или преподаватель/admin
- `create` — все студенты
---
## 6. Требования к интерфейсу (Bootstrap 5)
### Компоненты
- **Навбар** — логотип, каталог, «Мои курсы», профиль
- **Карточки курсов** — обложка, название, автор, уровень (бейдж), прогресс-бар
- **Страница курса** — описание, список уроков (accordion), кнопка записи
- **Страница урока** — контент (текст или embed видео), кнопка «Отметить пройденным»
- **Прогресс-бар** — Bootstrap `progress` для отображения прохождения курса
- **Accordion** — список уроков курса
- **Тест** — форма с radio/checkbox, кнопка отправки, результат
- **Дашборд преподавателя** — статистика (карточки), таблица студентов
- **Адаптивная сетка** — `col-md-4` для карточек, `col-md-8` + `col-md-4` для основного контента и сайдбара
### Цветовая схема уровней сложности
- Начальный — `bg-success`
- Средний — `bg-warning`
- Продвинутый — `bg-danger`
---
## 7. Git-workflow для команды
### Распределение модулей (для 2 человек)
| Участник | Модуль | Ветки |
|---|---|---|
| **Участник A** | Курсы, категории, обложки, дашборд преподавателя | `feature/courses-crud`, `feature/categories`, `feature-course-covers` |
| **Участник B** | Уроки, тесты, вопросы, прохождение тестов | `feature/lessons-crud`, `feature/quizzes`, `feature-quiz-questions` |
### Распределение модулей (для 3 человек)
| Участник | Модуль | Ветки |
|---|---|---|
| **Участник A** | Курсы, категории, загрузка обложек | `feature/courses-crud`, `feature/categories`, `feature-course-covers` |
| **Участник B** | Уроки, тесты, вопросы | `feature/lessons-crud`, `feature/quizzes`, `feature-quiz-questions` |
| **Участник C** | Запись на курс, прогресс, прохождение тестов, UI | `feature/enrollment`, `feature-progress-tracking`, `feature-student-ui` |
### Правила
1. Ветка `develop` — основная ветка разработки
2. Каждый участник создаёт фич-ветки от `develop`
3. Минимум 3 PR на участника
4. Обязательный код-ревью перед мёржем
5. Conventional Commits
### Визуализация workflow (2 участника)
```mermaid
gitGraph
commit id: "init" tag: "v1.0"
branch develop
checkout develop
branch feature/courses-crud
checkout develop
branch feature/lessons-crud
checkout feature/courses-crud
commit id: "feat: add courses CRUD with covers"
commit id: "feat: add categories CRUD"
checkout feature/lessons-crud
commit id: "feat: add lessons CRUD"
commit id: "feat: add quizzes system"
checkout develop
merge feature/courses-crud tag: "PR + review"
merge feature/lessons-crud tag: "PR + review"
checkout main
merge develop tag: "release v1.1"
```
### Визуализация workflow (3 участника)
```mermaid
gitGraph
commit id: "init" tag: "v1.0"
branch develop
checkout develop
branch feature/courses-crud
checkout develop
branch feature/lessons-crud
checkout develop
branch feature/enrollment
checkout feature/courses-crud
commit id: "feat: add courses CRUD with covers"
commit id: "feat: add instructor dashboard"
checkout feature/lessons-crud
commit id: "feat: add lessons CRUD"
commit id: "feat: add quizzes system"
checkout feature/enrollment
commit id: "feat: add enrollment flow"
commit id: "feat: add progress tracking"
checkout develop
merge feature/courses-crud tag: "PR + review"
merge feature/lessons-crud tag: "PR + review"
merge feature/enrollment tag: "PR + review"
checkout main
merge develop tag: "release v1.1"
```
---
## 8. Критерии приёмки
### Обязательно
- [ ] CRUD курсов с загрузкой обложки
- [ ] CRUD уроков внутри курса (вложенный ресурс)
- [ ] CRUD тестов и вопросов (минимум 3 ответа на вопрос, 1+ правильный)
- [ ] Запись на курс (студент)
- [ ] Отметка уроков пройденными
- [ ] Прохождение теста с подсчётом результата
- [ ] Прогресс-бар прохождения курса
- [ ] Панель преподавателя (мои курсы, студенты)
- [ ] Policies: студент не может редактировать курсы, преподаватель не может редактировать чужие курсы
- [ ] Адаптивная Bootstrap-вёрстка
- [ ] Flash-сообщения
- [ ] Пагинация каталога курсов
- [ ] Git-история: минимум 3 ветки на участника, PR с ревью
### Дополнительно (бонусные баллы)
- [ ] Рейтинг курса (средняя оценка студентов)
- [ ] Сертификат при завершении курса (генерация PDF)
- [ ] Поиск курсов по названию/описанию
- [ ] Фильтрация по уровню сложности
- [ ] Тесты: перемешивание вопросов и ответов
- [ ] Soft Deletes для курсов и уроков
---
## 9. Дополнительные задания (для продвинутых)
1. **Рейтинг курсов:** студенты оценивают курс после завершения (15 звёзд)
2. **Сертификаты:** генерация PDF-сертификата при 100% прохождении
3. **Обсуждения:** комментарии к урокам (вложенные, как на YouTube)
4. **Тесты:** таймер на прохождение теста, автоматическая отправка по истечении
5. **API:** RESTful API для каталога курсов и прохождения
6. **Тесты:** PHPUnit Feature-тесты для QuizController
7. **Events & Listeners:** событие «урок пройден» → обновление прогресса
---
## 10. Рекомендуемые материалы
- Laravel Docs: https://laravel.com/docs/12.x
- Nested Resources: https://laravel.com/docs/12.x/controllers#restful-nested-resources
- Bootstrap 5 Progress: https://getbootstrap.com/docs/5.3/components/progress/
- Bootstrap 5 Accordion: https://getbootstrap.com/docs/5.3/components/accordion/
- Laravel Policies: https://laravel.com/docs/12.x/authorization#creating-policies