Student

Прохождение тестов

Студенческий поток прохождения теста: начать попытку, прочитать текущее состояние, сохранить ответы (merge по question_id) и отправить попытку на автооценку. Все эндпоинты требуют авторизации; дополнительного гейта прав нет.

POST/api/v1/t/attempts

Начать попытку

Student JWT

Создаёт новую попытку прохождения теста. Идентификатор пользователя и его роль берутся из JWT, а не из тела запроса — клиент не может подменить личность. Роль на момент старта сохраняется как actor_role для последующей аналитики.

Стартовать попытку могут student/curator/admin одной школы. При исчерпании лимита попыток возвращается 409 max_attempts_reached. Если урок с этим тестом ограничен по дате (расписание курса), новая попытка после дедлайна возвращает 403 schedule_window_closed — КРОМЕ студентов, начавших хотя бы одну попытку до дедлайна (правило «первой попытки»). Админ/куратор это ограничение обходят.

Тело запроса

ПараметрТипОписание
quiz_idобяз.uuidИдентификатор теста.

Пример запроса

cURL
curl -X POST https://api.edumentor.kz/api/v1/t/attempts \
  -H "Authorization: Bearer <token>" \
  -H "X-Tenant-Subdomain: acme" \
  -H "Content-Type: application/json" \
  -d '{ "quiz_id": "9c1f2e3a-..." }'

Пример ответа

200 OK · application/json
{
  "success": true,
  "data": {
    "id": "11112222-...",
    "quiz_id": "9c1f2e3a-...",
    "user_id": "33334444-...",
    "status": "in_progress",
    "actor_role": "student",
    "score": "0.00",
    "max_score": "0.00",
    "passed": null,
    "started_at": "2026-05-28T09:00:00Z",
    "deadline_at": "2026-05-28T09:30:00Z",
    "submitted_at": null,
    "auto_finalized": false
  }
}

Ошибки

КодerrorКогда
400invalid_request_bodyТело запроса не прошло валидацию (отсутствует quiz_id).
400invalid_actor_roleРоль в JWT некорректна — попытка отклонена.
401unauthorizedТокен отсутствует или недействителен.
403schedule_window_closedУрок теста вне окна доступа по расписанию, и правило «первой попытки» не применимо (студент не начинал попытку до дедлайна).
404quiz_not_foundТест не найден или принадлежит другой школе.
409max_attempts_reachedИсчерпан лимит попыток для этого теста.
GET/api/v1/t/attempts/:id

Получить попытку

Student JWT

Возвращает текущее состояние попытки. Владелец (ученик-автор попытки) видит её всегда. Куратор/админ могут просматривать попытку в рамках своих прав (менеджер-куратор или куратор, у которого ученик в его группе); прочим возвращается 404, чтобы не раскрывать существование чужих попыток. Дополнительно в ответе возвращается saved_answers — массив сохранённых ответов студента для восстановления выбранных вариантов при возобновлении/обновлении; поле опускается, когда ещё ничего не сохранено. Каждый элемент несёт также awarded_points и is_correct — вердикт по вопросу (0 / false, пока попытка in_progress; после submit — фактически начисленные баллы и правильность).

Параметры пути

ПараметрТипОписание
idобяз.uuidИдентификатор попытки.

Пример запроса

cURL
curl https://api.edumentor.kz/api/v1/t/attempts/11112222-... \
  -H "Authorization: Bearer <token>" \
  -H "X-Tenant-Subdomain: acme"

Пример ответа

200 OK · application/json
{
  "success": true,
  "data": {
    "id": "11112222-...",
    "quiz_id": "9c1f2e3a-...",
    "user_id": "33334444-...",
    "status": "submitted",
    "actor_role": "student",
    "score": "2.00",
    "max_score": "3.00",
    "passed": true,
    "started_at": "2026-05-28T09:00:00Z",
    "deadline_at": "2026-05-28T09:30:00Z",
    "submitted_at": "2026-05-28T09:12:00Z",
    "auto_finalized": false,
    "saved_answers": [
      {
        "question_id": "a1b2c3d4-...",
        "payload": { "answer_ids": ["..."] },
        "awarded_points": "2.00",
        "is_correct": true
      }
    ]
  }
}

Ошибки

