Описание изменений с main (84ce4d1) до develop (afe85f7): локальный режим на SQLite и файловой системе, слой объектов, редактирование фото, новый интерфейс рабочего пространства, видео, Android-клиент, профиль, офлайн, живое обновление, исправления и инструкция по обновлению.
22 KiB
22 KiB
Описание релиза Galo — 21 октября 2026
База релиза: main (84ce4d1, 10 октября 2026) → develop (afe85f7, 21 октября 2026)
Объём: 138 коммитов, 4 спецификации обновлены, 1 изменение реализовано
Коротко о главном
- Локальный режим без внешних сервисов. Слой метаданных переключается на встроенный SQLite, хранилище блобов — на локальную файловую систему. По умолчанию приложение работает полностью на одной машине: без Postgres и без S3.
- Редактирование фотографий в браузере. Вкладка «Редактирование» с инструментом «Свет»: экспозиция, контраст, света, тени, белые и чёрные, тональная кривая по каналам с живой гистограммой. Правки видны сразу, без ожидания сервера.
- Новый интерфейс рабочего пространства. Альбомы с обложками, тёмная, светлая и нейтральная темы, единая система векторных иконок, гало-эмблема и фавикон.
- Нативный Android-клиент. Отдельное приложение: просмотр альбомов, загрузка с устройства, двусторонняя синхронизация с сервером, безопасная разгрузка превью.
- Видео и офлайн. Видео в общих альбомах с фоновой подготовкой и перемоткой; офлайн-кеш оболочки, списков и превью.
Новые возможности
Локальный режим: SQLite и файловая система
- Слой метаданных выбирается конфигурацией: внешний PostgreSQL или встроенный SQLite с тем же поведением для одного экземпляра приложения.
- Хранилище блобов выбирается отдельно: S3-совместимое (Garage) или локальная файловая система. Клиент никогда не видит хранилище — блобы всегда отдаются через бэкенд по подписанному URL.
- По умолчанию (
DB_BACKEND=sqlite,STORAGE_BACKEND=fs) приложение поднимается без Postgres и S3: данные лежат вgalo.dbи каталогеdata/. - Секрет подписи JWT и URL объектов генерируются при первом старте и хранятся в слое метаданных — переживают перезапуск и рестарт SQLite.
- Реконсиляция хранилища с журналом объектов:
make reconcile(отчёт),make reconcile-delete(удаление осиротевших блобов). Сборку мусора ведёт журнал, хранилище не сканируется.
Слой объектов
- Физическое объектное хранилище с непрозрачными ключами: идентификаторы альбомов и фото в ключах не участвуют, сопоставление живёт только в метаданных.
- Журнал объектов: у каждого объекта ровно одна запись с ключом, MIME-типом,
размером, габаритами и состоянием; фото ссылается на объекты по ролям
(
original,thumb,medium,preview,playback,edit,edit_thumb,edit_medium,edit_preview). - Один физический объект может разделяться несколькими фото: перенос и копирование меняют только ссылки, хранилище не трогается.
- Сборка мусора по ссылкам: объект удаляется, когда на него не ссылается ни одно фото и ни один аватар.
Редактирование фотографий
- Вкладка «Редактирование» в правой панели фото, инструмент «Свет»: экспозиция, контраст, света, тени, белые, чёрные.
- Тональная кривая: выбор канала (R/G/B/мастер), точки добавляются кликом по полю графика, перетаскиваются и двигаются стрелками с клавиатуры.
- Гистограмма каналов пересчитывается на лету с учётом текущих правок.
- Блок «Кривая» сворачивается (по умолчанию свёрнут), кнопки выбора канала остаются доступными.
- Предпросмотр правок рисуется в браузере — WASM-модулем на Rust, с резервной JS-реализацией, если модуль недоступен или считает иначе.
- Правки применяются сразу; на сервер уходят через 10 секунд без изменений или при переключении фото. Сервер рендерит отредактированную версию в фоне отдельной очередью и сообщает о готовности.
- Переключатель «Сброс» удаляет и параметры правок, и отредактированную версию.
- Редактирование неразрушающее: оригинал остаётся неизменным, скачивание отдаёт исходник. Рендер идёт по исходному объекту, а не по уменьшенной копии.
Интерфейс рабочего пространства
- Альбомы с обложками, «лайтрумовская» компоновка: рельс альбомов, сетка, единая панель фотографии.
- Три темы — тёмная, светлая, нейтральная — с семантическими токенами; переключатель тем переехал в шапку, нейтральная тема затемнена.
- Единая система иконок: встроенная векторная графика (Material Symbols) вместо эмодзи и символов системного шрифта — иконки наследуют цвет темы и не тянут внешние ресурсы.
- Гало-эмблема (диск солнца в отделённом кольце) и фирменный фавикон: отдаются самим приложением, наследуют тему, читаются в размере 16–24 px.
- Панель сведений о фото со сворачиваемыми секциями и настраиваемым набором атрибутов: состав EXIF хранится в профиле пользователя.
- Полноэкранный просмотр: своя панель, кнопка «на весь экран», возврат по
Esc.
Просмотр и навигация
- Зум колесом мыши (с привязкой к курсору, до 200%), клавишами
+и-;Spaceвозвращает во вписанный вид, а из вписанного — в 100% от оригинала по центру кадра. - В зуме стрелки клавиатуры панорамируют фото, переключение соседних снимков остаётся за мышью и кнопками у краёв.
- Скрытие боковых панелей альбома: кнопка в панели сетки и хоткей
Tab. Панели уезжают за края, содержимое занимает всю ширину, панели возвращаются при наведении на кромку окна. Размер миниатюр при этом сохраняется — в строке помещается больше фото. - Лента миниатюр в просмотре следует за текущим фото; на превью работает наведение- зум.
- Полноэкранный режим приложения по
Ctrl+F, навигация с клавиатуры в сетке с возвратом фокуса, открытие фото тапом на тач-экранах. - Просмотр 360-панорам по тегу
pano360, корректное направление перетаскивания. - Пока грузится оригинал для зума — спиннер; на Android — щипок-зум.
Работа с фотографиями
- Мультивыбор в сетке, контекстные меню, перенос и копирование снимков, корзина на уровне альбома и общие счётчики.
- Теги фото: правки расходятся по сетке и просмотру.
- Переименование фото и удаление из просмотра с подтверждением.
- EXIF извлекается полностью при загрузке; для старых снимков — дозаполнение
(
cmd/backfill-exif).
Офлайн-режим
- Service worker кеширует оболочку приложения, списки и эскизы/превью фотографий: открытые альбомы и ранее загруженные снимки доступны без сети.
- Модуль фильтров в офлайне не кешируется — он всегда подтягивается свежим.
Видео
- Загрузка видео в те же альбомы, что и фото (
kind=video). - Фоновая подготовка: постер (кадр кадра → обычные варианты сетки) и web-совместимый
вариант для воспроизведения (ремукс без перекодирования либо транскод в
h264/yuv420p/aac с
+faststart), с поддержкой перемотки (Range). - Транскод идёт в отдельном малом пуле и не вытесняет генерацию вариантов изображений; готовность транслируется подписчикам альбома.
- Без
ffmpeg/ffprobeприём видео отклоняется,/api/healthсообщает"video": "unavailable", изображения работают как прежде.
Android-клиент
- Отдельный Gradle-модуль, работает с существующим HTTP API, сервер и веб не
трогает. Kotlin + Jetpack Compose,
minSdk 28,targetSdk 35. - Двусторонняя синхронизация альбома устройства с серверным альбомом: загрузки, изменения состава, удаления.
- Безопасная разгрузка: с устройства уходит превью, оригинал остаётся на сервере; потеря серверной копии распознаётся и показывается в интерфейсе.
- Статус синхронизации на карточке альбома, ход восстановления оригиналов, сортировка списка, обновление списка альбомов в реальном времени.
- Установка на устройство одной командой:
make install-android-app(с выбором серийного номера при нескольких подключённых устройствах).
Профиль и учётная запись
- Профиль пользователя: круглый аватар с загрузкой и кадрированием, публичная отдача аватара по версионированной ссылке.
- Вход и регистрация по телефону (E.164) в дополнение к email, управление идентификаторами, удаление аккаунта.
- Предпочтения пользователя (в том числе состав панели сведений) хранятся на сервере.
Альбомы и живое обновление
- Обложки альбомов: отдельный жизненный цикл, обложка доводится до готовности и доставляется подписчикам.
- Живое обновление: события жизненного цикла альбома и изменения состава фото через SSE, подписчики видят изменения без перезагрузки.
- Квадратный вариант
medium— резкие миниатюры в сетке; шаг переключения размера миниатюр и направление ползунка приведены в порядок. - Быстрая загрузка больших альбомов.
Наблюдаемость и эксплуатация
- Настраиваемое логирование:
LOG_LEVEL(debugвключает access-логи и ожидаемые 4xx),LOG_FORMAT(json/text), request id в ответах и логах. scripts/seed.pyиmake testdata— наполнение запущенного инстанса тестовыми данными через публичный API.- Release-сборка:
make build-release— статичный бинарник с вшитой версией и UPX-сжатием, если он установлен.
Исправления
- Копия фото больше не наследует отредактированную версию. Раньше копирование
переносило все привязки объектов, включая
edit*: копия показывала отредактированную картинку, но не наследовала параметры правок, и первая же новая правка перезаписывала обработку с нуля. Теперь правка принадлежит своему фото, а копия показывает исходник. Разовая миграция убирает привязки у копий, созданных до фикса. - Предпросмотр правок работает и без зума, а не только в увеличенном виде.
- Устранено искажение цветов в предпросмотре (WASM-фильтры считались по преобразованным каналам).
- Гистограмма пересчитывается при правке, а не остаётся от исходного снимка.
- Линия тональной кривой видима в тёмной теме.
- Починен зум в просмотре: контейнер прокрутки и центрирование.
- Android: разгруженное превью больше не считается новой версией элемента.
- Сервер отдаёт контрольную сумму оригинала в ответе на загрузку — клиент может сверить файл.
- Счётчик корзины и правки тегов синхронизируются с сеткой и просмотром.
- Ошибка загрузки крупного файла показывается явно, лимит поднят.
make runпересобирает фронтенд, если он изменился.
Технические изменения
API
Новые эндпоинты:
PATCH /api/photos/:id/edit— сохранить параметры правок (тело:{"light": {...}}).DELETE /api/photos/:id/edit— сбросить правки вместе с отредактированной версией.GET|PATCH|DELETE /api/auth/me,POST /api/auth/me/password,POST /api/auth/me/identifiers,PATCH /api/auth/me/preferences,POST|DELETE /api/auth/me/avatar,GET /api/avatars/:userID/:version?size=large.POST /api/photo-batch/copy,POST /api/photo-batch/move— пакетные операции над снимками.
Изменившиеся ответы: у фото появились поля edit_params, edit_url,
edit_thumb_url, edit_medium_url, edit_preview_url; у видео — playback_url.
Схема данных и миграции
- Postgres: миграции до
000016; SQLite: до000008(нумерация диалектов независимая, миграции вшиты в бинарник и применяются автоматически при старте;make migrateприменяет только Postgres). - Новые роли объектов
edit,edit_thumb,edit_medium,edit_preview— рядом с обычнымиoriginal,thumb,medium,preview,playback. - Новая колонка
photos.edit_params— параметры неразрушающих правок.
Сборка
- Фильтры правок считает WASM-модуль из
frontend/wasm/light(Rust,no_std). Пересборка нужна только при правке самого модуля; в репозитории лежит готовыйlight.wasm, поэтому фронтенд собирается без Rust-инструментов. npm run wasm— отдельная пересборка модуля; обычная сборка фронтенда обновляет его сама.
Как обновиться
- Собрать бинарник:
make build(фронтенд →backend/static→go:embed→bin/galo) илиmake build-release— с вшитой версией. - Остановить сервис, заменить бинарник. Фронтенк вшит в бинарник, отдельно выкладывать нечего.
- Запустить: миграции применятся автоматически при старте для выбранного бэкенда.
Для Postgres можно отдельно прогнать
make migrate. - Для видео нужен
ffmpeg/ffprobeна хосте; без них приём видео отключается. - Android-клиент ставится отдельно:
make install-android-app.
Откат: бинарник возвращается предыдущей версии; миграции down не восстанавливают
удалённые привязки копий — это безопасно, отредактированные версии исходных фото
остаются на месте.
Ограничения
- Редактирование — только для изображений; видео не редактируется.
- Правки не порождают отдельной записи в истории: параметры хранятся в метаданных фото, отредактированная версия — как отдельный объект.
- Офлайн-кеш ограничен оболочкой, списками и эскизами/превью: оригиналы для зума и скачивания требуют сети.
- Android-клиент требует JDK 17 и Android SDK (
platforms;android-35,build-tools;35.0.0). - Номер версии берётся из
git describe --tags; в репозитории пока нет тегов, поэтому версия в сборке — короткий SHA илиdev. Для осмысленной нумерации нужен тег.
Для разработчиков
- Спецификации OpenSpec синхронизированы с поведением: обновлены
ui-workspace(редактирование, кривая, зум и навигация),media-objects(ролиedit*, раздельное владение правками, отдельная очередь рендера),photos(рендер по оригиналу),dev-make-workflow(сборка WASM-модуля). - Изменение
fix-copy-edit-variant-sharingреализовано (9/9 задач) и ждёт ревью и архивации:openspec listпоказывает его какcomplete. - Контрактные тесты репозиториев (
internal/repo/contract) гоняют один набор проверок на SQLite и Postgres — новый кейсCloneпроверяет, что копия не наследует отредактированную версию, в обоих хранилищах. - Интеграционные тесты Postgres требуют
TEST_DATABASE_URL; без них они пропускаются. Тесты e2e поднимают SQLite вt.TempDir()и внешних сервисов не требуют. - Сервис переименован в
galo, бренд — «гало»; сборкаmake build-releaseпишетbin/galo-$(VERSION).