- паспорт: сервис объявлен архивом с бессрочным хранением записей и текстов, машинная вычитка расшифровки внутри границ, приложение — основной вход; добавлены две границы: не файловое хранилище общего назначения и не биллинг; - заведены цели upload-reliability, user-settings, usage-stats и тринадцать задач; очередь пересобрана — сперва починки, затем разведки о хранилище, затем доступ и владелец, и только потом экраны; - архитектура: четыре новых открытых вопроса — приём большого файла, учёт расхода, срок хранения, потолок шести часов.
42 lines
3.1 KiB
Markdown
42 lines
3.1 KiB
Markdown
# ✨ Узнавать уже загруженный файл по хеш-сумме
|
|
|
|
- **Тип:** feature
|
|
- **Категория:** Очередь
|
|
- **Зачем:** Один и тот же файл, отправленный дважды, распознаётся дважды и оплачивается дважды: приём не смотрит на содержимое вовсе.
|
|
- **Теги:** goal:upload-reliability
|
|
|
|
Двигает пункт 1 «Завершения» цели: повторная отправка того же файла возвращает
|
|
прежнюю запись вместо второй задачи.
|
|
|
|
Совпадение ищется **в пределах одного пользователя**: чужая расшифровка по
|
|
совпадению хеш-суммы не отдаётся и о её существовании отправитель не узнаёт.
|
|
|
|
## Затрагивает
|
|
|
|
- `TranscribeService.createTranscribeJob` — единая точка приёма, через неё идут
|
|
оба входа;
|
|
- таблица `files`: колонка хеш-суммы, её миграция и индекс по паре «владелец,
|
|
хеш-сумма»;
|
|
- контракт `POST /api/audio`: ответ на повторный файл;
|
|
- ответ бота на повторно присланное голосовое;
|
|
- `docs/database.md` — представление данных.
|
|
|
|
## Критерии приёмки
|
|
|
|
- Повторная отправка того же файла тем же пользователем возвращает
|
|
идентификатор прежней задачи, второй задачи в базе не появляется. Оракул —
|
|
тест приёма: два вызова одним содержимым, в репозитории одна задача.
|
|
- Тот же файл от другого пользователя заводит свою задачу и своё распознавание.
|
|
Оракул — тест приёма с двумя владельцами: две задачи, тексты не разделяются.
|
|
- Повторный файл не остаётся вторым экземпляром в каталоге хранения. Оракул —
|
|
тест: после второго вызова в каталоге один файл.
|
|
- Незавершённая задача тоже узнаётся: повторная отправка отдаёт её состояние, а
|
|
не заводит соседнюю. Оракул — тест на задаче в состоянии `created`.
|
|
|
|
## Рамки
|
|
|
|
Владелец записи приходит из `record-ownership` — до неё дедупликация опирается
|
|
на того владельца, который уже есть. Хеш-сумма считается на сервере: подсчёт на
|
|
стороне приложения относится к `chunked-upload-choice`. Колонка добавляется во
|
|
всех четырёх местах репозитория SQLite (инвариант `CLAUDE.md`).
|