Mosaica |
Описание приложения
mosaica
Небольшое приложение на Node.js + Express для просмотра и редактирования AsciiDoc-документов, хранящихся в файлах.
Что умеет
-
открывает AsciiDoc-документы из папки
content/ -
показывает дерево файлов
-
создает, удаляет и перемещает файлы/папки прямо из компонента дерева
-
редактирует AsciiDoc в браузере
-
сохраняет изменения обратно в файлы
-
поддерживает авторизацию пользователей без базы данных
-
скрывает и показывает части документов по правам доступа пользователя
-
защищает редактор и файловый API ключами доступа
-
хранит пользователей в
SECURITY.JSON, а серверные сессии вSESSIONS.JSON -
поддерживает внутренние компоненты через синтаксис
webcomp::component-name[…] -
поддерживает файловое меню сайта и меню разделов через
_menu.json
Структура проекта
-
content/— пользовательский контент в формате.adoc -
SECURITY.JSON— пользователи, группы и ключи доступа -
SESSIONS.JSON— файловое хранилище активных серверных сессий -
src/— сервер и клиентские исходники -
public/— собранные браузерные бандлы -
dist/— собранный серверный код -
test/— автоматические smoke/regression тесты
Как это работает
-
сайт стартует с
content/index.adoc -
страница редактора находится в
content/editor.adoc -
дерево файлов показывает содержимое
content/ -
все пути в ссылках и редакторе указываются относительно
content/ -
префикс
content/в ссылках писать не нужно -
директивы с путями к файлам (например
include::) должны быть относительными к текущему документу:include::./temp.adoc[] -
заголовок вкладки браузера можно задать атрибутом документа
:title: -
пользователи, группы и права доступа хранятся в
SECURITY.JSON -
после входа сервер сохраняет сессию в
SESSIONS.JSONи выдает cookie -
блоки доступа рендерятся только для пользователей с нужным ключом доступа
-
внутри
webcomp::access[…]директивыinclude::…[]обрабатываются как отдельный блок (включая случай inline-записи) -
редактор, дерево и файловый API доступны только авторизованным пользователям с одним из ключей:
edit,content.edit,editor,admin -
при открытии документа сервер ищет шаблон с именем из
.envпеременнойtemplate_name -
шаблон ищется в папке документа и далее вверх по дереву до корня
content/ -
content::внутри шаблона заменяется содержимым открываемого документа до финального рендера AsciiDoc -
кнопки редактирования (иконка карандаша) добавляются на этапе серверного рендера отдельно для шаблона и отдельно для текущей страницы
-
меню:
-
глобальное меню берется из
content/_menu.json -
меню раздела ищется как ближайший
_menu.jsonвверх от текущего документа до корняcontent/ -
пункты меню можно ограничивать по ключу доступа через
accessKey
Компоненты
Авторизация
webcomp::auth[]
Дерево файлов
webcomp::file-tree[]
AsciiDoc-редактор
webcomp::asciidoc-editor[]
Меню
Вертикальное (по умолчанию):
webcomp::menu[type=site][]
Горизонтальное:
webcomp::menu[type=site,layout=horizontal][]
Меню раздела:
webcomp::menu[type=section][]
Меню раздела (горизонтальное):
webcomp::menu[type=section,layout=horizontal][]
Блок доступа
webcomp::access[key=demo][
Содержимое увидят только пользователи с ключом `demo`
]
Шаблонный слот
Шапка
content::
Подвал
Титул вкладки
Чтобы управлять названием вкладки браузера, задайте атрибут :title: в документе:
= Заголовок документа
:title: Мое название вкладки
Формат _menu.json
Файл может быть массивом пунктов или объектом вида { "items": […] }.
Поддерживаемые поля пункта:
-
title— заголовок пункта -
path— путь к документу (если не указан, пункт будет без ссылки) -
accessKey— ключ доступа для ограничения видимости пункта -
children— массив дочерних пунктов
Правила для path:
-
./…и../…считаются относительно папки, где лежит текущий_menu.json -
остальные пути считаются относительно корня
content/
Требования
-
Node.js >= 22
Установка
npm install
Опционально можно создать .env из .env.example.
Запуск
Режим разработки
npm run dev
Сборка
npm run build
Запуск production-сборки
npm start
Тесты
npm test
Docker
Сборка образа
docker build -t mosaica:local .
Локальный запуск контейнера
docker run --rm -p 3000:3000 mosaica:local
Приложение хранит контент, пользователей и сессии в файлах. Для production-контейнера эти данные лучше монтировать снаружи через volume:
-
TREE_BASE_DIR— директория сcontent/ -
SECURITY_FILE— путь кSECURITY.JSON -
SESSION_FILE— путь кSESSIONS.JSON
Kubernetes и Helm
В репозитории добавлен chart: chart/mosaica.
По умолчанию chart:
-
поднимает
1реплику -
создает
PersistentVolumeClaim -
хранит
content,SECURITY.JSONиSESSIONS.JSONв одном persistent volume -
при первом старте копирует стартовые
content/иSECURITY.JSONиз образа в volume -
публикует ingress для
mosaica.silinmo.ru
Пример ручного деплоя:
helm upgrade --install mosaica ./chart/mosaica \
--namespace mosaica \
--create-namespace \
--set image.repository=registry.example.com/mosaica \
--set image.tag=latest \
--set imagePullSecrets[0].name=regcred
Если у кластера есть свой ingress class или cert-manager, это настраивается через chart/mosaica/values.yaml, например:
ingress:
className: nginx
annotations:
cert-manager.io/cluster-issuer: letsencrypt
tls:
- hosts:
- mosaica.silinmo.ru
secretName: mosaica-tls
GitHub Actions deploy
Добавлен workflow .github/workflows/deploy.yml для self-hosted runner.
Он делает следующее:
-
собирает Docker-образ
-
пушит его в ваш registry
-
подключается к Kubernetes через
KUBE_CONFIG -
создает или обновляет
imagePullSecret -
выполняет
helm upgrade --install
Нужные GitHub Secrets:
-
REGISTRY_URL -
REGISTRY_USERNAME -
REGISTRY_PASSWORD -
KUBE_CONFIG
KUBE_CONFIG можно хранить либо как обычный текст kubeconfig, либо как base64 от kubeconfig: workflow поддерживает оба варианта.
По умолчанию workflow создает namespace mosaica и imagePullSecret с именем regcred.
Если в кластере нужен нестандартный ingress class, storage class или TLS, это лучше сразу прописать в chart/mosaica/values.yaml.
Основные маршруты
-
/— открываетcontent/index.adoc -
/editor— открывает страницу редактора и требует права доступа -
/health— health check -
/api/tree— дерево файлов, требует права доступа -
/api/tree/create— создать файл/папку, требует права доступа -
/api/tree/delete— удалить файл/папку, требует права доступа -
/api/tree/move— переместить/переименовать файл/папку, требует права доступа -
/api/file— чтение и сохранение файлов, требует права доступа -
/api/asciidoc/render— рендер AsciiDoc в HTML -
/api/menu— отдает меню сайта/раздела (type=site|section) -
/api/auth/session— текущая сессия пользователя -
/api/auth/register— регистрация -
/api/auth/login— вход -
/api/auth/logout— выход -
/api/auth/profile— обновление профиля
Ограничения
-
приложение работает только с файлами внутри
content/ -
выход за пределы базовой директории запрещен
-
бинарные файлы не поддерживаются
-
большие файлы могут быть отклонены по лимиту размера
-
данные пользователей и прав хранятся только в
SECURITY.JSON -
активные сессии хранятся только в
SESSIONS.JSON
Пример ссылки внутри контента
link:editor.adoc[Открыть редактор]
или
link:index.adoc[На главную]
Пример содержимого SECURITY.JSON
{
"users": [
{
"email": "user@example.com",
"username": "user",
"passwordHash": "scrypt:...",
"groups": ["demo", "Editor"]
}
],
"groups": [
{
"name": "Editor",
"keys": ["edit"]
},
{
"name": "demo",
"keys": ["demo"]
}
]
}
© Mijail O Silin aka captGreen, 2026