Meridian Office

Meridian Hub — стартовое окно и брокер пакета

Документ приложения по соглашениям раздела 8 библии (docs/00-foundation.md). Версия 0.1 · 2026-10-03. Фаза 1 · все редакции, включая Free · своего формата нет · цвет --m-ink #0B3C5D (токен --app-hub в макетах = --m-ink) · значок — логотип пакета · идентификаторы экранов HUB-xx · эталонный макет mockups/hub.html (HUB-01…HUB-04).

Содержание: 1. Назначение и аналоги · 2. Функции · 3. Экраны · 4. Модель данных · 5. Алгоритмы и скрипты · 6. Форматы · 7. Горячие клавиши · 8. Критерии готовности · 9. Риски · 10. Вопросы к библии.


1. Назначение и аналоги

Meridian Hub — две сущности в одном модуле:

  1. Стартовое окно (точка входа, лаунчер): недавние и закреплённые файлы, галерея шаблонов, создание документов, облачные подключения, «общие со мной», уведомления, «Что нового», обновления, аккаунт Meridian ID и состояние лицензии, параметры пакета, первый запуск.
  2. Брокер (meridian-broker, фоновый процесс без окна): единственный экземпляр на сеанс пользователя; принимает файлы из командной строки/ОС/протокола meridian:// и направляет их в приложения; ведёт недавние, индекс содержимого, миниатюры, облачную синхронизацию, уведомления, журнал автосохранения и восстановление после сбоя, планировщик фоновых задач, проверку и установку обновлений, расширенный буфер обмена между окнами (библия, раздел 6: «общий брокер для буфера, недавних, облака и обновлений»).

Процессная модель (библия 6): каждое окно документа — отдельный процесс приложения (meridian-write, meridian-sheets, …); брокер живёт, пока открыто хотя бы одно окно пакета или включён «быстрый запуск» (значок в трее/меню-баре, опционально); Hub-окно — обычный клиент брокера.

Аналог Что берём Чего избегаем
Стартовый экран Microsoft Office / «Backstage» недавние, закреплённые, шаблоны, аккаунт навязчивая реклама подписки, слабый поиск
LibreOffice Start Center единая галерея, миниатюры отсутствие облака, уведомлений, поиска по содержимому
macOS Spotlight / Windows Search поиск по содержимому зависимость от ОС: у нас индекс свой, одинаковый на трёх ОС
JetBrains Toolbox обновления, каналы отдельное приложение-менеджер

Код: kernel/crates/meridian-hub/ (брокер: IPC, реестр недавних, индекс, планировщик, миниатюры, crash journal), kernel/crates/meridian-update/, kernel/crates/meridian-id/, kernel/crates/meridian-license/ (библия 9.5), shell/src/hub/ (QML/C++: окно Hub, параметры, мастер первого запуска, командная палитра — общий компонент для всех приложений), shell/src/account/ (диалоги входа/активации).


2. Функции

2.1 Стартовое окно

Функция Описание Приоритет
Недавние файлы до 500 записей по всем приложениям; миниатюра, имя, приложение, расположение (Этот компьютер/облако/общий), время, размер; вид «Список» и «Папка» (дерево папок + файлы); фильтр по приложению; «удалить из списка», «открыть расположение», «копировать путь»; недоступные файлы — серые, «файл перемещён — найти?» P0
Закреплённые ручной порядок, группы (P1) P0
Избранное звёздочка на файлах и шаблонах P1
Создание документов карточки «Документ · Таблица · Презентация · Схема · Изображение · Заметка» (+ Форма, База, Письмо при наличии редакции; недоступные — с замком и подсказкой о редакции) → пустой или из шаблона; формат по умолчанию из параметров (Meridian/MS/ODF) P0
Галерея шаблонов источники: встроенные (в пакете), пользовательские (<profile>/templates/), корпоративные (общая папка по политике/Cloud организации), онлайн-каталог (templates.meridian-office.<tld>, фаза 7 — магазин); фильтры: приложение, категория, язык; сортировка; предпросмотр; «Создать документ»; «Сохранить как шаблон» из приложений попадает сюда P0 (онлайн — P1)
Поиск единое поле Ctrl+K: по именам недавних/закреплённых/папок, по содержимому проиндексированных документов (tantivy), по шаблонам, по командам (запуск приложения, параметры, «создать…»), по параметрам; результаты группами; клавиатурная навигация P0 (содержимое — P1)
Облако подключения: Meridian Cloud (фаза 6), WebDAV/Nextcloud/ownCloud, OneDrive (Microsoft Graph), Google Drive (Drive API v3), Dropbox (API v2), Яндекс Диск (REST API); обзор папок, открытие/сохранение в облако из диалогов всех приложений, статус синхронизации, квота; «общие со мной» (из API провайдеров и Meridian Cloud) P0 (WebDAV, Meridian Cloud-заглушка), P1 (провайдеры)
Уведомления центр уведомлений: комментарии/упоминания (Cloud), новые ответы Forms, письма Mail (сводно), обновления, лицензия, ошибки фона (индексация, синхронизация); действия в карточке; «не беспокоить»; системные тосты через ОС P0
«Что нового» страница с заметками выпуска по версии, показывается раз после обновления P1
Обновления проверка манифеста по каналу, загрузка в фоне (дельты), «установить при выходе», откат, уведомление в боковой панели и в строке состояния P0
Аккаунт и лицензия вход в Meridian ID (e-mail/пароль, OAuth, SSO, 2FA), аватар, редакция и статус (активна/пробная/истекает/офлайн-льгота), активация ключом, офлайн-активация файлом, устройства, «управление в портале» — подробности в docs/10-licensing-accounts.md P0
Параметры пакета вкладки: Общие, Внешний вид, Язык и регион, Сохранение и восстановление, Облако и аккаунт, Скрипты и безопасность, Конфиденциальность, Обновления, Горячие клавиши, Расширения + разделы приложений; изменения применяются сразу ко всем открытым окнам (через брокер) P0
Первый запуск мастер из 4 шагов: Внешний вид → Язык и регион → Форматы файлов → Аккаунт и облако; импорт настроек из Microsoft Office/LibreOffice (словари автозамены, пользовательские словари, недавние, шаблоны); регистрация ассоциаций P0
Ассоциации файлов регистрация типов (все расширения библии 3.2 + чужие форматы по выбору), «сделать приложением по умолчанию», значки типов, протокол meridian:// P0
Командная палитра общий компонент всех окон: команды текущего приложения, файлы, шаблоны, параметры, скрипты; нечёткий поиск; история P0
Восстановление после сбоя список документов с автосохранёнными версиями (из журналов операций), предпросмотр, «восстановить»/«открыть оригинал»/«удалить»; автоматическое предложение при запуске после аварийного завершения P0
Менеджер расширений скрипты, плагины, темы, шаблоны, словари: установленные/доступные (каталог, фаза 7), включение, обновление, разрешения, подпись; установка из файла .mext P1
Диагностика сбор логов всех процессов, версий, конфигурации GPU/шрифтов/ОС в архив для поддержки (без документов и секретов), «отправить отчёт» (по согласию) P0
Проверка совместимости среды при старте и по кнопке: GPU/драйвер (Skia backend fallback на CPU), шрифты (наличие комплекта), системные словари, IME, права на папки профиля, сетевые ограничения (прокси/TLS), Wayland/X11, HiDPI; отчёт с рекомендациями P1
Быстрые действия «Открыть файл», «Открыть папку как проект» (P2), перетаскивание файлов в окно Hub → открытие нужным приложением P0

