chore: добавить AGENTS.md с инструкциями для агентов
Правила работы в репозитории: команды, архитектура, миграции, конфигурация, фронтенд, OpenSpec и конвенции коммитов. Отдельный раздел про прогоны с эмулятором: instrumented-тесты и запуск AVD могут зависнуть, прогресс нужно проверять примерно раз в минуту, а не ждать молча.
This commit is contained in:
@@ -0,0 +1,126 @@
|
|||||||
|
# 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` и код.
|
||||||
Reference in New Issue
Block a user