Если вам понравилась эта статья, то можете поддержать автора, став спонсором на Boosty.
В одной из недавних статей я рассказывал про приложение Booklore — платформу для управления своей web-библиотекой.
При этом в другой своей статье, посвящённой лучшим open-source приложениям 2025 года, я указал это приложение как одно из открытий года.
По странному стечению обстоятельств буквально за пару дней до публикации видеообзора на это приложение автор удалил этот проект.
Что случилось с Booklore: разбор ситуации
Удаление проекта Booklore стало неожиданностью для пользователей, но если разобрать сообщения разработчика и обсуждения в Reddit/GitHub, становится понятна реальная картина.
Позиция разработчика
Автор проекта опубликовал тред на Reddit под названием:
“My side of the story, from the developer of BookLore”
Это была попытка объяснить происходящее, однако ключевую роль сыграла не только его позиция, а скорее реакция пользователей.
Один из показательных комментариев:
“you removed the API docs without notice”
Что это означает по факту:
- изменения вносились без предупреждения;
- нарушалась обратная совместимость.
В итоге страдали пользователи и разработчики интеграций
Конфликт с сообществом
Со временем накопились системные проблемы во взаимодействии с пользователями.
Из основных претензии можно отметить следующие:
- существенные, вплоть до breaking changes, изменения без уведомлений;
- удаление или ломание функциональности;
- слабая на грани отсутствия обратная связь;
В результате возник классический для мира open-source конфликт:
разработчик vs сообщество
Резкое исчезновение проекта
В момент удаления пользователи зафиксировали:
- GitHub-репозиторий стал недоступен (404)
- Discord-сервер исчез
- не было официального объявления
Это выглядело как исключительно эмоциональное решение, своего рода реакция на местами более чем справедливую критику, а потому это было некрасиво по отношению к обычным пользователям, которые не были в курсе происходящего.
Проблемы с форками и лицензией
Дополнительным фактором стали споры вокруг лицензии (AGPL-3.0).
Что происходило:
- появились форки проекта (например, Grimmory, герой сегодняшней статьи)
- обсуждались возможные нарушения лицензии
- возникли конфликты вокруг использования кода
Последнее - вообще нередкий случай, долстаточно посмотреть на ситуацию вокруг OnlyOffice и Nextcloud.
Накалпивающиеся негатив вокруг проекта
Ещё до удаления наблюдались тревожные сигналы:
- баги
- обсуждения “стоит ли использовать Booklore”
- критика архитектурных решений
- вопросы к telemetry. Да, тут тоже были вопросы.
То есть проект уже находился под давлением со стороны пользователей.
Итог: проект был удалён
Фактически к удалению Booklore привела не какая-то одна причина, а целая цепочка событий:
Главный вывод
В данном случае это не обычная история про “разработчик устал”, как недавно произошло с очень хорошим проектом Palmr.
Скорее речь идёт о плохой коммуникации → конфликте → токсичной среде → резком удалении проекта.
Ваш покорный слуга об этом ничего не знал и спокойно опубликовал видео про этот проект на разных видеоплощадках. Мне, конечно, написали в комментариях о том, что я неправ, проект уже мёртв, а видео неактуально. Ну ладно, у меня нет конфликта с сообществом, поэтому вот вам замена. Как я указал выше, оригинальный проект Booklore был быстро форкнут сообществом. Так как оригинальный Booklore публиковался под лицензией AGPL, то проект Grimmory — это фактически один в один перелицованный Booklore, но с новым названием. Если посмотреть файлы конфигурации, то в оригинальном docker-compose файле до сих пор фигурирует переменная booklore. В любом случае, так как получилась ситуация, в которой я опубликовал уже на дату публикации неактуальную статью, исправляюсь.
Ниже привожу рабочий вариант docker-compose файла и файла окружения
1services: # Секция описания сервисов (контейнеров)2
3 booklore: # Имя сервиса BookLore4 image: grimmory/grimmory:latest # Docker-образ BookLore из Docker Hub (тег latest)5 # image: ghcr.io/booklore-app/booklore:latest6 # Альтернативный образ из GitHub Container Registry (закомментирован)7 container_name: grimmory # Явное имя контейнера в Docker8 environment: # Переменные окружения контейнера9 - USER_ID=${APP_USER_ID} # UID пользователя для работы контейнера (права на файлы)10 - GROUP_ID=${APP_GROUP_ID} # GID группы для файлов и каталогов11 - TZ=${TZ} # Часовой пояс контейнера12 - DATABASE_URL=${DATABASE_URL} # URL подключения к базе данных MariaDB13 - DATABASE_USERNAME=${DB_USER} # Имя пользователя базы данных14 - DATABASE_PASSWORD=${DB_PASSWORD} # Пароль пользователя базы данных15 - BOOKLORE_PORT=${BOOKLORE_PORT} # Внутренний порт BookLore16 depends_on: # Зависимости сервиса17 mariadb: # Зависимость от сервиса mariadb18 condition: service_healthy # Запуск только после успешного healthcheck БД19 ports:20 - "${BOOKLORE_PORT}:${BOOKLORE_PORT}" # Проброс порта: host → container (обычно не нужен при использовании Traefik)21 volumes:22 - ./data:/app/data # Данные приложения BookLore23 - ./books:/books # Каталог с библиотекой книг24 - ./bookdrop:/bookdrop # Папка для автоматического импорта книг25 healthcheck: # Проверка работоспособности контейнера26 test: wget -q -O - http://localhost:${BOOKLORE_PORT}/api/v1/healthcheck27 # HTTP-запрос к встроенному healthcheck API BookLore28 interval: 60s # Интервал между проверками29 retries: 5 # Количество попыток до признания контейнера unhealthy30 start_period: 60s # Время ожидания перед началом проверок31 timeout: 10s # Таймаут одной проверки32 restart: unless-stopped # Автоперезапуск контейнера (кроме ручной остановки)33 networks:34 proxy: # Подключение к внешней сети proxy (Traefik)35 labels: # Метки Docker для интеграции с Traefik36 - "traefik.enable=true" # Включаем обработку контейнера Traefik37 - "traefik.http.routers.grimmory.entrypoints=web" # HTTP-вход (порт 80)38 - "traefik.http.routers.grimmory.rule=Host(`grimmory.stilicho.ru`)" # Направляем трафик с домена booklore.stilicho.ru в этот контейнер39 - "traefik.http.middlewares.grimmory-https-redirect.redirectscheme.scheme=https" # Middleware для редиректа HTTP → HTTPS40 - "traefik.http.routers.grimmory.middlewares=grimmory-https-redirect" # Применяем middleware редиректа к HTTP-маршруту41 - "traefik.http.routers.grimmory-secure.entrypoints=websecure" # HTTPS-вход (порт 443)42 - "traefik.http.routers.grimmory-secure.rule=Host(`grimmory.stilicho.ru`)" # HTTPS-маршрут для того же домена43 - "traefik.http.routers.grimmory-secure.tls=true" # Включаем TLS (HTTPS)44 - "traefik.http.routers.grimmory-secure.service=grimmory" # Привязываем HTTPS-роутер к сервису booklore45 - "traefik.http.services.grimmory.loadbalancer.server.port=6060" # Внутренний порт BookLore внутри контейнера46 - "traefik.docker.network=proxy" # Указываем Traefik, в какой Docker-сети искать контейнер47#48 mariadb: # Сервис базы данных MariaDB49 image: lscr.io/linuxserver/mariadb:11.4.550 # Образ MariaDB от LinuxServer.io (стабильный и удобный)51 container_name: mariadb # Явное имя контейнера52 environment: # Переменные окружения MariaDB53 - PUID=${DB_USER_ID} # UID владельца файлов БД54 - PGID=${DB_GROUP_ID} # GID владельца файлов БД55 - TZ=${TZ} # Часовой пояс56 - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} # Пароль root-пользователя БД57 - MYSQL_DATABASE=${MYSQL_DATABASE} # Имя базы данных, создаваемой при первом запуске58 - MYSQL_USER=${DB_USER} # Пользователь БД59 - MYSQL_PASSWORD=${DB_PASSWORD} # Пароль пользователя БД60 volumes:61 - ./mariadb/config:/config # Каталог с данными и конфигурацией MariaDB62 restart: unless-stopped # Автоперезапуск контейнера63 healthcheck: # Проверка доступности БД64 test: [ "CMD", "mariadb-admin", "ping", "-h", "localhost" ]65 interval: 5s # Интервал проверки66 timeout: 5s # Таймаут проверки67 retries: 10 # Количество попыток68 networks:69 proxy: # Подключение к сети proxy (Traefik)70
71networks:72 proxy: # Определение сети proxy73 external: true # Сеть уже существует и не создаётся Docker самостоятельноФайл с окружением
1# =========================================================2# 🎯 BookLore — основные настройки приложения3# =========================================================4
5APP_USER_ID=10006# UID пользователя на хосте, от имени которого7# BookLore будет работать внутри контейнера.8# Нужен для корректных прав доступа к volume.9APP_GROUP_ID=100010# GID группы на хосте.11# Должен совпадать с владельцем каталогов data / books / bookdrop.12TZ=Europe/Moscow13# Часовой пояс контейнеров.14# Используется для логов, планировщиков и временных меток.15BOOKLORE_PORT=606016# Порт, на котором BookLore слушает внутри контейнера.17# Также используется Traefik как внутренний порт сервиса.18# =========================================================19# 🗄️ Подключение BookLore к базе данных MariaDB20# =========================================================21DATABASE_URL=jdbc:mariadb://mariadb:3306/grimmory22# JDBC-строка подключения к MariaDB:23# - mariadb → имя сервиса в docker-compose24# - 3306 → стандартный порт MariaDB25# - grimmory → имя базы данных26DB_USER=grimmory27# Пользователь базы данных,28# под которым BookLore подключается к MariaDB.29DB_PASSWORD=ChangeMe_BookLoreApp_2025!30# Пароль пользователя базы данных.31# ⚠️ ОБЯЗАТЕЛЬНО сменить в продакшене.32# =========================================================33# 🔧 Настройки контейнера MariaDB (инициализация)34# =========================================================35DB_USER_ID=100036# UID пользователя, от имени которого37# MariaDB пишет данные в volume.38DB_GROUP_ID=100039# GID группы для файлов базы данных.40MYSQL_ROOT_PASSWORD=ChangeMe_MariaDBRoot_2025!41# Пароль root-пользователя MariaDB.42# Используется только для администрирования БД.43MYSQL_DATABASE=grimmory44# Имя базы данных, которая будет автоматически45# создана при первом запуске контейнера MariaDB.Some information may be outdated