2.2 Брокер

Функция Описание Приоритет
Единственный экземпляр lock + сокет/именованный канал; повторный запуск передаёт аргументы работающему брокеру P0
Маршрутизация файлов командная строка, ассоциации ОС, meridian://, перетаскивание, «Открыть с помощью»: определение типа (расширение → mimetype ZIP → сигнатура) → выбор приложения → запуск процесса или активация существующего окна с этим файлом P0
Реестр окон список открытых окон/документов по процессам, переключение «Окно» в меню всех приложений, «закрыть все», корректный выход пакета P0
Недавние/закреплённые API для приложений (добавить/обновить/удалить), миниатюры, слияние между устройствами через Cloud P0 (слияние — P1, фаза 6)
Индекс содержимого фоновая индексация документов из недавних и выбранных папок через кодеки в песочном процессе; tantivy P1
Миниатюры генерация и кэш для недавних/галереи/диалогов открытия; обработчик миниатюр ОС (Windows IThumbnailProvider, macOS QuickLook-плагин, Linux thumbnailer) — P1 P0 (кэш), P1 (ОС)
Облачная синхронизация фоновые задачи провайдеров (дельты, загрузка/выгрузка, конфликты), очередь, ограничение скорости; токены в хранилище ОС через Meridian ID-клиент P0 (каркас), P1 (провайдеры)
Уведомления приём от приложений/облака/обновлений, хранение, показ системных тостов, бейджи P0
Журнал автосохранения приложения пишут журналы операций каждые 2 с (библия 6); брокер ведёт реестр (crash_journal), следит за живостью процессов (heartbeat), при аварии помечает документы к восстановлению P0
Планировщик фоновых задач очередь с приоритетами и ограничениями ресурсов (CPU/IO/сеть/батарея/«пользователь активен»), отмена, повтор с backoff P0
Обновления проверка/загрузка/проверка подписи/дельта-применение/установка при выходе/откат P0
Аккаунт и лицензия единая сессия Meridian ID для всех окон (токены — только в брокере и хранилище ОС), проверка лицензии, плавающие аренды (Enterprise, фаза 6), раздача Features всем процессам при запуске и при изменении P0
Расширенный буфер обмена внутренние форматы MOP-фрагментов между окнами (таблица Sheets → Write с сохранением модели), история буфера (P2) P0 (базово)
Политики чтение групповых политик (Windows GPO/реестр, macOS профили plist, Linux /etc/meridian/policies.json) и организационных политик из Meridian Cloud (Business+): запреты облаков, каналы обновлений, принудительные параметры P1
Телеметрия только по согласию: анонимные метрики и отчёты о сбоях (minidump без документов) в telemetry-service P1

3. Экраны

Каркас окна — по разделу 5.3 библии, но у Hub нет ribbon: заголовок (значок, «Meridian Office», поиск ⌘K, состояние облака, аватар), слева навигация, центр, справа боковая панель, строка состояния («Meridian Office 1.1.3 · Windows» · «Последняя синхронизация 19:12»). HUB-01…HUB-04 соответствуют макету mockups/hub.html один в один.

