Архитектура проекта
C4 Component — компоненты API
C4Component
title Component diagram — Photo API
Container_Boundary(api, "Photo API") {
Component(routes, "API Routes", "FastAPI routers")
Component(auth, "Auth Service", "VKAuthService")
Component(photos, "Photo Service", "PhotoService")
Component(groups, "Group Service", "GroupService")
Component(db, "Database Layer", "SQLAlchemy async")
Component(storage, "Storage Layer", "MinIOStorage")
Component(kafka_prod, "Kafka Producer", "aiokafka")
Component(metrics, "Metrics", "Prometheus client")
Component(errors, "Error Handler", "AppException")
Component(config, "Config", "pydantic-settings")
}
Rel(client, routes, "HTTP")
Rel(routes, auth, "call")
Rel(routes, photos, "call")
Rel(routes, groups, "call")
Rel(photos, db, "SQLAlchemy")
Rel(photos, storage, "MinIO SDK")
Rel(photos, kafka_prod, "aiokafka")
Rel(groups, db, "SQLAlchemy")
Rel(auth, db, "SQLAlchemy")
Rel(routes, metrics, "record")
ER Diagram — база данных
erDiagram
tokens {
string data_token PK
string auth_token UK
string vk_owner_user_id
datetime created_at_time
datetime expires_at
}
groups {
int id PK
string id_string UK
string owner_data_token FK
datetime created_at
bool is_identity_group
bool is_private
string standart_hash
}
photos {
int id PK
string id_string UK
string object_key
string preview_key
datetime load_time
bigint photo_size
enum status
int attempts
int last_error_code
string last_error_message
bool is_private
string owner_data_token FK
int duplicate_group_id FK
int identity_photo_group_id FK
}
photo_analysis {
int photo_id PK, FK
int faces_count
int eyes_closed_count
bool is_blurred
float blur_score
int quality_metric
int light_level
string dominant_color
string tags
string model_version
string perceptual_hash
string sha256_hash
datetime analysis_at
}
Sequence — поток загрузки и анализа фото
Пользователь отправляет файл → API валидирует и сохраняет в MinIO → публикует событие в Kafka → Worker потребляет событие, читает из MinIO, вызывает gRPC анализатор → сохраняет результаты в БД, проверяет дубликаты.
Поток загрузки фото
- Клиент отправляет файл через POST /api/v1/photos/
- API валидирует: тип (image/jpeg, image/png), размер (≤3MB), magic bytes
- API сохраняет запись в PostgreSQL со статусом uploading
- API загружает файл в MinIO по ключу photos/{id}/original.{ext}
- API обновляет статус на pending
- API публикует событие в Kafka (топик photo-uploaded)
- Клиенту возвращается 202 Accepted
Анализ фото (Worker)
- Worker потребляет событие из Kafka
- Worker захватывает фото (optimistic lock)
- Worker читает оригинал из MinIO
- Worker вызывает внешний gRPC анализатор: детекция лиц, оценка размытия, перцептивный хеш, доминантный цвет, теги
- Worker вычисляет SHA256 и перцептивный хеш
- Worker генерирует preview (JPEG, max 800px width)
- Worker загружает preview в MinIO
- Worker сохраняет результаты анализа в БД
- Worker проверяет дубликаты (перцептивный хеш, расстояние Хэмминга < 20) и идентичные фото (SHA256)