Files
bare/docs/decisions/052-settings-devices-and-space.md
mayatnikovandClaude Opus 5 0c878477d2 Этап 5: история — экспорт и импорт .bare, устройства, место, пагинация
Экспорт: ключ архива из секрета аккаунта через HKDF, заголовок ровно 65 байт
(magic, версия, соль, 32 сырых байта отпечатка владельца, iv) и он же целиком
AAD шифротекста. Ника владельца в файле нет. Импорт сверяет отпечаток до
расшифровки, сливает идемпотентно по id, а записи peers берёт только для
ников, которых в локальном TOFU ещё нет: архивом доверие к ключу не перебить.

Настройки: устройства с датой и пометкой «это устройство», «занято N МБ»,
кнопка «экспортировать» в подтверждении выхода и в подтверждении входа
под другим ником — долг этапа 1 и обещание ADR-029 закрыты.
Лента: страницы по 50 с подгрузкой вверх без прыжка прокрутки; новая
страница вставляется, а не пересобирает ленту.

ADR-050: импорт не перезаписывает лежащую запись — у своей есть состояние
отправки, которого в архиве нет.
ADR-054: архив — недоверенный ввод. Ревью собрало архивы с ts вне диапазона
Date, мусорным lastId, ником с bidi-переопределением и roomId с обходом пути:
каждый из них навсегда ломал ленту или счётчик. Теперь форма ника, roomId,
id, ts и автора проверяется, а lastId из файла не читается вовсе.
ADR-051, 052, 053: тексты и кнопки, устройства и место, страницы ленты
без виртуализации.

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

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015DbCjVfTFq4ZFG8juD45YJ
2026-08-23 02:57:51 +03:00

3.9 KiB

ADR-052: Своё устройство из настроек не удаляется; занятое место — оценка браузера

Контекст

docs/ui.md описывает раздел «устройства» одной строкой: список id (первые 8 символов), дата, «это устройство», «удалить». Три вещи в ней не решены, а решить их надо в коде.

Первая — что делает «удалить» у своей строки. DELETE /api/devices/{id} уносит очередь, подписку и сессии устройства (docs/protocol.md). На своём это означает: следующий же запрос получает 401 unauthenticated и по docs/ui.md («Сеть и состояния») уводит на экран входа с целой IndexedDB. Выходом это не является: «выйти» стирает историю и сначала предлагает её сохранить (ADR-051). Получается третье состояние, которого в документе нет, — выход без вопроса и без стирания, с прежним deviceId в meta, который при следующем входе заведёт устройство заново.

Вторая — какая дата. Сервер отдаёт две: createdAt и lastSeen.

Третья — что такое N в «занято N МБ». Байты storage.estimate() в мегабайтах дают дробь с десятком знаков, а браузер, который estimate() не умеет, не даёт и её.

Решение

  • Своё устройство из раздела не удаляется. У своей строки вместо кнопки стоит пометка «это устройство». Отцепляет текущее устройство «выйти»: там и вопрос про историю, и стирание базы.
  • Сервер не меняется: DELETE /api/devices/{id} принимает любое своё устройство, включая текущее. Запрет — правило экрана, а не протокола: устройство, потерявшее сессию с чужой руки, обязано оставаться рабочим сценарием.
  • Дата в строке — дата появления устройства (createdAt), в местной зоне, цифрами: 22.08.2026. lastSeen не показывается: список нужен, чтобы узнать своё среди чужих и отцепить лишнее.
  • «занято N МБ» — usage из navigator.storage.estimate(), МБ равен 1024×1024 байтам. Число человеческое: до десятых, пока меньше десяти, дальше целое; десятые округляются вверх, потому что пара сотен килобайт — это не «0 МБ». Браузер без estimate() строки не получает: писать в неё нечего.
  • Записано в docs/ui.md, «Настройки».

Следствия

  • Потерянное устройство отцепляется с любого другого; текущее — выходом.
  • Кнопки «удалить» у своей строки нет никогда, даже когда устройство одно.
  • Занятое место — оценка происхождения целиком, а не сумма длин записей: индексы и служебные страницы IndexedDB тоже место. Она же намеренно грубая у самого браузера, и точнее показывать нечего.