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

248 lines
7.6 KiB
Markdown
Raw Permalink 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.
# 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) |
**Пример:**
```go
// 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` | Комбинированная статистика баланса и заявок |
**Пример:**
```go
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` | Получить информацию об инвайт-коде |
**Пример:**
```go
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
**Пример:**
```go
// Создание ТЗ
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 |
**Пример:**
```go
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`:
```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)
```bash
# Получить список сервисов
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 тесты с моками
```go
// Создать 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 файлов:
```yaml
grpc:
- name: smart-search-service
enableReflection: true
```
## Статистика
- **Всего gRPC методов**: 17
- **Всего handlers**: 5
- **Строк кода handlers**: ~390
- **Proto файлов**: 5