ID Экран Описание
HUB-01 Главный экран Hub Левая панель (220 px): Главная · Недавние · Избранное · Облако · Общие со мной (счётчик); раздел «ПРИЛОЖЕНИЯ»: Write, Sheets, Slides, Draw, Paint, PDF, Notes, Mail (бейдж непрочитанных), Base, Forms (недоступные по редакции — с замком); внизу «Параметры» и «Обновление 1.2 готово» (акцент --m-sun). Центр: приветствие «Добрый вечер, Александр» + «Суббота, 3 октября · 3 файла изменены сегодня», кнопки «⌘ Командная палитра» и «+ Создать»; ряд из 6 карточек создания (Документ, Таблица, Презентация, Схема, Изображение, Заметка); вкладки Недавние · Закреплённые · Общие со мной + переключатель вида «Список ▾ · Папка ▾»; список файлов: значок приложения, имя, метка расположения (☁ Облако / Этот Mac / 👥 Общий · имена), время и размер. Правая панель (320 px) «Облако и уведомления»: карточка Meridian Cloud (сервер, квота, прогресс), «СЕГОДНЯ» — уведомления (комментарии, ответы Forms, обновление). Состояния: пустой Hub («Начните с шаблона»), офлайн (облачные файлы серые, ☁ перечёркнут), вид «Папка» (дерево папок + файлы)
HUB-02 Галерея шаблонов Заголовок «Создать из шаблона», поиск шаблонов. Слева: ПРИЛОЖЕНИЕ (Все, Write, Sheets, Slides, Draw, Forms, …), КАТЕГОРИЯ (Бизнес, Образование, Личное, Корпоративные (имя организации), Мои шаблоны — со счётчиками). Центр: «Все шаблоны», фильтры «Язык» и «Сортировка: Популярные/Новые/По имени», сетка карточек 5 в ряд (миниатюра 140 px, имя, «Приложение · Категория»). Справа (340 px) «Предпросмотр»: большая миниатюра, имя, таблица Приложение/Формат (.mwt · A4, книжная)/Автор и дата/Язык, кнопки «Создать документ» и ★ (избранное). Двойной щелчок по карточке — создать
HUB-03 Параметры пакета Окно «Параметры Meridian Office» с поиском параметра. Слева список вкладок: Общие · Внешний вид · Язык и регион · Сохранение и восстановление · Облако и аккаунт · Скрипты и безопасность · Конфиденциальность · Обновления · Горячие клавиши · Расширения; ниже «ПРИЛОЖЕНИЯ» — разделы приложений (Write, Sheets, Slides, Mail, …). Содержимое вкладок — таблица 3.1. Футер: «Изменения применяются сразу ко всем открытым окнам», «Сбросить», «Готово»
HUB-04 Первый запуск и аккаунт Диалог 900 px: слева синяя панель с логотипом, «Добро пожаловать в Meridian Office», «Четыре коротких шага — и можно работать», список шагов с отметками (✓ Внешний вид · ✓ Язык и регион · ● Форматы файлов · ○ Аккаунт и облако); справа содержимое шага. Шаг «Форматы файлов»: «В каком формате сохранять по умолчанию?» — карточки-переключатели «Форматы Meridian (.mwx, .msx, .mpx)» (рекомендуется), «Форматы Microsoft Office (.docx, .xlsx, .pptx)», «OpenDocument (.odt, .ods, .odp)» с пояснениями; флажок «Сделать Meridian Office приложением по умолчанию для файлов Office и PDF»; кнопки «← Назад», «Пропустить», «Далее →». Шаг 1: тема (светлая/тёмная/как в системе/высокий контраст) и плотность; Шаг 2: язык интерфейса, язык проверки, регион/единицы, импорт настроек из Microsoft Office/LibreOffice (словари, автозамена, шаблоны); Шаг 4: вход в Meridian ID (кнопки OAuth, e-mail, «позже»), пробный период Pro, подключение облака
HUB-05 Восстановление после сбоя Появляется при запуске после аварийного завершения или из Параметры → Сохранение. Список документов: значок, имя, приложение, «автосохранено 19:11:58 (2 с назад)», размер журнала, путь оригинала; предпросмотр выбранной версии (миниатюра из журнала); варианты «Восстановить» (открывает в приложении как «Восстановлено — не сохранено»), «Открыть оригинал», «Сохранить копию…», «Удалить»; «Восстановить все»; переключатель «показывать старые журналы»
HUB-06 Облако и подключения Список подключений с состоянием (синхронизировано/ошибка/вход требуется/квота), «+ Подключить»: Meridian Cloud (вход Meridian ID или адрес своего сервера), WebDAV/Nextcloud (URL, логин — пароль в хранилище ОС), OneDrive, Google Drive, Dropbox, Яндекс Диск (OAuth в системном браузере); настройки подключения: папки для автономного доступа, «синхронизировать недавние», лимит скорости, «отключить»; журнал синхронизации; обзор файлов подключения (как вид «Папка»)
HUB-07 Расширения Вкладки Установленные · Каталог (фаза 7) · Обновления; карточки: имя, тип (скрипт/плагин/тема/шаблоны/словарь), версия, автор, подпись (проверена/нет), разрешения (файлы, сеть, буфер), «Включить/Отключить», «Удалить», «Настроить»; «Установить из файла (.mext)»; политика организации (запрет неподписанных)
HUB-08 Поиск по содержимому Полноэкранный результат поиска из ⌘K при вводе ≥ 3 символов: группы Файлы (по содержимому) · Файлы (по имени) · Шаблоны · Команды · Параметры · Заметки (Notes) · Письма (Mail); у файлов — фрагмент с подсветкой, путь, дата; фильтры: приложение, период, расположение; «Индексация: 1 240 из 1 300» в строке состояния; «Настроить папки для индекса»
HUB-09 Командная палитра Всплывающее окно поверх любого окна пакета (Ctrl/⌘+K): поле ввода, список результатов (команды текущего приложения с клавишами, файлы, шаблоны, параметры, скрипты, «перейти к окну…»); префиксы: > команды, @ файлы, # параметры, / скрипты, : страницы/листы; клавиши ↑↓ Enter Esc; история
HUB-10 Центр уведомлений Развёрнутый список (из правой панели HUB-01 или значка в заголовке): группы по дням, фильтр по источнику, «прочитать все», «очистить», настройки тишины; карточка с действиями (открыть документ/ответить/установить)
HUB-11 Обновление Диалог: версия, канал, размер (дельта/полный), заметки выпуска (кратко), «Установить при выходе» (по умолчанию) / «Установить сейчас» (закроет окна с сохранением) / «Напомнить позже»; прогресс загрузки в строке состояния; после установки — «Что нового» (HUB-12); «Откатить» в Параметры → Обновления
HUB-12 Что нового Страница в окне Hub: заметки выпуска по версиям с иллюстрациями, ссылки на документацию
HUB-13 Диагностика и совместимость Таблица проверок (GPU/рендер, шрифты, IME, словари, права, сеть/прокси, Wayland/X11, HiDPI, хранилище ОС для токенов) с состоянием и рекомендациями; «Собрать логи» → архив meridian-diag-<дата>.zip с перечнем содержимого; «Отправить в поддержку» (по согласию, через портал)
HUB-14 Аккаунт и лицензия Карточка аккаунта (аватар, имя, e-mail, организация), редакция и статус лицензии, срок, устройства (с «деактивировать»), «Активировать ключ» (MRDN-…), «Офлайн-активация» (.mreq → .mlic), «Управление в портале», «Выйти» — макет mockups/account.html, детали в docs/10-licensing-accounts.md
HUB-15 Диалог «Открыть / Сохранить как» (общий) Единый диалог пакета поверх нативного: слева «Этот компьютер · Недавние · Облака (по подключениям) · Общие со мной», центр — файлы с миниатюрами и фильтром по типу, справа предпросмотр; при сохранении — выбор формата с пояснением потерь (OOXML/ODF); доступен и как нативный диалог по настройке
HUB-16 Значок в трее / строке меню Меню: «Открыть Hub», «Создать ▸», недавние 10, состояние облака/обновления, «Выйти из Meridian Office»; настройка «запускать брокер при входе в систему»

3.1 Вкладки параметров (HUB-03)

