9.3 KiB
Verstak Platform Architecture
1. Общая схема
+----------------------+
| UI Shell |
| windows, layout, |
| command palette, |
| settings, toasts |
+----------+-----------+
|
+----------v-----------+
| Core Platform |
| plugin manager, |
| capabilities, |
| permissions, events |
+----------+-----------+
|
+-------------------+-------------------+
| | |
+-------v--------+ +-------v--------+ +-------v--------+
| Local Vault | | Storage API | | Sync Boundary |
| files, notes, | | SQLite, index, | | client adapter |
| assets, trash | | migrations | | not core truth |
+-------+--------+ +-------+--------+ +-------+--------+
| | |
+-------------------+-------------------+
|
+----------v-----------+
| Dynamic Plugins |
| official and third |
| party packages |
+----------------------+
2. Core Platform
Core Platform - минимальное ядро приложения. Оно не содержит бизнес-функции пользователя. Его задача - дать среду, в которую плагины безопасно подключают рабочие инструменты.
Core отвечает за:
- запуск приложения;
- открытие и проверку vault;
- загрузку и выгрузку плагинов;
- enable/disable состояние плагинов;
- capability registry;
- contribution points;
- settings registry;
- permissions;
- event bus;
- storage API;
- vault file API;
- command registry;
- diagnostics;
- sync boundary.
Core не должен импортировать конкретные плагины как обязательные модули.
3. UI Shell
UI Shell - общий интерфейс платформы:
- главное окно;
- навигация;
- вкладки и панели;
- command palette;
- global search entry point;
- settings window;
- plugin manager window;
- dialogs/toasts;
- error boundary для plugin UI.
UI Shell не знает, что такое notes editor или file preview как конкретная реализация. Он знает contribution points:
- sidebar items;
- main views;
- case tabs;
- file actions;
- note actions;
- context menu entries;
- settings panels;
- command palette commands;
- status bar items;
- activity cards;
- search providers.
4. Vault
Vault остается пользовательским рабочим пространством. Он должен быть максимально понятным снаружи.
Пример:
VerstakVault/
.verstak/
db.sqlite
config.json
plugins/
plugin-state/
cache/
trash/
Clients/
Romashka/
Notes/
Overview.md
Files/
Screenshots/
Projects/
Правила:
- пользовательские документы не прячутся в непрозрачные blob-таблицы без необходимости;
- SQLite хранит индексы, связи, историю, состояние UI, plugin metadata;
- файловая структура должна оставаться пригодной для ручного восстановления;
- имена заметок и файлов остаются человекочитаемыми;
- sync не является единственным способом доступа к данным.
5. Plugin Runtime
Плагины загружаются динамически из каталогов. Официальные плагины используют тот же механизм, что и сторонние.
Папки плагинов:
VerstakVault/.verstak/plugins/
official.files/
official.notes/
official.markdown-editor/
~/.config/verstak/plugins/
user.local-plugin/
Порядок загрузки:
- Найти plugin manifests.
- Проверить schemaVersion и apiVersion.
- Проверить enabled/disabled state.
- Проверить обязательные capabilities.
- Запросить permissions.
- Запустить backend sidecar, если нужен.
- Загрузить frontend bundle, если нужен.
- Принять регистрации capabilities и contributions.
- Перевести плагин в состояние loaded/degraded/failed/incompatible.
6. Backend Model
Не использовать Go plugin как основной механизм. Он плохо подходит для кроссплатформенного desktop-приложения из-за ABI, версий компилятора и сборки под разные ОС.
Предпочтительная модель:
- плагин может быть pure frontend;
- плагин может быть pure manifest/data;
- плагин может иметь backend sidecar;
- sidecar общается с core через локальный RPC;
- core выдает sidecar только разрешенные API;
- прямой произвольный доступ к vault и OS запрещен по умолчанию.
Sidecar может быть написан на Go, Rust, Python или другом языке, если он соблюдает протокол.
7. Frontend Model
Плагин поставляет frontend bundle:
frontend/
index.js
style.css
Frontend bundle не должен напрямую обращаться к Wails backend methods как к глобальному хаосу. Он работает через VerstakPluginAPI, который предоставляет:
- registerView;
- registerSettingsPanel;
- registerCommand;
- registerFileAction;
- callBackend;
- readSettings/writeSettings;
- subscribe/publish events;
- requestCapability.
8. Capability Registry
Плагины связываются не по имени друг друга, а через capabilities.
Пример:
editor.text
editor.text.markdown
viewer.file
viewer.image
preview.markdown
workspace.files
workspace.notes
capture.browser
activity.provider
secret-store
search.provider
Файловый плагин не зависит от official.markdown-editor. Он проверяет, есть ли capability editor.text.markdown. Если есть - показывает действие "Редактировать". Если нет - действие не появляется.
9. Plugin Manager UI
Core обязан иметь окно управления плагинами с первого платформенного этапа.
Функции:
- список установленных плагинов;
- enable/disable;
- status: loaded, disabled, failed, incompatible, degraded;
- version и apiVersion;
- source: official, local, third-party;
- capabilities provided;
- required/optional capabilities;
- permissions;
- кнопка "Settings", если плагин предоставляет settings panels;
- diagnostics/error log.
Выключение плагина не удаляет пользовательские данные.
10. Settings Registry
Настройки плагинов не должны быть произвольными экранами, спрятанными в разных местах.
Плагин регистрирует settings panels:
{
"contributes": {
"settingsPanels": [
{
"id": "official.notes.general",
"title": "Notes",
"component": "settings.general"
}
]
}
}
Core показывает кнопку настроек у выбранного плагина и открывает соответствующую панель/окно.
11. Event Bus
Event bus связывает плагины без прямых импортов.
Примеры событий:
vault.opened;case.selected;file.added;file.changed;note.saved;activity.recorded;browser.capture.received;plugin.enabled;plugin.disabled.
События должны иметь стабильные схемы. Плагин не должен полагаться на приватные поля другого плагина.
12. Sync Boundary
Sync server и browser extension выносятся в отдельные репозитории, но должны использовать общие protocol contracts.
Sync не должен знать о внутренних UI-плагинах. Он синхронизирует:
- vault metadata;
- files/blobs;
- plugin state where allowed;
- plugin data через зарегистрированные storage namespaces.
Плагины должны явно указывать, какие данные можно синхронизировать, а какие локальны только на устройстве.