graph TB
subgraph Users
MU["Mobile User - Flutter App"]
AP["Admin/Manager - Web Panel"]
end
subgraph StagePlus["Stage+ Platform"]
GW["Ingress / API Gateway - JWT auth"]
CORE["Core API - backend"]
IAM["IAM Service"]
CHAT["Chat Service"]
CALC["Calculator Service"]
SPECS["Car Specs Service"]
VTS["Vessel Tracking Service"]
end
subgraph External["External Systems"]
AJES["AJES Auction"]
DROM["Drom.ru - specs parser"]
CBR["CBR / Exchange Rates"]
FCM["Firebase Cloud Messaging"]
SMS["SMS Gateway - OTP Bot"]
MST["myshiptracking.com - AIS"]
PHX["phenix.asia - schedule"]
end
subgraph Data["Data Layer"]
PG[("PostgreSQL")]
REDIS_CACHE[("Redis Cache")]
REDIS_PUBSUB[("Redis PubSub")]
MINIO[("MinIO - S3 Storage")]
end
MU -->|"REST + WebSocket"| GW
AP -->|"REST"| GW
GW --> CORE
GW --> IAM
GW --> CHAT
GW --> CALC
GW --> SPECS
GW --> VTS
CORE --> PG
CORE --> REDIS_CACHE
CORE --> MINIO
IAM --> PG
IAM --> REDIS_CACHE
CHAT --> PG
CHAT --> REDIS_PUBSUB
SPECS --> PG
VTS --> PG
VTS --> REDIS_CACHE
CALC -->|"lookup HP"| SPECS
CHAT -->|"validate token"| IAM
CHAT -->|"car info"| CORE
CHAT -->|"push"| IAM
CORE -->|"parse"| AJES
SPECS -->|"parse"| DROM
CALC -->|"rates"| CBR
IAM -->|"push"| FCM
IAM -->|"OTP"| SMS
VTS -->|"AIS positions"| MST
VTS -->|"schedule"| PHX
| Service |
Стек |
Порт |
БД |
Функции |
| Core API (backend) |
FastAPI + SQLAlchemy + asyncpg |
8000 |
PostgreSQL + Redis + MinIO |
Каталог авто, заказы, файлы, курсы, вебхуки, AJES sync |
| IAM Service |
FastAPI + SQLAlchemy + asyncpg |
— |
PostgreSQL + Redis |
Auth (phone + OTP), users, push-уведомления, версии приложения |
| Chat Service |
FastAPI + WebSocket + Redis PubSub |
— |
PostgreSQL + Redis |
Чаты, сообщения, файлы, real-time через WS |
| Calculator Service |
FastAPI (stateless) |
— |
— (in-memory) |
Расчёт стоимости авто (таможня, утиль, доставка) |
| Car Specs Service |
FastAPI + SQLAlchemy + asyncpg |
— |
PostgreSQL |
Справочник характеристик авто (парсинг Drom.ru) |
| Vessel Tracking |
FastAPI + SQLAlchemy + asyncpg |
— |
PostgreSQL + Redis |
Отслеживание 8 судов Phenix Asia (AIS парсинг myshiptracking.com) |
sequenceDiagram
participant U as Flutter App
participant IAM as IAM Service
participant CORE as Core API
participant CALC as Calculator
participant SPECS as Car Specs
participant CHAT as Chat Service
U->>IAM: POST /auth/send-code
IAM-->>U: OTP sent via SMS
U->>IAM: POST /auth/verify
IAM-->>U: JWT token
U->>CORE: GET /cars
CORE-->>U: Car list
U->>CALC: POST /calculate
CALC->>SPECS: GET /specs
SPECS-->>CALC: horsepower
CALC-->>U: Full cost breakdown
U->>CHAT: WS /ws with JWT
U->>CHAT: Send message
CHAT->>IAM: Push notification
IAM->>FCM: Firebase push
graph TB
subgraph FlutterApp["Flutter App"]
subgraph CoreLayer["Core Layer"]
DI["service_locator - GetIt DI"]
API["ApiClient - Dio + JWT"]
WS["WsClient - WebSocket"]
SEC["SecureStorage"]
PUSH["PushNotificationService"]
end
subgraph Features["Features"]
AUTH["auth/"]
CAT["catalog/"]
ORDERS["orders/"]
CHATF["chat/"]
PROFILE["profile/"]
HOME["home/"]
AUCTIONS["auctions/"]
end
end
DI --> API
DI --> WS
DI --> SEC
DI --> PUSH
AUTH --> API
AUTH --> SEC
CAT --> API
ORDERS --> API
CHATF --> API
CHATF --> WS
Паттерны:
- DI: GetIt (service locator), все зависимости — lazy singleton
- State Management: Riverpod (pubspec) + GetIt (фактически). ⚠️ Смешение подходов
- Routing: GoRouter
- Network: Dio (REST) + web_socket_channel (WS)
- Auth storage: flutter_secure_storage (JWT в Keychain/Keystore)
- Offline: MessageQueueService (очередь сообщений при потере связи)
graph LR
subgraph CoreAPI["Core API"]
ROUTES["api"]
MODELS["models"]
SCHEMAS["schemas"]
SERVICES["services"]
end
ROUTES -->|"uses"| SERVICES
ROUTES -->|"validates"| SCHEMAS
SERVICES -->|"ORM"| MODELS
subgraph ApiRoutes["API Endpoints"]
R1["cars"]
R2["orders"]
R3["files"]
R4["rates"]
R5["webhooks"]
end
subgraph Svc["Service Layer"]
S1["ajes_parser"]
S2["ajes_sync"]
S3["auth"]
S4["cache"]
S5["car_calculator"]
S6["minio_client"]
end
graph LR
CALC -->|"HTTP GET /specs"| SPECS
CHAT -->|"HTTP validate"| IAM["IAM - token validation"]
CHAT -->|"HTTP"| CORE["Core API - car info"]
CHAT -->|"HTTP push"| IAM2["IAM - push_client"]
subgraph Async["Async Channel"]
CHAT_WS["Chat WS"] -->|"Redis PubSub"| CHAT_SUB["Chat Subscribers"]
end
Протоколы:
- Sync: HTTP (service-to-service, внутренний)
- Async: Redis PubSub (только chat real-time)
- Client ↔ Chat: WebSocket с reconnect + exponential backoff
erDiagram
USER ||--o{ ORDER : places
USER ||--o{ DEVICE_TOKEN : has
USER ||--o{ CHAT_MEMBER : participates
CAR ||--o{ ORDER : "ordered as"
CHAT ||--|{ CHAT_MEMBER : contains
CHAT ||--o{ MESSAGE : has
MESSAGE ||--o{ FILE : attaches
CAR_SPEC ||--|| CAR : "specs for"
USER {
int id PK
string phone
string name
string role
}
CAR {
int id PK
string make
string model
int year
int engine_volume
int price_jpy
}
ORDER {
int id PK
int user_id FK
int car_id FK
string status
}
CHAT {
int id PK
string type
}
MESSAGE {
int id PK
int chat_id FK
int sender_id FK
string content
string type
}
CAR_SPEC {
int id PK
string make
string model
int engine_volume
int horsepower
}
Обновлено: 2026-02-23. Статус после выполнения задач #67-#71.
- Декомпозиция на сервисы — логичное разделение по bounded contexts (IAM, Chat, Calculator, Specs)
- Единый стек бэкенда — FastAPI + SQLAlchemy + asyncpg везде → низкий когнитивный overhead
- Prometheus метрики — instrumentator подключен во всех сервисах
- Health checks — есть в каждом сервисе (DB + Redis проверки)
- Offline support — MessageQueueService в Flutter для chat
- WebSocket reconnect — exponential backoff в ws_client.dart
- ✅ API Gateway — единый baseUrl
mapp.stage-plus.ru, path-based routing через Ingress
- ✅ Shared auth library —
stageplus_auth с централизованным JWT decode
- ✅ Resilient HTTP client — retry + circuit breaker для inter-service вызовов (httpx + tenacity)
- ✅ Единый DI — Riverpod (GetIt удалён)
- ✅ CORS — ограничен до конкретных origins во всех сервисах
| # |
Проблема |
Решение |
Задача |
| 1 |
Нет API Gateway |
Единый Ingress + baseUrl в Flutter |
#67 ✅ |
| 2 |
JWT дублируется |
Shared library stageplus_auth + IAM /internal/verify |
#68 ✅ |
| 3 |
Нет retry/circuit breaker |
resilient_http модуль (httpx + tenacity) |
#69 ✅ |
| 4 |
Смешение GetIt + Riverpod |
Миграция на Riverpod, GetIt удалён |
#70 ✅ |
| 5 |
CORS wildcard в Calculator |
cors_origins через pydantic-settings |
#71 ✅ |
| # |
Проблема |
Приоритет |
Задача |
| 6 |
Redis — SPOF — один инстанс для cache + pubsub + sessions |
P2 |
#72 |
| 7 |
Rate limiting OTP — возможен SMS-флуд |
P2 |
#73 (частично реализован в коммите 802c465a) |
| 8 |
Celery — мёртвая зависимость в backend |
P2 |
#74 |
| 9 |
Contract testing между сервисами |
P3 |
#75 |
| 10 |
Message delivery guarantee — потеря при WS disconnect |
P3 |
#76 |
| 11 |
Structured logging — plaintext вместо JSON |
P3 |
#77 |
| 12 |
Feature architecture — нет domain/ в части features |
P3 |
#78 |
| # |
Замечание |
Серьёзность |
| 13 |
resilient_http/ дублируется copy-paste в 2 сервисах — вынести в shared package |
Minor |
| 14 |
stageplus_auth/ тоже copy-paste — аналогично |
Minor |
| 15 |
from jose import jwt в chat-service/car_client.py — legacy, не нужен |
Minor |
| 16 |
python-jose остаётся в requirements всех сервисов, хотя JWT только в stageplus_auth |
Minor |
| 17 |
Нет тестов на resilient_http и stageplus_auth |
Medium |
Подробное ревью: stageplus-review-2026-02-23
graph TB
subgraph Clients
APP["Flutter App"]
WEB["Web Panel"]
end
subgraph Edge
INGRESS["Ingress Nginx - TLS + Rate Limit"]
end
subgraph Gateway["API Gateway Layer"]
GW["API Gateway - routing, JWT, rate limit"]
end
subgraph Services
CORE["Core API"]
IAM["IAM Service"]
CHAT["Chat Service"]
CALC["Calculator"]
SPECS["Car Specs"]
end
subgraph DataLayer["Data"]
PG[("PostgreSQL - per-service DB")]
REDIS_CACHE[("Redis Cache")]
REDIS_PUBSUB[("Redis PubSub")]
MINIO[("MinIO")]
end
subgraph Observability
PROM["VictoriaMetrics"]
GRAF["Grafana"]
LOGS["Loki - structured logs"]
end
APP --> INGRESS
WEB --> INGRESS
INGRESS --> GW
GW --> CORE
GW --> IAM
GW --> CHAT
GW --> CALC
GW --> SPECS
CORE --> PG
IAM --> PG
CHAT --> PG
SPECS --> PG
CORE --> REDIS_CACHE
IAM --> REDIS_CACHE
CHAT --> REDIS_PUBSUB
CORE --> MINIO
CHAT --> MINIO
CORE --> PROM
IAM --> PROM
CHAT --> PROM
CALC --> PROM
SPECS --> PROM
- ✅ API Gateway — единая точка входа
mapp.stage-plus.ru, path-based routing
- ✅ Shared auth —
stageplus_auth library + IAM /internal/verify
- ✅ Redis split —
redis_cache_url + redis_pubsub_url
- ✅ Structured logging — JSON с trace_id во всех сервисах
- ✅ Circuit breaker —
resilient_http (httpx + tenacity) для inter-service calls
- ✅ Единый DI — Riverpod (GetIt удалён)
- ✅ Rate limiting — OTP: 3/10min per phone, 10/min per IP
- ✅ Contract testing — pytest + jsonschema в CI
- ✅ Message delivery guarantee — sequence_id + catch-up при WS reconnect
- ✅ Vessel Tracking Service — новый микросервис (AIS + schedule)
- Database per service — изоляция данных (сейчас shared DB)
- SMS-провайдер — заменить OTP-бот на реальный (SMS.ru / SMS Aero)
- 2FA для менеджеров (TOTP)
- Публикация в Google Play