Вкладка Содержимое
Общие имя пользователя и инициалы (для рецензирования), запуск: показывать Hub/последние документы, папка документов по умолчанию, формат по умолчанию (Meridian/Microsoft/ODF), единицы измерения (мм/см/дюймы/pt), подтверждения, «быстрый запуск» (брокер в трее)
Внешний вид тема (Светлая/Тёмная/Как в системе/Высокий контраст), плотность (Лента/Компактная панель/Фокус), цвет акцента (приложения/системы/нейтральный), масштаб интерфейса и шрифт (Inter 13 px), анимация с уважением к «уменьшить движение», значки (Meridian Glyphs/Цветные/Монохромные) — как в макете
Язык и регион язык интерфейса, языки документов/проверки (словари Lingo: установленные/загрузить), регион (форматы чисел/дат/валюты, первый день недели, бумага A4/Letter), раскладка клавиатуры для сочетаний, транслитерация имён файлов
Сохранение и восстановление интервал журнала автосохранения (2 с, фиксировано по библии; настраивается только «пауза на батарее»), хранить журналы N дней, резервные копии при сохранении (.bak), восстановление при запуске, «Открыть список восстановления» (HUB-05), очистка кэшей/миниатюр, расположение профиля
Облако и аккаунт аккаунт Meridian ID (вход/выход, 2FA, устройства), лицензия (ключ, статус, редакция, обновить), подключения облаков (HUB-06), «синхронизировать параметры и недавние между устройствами»
Скрипты и безопасность политика скриптов в документах (запрещены / только подписанные / спрашивать / разрешены для доверенных расположений), доверенные расположения и издатели, разрешения расширений, Python-плагин (вкл/путь), защищённый просмотр для файлов из интернета, блокировка внешнего содержимого, проверка подписей документов
Конфиденциальность телеметрия (выкл по умолчанию), отчёты о сбоях (спрашивать), онлайн-функции (проверка обновлений, онлайн-шаблоны, Assist — каждая отдельно), очистка истории недавних и поиска, «что мы собираем» (ссылка)
Обновления канал (stable/beta/nightly — nightly только с подтверждением), автоматическая проверка (ежедневно), загружать в фоне, устанавливать при выходе, «Проверить сейчас», история версий и «Откатить к предыдущей», прокси
Горячие клавиши схема (Microsoft Office / LibreOffice / Своя), таблица команд по приложениям с поиском и переназначением, конфликты, экспорт/импорт схемы (.mkeys JSON)
Расширения то же, что HUB-07, в виде вкладки
Разделы приложений параметры Write/Sheets/Slides/…/Mail: открываются как вкладки того же окна (содержимое — из документов приложений); при вызове из приложения окно открывается сразу на его разделе

4. Модель данных

4.1 Хранилище профиля

<profile>/                     ← Windows: %LOCALAPPDATA%\Meridian\Office ; macOS: ~/Library/Application Support/Meridian Office ; Linux: $XDG_DATA_HOME/meridian-office
├── hub.db                     ← SQLite (схема ниже), WAL
├── settings.json              ← параметры пакета (без секретов), с подписью политики при управлении организацией
├── index/                     ← tantivy (поиск по содержимому)
├── thumbs/<hash[0..2]>/<hash>.webp   ← миниатюры (256 и 512 px)
├── journals/<app>/<doc-ulid>/ ← журналы автосохранения приложений (ops.log + snapshot.*)
├── templates/                 ← пользовательские шаблоны (.mwt, .mst, …)
├── extensions/<id>/           ← установленные расширения
├── cache/                     ← облачные файлы для автономного доступа (по подключениям), обновления (updates/)
├── logs/                      ← журналы процессов (ротация 7 дней)
└── license.mlic, device.id    ← лицензия и отпечаток (библия 9.3); токены — только в хранилище ОС

4.2 Схема hub.db

PRAGMA journal_mode = WAL; PRAGMA application_id = 0x4D485831; -- 'MHX1'

CREATE TABLE recent (
  id INTEGER PRIMARY KEY, uri TEXT NOT NULL UNIQUE,          -- file:///… | cloud://<account>/<id> | meridian://…
  app TEXT NOT NULL, title TEXT, ext TEXT, size INTEGER, mtime INTEGER,
  last_opened INTEGER NOT NULL, open_count INTEGER DEFAULT 1, device_id TEXT NOT NULL,
  thumb_hash TEXT, location TEXT CHECK(location IN ('local','cloud','shared','removable','network')),
  cloud_account INTEGER REFERENCES cloud_accounts(id) ON DELETE SET NULL, shared_by TEXT,
  favorite INTEGER DEFAULT 0, missing INTEGER DEFAULT 0, removed INTEGER DEFAULT 0, synced INTEGER DEFAULT 0
);
CREATE INDEX recent_opened ON recent(last_opened DESC);
CREATE TABLE pinned (recent_id INTEGER PRIMARY KEY REFERENCES recent(id) ON DELETE CASCADE, ord INTEGER NOT NULL, group_name TEXT);

CREATE TABLE templates (
  id TEXT PRIMARY KEY,                                        -- ulid или стабильный id каталога
  source TEXT NOT NULL CHECK(source IN ('builtin','user','org','online')), app TEXT NOT NULL, path TEXT, url TEXT,
  title TEXT NOT NULL, description TEXT, category TEXT, lang TEXT, tags TEXT, author TEXT, version TEXT,
  updated INTEGER, popularity INTEGER DEFAULT 0, thumb_hash TEXT, favorite INTEGER DEFAULT 0, indexed_at INTEGER
);
CREATE INDEX templates_app_cat ON templates(app, category);

CREATE TABLE cloud_accounts (
  id INTEGER PRIMARY KEY, provider TEXT NOT NULL CHECK(provider IN ('meridian','webdav','onedrive','gdrive','dropbox','yandex')),
  display_name TEXT, account_id TEXT, email TEXT, server_url TEXT, root TEXT,
  credential_ref TEXT NOT NULL,                               -- ключ в хранилище ОС (Keychain/DPAPI/Secret Service); никаких токенов здесь
  state TEXT CHECK(state IN ('ok','auth_required','error','disabled')) DEFAULT 'ok', last_error TEXT,
  quota_used INTEGER, quota_total INTEGER, last_sync INTEGER, delta_cursor TEXT, offline_folders TEXT, rate_limit INTEGER, ord INTEGER
);
CREATE TABLE cloud_items (                                    -- кэш метаданных облачных файлов / cloud metadata cache
  account_id INTEGER REFERENCES cloud_accounts(id) ON DELETE CASCADE, remote_id TEXT, parent_id TEXT, name TEXT, is_dir INTEGER,
  size INTEGER, mtime INTEGER, etag TEXT, local_path TEXT, local_state TEXT CHECK(local_state IN ('none','cached','dirty','conflict')),
  shared_by TEXT, PRIMARY KEY(account_id, remote_id)
);
CREATE INDEX cloud_items_parent ON cloud_items(account_id, parent_id);

