## 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` и сообщение о ненайденной задаче