КодerrorКогда
400invalid_id_formatid не является корректным UUID.
401unauthorizedТокен отсутствует или недействителен.
404attempt_not_foundПопытка не найдена, принадлежит другой школе или недоступна вызывающему.
POST/api/v1/t/attempts/:id/answers

Сохранить ответы

Student JWT

Сохраняет ответы по вопросам. Каждая запись upsert-ится по паре (attempt_id, question_id), поэтому повторные вызовы безопасно сливаются (PATCH-семантика). Возвращает число сохранённых ответов.

Форма payload зависит от типа вопроса, причём принимается ЛЮБОЙ из поддерживаемых ключей (это устранило баг, когда ответы с ключом answer_ids не засчитывались и итоговый результат был 0). Для single_choice — answer_ids (массив, первый элемент берётся как выбранный), selected_answer_id или selected_option_id. Для multiple_choice — answer_ids, selected_answer_ids или selected_option_ids. Для free_text — { text }. Для matching — массив пар { left_id, right_id }, где left_id берётся из match_lefts[].id, а right_id — из match_rights[].id студенческого представления вопроса (это токен, НЕ сырой match.id). Подробно про формулы баллов и формат ответов — в разделе Начисление баллов и ответы на вопросы. Сервер декодирует payload по типу вопроса. Сохранение в уже отправленную попытку даёт 409 attempt_already_submitted.

Параметры пути

ПараметрТипОписание
idобяз.uuidИдентификатор попытки.

Тело запроса

ПараметрТипОписание
answersобяз.objectМассив { question_id (uuid), payload (object — зависит от типа вопроса) }; минимум 1.

Пример запроса

cURL
curl -X POST https://api.edumentor.kz/api/v1/t/attempts/11112222-.../answers \
  -H "Authorization: Bearer <token>" \
  -H "X-Tenant-Subdomain: acme" \
  -H "Content-Type: application/json" \
  -d '{
    "answers": [
      { "question_id": "a1b2c3d4-...", "payload": { "answer_ids": ["..."] } },
      { "question_id": "e5f6a7b8-...", "payload": { "text": "Мой ответ" } }
    ]
  }'

Пример ответа

200 OK · application/json
{
  "success": true,
  "data": { "saved": 2 }
}

Ошибки

КодerrorКогда
400invalid_request_bodyТело запроса не прошло валидацию.
400invalid_id_formatid попытки не является корректным UUID.
400question_not_in_quizОдин из question_id не относится к тесту этой попытки.
401unauthorizedТокен отсутствует или недействителен.
404attempt_not_foundПопытка не найдена или принадлежит другой школе.
404quiz_not_foundТест попытки не найден.
409attempt_already_submittedПопытка уже отправлена — изменять ответы нельзя.
POST/api/v1/t/attempts/:id/submit

Отправить попытку

Student JWT

Завершает попытку и запускает автооценку. Тело запроса игнорируется полностью — любые присланные клиентом score/passed/submitted_at отбрасываются; источником истины по баллу является сервер. Возвращает обновлённую попытку с итоговым баллом.

Для тестов со свободными ответами (free_text) итоговый балл может быть неполным до проверки куратором. Повторная отправка даёт 409 attempt_already_submitted.

Параметры пути

ПараметрТипОписание
idобяз.uuidИдентификатор попытки.

Пример запроса

cURL
curl -X POST https://api.edumentor.kz/api/v1/t/attempts/11112222-.../submit \
  -H "Authorization: Bearer <token>" \
  -H "X-Tenant-Subdomain: acme"

Пример ответа

200 OK · application/json
{
  "success": true,
  "data": {
    "id": "11112222-...",
    "quiz_id": "9c1f2e3a-...",
    "user_id": "33334444-...",
    "status": "submitted",
    "actor_role": "student",
    "score": "8.00",
    "max_score": "10.00",
    "passed": true,
    "started_at": "2026-05-28T09:00:00Z",
    "deadline_at": "2026-05-28T09:30:00Z",
    "submitted_at": "2026-05-28T09:25:00Z",
    "auto_finalized": false
  }
}

Ошибки

КодerrorКогда
400invalid_id_formatid попытки не является корректным UUID.
401unauthorizedТокен отсутствует или недействителен.
404attempt_not_foundПопытка не найдена или принадлежит другой школе.
404quiz_not_foundТест попытки не найден.
409attempt_already_submittedПопытка уже отправлена.