CREATE TABLE notifications (
  id INTEGER PRIMARY KEY, ts INTEGER NOT NULL, source TEXT NOT NULL,   -- app id | cloud | update | license | system
  kind TEXT NOT NULL, title TEXT NOT NULL, body TEXT, icon TEXT, actions TEXT,   -- JSON [{id,label,command}]
  uri TEXT, read INTEGER DEFAULT 0, dismissed INTEGER DEFAULT 0, dedupe_key TEXT UNIQUE
);
CREATE INDEX notifications_ts ON notifications(ts DESC);

CREATE TABLE crash_journal (
  id INTEGER PRIMARY KEY, doc_id TEXT NOT NULL UNIQUE, app TEXT NOT NULL, uri TEXT, title TEXT,
  journal_path TEXT NOT NULL, pid INTEGER, started INTEGER, last_write INTEGER, last_heartbeat INTEGER,
  state TEXT CHECK(state IN ('open','closed_clean','crashed','recovered','discarded')) DEFAULT 'open', snapshot_thumb TEXT
);

CREATE TABLE index_state (                                    -- индексация содержимого / content indexing bookkeeping
  uri TEXT PRIMARY KEY, mtime INTEGER, size INTEGER, hash BLOB, indexed_at INTEGER, status TEXT, error TEXT
);
CREATE TABLE index_roots (path TEXT PRIMARY KEY, recursive INTEGER DEFAULT 1, enabled INTEGER DEFAULT 1);

CREATE TABLE tasks (                                          -- планировщик фоновых задач / background scheduler
  id INTEGER PRIMARY KEY, kind TEXT NOT NULL, payload TEXT, priority INTEGER DEFAULT 5,
  state TEXT CHECK(state IN ('queued','running','done','failed','cancelled','deferred')) DEFAULT 'queued',
  not_before INTEGER, attempts INTEGER DEFAULT 0, max_attempts INTEGER DEFAULT 5, last_error TEXT,
  requires TEXT,                                              -- JSON: {network:true, ac_power:false, idle:true}
  created INTEGER, started INTEGER, finished INTEGER, progress REAL
);
CREATE INDEX tasks_state ON tasks(state, priority, not_before);

CREATE TABLE devices (device_id TEXT PRIMARY KEY, name TEXT, os TEXT, last_seen INTEGER, is_this INTEGER);
CREATE TABLE windows (pid INTEGER, window_id TEXT, app TEXT, uri TEXT, title TEXT, opened INTEGER, PRIMARY KEY(pid, window_id));   -- живой реестр, очищается при старте
CREATE TABLE extensions (id TEXT PRIMARY KEY, kind TEXT, name TEXT, version TEXT, author TEXT, path TEXT, enabled INTEGER DEFAULT 1,
                         signature_state TEXT, permissions TEXT, installed INTEGER, update_url TEXT, latest_version TEXT);
CREATE TABLE file_assoc (ext TEXT PRIMARY KEY, app TEXT, registered INTEGER, is_default INTEGER);
CREATE TABLE updates (version TEXT PRIMARY KEY, channel TEXT, manifest TEXT, state TEXT, downloaded_path TEXT, size INTEGER, downloaded INTEGER, verified INTEGER, applied INTEGER, rolled_back INTEGER);
CREATE TABLE kv (key TEXT PRIMARY KEY, value TEXT);          -- мелкие состояния: last_whats_new, first_run_done, index_version…

4.3 Структуры брокера (Rust)

// kernel/crates/meridian-hub/src/broker.rs
pub struct Broker {
    db: Db, ipc: IpcServer, scheduler: Scheduler, index: ContentIndex, thumbs: ThumbCache,
    cloud: CloudManager, notify: Notifier, updates: Updater, session: IdSession, license: LicenseState,
    windows: WindowRegistry, journals: JournalRegistry, clipboard: SharedClipboard, policies: Policies,
}

/// Сообщения IPC (CBOR по сокету) / IPC messages (CBOR over socket)
#[derive(Serialize, Deserialize)]
pub enum Request {
    Hello { app: AppId, pid: u32, version: Version },
    Open { uris: Vec<Uri>, hint: Option<AppId>, activate: bool },
    New { app: AppId, template: Option<TemplateId> },
    RecentTouch { uri: Uri, app: AppId, title: String, size: u64, mtime: i64 },
    RecentList { filter: RecentFilter }, Pin { uri: Uri, pinned: bool },
    JournalOpen { doc_id: Ulid, app: AppId, uri: Option<Uri> }, JournalHeartbeat { doc_id: Ulid }, JournalClose { doc_id: Ulid, clean: bool },
    Notify { notification: Notification }, NotificationsList, NotificationAck { id: i64 },
    CloudList { account: i64, parent: Option<String> }, CloudGet { account: i64, id: String }, CloudPut { account: i64, parent: String, local: PathBuf },
    Search { query: String, scope: SearchScope, limit: u32 },
    Features, Session, SettingsGet { keys: Vec<String> }, SettingsSet { patch: Map },
    WindowRegister { window_id: String, uri: Option<Uri>, title: String }, WindowList, WindowActivate { window_id: String },
    ClipboardPut { formats: Vec<ClipFormat> }, ClipboardGet { format: ClipFormat },
    TaskEnqueue { task: TaskSpec }, TaskCancel { id: i64 },
    UpdateCheck, UpdateApplyOnExit { enable: bool }, Quit { all: bool },
}
#[derive(Serialize, Deserialize)]
pub enum Event { RecentChanged, NotificationsChanged, SettingsChanged { keys: Vec<String> }, FeaturesChanged(Features),
                 CloudStateChanged { account: i64 }, UpdateAvailable(UpdateInfo), SessionChanged, OpenRequest { uris: Vec<Uri> },
                 IndexProgress { done: u64, total: u64 }, TaskProgress { id: i64, progress: f32 } }

