# Правила работы в репозитории 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)_.`. Лимит файла 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` — это локальный журнал, не коммитится.