• 0.2.0 4cc5c0f340

    0.2.0 Stable

    iu released this 2026-10-23 20:09:06 +00:00 | 0 commits to release/0.2.0 since this release

    Описание релиза Galo — 23 октября 2026

    Версия: 0.2.0
    База релиза: 0.1-alpha (723b19b, 21 октября 2026) → develop (9e39e3d, 23 октября 2026)
    Объём: 6 коммитов, 3 спецификации обновлены, 2 изменения реализованы


    Коротко о главном

    1. Инструмент «Цвет». Баланс белого, вибрация и насыщенность, цветовой
      микшер по восьми диапазонам оттенков, цветокоррекция по зонам яркости и
      общая поканальная коррекция. Предпросмотр считает WebGL2, есть WASM/JS-фолбэк.
    2. Пресеты тоновой кривой. Плавная монотонная кривая (PCHIP), подвижные
      крайние точки и плоские полки. Встроенные и пользовательские пресеты всех
      четырёх каналов хранятся в профиле, импортируются и экспортируются JSON-файлом.
    3. Настройки профиля больше не затирают друг друга. Сохранение сведений о фото
      и пресетов кривой мержится на сервере по разделам.
    4. Исправлено переключение фото в редакторе. Вкладка правой панели сохраняется,
      а несохранённые правки уходят тому фото, для которого сделаны.

    Новые возможности

    Инструмент «Цвет»

    • Баланс белого: температура и оттенок, пипетка по нейтральной точке на фото.
    • Вибрация и насыщенность с раздельными ползунками.
    • Цветовой микшер по восьми диапазонам (красный, оранжевый, жёлтый, зелёный,
      бирюзовый, синий, фиолетовый, пурпурный): тон, насыщенность и яркость каждого
      диапазона.
    • Цветокоррекция по зонам: колёса теней, средних тонов и светов, наложение и
      баланс зон.
    • Поканальная коррекция красного, зелёного и синего каналов.
    • Живой предпросмотр на WebGL2: кадр считает GPU, поэтому изменения видны сразу.
      Если WebGL2 недоступен, используется WASM/JS-фолбэк с тем же результатом.
    • Ползунки с градиентами, цветовые колёса и сброс значения двойным кликом.
    • Порядок операций совпадает в Go-рендере, WASM и JS-предпросмотре; паритет
      закреплён тестами.

    Тоновая кривая и пресеты

    • Плавная кривая: монотонная кубическая интерполяция (PCHIP) вместо прямых
      отрезков — и в SVG-графике, и в LUT для предпросмотра и серверного рендера.
    • Крайние точки (0,0) и (1,1) существуют сразу, двигаются по обеим осям;
      вне крайних точек кривая остаётся плоской. Первый клик по полю вставляет точку
      между крайними.
    • Встроенные пресеты: «Линейный», «Средний контраст», «Сильный контраст».
      Контраст задаётся в RGB, каналы R/G/B остаются линейными.
    • Пользовательские пресеты описывают кривые всех четырёх каналов:
      • сохранение, применение, переименование и удаление;
      • хранение в users.preferences.curve_presets в профиле пользователя;
      • приватность: чужие пресеты не видны;
      • импорт и экспорт JSON { "version": 1, "presets": [...] }, upsert по имени;
      • старый формат одного канала конвертируется при чтении.
    • Подпись показывает активный пресет; при ручной правке любого канала —
      «Пользовательский». Сброс возвращает линейную кривую.

    Настройки профиля

    • PATCH /api/auth/me/preferences теперь мержит разделы, а не заменяет весь
      JSON-объект.
    • Сохранение photo_info не стирает curve_presets, и наоборот.
    • Валидация: не больше 100 пресетов, имя 1..64 символа, 2..16 точек на каждый из
      четырёх каналов, x/y в диапазоне 0..1.
    • Неизвестные разделы настроек сохраняются без изменений.

    Исправления

    • Переключение фото в редакторе. Вкладка правой панели больше не сбрасывается
      на «Сведения». Накопленные правки отправляются фото, для которого сделаны, даже
      если пользователь уже перешёл к следующему.
    • Фоновые сохранения не подменяют текущее фото. Устаревшие ответы сохранения и
      загрузки игнорируются; панель показывает только фото текущего маршрута.
    • Копия фото не наследует отредактированную версию. Копия показывает исходник,
      правка принадлежит своему фото (архивная синхронизация спецификации
      media-objects).
    • Устранены ошибки доступа к photo = null при кратковременной смене фото.

    Технические изменения

    API

    • PATCH /api/auth/me/preferences — мерж известных разделов; в ответе возвращается
      полный объединённый объект.
    • PATCH /api/photos/:id/edit — параметры правок теперь включают блок color и
      тоновую кривую; серверный рендер использует те же LUT, что и предпросмотр.
    • DELETE /api/photos/:id/edit — сброс правок без изменений.

    Данные и миграции

    • Схема БД не менялась: новые настройки лежат в JSON-блобе
      users.preferences; параметры правок — в photos.edit_params.
    • Новые роли объектов и миграции не добавлялись.
    • Старые сохранённые кривые начнут интерполироваться плавно — визуальный результат
      может немного измениться без миграции данных.

    Сборка

    • Обновлён WASM-модуль фильтров (frontend/static/light.wasm).
    • make build-release собирает статический бинарник с вшитой версией и сжимает
      его UPX, если UPX доступен.
    • Версия берётся из git describe --tags; релизный тег — 0.2.0.

    Проверка

    • npm run check — 0 ошибок и предупреждений.
    • npm run test — 54 теста.
    • go test ./... — все пакеты зелёные.
    • E2E: сохранение/сброс цветовых правок, приватность и хранение пресетов кривой.
    • Проверено в браузере: WebGL2-предпросмотр, пипетка, меню пресетов, сохранение
      всех каналов, сохранение вкладки и правок при переключении фото.

    Как обновиться

    1. Собрать релизный бинарник: make build-release (или взять готовый
      bin/galo-0.2.0).
    2. Остановить сервис и заменить бинарник. Фронтенд вшит в бинарник.
    3. Запустить сервис: миграции применяются автоматически при старте для выбранного
      бэкенда. Для этого релиза отдельных миграций нет.
    4. Для видео по-прежнему нужны ffmpeg/ffprobe на хосте.
    5. Android-клиент обновляется отдельно через make install-android-app.

    Откат: вернуть предыдущий бинарник. Схема не менялась, данные правок и профиля
    остаются совместимыми; новые ключи настроек старый бинарник просто игнорирует.


    Ограничения

    • Редактирование цвета и кривой доступно только для изображений; видео не
      редактируется.
    • WebGL2-предпросмотр ускоряет отрисовку, но при его отсутствии используется
      WASM/JS-фолбэк.
    • Пресеты не синхронизируются между пользователями: перенос возможен только через
      экспорт/импорт JSON.
    • Правки не создают отдельной записи в истории: параметры хранятся в метаданных
      фото, отредактированная версия — отдельный объект.
    Downloads
  • 0.1-alpha Pre-Release

    iu released this 2026-10-21 18:29:36 +00:00 | 14 commits to develop since this release

    Описание релиза Galo — 21 октября 2026

    База релиза: main (84ce4d1, 10 октября 2026) → develop (afe85f7, 21 октября 2026)
    Объём: 138 коммитов, 4 спецификации обновлены, 1 изменение реализовано


    Коротко о главном

    1. Локальный режим без внешних сервисов. Слой метаданных переключается на
      встроенный SQLite, хранилище блобов — на локальную файловую систему. По умолчанию
      приложение работает полностью на одной машине: без Postgres и без S3.
    2. Редактирование фотографий в браузере. Вкладка «Редактирование» с инструментом
      «Свет»: экспозиция, контраст, света, тени, белые и чёрные, тональная кривая по
      каналам с живой гистограммой. Правки видны сразу, без ожидания сервера.
    3. Новый интерфейс рабочего пространства. Альбомы с обложками, тёмная, светлая и
      нейтральная темы, единая система векторных иконок, гало-эмблема и фавикон.
    4. Нативный Android-клиент. Отдельное приложение: просмотр альбомов, загрузка с
      устройства, двусторонняя синхронизация с сервером, безопасная разгрузка превью.
    5. Видео и офлайн. Видео в общих альбомах с фоновой подготовкой и перемоткой;
      офлайн-кеш оболочки, списков и превью.

    Новые возможности

    Локальный режим: 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 — отдельная пересборка модуля; обычная сборка фронтенда обновляет
      его сама.

    Как обновиться

    1. Собрать бинарник: make build (фронтенд → backend/static → go:embed → bin/galo)
      или make build-release — с вшитой версией.
    2. Остановить сервис, заменить бинарник. Фронтенк вшит в бинарник, отдельно
      выкладывать нечего.
    3. Запустить: миграции применятся автоматически при старте для выбранного бэкенда.
      Для Postgres можно отдельно прогнать make migrate.
    4. Для видео нужен ffmpeg/ffprobe на хосте; без них приём видео отключается.
    5. 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).
    Downloads