# ADR-018: Устройство — случайный идентификатор в IndexedDB Закрывает открытый вопрос из [ADR-008](008-server-relay.md). ## Контекст Очередь недоставленных сообщений — per-device (ADR-008), подписка на пуши — тоже per-device (ADR-011). Серверу нужно отличать устройства одного аккаунта. Стабильного идентификатора браузера не существует, и это правильно; его надо завести самим. ## Решение - При первом запуске клиент генерирует 128-битный случайный `deviceId` (`crypto.getRandomValues`) и хранит его в IndexedDB рядом с историей. Одно хранилище — один жизненный цикл: стёрли данные сайта — исчезли и история, и идентичность устройства. Новый запуск — новое устройство. - При входе клиент передаёт `deviceId`. Сервер создаёт запись устройства с ключом (аккаунт, `deviceId`) и очередь к нему. Сессионная cookie привязана к устройству. - `deviceId` — не секрет, а адрес очереди. Аутентифицирует сессия. Коллизии между аккаунтами невозможны: ключ составной. - Доставка — серверный fan-out: сообщение раскладывается в очереди всех устройств всех участников, кроме отправившего. Отправитель не знает и не должен знать устройств адресата: все устройства одного аккаунта владеют одним приватным ключом (ADR-006), шифротекст один для всех. - Устройство без связи 30 дней удаляется вместе с очередью и push-подпиской — тот же срок, что TTL очереди (ADR-008). На следующем запуске клиент регистрируется как новое устройство; локальная история при этом цела. - Клиент при регистрации устройства передаёт короткую метку из user-agent («Firefox · Linux»). Список устройств с метками и датой последней связи виден в настройках; любое можно удалить — очередь и сессия уничтожаются. ## Следствия - Сообщение, отправленное с телефона, появляется и на ноутбуке — как новое, через его очередь. Это не синхронизация истории: то, что было до появления устройства, на него не приедет. - Один браузер в двух профилях или в режиме инкогнито — разные устройства. Инкогнито плодит устройства при каждом запуске; их чистит 30-дневный срок и лимит в 10 устройств (ADR-017). - Потеря `deviceId` (чистка storage) эквивалентна потере устройства: недоставленное в старую очередь пропадает по TTL. `navigator.storage.persist()` (ADR-009) снижает риск.