Files
transcriber/docs/adr/ADR-2026-08-14-account-with-records-is-not-deleted.md
T
av 8af8ec2e54 у записи появился владелец: чужую больше не отдают
- колонка `owner` связью с `users` в обеих коллекциях новым шагом схемы
  `202608140001`; чтение задачи сужено владельцем, и чужая, ничья и
  несуществующая дают один ответ; правило просмотра файлов сужено им же
- приём по HTTP берёт владельца из сессии, а предъявителя без учётной записи
  пользователя отвергает до чтения тела: позже пришлось бы убирать уложенный
  файл, а уборки файлов сервис не умеет. Выборка воркера владельцем не сужается
- удаление учётной записи с записями отвергается стражем, и вешает его сама
  сборка хранилища: сборка, забывшая его позвать, теряла защиту молча
2026-08-14 12:18:11 +03:00

5.2 KiB

ADR-2026-08-14. Учётная запись с записями не удаляется, и это осознанный тупик

Решение

Удаление учётной записи, у которой остались задачи расшифровки либо файлы, отвергается — отказом с названной причиной. Способа удалить записи в сервисе нет вовсе, поэтому до задачи про удаление записи такая учётная запись не удаляется никак: ни владельцем панели, ни самим человеком.

Решение принято человеком на чекпоинте задачи record-ownership из трёх предложенных способов.

Дословно из источника:

Что делать с записями удалённого пользователя? Связь при выключенном каскаде снимает ссылку — записи остаются, но становятся ничьими и недостижимыми по API навсегда. Способы: запретить удаление учётной записи, пока у неё есть записи; держать рядом со связью неизменяемый снимок идентификатора; признать потерю ценой и записать её.

Почему

Колонка владельца — связь с учётной записью, и каскадное удаление у неё выключено: сервис объявлен архивом и молча удалить чужой архив не вправе. Одного этого мало, и проверка по исходникам pocketbase@v0.39.10 показала почему: при выключенном каскаде хранилище вынимает идентификатор из поля связи и сохраняет запись без проверок. Задачи остались бы на месте, но стали бы ничьими — а ничья запись по правилу той же задачи не достаётся по API никому. Архив человека исчезал бы молча, и восстановить владельца было бы нечем: прежнего значения не остаётся нигде.

Прежнее обоснование выбора связи вместо строки — «связь удержит целостность» — было неверным, и это выяснилось на ревью дизайна.

Чем платим

Владелец панели упирается в отказ, а выхода из него сегодня нет: удаление записи приносит отдельная задача. Тупик назван прямо, а не обнаружен потом.

Отказ обязан доезжать до спрашивающего: хранилище пропускает наружу только свою ошибку роутера, а всякую другую подменяет сообщением про обязательную связь. Подсказка эта ведущая — единственная обязательная связь у задачи это файл, — и владелец панели, поверив ей, пошёл бы удалять записи руками, то есть делать ровно то необратимое, ради предотвращения чего запрет и заведён. Это нашло ревью кода.

Что рассматривалось и отвергнуто

  • Неизменяемый снимок идентификатора рядом со связью. Пережил бы удаление, и запись можно было бы вернуть человеку. Отвергнуто: владельцем становится любая строка, и целостность, ради которой выбрана связь, теряется.
  • Признать потерю ценой и записать её. Дешевле всего сегодня — удаления пользователей в сервисе нет вовсе. Отвергнуто: архив, теряемый одной кнопкой в панели, противоречит решению от 2026-08-11 о том, что сервис — архив.

Связанное

Запрет ставит сама сборка хранилища, а не вызывающий: сборка, забывшая его позвать, теряет защиту молча — и теряла, пока его добавляли отдельной строкой запуска. Норма — openspec/specs/storage, «Учётная запись с записями не удаляется».