5. Алгоритмы и скрипты

5.1 Единственный экземпляр и IPC

pub fn connect_or_spawn() -> Result<BrokerClient> {
    let lock = Lock::try_acquire(profile().join("broker.lock"))?;       // flock / LockFileEx
    match lock {
        Lock::Held(_) => {                                              // брокера нет — мы становимся брокером / no broker: become one
            spawn_broker_process()?;                                    // отдельный процесс meridian-broker, lock передаётся ему
        }
        Lock::Busy => {}                                                // брокер есть / broker exists
    }
    // Подключение с повтором до 3 с; при неудаче — сброс устаревшего lock и повторная попытка один раз
    retry(Duration::from_secs(3), || BrokerClient::connect(socket_path()))
}

5.2 Планировщик фоновых задач с ограничением ресурсов

Scheduler (tokio, N воркеров = min(2, cores/2)):
  очереди по классам: interactive (миниатюры видимых, поиск) > sync (облако, недавние) > index (содержимое) > maintenance (очистка, обновления)
  выбор задачи: наивысший класс с готовой задачей (not_before <= now, requires выполнены), внутри класса — priority, затем FIFO
  requires: network (есть сеть и не «лимитный» тариф — NetworkInformation/SCNetworkReachability/NetworkManager), ac_power (не на батарее < 20 %),
            idle (пользователь неактивен ≥ 30 с — для index/maintenance), not_fullscreen (презентация/игра — пауза)
  ограничение ресурсов: index/maintenance — один воркер, низкий приоритет потока (SCHED_IDLE / BELOW_NORMAL / QOS_CLASS_BACKGROUND),
            IO-троттлинг (ionice idle / IOPOL_THROTTLE / Windows IO priority Low), пауза при CPU пользователя > 60 % 5 с подряд,
            лимит памяти на задачу (песочный процесс кодеков с RLIMIT/Job Object/task_set_limit)
  отказоустойчивость: повтор с backoff 2^attempts мин (макс 6 ч), max_attempts; после — failed с уведомлением (для sync) или тихо (index)
  отмена: cooperative (CancellationToken), прогресс в tasks.progress → Event::TaskProgress
  персистентность: tasks в hub.db; при старте running → queued

5.3 Индексация содержимого документов

5.4 Генерация миниатюр

5.5 Слияние недавних между устройствами (Cloud, фаза 6)

sync_recent(local, remote):                                  // remote — список записей из Cloud (по аккаунту)
  ключ = uri для cloud://; для file:// — (device_id, path): локальные пути другого устройства показываются
          как «на устройстве X» (открыть нельзя, но можно найти копию в облаке по cloud_id, если файл синхронизирован)
  объединение по ключу:
    last_opened = max(local, remote); open_count = сумма дельт (CRDT-счётчик по device_id)
    removed (пользователь удалил из списка) — LWW по времени удаления; favorite — LWW
    pinned — порядок как последовательность по устройству-источнику последней правки (LWW на список)
  усечение: 500 записей по last_opened; записи других устройств без cloud_id — не старше 90 дней
  конфликты не блокируют: результат пишется локально, выгружается дельта (только изменённые записи)

5.6 Журнал автосохранения и восстановление

5.7 Обновления

check():   GET https://update.meridian-office.<tld>/v1/<channel>/<platform>-<arch>/manifest.json  (ETag; раз в сутки; прокси системный)
           manifest = { version, released, min_from, packages: [{ kind: full|delta, from, url, size, sha256, sig }], notes_url, mandatory, rollout: 0..100 }
           подпись: manifest.sig — Ed25519 (ключ зашит в сборку; резервный — для ротации); проверка ДО разбора JSON
           rollout: hash(device_id) % 100 < rollout → предложить; mandatory → нельзя отложить дольше 7 дней
download(): выбор пакета: delta (from == текущая версия) иначе full; загрузка в cache/updates/ с докачкой (Range), лимит скорости по настройке,
            проверка sha256 и подписи пакета (minisign-совместимая); при ошибке — full
apply():   «при выходе»: когда все окна закрыты (брокер ждёт) или по кнопке «сейчас» (брокер просит окна сохранить и закрыться)
           Windows (MSIX): PackageManager.AddPackageByUriAsync с DeferRegistration → регистрируется при следующем запуске; MSI — msiexec /qn с UAC;
           macOS: распаковка bundle в staging, проверка подписи/нотаризации (codesign --verify, spctl), атомарная замена через rename, перезапуск;
           Linux: Flatpak — `flatpak update` (через portal), AppImage — замена файла + сохранение прав, deb/rpm — уведомление «обновите через менеджер пакетов»
           дельты: формат bidiff/zstd по файлам внутри bundle (список файлов с хэшами «до/после»), применение в staging, затем верификация полного хэша
rollback(): предыдущая версия хранится (MSIX — встроенный откат; macOS — `Meridian Office.app.previous`; AppImage — `.previous`) 1 релиз; «Откатить» в параметрах

Hub после обновления показывает HUB-12 один раз; каналы beta/nightly — отдельный rollout и предупреждение.

5.8 Аккаунт, лицензия и флаги функций

Брокер держит сессию Meridian ID (refresh-токен в хранилище ОС, access — в памяти), раз в 7 дней подтверждает подписку (библия 9.3), читает license.mlic, вычисляет Features и раздаёт процессам при Hello и через Event::FeaturesChanged; окна показывают «замок» по Features::has(Feature::X). Плавающие лицензии (Enterprise, фаза 6): аренда на 1 ч продлевается брокером в фоне. Детали — docs/10-licensing-accounts.md.

5.9 MeridianScript API Hub

Объект App в контексте Hub и объект Meridian.hub из любого приложения (одно и то же API через брокер).

