From 723b19bbe58ba5ef4b63419251260b3d2f428b3e Mon Sep 17 00:00:00 2001 From: Iu Date: Wed, 21 Oct 2026 21:15:59 +0300 Subject: [PATCH] =?UTF-8?q?docs:=20=D0=BE=D0=BF=D0=B8=D1=81=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D1=80=D0=B5=D0=BB=D0=B8=D0=B7=D0=B0=20Galo=20?= =?UTF-8?q?=D0=B7=D0=B0=2021=20=D0=BE=D0=BA=D1=82=D1=8F=D0=B1=D1=80=D1=8F?= =?UTF-8?q?=202026?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Описание изменений с main (84ce4d1) до develop (afe85f7): локальный режим на SQLite и файловой системе, слой объектов, редактирование фото, новый интерфейс рабочего пространства, видео, Android-клиент, профиль, офлайн, живое обновление, исправления и инструкция по обновлению. --- .../2026-10-21-описание-релиза.md | 280 ++++++++++++++++++ 1 file changed, 280 insertions(+) create mode 100644 Отчёты об изменениях/2026-10-21-описание-релиза.md diff --git a/Отчёты об изменениях/2026-10-21-описание-релиза.md b/Отчёты об изменениях/2026-10-21-описание-релиза.md new file mode 100644 index 0000000..1f2ef63 --- /dev/null +++ b/Отчёты об изменениях/2026-10-21-описание-релиза.md @@ -0,0 +1,280 @@ +# Описание релиза 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)`.