# Правила работы в репозитории evening_detective_server

Дополняют глобальный `~/.dsh/AGENTS.md`. Применяются в любой сессии в этом каталоге.

## Сборка и проверки

- **Кэш сборки**: системный `GOCACHE` (`/home/vladimir/.cache/go-build`) в этом окружении read-only. Всегда запускай Go-команды с локальным кэшем:
  `export GOCACHE=/home/vladimir/projects/evening_detective_server/.gocache`
  (иначе `go build/vet/test` падают с `read-only file system`).
- Стандартный набор проверок после изменений: `gofmt -l cmd/ internal/ api/`, `go build ./...`, `go vet ./...`, `go test -count=1 ./...`; при конкурентности — `go test -race ./...`.
- `go mod tidy` может не отработать (read-only module cache): если не хватает только перевода импортируемого пакета в прямые зависимости — перенеси его в первый require-блок вручную (эквивалентно tidy).

## Прото

- API описано в `api/main.proto`; сгенерированный код — `proto/` и `cmd/evening_detective_server/main.swagger.json`.
- После правки proto обязателен `make generate` (protoc v35.1, плагины в `~/go/bin`), затем `go build ./...`.
- **Конвенция REST — camelCase** (`accessToken`, `actionsCount`). Осознанное исключение: `file_type` в `Application`/`UploadFileRsp` (явный `json_name = "file_type"`, единый snake_case с внутренним JSON истории). Новые поля с явным json_name — только по согласованию.

## Известные факты (не переоткрывать в каждой задаче)

- Файлы хранятся в S3-совместимом RustFS (`file_storage`), URL префиксуются `FILE_PREFIX_DOMAIN` (см. `.env.example`). В БД и JSON истории — относительные имена; префикс добавляется только при чтении (идемпотентно, `prefixDomain`/`mapStory`).
- `string_tools.Transliterate` удаляет ВСЁ кроме `[a-z0-9_]` — включая точку расширения: `Transliterate("photo.png")` → `"photopng"`. Работать с расширением файла — отдельно (split base/ext до транслитерации).
- Улики = `Application { name, image, file_type }` (proto `api/main.proto`, `storytelling.Application`): живут в JSON истории сценария и в таблице `applications` (выданные команде). `file_type`: `image | pdf | audio`, деривируется из расширения через `file_storage.FileType`.
- Загрузка файлов: `POST /api/files/upload` — только роль `Author`, allowlist расширений pdf/jpg/jpeg/png/gif/webp/mp3/ogg/wav, содержимое проверяется sniff'ом (текст/html отклоняется), имя уникализируется `translit(base)_<hex>.<ext>`. Лимит файла 64 МБ: HTTP `maxFileUploadBody`, gRPC `grpcMsgLimit = maxFileSize + 1MiB`, бизнес-проверка в `file_service`.
- Ошибки размера на HTTP-слое мапятся в 413 через `customErrorHandler` (см. `cmd/evening_detective_server/main.go`): ветка `InvalidArgument` + «request body too large» — единственная реальная защита 413 (сгенерированный gateway-код строкифицирует `*http.MaxBytesError` через `%v`).
- Скачивание `GET /api/files/{filename}` — публичное, с `X-Content-Type-Options: nosniff`.

## Процесс ревью (скилл task-execution)

Загружай скилл `task-execution` для нетривиальных задач. Внутри него действуют правила экономии контекста:
- бюджет **3 раунда** на цикл (план/результат), «все замечания одним списком»;
- план/состояние — во внешнем файле (`.dsh/task-plan.md`), промпт ревью — дельта + `git diff`;
- саморевью фактическими проверками до отправки сеньёру (поведение функций на реальных данных, сгенерированный код, арифметика).

## Улучшения вне скоупа (скилл todo-collect)

Если в ходе задачи нашлось улучшение/долг, не мешающее текущей работе — **не чини попутно**: запиши его в локальную папку `todo/` по скиллу `todo-collect` (каждая задача — отдельный файл, шаблон в скилле) и продолжай текущую задачу. Папка в `.gitignore` — это локальный журнал, не коммитится.
