Skip to content
 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

439 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Backend Service

Сервис для многофункционального телеграм бота для аккаунтов из Яндекс Staff, предоставляющего бизнес-функции для внутреннних заказчиков и их внешних партнеров. Поверх сценариев бота доступны HTTP API на Gin (префикс /api/v1), JWT-авторизация, сессии в Redis, файлы в S3-совместном хранилище (MinIO), SMTP для писем сброса пароля, приём вебхуков Яндекс Форм и фоновая очистка «осиротевших» файлов.

Поддерживаемый функционал:

  1. Авторизация через Staff аккаунт Яндекса с использованием ролевой модели;
  2. Преоставляет перечень коробочных решений по посещению мероприятий с возможностью выбора свободных дат и времени;
  3. Скачивание гайда по посещению мероприятий;
  4. Запрос спецпроекта;
  5. Просмотр примеров спец.проектов;
  6. Просмотр справочной информации о сервисе;
  7. Связь с поддержкой;
  8. HTTP API для админки и интеграций (/api/v1): регистрация и вход, refresh-токены, выход, запрос и сброс пароля по e-mail (SMTP из конфига);
  9. Коробочные решения в API: список, карточка, создание, изменение, удаление, загрузка изображения, смена статуса; проверка ролей и отдельных прав (создание/редактирование/удаление коробок);
  10. Спецпроекты в API: список, создание, просмотр, обновление, удаление с разграничением прав;
  11. Заявки на спецпроекты: список, создание оператором, просмотр, смена статуса, удаление;
  12. Бронирования: список, просмотр по id, смена статуса, удаление; отдельные права на просмотр/редактирование/удаление;
  13. Настройки сервиса: тексты сообщений бота; чтение и изменение матрицы прав по ролям (админ);
  14. Аналитика: выгрузка (эндпоинт export) при наличии права на просмотр аналитики;
  15. Страницы ресурсов (контент разделов бота — о сервисе, гайд, примеры, полезные ссылки, заявка на спецпроект): список, получение по slug, правка, загрузка файла к странице, удаление ссылок и страницы;
  16. Загрузка файлов через API (POST /files/upload) в объектное хранилище; публичная выдача контента страницы ресурса без JWT (GET /api/v1/public/resources/:slug);
  17. Пользователи Staff: список и карточка (админ); создание, обновление, смена статуса учётной записи; дашборд для роли менеджер/админ;
  18. Интеграция с Яндекс Формами: публичный POST /api/v1/public/applications/ принимает тело ответа формы; сверяются заголовки X-Webhook-Token (секрет из конфига) и X-Form-Answer-Id;
  19. Сессии бота и связанные сценарии в Redis; ограничение частоты обработки апдейтов и внешних вызовов (rate limiting в боте);
  20. MinIO (или другое S3-совместное API) для медиа и вложений; при старте создаётся bucket; фоновый воркер удаляет объекты в хранилище, на которые больше нет ссылок в БД (параметры file_gc / FILE_GC_*);
  21. Режим API_ONLY: один процесс поднимает API, миграции, метрики и health без запуска Telegram-бота (удобно для разработки фронта);
  22. CORS для браузерного фронта, метрики Prometheus и middleware на стороне Gin; маршруты собраны в internal/api/server/routes.go.

Содержание

  • Введение
  • Структура проекта
  • Требования
  • Конфигурация
  • Быстрый старт
  • Запуск (локально и Docker)
  • HTTP API (/api/v1)
  • Миграции базы данных
  • Makefile цели
  • Логи и метрики
  • Разработка
  • Тесты и линтинг
  • Точки здоровья (health/endpoints)
  • Траблшутинг

Введение

Сервис написан на Go, включает HTTP API, работу с БД и миграциями, логирование, метрики и процесс Telegram-бота. Фактически один исполняемый модуль собирается из cmd/bot: при старте выполняются миграции goose, подключаются PostgreSQL и Redis, инициализируется клиент к объектному хранилищу, поднимается Gin-сервер с CORS и JWT-middleware, отдельный HTTP-сервер для /metrics и /health на порту prometheus_port, опционально запускается бот и воркер очистки файлов. Конфигурация читается через Viper из config/config.yaml с переопределением из переменных окружения; для локальной разработки используйте .env.example.env.

Запуск возможен локально, в Docker и через docker-compose, в том числе целями make run-local (полный стек, порты на 127.0.0.1) и make run-local-api (инфраструктура на localhost для go run на хосте).


Структура проекта


