Files
ds-galo/AGENTS.md
T
iu 863038b5a0 chore: добавить AGENTS.md с инструкциями для агентов
Правила работы в репозитории: команды, архитектура, миграции, конфигурация,
фронтенд, OpenSpec и конвенции коммитов. Отдельный раздел про прогоны с
эмулятором: instrumented-тесты и запуск AVD могут зависнуть, прогресс нужно
проверять примерно раз в минуту, а не ждать молча.
2026-10-16 13:28:03 +03:00

127 lines
9.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AGENTS.md
Инструкции для агентов, работающих в этом репозитории. Читай вместе с `README.md`
(актуальный источник правды) и `project.md` (исходное ТЗ).
## Что это
Self-hosted фотоальбом: Go-бэкенд с вшитой через `go:embed` статикой SvelteKit,
один статический бинарник (`CGO_ENABLED=0`), без Docker. Плюс отдельный Android-клиент.
По умолчанию (`DB_BACKEND=sqlite`, `STORAGE_BACKEND=fs`) работает полностью локально,
без Postgres и S3. Postgres/Garage (`pg.localnet`, `s3.localnet`) — опциональные слои.
## Команды
Все команды — из корня репозитория. Голый `make` только печатает список целей.
```bash
make build # frontend -> backend/static -> go:embed -> bin/galo
make frontend # npm run build (инкрементально), копирует статику в backend/static
make backend # CGO_ENABLED=0 go build -tags nodynamic -o ../bin/galo
make run # frontend + backend + запуск ./bin/galo
make migrate # применяет только Postgres-миграции (cmd/migrate)
make test # cd backend && go test ./... (только бэкенд!)
make testdata # наполняет запущенный инстанс через scripts/seed.py
make android # cd android && ./gradlew :app:assembleDebug
make install-android-app # сборка + установка debug-APK на устройство
```
- `-tags nodynamic` обязателен: без него `gen2brain/webp` тянет динамический libwebp
и бинарник перестаёт быть статическим.
- Порядок сборки важен: `frontend` должен отработать до `backend`, иначе `go:embed
all:static` вшивает только `backend/static/.gitkeep` и бинарник выходит без UI.
- `make test` не запускает фронтенд-тесты; отдельных make-целей для них нет:
`cd frontend && npm run test` (vitest, окружение `node`, файлы `src/**/*.test.ts`) и
`cd frontend && npm run check` (svelte-check/typecheck).
- Один Go-тест: `cd backend && go test ./internal/photos/ -run TestName -v`.
- Интеграционные тесты Postgres-репозиториев пропускаются без `TEST_DATABASE_URL`:
`TEST_DATABASE_URL='postgres://user:pass@pg.localnet:5432/galo?sslmode=disable' \
cd backend && go test ./internal/repo/ -v`
- Тесты видео (`internal/e2e`) сами пропускаются, если нет `ffmpeg`/`ffprobe`.
Тесты e2e репозиториев поднимают SQLite в `t.TempDir()` и внешних сервисов не требуют.
## Тесты на эмуляторе
Instrumented-прогоны (`:app:connectedDebugAndroidTest`) и сам запуск AVD **могут зависнуть** —
не дожидайся их молча. Пока идёт прогон, проверяй прогресс **примерно раз в минуту**: жив ли
процесс, обновляются ли результаты, отвечает ли устройство:
```bash
pgrep -fa "GradleWrapperMain|Gradle Test Executor"
ls -la android/app/build/outputs/androidTest-results/connected/debug/
adb devices
```
Если прогресса нет дольше пары минут — снимай прогон (`kill`), а не жди дальше, и разбирайся
по дампу потоков (`jstack <pid>` JVM тестов). То же относится к обычным unit-тестам: они тоже
идут в отдельной JVM, и её зависание видно только по тому, что результаты перестали
обновляться.
## Архитектура
- Go-модуль `galo` (`backend/go.mod`, Go 1.26). Точки входа: `backend/cmd/server`,
`cmd/migrate`, `cmd/reconcile`, `cmd/backfill-exif`.
- Доменные пакеты в `backend/internal/<domain>` (albums, auth, members, photos, social,
notifications, sharelinks, storage, sse, settings, video). Каждый содержит сервис,
HTTP-обработчики и `Repository`-интерфейс.
- `internal/store/store.go` — единственное место, которое знает конкретные реализации.
При добавлении метода в `Repository` нужно реализовать его в **обоих** вариантах:
Postgres (`NewStore/NewPostgres`) и SQLite (`NewSQLiteStore/NewSQLite`).
- `backend/internal/app` — маршруты/статика; `internal/repo/contract` — контрактные тесты,
которые гоняют одинаковый набор проверок для SQLite и Postgres.
- `backend/embed.go` вшивает `static` (фронтенд) и `migrations/**`. Паттерны эмбеда —
`migrations/*.sql migrations/sqlite/*.sql`: новые файлы должны им соответствовать.
- Права проверяются на уровне сервиса, не только в UI. Блобы наружу отдаются только
через бэкенд: `GET /api/objects/<key>` с HMAC-подписью, один маршрут для авторизованных
и для share-ссылок. Ключи объектов непрозрачны: `objects/{object_id}/{role}`.
- SSE (`/api/sse/...`) авторизуется через `?token=`, т.к. `EventSource` не шлёт заголовки.
Для nginx критичен `proxy_buffering off`.
- `android/` — самостоятельный Gradle-модуль, серверный и веб-код не трогает; использует
уже существующий HTTP API. Тесты: `cd android && ./gradlew test`.
## Миграции (частый источник ошибок)
Схема поддерживается в **двух диалектах** с независимой нумерацией:
- Postgres: `backend/migrations/NNNNNN_*.{up,down}.sql`
- SQLite: `backend/migrations/sqlite/NNNNNN_*.{up,down}.sql`
Любое изменение схемы нужно добавить в оба каталога, номера версий не обязаны совпадать
(сейчас они разошлись). Миграции вшиты в бинарник и применяются автоматически при старте
сервера для выбранного бэкенда. `make migrate` применяет только Postgres.
`cmd/reconcile` существует для сверки хранилища с журналом `objects` (сборка мусора
журналом управляется и хранилище не сканирует).
## Конфигурация и данные
- `.env` читается вручную в `cmd/*/main.go` из `.env`, затем `../.env` (без dotenv-библиотеки).
- Секреты подписи JWT и URL объектов не задаются в env: генерируются при первом старте и
лежат в слое метаданных (`app_settings`), поэтому переживают перезапуск и рестарт SQLite.
- Локальные артефакты в корне (`galo.db*`, `/data/`, `bin/`, `backend/static/*`,
`frontend/build/`) в git не попадают — не коммить их.
## Фронтенд
- SvelteKit 2 + Svelte 5 (runes), `adapter-static` с `fallback: index.html`, Tailwind v4.
- Тёмная/светлая/нейтральная темы через `data-theme` на `<html>` и семантические
CSS-токены. В компонентах — только семантические классы (`bg-bg-elevated`, `text-muted`
и т.п.), **никаких `dark:` префиксов**.
- Vite dev-сервер проксирует `/api` на `localhost:8080` (см. `vite.config.ts`).
## OpenSpec
Спецификации — в `openspec/specs/<capability>/spec.md`; завершённые изменения —
в `openspec/changes/archive/<YYYY-MM-DD-name>`. Активных изменений сейчас нет.
Workflow-команды и скиллы лежат в `.opencode/` и требуют CLI `openspec`
(в этом окружении он может быть не установлен — проверь `command -v openspec`).
При изменении поведения сначала обновляй/создавай спеку, а не только код.
## Конвенции репозитория
- Ветка `develop`; коммиты — Conventional Commits с русским описанием
(`feat(realtime): ...`, `test(android): ...`, `chore: ...`). Функциональные ветки
вливаются в `develop` через merge-коммиты.
- `project.md` — исходное ТЗ и местами устарел (например, называет S3 бэкендом по
умолчанию и старую раскладку ключей `albums/...`). Ориентируйся на `README.md` и код.