Улучшение соответсвия

This commit is contained in:
2026-05-28 17:23:54 +03:00
parent 5c40687011
commit 0c15c7b786
39 changed files with 161 additions and 204 deletions

View File

@@ -21,9 +21,8 @@ start
:Инициализация Room,
загрузка метаданных vault;
if (Есть сохранённые vault?) then (нет)
:Экран «первый запуск» /
создание локального vault;
if (Есть LocalVault / storage?) then (нет)
:Первый запуск;
else (да)
endif
@@ -35,10 +34,10 @@ else (нет)
endif
partition "**Основной поток (UI)**" {
:(A) Главный экран:
список локальных и удалённых vault;
:Действия пользователя
(открыть, зашифровать, содержимое…);
:(A) Main: LocalVault — список storage,
вкладка удалённых — список IVault;
:Действия с **storage**
(шифрование, открытие, файлы…);
}
fork

View File

@@ -1,8 +1,8 @@
@startuml fig_02_vault_lifecycle
scale 3
title
Wallenc — пользовательский поток: жизненный цикл vault
и точки постановки в очередь синхронизации (проект)
Wallenc — жизненный цикл storage (IStorage)
внутри IVault; журнал синхронизации
end title
skinparam defaultFontName "DejaVu Sans"
@@ -13,45 +13,41 @@ skinparam state {
skinparam noteBackgroundColor #E3F2FD
skinparam noteBorderColor #1565C0
state "(Б) Список vault" as List
state "(Б) Список storage\n(LocalVault или VaultBrowser)" as List
List --> Create : Создать vault
Create --> List : Vault создан
List --> Create : Создать storage\n(FAB)
Create --> List : Storage создан
List --> EncryptDlg : Включить шифрование
EncryptDlg --> Encrypting : Подтверждение, мастер-ключ
List --> EncryptDlg : Включить шифрование storage
EncryptDlg --> Encrypting : Подтверждение, ключ
state Encrypting {
state "Шифрование данных + запись метаданных" as EncWork
state "Шифрование + метаданные Room" as EncWork
}
Encrypting --> List : Готово
note right of Encrypting
После успешной записи **коммита**
в историю Storage (проект):
UUID storage → **очередь синхронизации**
в Room (для таймера)
Запись в журнал sync (проект):
UUID **storage** → очередь
группы DbStorageSyncGroup
end note
List --> OpenDlg : Открыть зашифрованный
List --> OpenDlg : Открыть зашифрованный storage
OpenDlg --> Opened : Ключ верный
OpenDlg --> List : Отмена / неверный ключ
state Opened {
state "Просмотр / работа с содержимым" as Browse
state "Файлы, секреты, 2FA\n(StorageHome)" as Browse
}
Opened --> List : Закрыть vault / блокировка
Opened --> List : Закрыть / заблокировать storage
List --> RenameDel : Переименовать / удалить
List --> RenameDel : Переименовать / удалить storage
RenameDel --> List : Подтверждение
note bottom of List
**Синхронизация (проект):** любое изменение,
порождающее новый **коммит** в Storage,
добавляет storage UUID в таблицу очереди;
**SyncService** по таймеру обрабатывает очередь,
сравнивает истории коммитов с удалённой копией
и приводит зашифрованное содержимое
к одному состоянию (без передачи ключей).
**Синхронизация:** изменения в **storage**
пишутся в журнал; StorageSyncEngine
согласует группы storage по ревизиям
(зашифрованное содержимое, без ключей).
end note
@enduml

View File

@@ -1,8 +1,8 @@
@startuml fig_03_navigation_hub
scale 2
title
Wallenc — навигация от главного экрана
и связь с фоновой синхронизацией (проект)
Wallenc — навигация (Main) и доменная иерархия
VaultsManager → IVault → IStorage → файлы
end title
skinparam defaultFontName "DejaVu Sans"
@@ -13,39 +13,42 @@ skinparam noteBorderColor #C2185B
start
:(A) Главный экран:
список локальных vault;
partition "**Main: нижняя навигация**" {
:(A) Вкладка LocalVault\n(один LocalVault на устройстве);
note right
На экране — список **IStorage**,
не список vault
end note
repeat
:Ожидание действия пользователя;
backward:Назад с подэкрана;
switch (Действие?)
case (FAB / новый vault)
:Создание локального vault;
case (Выбор vault)
:Карточка / детали vault;
case (Удалённые vault)
:Экран удалённых vault;
if (Нужен OAuth Яндекс?) then (да)
:Авторизация Яндекс;
endif
case (Настройки)
:Экран настроек;
endswitch
repeat while (Пользователь в приложении?) is (да)
-> нет;
repeat
:Ожидание действия;
backward:Назад с вложенного экрана;
switch (Действие?)
case (FAB)
:createStorage()\nновый **storage** в LocalVault;
case (Выбор storage)
:StorageHome:\nфайлы, 2FA, текстовые секреты;
case (Вкладка «Удалённые vault»)
:Список **IVault** (Yandex по OAuth);
if (Нужен OAuth?) then (да)
:Авторизация Яндекс;
endif
:Выбор vault → VaultBrowser;
:Список **storage** в выбранном vault;
:StorageHome;
endswitch
repeat while (Пользователь в Main?) is (да)
-> нет;
}
stop
floating note right
**Фон: SyncWorker (по таймеру Android) — проект**
Room: таблица очереди с **UUID storage**
Периодический запуск метода синхронизации
Для каждого Storage — история **коммитов** (как git)
Сравнение локальной и удалённой истории,
приведение зашифрованного содержимого
к одному состоянию (ключи на сервер не уходят)
• Работает **независимо** от текущего экрана UI
**Фон: StorageSyncEngine**
DbStorageSyncGroup: UUID **storage** в группе
Журнал изменений по путям, merge ревизий
Независимо от текущего экрана UI
Ключи шифрования провайдеру не передаются
end note
@enduml

View File

@@ -1,4 +1,5 @@
@startuml fig_04_domain_class
title Модуль :domain — IVaultsManager / IVault / IStorage
scale 1.15
skinparam shadowing false
skinparam classFontSize 10
@@ -23,9 +24,13 @@ package usecases {
class GetOpenedStoragesUseCase {
+ getOpenedStorages(): StateFlow<Map<UUID, IStorageInfo>>
}
class ManageLocalVaultUseCase {
+ getLocalStorages(): StateFlow<List<IStorageInfo>>
+ createStorage(): Unit
class ManageVaultUseCase {
+ find(UUID): IVault?
+ storagesOf(UUID): Flow<List<IStorage>>
+ createStorage(UUID): IStorage
}
class FindStorageUseCase {
+ find(UUID): IStorage?
}
class StorageFileManagementUseCase {
+ getAllDirs(): Unit
@@ -101,9 +106,6 @@ package interfaces {
class ILogger {
+ debug(String, String): void
}
class IYandexVault {
+ getAccountEmail(): String
}
class IMetaInfo {
+ getSize(): long
+ isDeleted(): boolean
@@ -125,13 +127,9 @@ package interfaces {
+ isVirtualStorage(): boolean
}
class IVaultsManager {
+ getLocalVault(): IVault
+ removeRemoteVault(UUID): Unit
+ addYandexVault(String): Unit
+ getRemoteVaults(): StateFlow<List<IVault>>
+ getAllStorages(): StateFlow<List<IStorage>>
+ getAllVaults(): StateFlow<List<IVault>>
+ getUnlockManager(): IUnlockManager
+ vaults: StateFlow<List<IVault>>
+ allStorages: StateFlow<List<IStorage>>
+ unlockManager: IUnlockManager
}
class IStorageMetaInfo {
+ getEncInfo(): StorageEncryptionInfo
@@ -150,22 +148,16 @@ package interfaces {
+ getMetaInfo(): StateFlow<IStorageMetaInfo>
+ isVirtualStorage(): boolean
}
class IStorageExplorer {
+ getCurrentPath(): StateFlow<String>
}
class IVaultInfo {
+ getAvailableSpace(): StateFlow<Integer>
+ getType(): VaultType
+ getTotalSpace(): StateFlow<Integer>
+ getUuid(): UUID
+ isAvailable(): StateFlow<Boolean>
+ getStorages(): StateFlow<List<IStorageInfo>>
+ uuid: UUID
}
class IUnlockManager {
+ openedStorages: StateFlow<Map<UUID, IStorage>>
+ getOpenedStorageKey(UUID): EncryptKey
+ open(IStorage, EncryptKey, boolean): IStorage
+ rememberKey(IStorage, EncryptKey): Unit
+ close(IStorage): Unit
+ close(UUID): Unit
+ open(IStorage, EncryptKey, boolean): Unit
+ getOpenedStorages(): StateFlow<Map<UUID, IStorage>>
}
class IDirectory {
+ getMetaInfo(): IMetaInfo
@@ -194,15 +186,16 @@ package interfaces {
+ getFileInfo(String): Unit
}
class IVault {
+ getAvailableSpace(): StateFlow<Integer>
+ getType(): VaultType
+ getTotalSpace(): StateFlow<Integer>
+ uuid: UUID
+ storages: StateFlow<List<IStorage>>
+ storagesScanInProgress: StateFlow<Boolean>
+ isAvailable: StateFlow<Boolean>
+ totalSpace: StateFlow<Long>
+ availableSpace: StateFlow<Long>
+ createStorage(): IStorage
+ createStorage(StorageEncryptionInfo): IStorage
+ remove(IStorage): Unit
+ createStorage(StorageEncryptionInfo): Unit
+ getUuid(): UUID
+ isAvailable(): StateFlow<Boolean>
+ getStorages(): StateFlow<List<IStorage>>
+ createStorage(): Unit
+ rescanStorages(): Unit
}
}
@@ -277,25 +270,6 @@ package common.impl {
}
}
package auth {
class RemoteYandexAuthResult {
}
class RemoteYandexSignInLauncher {
+ launch(): void
}
}
package enums {
class VaultType {
+ DECRYPTED: VaultType
+ LOCAL: VaultType
+ YANDEX: VaultType
+ valueOf(String): VaultType
+ values(): VaultType[]
+ getEntries(): EnumEntries<VaultType>
}
}
usecases.ManageStoragesEncryptionUseCase ..> interfaces.IStorageMetaInfo
usecases.ManageStoragesEncryptionUseCase ..> interfaces.IStorageInfo
usecases.ManageStoragesEncryptionUseCase ..> tasks.TaskProgress
@@ -312,20 +286,16 @@ usecases.RemoveStorageUseCase ..> interfaces.IUnlockManager
usecases.RemoveStorageUseCase ..> interfaces.IVault
tasks.TaskLogLine ..> tasks.TaskLogLevel
tasks.PipelineWork ..> tasks.TaskContext
interfaces.IVault <|.. interfaces.IYandexVault
interfaces.IVaultInfo <|.. interfaces.IYandexVault
interfaces.IYandexVault ..> interfaces.IStorage
interfaces.IYandexVault ..> interfaces.IVault
interfaces.IYandexVault ..> enums.VaultType
interfaces.IYandexVault ..> datatypes.StorageEncryptionInfo
usecases.GetOpenedStoragesUseCase ..> interfaces.IStorageInfo
usecases.GetOpenedStoragesUseCase ..> interfaces.IUnlockManager
tasks.TaskContext ..> tasks.TaskLogLevel
tasks.TaskContext ..> tasks.TaskProgress
tasks.TaskContext ..> tasks.TaskId
usecases.ManageLocalVaultUseCase ..> interfaces.IStorageInfo
usecases.ManageLocalVaultUseCase ..> interfaces.IVaultsManager
usecases.ManageLocalVaultUseCase ..> interfaces.IVault
usecases.ManageVaultUseCase ..> interfaces.IStorage
usecases.ManageVaultUseCase ..> interfaces.IVaultsManager
usecases.ManageVaultUseCase ..> interfaces.IVault
usecases.FindStorageUseCase ..> interfaces.IStorage
usecases.FindStorageUseCase ..> interfaces.IVaultsManager
usecases.StorageFileManagementUseCase ..> interfaces.IFile
usecases.StorageFileManagementUseCase ..> interfaces.IStorage
usecases.StorageFileManagementUseCase ..> interfaces.IStorageInfo
@@ -362,9 +332,7 @@ interfaces.IStorageInfo ..> interfaces.IStorageMetaInfo
interfaces.IStorageInfo ..> interfaces.IStorage
usecases.RenameStorageUseCase ..> interfaces.IStorage
usecases.RenameStorageUseCase ..> interfaces.IStorageInfo
interfaces.IVaultInfo ..> interfaces.IStorageInfo
interfaces.IVaultInfo ..> interfaces.IVault
interfaces.IVaultInfo ..> enums.VaultType
tasks.TaskForegroundItem ..> tasks.TaskProgress
tasks.TaskForegroundItem ..> tasks.TaskId
interfaces.IUnlockManager ..> interfaces.IStorage
@@ -376,9 +344,7 @@ interfaces.IStorageAccessor ..> datatypes.DataPackage
interfaces.IVaultInfo <|.. interfaces.IVault
interfaces.IVault ..> interfaces.IStorage
interfaces.IVault ..> interfaces.IVaultInfo
interfaces.IVault ..> enums.VaultType
interfaces.IVault ..> datatypes.StorageEncryptionInfo
auth.RemoteYandexSignInLauncher ..> auth.RemoteYandexAuthResult
datatypes.DataPackage <|-- datatypes.DataPage
datatypes.DataPage ..> datatypes.DataPackage
interfaces.IFile <|.. common.impl.CommonFile

View File

@@ -12,7 +12,7 @@ rectangle "Wallenc\n(Android)" as App {
cloud "Внешний провайдер\n(Яндекс Диск API)" as Cloud
User --> UI : управление vault,\nфайлы, OAuth
User --> UI : storage, vault,\nOAuth, файлы
UI --> Domain
Domain --> Room
Domain --> Cloud : ciphertext,\nOAuth, метаданные API

View File

@@ -1,6 +1,6 @@
@startuml fig_15_bpmn_vault
scale 2
title BPMN: жизненный цикл vault
title BPMN: жизненный цикл storage (IStorage)
skinparam defaultFontName "DejaVu Sans"
skinparam activity {
BackgroundColor #F8F8F8
@@ -8,20 +8,23 @@ skinparam activity {
}
start
:Создать vault;
if (Нужно шифрование?) then (да)
:Создать **storage** в vault\n(createStorage);
note right
Vault (IVault) не шифруется.
Шифрование только у **storage**
end note
if (Включить шифрование storage?) then (да)
:Ввести пароль;
:Шифрование данных;
:enableEncryption(storage);
else (нет)
endif
:Открыть vault;
:Работа с содержимым;
if (Удалённое хранилище?) then (да)
:OAuth / привязка;
:Синхронизация;
:openStorage(storage)\nпри необходимости;
:Работа с содержимым storage:\nфайлы, 2FA, секреты;
if (Storage в группе синхронизации?) then (да)
:StorageSyncEngine\n(журнал ревизий);
else (нет)
endif
:Закрыть vault;
:closeStorage / блокировка;
stop
@enduml

View File

@@ -10,14 +10,14 @@ skinparam activity {
start
:Пользователь включает шифрование;
:Сформировать EncryptKey;
:Encryptor.encrypt данные vault;
:Записать StorageEncryptionInfo\nв Room;
:Encryptor: шифрование файлов\n**storage** (IStorageAccessor);
:storage.setEncInfo Room\n(DbStorageMetaInfo);
:checkKey(ключ);
if (Ключ верный?) then (да)
:openStorage(зашифрованное представление);
:Доступ к содержимому;
:IUnlockManager.open(storage)\nвиртуальное представление;
:Доступ к файлам storage;
else (нет)
:Ошибка, vault закрыт;
:Ошибка, storage не открыт;
endif
stop

View File

@@ -1,6 +1,6 @@
@startuml fig_22_cjm_vault
scale 3
title Customer Journey Map: защита vault
title Customer Journey Map: защита storage
skinparam defaultFontName "DejaVu Sans"
|Этап|
@@ -11,9 +11,9 @@ skinparam defaultFontName "DejaVu Sans"
|Действия|
|Понимает риск\nоблака|
|Создаёт vault,\nвключает шифрование|
|Открывает vault,\nработает с файлами|
|Синхронизирует\nбез передачи ключей|
|Создаёт storage,\nвключает шифрование storage|
|Открывает storage,\nработает с файлами|
|Синхронизирует storage\nбез передачи ключей|
|Ожидания|
|Данные не читаются\nпровайдером|

View File

@@ -24,7 +24,7 @@ Enc ..> ML : опционально\nлокальные эмбеддинги\nп
note bottom of ML
Обучение: офлайн на размеченных\nсинтетических/агрегированных данных;
выгрузка содержимого vault\nна облако для train — не используется
выгрузка содержимого storage\nна облако для train — не используется
end note
@enduml