Модуль историй с документацией
This commit is contained in:
84
backend/src/Docs/stories_module_documentation.md
Normal file
84
backend/src/Docs/stories_module_documentation.md
Normal file
@@ -0,0 +1,84 @@
|
||||
# Модуль Историй (Stories) - Техническая Документация
|
||||
|
||||
## 1. Обзор
|
||||
**Модуль Историй** отвечает за создание, просмотр и предоставление ленты временных публикаций. Любая история доступна для просмотра в ленте ровно 24 часа с момента её публикации, после чего автоматически исчезает.
|
||||
Модуль построен на архитектуре **CQRS** с использованием паттерна MediatR, а публичный REST API реализован через Minimal APIs с помощью библиотеки Carter.
|
||||
|
||||
*Важная деталь предметной области:* Ответы на истории и быстрые реакции обрабатываются модулем `Conversations/Messaging` и доставляются автору в личные сообщения (Direct Messages) как специальный тип сообщения ([StoryMessage](file:///e:/GIT/forkmessager/backend/src/Modules/Messaging/Infrastructure/Persistence/MessageRepository.cs#104-116)). Сам модуль Stories отвечает исключительно за контент, жизненный цикл и учет просмотров истории.
|
||||
|
||||
## 2. Гибридная Архитектура Хранения
|
||||
Для обеспечения отказоустойчивости при масштабировании, модуль использует **Гибридную модель данных**, распределяя нагрузку между двумя базами:
|
||||
|
||||
### A. MongoDB (Документное хранилище)
|
||||
Используется как основное хранилище сверхбыстрых данных документа [Story](file:///e:/GIT/forkmessager/backend/src/Modules/Stories/Domain/Story.cs#17-26) ([IStoryRepository](file:///e:/GIT/forkmessager/backend/src/Modules/Stories/Application/Abstractions/IStoryRepository.cs#9-19)).
|
||||
* **Молниеносное чтение:** Отсутствие тяжелых SQL-связей (джоинов) позволяет мгновенно формировать ленты историй для пользователей. Актуальность истории вычисляется автоматически при выборке путем сравнения времени создания с текущим.
|
||||
* **Атомарные операции:** Счетчик просмотров ([ViewsCount](file:///e:/GIT/forkmessager/backend/src/Modules/Stories/Domain/Story.cs#32-36)) обновляется быстрой In-Place атомарной операцией `$inc`, что полностью исключает блокировки записей (locking) при массовых просмотрах.
|
||||
* **Нативное шифрование (E2EE):** Чувствительные текстовые поля (такие как `Content` и `MediaUrl`) автоматически и прозрачно шифруются алгоритмом AES-256 прямо перед записью в базу через кастомный [EncryptedStringSerializer](file:///e:/GIT/forkmessager/backend/src/Modules/Stories/Infrastructure/Persistence/Mongo/EncryptedStringSerializer.cs#8-50), внедрённый на уровне BSON-маппинга.
|
||||
|
||||
### B. PostgreSQL (Реляционная база данных)
|
||||
Используется для хранения точных логов просмотров [StoryViewers](file:///e:/GIT/forkmessager/backend/src/Modules/Stories/Application/Stories/Queries/GetStoryViewers/GetStoryViewersQuery.cs#22-23) (через [StoriesDbContext](file:///e:/GIT/forkmessager/backend/src/Modules/Stories/Infrastructure/Database/StoriesDbContext.cs#10-13)).
|
||||
* **Точечный контроль:** Хранение идентификаторов уникальных зрителей (`ViewerId`) в реляционной БД предотвращает раздувание BSON-документов MongoDB.
|
||||
* **Строгая целостность:** Таблица просмотров содержит составной уникальный индекс (`StoryId`, [UserId](file:///e:/GIT/forkmessager/backend/src/Host/Program.cs#201-205)), что на уровне самой базы гарантирует защиту от "накрутки" — один человек засчитывается в просмотры истории только один раз.
|
||||
|
||||
---
|
||||
|
||||
## 3. Модели Данных
|
||||
|
||||
### Документ [Story](file:///e:/GIT/forkmessager/backend/src/Modules/Stories/Domain/Story.cs#17-26) (в MongoDB)
|
||||
* **Id (Guid):** Уникальный внутренний ключ.
|
||||
* **UserId (Guid):** Создатель истории.
|
||||
* **Type (StoryType Enum):** Тип контента: `Text = 0`, `Image = 1` или `Video = 2`.
|
||||
* **MediaUrl (string, зашифровано!):** Ссылка на привязанный S3-файл.
|
||||
* **Content (string, зашифровано!):** Содержимое текстовой истории или подпись к медиа.
|
||||
* **BgColor (string, опционально):** Цвет фона для текстового типа.
|
||||
* **CreatedAt (DateTime):** Точка отсчета жизни истории. На основе этого времени "на лету" вычисляется активность истории (обычно `CreatedAt > DateTime.UtcNow.AddHours(-24)`).
|
||||
* **ViewsCount (int):** Предвычисленный быстрый счетчик уникальных просмотров, готовый к мгновенной выдаче клиентам.
|
||||
|
||||
### Сущность [StoryViewer](file:///e:/GIT/forkmessager/backend/src/Modules/Stories/Domain/StoryViewer.cs#11-17) (в PostgreSQL)
|
||||
* **Id (Guid):** Первичный ключ записи.
|
||||
* **StoryId (Guid):** Внешний условный ключ профиля истории.
|
||||
* **UserId (Guid):** Идентификатор посмотревшего.
|
||||
* **ViewedAt (DateTime):** Точная временная метка факта просмотра.
|
||||
|
||||
---
|
||||
|
||||
## 4. Хранение Файлов и Безопасность
|
||||
* **MinIO S3 Хранилище:** Загрузка тяжелого медиа производится через смежный модуль [Storage](file:///e:/GIT/forkmessager/backend/src/Modules/Storage/DependencyInjection.cs#13-35). Файлы именуются по алгоритму SHA-256 (от содержимого файла), что нативно гарантирует абсолютную дедупликацию мемов и роликов на серверах.
|
||||
* **Шифрование данных (At-Rest):** Все текстовые данные, попадающие в Mongo, зашифрованы сервисом `IEncryptionService`. Дамп базы данных не имеет ценности без ключей окружения приложения.
|
||||
|
||||
---
|
||||
|
||||
## 5. Описание API Эндпоинтов (`api/stories`)
|
||||
|
||||
| Метод | Маршрут | Описание |
|
||||
| :--- | :--- | :--- |
|
||||
| `GET` | `/` | Получение гибридной ленты актуальных историй текущих друзей (Mongo+Postgres маппинг). |
|
||||
| `GET` | `/user/{userId}` | Запрос актуальных историй конкретного активного пользователя. |
|
||||
| `POST` | `/` | Создание и мгновенная публикация новой истории. |
|
||||
| `DELETE`| `/{id}` | Удаление собственной истории автором в любой момент времени. |
|
||||
| `POST` | `/{id}/view` | Фиксация просмотра. Добавляет запись в PostgreSQL и инкрементит MongoDB-счетчик. |
|
||||
| `GET` | `/{id}/viewers` | Получение списка зрителей истории (функция "свайп вверх" для авторов). |
|
||||
|
||||
---
|
||||
|
||||
## 6. Real-Time Интеграция (SignalR WebSockets)
|
||||
Модуль историй поддерживает мгновенное оповещение авторов через WebSockets, встроенное в [ViewStoryCommand](file:///e:/GIT/forkmessager/backend/src/Modules/Stories/Application/Stories/Commands/ViewStory/ViewStoryCommand.cs#22-23).
|
||||
Логика прямого эфира (когда Юзер B просматривает историю Юзера A):
|
||||
1. Запрос валидируется через PostgreSQL (ранее не просмотрено).
|
||||
2. Выполняется мгновенный инкремент `$inc` счетчика в MongoDB.
|
||||
3. Через `ChatHub` адресно автору истории моментально отправляется событие `story_viewed`.
|
||||
|
||||
**Спецификация JSON-события "Мою историю просмотрели":**
|
||||
```json
|
||||
{
|
||||
"storyId": "guid",
|
||||
"userId": "guid", // Кто именно сейчас посмотрел
|
||||
"username": "johndoe",
|
||||
"displayName": "John Doe",
|
||||
"avatar": "url...",
|
||||
"viewedAt": "timestamp",
|
||||
"viewCount": 42, // Актуальный живой счетчик на этот момент!
|
||||
"ownerId": "guid" // Кому адресован ивент (User A)
|
||||
}
|
||||
```
|
||||
Фронтенд может слушать событие `story_viewed` и анимированно обновлять счетчики "в прямом эфире", а также пополнять список зрителей в попапе истории без дополнительных HTTP-запросов.
|
||||
Reference in New Issue
Block a user