Техническое задание: Платформа для онлайн-курсов
1. Описание проекта
Веб-платформа для публикации и прохождения онлайн-курсов с отслеживанием прогресса студентов и системой тестирования. Проект закрепляет навыки CRUD, вложенных сущностей (курс → уроки → тесты), разграничения прав и совместной работы через Git.
Команда: 2–3 человека
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 |
Прогресс в процентах (0–100) |
| 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. Маршруты и контроллеры
// Публичные маршруты
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
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 |
Правила
- Ветка
develop — основная ветка разработки
- Каждый участник создаёт фич-ветки от
develop
- Минимум 3 PR на участника
- Обязательный код-ревью перед мёржем
- Conventional Commits
Визуализация workflow (2 участника)
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 участника)
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. Критерии приёмки
Обязательно
Дополнительно (бонусные баллы)
9. Дополнительные задания (для продвинутых)
- Рейтинг курсов: студенты оценивают курс после завершения (1–5 звёзд)
- Сертификаты: генерация PDF-сертификата при 100% прохождении
- Обсуждения: комментарии к урокам (вложенные, как на YouTube)
- Тесты: таймер на прохождение теста, автоматическая отправка по истечении
- API: RESTful API для каталога курсов и прохождения
- Тесты: PHPUnit Feature-тесты для QuizController
- Events & Listeners: событие «урок пройден» → обновление прогресса
10. Рекомендуемые материалы