86 KiB
Luma — техническое задание для Web, Desktop и Android
Версия: 1.0. Дата: 14 октября 2026 года. Статус: целевой стандарт разработки.
Связанный документ: UI Kit.
Содержание
- 1. Назначение документа
- 2. Продукт и пользователи
- 3. Платформы и объём
- 4. Общие требования к реализации
- 5. Предметная модель
- 6. Аккаунты и вход
- 7. Соединение и аутентификация
- 8. Навигация и основные экраны
- 9. Контакты, presence и аватары
- 10. Текстовые сообщения и доставка
- 11. Действия над сообщениями
- 12. Реакции и typing
- 13. Группы MUC
- 14. Шифрование и устройства
- 15. Файлы и вложения
- 16. Просмотр и сохранение медиа
- 17. Запись аудио, видео и геопозиция
- 18. Локальная история и MAM
- 19. Звонки
- 20. Уведомления, push и фоновая работа
- 21. Локальная защита и хранение
- 22. Приватность и безопасность
- 23. Совместимость протоколов
- 24. Нефункциональные требования
- 25. Критерии приёмки
- 26. Состав результата разработки
- 27. Паспорт конкретного приложения
1. Назначение документа
Разработать семейство XMPP-приложений Luma с общими пользовательскими сценариями, совместимыми сообщениями и единым визуальным языком для Web, Desktop и Android.
Документ является самостоятельным техническим заданием. Он определяет результат, поведение и критерии приёмки без привязки к языку программирования, UI framework, структуре исходников и конкретной библиотеке XMPP.
«Обязательно» означает требование базового продукта. «При наличии возможности» означает управляемую зависимость от разрешений, оборудования, сервера или платформы, а не необязательную реализацию обработки отказа. Даже при отсутствии функции приложение обязано корректно объяснить ограничение и сохранить доступность остальных сценариев.
Требования с идентификаторами используются в тестах и задачах. Выбранные технологии, поддерживаемые версии ОС/браузеров и инфраструктурные адреса фиксируются отдельно в паспорте конкретного приложения до его выпуска.
2. Продукт и пользователи
Luma — мессенджер для пользователей существующих XMPP-аккаунтов. Пользователь входит по JID и паролю, выбирает совместимый сервер, общается лично и в группах, отправляет файлы и звонит другим пользователям.
Основные ценности:
- независимость от одного XMPP-провайдера;
- совместимость с другими XMPP-клиентами;
- конфиденциальность содержимого через OMEMO;
- локальная история и восстановление с сервера;
- одинаковая семантика сообщений и действий на разных устройствах;
- понятные ошибки и отсутствие молчаливого отключения защиты.
Интерфейс первого выпуска — русский. Вся пользовательская строка должна допускать последующее добавление локализаций. Идентификаторы протокола и адреса пользователей не переводятся.
3. Платформы и объём
| Платформа | Форма | Обязательный сценарий |
|---|---|---|
| Web | Приложение в браузере, адаптивное для телефона и компьютера | Работа в активной сессии, локальная история, сообщения, медиа и звонки при доступных разрешениях |
| Desktop | Устанавливаемое приложение для утверждённого набора настольных ОС | Оконный интерфейс, системные уведомления, работа при скрытом окне в пределах жизненного цикла процесса |
| Android | Устанавливаемое мобильное приложение | Сенсорный интерфейс, системный lifecycle, уведомления и входящие вызовы через поддержанный фоновый механизм |
3.1. Базовый объём
- несколько сохранённых аккаунтов, один активный XMPP-контекст;
- вход/выход/переключение, настройки подключения;
- контакты, presence, личные чаты и чат с собой;
- MUC: создание, вход, приглашение, выход, локальное удаление;
- текст, replies, reactions, correction, retraction и локальное удаление;
- множественный выбор и пересылка;
- OMEMO legacy и OMEMO 2, доверие устройствам;
- файлы, фото, видео, музыка, voice, video notes и геоточки;
- локальная история, MAM, Carbons, receipts и read state;
- аудио-/видеозвонки один на один и история звонков;
- аватары;
- настройка уведомлений, app lock и биометрия при доступности;
- серверная диагностика;
- push и фоновые входящие в пределах утверждённой платформенной интеграции.
3.2. За пределами базового объёма
Apple Watch и другие companion-устройства, регистрация новых XMPP-аккаунтов, восстановление серверного пароля, групповые звонки, каналы/MIX, боты, платежи, истории, live location, полнотекстовый поиск всех сообщений, обязательные одновременные соединения всех сохранённых аккаунтов.
Развёртывание XMPP-провайдера не является функцией пользовательского клиента. Инфраструктура push/relay, если нужна для заявленной доставки, входит в состав решения отдельным компонентом и должна быть поставлена либо явно подключена к утверждённому внешнему сервису.
4. Общие требования к реализации
GEN-001. Одинаковые действия на разных платформах должны иметь одинаковый смысл: «Отправлено», «Доставлено», «Прочитано», локальное удаление и отзыв нельзя интерпретировать по-разному.
GEN-002. UI, предметная логика, протоколы, хранение и системные интеграции разделяются устойчивыми интерфейсами. UI не владеет криптографической сессией или активным медиасоединением.
GEN-003. Криптография, обработка больших файлов, индексирование и архивная загрузка не должны монопольно занимать поток отображения интерфейса.
GEN-004. Все долгие операции имеют состояние выполнения, завершения, ошибки и отмены там, где отмена безопасна. Ошибка не оставляет интерфейс навсегда заблокированным.
GEN-005. Недоступная возможность сервера отключает соответствующую функцию с объяснением, сохраняя остальные функции. Поддержка, объявленная сервером, не отображается как уже настроенная интеграция приложения.
GEN-006. Приложение не обещает гарантированную доставку, прочтение, удаление чужих копий, работу закрытого процесса или конфиденциальность метаданных, если механизм этого не обеспечивает.
GEN-007. Исходные документы, тесты и поставляемая версия приложения должны соответствовать друг другу. Релиз имеет номер версии и журнал изменений.
5. Предметная модель
Ниже приведён логический контракт. Физическая схема БД и способы сериализации выбираются реализацией.
5.1. Аккаунт
| Атрибут | Содержание |
|---|---|
| accountId | Нормализованный bare JID, устойчивый ключ локального контекста |
| jid | Адрес пользователя |
| displayName | Отображаемое имя |
| deviceResource | Уникальный для установки ресурс соединения |
| connectionSettings | Endpoint/host/port, транспортный режим, настройки discovery |
| encryptionDefault | По умолчанию включён |
| typingEnabled | По умолчанию включён |
| notificationSettings | Разрешение/предпочтения, показ preview |
| credentialReference | Ссылка на защищённое хранилище, не пароль в общедоступном объекте |
Пароли, refresh tokens и приватные ключи не входят в открытый экспорт настроек.
5.2. Диалог
Идентичность диалога — accountId + conversationJid, а не один JID без контекста аккаунта.
Атрибуты: JID, direct/group, имя, avatar reference, lastActivity, lastMessagePreview, unreadCount, presence, optional pinned flag, encryptionOverride, group nickname, joined, autojoin, occupantCount и invitation metadata.
Значение joined после перезапуска определяется реальным соединением, а не только записью в БД. Режим шифрования: наследовать аккаунт / всегда включено / выключено.
5.3. Сообщение
| Группа | Атрибуты |
|---|---|
| Идентичность | accountId, conversationId, clientId, optional originId, server stanzaId, archive UID |
| Автор | sender JID, optional nickname/display name, incoming/outgoing |
| Содержимое | kind, body, timestamp |
| Доставка | sending / sent / delivered / read / failed |
| Защита | encrypted / plaintext / decryptionFailed, optional device/fingerprint reference |
| Медиа | remote URI, filename, MIME, byte count, duration, local asset reference |
| Изменения | editedAt, retractedAt |
| Reply | targetId, author JID, preview |
| Пересылка | Атрибуция источника, без ложного сохранения исходного авторства нового сообщения |
| Реакции | Автор → текущий набор emoji и timestamp |
| Звонок | Направление, audio/video, исход, начало, duration |
Kinds: text, attachment, photo, video, audio, voice, videoNote, location, system. Исторический звонок — системная запись с типизированными metadata.
5.4. Служебные сущности
- archive checkpoint: account/room archive key, opaque cursor, timestamp;
- local deletion suppression: account + conversation + идентификаторы удалённого сообщения;
- device: owner JID, id, protocol support, identity fingerprint, active/trust;
- attachment draft: staged asset, kind, filename, MIME, size, duration, thumbnail;
- call session: id, endpoint full JID, direction, media, phase, tracks/control state;
- pending operation: тип, target, автор, timestamp и ограниченный срок/объём удержания.
6. Аккаунты и вход
ACC-001. Входная форма содержит JID, пароль, показать/скрыть пароль и дополнительные настройки. Пустой JID/пароль не принимаются.
ACC-002. JID валидируется по выбранному XMPP address preparation; пробелы по краям ввода обрабатываются, resource не смешивается с bare account identity. Пароль не обрезается молча.
ACC-003. Native-клиенты поддерживают discovery и ручной host/port с STARTTLS/direct TLS. Стандартные порты: 5222 для STARTTLS, 5223 для direct TLS. Порт проверяется как число 1…65535; нечисловой ввод показывает ошибку, а не молча превращается в default.
ACC-004. Web-клиент использует защищённый WebSocket XMPP endpoint. Форма допускает ввод/выбор WSS endpoint и не обещает прямое использование произвольного TCP host/port браузером. BOSH не обязателен; если включён отдельно, допускается только HTTPS.
ACC-005. Endpoint discovery не должен незаметно отправлять пароль произвольному стороннему шлюзу. Пользователь видит домен выбранного endpoint; для неизвестной конфигурации требуется явный выбор сервера.
ACC-006. На время входа показывается progress и блокируется повторная отправка той же формы. После успешного входа открываются локальная история и основной интерфейс. Ошибка оставляет возможность исправить credentials.
ACC-007. Можно сохранить несколько аккаунтов. Добавление аккаунта делает его активным после успешного входа. Одновременно обязательно только одно активное соединение; неактивные аккаунты не представляются как постоянно online.
ACC-008. Переключение закрывает/отделяет старый контекст и открывает данные нового. Завершившаяся поздно операция прошлого аккаунта не может записать результат в новый аккаунт или отправить сообщение от его имени.
ACC-009. При доступных credentials запуск восстанавливает активный аккаунт и локальную историю, затем соединение. Если secrets недоступны/истекли, приложение запрашивает повторный вход без потери сохранённой истории.
ACC-010. Для каждого устройства создаётся устойчивый уникальный ресурс; одновременный запуск разных устройств одного аккаунта не должен создавать конфликт одинаковых default resources.
6.1. Выход и удаление данных
ACC-011. «Выйти» прекращает соединение, unregister/disable применимую push-привязку, удаляет сохранённые credentials текущего аккаунта и очищает его чувствительное session state. Локальную историю можно сохранить.
ACC-012. Отдельный вариант «Выйти и удалить локальные данные» удаляет историю, suppression, drafts, медиа cache и данные аккаунта в локальном профиле. Удаление OMEMO identity — явно обозначенный вариант со предупреждением о потере доступа к старым encrypted сообщениям; без согласия identity не уничтожается как побочный эффект обычного выхода.
ACC-013. Удаление локальных данных не называется secure erase и не обещает удаление server archives, exports, backup или чужих копий.
ACC-014. Перед уходом из аккаунта незавершённые записи/загрузки имеют определённое поведение: отмена либо сохранение безопасного локального результата; нет продолжения отправки от случайного другого аккаунта.
7. Соединение и аутентификация
NET-001. Подключение защищено TLS; проверяются certificate chain и ожидаемое имя сервиса/endpoint согласно используемому транспорту. Insecure HTTP/WS и обход ошибок сертификата не включены в пользовательский стандарт.
NET-002. Нативный транспорт поддерживает DNS discovery и ручные параметры. В Web используется WSS endpoint, утверждённый для выбранного сервера.
NET-003. Аутентификация выбирает наиболее сильный совместимый объявленный механизм. Приоритет SCRAM-PLUS с доступным channel binding, затем SCRAM-SHA-512/256/1, затем разрешённый защищённым транспортом fallback.
NET-004. PLUS не имитируется при отсутствии данных реального TLS-канала. В частности, реализации, не имеющие доступа к exporter/binding, выбирают совместимый non-PLUS механизм и корректно отражают это в диагностике.
NET-005. Проверяются nonce, server proof/signature, параметры challenge и применимые downgrade-protection данные. Для limits на challenge/iterations определяется защитная конфигурация, предотвращающая блокировку клиента недоверенным вводом.
NET-006. Состояния: отключено, подключение, подключено, восстановление, ошибка/требуется вход. Причина ошибки локализована. Нельзя показывать «Подключено» только по наличию сохранённого аккаунта.
NET-007. Поддерживаются stream management, carbons, ping и client-state indication при поддержке транспорта/сервера.
NET-008. Повторное соединение использует ограниченный backoff с jitter, прекращается при явном logout и не создаёт параллельных конкурирующих клиентов одного контекста. Возврат в foreground инициирует проверку/восстановление.
NET-009. Смена сети, sleep/wake, закрытие вкладки и потеря credentials обрабатываются без повреждения локального состояния. Возобновление stream не должно повторно создавать bubbles уже известных сообщений.
8. Навигация и основные экраны
NAV-001. Основные разделы: Контакты, Звонки, Чаты, Настройки. Начальный раздел — Чаты. Compact/wide варианты заданы UI Kit.
NAV-002. Поиск расположен над соответствующим списком. Поиск чатов — по имени/JID/аккаунту, контактов — по имени/JID, звонков — по собеседнику. Это фильтр списков; полнотекстовый поиск истории отдельно не обещается.
NAV-003. Чаты сортируются pinned-first при наличии pinned-функции, затем по последней активности, затем по имени для стабильности. Изменение unread не должно произвольно менять порядок при одинаковой активности.
NAV-004. В списке видны avatar, имя, preview, время, unread и применимый status. Аккаунт отображается при необходимости различать одинаковые JID.
NAV-005. Пустые данные и отсутствие совпадений поиска имеют разные объяснения. Создание чата/комнаты остаётся доступным в empty state.
NAV-006. Back возвращает в предыдущий логический контекст. На широком экране смена selection не должна ломать sidebar; клавиатурная навигация обязательна для Web/Desktop.
9. Контакты, presence и аватары
CON-001. Контакты синхронизируются через roster: initial state и последующие изменения. Удаление контакта из roster не удаляет историю.
CON-002. Новый direct chat открывается по валидному JID с optional name и выбором добавления в roster. Отсутствие roster membership не запрещает сообщение само по себе.
CON-003. Presence показывает реальное известное состояние; нет объявления online только из-за cached avatar/history.
CON-004. MUC-комнаты показываются отдельно от людей. Список сохранённых комнат не выдаётся за полный серверный список членства.
CON-005. Аватары публикуются/получаются через совместимые XMPP PEP mechanisms; legacy fallback допустим. Новый avatar нормализуется до разумного размера, baseline 512 px по длинной стороне.
CON-006. При отсутствии изображения используется стабильный цвет и инициалы, для группы — group symbol. Обновление cache не требует перезапуска клиента.
CON-007. Пользователю не обещается OMEMO для аватаров; доступ определяется серверными правами.
10. Текстовые сообщения и доставка
MSG-001. Пустое после trim сообщение не отправляется. Каждая новая отправка имеет устойчивый уникальный client/origin id и зафиксированный аккаунт/получателя.
MSG-002. До сетевого результата создаётся optimistic запись sending. Success transport send → sent, receipt → delivered, displayed → read. Ошибка → failed с объяснением.
MSG-003. Sent означает передачу по клиентскому протокольному пути, delivered — полученный receipt, read — подтверждённый marker. UI не выводит read только из времени или online собеседника.
MSG-004. Объединение live, Carbons и MAM не создаёт duplicate. Проверяются контекст аккаунта/чата и origin/stanza/client identities; archive UID не используется глобально для разных архивов.
MSG-005. Доставка повышается монотонно sending → sent → delivered → read. Failed не «исправляется» молча архивной копией; явная повторная отправка — отдельное действие с контролем дубликатов.
MSG-006. Порядок ленты — timestamp и устойчивый id при равных датах. Архивная вставка сверху сохраняет viewport.
MSG-007. Служебные receipts, reactions, markers и пустые protocol messages не становятся обычными bubbles. Реальная ошибка дешифрования отображается как отдельное безопасное состояние.
MSG-008. Чат с собой поддерживает текст/медиа и sync. Успешное собственное сообщение допускается помечать read по определённому self-chat правилу.
MSG-009. У исходящего failed text доступно явное «Повторить», если payload сохранён. Повтор не должен незаметно менять encryption policy уже подготовленного сообщения; изменение режима требует нового явного решения.
10.1. Непрочитанные
READ-001. Новое входящее увеличивает локальный unread, если чат не просматривается активно. Архивный replay не раздувает счётчик повторно.
READ-002. При активном просмотре last-visible/latest incoming direct message отправляется displayed по протоколу; одно и то же состояние не рассылается без необходимости.
READ-003. Outgoing direct messages помечаются markable. Для MUC приложение не рассылает direct displayed markers в комнату как универсальный механизм прочтения всеми участниками.
READ-004. Поддерживается own-device sync read state через совместимое служебное расширение. Маркер, пришедший раньше сообщения, применяется после получения target. Пользователь не видит служебную запись в self-chat.
READ-005. Read marker — metadata; нельзя заявлять его E2EE только по encrypted body исходного сообщения.
11. Действия над сообщениями
11.1. Доступность
| Действие | Требование |
|---|---|
| Ответить | Не удалённое, не служебное; в MUC нужен server room stanza id |
| Переслать | Не удалённое и не служебное |
| Копировать | Есть пользовательский текст/подпись, не tombstone |
| Редактировать | Собственный отправленный direct text |
| Удалить у всех | Собственное отправленное direct сообщение, поддерживаемый retraction |
| Удалить у меня | Локальная запись текущего аккаунта |
| Реакция | Доступное пользовательское сообщение с устойчивым reference id |
| Сохранить | Доступное/получаемое медиа по явному действию |
| Повторить | Failed собственная отправка, payload ещё доступен |
Для group edit/retraction базовый UI не обещает поддержку. Состояние sending ограничивает действия, требующие завершённой идентичности.
11.2. Редактирование
EDIT-001. Используется совместимая message correction. Оригинал сохраняет свою идентичность и положение; заменяется body, устанавливается editedAt.
EDIT-002. Применение проверяет чат, автора, допустимый тип, security context и timestamp. Сторонний отправитель не может исправить чужое сообщение.
EDIT-003. Correction до оригинала удерживается в ограниченной pending очереди. Более старая correction не заменяет новую.
EDIT-004. Шифрование исправления соответствует исходному сообщению; не допускается plaintext раскрытие исправляемого encrypted body из-за текущего глобального переключателя.
11.3. Ответы
REPLY-001. Поддерживаются стандартная reply reference и fallback для совместимых старых клиентов. Unicode offsets считаются согласно протоколу, без смешения байтов и символов.
REPLY-002. Отображается компактный preview источника, а fallback quote не дублируется в основном body.
REPLY-003. Нажатие открывает источник/ветку, если reference известен. При недоступном оригинале показывается preview и объяснение без crash.
REPLY-004. Legacy > quote допускается отображать без ложного target id. MUC replies ссылаются на room-assigned stanza id и корректный occupant identity.
REPLY-005. Reference нельзя применить к другому чату с совпавшим id. Визуальная ветка — группировка reply, не отдельная серверная комната.
11.4. Пересылка
FWD-001. Можно выбрать одно/несколько сообщений и переслать в существующий чат либо на валидный JID. Порядок: timestamp, устойчивый id.
FWD-002. Создаются новые сообщения с новой identity и понятной атрибуцией. Пересылка не подделывает исходного sender.
FWD-003. Media скачивается/расшифровывается и заново загружается для нового recipient и его encryption policy. Старый encrypted URI/key не переиспользуется автоматически.
FWD-004. При частичной ошибке показывается количество успешно пересланного; уже доставленные элементы не откатываются и не повторяются молча.
11.5. Удаление
DEL-001. «Удалить у меня» удаляет local row и сохраняет suppression всех известных identities, чтобы MAM/live echo не восстановили удалённое сообщение.
DEL-002. «Удалить у всех» отправляет retraction, проверяет авторство при применении и заменяет target на tombstone. Очищаются body/media/reply/reaction sensitive payload и связанные доступные cache.
DEL-003. Retract до оригинала удерживается pending. Generic fallback не повторяет удаляемое содержимое.
DEL-004. UI явно сообщает разницу локального удаления и отзыва. Ни одно не обещает стирание screenshots, backups, чужих exports или неподдерживающего клиента.
DEL-005. Массовое действие фильтрует/объясняет недоступные элементы; подтверждение показывает область действия и число сообщений.
12. Реакции и typing
REACT-001. Реакции совместимы с XMPP reactions: target id и полный актуальный набор автора; пустой набор снимает реакцию.
REACT-002. Emoji валидируются, дубликаты удаляются. Один reaction value — один grapheme, ограниченный безопасной длиной; baseline до 64 UTF-8 bytes.
REACT-003. Показываются emoji, count и own state. Повторный tap переключает свой вклад. Более старое событие не отменяет новое.
REACT-004. Direct авторы сравниваются по подготовленному bare JID, group — по корректной occupant identity. Нельзя объединять разных участников из-за неверной нормализации resource.
REACT-005. Реакции не шифруются автоматически только из-за OMEMO текста. Базовая совместимая stanza является видимой серверу metadata; отдельное encrypted extension требует самостоятельного согласования и interoperability tests.
TYPE-001. Typing имеет active/composing/paused/inactive/gone. Baseline пауза после 5 с, удалённый composing истекает через 8 с без обновления.
TYPE-002. Настройка typing per-account; выключение прекращает отправку/отображение и очищает pending indicators. Для direct учитывается поддержка peer.
TYPE-003. В группе показываются имена для одного/двух участников, затем обобщённый статус. Переход между чатами/уход из foreground не оставляет вечное «печатает».
13. Группы MUC
MUC-001. Пользователь создаёт/открывает room JID, задаёт nickname и optional name; для защищённых комнат предусмотрен запрос password при требовании сервера.
MUC-002. Поддерживаются invitations, accept/join, occupant count, autojoin и информация о комнате. Invitees валидируются; некорректные адреса явно обозначаются.
MUC-003. Новая encrypted-friendly комната конфигурируется persistent, members-only, nonanonymous и с доступными участникам affiliation lists, если сервер даёт эти права.
MUC-004. Для encrypted send проверяются real JID всех необходимых online/offline recipients через occupants и member/admin/owner lists. Недоступный/неполный набор получателей блокирует безопасную отправку.
MUC-005. Скрытые JID, отсутствие устройств или невозможность построить session не вызывают fallback к plaintext. Ошибка объясняет, что может изменить владелец/участник.
MUC-006. Own echo дополняет room stanza identity даже при повторном encrypted payload. Replies/reactions становятся доступны после устойчивой серверной identity.
MUC-007. «Выйти» сохраняет локальный чат/историю и снимает joined. «Удалить чат» удаляет локальную историю/сохранённую комнату после выхода; это не уничтожение комнаты сервера.
MUC-008. После локального удаления поздние события текущей room session не создают чат заново без явного основания. Повторное приглашение/вход имеют определённую семантику.
14. Шифрование и устройства
ENC-001. OMEMO включён по умолчанию для аккаунта. Per-chat override: наследовать / включено / выключено. UI показывает итоговый режим до отправки.
ENC-002. Ошибка encryption никогда не приводит к автоматической plaintext отправке. Plaintext возможен только при явно выбранной политике.
ENC-003. Поддерживаются legacy OMEMO и OMEMO 2 с совместимыми wire formats, device lists/bundles и согласованной lifecycle политикой identity/session.
ENC-004. Для direct предпочтителен OMEMO 2 при готовности и поддержке peer; иначе совместимый legacy. Для group OMEMO 2 используется только при поддержке всех recipients; legacy остаётся encrypted fallback.
ENC-005. Encrypt-to-self охватывает собственные другие устройства, чтобы Carbons/MAM могли быть прочитаны. Active own device не включается как чужой recipient с некорректной обязательной self-session.
ENC-006. Private identity, prekeys и sessions сохраняются устойчиво и раздельно по аккаунтам. Обновление приложения не создаёт новую identity без необходимости.
ENC-007. TOFU и verified различаются. Первое доверие отмечается как автоматическое; changed identity переводится в undecided и требует понятного решения. Compromised key не используется как trusted.
ENC-008. Пользователь видит список устройств, protocol support, fingerprint, active state и trust, может отметить проверенный fingerprint и снять verification.
ENC-009. OMEMO encryption/decryption выполняются в клиентском endpoint. Web gateway может передавать encrypted stanza, но не получает password/crypto state для скрытой серверной расшифровки. Применяются проверенные криптографические реализации и совместимые test vectors. Собственный новый алгоритм, замена примитивов или трактовка общего session storage как доказанной interoperability не допускаются.
ENC-010. Зашифрованный text не означает шифрование JID, времени, stanza ids, replies metadata, reactions, typing, avatars или custom sync. Матрица раскрываемых metadata является частью security документации каждого релиза.
ENC-011. Криптографический формат OMEMO 2 реализуется по утверждённой совместимой редакции с SCE и необходимыми payload/key/MAC rules; он не заменяется media AES-GCM только из-за удобства библиотеки.
15. Файлы и вложения
FILE-001. Поддерживаются файл, фото, видео, музыка, voice и videoNote. Тип определяется безопасно по metadata/MIME/доступному анализу; расширение не даёт права автоматически выполнять содержимое.
FILE-002. Можно выбрать до 20 элементов за пакет, просмотреть, удалить отдельные и добавить общую подпись. Перевышение лимита объясняется; элементы не теряются молча.
FILE-003. Источник копируется/удерживается в staged draft с достаточным сроком доступа. Не предполагается, что временный URL picker остаётся доступным после его закрытия.
FILE-004. При encrypted policy blob шифруется до upload случайным file key; ключ передаётся внутри защищённого сообщения, не upload service. Для plaintext это явно обозначено.
FILE-005. Используется HTTP File Upload discovery/slot. Выбирается подходящий component по реально загружаемому размеру. Ограничение сервера и памяти отображается до бессмысленного повторения операции.
FILE-006. Upload/download допускаются по HTTPS. Проверка распространяется на redirect chain; переход к небезопасной схеме не допускается. HTTP headers/credentials slot не отправляются произвольному другому origin после redirect.
FILE-007. Сохраняется исходное безопасное расширение filename. Encrypted media URI использует совместимую aesgcm scheme/key fragment, а не вымышленное обязательное расширение файла.
FILE-008. Body media-сообщения остаётся распознаваемой ссылкой; plaintext дополнительно передаёт совместимый OOB. Подпись пакета — отдельный text/reply к первому подходящему вложению.
FILE-009. Пакет отправляется с контролем порядка. Successful drafts удаляются из pending, failed остаются для retry; caption отправляется после успешных вложений. Ошибка caption не откатывает уже отправленные файлы.
FILE-010. Retry сохраняет account/recipient/message identity и encryption context. Сбой после PUT, но до XMPP send может оставить orphan blob; это не обозначается как гарантированно удалённый файл.
FILE-011. Загрузки поддерживают progress по доступным данным, cancellation и bounded retry. Недостаток диска/памяти обрабатывается как ошибка без повреждения остальных сообщений.
FILE-012. В Web endpoint обязан поддерживать необходимые browser access/CORS политики. Proxy не получает file key или decrypted blob для обхода ограничений незаметно для пользователя.
15.1. Совместимые transport metadata
Созданные Luma voice/videoNote сохраняют распознаваемое имя при загрузке:
| Тип | Формат transport filename |
|---|---|
| Voice | luma-voice-<durationMilliseconds>-<filename.ext> |
| VideoNote | luma-videonote-<durationMilliseconds>-<filename.ext> |
| Другой файл | Безопасное исходное имя с расширением |
Duration — положительное конечное значение, округлённое до миллисекунд. При отсутствии валидной duration имя не должно содержать неверную/отрицательную длительность. Получатель распознаёт специальные prefixes, обычный MIME/расширение и прежние совместимые encrypted URI. Transport filename и размер доступны upload service; они не являются секретными metadata.
byteCount сообщения относится к исходному файлу; лимит slot сравнивается с размером реально загружаемого encrypted/plain blob.
15.2. Baseline сетевых параметров
| Параметр | Значение по умолчанию |
|---|---|
| Upload request timeout | 120 с |
| Upload total resource timeout | 300 с |
| Automatic attempts | 2 суммарно |
| Задержка перед второй попыткой | 600 мс, допустим небольшой jitter |
| Retryable HTTP | 408, 429 с учётом Retry-After, 5xx |
| Неповторяемые без изменения условий | Insecure URL, invalid input/key, неподходящий размер, постоянный permission error |
Повтор discovery/slot/transport ограничен. Таймауты конфигурируемы и не являются обещанием скорости сети.
16. Просмотр и сохранение медиа
MEDIA-001. Photo/video имеют inline preview с сохранением aspect ratio без неожиданного crop. Loading/error/placeholder различаются.
MEDIA-002. Фото открывается в viewer с zoom/pan. Видео имеет play/pause/seek/fullscreen и доступные системные controls. Voice/audio — inline player, duration, seek, progress; voice speeds 1×/1.5×/2×.
MEDIA-003. В пределах приложения активный media playback согласован: начало другого audio/video не создаёт неконтролируемое одновременное звучание. Системный audio focus обрабатывается по платформе.
MEDIA-004. VideoNote показан кругом, воспроизводится inline и увеличивается при playback. Изменение размера не вызывает потерю позиции чтения.
MEDIA-005. Preview cache не скачивает один файл многократно из-за повторного появления row. Decrypted cache ограничивается размером/сроком и очищается согласно privacy/account lifecycle.
MEDIA-006. Экспорт/скачивание/копирование выполняются явно. Пользователь выбирает доступное платформенное место сохранения; отмена не показывает success.
MEDIA-007. Viewer закрывается доступной кнопкой/keyboard action и gesture по UI Kit. Zoomed pan не конфликтует с dismiss.
MEDIA-008. Неподдерживаемый codec/file открывается безопасным fallback/download с объяснением; не имитируется успешное воспроизведение.
17. Запись аудио, видео и геопозиция
REC-001. Разрешения microphone/camera запрашиваются по действию пользователя. Отказ не ломает текстовый composer.
REC-002. Voice: start, elapsed, cancel, finish; запись короче 0.4 с не отправляется. Длительность голоса не ограничивается автоматически 60 секундами: ограничения файла/сервера действуют отдельно.
REC-003. VideoNote: до 60 с, корректная ориентация, переключение камеры при доступном hardware. Минимальный валидный media asset — 0.8 с; early stop может дождаться достаточного capture, baseline 1.2 с.
REC-004. Отпускание/отмена до асинхронного старта capture не оставляет скрытую запись. Finalization имеет timeout и завершает UI в определённое состояние.
REC-005. При interruption пригодный partial asset может быть предложен для восстановления/предпросмотра, но не отправляется автоматически как подтверждённое действие.
REC-006. На touch поддерживаются hold/slide cancel/lock. На mouse/keyboard всегда есть явные start/stop/cancel; жест не является единственным способом записи.
GEO-001. Отправка текущей или выбранной точки доступна через меню вложения. Разрешение location запрашивается только в этом сценарии.
GEO-002. При denied/отсутствии GPS доступен ручной выбор координат на карте либо ввод точки. Live tracking в scope не входит.
GEO-003. Передаётся совместимый geo URI: finite latitude −90…90, longitude −180…180, optional nonnegative uncertainty. UI не выдаёт число знаков после запятой за точность датчика.
GEO-004. Карта/tiles provider и передача ему coordinates отражены в privacy конфигурации решения. OMEMO чата не скрывает запрос карты от её провайдера.
18. Локальная история и MAM
HIST-001. История хранится локально с изоляцией аккаунтов. Существующие сообщения доступны при временном отсутствии сети, если устройство/профиль допускает persistent storage.
HIST-002. На первом входе загружается ограниченное недавнее окно, baseline 40 сообщений. Полная многолетняя история не блокирует запуск; старое догружается по запросу/прокрутке.
HIST-003. Account archive и каждая MUC имеют собственные checkpoint. Cursor непрозрачен, не вычисляется из local id и не переносится между архивами.
HIST-004. Incremental запрос использует stored cursor. При его истечении допустим однократный timestamp fallback с overlap 60 с. Цикл cursor↔timestamp запрещён.
HIST-005. Проверяются query id, допустимый источник, порядок завершения и размер страницы. Чужой результат/overflow не считается успешной историей.
HIST-006. Missing/repeating cursor у incomplete page прекращает проход с recoverable error. Не допускаются вечный spinner и пропуск остатка как якобы complete.
HIST-007. Архивные mutations применяются согласованными пачками. Durable checkpoint продвигается только после успешной локальной транзакции соответствующих данных. Ошибка диска сохраняет предыдущую точку восстановления.
HIST-008. Backward pagination берёт следующий before из server RSM first даже если страница содержала только reactions/retractions/дубликаты.
HIST-009. Pending correction/retraction/reaction/read marker применяются после target. Очереди ограничены и очищаются по политике; overflow не создаёт crash.
HIST-010. Расшифрование и большие batches уступают время UI. Background/media capture/upload могут временно снижать архивную активность; возобновление не теряет checkpoint.
HIST-011. Автоматические retries ограничены; после исчерпания показывается recoverable state и доступно повторить. Незавершённый проход не объявляется «История полностью загружена».
HIST-012. Локальная миграция выполняется транзакционно; исходный формат удаляется после успешной записи. Upgrade не должен уничтожать единственную durable копию данных.
18.1. Baseline ограничений
| Параметр | Значение |
|---|---|
| MAM page/bootstrap | 40 / 40 |
| Максимум buffered stanza одной query | 96 |
| Decode slice | 8, с уступкой UI между срезами |
| Ориентир порции применения | До 2 страниц или 2 с перед yield/commit |
| Query/apply timeout | 20 / 20 с |
| Interactive backward query timeout | 15 с |
| Межстраничная пауза | 100 мс |
| Page retry | 1 дополнительный |
| Automatic catch-up recovery | До 3 повторов, пауза 20 с |
| Pending corrections/retractions | До 100 каждого вида |
| Pending reactions | До 200 |
Порция работы не ограничивает всю историю двумя страницами: после yield допустимо продолжение. Реализация может уменьшать slice по нагрузке и увеличивать configurable server-compatible limits после измерений, но не отменять контроль объёма.
19. Звонки
CALL-001. Поддерживаются аудио-/видеозвонки один на один, один активный звонок на клиентский контекст. Второй входящий/исходящий получает определённый busy/reject сценарий.
CALL-002. До запуска запрашиваются microphone/camera permissions. Есть incoming accept/decline, connecting, connected, elapsed и завершение.
CALL-003. Доступны mute, camera enable/disable, switch camera при нескольких камерах и speaker/audio output выбор в пределах платформенных возможностей.
CALL-004. Используется совместимый Jingle/JMI signaling и WebRTC media с ICE/DTLS-SRTP. Endpoint выбирается как подходящий full JID; последующие сообщения согласованы с тем же ресурсом.
CALL-005. SDP media sections сохраняют порядок offer. ICE candidates удерживаются до готового remote description, затем передаются/применяются без вечного ожидания bare/full JID.
CALL-006. STUN/TURN обнаруживаются через extdisco или утверждённую конфигурацию. Проверяются scheme, host/port, transport, expiration и credentials. Невалидная запись не приводит к crash медиадвижка.
CALL-007. TURN relay необходим для утверждённой тестовой матрицы сложных сетей. Отсутствие relay показывается диагностически; STUN не описывается как гарантия соединения за любым NAT.
CALL-008. Внешний fallback STUN допускается только как задокументированный конфигурационный выбор. Сервис-получатель сетевых адресов отражается в privacy документации.
CALL-009. Смена сети/краткая ICE failure имеют ограниченное recovery окно. После него звонок завершается корректно, освобождает tracks/camera/microphone и снимает active state.
CALL-010. Закрытие экрана звонка не может оставить скрыто включённый microphone/camera вопреки показанному состоянию. Background behavior задаётся интеграцией платформы, не визуальным состоянием окна.
19.1. История
CALL-011. Каждый звонок создаёт одну history card: направление, media type, начало, duration и outcome.
Outcomes: completed, declined, missed, cancelled, unanswered, failed, answeredElsewhere. Если media было connected, последующая transport error не переименовывает состоявшийся разговор в неудачную попытку; duration сохраняется.
Классификация до connected: отказ стороны → declined; собственная отмена → cancelled; timeout incoming ringing → missed; timeout outgoing ringing → unanswered; сбой negotiation → failed; подтверждённый ответ другим собственным устройством → answeredElsewhere.
CALL-012. Missed incoming увеличивает unread. Дубликаты completion callbacks не создают несколько карточек.
CALL-013. Call history синхронизируется с собственными устройствами через совместимое расширение и MAM/Carbons, если сервер хранит такие события. Metadata не выдаётся за OMEMO body.
19.2. Baseline таймеров
| Фаза | Значение |
|---|---|
| Ringing | 60 с |
| Negotiation | 90 с |
| ICE failed grace | 8 с |
| ICE disconnected grace | 12 с |
Таймеры должны согласовываться с сервером и remote signaling; они не гарантируют фонового пробуждения.
20. Уведомления, push и фоновая работа
PUSH-001. Поддерживаются локальные уведомления для новых событий активного клиента и отдельная push-интеграция для разрешённых платформенных состояний.
PUSH-002. Notification создаётся для нового incoming, не для outgoing/повторного MAM. В активно просматриваемом чате дублирующий banner подавляется.
PUSH-003. Уведомление содержит безопасную идентичность account/conversation/event для перехода в правильный контекст. Повторная доставка push и network event дедуплицируется.
PUSH-004. Default privacy: push payload не содержит plaintext body, file key или credentials. Preview после получения сообщения определяется пользовательской настройкой; при app lock default preview скрыт.
PUSH-005. Gateway/registration lifecycle включает register/update token, enable по XMPP, disable/logout/revoke и обработку expired token. Наличие server push feature без registration не отображается как «Push работает».
PUSH-006. Push — сигнал получения/пробуждения, а не источник истины истории. После него клиент синхронизируется с сервером; утерянный push не должен навсегда потерять сообщение.
PUSH-007. Базовый single-active-account режим регистрирует доставку для активного аккаунта; переключение согласует старую и новую registration. Уведомления неактивных аккаунтов не обещаются без отдельно реализованного multiaccount background режима. Поздний push сохраняет исходную account identity и не открывает переписку другого аккаунта.
20.1. Web
WEB-001. Для уведомлений вне открытой страницы поставляется поддержанный Web Push/service worker путь и gateway, если браузер/пользователь предоставили возможность. При отсутствии поддержки/permission приложение честно показывает статус «Только при открытом приложении».
WEB-002. Закрытая страница не считается постоянно подключённой XMPP-сессией. Service worker notification не гарантирует непрерывный microphone, медиазвонок или автоматический показ полноэкранного incoming UI.
WEB-003. Incoming push может уведомить о вызове и открыть приложение по действию. После открытия проверяются актуальность и состояние вызова; истёкший вызов не «принимается» из старого notification.
WEB-004. Несколько вкладок координируют активное соединение/device state либо используют изолированные ресурсы с безопасным доступом к crypto state. Не допускаются конкурентные повреждающие записи ratchet sessions.
20.2. Desktop
DESK-001. Пользователь понимает разницу «закрыть окно», «скрыть/свернуть» и «выйти из приложения». Работа в tray/фоновой сессии и автозапуск — явно управляемые настройки.
DESK-002. При живом фоновом процессе поддерживаются сообщения и incoming calls. Полностью завершённый процесс не получает обещание гарантированного пробуждения без отдельного системного механизма.
DESK-003. Sleep/wake, network change и logout восстанавливают/отключают соединение и push registration корректно. Tray icon не показывает active call после завершения.
20.3. Android
AND-001. Поставляется интеграция системной доставки уведомлений и входящих вызовов для утверждённого режима устройства. Выбор push provider и доступность устройств без соответствующего сервиса фиксируются в паспорте релиза.
AND-002. Фоновая работа соответствует lifecycle/permissions ОС. Постоянный socket в обычном скрытом UI не используется как единственная гарантия доставки.
AND-003. Для ongoing call используется разрешённый системный foreground/call механизм с видимым статусом; control из notification согласован с app state.
AND-004. Force stop, отозванные разрешения, ограничения батареи и отключённая сеть имеют задокументированную деградацию. Приложение не обещает обход пользовательского запрета ОС.
20.4. Приёмка интеграции
Push и фоновые звонки нельзя принять только по работающему foreground demo. Для каждой платформы проверяются foreground, скрытый UI, закрытый процесс/вкладка, denied permission, sleep, token rotation, logout и переход по старому notification. Недоступные платформой режимы обозначаются как ограничения, а не как выполненная гарантия доставки.
21. Локальная защита и хранение
STORE-001. История, crypto state и настройки раздельны по accountId; операции сохранения транзакционны либо имеют проверяемый equivalent recovery механизм.
STORE-002. Native credentials защищены системным secure storage; private key material защищается подходящим устройству key wrapping/access control. Пароль не хранится в открытом preferences файле.
STORE-003. В Web пароль не хранится plaintext в localStorage, URLs, analytics или общедоступных configuration objects. Persistent login и разблокировка crypto state используют отдельное задокументированное защищённое решение; отсутствие такого решения означает повторный вход, а не незаметное ослабление.
STORE-004. Web storage может иметь квоты/очистку. Приложение обрабатывает quota/exhaustion и показывает, когда история не сохранена устойчиво. Browser storage не представляется эквивалентом hardware-backed native vault.
STORE-005. Media cache имеет лимит и eviction. Draft/failed payload не исчезает без объяснения; при невозможном retry действие отключено с причиной.
STORE-006. Автосохранение не теряет введённый текст при переходах/обычном восстановлении. Draft принадлежит account + conversation; он не переносится в другой чат из-за reuse UI.
STORE-007. Миграции versioned и тестируются на старых данных/сбоях. Ошибка открытия persistent store показывает ограниченный режим, а не ложное подтверждение durable записи.
LOCK-001. App lock скрывает всю sensitive UI: чат, media, call details и previews. Поддерживаются пользовательский passcode и доступная системная биометрия.
LOCK-002. Минимальная длина passcode 4 символа, предусмотрены ограничение частоты ошибочных попыток и корректное хранение verifier/секрета. App lock не объявляется шифрованием базы без отдельного encryption механизма.
LOCK-003. После запуска и ухода в background lock применяется по настройке. Краткая потеря focus для системного picker/permission dialog не прерывает незавершённую операцию.
LOCK-004. Web не обещает native biometric unlock на любом браузере; при отсутствии защищённой интеграции остаётся passcode либо повторная авторизация. Lock settings показывают фактическую возможность.
22. Приватность и безопасность
SEC-001. Документируется разделение transport TLS, OMEMO payload, file encryption, DTLS-SRTP media, local protection и UI lock. Термины не подменяют друг друга.
SEC-002. Server/upload/STUN/TURN/maps/push providers получают только необходимые данные. Перечень providers и metadata доступен пользователю.
SEC-003. Логи исключают passwords, tokens, private/session keys, decrypted bodies и file key fragments. Сетевые трассы по умолчанию обезличены; диагностический экспорт требует явного действия и предупреждения о metadata.
SEC-004. Полученные text/filenames/URLs/XML не выполняются как HTML/script/команда. Web rendering безопасен для XSS; переход по внешним URL не передаёт секретный контекст.
SEC-005. У ограничений входных данных есть предельный размер/depth/count. Недоверенные stanza, challenges, media metadata и custom sync parsers не должны создавать бесконечную работу/выделение памяти.
SEC-006. Copy/export явно выводит plaintext за границы клиента; локальная очистка не обещает удалить clipboard или пользовательский файл.
SEC-007. «Удалить у всех» — протокольный отзыв; «Удалить локальные данные» — удаление собственного профиля. В UI нет обещания абсолютного стирания всех копий.
SEC-008. Для push/служебной own-device синхронизации проверяется источник и принадлежность аккаунту. Remote peer не может подделать собственную call/read history только прислав похожий XML element.
23. Совместимость протоколов
Обязательный профиль включает:
| Область | Протокол/семантика |
|---|---|
| XMPP | Базовые stream/session, roster, presence; XEP-0030 discovery |
| Web transport | Защищённый XMPP WebSocket endpoint |
| Устойчивость | XEP-0198 Stream Management, XEP-0199 Ping, XEP-0280 Carbons, XEP-0352 CSI |
| Группы | XEP-0045 MUC, invitations/room configuration и MUC-MAM |
| История | XEP-0313 MAM, XEP-0059 RSM, XEP-0359 origin-id/stanza-id |
| Доставка | XEP-0184 Receipts и XEP-0333 Chat Markers |
| Действия | XEP-0308 Correction, XEP-0461 Reply, XEP-0428 Fallback, XEP-0444 Reactions, XEP-0424 Retraction |
| Медиа | XEP-0363 HTTP Upload, XEP-0066 OOB, XEP-0454 encrypted file URI |
| Защита | XEP-0384: совместимые legacy/OMEMO 2; XEP-0420 SCE для нового формата |
| Аватары | XEP-0084 User Avatar PEP, optional legacy compatibility |
| Звонки | XEP-0166/0167 Jingle/RTP, XEP-0353 JMI, ICE/DTLS-SRTP, XEP-0215 extdisco |
| Push | XEP-0357 registration и платформенная доставка |
23.1. Own-device расширения
Для совместимости устройств Luma используются согласованные пространства имён:
https://luma.chat/read-marker: conversation JID, target origin/client id, optional stanza id и timestamp; без видимого body;https://luma.chat/call-history: peer JID, direction, outcome, audio/video, startedAt, duration и устойчивый event id.
Wire names read-marker: conversation, id, optional stanza, when; call-history: with, direction, status, video, start, duration. Даты сериализуются ISO 8601 с timezone, duration — неотрицательные секунды, ids — непрозрачные строки. Origin-id внешней stanza служит устойчивой идентичностью события. Отсутствие неизвестной новой версии не должно ломать ранее поддержанный payload.
Схемы versioned при изменении; неизвестные поля игнорируются безопасно, обязательные валидируются. Повторная доставка идемпотентна. Совместимость с существующими payload не ломается без миграции. Эти расширения не считаются универсально поддерживаемыми всеми XMPP-клиентами.
23.2. Матрица испытаний
Релиз подтверждает обмен с минимум двумя независимыми XMPP-клиентами из утверждённого набора и минимум одним поддерживаемым сервером. Отдельно проверяются legacy/OMEMO 2, direct/MUC, media и calls. Поддержка XEP по имени без сценариев interoperability недостаточна.
24. Нефункциональные требования
NFR-001. UI Kit является обязательным стандартом visual/interaction behavior. Small/wide layout определяется доступной шириной, не строкой User-Agent.
NFR-002. Списки/лента виртуализируются или используют equivalent bounded rendering. Большой архив не создаёт все визуальные rows одновременно.
NFR-003. Проект задаёт измеряемые бюджеты startup, RAM, cache и frame responsiveness для утверждённых reference devices. До утверждения devices не заявляется произвольный универсальный SLA.
NFR-004. Encryption/decoding/uploads уступают ресурсы active input/capture. Scroll и text entry остаются доступными во время catch-up.
NFR-005. Системные permissions запрашиваются по контексту. Denied, hardware missing и revoked during session входят в тестовую матрицу.
NFR-006. Web/Desktop полностью управляются клавиатурой; Android поддерживает системную accessibility. Focus, text scale, reduced motion и contrast проверяются по UI Kit.
NFR-007. Сборки воспроизводимы: pinned/locked dependencies, migrations, build instructions, CI, license notices и release artifacts. Выбор framework не включён в пользовательские требования.
NFR-008. CI запускает unit/integration checks и smoke UI tests для поставляемых targets. Подпись/публикация и secrets отделены от публичного репозитория.
NFR-009. Crash/error reports не включают sensitive content по умолчанию. Телеметрия имеет утверждённую privacy-конфигурацию.
25. Критерии приёмки
Каждый сценарий выполняется на каждой заявленной платформе либо имеет заранее согласованную аппаратную/системную деградацию. «Не удалось проверить» не равнозначно «Выполнено».
| Сценарий | Ожидаемый результат | Требования |
|---|---|---|
| Первый вход/ошибка/перезапуск | Верный lifecycle, история сохранена, secrets не раскрыты | ACC-001…010 |
| Нечисловой port / WSS endpoint | Понятная validation и правильный транспорт | ACC-003…005 |
| Переключение во время upload | Нет отправки/записи от другого аккаунта | ACC-008,014 |
| Logout с удалением/сохранением | Объяснённая область очистки и push disable | ACC-011…013 |
| TLS/auth отказ | Нет ослабления доверия или подделанного PLUS | NET-001…005 |
| Смена сети/sleep/reconnect | Один согласованный клиент, без duplicate | NET-006…009 |
| Text/receipts/displayed | sending/sent/delivered/read имеют разные основания | MSG-001…005 |
| Replay live/Carbons/MAM | Одна запись, правильные ids/delivery | MSG-004,005 |
| Draft переход между чатами | Текст остаётся у правильного recipient/account | STORE-006 |
| Edit/retract до оригинала | Отложенное корректное применение | EDIT-003, DEL-003 |
| Чужая correction/retraction | Не изменяет чужое сообщение | EDIT-002, SEC-008 |
| Reply XML/legacy/MUC | Корректный preview/reference без вымышленного id | REPLY-001…005 |
| Multi-forward и ошибка | Порядок, новая encryption policy, partial result | FWD-001…004 |
| Local delete + MAM | Удалённое не возвращается | DEL-001 |
| Реакция/снятие/старое событие | Count/own state и порядок актуальны | REACT-001…005 |
| Typing timeout/отключение | Нет вечного composing | TYPE-001…003 |
| Group hidden recipients | Fail closed, без plaintext | MUC-003…006 |
| OMEMO2/legacy/changed identity | Совместимый формат, правильное доверие | ENC-003…009 |
| Upload HTTPS/redirect/error | Secret-safe transport и bounded retry | FILE-004…012 |
| 20 media, partial failure, caption | Ошибки не уничтожают успешное/оставшееся | FILE-002,009 |
| Viewer/player/export cancel | Correct ratio/control и отсутствие ложного success | MEDIA-001…008 |
| Permissions/short record/early release | Нет скрытой capture и autosend partial | REC-001…006 |
| Location denied/manual | Точка отправляется без фонового tracking | GEO-001…004 |
| Fresh MAM/repeating cursor/disk failure | Checkpoint не теряется/не перескакивает | HIST-002…012 |
| JMI/full JID/SDP/late ICE | Correct endpoint и ограниченный recovery | CALL-004…009 |
| Call outcome/sync/duplicate callback | Одна правильная history card | CALL-011…013 |
| Push и network event вместе | Одна notification/event, правильный чат | PUSH-001…006 |
| Web вкладка закрыта / stale call | Notification/open по доступной платформе, без ложного active call | WEB-001…004 |
| Desktop скрыт/завершён/sleep | Поведение соответствует заявленному lifecycle | DESK-001…003 |
| Android background/permission/force stop | Проверенная доставка и честная деградация | AND-001…004 |
| Lock / preview / export | Sensitive UI скрыта, границы защиты объяснены | LOCK-001…004, SEC-006 |
| Quota/migration/cache eviction | Нет ложного durable success/повреждения | STORE-001…007 |
| Keyboard/text scale/dark/reduced motion | Доступный интерфейс | NFR-006, UI Kit |
26. Состав результата разработки
- Устанавливаемое/развёрнутое приложение каждого согласованного target.
- Исходники, locked dependencies, reproducible build и CI.
- Реализованный набор UI components/tokens по
uikit_clear.md. - Версионированные data schemas/migrations и протокольные adapters.
- Push/gateway/TURN/WSS конфигурация в пределах выбранной инфраструктуры, без secrets в репозитории.
- Unit, integration, interoperability и UI/accessibility tests с результатами.
- Пользовательская справка, privacy/security описание и известные ограничения.
- Паспорт релиза и checklist поддерживаемых систем.
27. Паспорт конкретного приложения
До начала platform-specific реализации фиксируются решения, не изменяющие пользовательский контракт:
| Решение | Что должно быть указано |
|---|---|
| Поддерживаемые targets | Desktop ОС, Android min/target, Web браузеры и режим PWA |
| Технологии | UI/runtime, XMPP/crypto/media libraries и стратегия shared code |
| Транспорт | Native discovery и Web endpoint configuration |
| Backend | WSS, push gateway/provider, TURN, upload и maps |
| Secrets | Native vault, Web persistent-login/crypto unlock модель |
| Lifecycle | Что означает закрыть окно/вкладку, background и explicit quit |
| Лимиты | Размеры файлов/cache, pending limits, performance reference devices |
| Совместимость | Серверы/клиенты и редакции encrypted wire formats |
| Дистрибуция | Signing, обновления, hosting и каналы поставки |
Паспорт заполняется до выпуска. Отсутствующее решение не заменяется непроверенным обещанием общей поддержки всех ОС, браузеров или фоновых состояний.