# ✨ Узнавать уже загруженный файл по хеш-сумме - **Тип:** feature - **Категория:** Очередь — Дедупликация ищет совпадение в пределах пользователя — то есть после владельца записи, и экономит деньги с первого дня приложения. - **Зачем:** Один и тот же файл, отправленный дважды, распознаётся дважды и оплачивается дважды: приём не смотрит на содержимое вовсе. Повторная отправка того же файла возвращает прежнюю запись вместо второй задачи. Совпадение ищется **в пределах одного пользователя**: чужая расшифровка по совпадению хеш-суммы не отдаётся и о её существовании отправитель не узнаёт. ## Затрагивает - `TranscribeService.createTranscribeJob` — единая точка приёма, через неё идут оба входа; - таблица `files`: колонка хеш-суммы, её миграция и индекс по паре «владелец, хеш-сумма»; - контракт `POST /api/audio`: ответ на повторный файл; - ответ бота на повторно присланное голосовое; - `docs/database.md` — представление данных. ## Критерии приёмки - Повторная отправка того же файла тем же пользователем возвращает идентификатор прежней задачи, второй задачи в базе не появляется. Оракул — тест приёма: два вызова одним содержимым, в репозитории одна задача. - Тот же файл от другого пользователя заводит свою задачу и своё распознавание. Оракул — тест приёма с двумя владельцами: две задачи, тексты не разделяются. - Повторный файл не остаётся вторым экземпляром в каталоге хранения. Оракул — тест: после второго вызова в каталоге один файл. - Незавершённая задача тоже узнаётся: повторная отправка отдаёт её состояние, а не заводит соседнюю. Оракул — тест на задаче в состоянии `created`. ## Рамки Владелец записи приходит из `record-ownership` — до неё дедупликация опирается на того владельца, который уже есть. Хеш-сумма считается на сервере: подсчёт на стороне приложения относится к `chunked-upload-choice`. Колонка добавляется во всех четырёх местах пакета хранилища `internal/adapter/repo/pocketbase` — `applyToRecord`, `recordToJob`, `acquireColumns`, `acquiredRow` с её `toJob`, — плюс шаг схемы (инвариант `CLAUDE.md`).