# ИКАР Иконка ИКАР Самостоятельный Android-мессенджер с сервером `ikar_server`. Имя приложения — **ИКАР**, пакет Android — `ru.ikar.app`, версия исходников — `1.0.4+5` (не опубликована), вариант сборки — `ikar`. Опубликованный выпуск — `1.0.3+4`. Клиент находится в `C:\Repos\IKAR`, сервер — в `ikar_server/`. Иконка перенесена из прежнего Икара. Исходный каталог `C:\Repos\Qlyra` не изменён; использованный клиентский код и библиотеки сохраняют свои авторские сведения и лицензии. ## Возможности Личные сообщения, групповые чаты и каналы, редактирование и удаление сообщений, ответы и форматирование, реакции, поиск, контакты, блокировки, папки, опросы, истории, загрузка и скачивание файлов, фото, видео и голосовых сообщений, расшифровка русской речи на Pi, стикеры, отложенная отправка, голосовые и видеозвонки, фоновые уведомления, боты и мини-приложения. Настройки оформления, масштаба отметок доставки, плагины и остальные локальные возможности исходного клиента сохранены. Сервер предоставляет собственный HTTPS API и события SignalR; клиент не авторизуется на серверах MAX. Файлы выдаются по подписанным ссылкам, сообщения сохраняются в SQLite. Сервер проверяет участие в чате и права публикации в каналах. Повтор запроса с тем же идентификатором сообщения возвращает сохранённое сообщение. Задания отложенной отправки переживают перезапуск сервера. Регистрация привязывает аккаунт к ключу Android Keystore. Номер служит идентификатором и **не подтверждается SMS**. Вход на другом устройстве требует доступного механизма привязки/восстановления собственного сервера; приложение не использует SMS-службу MAX. До передачи приложения другим людям нужно определить способ подтверждения номера и восстановления потерянного ключа. Старые аккаунты MAX автоматически не переносятся. «Карточка ИКАР» показывает собственный профиль и QR-ссылку. Государственный Цифровой ID, Сферум и чужие каталоги/мини-приложения не являются сервисами ИКАР. Собственные мини-приложения настраиваются владельцем бота через `PUT /api/bots/{botId}/web-app` с телом `{"url":"https://..."}`; данные запуска подписаны HMAC, номер передаётся отдельным запросом после подтверждения в клиенте. Сквозное шифрование исходного клиента сохранено в коде как отдельная функция. Обычные сообщения сервер принимает и хранит в читаемом виде; HTTPS обеспечивает шифрование транспорта. Проверки не доказывают работу всех режимов сквозного шифрования и звонков с большим количеством участников. ## Доработки из Komet Адаптированы изменения ветки `feature/FullStack` (`58576bc1`) и жесты из [PR №166](https://github.com/KometTeam/Komet/pull/166) (`10a194ed`). Ползунок качества видео получил полноценную область касания; качество и обрезка учитывают края системных жестов Android. Копирование, выделение и редактирование зашифрованных сообщений используют доступный расшифрованный текст. Недоступный текст не подменяется шифротекстом; локальное хранение и отправка сохраняют существующую схему шифрования. В настройках темы добавлена «Собственная тема»: выбор цветов, поворота и анимации градиента. Градиент сохраняется для аккаунта между запусками, отдельные фоны чатов продолжают иметь приоритет. Жесты назад, ответа, закрытия фото и скрытия клавиатуры согласованы между собой; короткий отменённый свайп возвращает фото, масштабирование не закрывает просмотр. «Невидимка» передаёт `interactive=false` в авторизованный ping и подключение SignalR, включая переподключения. Переключение настройки и уход приложения в фон обновляют активность сервера. Сервер учитывает отдельные соединения и сессии, сохраняет соединение для доставки сообщений и звонков, но не показывает невидимую сессию онлайн. Публичное время появления хранится отдельно от служебной активности сессии и не обновляется невидимыми запросами. Обновление схемы SQLite переносит прежнее время появления один раз. Видимая сессия на другом устройстве по-прежнему показывает аккаунт онлайн. Проверки: полный клиентский прогон — 1189 прошли, 3 пропущены; сервер — 150 прошли, без пропусков. Анализ `lib` и `test` не выявил ошибок и предупреждений, остались 42 информационных замечания стиля. Проверены выбор качества видео, сохранение темы, доступ к расшифрованному тексту, жесты, переключение невидимости, переподключение и сохранение публичной активности при обновлении схемы. Локальные отчёты: `artifacts/komet-full-flutter-tests.log`, `artifacts/komet-server-tests.log`, `artifacts/komet-implementation-analyze.log`. Эти изменения относятся к исходникам клиента и сервера. Для использования на телефоне нужны обновление сервера и сборка нового APK; текущий опубликованный выпуск их не содержит. Новый APK, развёртывание и проверка этих изменений на телефоне в этой задаче не выполнялись. ## Размещение на Pi Внешний диск: `/mnt/data` (`/dev/sdb1`, ext4). Корень новой установки: `/mnt/data/ikar_server`. - `current` — ссылка на действующий выпуск в `releases/20261007-video`; - `shared/data` — SQLite, вложения, данные устройств и публикация APK; - `shared/server.env`, `shared/turn.env` — закрытые настройки, доступ 0600; - `backups` — ежедневные согласованные копии SQLite и вложений, хранение 14 дней; - `rollback` — резервная копия прежнего Икара, сохранённая перед удалением. Собственный Compose-проект `ikar_server` содержит контейнеры `ikar_server`, `ikar_server_turn` и `ikar_server_asr`. API слушает `127.0.0.1:5099`, TURN — 3478 с портами ретрансляции 49160–49200, распознавание речи доступно только во внутренней сети контейнеров. Использован уже существовавший маршрут Caddy; конфигурации соседних программ не менялись. Автозапуск: `ikar_server.service`; резервные копии: `ikar_server-backup.timer` (03:30 с небольшим разбросом времени). Старт требует смонтированного внешнего диска и маркера в каталоге данных. ```sh systemctl status ikar_server.service ikar_server-backup.timer curl http://127.0.0.1:5099/health sudo systemctl start ikar_server-backup.service ``` Адрес сервера — `https://ikar.kusoft.xyz`. На проверке 7 октября 2026 года DNS-запись разрешалась в `195.216.241.165`. APK также умеет подключаться к этому IP с сохранением проверки сертификата имени `ikar.kusoft.xyz`, если DNS временно недоступен. Для звонков через разные NAT нужен проброс на роутере: 3478 TCP/UDP и 49160–49200 UDP на `192.168.0.185`. При проверке TURN работал через локальный адрес Pi; запросы на внешний адрес не получили ответа TURN. Публичная ретрансляция пока не подтверждена. Звонок с аудио/видео в эмуляторе прошёл через прямое WebRTC-соединение; это не доказывает работу через любую мобильную сеть. ## Сборка Flutter 3.44.3, Java 17, Android SDK, Rust; для сервера .NET 10. На этой машине используются `C:\Tools\jdk-17`, `C:\Tools\AndroidSdk`, `C:\Tools\gradle-home` и `C:\Tools\pub-cache`. ```powershell flutter pub get flutter build apk --release --flavor ikar --no-pub flutter test --no-pub flutter analyze --no-pub --no-fatal-infos lib test dotnet test ikar_server/src/Ikar.Server.Tests/Ikar.Server.Tests.csproj ``` Подпись выпуска хранится в закрытом локальном каталоге `.secrets`; `android/key.properties` не публикуется. Для тестов криптографии нужны нативные библиотеки текущей ОС: можно указать `QLYRA_CRYPTO_LIBRARY` и добавить каталог остальных DLL в `PATH`. Имена библиотек — внутренние имена зависимостей и не определяют название приложения. `tool/deploy_ikar.ps1` упаковывает опубликованный `linux-arm64` сервер и обновляет только новый Compose-проект на Pi. Модель Vosk в `ikar_server/asr/model.zip` проверяется по SHA-256 при сборке контейнера. Скрипты в `tool/` для проверок используют временные тестовые аккаунты и удаляют их по завершении. ## Меню расшифровки голосовых сообщений 1.0.4 (не опубликовано) Расшифровка сохранена и перенесена из маленькой кнопки «Т» в меню голосового сообщения. Нажатие на облако открывает меню с пунктом «Расшифровка голосового сообщения»: нажимается вся строка, её высота не меньше 48 логических пикселей и увеличивается при переносе текста или увеличенном шрифте. У обычных сообщений, файлов, видео, удалённых и ещё не отправленных записей этого пункта нет. Пересланные записи используют идентификаторы исходного голосового сообщения. Под записью отображается состояние распознавания, затем готовый текст; через меню его можно скрыть и показать снова без повторного запроса. Одновременные нажатия не создают повторные запросы. Ошибку можно повторить; результат, уже полученный через push, не затирается поздним ответом о постановке в очередь или сетевой ошибкой. Целевые тесты: `artifacts/voice-menu-tests.log`. Анализ изменённых UI-файлов и новых тестов: `artifacts/voice-menu-analyze-final.log`. Живая проверка тестовой записи подтвердила загрузку, запрос получателя, завершение распознавания через push, сохранение текста для обоих участников и запрет доступа постороннему: `artifacts/voice-transcription-live-verification.json`. Тестовые аккаунты удалены. Новая версия не публиковалась и не устанавливалась на телефон по указанию пользователя; нового APK нет. ## Исправления видео 1.0.3 Серверный ответ на `VIDEO_PLAY` раньше содержал `external` и `hls`: стандартная JSON-сериализация меняла регистр ключей `EXTERNAL` и `HLS`, которые ожидает клиент. Теперь ключ `EXTERNAL` сохраняет точное написание, а исходный MP4 больше не выдаётся за HLS-плейлист. Выдача файла поддерживает HTTP byte ranges для перемотки. Сервер создаёт JPEG-превью и определяет реальные размеры и длительность видео с помощью FFmpeg/FFprobe. Превью сохраняется рядом с исходным файлом; повторные запросы используют готовый результат. Это работает и для прежних загрузок. Картинка выдаётся участникам чата по отдельной подписанной ссылке: токен видео нельзя использовать для превью, удалённые и истёкшие сообщения недоступны. В клиенте обновление вложения или подписанной ссылки перерисовывает существующий пузырь, даже если текст и статус сообщения не изменились. 142 серверных теста прошли. Живая проверка охватила загрузку MP4 чанком, доставку получателю, историю, скачивание с проверкой SHA-256 обоими участниками, ответы 206 для перемотки, JPEG-превью, метаданные и защиту доступа. На подключённом физическом телефоне с установленной версией 1.0.2 исходное видео 33 092 306 байт открылось в плеере; превью и длительность 0:05 появились в чате после обновления серверных данных. Сервер обновлён с согласованной резервной копией базы и вложений; рабочая база и база из копии прошли проверку целостности. Отчёты: `artifacts/video-server-tests.log`, `artifacts/video-live-verification.json`, `artifacts/deployment-video.json`, `artifacts/video-server-runtime-verification.json`. Клиент: 17 целевых тестов прошли; полный прогон — 1147 прошли, 9 пропущены. Анализ изменённых файлов не выявил ошибок и предупреждений (19 информационных замечаний стиля). Отчёты: `artifacts/video-client-tests.log`, `artifacts/flutter-tests-1.0.3.log`, `artifacts/video-client-analyze.log`. APK `artifacts/ikar-1.0.3+4.apk` подписан прежним ключом ИКАР; свежие Flutter-библиотеки всех трёх ABI проверены в итоговом файле. SHA-256: `5dd485f9a797f28c0eb522f8098c574c0e523796cd83cf50414cffea86747b71`. Выпуск опубликован в [Аргусе](https://argus.kusoft.xyz/#app=ikar): [скачать ИКАР 1.0.3](https://argus.kusoft.xyz/api/apps/ikar/releases/22ec0d08-3407-464e-bf04-871a4a42315a/download). Публичные манифест, каталог и скачанный APK совпадают по версии, размеру и SHA-256; TLS проверен, база каталога и резервная копия целостны. Другие карточки и сервисы публикация не изменяла. Установка нового APK на физический телефон не выполнена: USB перешёл в offline, затем пользователь выбрал завершить публикацию без установки. Отчёты: `artifacts/apk-jni-verification-1.0.3.json`, `artifacts/argus-publication-1.0.3.json`, `artifacts/argus-public-verification-1.0.3.json`. ## Исправления 1.0.2 Раздел FKM убран из настроек уведомлений. FKM принудительно выключена в клиенте и Android: включённая настройка прежнего выпуска сбрасывается, служба останавливается, постоянное уведомление удаляется. Повторный запуск и загрузка Android не включают её обратно. Обычные настройки уведомлений сохранены. При отсутствии связи с сервером шапка показывает «Соединение...»; после восстановления связи возвращается обычный заголовок. Сбои подключения, тайм-ауты и ответы шлюза 502/503/504 запускают переподключение без повторяющихся служебных сообщений снизу. Ошибки конкретных операций при работающем соединении по-прежнему отображаются. Проверки: полный клиентский прогон — 1144 прошли, 9 пропущены; 15 целевых тестов проверяют отключение FKM, отсутствие её меню, переходы состояния сети и сохранение ошибок операций. Анализ изменённых файлов не выявил ошибок и предупреждений (19 информационных замечаний стиля). Отчёты: `artifacts/flutter-tests-1.0.2.log`, `artifacts/offline-fkm-tests-1.0.2.log`, `artifacts/offline-fkm-analyze-1.0.2.log`. APK `artifacts/ikar-1.0.2+3.apk` подписан прежним ключом ИКАР; свежие Flutter-библиотеки всех трёх ABI сверены с содержимым APK. SHA-256: `fd3f4347ea7fe1e078dce3f5d442430eb79ede5bf529a49e8890956e7668b3a6`. В эмуляторе Android API 35 обновление сохранило данные и сбросило старую настройку `enabled=true` в `false`; повторный запуск сохранил отключённое состояние. Служба FKM и её постоянное уведомление отсутствуют, ошибок Android Runtime и Flutter не зарегистрировано. На физическом телефоне этот выпуск не проверялся. Отчёты: `artifacts/apk-jni-verification-1.0.2.json`, `artifacts/emulator-fkm-verification-1.0.2.json`. Выпуск опубликован в [Аргусе](https://argus.kusoft.xyz/#app=ikar). [Скачать ИКАР 1.0.2](https://argus.kusoft.xyz/api/apps/ikar/releases/9419489c-6cd6-467d-9f05-3bf3298d92f0/download). Публичные каталог, манифест и скачанный APK проверены по версии, размеру и SHA-256 с проверкой TLS. Перед публикацией создана согласованная резервная копия базы Аргуса; база и копия целостны, другие карточки и работающие сервисы сохранены. Сервер остался на выпуске 1.0.1: изменение относится к Android-клиенту. Отчёты: `artifacts/argus-publication-1.0.2.json`, `artifacts/argus-public-verification-1.0.2.json`. ## Исправления 1.0.1 Первое сообщение нового диалога раньше отклонялось локальной SQLite: запись сообщения создавалась до родительской записи чата. Теперь диалог и сообщение сохраняются атомарно; подготовка первого диалога также охватывает фото, файлы, голосовые сообщения и стикеры. Отмена подтверждения отправки не создаёт пустой чат. Сервер поддерживает приватное «Избранное» с `chatId=0`, пустую историю нового диалога и подписку по XOR ID. Отключение подписки больше не удаляет участие в чате. Полная синхронизация контактов очищает устаревшие записи, защищена от смены аккаунта и параллельного добавления контакта. Сохранение устаревшего контакта восстанавливает связь через `ADD`; ошибки поиска различают отсутствие пользователя и сбой сервера и отображаются по-русски. Проверки: 137 серверных тестов; полный клиентский прогон — 1127 прошли, 9 пропущены; после последних защит синхронизации — 55 целевых тестов. Все 17 живых проверок API прошли, включая отправку в «Избранное», первое сообщение, доставку второму клиенту, историю, контакты и сохранение членства после отключения подписки. Отчёты: `artifacts/messaging-fix-after.json`, `artifacts/focused-tests-1.0.1-final.log`, `artifacts/deployment-1.0.1.json`. Сервер обновлён с согласованной резервной копией; соседние контейнеры сохранены. APK `artifacts/ikar-1.0.1+2.apk` имеет прежнюю подпись ИКАР, versionCode 2 и свежие Flutter-библиотеки для всех трёх ABI. SHA-256: `6c23cc0063e63eda03172f10209a09a4dfc11655b435ce7aa982d495e3b329ad`. Выпуск опубликован в [Аргусе](https://argus.kusoft.xyz/#app=ikar). [Скачать ИКАР 1.0.1](https://argus.kusoft.xyz/api/apps/ikar/releases/ae0be8b6-9033-4b76-afce-42c9cac566c8/download). База каталога и резервная копия проверены; другие карточки и работающие сервисы сохранены. Передача на физический телефон и проверка исправлений на нём не выполнены: USB-соединение было отключено. Отчёты публикации: `artifacts/argus-publication-1.0.1.json` и `artifacts/argus-public-verification-1.0.1.json`. ## Проверка первого выпуска 1.0.0 - APK: `artifacts/ikar-1.0.0+1.apk`, контрольная сумма рядом; - клиент: 1107 тестов прошли, 9 пропущены; - сервер: 133 теста прошли, результаты — `artifacts/server-tests.log`; - живой HTTPS API: `artifacts/live-smoke.json`; - обмен сообщениями из Android-интерфейса: `artifacts/native-message.json`; - звонок с настоящим WebRTC и искусственным аудио/видео: `artifacts/native-call.json`; - фоновое уведомление Android: `artifacts/native-background-notification.json`; - боты и подписанные данные мини-приложений: `artifacts/live-bot-smoke.json`; - локальная ретрансляция TURN в обе стороны: `artifacts/local-turn-verification.json`; - скачивание APK по HTTPS с проверкой SHA-256: `artifacts/release-verification.json`; - итоговое состояние Pi и сохранность соседних сервисов: `artifacts/pi-verification.json`. ИКАР 1.0.0 (Android versionCode 1) опубликован в [Аргусе](https://argus.kusoft.xyz/#app=ikar). [Скачать APK](https://argus.kusoft.xyz/api/apps/ikar/releases/5def8cec-6349-437f-ad7b-68ad99bf4a84/download). Публичный файл совпадает с `artifacts/ikar-1.0.0+1.apk` по размеру, SHA-256 и подписи ИКАР. Перед публикацией сохранена согласованная копия базы Аргуса; база и копия прошли проверку целостности. Публикация не изменяла другие карточки и не перезапускала сервисы на Pi. Отчёты: `artifacts/argus-publication.json`, `artifacts/argus-public-verification.json` и `artifacts/argus-apk-signature.txt`. Скрипты первого выпуска: `tool/publish_argus_release.py` и `tool/verify_argus_release.dart`. Android проверен в эмуляторе API 35. Проверки на физическом телефоне и в разных мобильных сетях не проводились. Отдельные функции исходного клиента проверены модульными тестами; список живых сценариев приведён в отчётах, поэтому он не означает проверку каждого экрана и интеграции. Стикеры: [Noto Emoji v2.047](https://github.com/googlefonts/noto-emoji/tree/v2.047), Apache 2.0 (лицензия рядом с изображениями). Распознавание: [Vosk, русская модель small-ru-0.22](https://alphacephei.com/vosk/models), Apache 2.0.