Микросервисная система на C# / .NET 8, реализующая управление валютными курсами и избранными валютами пользователя.
Таблица currency
| Поле | Тип | Описание |
|---|---|---|
| id | uuid | Первичный ключ |
| name | text | Название валюты |
| rate | numeric | Курс к рублю |
Таблица user
| Поле | Тип | Описание |
|---|---|---|
| id | uuid | Первичный ключ |
| name | text | Имя пользователя |
| password | text | BCrypt-хеш пароля |
Пользователь может добавлять валюты в избранное (favorites) — связь many-to-many между user и currency.
- Микросервис миграции БД
- Фоновый сервис — получение курсов ЦБР и заполнение таблицы
currency - UserService — регистрация, логин, логаут (Clean Architecture + CQRS)
- FinanceService — получение курсов валют по пользователю (Clean Architecture + CQRS)
- JWT-авторизация
- API Gateway для обоих микросервисов
- Unit-тесты для UserService и FinanceService
┌─────────────────────────────────────────────────────┐
│ API Gateway │
│ (YARP, :5000) │
│ JWT validation + blacklist check + routing │
└──────────────┬──────────────────────┬───────────────┘
│ │
▼ ▼
┌───────────────────┐ ┌────────────────────┐
│ UserService │ │ FinanceService │
│ (:5001) │ │ (:5002) │
│ register/login/ │ │ GET rates by user │
│ logout │ │ add/remove favorite │
└───────────────────┘ └────────────────────┘
│ │
└──────────┬───────────┘
▼
┌──────────────────┐
│ PostgreSQL │
│ loyalcode DB │
└──────────────────┘
▲
┌───────────┴────────────┐
│ MigrationService │ (запускается первым, создаёт схему)
│ CurrencyUpdater │ (фоновый, обновляет курсы ЦБР)
└────────────────────────┘
Domain → Application → Infrastructure → API
- Domain — сущности, доменные исключения, без зависимостей
- Application — команды/запросы (MediatR), интерфейсы репозиториев, валидаторы (FluentValidation), pipeline behaviors
- Infrastructure — EF Core, реализации репозиториев, сервисы (JWT, BCrypt)
- API — контроллеры, регистрация зависимостей
src/
├── Gateway/
│ └── LoyalCode.Gateway/ # YARP API Gateway (:5000)
└── Services/
├── Migration/
│ └── LoyalCode.Migration/ # Worker: EF Core миграции при старте
├── CurrencyUpdater/
│ └── LoyalCode.CurrencyUpdater/ # Worker: опрос ЦБР каждые N минут
├── UserService/
│ ├── LoyalCode.UserService.Domain/
│ ├── LoyalCode.UserService.Application/
│ ├── LoyalCode.UserService.Infrastructure/
│ └── LoyalCode.UserService.API/ # (:5001)
└── FinanceService/
├── LoyalCode.FinanceService.Domain/
├── LoyalCode.FinanceService.Application/
├── LoyalCode.FinanceService.Infrastructure/
└── LoyalCode.FinanceService.API/ # (:5002)
tests/
├── LoyalCode.UserService.Tests/
└── LoyalCode.FinanceService.Tests/
Все запросы идут через Gateway. Он валидирует JWT и проксирует запросы к сервисам.
| Метод | Путь | Auth | Описание |
|---|---|---|---|
| POST | /api/auth/register |
— | Регистрация ({ name, password }) |
| POST | /api/auth/login |
— | Логин, возвращает JWT-токен |
| POST | /api/auth/logout |
JWT | Логаут, инвалидирует токен |
| Метод | Путь | Auth | Описание |
|---|---|---|---|
| GET | /api/currency/rates |
JWT | Курсы избранных валют пользователя |
| POST | /api/currency/favorites |
JWT | Добавить валюту в избранное (body: guid) |
| DELETE | /api/currency/favorites/{currencyId} |
JWT | Удалить валюту из избранного |
| Технология | Версия | Назначение |
|---|---|---|
| .NET | 8.0.125 | Runtime/SDK |
| ASP.NET Core | 8.0 | Web API |
| Entity Framework Core | 8.0.0 | ORM |
| Npgsql EF Provider | 8.0.0 | PostgreSQL |
| MediatR | 12.4.1 | CQRS pipeline |
| FluentValidation | 12.1.1 | Валидация команд |
| YARP | 2.2.0 | Reverse Proxy / API Gateway |
| BCrypt.Net-Next | 4.0.3 | Хеширование паролей |
| xUnit + Moq + FluentAssertions | — | Unit-тесты |
- .NET 8 SDK
- PostgreSQL (локально или в Docker)
Создайте базу данных и убедитесь, что строка подключения в appsettings.json каждого сервиса корректна:
"ConnectionStrings": {
"DefaultConnection": "Host=localhost;Port=5432;Database=loyalcode;Username=postgres;Password=postgres"
}В production используйте переменные окружения или dotnet user-secrets вместо хранения credentials в конфиге.
# 1. Миграции (создаёт схему БД и завершается)
dotnet run --project src/Services/Migration/LoyalCode.Migration
# 2. Обновление курсов ЦБР (фоновый, запускать параллельно или отдельно)
dotnet run --project src/Services/CurrencyUpdater/LoyalCode.CurrencyUpdater
# 3. UserService
dotnet run --project src/Services/UserService/LoyalCode.UserService.API
# 4. FinanceService
dotnet run --project src/Services/FinanceService/LoyalCode.FinanceService.API
# 5. Gateway (единая точка входа)
dotnet run --project src/Gateway/LoyalCode.GatewayПосле запуска:
- Swagger UserService:
http://localhost:5001/swagger - Swagger FinanceService:
http://localhost:5002/swagger - Gateway:
http://localhost:5000 - Health checks:
http://localhost:500X/health
dotnet testJWT + blacklist. Токены подписываются HS256. При логауте jti токена добавляется в in-memory blacklist (ConcurrentDictionary). Gateway при каждом запросе проверяет blacklist через GET /internal/tokens/{jti}/is-revoked у UserService.
Upsert курсов. CurrencyUpdater загружает XML с ЦБР, нормализует курс (value / nominal), затем обновляет существующие записи или добавляет новые.
FluentValidation в MediatR pipeline. ValidationBehavior<TRequest,TResponse> перехватывает все команды до хендлера. Невалидные запросы возвращают 400 Bad Request с перечнем ошибок.
Избранные валюты. Отдельная таблица user_favorites (many-to-many). GetRatesByUser делает один JOIN вместо N+1 запросов.