BOOK-LIBRARY: React-админка и операционный центр

React-админка в BOOK-LIBRARY появилась не ради смены стека и не как отдельная «панель ради панели». В раннем варианте админские экраны жили рядом с публичной SvelteKit-витриной, но со временем стало понятно: человек, который ведёт библиотеку, работает совсем в другом режиме, чем читатель. Читателю нужен каталог и понятный путь к книге. Администратору нужно видеть очереди, статусы, ошибки, внешний поиск, переводы, провайдеров и настройки безопасности.

Поэтому старая Svelte-admin часть удалена, а целевая админка вынесена в отдельное React-приложение. Публичная витрина остаётся спокойной страницей библиотеки, а React становится операционным центром — местом, где каталог не просто показывают, а поддерживают в рабочем состоянии.

Почему отдельная админка

У админки другой ритм работы. В ней нужно не просто нажать «добавить книгу», а понять, что происходит с системой прямо сейчас:

  • какие задачи сейчас выполняются;
  • какие импорты завершились ошибкой;
  • где есть дубли или спорные категории;
  • какие переводы ждут проверки;
  • какой LLM-провайдер используется;
  • всё ли в порядке с доступом и паролем.

Если смешивать это с публичной витриной, интерфейс быстро становится шумным: читателю начинают мешать служебные детали, а администратору — ограничения публичной страницы. Отдельная React-админка держит операционные сценарии в одном месте и не усложняет читательскую часть.

Dashboard и operations

Dashboard нужен как короткий обзор состояния библиотеки. Это не декоративная главная страница, а вход в работу: быстро понять, где всё спокойно, где импорт требует внимания, какие переводы идут дальше и какие настройки могут повлиять на следующие операции.

Operations-слой связан с durable jobs. Одиночный импорт, batch ZIP, Anna’s Archive, Flibusta и LLM-переводы не должны зависеть от одного длинного HTTP-запроса. Backend создаёт задачу, хранит её состояние, а админка показывает прогресс через polling.

Для администратора это меняет поведение интерфейса. Вместо ощущения, что форма зависла где-то между загрузкой файла и появлением карточки, он видит queued, running, failed, cancelled или completed. Если задача упала, можно разобрать причину и повторить отдельный этап, не превращая каждую ошибку в ручное расследование с нуля.

Durable import queue

Очередь импорта — один из главных операционных узлов. Через неё проходят:

  • одиночные загрузки файлов;
  • batch ZIP;
  • импорт найденных книг из внешних источников;
  • повтор неудачных операций;
  • отчёты по skipped, failed и possible duplicates.

Такой подход особенно полезен при больших коллекциях. Импорт — это не одна функция, а цепочка решений: принять файл, извлечь метаданные, подобрать категорию, проверить дубль, найти обложку, сохранить карточку. Очередь делает эту цепочку видимой, а значит управляемой: понятно, на каком шаге книга застряла и что с ней делать дальше.

SearchPage: Anna’s Archive и Flibusta

Отдельная страница поиска объединяет Anna’s Archive и Flibusta. Это удобнее, чем держать два разрозненных сценария и каждый раз заново вспоминать, откуда брать нужное издание. Администратор вводит запрос, сравнивает найденные варианты и запускает импорт выбранной книги.

Внешний поиск не считается источником истины. У результата может быть неверное описание, не та обложка или несколько похожих изданий. Поэтому SearchPage важен не как кнопка «автоматически скачать всё», а как точка принятия решения: посмотреть candidates, выбрать подходящий вариант и запустить контролируемый import job.

Переводы в админке

LLM-переводы требуют отдельного интерфейса, потому что это уже не простое поле «перевести описание». Перевод книги — долгий pipeline: подготовка canonical document, segmentation, batch translation, QA findings, assembly, artifacts и publish/unpublish.

В админке нужно видеть:

  • список translation jobs;
  • текущий этап задачи;
  • ошибки провайдера или сегмента;
  • сегменты, которые требуют ручной проверки;
  • QA findings;
  • готовые EPUB/PDF artifacts;
  • состояние публикации.

Публичная витрина показывает только published translations. Всё, что требует проверки, остаётся в админке, чтобы читатель видел аккуратный результат, а не внутреннюю кухню длинного процесса.

Settings, providers и security

LLM providers стали runtime-настройками в SQLite. Их можно включать, выключать, менять priority и использовать fallback. Это важно для переводов и метаданных: один provider может быть дорогим, нестабильным или временно недоступным, а работу библиотеки всё равно нужно продолжать без правки кода.

Security-настройки тоже вынесены ближе к администратору. В проекте есть SQLite-backed sessions, admin_users, смена пароля и emergency env override. State-changing admin API закрыты CSRF-защитой, а CORS разделён для публичных и admin origins.

Это не заменяет нормальную инфраструктурную дисциплину, но убирает раннюю прототипную слабость, когда админский доступ держится только на одном значении из окружения и плохо подходит для реального рабочего места.

Proxy и hosted admin bundle

Backend может обслуживать production-hosted bundle React-админки. Это удобно для операционной части: backend и админка выкатываются вместе, поэтому рабочий инструмент администратора остаётся рядом с API и задачами, которыми он управляет. Публичная SvelteKit-витрина при этом может разворачиваться отдельно, если она нужна как самостоятельная поверхность.

Такое разделение не мешает Quartz-интеграции. Quartz может показывать отобранный каталог, но не становится местом управления книгами. Все операции импорта, переводов, провайдеров и скачивания остаются в BOOK-LIBRARY.

Визуальный подход

React-админка использует shadcn/ui-подход и тёмную нейтральную палитру. Это подходит задаче: интерфейс должен быть спокойным, плотным и читаемым, без лишней декоративности. В админке важнее быстро понять состояние задачи, чем впечатлить анимацией.

Хорошая админка в таком проекте — это не «красивый dashboard ради dashboard». Это место, где видно, что было импортировано, что сломалось, что требует ручной проверки и что уже можно показать читателю. Именно поэтому React-часть здесь важна не сама по себе, а как рабочая поверхность для человека, который каждый день удерживает каталог в порядке.

Связанные заметки