1Bilim Platform
Техническое задание на разработку образовательной платформы
📋 1. Обзор проекта
1Bilim — образовательная платформа для проведения онлайн-марафонов по изучению языков. Платформа позволяет создавать структурированные курсы с модулями и уроками, отслеживать прогресс учеников, организовывать проверку домашних заданий и поддерживать коммуникацию между участниками.
Ключевые возможности
🛠 2. Технологический стек
Frontend
Backend
База данных & Инфра
👥 3. Роли и права доступа
Описание ролей
| Роль | Описание | Ключевые возможности |
|---|---|---|
| Admin | Полный доступ к системе | Всё: марафоны, пользователи, настройки, аналитика |
| Curator | Куратор учеников | Свои ученики, чат, проверка ДЗ, мотивация |
| Teacher | Учитель / Преподаватель | Ведение уроков, проверка ДЗ |
| Student | Ученик | Прохождение уроков, отправка ДЗ, чат с куратором |
Матрица прав доступа
| Функция | Admin | Curator | Teacher | Student |
|---|---|---|---|---|
| Создание/редактирование марафонов | ✓ | ✗ | ✗ | ✗ |
| Создание уроков | ✓ | ✗ | ✗ | ✗ |
| Управление всеми учениками | ✓ | ✗ | ✗ | ✗ |
| Просмотр своих учеников | ✓ | ✓ | ✓ | ✗ |
| Проверка ДЗ | ✓ | ✓ | ✓ | ✗ |
| Чат с учениками | ✓ | ✓ | ✗ | ✗ |
| Прохождение уроков | ✗ | ✗ | ✗ | ✓ |
| Отправка ДЗ | ✗ | ✗ | ✗ | ✓ |
| Управление кураторами/учителями | ✓ | ✗ | ✗ | ✗ |
| Управление сторисами | ✓ | ✗ | ✗ | ✗ |
| Полная аналитика | ✓ | Частично | Частично | ✗ |
📚 4. Админ: Марафоны
Марафон — основная сущность платформы, представляющая учебный курс. Содержит модули с уроками.
Режимы прохождения
| Режим | Код | Описание |
|---|---|---|
| Открытый | open | Все уроки доступны сразу |
| Последовательный | sequential | Следующий урок после завершения предыдущего |
| С проверкой | with_review | Следующий урок после проверки ДЗ |
Функции
- Создание, редактирование, удаление марафонов
- Настройка обложки, описания, языка, уровня
- Выбор режима прохождения
- Настройка рейтинга (показывать/скрывать, топ-5/10/все)
- Дублирование марафона
- Привязка кураторов к марафону
- Статусы: черновик, опубликован, архив
📂 5. Админ: Модули
Модуль — раздел внутри марафона, группирующий уроки по темам.
Функции
- Создание модулей внутри марафона
- Название, описание, порядок сортировки
- Drag-and-drop для изменения порядка
- Удаление модуля (с уроками или перенос)
Поля модуля
| Поле | Тип | Описание |
|---|---|---|
| title | string | Название модуля |
| description | text | Описание (опционально) |
| sort_order | int | Порядок отображения |
| is_published | boolean | Опубликован ли |
🎨 6. Админ: Конструктор уроков
Блочный редактор для создания уроков. Каждый урок состоит из блоков контента разных типов.
Типы блоков
| Тип | Код | Описание |
|---|---|---|
| 📝 Текст | text | Rich-text с форматированием |
| 🎬 Видео | video | YouTube, Vimeo, загрузка файла |
| 🎧 Аудио | audio | Аудиофайл с плеером |
| 🖼️ Изображение | image | Картинка с подписью |
| 📎 Файл | file | Скачиваемый файл (PDF, DOC) |
| ❓ Тест | quiz | Вопросы с вариантами ответов |
| ✍️ Открытый вопрос | open_question | Текстовый ответ |
| 🎤 Аудио-ответ | audio_answer | Запись голоса |
| 📹 Видео-ответ | video_answer | Запись видео |
| ➗ Разделитель | divider | Визуальный разделитель |
| 💡 Заметка | callout | Выделенный блок (info, warning) |
Настройки урока
- Название — заголовок урока
- Описание — краткое описание
- Порядок — позиция в модуле
- Баллы — за прохождение (для рейтинга)
- Требует ДЗ — нужна ли проверка
- Статус — черновик/опубликован
Структура блока (JSON)
{
"id": "block_uuid",
"type": "video",
"sort_order": 1,
"content": {
"url": "https://youtube.com/watch?v=xxx",
"title": "Введение в курс"
},
"settings": {
"autoplay": false,
"required": true
}
} 📝 7. Админ: Домашние задания
Система проверки ДЗ учеников. Админ видит все ДЗ по всем марафонам.
Статусы ДЗ
| Статус | Код | Описание |
|---|---|---|
| ⏳ Ожидает | pending | Отправлено, ждёт проверки |
| 👀 На проверке | reviewing | Куратор/учитель взял в работу |
| ✅ Принято | approved | ДЗ принято |
| 🔄 На доработку | revision | Нужны исправления |
| ❌ Отклонено | rejected | ДЗ отклонено |
Функции
- Просмотр всех ДЗ с фильтрацией по статусу, марафону, куратору
- Назначение ДЗ на куратора/учителя
- Просмотр истории проверок
- Аналитика по времени проверки
👨🎓 8. Админ: Ученики
Функции
- Список всех учеников с поиском и фильтрами
- Добавление ученика (вручную или импорт CSV)
- Привязка к марафону с указанием периода доступа
- Назначение куратора ученику
- Просмотр прогресса и статистики
- Блокировка/разблокировка
- Продление доступа к марафону
Поля ученика
| Поле | Тип | Описание |
|---|---|---|
| string | Email (уникальный) | |
| phone | string | Телефон |
| first_name | string | Имя |
| last_name | string | Фамилия |
| avatar_url | string | Аватар |
| status | enum | active, blocked, deleted |
| timezone | string | Часовой пояс |
👨💼 9. Админ: Кураторы
Функции
- Список всех кураторов
- Добавление/редактирование куратора
- Привязка к марафонам
- Распределение учеников между кураторами
- Статистика: кол-во учеников, проверенных ДЗ, время ответа
- Лимит учеников на куратора
Поля куратора
| Поле | Тип | Описание |
|---|---|---|
| string | Email для входа | |
| first_name | string | Имя |
| last_name | string | Фамилия |
| phone | string | Телефон |
| max_students | int | Лимит учеников |
| is_active | boolean | Активен ли |
👩🏫 10. Админ: Учителя
Функции
- Список всех учителей
- Добавление/редактирование учителя
- Привязка к марафонам (учитель видит только свои марафоны)
- Статистика по проверенным ДЗ
Возможности учителя
- Просмотр уроков в своих марафонах
- Проверка ДЗ учеников своих марафонов
- Обратная связь по ДЗ
- Нет доступа: управление учениками, чат, создание марафонов
📱 11. Админ: Сторисы
Stories — вовлекающий контент в формате историй, отображается на главной ученика.
Функции
- Создание сторисов (изображение или видео до 60 сек)
- Настройка порядка отображения
- Привязка к марафону (или глобальные для всех)
- Период активности (дата начала — дата окончания)
- Статистика просмотров
- Ссылка/действие при клике
Поля сториса
| Поле | Тип | Описание |
|---|---|---|
| title | string | Название (для админки) |
| media_url | string | URL изображения/видео |
| media_type | enum | image, video |
| link_url | string | Ссылка при клике (опционально) |
| marathon_id | uuid | Привязка к марафону (null = для всех) |
| starts_at | timestamp | Начало показа |
| ends_at | timestamp | Конец показа |
| sort_order | int | Порядок |
| is_active | boolean | Активен ли |
💬 12. Админ: Чат
Админ имеет доступ ко всем чатам системы для мониторинга и модерации.
Функции админа
- Просмотр всех чатов куратор-ученик
- Поиск по чатам и сообщениям
- Модерация: удаление сообщений
- Аналитика: время ответа кураторов, активность
Архитектура чата
- Тип: Личные чаты (1 куратор — 1 ученик)
- Real-time: WebSocket для мгновенных сообщений
- Типы сообщений: текст, изображение, файл, голосовое
- Статусы: отправлено, доставлено, прочитано
Структура сообщения
{
"id": "msg_uuid",
"chat_id": "chat_uuid",
"sender_id": "user_uuid",
"type": "text",
"content": "Привет! Как дела с уроком?",
"attachments": [],
"status": "read",
"created_at": "2025-01-15T10:30:00Z"
} 📊 13. Куратор: Дашборд
Главная страница куратора с ключевыми метриками и быстрыми действиями.
Виджеты дашборда
Список учеников куратора
- Фото, имя, марафон, прогресс
- Последняя активность
- Статус последнего ДЗ
- Быстрый переход в чат
- Фильтр: все, активные, неактивные, с ДЗ
✅ 14. Куратор: Проверка ДЗ
Интерфейс проверки
- Список ДЗ только своих учеников
- Фильтры: ожидает, на доработке, все
- Сортировка: по дате, по ученику, по уроку
- Предпросмотр ответа ученика
Действия при проверке
| Действие | Описание |
|---|---|
| ✅ Принять | ДЗ засчитано, ученик получает баллы |
| 🔄 На доработку | С комментарием что исправить |
| ❌ Отклонить | ДЗ не принято (редкий случай) |
Обратная связь
- Текстовый комментарий
- Голосовое сообщение
- Оценка (опционально, если включено)
- Бонусные баллы за отличную работу
📊 15. Учитель: Дашборд
Упрощённый дашборд для учителя с фокусом на проверку ДЗ.
Виджеты
Ограничения учителя
Учитель НЕ имеет доступа к: чатам, управлению учениками, созданию контента, назначению кураторов.
✅ 16. Учитель: Проверка ДЗ
Учитель проверяет ДЗ учеников из марафонов, к которым он привязан.
Функции
- Список ДЗ по своим марафонам
- Фильтр по марафону, уроку, статусу
- Те же действия: принять, на доработку, отклонить
- Комментарии и обратная связь
Отличие от куратора
| Функция | Куратор | Учитель |
|---|---|---|
| Видит ДЗ | Только своих учеников | Всех учеников марафона |
| Чат с учениками | ✓ | ✗ |
| Мотивация учеников | ✓ | ✗ |
🏠 17. Ученик: Главная
Главная страница ученика — точка входа в обучение.
Элементы главной
- Stories: Карусель историй сверху
- Продолжить: Последний незавершённый урок
- Мои марафоны: Карточки активных марафонов с прогрессом
- Прогресс: Визуальный прогресс-бар
- Рейтинг: Позиция в таблице лидеров
- Уведомления: Новые сообщения, проверенные ДЗ
Карточка марафона
┌─────────────────────────────────┐
│ [Обложка марафона] │
├─────────────────────────────────┤
│ Английский A1 │
│ ████████░░░░░░ 65% │
│ Урок 13 из 20 │
│ ⏰ Осталось 14 дней │
│ [Продолжить] │
└─────────────────────────────────┘ 📖 18. Ученик: Уроки
Структура марафона
- Список модулей (аккордеон)
- Уроки внутри модулей
- Статусы: ✅ пройден, 🔵 доступен, 🔒 заблокирован
- Индикатор ДЗ: нужно отправить / на проверке / принято
Страница урока
- Последовательное отображение блоков
- Видео-плеер с запоминанием позиции
- Интерактивные тесты
- Форма отправки ДЗ внизу
- Кнопка "Завершить урок"
Отправка ДЗ
- Текстовый ответ
- Загрузка файлов (фото, документы)
- Запись аудио (для speaking)
- Запись видео (для pronunciation)
Если марафон в режиме with_review, следующий урок откроется только после принятия ДЗ куратором.
📋 19. Ученик: Мои ДЗ
Список ДЗ
- Все отправленные ДЗ ученика
- Фильтр по статусу и марафону
- Информация: урок, дата отправки, статус, комментарий
Статусы для ученика
| Статус | Отображение | Действие |
|---|---|---|
| pending | ⏳ На проверке | Ждать |
| approved | ✅ Принято | Посмотреть комментарий |
| revision | 🔄 Нужны исправления | Исправить и отправить заново |
| rejected | ❌ Отклонено | Связаться с куратором |
Повторная отправка
При статусе "На доработку" ученик может:
- Посмотреть комментарий куратора
- Исправить ответ
- Отправить заново
💬 20. Ученик: Чат с куратором
Функции
- Личный чат с назначенным куратором
- Отправка текстовых сообщений
- Отправка фото и файлов
- Запись и отправка голосовых сообщений
- Индикатор "печатает..."
- Статусы: отправлено ✓, прочитано ✓✓
Уведомления
- Push-уведомления о новых сообщениях
- Бейдж с количеством непрочитанных
- Email-уведомление если не в сети 24+ часа
Если куратор не назначен, показывается заглушка с контактом поддержки.
🗄️ 21. База данных: Обзор
PostgreSQL 15+ с использованием UUID для первичных ключей, JSONB для гибких структур.
Диаграмма связей (упрощённая)
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ users │────<│ marathon_ │>────│ marathons │
│ │ │ enrollments │ │ │
└─────────────┘ └─────────────┘ └─────────────┘
│ │
│ │
▼ ▼
┌─────────────┐ ┌─────────────┐
│ chats │ │ modules │
│ │ │ │
└─────────────┘ └─────────────┘
│ │
▼ ▼
┌─────────────┐ ┌─────────────┐
│ messages │ │ lessons │
│ │ │ │
└─────────────┘ └─────────────┘
│
▼
┌─────────────┐
│ blocks │
│ │
└─────────────┘
Соглашения
- Все таблицы имеют
id(UUID),created_at,updated_at - Soft delete через
deleted_at(GORM) - Внешние ключи с каскадным удалением где нужно
- Индексы на часто запрашиваемых полях
📊 22. База данных: Таблицы
users
Все пользователи системы (админы, кураторы, учителя, ученики)
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) UNIQUE NOT NULL,
phone VARCHAR(20),
password_hash VARCHAR(255) NOT NULL,
first_name VARCHAR(100) NOT NULL,
last_name VARCHAR(100),
avatar_url VARCHAR(500),
role VARCHAR(20) NOT NULL, -- admin, curator, teacher, student
status VARCHAR(20) DEFAULT 'active', -- active, blocked, deleted
timezone VARCHAR(50) DEFAULT 'UTC',
last_login_at TIMESTAMP,
email_verified BOOLEAN DEFAULT false,
created_at TIMESTAMP DEFAULT now(),
updated_at TIMESTAMP DEFAULT now(),
deleted_at TIMESTAMP
);
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_users_role ON users(role);
CREATE INDEX idx_users_status ON users(status); marathons
Марафоны / Курсы
CREATE TABLE marathons (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
title VARCHAR(255) NOT NULL,
slug VARCHAR(255) UNIQUE NOT NULL,
description TEXT,
cover_url VARCHAR(500),
language VARCHAR(10), -- en, ru, kk
level VARCHAR(10), -- A1, A2, B1, B2, C1, C2
access_mode VARCHAR(20) DEFAULT 'sequential', -- open, sequential, with_review
show_rating BOOLEAN DEFAULT true,
rating_type VARCHAR(20) DEFAULT 'top_10', -- top_5, top_10, all
status VARCHAR(20) DEFAULT 'draft', -- draft, published, archived
total_lessons INT DEFAULT 0,
total_points INT DEFAULT 0,
created_by UUID REFERENCES users(id),
created_at TIMESTAMP DEFAULT now(),
updated_at TIMESTAMP DEFAULT now(),
deleted_at TIMESTAMP
);
CREATE INDEX idx_marathons_status ON marathons(status);
CREATE INDEX idx_marathons_slug ON marathons(slug); modules
Модули внутри марафонов
CREATE TABLE modules (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
marathon_id UUID NOT NULL REFERENCES marathons(id) ON DELETE CASCADE,
title VARCHAR(255) NOT NULL,
description TEXT,
sort_order INT DEFAULT 0,
is_published BOOLEAN DEFAULT false,
created_at TIMESTAMP DEFAULT now(),
updated_at TIMESTAMP DEFAULT now(),
deleted_at TIMESTAMP
);
CREATE INDEX idx_modules_marathon ON modules(marathon_id);
CREATE INDEX idx_modules_sort ON modules(marathon_id, sort_order); lessons
Уроки внутри модулей
CREATE TABLE lessons (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
module_id UUID NOT NULL REFERENCES modules(id) ON DELETE CASCADE,
title VARCHAR(255) NOT NULL,
description TEXT,
sort_order INT DEFAULT 0,
points INT DEFAULT 10,
requires_hw BOOLEAN DEFAULT false,
is_published BOOLEAN DEFAULT false,
created_at TIMESTAMP DEFAULT now(),
updated_at TIMESTAMP DEFAULT now(),
deleted_at TIMESTAMP
);
CREATE INDEX idx_lessons_module ON lessons(module_id);
CREATE INDEX idx_lessons_sort ON lessons(module_id, sort_order); blocks
Блоки контента внутри уроков
CREATE TABLE blocks (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
lesson_id UUID NOT NULL REFERENCES lessons(id) ON DELETE CASCADE,
type VARCHAR(30) NOT NULL,
sort_order INT DEFAULT 0,
content JSONB NOT NULL DEFAULT '{}',
settings JSONB DEFAULT '{}',
created_at TIMESTAMP DEFAULT now(),
updated_at TIMESTAMP DEFAULT now()
);
CREATE INDEX idx_blocks_lesson ON blocks(lesson_id);
CREATE INDEX idx_blocks_sort ON blocks(lesson_id, sort_order); marathon_enrollments
Записи учеников на марафоны
CREATE TABLE marathon_enrollments (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
marathon_id UUID NOT NULL REFERENCES marathons(id) ON DELETE CASCADE,
curator_id UUID REFERENCES users(id),
starts_at TIMESTAMP NOT NULL,
expires_at TIMESTAMP,
total_points INT DEFAULT 0,
completed_lessons INT DEFAULT 0,
last_lesson_id UUID REFERENCES lessons(id),
status VARCHAR(20) DEFAULT 'active',
created_at TIMESTAMP DEFAULT now(),
updated_at TIMESTAMP DEFAULT now(),
UNIQUE(user_id, marathon_id)
);
CREATE INDEX idx_enrollments_user ON marathon_enrollments(user_id);
CREATE INDEX idx_enrollments_marathon ON marathon_enrollments(marathon_id);
CREATE INDEX idx_enrollments_curator ON marathon_enrollments(curator_id); lesson_progress
Прогресс ученика по урокам
CREATE TABLE lesson_progress (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
lesson_id UUID NOT NULL REFERENCES lessons(id) ON DELETE CASCADE,
enrollment_id UUID NOT NULL REFERENCES marathon_enrollments(id) ON DELETE CASCADE,
status VARCHAR(20) DEFAULT 'not_started',
points_earned INT DEFAULT 0,
video_progress JSONB DEFAULT '{}',
started_at TIMESTAMP,
completed_at TIMESTAMP,
created_at TIMESTAMP DEFAULT now(),
updated_at TIMESTAMP DEFAULT now(),
UNIQUE(user_id, lesson_id)
);
CREATE INDEX idx_progress_user ON lesson_progress(user_id);
CREATE INDEX idx_progress_enrollment ON lesson_progress(enrollment_id); homework_submissions
Отправленные домашние задания
CREATE TABLE homework_submissions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
lesson_id UUID NOT NULL REFERENCES lessons(id) ON DELETE CASCADE,
enrollment_id UUID NOT NULL REFERENCES marathon_enrollments(id) ON DELETE CASCADE,
content JSONB NOT NULL,
status VARCHAR(20) DEFAULT 'pending',
reviewer_id UUID REFERENCES users(id),
reviewed_at TIMESTAMP,
feedback TEXT,
feedback_audio VARCHAR(500),
grade INT,
bonus_points INT DEFAULT 0,
version INT DEFAULT 1,
parent_id UUID REFERENCES homework_submissions(id),
submitted_at TIMESTAMP DEFAULT now(),
created_at TIMESTAMP DEFAULT now(),
updated_at TIMESTAMP DEFAULT now()
);
CREATE INDEX idx_hw_user ON homework_submissions(user_id);
CREATE INDEX idx_hw_status ON homework_submissions(status);
CREATE INDEX idx_hw_reviewer ON homework_submissions(reviewer_id); chats
Чаты между куратором и учеником
CREATE TABLE chats (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
student_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
curator_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
marathon_id UUID REFERENCES marathons(id),
last_message_at TIMESTAMP,
last_message_preview VARCHAR(100),
student_unread INT DEFAULT 0,
curator_unread INT DEFAULT 0,
created_at TIMESTAMP DEFAULT now(),
updated_at TIMESTAMP DEFAULT now(),
UNIQUE(student_id, curator_id, marathon_id)
);
CREATE INDEX idx_chats_student ON chats(student_id);
CREATE INDEX idx_chats_curator ON chats(curator_id); messages
Сообщения в чатах
CREATE TABLE messages (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
chat_id UUID NOT NULL REFERENCES chats(id) ON DELETE CASCADE,
sender_id UUID NOT NULL REFERENCES users(id),
type VARCHAR(20) DEFAULT 'text',
content TEXT,
attachments JSONB DEFAULT '[]',
status VARCHAR(20) DEFAULT 'sent',
read_at TIMESTAMP,
created_at TIMESTAMP DEFAULT now(),
deleted_at TIMESTAMP
);
CREATE INDEX idx_messages_chat ON messages(chat_id);
CREATE INDEX idx_messages_created ON messages(chat_id, created_at DESC); stories
Сторисы
CREATE TABLE stories (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
title VARCHAR(255) NOT NULL,
media_url VARCHAR(500) NOT NULL,
media_type VARCHAR(10) NOT NULL,
thumbnail_url VARCHAR(500),
link_url VARCHAR(500),
link_text VARCHAR(50),
marathon_id UUID REFERENCES marathons(id),
sort_order INT DEFAULT 0,
starts_at TIMESTAMP,
ends_at TIMESTAMP,
is_active BOOLEAN DEFAULT true,
views_count INT DEFAULT 0,
created_by UUID REFERENCES users(id),
created_at TIMESTAMP DEFAULT now(),
updated_at TIMESTAMP DEFAULT now(),
deleted_at TIMESTAMP
);
CREATE INDEX idx_stories_active ON stories(is_active, starts_at, ends_at); story_views
Просмотры сторисов
CREATE TABLE story_views (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
story_id UUID NOT NULL REFERENCES stories(id) ON DELETE CASCADE,
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
viewed_at TIMESTAMP DEFAULT now(),
UNIQUE(story_id, user_id)
);
CREATE INDEX idx_story_views_user ON story_views(user_id); curator_marathon_assignments
Привязка кураторов к марафонам
CREATE TABLE curator_marathon_assignments (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
curator_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
marathon_id UUID NOT NULL REFERENCES marathons(id) ON DELETE CASCADE,
max_students INT DEFAULT 50,
is_active BOOLEAN DEFAULT true,
created_at TIMESTAMP DEFAULT now(),
UNIQUE(curator_id, marathon_id)
); teacher_marathon_assignments
Привязка учителей к марафонам
CREATE TABLE teacher_marathon_assignments (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
teacher_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
marathon_id UUID NOT NULL REFERENCES marathons(id) ON DELETE CASCADE,
is_active BOOLEAN DEFAULT true,
created_at TIMESTAMP DEFAULT now(),
UNIQUE(teacher_id, marathon_id)
); notifications
Уведомления пользователей
CREATE TABLE notifications (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
type VARCHAR(50) NOT NULL,
title VARCHAR(255) NOT NULL,
body TEXT,
data JSONB DEFAULT '{}',
is_read BOOLEAN DEFAULT false,
read_at TIMESTAMP,
created_at TIMESTAMP DEFAULT now()
);
CREATE INDEX idx_notifications_user ON notifications(user_id);
CREATE INDEX idx_notifications_unread ON notifications(user_id, is_read); refresh_tokens
Токены для обновления JWT
CREATE TABLE refresh_tokens (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
token VARCHAR(500) UNIQUE NOT NULL,
device_info VARCHAR(255),
ip_address VARCHAR(45),
expires_at TIMESTAMP NOT NULL,
created_at TIMESTAMP DEFAULT now()
);
CREATE INDEX idx_refresh_tokens_user ON refresh_tokens(user_id);
CREATE INDEX idx_refresh_tokens_token ON refresh_tokens(token); file_uploads
Загруженные файлы
CREATE TABLE file_uploads (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES users(id),
original_name VARCHAR(255) NOT NULL,
stored_name VARCHAR(255) NOT NULL,
mime_type VARCHAR(100),
size_bytes BIGINT,
url VARCHAR(500) NOT NULL,
storage_path VARCHAR(500),
entity_type VARCHAR(50),
entity_id UUID,
created_at TIMESTAMP DEFAULT now()
);
CREATE INDEX idx_files_user ON file_uploads(user_id);
CREATE INDEX idx_files_entity ON file_uploads(entity_type, entity_id); activity_logs
Лог активности для аналитики
CREATE TABLE activity_logs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES users(id),
action VARCHAR(100) NOT NULL,
entity_type VARCHAR(50),
entity_id UUID,
metadata JSONB DEFAULT '{}',
ip_address VARCHAR(45),
user_agent VARCHAR(500),
created_at TIMESTAMP DEFAULT now()
);
CREATE INDEX idx_activity_user ON activity_logs(user_id);
CREATE INDEX idx_activity_action ON activity_logs(action);
CREATE INDEX idx_activity_created ON activity_logs(created_at); quiz_attempts
Попытки прохождения тестов
CREATE TABLE quiz_attempts (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
block_id UUID NOT NULL REFERENCES blocks(id) ON DELETE CASCADE,
answers JSONB NOT NULL,
score INT NOT NULL,
max_score INT NOT NULL,
is_passed BOOLEAN DEFAULT false,
attempt_number INT DEFAULT 1,
time_spent_sec INT,
created_at TIMESTAMP DEFAULT now()
);
CREATE INDEX idx_quiz_user ON quiz_attempts(user_id);
CREATE INDEX idx_quiz_block ON quiz_attempts(block_id); 🔌 23. API Эндпоинты
RESTful API с версионированием. Base URL: /api/v1
🔐 Аутентификация
| Метод | Endpoint | Описание | Доступ |
|---|---|---|---|
| POST | /auth/register | Регистрация ученика | Public |
| POST | /auth/login | Вход по email/password | Public |
| POST | /auth/refresh | Обновить токены | Public |
| POST | /auth/logout | Выход (инвалидация токена) | Auth |
| POST | /auth/forgot-password | Запрос сброса пароля | Public |
| POST | /auth/reset-password | Установить новый пароль | Public |
| GET | /auth/me | Получить текущего пользователя | Auth |
👥 Админ: Пользователи
| Метод | Endpoint | Описание |
|---|---|---|
| GET | /admin/users | Список пользователей (фильтры, пагинация) |
| POST | /admin/users | Создать пользователя |
| GET | /admin/users/:id | Получить пользователя |
| PUT | /admin/users/:id | Обновить пользователя |
| DELETE | /admin/users/:id | Удалить пользователя |
| POST | /admin/users/:id/block | Заблокировать |
| POST | /admin/users/:id/unblock | Разблокировать |
| POST | /admin/users/import | Импорт из Excel |
| GET | /admin/users/export | Экспорт в Excel |
🏃 Админ: Марафоны
| Метод | Endpoint | Описание |
|---|---|---|
| GET | /admin/marathons | Список марафонов |
| POST | /admin/marathons | Создать марафон |
| GET | /admin/marathons/:id | Получить марафон |
| PUT | /admin/marathons/:id | Обновить марафон |
| DELETE | /admin/marathons/:id | Удалить марафон |
| POST | /admin/marathons/:id/publish | Опубликовать |
| POST | /admin/marathons/:id/archive | Архивировать |
| POST | /admin/marathons/:id/duplicate | Дублировать |
| GET | /admin/marathons/:id/students | Ученики марафона |
| GET | /admin/marathons/:id/stats | Статистика марафона |
📦 Админ: Модули
| Метод | Endpoint | Описание |
|---|---|---|
| GET | /admin/marathons/:marathonId/modules | Список модулей |
| POST | /admin/marathons/:marathonId/modules | Создать модуль |
| GET | /admin/modules/:id | Получить модуль |
| PUT | /admin/modules/:id | Обновить модуль |
| DELETE | /admin/modules/:id | Удалить модуль |
| PUT | /admin/modules/reorder | Изменить порядок |
📖 Админ: Уроки
| Метод | Endpoint | Описание |
|---|---|---|
| GET | /admin/modules/:moduleId/lessons | Список уроков |
| POST | /admin/modules/:moduleId/lessons | Создать урок |
| GET | /admin/lessons/:id | Получить урок с блоками |
| PUT | /admin/lessons/:id | Обновить урок |
| DELETE | /admin/lessons/:id | Удалить урок |
| PUT | /admin/lessons/reorder | Изменить порядок |
🧱 Админ: Блоки контента
| Метод | Endpoint | Описание |
|---|---|---|
| GET | /admin/lessons/:lessonId/blocks | Список блоков |
| POST | /admin/lessons/:lessonId/blocks | Создать блок |
| GET | /admin/blocks/:id | Получить блок |
| PUT | /admin/blocks/:id | Обновить блок |
| DELETE | /admin/blocks/:id | Удалить блок |
| PUT | /admin/blocks/reorder | Изменить порядок |
📝 Админ: Записи на марафоны
| Метод | Endpoint | Описание |
|---|---|---|
| GET | /admin/enrollments | Список записей |
| POST | /admin/enrollments | Записать ученика на марафон |
| GET | /admin/enrollments/:id | Получить запись |
| PUT | /admin/enrollments/:id | Обновить (куратор, даты) |
| DELETE | /admin/enrollments/:id | Удалить запись |
| POST | /admin/enrollments/:id/extend | Продлить доступ |
| POST | /admin/enrollments/:id/assign-curator | Назначить куратора |
📋 Админ: Домашние задания
| Метод | Endpoint | Описание |
|---|---|---|
| GET | /admin/homework | Все ДЗ (фильтры) |
| GET | /admin/homework/:id | Детали ДЗ |
| POST | /admin/homework/:id/review | Проверить ДЗ |
| GET | /admin/homework/stats | Статистика по ДЗ |
📱 Админ: Сторисы
| Метод | Endpoint | Описание |
|---|---|---|
| GET | /admin/stories | Список сторисов |
| POST | /admin/stories | Создать сторис |
| GET | /admin/stories/:id | Получить сторис |
| PUT | /admin/stories/:id | Обновить сторис |
| DELETE | /admin/stories/:id | Удалить сторис |
| GET | /admin/stories/:id/stats | Статистика просмотров |
📊 Админ: Аналитика
| Метод | Endpoint | Описание |
|---|---|---|
| GET | /admin/analytics/dashboard | Общий дашборд |
| GET | /admin/analytics/users | Аналитика по пользователям |
| GET | /admin/analytics/marathons | Аналитика по марафонам |
| GET | /admin/analytics/homework | Аналитика по ДЗ |
| GET | /admin/analytics/curators | Эффективность кураторов |
👨🏫 Куратор
| Метод | Endpoint | Описание |
|---|---|---|
| GET | /curator/dashboard | Дашборд куратора |
| GET | /curator/students | Мои ученики |
| GET | /curator/students/:id | Детали ученика |
| GET | /curator/homework | ДЗ на проверку |
| GET | /curator/homework/:id | Детали ДЗ |
| POST | /curator/homework/:id/review | Проверить ДЗ |
| GET | /curator/chats | Список чатов |
| GET | /curator/chats/:id | Получить чат |
| GET | /curator/chats/:id/messages | Сообщения чата |
| POST | /curator/chats/:id/messages | Отправить сообщение |
👩🏫 Учитель
| Метод | Endpoint | Описание |
|---|---|---|
| GET | /teacher/dashboard | Дашборд учителя |
| GET | /teacher/marathons | Мои марафоны |
| GET | /teacher/homework | ДЗ на проверку |
| GET | /teacher/homework/:id | Детали ДЗ |
| POST | /teacher/homework/:id/review | Проверить ДЗ |
🎓 Ученик
| Метод | Endpoint | Описание |
|---|---|---|
| GET | /student/dashboard | Главная ученика |
| GET | /student/stories | Активные сторисы |
| POST | /student/stories/:id/view | Отметить просмотр |
| GET | /student/marathons | Мои марафоны |
| GET | /student/marathons/:id | Детали марафона |
| GET | /student/marathons/:id/progress | Мой прогресс |
| GET | /student/marathons/:id/leaderboard | Таблица лидеров |
| GET | /student/lessons/:id | Получить урок |
| POST | /student/lessons/:id/complete | Завершить урок |
| POST | /student/lessons/:id/progress | Сохранить прогресс видео |
| POST | /student/lessons/:id/homework | Отправить ДЗ |
| GET | /student/homework | Мои ДЗ |
| GET | /student/homework/:id | Детали ДЗ |
| POST | /student/quizzes/:blockId/submit | Отправить ответы теста |
| GET | /student/chat | Чат с куратором |
| GET | /student/chat/messages | Сообщения |
| POST | /student/chat/messages | Отправить сообщение |
| GET | /student/notifications | Уведомления |
| POST | /student/notifications/:id/read | Прочитать |
📁 Файлы
| Метод | Endpoint | Описание |
|---|---|---|
| POST | /files/upload | Загрузить файл |
| POST | /files/upload/image | Загрузить изображение |
| POST | /files/upload/video | Загрузить видео |
| POST | /files/upload/audio | Загрузить аудио |
| DELETE | /files/:id | Удалить файл |
🔄 WebSocket
// Подключение
ws://api.domain.com/ws?token=JWT_TOKEN
// События от сервера:
{
"event": "new_message",
"data": { /* message object */ }
}
{
"event": "homework_reviewed",
"data": { "homework_id": "...", "status": "approved" }
}
{
"event": "typing",
"data": { "chat_id": "...", "user_id": "..." }
}
// События от клиента:
{
"event": "typing_start",
"data": { "chat_id": "..." }
}
{
"event": "message_read",
"data": { "message_id": "..." }
} 📤 24. Формат ответов API
Успешный ответ
{
"success": true,
"data": {
// данные
},
"meta": {
"page": 1,
"per_page": 20,
"total": 150,
"total_pages": 8
}
} Ошибка
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Validation failed",
"details": {
"email": "Invalid email format",
"password": "Minimum 8 characters"
}
}
} HTTP коды
| Код | Описание |
|---|---|
| 200 | OK — успех |
| 201 | Created — ресурс создан |
| 204 | No Content — удаление успешно |
| 400 | Bad Request — ошибка валидации |
| 401 | Unauthorized — не авторизован |
| 403 | Forbidden — нет доступа |
| 404 | Not Found — не найдено |
| 409 | Conflict — конфликт (дубликат) |
| 422 | Unprocessable Entity — бизнес-логика |
| 500 | Internal Server Error |
🚀 25. Деплой и инфраструктура
Рекомендуемый стек
- Хостинг: AWS / DigitalOcean / Hetzner
- Контейнеризация: Docker + Docker Compose
- Оркестрация: Kubernetes (для масштабирования)
- CI/CD: GitHub Actions
- База данных: PostgreSQL 15+ (managed или self-hosted)
- Кэш: Redis
- Файлы: S3 / MinIO
- CDN: CloudFlare
- Мониторинг: Prometheus + Grafana
- Логи: ELK Stack / Loki
Переменные окружения
# Server
APP_ENV=production
APP_PORT=8080
APP_SECRET=your-secret-key
# Database
DB_HOST=localhost
DB_PORT=5432
DB_NAME=marathon_lms
DB_USER=postgres
DB_PASSWORD=secret
# Redis
REDIS_HOST=localhost
REDIS_PORT=6379
# JWT
JWT_SECRET=your-jwt-secret
JWT_ACCESS_TTL=15m
JWT_REFRESH_TTL=7d
# S3
S3_ENDPOINT=https://s3.amazonaws.com
S3_BUCKET=marathon-files
S3_ACCESS_KEY=xxx
S3_SECRET_KEY=xxx
# Email
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=noreply@domain.com
SMTP_PASSWORD=xxx
# Push Notifications
FCM_SERVER_KEY=xxx
APNS_KEY_ID=xxx ✅ 26. Итоговая сводка
Что покрывает эта документация
| ✅ | 4 роли пользователей с разными правами |
| ✅ | Полный CRUD для марафонов, модулей, уроков |
| ✅ | 15 типов блоков контента |
| ✅ | Система домашних заданий с проверкой |
| ✅ | Чат ученик-куратор в реальном времени |
| ✅ | Сторисы с таргетингом |
| ✅ | Рейтинг и геймификация |
| ✅ | Прогресс и аналитика |
| ✅ | Уведомления (push + in-app) |
| ✅ | Полная схема базы данных |
| ✅ | REST API эндпоинты |
| ✅ | WebSocket события |
Рекомендации по разработке
- MVP (4-6 недель): Auth, марафоны, уроки, базовые блоки
- V1 (8-10 недель): + ДЗ, чат, сторисы, рейтинг
- V2 (12+ недель): + аналитика, импорт/экспорт, мобильное приложение
Команда разработки
- 1 Backend разработчик (Go)
- 1 Frontend разработчик (React/Next.js)
- 1 Mobile разработчик (Flutter/React Native) — для V2
- 0.5 DevOps (настройка инфраструктуры)
🎉 Документация готова к разработке!
Версия: 1.0 | Дата: Январь 2025
При вопросах — обращайтесь к автору ТЗ
