This commit is contained in:
Oscar
2026-06-02 16:22:53 +03:00
parent dc44cdd639
commit bc3e48bcad
37 changed files with 973 additions and 1894 deletions

View File

@@ -23,6 +23,31 @@
---
## Рефакторинг: мульти-профиль (02.06.2026)
Полная переработка доменной модели. Основная причина: один пользователь
может иметь несколько публичных профилей. Все социальные операции
переведены с `user_id` на `profile_id`.
**Ключевые изменения схемы:**
- `profile.user_id` — убран `UNIQUE`, теперь один user → много профилей
- `profile.active_chat_id` — перенесено из `user` в `profile`
- `user.active_chat_id` — удалено
- `media``profile_media` (FK на `profile`, тип: `photo | video | audio`, добавлен `sort_order`)
- `like.source_user/target_user``like.source_profile_id/target_profile_id`
- `match.user1_id/user2_id``match.profile1_id/profile2_id`
- `chat.profile1_id/profile2_id` — теперь честные FK на `profile`
- `message.user_id``message.profile_id`
- `date.user1_id/user2_id``date.profile1_id/profile2_id`
- `report.source_user``report.source_profile_id`
**Паттерн ownership:** все операции, изменяющие профиль, проверяют
`profile.user_id === jwt.sub` через `assertProfileOwnership()` в каждом сервисе.
**WebSocket:** `profileId` передаётся в `handshake.auth.profileId` при подключении.
---
## Архитектурные решения
### 1. Глобальный JWT-guard через `APP_GUARD`
@@ -103,7 +128,7 @@ seed (например, хешем userId + дата).
| # | Пункт ТЗ | Как реализовано | Причина |
|---|---|---|---|
| 1 | `chat.profile1_id → profile` | Поле хранит `user_id` | Матч создаётся между пользователями, а не профилями; JOIN с профилем не нужен на горячем пути |
| 1 | `chat.profile1_id → profile` | Реализовано корректно после рефакторинга | — |
| 2 | Поиск «неактивен» при превышении лимита матчей | `BadRequestException` при лайке | Проще контракт с клиентом: ошибка явная, не нужно отдельного флага `searchActive` |
| 3 | Тарифный план один, но оплата предусмотрена | Таблицы `tariff` и `payment` созданы, логика оплаты не реализована | ТЗ: «регистрация открыта для всех, тарифный план один» — бизнес-логики оплаты нет |
| 4 | `radiusKm` в фильтре ленты | Параметр принимается, но фильтрация по радиусу не применяется | Требует PostGIS или формулы Haversine; добавить в следующей итерации |