Files
transcriber/CLAUDE.md
T
av a4646c0930 Инструкции для Claude, конфиг линтера, актуализация README
CLAUDE.md описывает конвейер задач, подвохи конфига и правило про четыре
списка колонок в репозитории sqlite.

.golangci.yml включает стандартный набор плюс errorlint; осознанные
непроверенные вызовы вынесены в исключения.

README приведён к коду: эндпоинты /api/audio и /api/status/:id, состояния
задач, структура internal/, фактические колонки таблиц.
2026-08-10 20:24:30 +03:00

100 lines
5.9 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.
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Проект и общение по нему ведём по-русски.
## Что это
Сервис расшифровки аудио. Два входа — Telegram-бот и HTTP API, один общий конвейер
обработки. Распознавание асинхронное, через Yandex SpeechKit; файл едет в Yandex
Object Storage, оттуда его забирает SpeechKit.
## Команды
```bash
go build ./... # нужен CGO: mattn/go-sqlite3
go test ./...
go vet ./...
gofmt -l .
golangci-lint run
go run . -c config.toml # флаг -c или --config, по умолчанию config.toml
task image # docker-образ, тег из $BUILD_ID (по умолчанию dev)
```
`golangci-lint run` на чистом `master` даёт 4 замечания в существующем коде (два
непроверенных `Close`, два сравнения ошибок через приведение типа вместо
`errors.As`). Их пока не чинили — новые замечания отличай от этих.
Деплой запускается не отсюда, а из `pet-project-server`: `inv pl -- transcriber`.
Плейбук сам зовёт `task image` по контракту роли `app_image`, образ едет на сервер
через `docker save`/`load`, реестр не участвует.
`lefthook` на pre-commit гоняет `gitleaks git --staged`.
## Конфиг
`config.toml` в gitignore, образец — `config.dist.toml`. Разбирается в
`internal/config`; значения по умолчанию заданы в `defaultConfig()`, файл их
перекрывает. Правишь поле — правь оба места.
Два подвоха:
- Ключ белого списка пользователей Telegram называется `users_while_list` (опечатка
в теге toml), лежит в секции `[server]`, и в `config.dist.toml` его нет вообще.
Без него бот отвечает отказом всем.
- Список сверяется с `update.Message.From.String()` из tgbotapi — это `@username`
либо имя с фамилией, а не числовой id.
## Конвейер задач
Состояния `TranscribeJob`: `created``converted``transcribe``done` / `failed`
(константы в `internal/entity/job.go`).
Три воркера в `main.go` крутят по одному шагу каждый, опрашивая базу раз в секунду:
`conversion_worker` (created → converted, ffmpeg в ogg), `transcribe_worker`
(converted → transcribe, заливка в S3 и старт распознавания), `check_worker`
(transcribe → done/failed, опрос операции Yandex).
Задача захватывается через `FindAndAcquire`: один `UPDATE` проставляет
`acquisition_id`, дальше строка читается по нему. Задача с истёкшим `acquire_time`
достаётся заново — час для конвертации и распознавания, сутки для проверки.
`delay_time` откладывает следующую попытку.
`contract.NoopJobError` — не ошибка, а «задач в этом состоянии нет». Воркер такой
случай не логирует и не считает в метрику. Возвращая ошибку из шага конвейера, не
теряй эту семантику.
Ошибку, после которой задачу нет смысла повторять, оформляй через `failJob`: он
переводит задачу в `failed` и сам шлёт человеку понятный текст в Telegram. Возврат
обычной ошибки оставляет задачу в текущем состоянии на повтор.
## Слои
`internal/entity` — модели, `internal/contract` — интерфейсы и типы ошибок,
`internal/service` — конвейер, `internal/controller/{http,tg,worker}` — входы,
`internal/adapter/*` — реализации contract (ffmpeg, yandex, telegram, sqlite).
Сервис зависит только от интерфейсов `contract`; конкретные адаптеры собираются
в `main.go`.
## База
Миграции goose в `migrations/`, вшиты в бинарник через `//go:embed migrations/*.sql`
в `main.go` и накатываются при старте. Новый файл достаточно положить в каталог,
регистрировать нигде не надо. Диалект — `sqlite3`.
Добавляя колонку, правь четыре места: миграцию, структуру в `internal/entity`,
и в `internal/adapter/repo/sqlite` — списки колонок в `Create`, `Save`, `GetByID` и
`FindAndAcquire`. Списки продублированы, компилятор расхождение не поймает.
## Конвенции
- Коммиты прямо в `master`, без веток и PR.
- В сообщении коммита не ставить трейлер `Co-Authored-By`.
- Логи — `log/slog`, структурные пары ключ-значение, логгер прокидывается
конструктором. `log.Printf` в `internal/controller/http/transcribe.go` — остаток,
на него не равняться.
- Текст, который увидит пользователь Telegram, — по-русски. Логи и комментарии в
коде — как в соседних файлах.
- Метрики Prometheus объявляются в `internal/metrics` с префиксом `transcriber_`.