interface HubApp {
  recent: {
    list(opts?: { app?: AppId; limit?: number; location?: 'local'|'cloud'|'shared'; pinnedOnly?: boolean }): Promise<RecentItem[]>;
    pin(uri: string, pinned?: boolean): Promise<void>; remove(uri: string): Promise<void>; clear(): Promise<void>;
    open(uri: string, opts?: { app?: AppId; readOnly?: boolean }): Promise<void>;
    on(event: 'changed', h: () => void): Disposable;
  };
  templates: {
    list(filter?: { app?: AppId; category?: string; lang?: string; source?: 'builtin'|'user'|'org'|'online'; query?: string }): Promise<Template[]>;
    create(templateId: string, opts?: { title?: string; openIn?: 'window'|'tab' }): Promise<DocumentHandle>;
    register(path: string, meta?: { title?: string; category?: string; lang?: string }): Promise<Template>;
    unregister(id: string): Promise<void>; favorite(id: string, on?: boolean): Promise<void>;
  };
  cloud: {
    accounts: CloudAccount[]; connect(provider: 'meridian'|'webdav'|'onedrive'|'gdrive'|'dropbox'|'yandex', opts?: { serverUrl?: string }): Promise<CloudAccount>;
    disconnect(accountId: number): Promise<void>; sync(accountId?: number): Promise<void>;
    list(accountId: number, path?: string): Promise<CloudItem[]>; download(accountId: number, remoteId: string, localPath: string): Promise<void>;
    upload(accountId: number, localPath: string, remoteFolder: string): Promise<CloudItem>; status(): CloudStatus;
    on(event: 'stateChanged'|'syncCompleted', h: (e: { accountId: number }) => void): Disposable;
  };
  notifications: {
    post(n: { title: string; body?: string; icon?: string; uri?: string; actions?: { id: string; label: string }[]; dedupeKey?: string }): Promise<number>;
    list(opts?: { unreadOnly?: boolean; source?: string }): Promise<Notification[]>; markRead(id?: number): Promise<void>; dismiss(id: number): Promise<void>;
    on(event: 'action', h: (e: { id: number; actionId: string }) => void): Disposable;
  };
  search(query: string, scope?: ('files'|'content'|'templates'|'commands'|'settings')[]): Promise<SearchResult[]>;
  launch(app: AppId, opts?: { file?: string; template?: string }): Promise<void>;
  windows: { list(): Promise<WindowInfo[]>; activate(id: string): Promise<void> };
  commands: { register(cmd: { id: string; title: string; keywords?: string[]; shortcut?: string; run: () => void | Promise<void> }): Disposable };
  settings: { get<T = unknown>(key: string): Promise<T>; set(key: string, value: unknown): Promise<void>; on(event: 'changed', h: (keys: string[]) => void): Disposable };
  session: { user: User | null; features: string[]; edition: string; signIn(): Promise<User>; signOut(): Promise<void> };
  updates: { check(): Promise<UpdateInfo | null>; on(event: 'available', h: (u: UpdateInfo) => void): Disposable };
  tasks: { enqueue(spec: { kind: string; payload?: unknown; priority?: number; requires?: Requires }): Promise<number>; cancel(id: number): Promise<void> };
}

Примеры:

// 1. Команда в палитре: открыть вчерашние документы / Palette command: reopen yesterday's documents
Meridian.hub.commands.register({ id: 'my.reopenYesterday', title: 'Открыть вчерашние документы', run: async () => {
  const since = Date.now() - 864e5;
  for (const r of await Meridian.hub.recent.list({ limit: 50 })) if (r.lastOpened.getTime() > since) await Meridian.hub.recent.open(r.uri);
}});

// 2. Регистрация корпоративных шаблонов из общей папки / Register org templates from a shared folder
for (const f of await Meridian.fs.list('//fileserver/templates', { ext: ['.mwt', '.mst', '.mpt'] }))
  await Meridian.hub.templates.register(f.path, { category: 'Корпоративные' });

// 3. Уведомление с действием / Notification with an action
const id = await Meridian.hub.notifications.post({ title: 'Отчёт готов', body: 'Квартальный отчёт собран', actions: [{ id: 'open', label: 'Открыть' }], uri: 'file:///…/Отчёт.mwx' });
Meridian.hub.notifications.on('action', e => { if (e.id === id && e.actionId === 'open') Meridian.hub.recent.open('file:///…/Отчёт.mwx'); });

Скрипты Hub (автозапуск при старте брокера) — только из extensions/ с разрешениями hub.recent, hub.cloud, hub.notifications, fs.read; политика организации может их запретить.


6. Форматы

У Hub нет собственного формата документа. Форматы, которыми он оперирует:

Формат Назначение
settings.json параметры пакета (схема JSON Schema settings.schema.json), экспорт/импорт параметров, политики организации (подписанный policy.json)
.mkeys схема горячих клавиш (JSON)
.mext расширение: ZIP с extension.json (id, версия, тип, разрешения, точки входа), scripts/, themes/, templates/, dictionaries/, подпись signature.sig (Ed25519)
manifest.json обновлений раздел 5.7, подпись отдельным файлом
Шаблоны .mwt/.mst/.mpt/.mvt/.mft и чужие (.dotx/.xltx/.potx/.ott/.ots/.otp) галерея; чужие шаблоны открываются через кодеки соответствующих приложений
thumbnail.png в пакетах источник миниатюр
meridian:// протокол: meridian://<app>/<action>?<params>; регистрируется при установке; параметры URL-кодированы; пути из протокола проверяются (без выхода за доверенные расположения без подтверждения)
Журналы journals/ ops.log (кадры: длина, CRC32C, CBOR операции), snapshot.<ext> — формат приложения
Диагностический архив meridian-diag-<дата>.zip логи, about.json (версии, ОС, GPU, шрифты), settings.json без секретов, список расширений

7. Горячие клавиши

Действие Клавиши
Командная палитра (везде) Ctrl+K / ⌘K
Открыть Hub из любого окна Ctrl+Shift+H
Создать: документ / таблицу / презентацию / схему / изображение / заметку Ctrl+N (в Hub — меню выбора), Ctrl+Shift+1…6
Открыть файл Ctrl+O
Поиск (фокус в поле) Ctrl+F или Ctrl+K
Разделы Hub: Главная / Недавние / Избранное / Облако / Общие Alt+1…5
Галерея шаблонов Ctrl+Shift+N
Параметры пакета Ctrl+,
Закрепить/открепить выбранный файл Ctrl+P (в списке)
Удалить из недавних Delete
Открыть расположение файла Ctrl+Shift+R
Открыть в режиме «только чтение» Ctrl+Shift+O
Переключить вид Список / Папка Ctrl+Shift+L / Ctrl+Shift+F
Центр уведомлений Ctrl+Shift+U
Проверить обновления Ctrl+Shift+Alt+U
Восстановление после сбоя Ctrl+Shift+Alt+R
Переключение окон пакета Ctrl+Tab (в меню «Окно» всех приложений — список)
Выход из Meridian Office (все окна) Ctrl+Shift+Q / ⌘Q
Глобальные (регистрирует брокер, настраиваются): быстрая заметка / скриншот в Notes Win+Alt+N · Win+Shift+N / ⌃⌥N · ⌘⇧N

