Структура, доп модули, федерация, документация

This commit is contained in:
Халимов Рустам
2026-03-27 00:55:01 +03:00
parent 7cb6ac61dd
commit 7ef73b414c
64 changed files with 3080 additions and 133 deletions

View File

@@ -0,0 +1,59 @@
# Модуль Хранилища (Storage) - Техническая Документация
## 1. Обзор
**Модуль Storage** отвечает за централизованное управление файлами на платформе (аватары, медиа в чатах, вложения в историях). Модуль выступает абстракцией над S3-совместимым объектным хранилищем (в данный момент реализовано через **MinIO**) и интегрируется с криптографическим ядром для обеспечения безопасности файлов.
Ключевая особенность: модуль реализует концепцию **Zero-Knowledge At-Rest Encryption** — ни один файл не попадает на жесткие диски S3-сервера в открытом виде.
## 2. Архитектура и Процесс Загрузки
Сервис [S3FileStorageService](file:///e:/GIT/forkmessager/backend/src/Modules/Storage/Infrastructure/Storage/S3FileStorageService.cs#21-27) (реализация [IFileStorageService](file:///e:/GIT/forkmessager/backend/src/Shared/Knot.Shared.Kernel/Storage/IFileStorageService.cs#6-26) из Shared Kernel) прогоняет файлы через строго определенный пайплайн:
### 1. Временное буферизирование
Поскольку поток загрузки (HTTP Request Stream) зачастую нельзя читать дважды (отсутствует `Seek`), файл сначала сохраняется во временную директорию ОС.
### 2. Абсолютная дедупликация (SHA-256)
Модуль вычисляет криптографический `SHA-256` хэш от содержимого загруженного файла.
Именно этот хэш (вместе с расширением) становится именем файла (Object Key) в корзине (Bucket) S3.
* **Результат:** Если тысяча пользователей перешлет друг другу один и тот же мем (файл), физически в S3 он будет загружен и сохранен **ровно один раз**, колоссально экономя место на серверах.
### 3. "На лету" Шифрование (E2EE/At-Rest)
Далее применяется `IEncryptionService` (обычно AES-256-CBC).
На основе временного файла открывается `CryptoStream`, который шифрует байты файла "на лету" во второй временный файл. Случайный Вектор Инициализации (Initalization Vector, `IV`) генерируется сервисом уникально для каждого файла.
### 4. Загрузка в S3 с Метаданными
Зашифрованный бинарник улетает в MinIO. Чувствительная информация сохраняется **совершенно безопасно** в заголовках метаданных объекта (MinIO Object MetaData):
* `ContentType`: Исходный MIME-тип (например, `image/png`).
* `OriginalFileName`: Закодированное исходное имя файла (Urlescaped).
* `IV`: Вектор инициализации (Base64), необходимый для последующей расшифровки. Без секретного мастер-ключа приложения этот IV бесполезен.
* `EncryptionAlgorithm`: Маркер алгоритма (`AES-256-CBC`).
В конце цикла бэкенд зачищает локальные временные файлы.
## 3. Процесс Скачивания и Кэширование (API)
Модуль предоставляет минималистичный REST API интерфейс, реализованный через **Carter** ([FilesEndpoints](file:///e:/GIT/forkmessager/backend/src/Modules/Storage/Presentation/Endpoints/FilesEndpoints.cs#11-54)).
### Эндпоинты
| Метод | Маршрут | Параметры | Описание |
| :--- | :--- | :--- | :--- |
| `GET` | `/api/files/{id}` | `?download=true` | Отдает расшифрованный файл. Поддерживает `Range` запросы для стриминга видео и музыки. |
### Механизм In-Memory Caching (Производительность)
Расшифровка файлов (особенно видео) в реальном времени и постоянный запрос их из S3 съедает процессорное время и сетевой канал бэкенда.
К эндпоинту скачивания подключен `IMemoryCache`:
1. При первом запросе файла (например, аватара популярного пользователя), он скачивается из MinIO во временный файл ОС на бэкенде.
2. Файл прогоняется через `CryptoStream` (с использованием `IV` из метаданных корзины S3) для дешифровки и выгрузки в `MemoryStream`.
3. Байты готового файла, его `ContentType` и исходное имя кэшируются в RAM бэкенда на **30 минут** (Sliding Expiration).
4. Все последующие запросы отдают готовые байты прямо из оперативной памяти без сетевого похода в MinIO и без повторной расшифровки.
### Поддержка Range-запросов
API использует метод `Results.File(..., enableRangeProcessing: true)`. Это означает, что плееры в браузере или мобильном клиенте могут запрашивать видео кусками (например, `Range: bytes=1000-2000`), и бэкенд корректно отдаст только нужный чанк (из кэша или после скачивания), что делает модуль пригодным для видео-стриминга прямо из коробки.
---
## Итог
Модуль представляет собой пуленепробиваемый шлюз для работы с медиа:
* Обеспечивает полную конфиденциальность (ни один файл не хранится открытым в корзине облака).
* Защищен от дубликатов (переиспользование за счет SHA-256 хэшей).
* Высоко оптимизирован для раздачи горячего контента (In-Memory кэширование и поддержка HTTP Range Streaming).