1Bilim Platform

Техническое задание на разработку образовательной платформы

Версия: 1.0.0
Дата: Январь 2025
Статус: В разработке

📋 1. Обзор проекта

1Bilim — образовательная платформа для проведения онлайн-марафонов по изучению языков. Платформа позволяет создавать структурированные курсы с модулями и уроками, отслеживать прогресс учеников, организовывать проверку домашних заданий и поддерживать коммуникацию между участниками.

Ключевые возможности

📚
Марафоны и курсы
Гибкая структура: марафоны → модули → уроки. Три режима прохождения.
🎨
Конструктор уроков
Блочный редактор с 10+ типами контента: текст, видео, аудио, тесты.
Домашние задания
Система отправки и проверки ДЗ кураторами и учителями.
📊
Аналитика и рейтинг
Отслеживание прогресса, таблица лидеров, статистика.
💬
Чат-система
Личные чаты ученик-куратор для поддержки и мотивации.
📱
Stories
Вовлекающий контент в формате историй.

🛠 2. Технологический стек

Frontend

⚛️ React 18+
📘 TypeScript
🎨 Tailwind CSS
🔄 TanStack Query
📦 Zustand
📝 React Hook Form

Backend

🐹 Go 1.21+
🌐 Gin Framework
🗃️ GORM
🔐 JWT Auth
📡 WebSocket
☁️ AWS S3

База данных & Инфра

🐘 PostgreSQL 15+
🔴 Redis
🐳 Docker
🔄 GitHub Actions

👥 3. Роли и права доступа

Описание ролей

Роль Описание Ключевые возможности
Admin Полный доступ к системе Всё: марафоны, пользователи, настройки, аналитика
Curator Куратор учеников Свои ученики, чат, проверка ДЗ, мотивация
Teacher Учитель / Преподаватель Ведение уроков, проверка ДЗ
Student Ученик Прохождение уроков, отправка ДЗ, чат с куратором

Матрица прав доступа

Функция Admin Curator Teacher Student
Создание/редактирование марафонов
Создание уроков
Управление всеми учениками
Просмотр своих учеников
Проверка ДЗ
Чат с учениками
Прохождение уроков
Отправка ДЗ
Управление кураторами/учителями
Управление сторисами
Полная аналитикаЧастичноЧастично

📚 4. Админ: Марафоны

Марафон — основная сущность платформы, представляющая учебный курс. Содержит модули с уроками.

Режимы прохождения

РежимКодОписание
ОткрытыйopenВсе уроки доступны сразу
ПоследовательныйsequentialСледующий урок после завершения предыдущего
С проверкойwith_reviewСледующий урок после проверки ДЗ

Функции

  • Создание, редактирование, удаление марафонов
  • Настройка обложки, описания, языка, уровня
  • Выбор режима прохождения
  • Настройка рейтинга (показывать/скрывать, топ-5/10/все)
  • Дублирование марафона
  • Привязка кураторов к марафону
  • Статусы: черновик, опубликован, архив

📂 5. Админ: Модули

Модуль — раздел внутри марафона, группирующий уроки по темам.

Функции

  • Создание модулей внутри марафона
  • Название, описание, порядок сортировки
  • Drag-and-drop для изменения порядка
  • Удаление модуля (с уроками или перенос)

Поля модуля

ПолеТипОписание
titlestringНазвание модуля
descriptiontextОписание (опционально)
sort_orderintПорядок отображения
is_publishedbooleanОпубликован ли

🎨 6. Админ: Конструктор уроков

Блочный редактор для создания уроков. Каждый урок состоит из блоков контента разных типов.

Типы блоков

ТипКодОписание
📝 ТекстtextRich-text с форматированием
🎬 ВидеоvideoYouTube, 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)
  • Привязка к марафону с указанием периода доступа
  • Назначение куратора ученику
  • Просмотр прогресса и статистики
  • Блокировка/разблокировка
  • Продление доступа к марафону

Поля ученика

ПолеТипОписание
emailstringEmail (уникальный)
phonestringТелефон
first_namestringИмя
last_namestringФамилия
avatar_urlstringАватар
statusenumactive, blocked, deleted
timezonestringЧасовой пояс

👨‍💼 9. Админ: Кураторы

Функции

  • Список всех кураторов
  • Добавление/редактирование куратора
  • Привязка к марафонам
  • Распределение учеников между кураторами
  • Статистика: кол-во учеников, проверенных ДЗ, время ответа
  • Лимит учеников на куратора

Поля куратора

ПолеТипОписание
emailstringEmail для входа
first_namestringИмя
last_namestringФамилия
phonestringТелефон
max_studentsintЛимит учеников
is_activebooleanАктивен ли

👩‍🏫 10. Админ: Учителя

Функции

  • Список всех учителей
  • Добавление/редактирование учителя
  • Привязка к марафонам (учитель видит только свои марафоны)
  • Статистика по проверенным ДЗ

Возможности учителя

  • Просмотр уроков в своих марафонах
  • Проверка ДЗ учеников своих марафонов
  • Обратная связь по ДЗ
  • Нет доступа: управление учениками, чат, создание марафонов

📱 11. Админ: Сторисы

Stories — вовлекающий контент в формате историй, отображается на главной ученика.

Функции

  • Создание сторисов (изображение или видео до 60 сек)
  • Настройка порядка отображения
  • Привязка к марафону (или глобальные для всех)
  • Период активности (дата начала — дата окончания)
  • Статистика просмотров
  • Ссылка/действие при клике

Поля сториса

ПолеТипОписание
titlestringНазвание (для админки)
media_urlstringURL изображения/видео
media_typeenumimage, video
link_urlstringСсылка при клике (опционально)
marathon_iduuidПривязка к марафону (null = для всех)
starts_attimestampНачало показа
ends_attimestampКонец показа
sort_orderintПорядок
is_activebooleanАктивен ли

💬 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. Куратор: Дашборд

Главная страница куратора с ключевыми метриками и быстрыми действиями.

Виджеты дашборда

👥
Мои ученики
Общее количество и активных за неделю
📝
ДЗ на проверку
Количество ожидающих ДЗ
💬
Непрочитанные
Сообщения в чатах
⚠️
Требуют внимания
Неактивные ученики (3+ дней)

Список учеников куратора

  • Фото, имя, марафон, прогресс
  • Последняя активность
  • Статус последнего ДЗ
  • Быстрый переход в чат
  • Фильтр: все, активные, неактивные, с ДЗ

✅ 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/passwordPublic
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 коды

КодОписание
200OK — успех
201Created — ресурс создан
204No Content — удаление успешно
400Bad Request — ошибка валидации
401Unauthorized — не авторизован
403Forbidden — нет доступа
404Not Found — не найдено
409Conflict — конфликт (дубликат)
422Unprocessable Entity — бизнес-логика
500Internal 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 события

Рекомендации по разработке

  1. MVP (4-6 недель): Auth, марафоны, уроки, базовые блоки
  2. V1 (8-10 недель): + ДЗ, чат, сторисы, рейтинг
  3. V2 (12+ недель): + аналитика, импорт/экспорт, мобильное приложение

Команда разработки

  • 1 Backend разработчик (Go)
  • 1 Frontend разработчик (React/Next.js)
  • 1 Mobile разработчик (Flutter/React Native) — для V2
  • 0.5 DevOps (настройка инфраструктуры)

🎉 Документация готова к разработке!

Версия: 1.0 | Дата: Январь 2025

При вопросах — обращайтесь к автору ТЗ