Files
Luma/tz_clear.md
T
wt e018be346a
Build Unsigned iOS ipa / Build Unsigned iOS IPA (push) Canceled after 0s
Build Unsigned macOS App / Build macOS ZIP (push) Canceled after 0s
iOS CI / Build and Test SwiftUI App (push) Canceled after 0s
added Docs/UIKIT.md uikit_clear.md tz.md tz_clear.md
2026-10-14 17:56:31 +07:00

86 KiB
Raw Blame History

Luma — техническое задание для Web, Desktop и Android

Версия: 1.0. Дата: 14 октября 2026 года. Статус: целевой стандарт разработки.

Связанный документ: UI Kit.

Содержание

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. Состав результата разработки

  1. Устанавливаемое/развёрнутое приложение каждого согласованного target.
  2. Исходники, locked dependencies, reproducible build и CI.
  3. Реализованный набор UI components/tokens по uikit_clear.md.
  4. Версионированные data schemas/migrations и протокольные adapters.
  5. Push/gateway/TURN/WSS конфигурация в пределах выбранной инфраструктуры, без secrets в репозитории.
  6. Unit, integration, interoperability и UI/accessibility tests с результатами.
  7. Пользовательская справка, privacy/security описание и известные ограничения.
  8. Паспорт релиза и 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 и каналы поставки

Паспорт заполняется до выпуска. Отсутствующее решение не заменяется непроверенным обещанием общей поддержки всех ОС, браузеров или фоновых состояний.