## ADDED Requirements ### Requirement: Приём записи по HTTP Сервис SHALL принимать запись от внешней программы запросом `POST /api/audio` с телом `multipart/form-data` и полем `audio`. Принятая запись MUST быть сохранена и получить заведённую под неё задачу расшифровки в состоянии `created`; ответ MUST нести идентификатор задачи полем `job_id` и её состояние полем `status`. Имена полей ответа нормативны: контракт HTTP API объявлен проектом необратимым, и переименование поля ломает внешнюю программу молча. Приём не судит о годности записи сам: расширение он берёт из имени файла, а пригодность содержимого узнаёт у источника метаданных. #### Scenario: Запись принята - **GIVEN** источник метаданных читает запись и отдаёт её длительность - **WHEN** программа шлёт `POST /api/audio` с полем `audio` - **THEN** ответ имеет код `201`, а в теле лежат непустой `job_id` и `status` со значением `created` - **AND** содержимое записи целиком лежит в каталоге хранения одним файлом #### Scenario: Поля с записью нет - **WHEN** программа шлёт `POST /api/audio` без поля `audio` - **THEN** ответ имеет код `400` и сообщение об отсутствии записи - **AND** ни файла, ни задачи не заводится #### Scenario: Размеру записи приём не судья - **GIVEN** источник метаданных читает запись и отдаёт её длительность - **WHEN** программа шлёт запись нулевой длины - **THEN** ответ имеет код `201`: собственного порога по размеру у приёма нет ### Requirement: Имя файла в хранилище Сервис SHALL сохранять принятую запись под собственным именем — идентификатором, к которому приписано расширение из имени файла отправителя. Имя, данное отправителем, MUST не попадать в хранилище: оно приходит извне и содержимым своим приёму не подконтрольно. Расширения в присланном имени нет — сервис MUST подставить `.audio`, чтобы у файла на диске расширение было всегда. #### Scenario: Расширение взято из имени отправителя - **WHEN** программа шлёт запись с именем `test.mp3` - **THEN** файл в каталоге хранения имеет расширение `.mp3` #### Scenario: Имени без расширения назначено своё - **WHEN** программа шлёт запись с именем `test` без расширения - **THEN** файл в каталоге хранения имеет расширение `.audio` ### Requirement: Отказ чтения метаданных Сервис SHALL отвечать отказом, когда источник метаданных не смог прочитать принятую запись. Ответ MUST иметь код `500`, а причина отказа MUST не попадать в тело ответа: она принадлежит журналу, а не отправителю. #### Scenario: Источник метаданных вернул ошибку - **GIVEN** источник метаданных не может прочитать запись - **WHEN** программа шлёт `POST /api/audio` с этой записью - **THEN** ответ имеет код `500` - **AND** задача расшифровки не заводится ### Requirement: Опрос готовности задачи Сервис SHALL отдавать состояние задачи расшифровки по запросу `GET /api/status/:id`. Ответ MUST нести идентификатор полем `job_id`, состояние полем `status` и время заведения полем `created_at`, а текст расшифровки полем `transcription_text`, и это поле MUST отсутствовать в ответе, пока текста нет: пустая строка на месте отсутствующего текста читается как «расшифровка пуста». #### Scenario: Задача найдена - **WHEN** программа спрашивает состояние заведённой задачи - **THEN** ответ имеет код `200` и несёт `job_id`, `status` и `created_at` #### Scenario: Расшифровки ещё нет - **WHEN** программа спрашивает состояние задачи, которая ещё не дошла до текста - **THEN** поля `transcription_text` в ответе нет вовсе #### Scenario: Задачи с таким идентификатором нет - **WHEN** программа спрашивает состояние по неизвестному идентификатору - **THEN** ответ имеет код `404` и сообщение о ненайденной задаче