8. Критерии готовности

8.1 Hub 1.0 (фаза 1, вместе с Write)

  1. Холодный запуск Hub ≤ 1,0 с до интерактивности (SSD, средний ноутбук), брокер ≤ 300 мс; повторное открытие файла из проводника при запущенном брокере — окно приложения ≤ 1,5 с.
  2. Единственный экземпляр: 100 параллельных запусков meridian-write file.docx открывают один документ один раз; 10 разных файлов — 10 окон; протокол meridian:// работает на трёх ОС.
  3. Недавние: 500 записей, миниатюры для всех форматов библии 3.3 (кэш, рендер в песочнице; падение рендера не ломает Hub); недоступные файлы помечены; вид «Папка».
  4. Галерея: ≥ 60 встроенных шаблонов (Write/Sheets/Slides минимум) с миниатюрами, фильтры, предпросмотр, корпоративная папка; поиск по шаблонам ≤ 100 мс.
  5. Параметры: все 10 вкладок; изменение темы/плотности применяется ко всем открытым окнам ≤ 200 мс; экспорт/импорт параметров; импорт настроек из MS Office/LibreOffice (словари, автозамена).
  6. Первый запуск: мастер 4 шага, ассоциации файлов регистрируются на трёх ОС (MSIX-манифест, Info.plist UTI, .desktop + MIME XML), пробный период активируется.
  7. Восстановление: kill -9 приложения с несохранённым документом → HUB-05 предлагает версию не старше 2 с; 100 итераций теста без потерь.
  8. Обновления: проверка/загрузка/подпись/дельта/установка при выходе/откат — на трёх ОС (stable и beta); поддельный манифест или пакет отвергаются (тест с неверной подписью).
  9. Аккаунт и лицензия: вход, активация ключом, офлайн-активация, отображение редакции, Features у всех окон; без сети и аккаунта Free работает полностью.
  10. Облако: WebDAV/Nextcloud (открыть/сохранить/обзор/автономный кэш) и заглушка Meridian Cloud; токены только в хранилище ОС (аудит: grep профиля на токены — пусто).
  11. Уведомления: системные тосты на трёх ОС с действиями, центр уведомлений, тишина.
  12. Диагностика: архив собирается ≤ 10 с, не содержит содержимого документов и секретов (автотест).
  13. Доступность Hub (экранный диктор, клавиатура, высокий контраст) и снимочные тесты HUB-01…HUB-16.

8.2 Hub 1.x

Поиск по содержимому (tantivy, песочный кодек-хост), провайдеры OneDrive/Google Drive/Dropbox/Яндекс Диск, ОС-миниатюры, менеджер расширений, «Что нового», проверка совместимости среды, политики организаций, слияние недавних между устройствами (фаза 6), онлайн-каталог шаблонов (фаза 7).


9. Риски

Риск Вероятность Влияние Снижение
Брокер — единая точка отказа: его сбой/зависание блокирует открытие файлов средняя «ничего не открывается» приложения работают без брокера (деградация: нет недавних/облака), автоперезапуск брокера, сторожевой таймер, lock с проверкой живости
Различия ОС в ассоциациях, протоколах, автозапуске, одиночном экземпляре (sandbox macOS, Flatpak-портал, MSIX-ограничения) высокая неработающие сценарии на одной из ОС матрица тестов на трёх ОС в CI, отдельные реализации за трейтами Platform, ранняя проверка в фазе 0
OAuth-регистрации у облачных провайдеров (Google Drive — верификация CASA, OneDrive — Entra, Dropbox — production approval, Яндекс — модерация) высокая провайдеры недоступны до одобрения начать в фазе 1, WebDAV как универсальный путь, ввод собственного client_id для организаций
Индексация содержимого — нагрузка на CPU/диск/батарею, жалобы «тормозит компьютер» средняя негатив планировщик с idle/battery-условиями, низкий приоритет, лимиты, выключатель, по умолчанию только «Документы» и недавние
Приватность индекса и миниатюр (на общих компьютерах) средняя утечка содержимого профиль пользователя с правами 0700, не индексировать защищённые документы, «очистить индекс», политика организации
Автообновление: подпись/ключи, откат, сломанная дельта средняя неработающая установка подпись Ed25519 с резервным ключом, верификация полного хэша после дельты, автоматический fallback на полный пакет, откат, поэтапный rollout
Flatpak/MSIX-песочницы ограничивают доступ к файлам и реестру для ассоциаций и миниатюр средняя неполные функции на Linux/Windows Store порталы (xdg-desktop-portal), MSIX-расширения (windows.fileTypeAssociation, windows.protocol, windows.thumbnailHandler)
Зависимость UI многих модулей от Hub (поиск, параметры, палитра) усложняет релизы приложений низкая связанность палитра и параметры — общие компоненты shell/, версионированный IPC-протокол с совместимостью на 2 минорные версии

10. Вопросы к библии

  1. Токен цвета Hub. В mds.css/макетах используется --app-hub, в таблице 5.2 библии его нет (Hub = --m-ink). Предлагаем добавить строку --app-hub = #0B3C5D (= --m-ink) для единообразия токенов.
  2. Процесс брокера. Библия (раздел 6) называет брокером Hub; здесь уточнено: брокер — отдельный безоконный процесс meridian-broker, окно Hub — его клиент. Если это согласуется с 03-architecture.md, стоит отразить формулировку там.
  3. Глобальные сочетания клавиш пакета (быстрая заметка, скриншот в Notes) — регистрирует брокер; просим зафиксировать перечень зарезервированных глобальных сочетаний в разделе 5.3 библии (см. также docs/apps/notes.md, вопрос 10.3).
  4. Расширения .mext и схема .mkeys — новые расширения файлов, не входящие в таблицу 3.2 (она про документы); предлагаем отдельную таблицу «служебные форматы» в библии или в 03-architecture.md.
  5. Онлайн-каталог шаблонов (templates.meridian-office.<tld>) и сервис обновлений уже есть в 9.4 (update-service); каталог шаблонов как сервис в 9.4 отсутствует — добавить в фазу 7 (магазин).