├── main.go                 # Точка входа HTTP-сервиса (API)
├── cmd/
│   └── bot/
│       └── main.go         # Точка входа отдельного процесса бота
├── internal/
│   ├── bot/                # Логика бота: обработчики, клиенты, воркеры
│   ├── handlers/           # HTTP-обработчики (роуты, контроллеры)
│   ├── models/             # Доменные модели и DTO
│   ├── database/           # Подключение к БД, репозитории
│   ├── config/             # Чтение и валидация конфигурации
│   ├── logger/             # Инициализация и обертки логирования
│   └── metrics/            # Метрики
├── migrations/             # SQL/скрипты миграций базы данных
├── config/
│   └── config.yaml         # Основной конфигурационный файл
├── Dockerfile              # Сборка Docker-образа приложения
├── docker-compose.yml      # Сценарий запуска сервиса и зависимостей (БД и т.д.)
├── Makefile                # Сценарии автоматизации (build, run, test, lint, migrate)
└── go.mod / go.sum         # Модули и зависимости Go

В актуальной ветке main.go в корне может отсутствовать; единая точка входа — cmd/bot/main.go. Дополнительно в дереве кода:

  • internal/api/ — Gin: server, handlers, middleware (аутентификация по JWT, CORS, метрики, проверка ролей);
  • internal/repository/postgres, internal/repository/redis — доступ к данным и сессиям;
  • internal/storage/minio — загрузка и удаление объектов в бакете;
  • internal/worker/ — фоновые задачи (очистка файлов);
  • internal/service/ и internal/dto/ — бизнес-логика и контракты API/бота;
  • scripts/ — обёртки ./scripts/run, ./scripts/stop над make;
  • docker-compose.infra.yml, docker-compose.local.infra.yml, docker-compose.local.app.yml — база, Redis, MinIO и публикация портов для локальной разработки;
  • .env.example — шаблон переменных для compose и хоста.

Требования

  • Go 1.26+ — на компе нужна актуальная версия. Проверка: go version. Установка: go.dev/dl. Для автоматической подстановки тулчейна: в go.env или окружении задать GOTOOLCHAIN=auto. Версия модуля в репозитории смотрите в go.mod.
  • Docker 24+ и Docker Compose (для контейнерного запуска)
  • Доступ к СУБД (например, PostgreSQL)
  • Redis (сессии и сопутствующая логика)
  • S3-совместное хранилище (в compose по умолчанию MinIO)

Конфигурация

Базовая конфигурация хранится в config/config.yaml. Значения могут переопределяться через переменные окружения.

Пример содержимого config/config.yaml:

server:
  port: 8080
  readTimeout: 5s
  writeTimeout: 5s

database:
  maxOpenConns: 20
  maxIdleConns: 5
  connMaxLifetime: 30m

logger:
  level: info
  format: json

metrics:
  enabled: true
  endpoint: /metrics

bot:
  enabled: true
  token: "${BOT_TOKEN}"     # можно переопределить через окружение

Переменные окружения (примеры):

  • APP_ENV=local|dev|prod
  • BOT_TOKEN=...
  • DB_DSN=... (доступ к БД, ссылка на запись в защищённом хранилище)
  • LOG_LEVEL=debug|info|warn|error

Загрузчик конфигурации читает config.yaml, затем применяет ENV-опции.

В коде загрузка реализована через Viper (internal/config/config.go). Имеют значение, в частности:

  • параметры PostgreSQL (db.* / POSTGRES_*, DB_HOST_PORT);
  • Redis (redis.* / REDIS_ADDR, REDIS_PASSWORD, REDIS_DB);
  • JWT и TTL токенов (auth_config / JWT_SECRET);
  • MinIO: endpoint, ключи, имя бакета, public_base_url (MINIO_*);
  • SMTP и базовый URL для ссылок в письмах (email.* / SMTP_*, EMAIL_*);
  • yandex_forms.webhook_token / YANDEX_FORMS_WEBHOOK_TOKEN (обязателен при старте приложения);
  • file_gc — включение воркера, интервал, «период милосердия» для сирот, размер батча;
  • api_only, cors, лимиты msg_rps / api_rps, session.ttl, port, prometheus_port, migrations_dir.

Удобный старт для Docker и хоста: скопировать .env.example в .env и заполнить секреты.


