4.8 KiB
4.8 KiB
Архитектура
Архитектура системы
flowchart LR
Browser["Browser<br/>(React SPA)"]
API["NestJS API<br/>:3000"]
Cache["In-memory cache<br/>(cache-manager)"]
MOEX["MOEX ISS API<br/>iss.moex.com"]
DB[("SQLite<br/>(Prisma)")]
Browser -->|"/api/v1/*"| API
Browser -->|"Cookie: refreshToken"| API
Browser -->|"Authorization: Bearer"| API
API -->|"getOrFetch()"| Cache
API -->|"GET /iss/*.json"| MOEX
API -->|"Prisma ORM"| DB
Cache -->|"данные"| API
DB -->|"пользователи и портфели"| API
MOEX -->|"сырые данные"| API
Внутренние модули backend
flowchart LR
Auth["AuthModule<br/>JWT + bcrypt + guards"]
Shares["SharesModule"]
Bonds["BondsModule"]
Candles["CandlesModule"]
Securities["SecuritiesModule"]
Portfolio["PortfolioModule"]
Health["HealthModule"]
MoexClient["MoexClientModule<br/>p-queue + circuit breaker"]
CacheService["CacheService<br/>(global)"]
Prisma["PrismaService<br/>(global)"]
Auth -->|"CRUD пользователей"| Prisma
Portfolio -->|"портфели и позиции"| Prisma
MoexClient -->|"запрашивает"| Shares
MoexClient -->|"запрашивает"| Bonds
MoexClient -->|"запрашивает"| Candles
MoexClient -->|"запрашивает"| Securities
MoexClient -->|"обогащает"| Portfolio
Shares -->|"использует"| CacheService
Bonds -->|"использует"| CacheService
Candles -->|"использует"| CacheService
Securities -->|"использует"| CacheService
Portfolio -->|"использует"| CacheService
Поток авторизованного запроса
sequenceDiagram
participant User as Пользователь
participant Frontend as React SPA
participant Backend as NestJS API
participant Cache as In-memory cache
participant MOEX as MOEX ISS
participant AuthDB as SQLite
User->>Frontend: Открывает акцию SBER
Note over Frontend: access token хранится в памяти
Frontend->>Backend: GET /securities/shares/SBER (Authorization: Bearer)
Backend->>Backend: JwtAuthGuard проверяет token
Backend->>Cache: getOrFetch('share:SBER')
alt cache miss
Cache->>Backend: null
Backend->>MOEX: GET /iss/.../SBER.json
MOEX-->>Backend: сырые данные
Backend->>Cache: set('share:SBER', ..., TTL=900)
else cache hit
Cache-->>Backend: cached data
end
Backend-->>Frontend: { data, meta }
Frontend-->>User: отрисованный UI
Архитектурные решения
Все архитектурные решения описаны в ADR-страницах этой документации:
| ADR | Кратко |
|---|---|
| ADR-001 | Backend — единственная точка доступа к MOEX |
| ADR-002 | In-memory cache через cache-manager |
| ADR-003 | Rate limiting через p-queue |
| ADR-004 | Архитектура feature-модулей |
| ADR-005 | OpenAPI codegen для frontend |
| ADR-006 | Отказ от CCI (Custom Components Infrastructure) |
| ADR-007 | Двухуровневая стратегия cache |
| ADR-008 | Authentication и Authorization |
| ADR-009 | Доменная модель портфеля |
| ADR-010 | Расчёт цен на backend |
Формат ответа
Все ответы API обёрнуты в единый формат:
{
"data": { ... },
"meta": {
"fromCache": false,
"cachedAt": "2026-06-13T12:00:00.000Z"
}
}
При ошибках возвращается:
{
"statusCode": 404,
"message": "Share SBER not found",
"error": "Not Found",
"timestamp": "2026-06-13T12:00:00.000Z",
"path": "/api/v1/securities/shares/SBER"
}
Глобальная конфигурация
- Глобальный префикс:
/api/v1 - ValidationPipe:
transform: true, whitelist: true - HttpExceptionFilter (catch-all)
- TransformInterceptor (авто-обёртка в
ApiResponse) - RequestLoggingMiddleware (логирует
METHOD /path STATUS DURATIONms) - JwtAuthGuard (глобально,
@Public()для открытых эндпоинтов) - RolesGuard (проверка ролей)
- CORS: разрешён для всех origins,
credentials: true