Skip to content

Архитектура MARV

Оглавление

  1. Обзор архитектуры
  2. Структура проекта
  3. Domain-Driven Design
  4. Слои приложения
  5. Ключевые паттерны
  6. Модули системы
  7. Обработка событий
  8. Управление конфигурацией

Обзор архитектуры

MARV построен на принципах Domain-Driven Design (DDD) с чётким разделением на слои.

Архитектурные принципы

  1. Layered Architecture - чёткое разделение ответственности
  2. Dependency Inversion - зависимости направлены к domain
  3. Value Objects - типобезопасные идентификаторы
  4. Event-Driven - асинхронная обработка через EventBus
  5. Repository Pattern - абстракция доступа к данным
  6. Factory Pattern - создание сложных объектов

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

marv/
├── cmd/                      # Точки входа (бинарники)
│   ├── marv/                # Основной сервер
│   │   └── main.go
│   ├── hgoose/              # Утилита миграций БД (goose v3)
│   └── config-migrator/     # Миграция legacy-конфигов

├── domain/                    # Ядро бизнес-логики (не зависит ни от чего)
│   ├── models/               # Domain модели
│   │   └── vo/              # Value Objects (28 типов ID, с UnmarshalJSON валидацией)
│   ├── services/            # Domain сервисы (чистая логика)
│   ├── repositories/        # Интерфейсы репозиториев
│   ├── interfaces/          # Интерфейсы внешних зависимостей (cache, config, logger, http, scheduler, platform, bots, media, uow, event_bus, ...)
│   ├── event_bus/           # Event Bus (sync + async, DLQ, retry)
│   ├── errors/              # Domain ошибки (коды + sentinel)
│   ├── iap/                 # Контракты In-App Purchase
│   ├── platform/            # Контракты платформ (VK, OK, TG, FB, ...)
│   └── shared/              # Общие типы (ApiType, ApiTypeRange, RawExpr, stats)

├── application/              # Оркестрация use-cases
│   ├── container/           # DI Container (split: container, getters, events, ops)
│   ├── dto/                 # Data Transfer Objects
│   ├── mappers/             # Domain ↔ DTO преобразования
│   ├── services/            # Application-сервисы (OnlineTracker и др.)
│   └── interfaces/          # ModuleType (20), CoreModules, SystemModuleSet,
│                            # Controller, StatsProvider (source of truth)

├── infrastructure/           # Внешние зависимости (PostgreSQL, Redis, HTTP)
│   ├── database/            # PostgreSQL (GORM) + mapper + ORM модели
│   ├── cache/               # Redis + MemoryStore (тесты)
│   ├── config/              # Koanf + JSON Schema валидация
│   ├── logger/              # Zerolog (file + stdout)
│   ├── http/                # HTTP-клиент + retry
│   ├── repositories/        # GORM-реализации репозиториев
│   ├── platform/            # Интеграции платформ
│   │   ├── clients/         # HTTP-клиенты сторонних сторов (Discord, GalaxyStore, Myket)
│   │   └── providers/       # ~30 провайдеров платформ + registry.go (например VK, OK, Yandex, FB, TG, Apple, Google)
│   ├── bots/                # Telegram и др. боты
│   ├── cloudflare/          # Cloudflare Stream API
│   ├── tasks/               # Cron tasks
│   │   ├── factory.go
│   │   ├── runtime/         # Общие зависимости задач (config, http)
│   │   └── implementations/
│   ├── scheduler/           # gocron + RunTracker (из shared/cron) + LeaderChecker (реализация — shared/leader)
│   ├── rival/               # Rival policy engine
│   ├── trafficflow/         # TrafficFlow callback gateway
│   └── observability/       # Метрики, мониторинг
│       ├── metrics/         # Prometheus (cache, controllers, db, http, tasks)
│       └── system/          # HostInfo (platform, kernel, uptime)

