Files
smart-search-back/GRPC_SERVICES.md
vallyenfail 80e5f318a9
All checks were successful
Deploy Smart Search Backend Test / deploy (push) Successful in 1m24s
add service
2026-01-18 01:48:46 +03:00

7.6 KiB
Raw Blame History

gRPC Services

Архитектура

gRPC handlers разделены на отдельные структуры для каждого сервиса во избежание коллизий имён методов (например, GetInfo присутствует как в UserService, так и в InviteService).

Структура handlers

internal/grpc/
├── server.go           # Инициализация handlers и регистрация
├── auth_handler.go     # AuthService gRPC методы
├── user_handler.go     # UserService gRPC методы
├── invite_handler.go   # InviteService gRPC методы
├── request_handler.go  # RequestService gRPC методы
├── supplier_handler.go # SupplierService gRPC методы
└── error_mapper.go     # Маппинг ошибок в gRPC статусы

Сервисы

1. AuthService

Proto: api/proto/auth/auth.proto

Метод Описание
Register Регистрация нового пользователя по инвайт-коду
Login Аутентификация пользователя (email + password)
Refresh Обновление access token по refresh token
Validate Валидация access token
Logout Выход (invalidate refresh token)

Пример:

// Login
req := &auth.LoginRequest{
    Email:     "user@example.com",
    Password:  "password",
    Ip:        "127.0.0.1",
    UserAgent: "MyApp/1.0",
}
resp, err := authClient.Login(ctx, req)
// resp.AccessToken, resp.RefreshToken

2. UserService

Proto: api/proto/user/user.proto

Метод Описание
GetInfo Получить информацию о пользователе
GetBalance Получить баланс
GetStatistics Получить статистику заявок
GetBalanceStatistics Комбинированная статистика баланса и заявок

Пример:

req := &user.GetInfoRequest{UserId: 123}
resp, err := userClient.GetInfo(ctx, req)
// resp.Email, resp.Name, resp.CompanyName...

3. InviteService

Proto: api/proto/invite/invite.proto

Метод Описание
Generate Сгенерировать инвайт-код
GetInfo Получить информацию об инвайт-коде

Пример:

req := &invite.GenerateRequest{
    UserId:  123,
    TtlDays: 30,
    MaxUses: 5,
}
resp, err := inviteClient.Generate(ctx, req)
// resp.Code, resp.ExpiresAt

4. RequestService

Proto: api/proto/request/request.proto

Метод Описание
CreateTZ Создать заявку и сгенерировать ТЗ (AI)
ApproveTZ Подтвердить ТЗ и найти поставщиков (AI)
GetMailingList Получить список заявок пользователя
GetMailingListByID Получить детали конкретной заявки

Особенности:

  • CreateTZ: поддерживает опциональные file_data и file_name для прикрепления файлов
  • ApproveTZ: запускает поиск поставщиков через Perplexity API

Пример:

// Создание ТЗ
req := &request.CreateTZRequest{
    UserId:     123,
    RequestTxt: "Нужны поставщики автозапчастей",
    FileData:   fileBytes,  // опционально
    FileName:   "specs.pdf", // опционально
}
resp, err := requestClient.CreateTZ(ctx, req)
// resp.RequestId, resp.TzText (сгенерировано AI)

// Подтверждение ТЗ
approveReq := &request.ApproveTZRequest{
    RequestId: resp.RequestId,
    FinalTz:   "Отредактированное ТЗ",
    UserId:    123,
}
approveResp, err := requestClient.ApproveTZ(ctx, approveReq)
// approveResp.MailingStatus (поставщики найдены)

5. SupplierService

Proto: api/proto/supplier/supplier.proto

Метод Описание
ExportExcel Экспортировать список поставщиков в Excel

Пример:

req := &supplier.ExportExcelRequest{
    RequestId: "uuid-string",
    UserId:    123,
}
resp, err := supplierClient.ExportExcel(ctx, req)
// resp.FileData, resp.FileName, resp.MimeType

Обработка ошибок

Все ошибки из service layer автоматически мапятся в gRPC статусы через errors.ToGRPCError():

Код ошибки gRPC Status
AUTH_INVALID_CREDENTIALS Unauthenticated
AUTH_INVALID_TOKEN Unauthenticated
USER_NOT_FOUND NotFound
REQUEST_NOT_FOUND NotFound
INVITE_LIMIT_REACHED ResourceExhausted
INVITE_INVALID_OR_EXPIRED FailedPrecondition
EMAIL_ALREADY_EXISTS AlreadyExists
INSUFFICIENT_BALANCE FailedPrecondition
Внутренние ошибки Internal (без деталей)

Регистрация сервисов

В cmd/server/main.go:

authHandler, userHandler, inviteHandler, requestHandler, supplierHandler := 
    grpcServer.NewHandlers(pool, openAIKey, perplexityKey)

grpcEntry.AddRegFuncGrpc(func(s *grpc.Server) {
    grpcServer.RegisterServices(s, 
        authHandler, userHandler, inviteHandler, 
        requestHandler, supplierHandler)
})

Context Flow

gRPC Request → Handler(ctx) → Service(ctx) → Repository(ctx) → pgx(ctx)

Все gRPC handlers принимают context.Context из gRPC request и прокидывают его через все слои.

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

Для тестирования gRPC методов можно использовать:

1. grpcurl (CLI)

# Получить список сервисов
grpcurl -plaintext localhost:9091 list

# Вызвать метод
grpcurl -plaintext \
  -d '{"email":"user@example.com","password":"password","ip":"127.0.0.1","user_agent":"test"}' \
  localhost:9091 auth.AuthService/Login

2. Unit тесты с моками

// Создать mock service
mockRequestService := &mockRequestService{
    createTZFunc: func(ctx context.Context, userID int, txt string) (uuid.UUID, string, error) {
        return uuid.New(), "Mock TZ", nil
    },
}

// Создать handler с mock
handler := &grpc.RequestHandler{
    requestService: mockRequestService,
}

// Тестировать
resp, err := handler.CreateTZ(ctx, &request.CreateTZRequest{...})

Метрики и трейсинг

Все gRPC методы автоматически отслеживаются через rk-boot:

  • Метрики: запросы, ошибки, latency
  • Трейсинг: distributed tracing через OpenTelemetry
  • Логирование: все запросы логируются с request ID

Доступно на:

  • Метрики: http://localhost:9091/metrics
  • Health: http://localhost:9091/health

Reflection

gRPC Reflection включен в config/boot.yaml, что позволяет использовать grpcurl и другие инструменты без .proto файлов:

grpc:
  - name: smart-search-service
    enableReflection: true

Статистика

  • Всего gRPC методов: 17
  • Всего handlers: 5
  • Строк кода handlers: ~390
  • Proto файлов: 5