#import "common.typ": pz-fig, pz-table = Проектирование архитектуры системы == Схема бизнес-процессов предметной области === Организационная структура Участники процесса: *пользователь*, *мобильное приложение Wallenc*, *внешний провайдер хранения* (облачный API). Сервер приложения отсутствует. === Карта процессов Основные процессы: создание storage в vault → опциональное шифрование storage → открытие storage → работа с файлами → закрытие; для удалённых vault — OAuth → привязка учётной записи → листинг storage провайдера → проектная синхронизация. === Диаграмма BPMN На рисунке @fig-15 представлена диаграмма BPMN основного процесса работы со storage внутри vault. #pz-fig("fig_15_bpmn_vault.png", [BPMN: storage — создание, шифрование, открытие, содержимое], "fig-15") === Карта систем Wallenc выступает посредником между пользователем и файловыми API провайдера, дополняя взаимодействие локальной БД Room и криптографическим модулем. == Диаграмма DFD DFD уровня 0 (рис. @fig-16) отражает потоки между UI, доменной логикой, криптографией, адаптерами хранилищ, Room и внешним API. #pz-fig("fig_16_dfd_level0.png", [DFD уровень 0: потоки данных в Wallenc], "fig-16") == Объектно-ориентированный анализ и проектирование (UML) === Диаграмма прецедентов Прецеденты включают управление storage, подключение удалённых vault (OAuth), шифрование и открытие storage, работу с файлами и синхронизацию групп storage (рис. @fig-17). #pz-fig("fig_17_use_case.png", [Диаграмма прецедентов Wallenc], "fig-17") === Диаграмма классов Доменная модель модуля `:domain` (интерфейсы хранилищ, use case, сущности шифрования) приведена на рисунке @fig-04. #pz-fig("fig_04_domain_class.png", [Диаграмма классов модуля domain], "fig-04") === Доменная иерархия хранения данных Модель данных приложения строится на трёх уровнях (см. `IVaultsManager`, `IVault`, `IStorage` на рис. @fig-04): + *VaultsManager* — единая точка доступа: реактивный список всех vault (`vaults`), агрегированный список storage (`allStorages`) и `IUnlockManager` для открытых storage; + *IVault* — контейнер, объединяющий набор storage. *LocalVault* в приложении один (корень на устройстве); удалённые vault (например, `YandexVault`) добавляются по одному на привязанную учётную запись OAuth; + *IStorage* — хранилище, которое пользователь создаёт, переименовывает и удаляет в интерфейсе; внутри — файлы и каталоги, доступные через `IStorageAccessor` (с опциональным клиентским шифрованием). Пользовательские сценарии «создать локальный vault» в UI соответствуют созданию нового *storage* внутри единственного `LocalVault`, а не появлению второго локального vault. Служебные сущности Room показаны на рисунке @fig-11. #pz-fig("fig_11_room_schema.png", [Схема служебных сущностей Room], "fig-11") === Диаграмма развёртывания Компоненты развёртывания: устройство Android (приложение, Room), облачный API Яндекса (рис. @fig-18). #pz-fig("fig_18_deployment.png", [Диаграмма развёртывания], "fig-18") Архитектурные слои MVVM + Clean Architecture и соответствие модулям Gradle — на рисунке @fig-19. #pz-fig("fig_19_clean_architecture.png", [Слои Clean Architecture и модули проекта], "fig-19") == Проектирование локальной базы данных Служебная БД Room хранит ключи шифрования для пар «исходный storage → зашифрованное представление» (`DbStorageKeyMap`), сериализованные метаданные storage (`DbStorageMetaInfo`), учётные записи Яндекс (`DbYandexAccount`) и группы синхронизации (`DbStorageSyncGroup`). Пользовательский контент в открытом виде в БД не сохраняется — только параметры, необходимые для восстановления состояния приложения при следующем запуске. Доступ инкапсулирован в DAO и репозиториях модуля `:infrastructure-android`. #pz-table( [Сущности Room и назначение], 3, table.header([Сущность], [Назначение], [Связь с тестами]), [`DbStorageKeyMap`], [Ключ для `sourceUuid` storage (связь с зашифрованной копией)], [Интеграция], [`DbStorageMetaInfo`], [Сериализованные метаданные `IStorage` (имя, путь, шифрование)], [Интеграция], [`DbYandexAccount`], [OAuth access token, идентификатор аккаунта], [`YandexAccountRepositoryTest`], [`DbStorageSyncGroup`], [Группа UUID для синхронизации], [`StorageSyncEngineTest`], ) == Проектирование подсистемы синхронизации Подсистема синхронизации спроектирована как набор независимых операций над журналом изменений каждого `Storage`. Алгоритм выбирает «победителя» по ревизии, копирует или удаляет файлы на целевом хранилище, не расшифровывая данные на сервере. Блокировки предотвращают одновременную синхронизацию одной группы; при отмене задачи блокировки снимаются (покрыто unit-тестами `syncGroupCooperativeCancellationReleasesLocks` и др., гл. 5). Подробное описание реализации и выбора источника для каждого пути — в гл. 4 (§ алгоритм согласования журналов, рис. @fig-35). == Нефункциональные архитектурные решения #pz-table( [Нефункциональные решения], 2, table.header([Атрибут], [Решение]), [Производительность], [Потоковое шифрование, фоновые задачи в `:task-runtime`], [Безопасность], [AES, проверка ключа без полного decrypt, скрытие служебных путей], [Расширяемость], [`vault-contracts`, регистрация провайдеров], [Сопровождаемость], [Модульные тесты 68 + листинги в приложении А], [Надёжность], [Room-транзакции, восстановление журнала после сбоя записи], ) == Вывод Спроектирована клиентская архитектура с разделением domain, infrastructure и presentation, единым интерфейсом vault и заделом под синхронизацию без передачи ключей. Диаграммы зафиксированы в приложении Г.