BOOK-LIBRARY и Quartz
Эта заметка — про границу между двумя частями одного проекта. BOOK-LIBRARY отвечает за рабочую библиотеку: книги, обложки, категории, переводы, админские задачи и временные ссылки на скачивание. Quartz отвечает за публичный слой: заметки, проектные страницы, подборки и навигацию вокруг материалов.
Интеграция нужна не для того, чтобы превратить сайт в зеркало файлового каталога. Идея спокойнее и полезнее: дать читателю понятную витрину библиотеки внутри сайта, но оставить управление файлами там, где оно уже устроено как библиотечная система.
Такое разделение важно. Если просто скопировать книги в статический сайт, быстро появятся проблемы: где обновлять метаданные, как отзывать файл, что делать с обложками, как не публиковать черновые переводы и как не смешивать заметки с файловым архивом. Поэтому интеграция сделана аккуратнее: Quartz показывает материалы в контексте, а BOOK-LIBRARY продолжает управлять тем, что именно доступно читателю.
Что уже есть на стороне Quartz
В Quartz уже есть несколько частей, связанных с библиотекой:
content/library.md;quartz/components/LibraryPage.tsx;quartz/components/scripts/libraryPage.inline.ts;quartz/static/data/bookshelf.json;- generated catalog
quartz/static/generated/bookshelf-catalog.json; - mirrored covers через
quartz/util/bookshelfCatalog.ts.
Вместе эти элементы делают библиотеку видимой на сайте: читатель видит отобранный каталог и обложки рядом с заметками, а Quartz при этом не превращается в backend для книг.
Public API вместо прямого доступа к файлам
BOOK-LIBRARY отдаёт публичные данные через public API. Для Quartz это правильная граница: сайту нужны карточки, категории и обложки, но ему не нужно знать внутреннее устройство uploads или SQLite.
Для читателя это выглядит просто: на статическом сайте появляется понятная карточка книги и путь к материалу. Для системы граница остаётся строгой: файлы книг остаются за backend. Скачивание проходит через temp-token flow — сначала запрашивается временная ссылка, потом backend отдаёт файл по token. Это сохраняет контроль на стороне библиотеки и не раскрывает постоянные URL на книги.
Quartz в этой схеме не становится посредником скачивания. Он может быть витриной, навигацией и контекстом, но не файловым сервером.
Static catalog и live API
На странице библиотеки клиентский скрипт сначала пытается работать с живым API BOOK-LIBRARY. Он загружает категории из /api/categories, а книги категории — из /api/categories/:id/books с limit и offset. Так витрина может показывать актуальные публичные данные, когда backend доступен.
Если live API недоступен, включается static fallback. Скрипт читает catalogPath из bookshelf.json, загружает bookshelf-catalog.json и берёт категории и книги оттуда. Для читателя это важная деталь: Quartz не превращается в хрупкую страницу, которая ломается при каждом сбое backend или cross-origin-запроса, а остаётся полезной статической витриной.
В текущем конфиге:
{
"backendBaseUrl": "https://book.slavx.ru",
"catalogPath": "/static/generated/bookshelf-catalog.json",
"previewDescriptionLength": 260
}Rails, hover preview и modal
LibraryPage показывает книги не обычным списком, а как полку. Каждая категория становится горизонтальным rail: читатель пролистывает обложки, а на десктопе может навести курсор и увидеть hover preview с названием, автором, форматом и коротким описанием.
Клик по книге открывает modal. В нём показываются обложка, категория, номер, формат, автор и полное описание. Если обложка не загрузилась, интерфейс показывает fallback с первой буквой названия. Это небольшая деталь, но она поддерживает ощущение аккуратной витрины: вместо пустого битого image-box читатель всё равно видит понятную карточку.
Build-time generation
generateBookshelfStaticAssets в bookshelfCatalog.ts делает эту витрину устойчивой ещё на build-time: ходит в BOOK-LIBRARY, получает категории, проходит по книгам, скачивает обложки и записывает:
- JSON-каталог в
quartz/static/generated/bookshelf-catalog.json; - mirrored covers в
quartz/static/generated/book-library-covers.
Это удобно для статического fallback, но важно не перепутать роли. Generated-файлы — не ручной источник истины, а снимок публичной части библиотеки на момент сборки. Если в generated JSON что-то «поправить руками», следующая сборка может перезаписать изменение.
Mirrored covers
Обложки можно зеркалировать в Quartz как статические файлы. Это удобно для карточек: сайт не зависит от внешних URL обложек и может показывать изображения рядом с заметками.
Но mirrored covers — это не перенос всей библиотеки. Обложка помогает читателю узнать книгу и связать её с заметкой, а файл книги остаётся в BOOK-LIBRARY. Такое разделение хорошо ложится на формат сайта: Quartz показывает контекст, BOOK-LIBRARY обслуживает библиотечные операции.
CORS, CORP и public origins
Для такой интеграции важны не только данные, но и браузерные границы. В BOOK-LIBRARY разделены public и admin origins. Публичная часть может быть доступна Quartz-сайту, а админские API не должны случайно открываться тем же способом.
Для обложек используется public CORP. Это помогает корректно показывать изображения в публичных контекстах и не смешивать правила доступа к covers с правилами доступа к admin API.
Здесь нет цели сделать сложную security-схему ради самой схемы. Смысл проще: Quartz получает только то, что должно быть публичным, а операции управления остаются в React-админке BOOK-LIBRARY.
Чем это отличается от прямой публикации книг
Прямая публикация книг на Quartz выглядела бы проще технически: положить файлы в static-директорию и дать ссылки. На первый взгляд это самый короткий путь, но для этого проекта такой вариант хуже.
Он ломает несколько важных границ:
- скачивание перестаёт идти через временные токены;
- сложнее скрывать черновые или снятые с публикации переводы;
- Quartz-репозиторий начинает разрастаться файлами книг;
- админка теряет контроль над тем, что реально доступно читателю;
- становится труднее поддерживать одну версию карточки и обложки.
Поэтому Quartz лучше использовать как витрину и навигационный слой. Он помогает объяснить, зачем материал здесь, с какими заметками он связан и почему его стоит открыть. А сами файлы, import jobs, translation jobs и публикация artifacts должны оставаться в BOOK-LIBRARY.
Curated-подборки вместо полного зеркала
Самый полезный следующий шаг — не показывать весь каталог подряд, а делать curated-подборки. Например: книги по теме проекта, подборка по разработке, художественная полка, книги рядом с конкретной заметкой.
Такой формат хорошо подходит Quartz. Статический сайт силён не тем, что хранит всё, а тем, что связывает материалы между собой. Подборка может содержать короткий комментарий, ссылку на заметку, обложку, автора и путь к карточке книги. Тогда читатель попадает не в безличный архив, а в маленький маршрут по теме.
Markdown-карточки и обратные ссылки
Для отдельных книг можно генерировать Markdown-карточки. Не обязательно для всей библиотеки — только для тех записей, которые действительно нужны на сайте.
Возможная карточка может содержать:
- название и автора;
- категорию или подборку;
- короткое описание;
- обложку;
- связь с заметками на сайте;
- ссылку на карточку или скачивание через BOOK-LIBRARY.
Интереснее всего здесь обратные ссылки. Если по книге есть заметка, обзор или конспект, Quartz может вести к книге, а BOOK-LIBRARY — обратно к заметке. Тогда библиотека перестаёт быть отдельным складом файлов и становится частью личной базы знаний: книга, карточка и мысль из заметки оказываются рядом.
Где проходит граница
После всех деталей граница получается простой:
- BOOK-LIBRARY хранит книги, метаданные, обложки, переводы, jobs и download flow;
- React-админка управляет импортом, переводами, провайдерами и безопасностью;
- публичная витрина BOOK-LIBRARY может показывать живой каталог;
- Quartz показывает отобранный статический слой: подборки, карточки, заметки, rails и mirrored covers.
Такое разделение спокойнее, чем попытка сделать один инструмент для всего. Quartz остаётся хорошим сайтом для текста, связей и публичных подборок. BOOK-LIBRARY остаётся рабочей библиотечной системой, где управляются файлы, публикация и операции вокруг книг.
Связанные заметки
- Обзор и сценарии — где Quartz находится среди пользовательских сценариев.
- Архитектура — почему backend остаётся источником истины для файлов и токенов.
- Roadmap — какие шаги по Quartz-интеграции стоит развивать дальше.
- Книжная полка в Quartz — подробный разбор стороны Quartz.