Быстрый старт

  • Убедитесь, что корректно заполнен config/config.yaml
  • Запустите сервис:
    • Локально: go run ./main.go
    • В Docker: docker compose up --build
  • Для полного локального стека из репозитория: cp .env.example .env, заполните токены и пароли, затем make run-local или ./scripts/run
  • Чтобы поднять только Postgres, Redis и MinIO на 127.0.0.1 и гонять API на машине разработчика: make run-local-api, далее экспорт переменных из .env (в т.ч. DB_HOST_PORT, REDIS_ADDR, переменные MinIO) и go run ./cmd/bot/*.go — см. комментарии в .env.example

Запуск

Локально (без Docker)

  • Запуск API:
    go run ./main.go
  • Запуск бота:
    go run ./cmd/bot/main.go

Сейчас типичный запуск API и бота одной командой:

go run ./cmd/bot/*.go

или make run. Только HTTP API и метрики без бота: задайте API_ONLY=true (и при необходимости пустой BOT_TOKEN не используется в этом режиме согласно логике конфига).

Docker

  • Собрать образ:
    docker build -t backend-service:latest .
  • Запустить контейнер:
    docker run --rm -p 8080:8080 \
      -e APP_ENV=prod \
      -e BOT_TOKEN=... \
      backend-service:latest

Docker Compose

  • Запуск сервиса и зависимостей:
    docker compose up --build
  • Остановка:
    docker compose down

Для этого репозитория удобно пользоваться make run-local (инфра из docker-compose.infra.yml + приложение, порты проброшены на 127.0.0.1 через overlay-файлы), make stop-local или ./scripts/stop, make run-local-api — только инфраструктура на localhost. Подробности в Makefile и scripts/README.md.

Скрипты run/stop и токен бота через .env

Чтобы поднимать весь бэкенд (postgres, redis, bot) одной командой и задавать токен бота через файл:

  1. Скопируйте пример env-файла и укажите токен:
    cp .env .env
    # отредактируйте .env: BOT_TOKEN=ваш_токен_от_BotFather
  2. Запуск:
    ./scripts/run
  3. Остановка:
    ./scripts/stop

Скрипт run проверяет наличие .env и непустого BOT_TOKEN перед запуском. Логи бота: docker compose logs -f bot.

Примечание: убедитесь, что в docker-compose.yml настроены сервисы (например, db) и корректные переменные окружения. В полном стеке также поднимаются Redis, MinIO и сервис приложения с зависимостями по healthcheck.


HTTP API (/api/v1)

  • Без JWT: группа /api/v1/auth — логин, регистрация, обновление и инвалидация сессии (refresh/logout), восстановление и смена пароля.
  • С JWT: защищённые группы с проверкой ролей Staff и набора прав (см. модели прав в internal/models):
    • /boxes — коробочные решения;
    • /special-projects — спецпроекты;
    • /applications — заявки;
    • /bookings — бронирования;
    • /settings — сообщения и права;
    • /analytics — в т.ч. выгрузка;
    • /resources — страницы ресурсов и файлы к ним;
    • /files/upload — загрузка файла в хранилище;
    • /users — список/карточка (админ) и отдельные админские маршруты создания/обновления/статуса;
    • /dashboard — сводка для менеджеров и администраторов.
  • Публично: GET /api/v1/public/resources/:slug, POST /api/v1/public/applications/ (вебхук форм; ответы сервиса не раскрывают ошибки валидации наружу).

Полный перечень методов и путей — в internal/api/server/routes.go.


Миграции базы данных

Для управления миграциями используется goose. Миграции автоматически применяются при запуске приложения.

  • Создание миграции:

    make migration-create NAME=название
    make migration-create NAME=create_users_table
  • Откат последней миграции:

    make migration-rollback DB_DSN="postgres://user:pass@localhost:5432/db?sslmode=disable"
  • Структура файла миграции:

-- +goose Up CREATE TABLE ...;

-- +goose Down DROP TABLE ...;

  • Команды Makefile:

    • make migration — справка
    • make migration-create NAME= — создать миграцию
    • make migration-rollback DB_DSN= — откатить последнюю
  • Логи при запуске:

    • Current database version: 20240321120000
    • Found 2 pending migration(s)
    • Applied 2 migration(s)
    • Database version: 20240321120000 → 20240322123456

Makefile цели

Помимо сборки и запуска:

  • build — бинарь в ./bin/app из cmd/bot;
  • rungo run того же модуля;
  • test — тесты с подробным выводом и покрытием;
  • fmt / fix — форматирование и группировка импортов (goimports + gofmt);
  • vet, lint, lint-fix — статический анализ;
  • migration, migration-create, migration-rollback — миграции goose;
  • run-local, run-local-api, stop-local — Docker compose для локальной разработки;
  • run-frontend, run-frontend-local-api — npm-скрипты внешнего фронта (FRONTEND_DIR=...);
  • generate-mocks — генерация моков;
  • help — краткая справка по целям.

Логи и метрики

  • Логи:

    • Конфигурируются через internal/logger и config.yaml.
    • Уровни логирования: debug, info, error.
  • Метрики:

    • Экспорт метрик Prometheus включается через metrics.enabled.
    • Эндпоинт метрик задаётся metrics.endpoint (например, /metrics).
    • В internal/metrics обычно находятся регистраторы, middleware и хэндлеры.

Отдельно от основного API на порту PROMETHEUS_PORT (например, 9090) поднят mux с GET /metrics (Prometheus) и GET /health (пинг БД и проверка доступности Telegram API с кэшем). Основной REST API слушает SERVER_PORT (маршруты под /api/v1/...).


Разработка

  • Структура кода следует стандарту Go Modules.
  • Бизнес‑логика и инфраструктурный код разделены по пакетам внутри internal/.
  • Новые HTTP‑маршруты добавляйте в internal/handlers.
  • Новые модели — в internal/models.
  • Работу с БД (репозитории/ORM) — в internal/database.
  • Конфиги и валидация — в internal/config.

Для веб-API админки используйте internal/api/handlers и регистрацию в internal/api/server/routes.go; реализации доступа к данным — internal/repository/postgres, сессии — internal/repository/redis.

Рекомендации:

  • Соблюдайте контракты интерфейсов для удобства тестирования.
  • Используйте контекст context.Context во всех внешних вызовах.
  • Оборачивайте ошибки и логируйте с полями (structured logging).

Тесты и линтинг

  • Запуск тестов:
    go test ./... -race -cover
  • Линтинг (пример с golangci-lint):
    golangci-lint run
  • Форматирование:
    gofmt -w .
    go mod tidy

Те же задачи можно вызывать через make test, make lint, make lint-fix, make fmt.


Точки здоровья (health / readiness / liveness)

Рекомендуется:

  • /healthz — liveness probe (проверка, что процесс жив).
  • /readyz — readiness probe (проверка готовности зависимостей, например БД).
  • /metrics — метрики (если включено).

Порты и пути настраиваются через config.yaml.

В текущей реализации процесса приложения на порту prometheus_port доступны /health (JSON со статусом БД и Telegram) и /metrics; см. cmd/bot/main.go и internal/api/health.go.


Траблшутинг

  • Проблема запуска:
    • Проверьте config/config.yaml и переменные окружения.
    • Убедитесь, что БД доступна и DSN корректен.
    • Проверьте YANDEX_FORMS_WEBHOOK_TOKEN: пустое значение не пройдёт валидацию конфига при старте.
  • Ошибки миграций:
    • Удостоверьтесь, что инструмент миграций установлен.
    • Сверьте права пользователя БД.
  • Нет метрик:
    • Проверьте metrics.enabled и путь metrics.endpoint.
    • Убедитесь, что порт PROMETHEUS_PORT не занят другим процессом; проверка: curl на http://127.0.0.1:${PROMETHEUS_PORT}/health.
  • Логи пустые или слишком многословные:
    • Настройте logger.level и logger.format.
  • Ошибки Redis или MinIO:
    • В Docker используйте хосты сервисов из compose (redis, minio); при go run на хосте127.0.0.1 и порты из docker-compose.local.infra.yml (5432, 6379, 9000, консоль MinIO 9001).
  • 401/403 в API:
    • Проверьте заголовок авторизации, срок JWT и роль пользователя в Staff относительно требуемых прав маршрута.

Профилирование (pprof)

pprof доступен на отдельном порту только локально.

Локально:

# Снять CPU профиль под нагрузкой (30 секунд)
go tool pprof 'http://localhost:6060/debug/pprof/profile?seconds=30'

# Heap (память)
go tool pprof -http=:8091 'http://localhost:6060/debug/pprof/heap'

# Горутины
go tool pprof -http=:8091 'http://localhost:6060/debug/pprof/goroutine'

На проде — только через SSH туннель:

ssh -L 6060:localhost:6060 user@server
# затем локально:
go tool pprof 'http://localhost:6060/debug/pprof/profile?seconds=30'

Порт 6060 проброшен только на 127.0.0.1 — снаружи недоступен.


About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages