- проверки больше не зовут ffprobe и не меняют рабочий каталог процесса; добавлены случаи на отказ чтения метаданных и на отсутствие поля audio - заведена спека intake на приём по HTTP, ADR о подставных адаптерах, запись в журнал ревью о проверке, которая не могла упасть - go test снят из объявленных долгов CLAUDE.md, послабление errcheck для _test.go в .golangci.yml убрано
91 lines
5.8 KiB
Markdown
91 lines
5.8 KiB
Markdown
## 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` и сообщение о ненайденной задаче
|