Files
transcriber/openspec/changes/archive/2026-08-12-oidc-login/specs/intake/spec.md
T
av c44f0e7582 HTTP API закрыт за вход через OIDC у Authelia
- шаг схемы закрывает поверхность, которую хранилище приносит открытой:
  собственную регистрацию, вход по паролю и одноразовый код — без этого
  закрытие приёма обходилось двумя запросами
- продление сессии выключено, срок семь суток: иначе отзыв доступа у
  провайдера до сервиса не доходит никогда
- файл записи отдаётся вошедшему по токену файла — пересмотр
  ADR-2026-08-12-file-link-open-but-not-logged
2026-08-12 17:44:22 +03:00

7.0 KiB
Raw Blame History

MODIFIED Requirements

Requirement: Приём записи по HTTP

Сервис SHALL принимать запись от внешней программы запросом POST /api/audio с телом multipart/form-data и полем audio только от узнанного отправителя. Запрос без сессии MUST получать код 401, и по нему MUST не заводиться ни файл, ни задача расшифровки. Принятая запись от узнанного отправителя MUST быть сохранена и получить заведённую под неё задачу расшифровки в состоянии created; ответ MUST нести идентификатор задачи полем job_id и её состояние полем status.

Отказ по отсутствию сессии наступает раньше чтения тела: запись, за которую не заплатит узнанный отправитель, не должна попасть даже в память.

Имена полей ответа нормативны: контракт HTTP API объявлен проектом необратимым, и переименование поля ломает внешнюю программу молча. Появление отказа без сессии — намеренная ломка этого контракта: до неё приём стоял открытым наружу.

Приём не судит о годности записи сам: расширение он берёт из имени файла, а пригодность содержимого узнаёт у источника метаданных.

Куда именно ложится принятая запись, приёму не принадлежит: раскладку выбирает хранилище, и нормирует её capability storage.

Владельца у принятой записи приём не заводит: после входа видно ровно то же, что видно было анонимно.

Scenario: Запись принята

  • GIVEN источник метаданных читает запись и отдаёт её длительность
  • AND отправитель предъявил сессию
  • WHEN программа шлёт POST /api/audio с полем audio
  • THEN ответ имеет код 201, а в теле лежат непустой job_id и status со значением created
  • AND содержимое записи целиком лежит в хранилище одним файлом

Scenario: Сессии нет

  • WHEN программа шлёт POST /api/audio с полем audio без сессии
  • THEN ответ имеет код 401
  • AND ни файла, ни задачи не заводится
  • AND тело ответа не несёт данных задачи

Scenario: Поля с записью нет

  • GIVEN отправитель предъявил сессию
  • WHEN программа шлёт POST /api/audio без поля audio
  • THEN ответ имеет код 400 и сообщение об отсутствии записи
  • AND ни файла, ни задачи не заводится

Scenario: Размеру записи приём не судья

  • GIVEN источник метаданных читает запись и отдаёт её длительность
  • AND отправитель предъявил сессию
  • WHEN программа шлёт запись нулевой длины
  • THEN ответ имеет код 201: собственного порога по размеру у приёма нет

Requirement: Опрос готовности задачи

Сервис SHALL отдавать состояние задачи расшифровки по запросу GET /api/status/:id только узнанному отправителю. Запрос без сессии MUST получать код 401, и тело такого ответа MUST не нести ни состояния задачи, ни текста расшифровки. Ответ узнанному отправителю MUST нести идентификатор полем job_id, состояние полем status и время заведения полем created_at, а текст расшифровки полем transcription_text, и это поле MUST отсутствовать в ответе, пока текста нет: пустая строка на месте отсутствующего текста читается как «расшифровка пуста».

Отказ без сессии MUST не зависеть от того, есть такая задача или нет: иначе по кодам ответа перебирается список заведённых задач.

Выборку по владельцу опрос не сужает: узнанный отправитель видит любую задачу по её идентификатору ровно как прежде. Сужение придёт отдельной задачей.

Scenario: Задача найдена

  • GIVEN отправитель предъявил сессию
  • WHEN программа спрашивает состояние заведённой задачи
  • THEN ответ имеет код 200 и несёт job_id, status и created_at

Scenario: Сессии нет

  • WHEN программа спрашивает состояние заведённой задачи без сессии
  • THEN ответ имеет код 401
  • AND тело ответа не несёт ни состояния задачи, ни текста расшифровки

Scenario: Без сессии неизвестная задача неотличима от заведённой

  • WHEN программа без сессии спрашивает состояние заведённой задачи, а затем состояние по неизвестному идентификатору
  • THEN оба ответа имеют код 401

Scenario: Расшифровки ещё нет

  • GIVEN отправитель предъявил сессию
  • WHEN программа спрашивает состояние задачи, которая ещё не дошла до текста
  • THEN поля transcription_text в ответе нет вовсе

Scenario: Задачи с таким идентификатором нет

  • GIVEN отправитель предъявил сессию
  • WHEN программа спрашивает состояние по неизвестному идентификатору
  • THEN ответ имеет код 404 и сообщение о ненайденной задаче