├── interfaces/               # HTTP-слой (Gin)
│   └── api/
│       ├── apierrors/       # Маппинг доменных ошибок → HTTP
│       ├── common/          # RouterGroup — обёртка над gin с BeforeUse()
│       ├── controllers/     # HTTP контроллеры
│       │   ├── v1/         # API v1 (legacy, POST-based)
│       │   ├── v2/         # API v2 (основной, RESTful)
│       │   ├── acp/        # Admin Control Panel
│       │   ├── ext/        # External webhooks
│       │   └── api/        # Системный API
│       ├── merchants/       # Merchant handlers
│       ├── middlewares/     # error_handler, log_request, metrics, rate_limit, server_id, cf_country_code_proxy
│       └── router/          # Роутинг: v1, v2, acp, ext (SetupRoutes)

├── modules/                  # Модульная система (20 модулей, config-driven)
│   ├── contracts.go          # Типизированные контракты (V1/V2/Acp/Ext Module)
│   ├── factory.go           # Factory для создания модулей
│   ├── manager.go           # Менеджер жизненного цикла (идемпотентный)
│   ├── types/               # ModuleType (re-export из application/interfaces)
│   └── implementations/     # 20 реализаций модулей

├── pkg/                      # Shared packages
│   ├── engine/              # Engine: boot, gin (в т.ч. CORS для dev), lifecycle, prometheus
│   ├── cachekeys/           # Построение/нормализация ключей кэша (keys.go)
│   ├── runtime/             # Shared singletons
│   │   └── httpclient/      # Thread-safe HTTP client (sync.RWMutex)
│   └── utils/               # Crypto-фасад над shared/cryptox + OAuth

├── config/                   # Конфигурационные файлы
│   ├── config.example.yml   # Пример конфигурации
│   ├── .env.example         # Пример переменных окружения (MARV__*)
│   ├── bots.example.json    # Пример конфигурации ботов
│   └── products.example.json # Пример каталога продуктов

├── scripts/                  # Вспомогательные скрипты
│   └── deploy.sh           # Помощник деплоя (migrate, run, config-migrate)

├── migrations/               # SQL-миграции (goose v3)
├── docs/                     # Документация (OpenAPI, VitePress, Redocly)
├── tests/                    # Интеграционные тесты

├── Dockerfile               # Multi-stage build (marv + hgoose + config-migrator)
├── docker-compose.yml       # Локальная разработка (app + Postgres + Redis)
├── Makefile                 # Сборка, линт, тесты, бандлы
└── .gitlab-ci.yml           # CI/CD (lint → test → security → build/release)

Domain-Driven Design

Value Objects

28 типов типобезопасных идентификаторов в domain/models/vo/ (генерируются gen_ids.go — генератор под тегом //go:build ignore, запускается через go run):

Core Entities:
├── user_id.go              - UserId
├── world_id.go             - WorldId
├── message_id.go           - MessageId
├── transaction_id.go       - TransactionId
├── stream_id.go            - StreamId
├── stream_input_id.go      - StreamInputId
├── event_id.go             - EventId
├── event_result_id.go      - EventResultId
├── event_dlq_id.go         - EventDlqId
├── traffic_flow_id.go      - TrafficFlowId
├── traffic_flow_entry_id.go - TrafficFlowEntryId
└── rival_id.go             - RivalId

System Entities:
├── experiment_id.go        - ExperimentId
├── remote_config_id.go     - RemoteConfigId
├── cron_task_id.go         - CronTaskId
├── alert_id.go             - AlertId
├── alert_delivery_log_id.go - AlertDeliveryLogId
└── ad_id.go                - AdId

Clan Entities:
├── clan_id.go                    - ClanId
├── clan_join_request_id.go       - ClanJoinRequestId
├── clan_moderation_action_id.go  - ClanModerationActionId
├── clan_war_id.go                - ClanWarId
├── clan_war_pvp_id.go            - ClanWarPvpId
├── clan_war_reward_id.go         - ClanWarRewardId
└── clan_war_final_id.go          - ClanWarFinalId

Backup Entities:
├── user_backup_id.go       - UserBackupId
├── world_backup_id.go      - WorldBackupId
└── user_data_update_id.go  - UserDataUpdateId

Пример использования:

go
// Правильно - невозможно перепутать параметры
func CreateMessage(userID UserId, worldID WorldId, eventID EventId)

// Неправильно - легко перепутать
func CreateMessage(userID int64, worldID int64, eventID int64)

Version Vector (Optimistic Concurrency)

Тип VersionVector (domain/models/version_vector.go) — map[string]uint64, используется для оптимистичного контроля конкурентности при обновлении data пользователя. Ключ "server" зарезервирован для серверных правок через ACP.

Функции: ParseVersionVector, CompareVersionVectors, MergeMaxVersionVectors, IncrementServer. Ошибки конфликтов: domain/errors/version_conflict.go → статус-коды 3001-3005 (V1) / 409 Conflict (V2).

Domain Abstractions (domain/shared)

RawExpr — абстракция для raw SQL выражений, позволяющая domain-сервисам формировать SQL-выражения (например, counter + 1) без импорта gorm. Infrastructure-слой конвертирует RawExpr в gorm.Expr:

go
// domain — формирует выражение
updates["execution_count"] = shared.NewExpr("execution_count + ?", 1)

// infrastructure — конвертирует для GORM
if expr, ok := v.(shared.RawExpr); ok {
    out[k] = gorm.Expr(expr.SQL, expr.Vars...)
}

UpdateMap Pattern (GORM)

Для обновления записей в PostgreSQL все репозитории используют паттерн UpdateMap — явное формирование map[string]any вместо передачи ORM-структуры в GORM.Updates(). Это необходимо, потому что Updates(struct) игнорирует zero-value поля (false, 0, ""):

go
// infrastructure/database/mapper/cron_task.go
func CronTaskUpdateMap(m *models.CronTask) map[string]any {
    return map[string]any{
        "enabled":    m.Enabled,    // false корректно сохранится
        "name":       m.Name,
        "expression": m.Expression,
        // ...
    }
}

// infrastructure/repositories/postgres/cron_task.go
func (r *repo) Update(ctx context.Context, task *models.CronTask) error {
    return r.db.Model(&orm.CronTaskRecord{}).
        Where("id = ?", task.ID).
        Updates(dbmapper.CronTaskUpdateMap(task)).Error
}

Этот паттерн реализован для всех сущностей: CronTask, Ad, Alert, RemoteConfig, Stream, Event, Message, TrafficFlow, Experiment.

Rich Domain Models

Модели содержат бизнес-логику, а не только данные:

go
// Rich Model
type User struct {
    ID     UserId
    Banned bool
    // ...
}

func (u *User) Ban() { u.Banned = true }
func (u *User) Unban() { u.Banned = false }
func (u *User) IsBanned() bool { return u.Banned }
func (u *User) CanCreateWorld() bool { return !u.IsBanned() }

Модели с rich behavior:

  • User - ban/unban, attach to ACP, session management
  • World - IsDefault(), BelongsToUser()
  • Message - IsCompleted(), MarkAsCompleted(), IsExpired()
  • Stream - IsFull(), CanAddInput()
  • Event - IsActive(), IsFinished(), CanAddResult()

Слои приложения

1. Domain Layer (Ядро)

Ответственность: Бизнес-логика, инварианты, правила

Компоненты:

  • Models - сущности и value objects
  • Services - сложная domain логика (координация entities)
  • Repositories - интерфейсы (не реализации!)
  • Events - доменные события
  • Errors - доменные ошибки

Правила:

  • НЕ зависит от других слоёв
  • НЕ знает о БД, HTTP, кэше
  • Только чистая бизнес-логика
  • Только Go стандартная библиотека + domain dependencies

Пример:

go
// domain/services/user.go
func (s *UserService) BanUser(ctx context.Context, userID UserId, reason string) error {
    user, err := s.repo.GetByID(ctx, userID)
    if err != nil {
        return err
    }
    
    // Бизнес-логика в domain
    user.Ban()
    
    // Сохранение через интерфейс
    return s.repo.Update(ctx, user)
}

2. Application Layer (Оркестрация)

Ответственность: Use cases, координация domain объектов

Компоненты:

  • Services - оркестрация domain сервисов
  • Container - Dependency Injection
  • DTOs - передача данных между слоями
  • Mappers - преобразование Domain ↔ DTO

Правила:

  • Зависит от Domain
  • НЕ зависит от Infrastructure/Interfaces
  • Оркестрирует несколько domain сервисов
  • Управляет транзакциями

Пример:

go
// application/services/user.go
func (s *UserService) BanUserWithCleanup(ctx context.Context, dto *BanUserDTO) error {
    // Оркестрация нескольких domain операций
    if err := s.domain.BanUser(ctx, dto.UserID, dto.Reason); err != nil {
        return err
    }
    
    // Очистка связанных данных
    if err := s.domain.InvalidateSessions(ctx, dto.UserID); err != nil {
        return err
    }
    
    // Публикация события
    event := NewUserBannedEvent(dto.UserID, dto.Reason)
    return s.eventBus.Publish(ctx, event)
}

3. Infrastructure Layer (Реализации)

Ответственность: Внешние зависимости (БД, кэш, HTTP)

Компоненты:

  • Repositories - PostgreSQL реализации
  • Cache - Redis реализации
  • Config - Koanf конфигурация
  • Logger - zerolog логирование
  • Platform - интеграции с платформами

Правила:

  • Реализует интерфейсы из Domain
  • Конвертирует Domain ↔ ORM
  • Использует внешние библиотеки
  • НЕ содержит бизнес-логику

Пример:

go
// infrastructure/repositories/postgres/user.go
func (r *userRepository) GetByID(ctx context.Context, id UserId) (*models.User, error) {
    var record orm.UserRecord
    err := r.db.Where("id = ?", id.Int64()).First(&record).Error
    if err != nil {
        return nil, err
    }
    
    // Конвертация ORM → Domain
    return mapper.UserDomainFromRecord(&record), nil
}

4. Interfaces Layer (API)

Ответственность: HTTP endpoints, CLI

Компоненты:

  • Controllers - HTTP обработчики
  • Middlewares - error_handler, log_request, metrics, rate_limit, server_id, cf_country_code_proxy. Аутентификация (Auth/RequireUser) реализована методами базового контроллера и подключается как middleware. Permissive CORS для dev-режима живёт в pkg/engine/gin.go (включается флагом app.security.enable_cors).
  • Router - маршрутизация (Gin)

Правила:

  • Зависит от Application/Domain интерфейсов
  • Валидация входных данных
  • Преобразование HTTP ↔ DTO
  • НЕ содержит бизнес-логику

Пример:

go
// interfaces/api/controllers/v2/users.go
func (c *UsersController) BanUser(ctx *gin.Context) {
    var dto dto.BanUserDTO
    if err := ctx.ShouldBindJSON(&dto); err != nil {
        ctx.Error(apierrors.ErrInvalidInput.WithCause(err))
        return
    }
    
    // Делегирование в application layer
    if err := c.service.BanUser(ctx.Request.Context(), &dto); err != nil {
        ctx.Error(err)
        return
    }
    
    ctx.JSON(200, gin.H{"success": true})
}

Ключевые паттерны

1. Repository Pattern

Абстракция доступа к данным:

go
// domain/repositories/user.go (интерфейс)
type UserRepository interface {
    GetByID(ctx context.Context, id UserId) (*User, error)
    Create(ctx context.Context, user *User) error
    Update(ctx context.Context, user *User) error
}

// infrastructure/repositories/postgres/user.go (реализация)
type userRepository struct {
    db database.Store
}

// infrastructure/repositories/decorators/user_cached.go (decorator)
type cachedUserRepository struct {
    inner repositories.UserRepository
    cache interfaces.CacheStore
}

2. Factory Pattern

Создание сложных объектов:

go
// modules/factory.go
type Factory struct {
    modules map[appinterfaces.ModuleType]func(*container.Container) appinterfaces.Module
}

func (f *Factory) Create(moduleType appinterfaces.ModuleType, container *container.Container) (appinterfaces.Module, error) {
    creator := f.modules[moduleType]
    return creator(container), nil
}

Используется для:

  • Модули (modules/factory.go)
  • Tasks (infrastructure/tasks/factory.go)

3. Dependency Injection

Центральный контейнер:

go
// application/container/container.go
type Container struct {
    config        interfaces.ConfigStore
    db            database.Store
    cache         interfaces.CacheStore
    eventBus      interfaces.EventBus
    // ... сервисы
}

func (c *Container) Users() interfaces.UserService {
    c.once.Do(func() {
        c.users = services.NewUserService(...)
    })
    return c.users
}

4. Event-Driven Architecture

EventBus для async операций:

go
// domain/event_bus/events/user.go
type UserBannedEvent struct {
    UserID UserId
    Reason string
}

// domain/event_bus/handlers/user.go
type UserEventHandler struct {
    repo repositories.UserRepository
}

func (h *UserEventHandler) HandleUserBanned(ctx context.Context, event *events.UserBannedEvent) error {
    // Обработка события
    log.Info().Msg("User banned")
    return nil
}

// Регистрация в container
func (c *Container) setupEventHandlers() {
    handler := handlers.NewUserEventHandler(c.Users())
    c.eventBus.Subscribe("user.banned", handler.HandleUserBanned)
}

Модули системы

Модульная архитектура

20 модулей в modules/implementations/:

МодульФайлОписание
Useruser.goПользователи и профили
Worldworld.goИгровые миры
Transactiontransaction.goIAP транзакции
Messagemessage.goСистема сообщений
Streamstream.goLivestream функционал
Eventevent.goИгровые события
TrafficFlowtraffic_flow.goОфферная механика
Rivalrival.goСоперники
Experimentexperiment.goЭксперименты
RemoteConfigremote_config.goУдалённые конфиги
Adsads.goРеклама
Alertalert.goСистема оповещений
Productproduct.goКаталог продуктов
Merchantmerchant.goMerchant хендлеры
Platformplatform.goPlatform хендлеры
Botsbots.goTelegram и др. боты
CronTaskcron_task.goПланировщик
Systemsystem.goСистемные функции
Orderorder.goЗаказы (SKU ↔ транзакция)
Clanclans.goКланы: ростер, модерация, война 5×5 (v2 + acp)

Загрузка модулей

Модули загружаются из конфига app.modules (рекомендуется) или программно через engine.With...():

yaml
app:
  modules:
    - user
    - world
    - transaction
    - stream
    - event

Manager.Create() идемпотентен — дублирование безопасно при комбинации конфига и кода.

Core и System модули определены в application/interfaces/interfaces.go (source of truth) и re-export в modules/types/types.go:

  • CoreModules — модули, загружаемые всегда: system, user, cron_task, merchant, platform.
  • SystemModuleSet — множество системных модулей (используется при формировании ModuleInfoList для ACP).

Контракты модулей (modules/contracts.go)

Типизированные интерфейсы модулей для каждого API-слоя:

go
type V1Module interface {
    appinterfaces.Module
    GetV1Controllers() []func(*v1.Controller) appinterfaces.Controller
}
type V2Module interface { ... }
type AcpModule interface { ... }
type ExtModule interface { ... }

Интерфейс модуля

go
type Module interface {
    Type() types.ModuleType
}

Модули реализуют дополнительные интерфейсы для предоставления контроллеров различных API-слоёв (GetV1Controllers(), GetV2Controllers(), GetAcpControllers(), GetExtControllers()). Роутеры опрашивают модули через Manager и регистрируют контроллеры.

Фазы:

  1. Create — Factory создаёт модуль по типу из конфига (app.modules) или программно
  2. Routes — Router'ы запрашивают контроллеры у модулей и регистрируют HTTP endpoints

Обработка событий

EventBus

Два типа шин:

go
// Синхронная (блокирующая)
c.eventBus = event_bus.NewInMemoryEventBus()

// Асинхронная (non-blocking, workers)
c.asyncEventBus = event_bus.NewAsyncEventBus(10)

События в системе

СобытиеТипОписание
IapVerifiedEventSyncIAP транзакция проверена
TrafficFlowCompletedEventAsyncОффер завершён
UserBannedEventAsyncПользователь забанен

Регистрация обработчика

go
// application/container/container.go
func (c *Container) setupEventHandlers() {
    // IAP handler
    iapHandler := handlers.NewIapVerificationHandler(
        c.Transactions(),
        c.Users(),
    )
    c.eventBus.Subscribe("iap.verified", iapHandler.Handle)
}

Управление конфигурацией

Подробное описание всех параметров конфигурации — см. Конфигурация.


Data Flow

Типичный запрос (создание world):

1. HTTP Request

2. Middleware chain (interfaces/api/middlewares/*)
   - error_handler, log_request, metrics, rate_limit, server_id, cf_country_code_proxy
   - Аутентификация (Auth/RequireUser — методы базового контроллера)

3. Controller (interfaces/api/controllers/v2/worlds.go)
   - Валидация JSON
   - Создание DTO

4. Application Service (application/services/world.go)
   - Оркестрация
   - Вызов domain сервисов

5. Domain Service (domain/services/world.go)
   - Бизнес-логика
   - Валидация invariants

6. Repository (интерфейс из domain/repositories)
   - Cache Decorator (infrastructure/repositories/decorators/world_cached.go)
     оборачивает postgres-репозиторий (паттерн decorator):
     на write — инвалидирует кэш и делегирует записи;
     на read — сначала кэш, при промахе — postgres
   - Postgres-репозиторий (infrastructure/repositories/postgres/world.go):
     конвертация Domain → ORM, SQL-запрос

7. EventBus
   - Публикация WorldCreatedEvent

8. Response
   - Конвертация Domain → DTO
   - HTTP 201 Created

Тестирование

Структура тестов

domain/services/*_test.go       - Domain logic unit tests
application/services/*_test.go  - Application use cases tests
interfaces/api/controllers/*_test.go - HTTP handlers tests

Паттерн: Local Interfaces + Stubs

go
// interfaces/api/controllers/v2/users_test.go
type stubUserService struct {
    getUserResponse *models.User
    getUserError    error
}

func (s *stubUserService) GetUser(ctx, id) (*models.User, error) {
    return s.getUserResponse, s.getUserError
}

func TestUsersController_GetUser(t *testing.T) {
    service := &stubUserService{
        getUserResponse: &models.User{ID: 1},
    }
    
    controller := NewUsersController(service)
    // ... тестируем контроллер
}

Метрики и мониторинг

Prometheus метрики

POST /acp/system/metrics

Метрики:

  • HTTP requests (duration, count, errors)
  • DB queries (duration, count)
  • Cache operations (hits, misses)
  • Task executions (duration, success/failure)

Аналитика и мониторинг

POST /acp/system/overview

Сводная информация для ACP-дашборда: статистика пользователей (кэшируется задачей stats_snapshot), пользователи онлайн и сессии за день (Redis), состояние кластера, память, Redis INFO, статусы задач.

POST /acp/me

Точка входа ACP: текущий оператор, привязанные аккаунты, версия сервера, модули, платформы, маршруты.

Structured Logging

go
// zerolog
log.Info().
    Str("user_id", userID.String()).
    Str("action", "ban").
    Msg("User banned")

Alert система

Механика оповещений (шаблоны, маршрутизация, провайдеры доставки) вынесена в общий модуль gitlab.hgpoint.com/servers/shared — пакеты shared/alerts и shared/alerts/providers. В MARV остаётся только локальный cron-диспетчер.

Из shared/alerts:

КомпонентОписание
Config / LoadConfigDestinations (куда отправлять), Templates (как форматировать)
MatchesDestination()Фильтрация destination по severity и tags
TemplateRendererРендер текста алерта по шаблону провайдера

Провайдеры доставки (shared/alerts/providers):

  • HelmProvider — структурированные алерты в HELM Alert Center (POST /ext/alerts/ingest, Bearer-авторизация), авто-обогащение тегами (source:<source>, server:<id>, version, env); для MARV source = "marv"
  • SlackProvider — webhook
  • TelegramProvider — Bot API

Локальный диспетчер: infrastructure/tasks/implementations/alert_dispatcher.go — cron task; читает конфиг через alerts.LoadConfig, выбирает destinations (selectDestinationsMatchesDestination), рендерит сообщение и отправляет через провайдеры доставки.


Производительность

Cache Strategy

Кэш:

  1. Redis - distributed

TTL политики:

  • User data: 1 hour
  • Worlds: 30 minutes
  • Products: 24 hours
  • Remote configs: 5 minutes

Database Optimization

Индексы:

  • Composite indexes для cleanup операций
  • Covering indexes для частых запросов

Connection Pooling:

yaml
infrastructure:
  database:
    max_open_conns: 25
    max_idle_conns: 5
    conn_max_lifetime: 300s

Безопасность

Аутентификация

Client API (V2):

  • JWT-авторизация (Authorization: Bearer <JWT>, токен через POST /v2/login)
  • Single session (jti)

Client API (V1, deprecated):

  • Per-request платформенная авторизация через X-Auth-Token, X-Auth-Type, X-Auth-Uid
  • Single session mode (deprecated): при app.session.single_mode.enabled на /v1/users/fetch генерируется X-Set-Session-Token; при blocking: true — запросы без актуального токена блокируются

Верификация токенов платформ:

Базовый Platform предоставляет дефолтную реализацию верификации, которую конкретные платформы могут переопределить:

МетодФормулаНазначение
VerifyApiTokenMD5(apiType + apiUID + secret)V2: поле api_token в теле POST /v2/login и при привязке логина (/v2/identities/connect). Применяется default-платформами без собственной верификации.
VerifyAuthTokenMD5(secret_apiType_apiUID)V1 (deprecated): per-request заголовок X-Auth-Token (вместе с X-Auth-Type / X-Auth-Uid).

Где secret = app.security.secret из конфигурации, apiType = числовой ID платформы, apiUID = UID пользователя.

Платформы с собственной верификацией (VK, OK, Yandex, Facebook и др.) переопределяют эти методы. Платформы без переопределения (Amazon, App Store, Google Play, и т.д.) используют базовую реализацию.

ACP:

  • HELM service token (Authorization: Bearer <RS256 JWT>, issuer helm) — верифицируется по HELM JWKS (acp.jwks, синкается задачей helm_certs); per-env доступ берётся из claim access["<slug>/<env>"] по ключу acp.access_key.

External webhooks:

  • Signature verification
  • IP whitelisting (опционально)

Rate Limiting

In-memory token bucket (per-IP), конфигурируется через:

yaml
app:
  security:
    rate_limit:
      enabled: true
      rps: 100
      burst: 200

При превышении — HTTP 429. Старые записи IP автоматически очищаются.

Авторизация

Role-based access control:

go
router.WithControllerRole(access.RoleAdmin)
router.WithControllerRole(access.RoleModerator)

Статический анализ

В CI и линтере включены: gosec (уязвимости), bodyclose (утечка HTTP-ресурсов), noctx (пропущенный context). Сканирование зависимостей: govulncheck.