# Модуль: Личный кабинет

[← К оглавлению](../README.md)

Раздел `/cabinet/*` (middleware `auth`). Объединяет дашборд, профиль, объявления пользователя, сообщения, избранное, уведомления и виджеты. Страницы с разделами обёрнуты в `layouts/cabinet.blade.php` (боковое меню `cabinet/partials/sidebar.blade.php` слева, на мобильном — горизонтальные вкладки).

## Маршруты (`routes/web.php`, группа `cabinet.`)

| URL | Назначение |
|---|---|
| `GET /cabinet` | **дашборд** (`DashboardController`) |
| `GET /cabinet/profile`, `PUT /cabinet/profile` | профиль |
| `GET /cabinet/ads`, `…/create`, `POST /cabinet/ads` | мои объявления / подача |
| `GET /cabinet/ads/{ad}/edit`, `PUT /cabinet/ads/{ad}` | **редактирование объявления** |
| `POST /cabinet/ads/{ad}/bump` | поднять объявление наверх (см. «Поднятия и рефералы») |
| `GET /cabinet/referrals` | **приглашайте друзей** (реферальная ссылка + статистика) |
| `GET /cabinet/favorites` | избранное |
| `GET /cabinet/notifications` | уведомления |
| `GET /cabinet/chat`, `/cabinet/chat/{thread}`, `/cabinet/chat-threads` … | чат + JSON-список для плавающего виджета (см. [messaging.md](messaging.md)) |
| `GET /cabinet/widgets` … | виджеты (см. [widget.md](widget.md)) |

## Дашборд («Главное»)

`Cabinet/DashboardController` + `cabinet/dashboard.blade.php`: карточки «Объявления» (Активные / С ошибками / Неопубликованные), блок **«Доступно поднятий»** (с кнопкой «Пригласить друзей») и «Статистика» (Просмотры / Избранное / Контакты) по объявлениям пользователя.

## Боковое меню

`cabinet/partials/sidebar.blade.php`: Главное · Мои объявления · Сообщения (с бейджем непрочитанных) · Приглашайте друзей · Профиль · Виджеты для сайта. Сверху — аватар, имя и рейтинг.

## Профиль

`Cabinet/ProfileController.php` + `resources/views/cabinet/profile.blade.php`:
имя, компания, **описание (до 2000 симв.)**, телефон, почта, аватар (загрузка в `storage/app/public/avatars`, при замене старый удаляется). Кнопка «Выйти».
- **Телефон** — маска `+7 (900) 000-00-00` (Alpine `phoneMask`, только цифры); на сервере нормализуется и валидируется (`regex:/^7\d{10}$/`), хранится как `+7XXXXXXXXXX`.
- **Модерация полей** — имя, компания и описание перед сохранением проверяются DeepSeek (`ModerationService::checkProfile`) на мат, запрещённые фразы и ссылки; при нарушении профиль не сохраняется (см. [integrations.md](integrations.md)).
- **Смена почты** — подтверждается кодом (на текущий адрес, а если реальной почты нет — на новый). Отправка письма обёрнута так, что сбой SMTP не роняет запрос в 500: профиль сохраняется, а пользователь видит «Не удалось отправить письмо с кодом. Попробуйте позже.» (`ProfileController::sendEmailCode`).

## Мои объявления

`Cabinet/AdController@index` + `cabinet/ads/index.blade.php`: список объявлений пользователя со статусами-бейджами (Активно / На модерации / Заблокировано / Завершено / Черновик) и ссылкой «Редактировать». Подача и правка — см. [ads.md](ads.md).

## Поднятия и рефералы

**Поднятие** (`Ad::bumpToTop()` — обновляет `published_at` + `bumped_at`; одно объявление поднимается раз в день, `Ad::bumpedToday()`).

Лимит (`Cabinet/AdController@bump`, хелперы на `User`):
- **1 бесплатное поднятие в день** у всех; сверх него тратится реферальный пул `users.bump_credits` (не сгорает).
- `User::availableBumps()` = (использовал сегодня бесплатное? 0 : 1) + `bump_credits`. Показывается на дашборде и в списке объявлений.
- `User::bumpsUsedToday()` / `hasFreeBumpToday()` — счёт по `whereDate('bumped_at', today())`.
- Старое правило «не более трети активных объявлений в день» удалено.

**Реферальная система** (`Cabinet/ReferralController` + `cabinet/referrals.blade.php`, `ReferralLinkController`, `App\Services\ReferralService`):
- У пользователя `referral_code` (ставится хуком `User::creating`, бэкафилл существующих в миграции). Ссылка — `placeo.ru/r/{code}` (`referral.link`): код пишется в `session('ref_code')`, при любой регистрации (e-mail / Яндекс / виджет) привязывается в `users.referred_by` через хук модели.
- За каждое объявление приглашённого, **прошедшее модерацию** (переход в `active` — хуки `created`/`updated` в `Ad::booted()`), рефереру начисляется `ReferralService::REWARD_PER_AD` = **5** поднятий. Потолок `DAILY_CAP_PER_REFERRAL` = **50** в день с одного друга.
- Идемпотентность и дневной потолок — журнал `referral_rewards` (`referrer_id, referred_id, ad_id (unique), credits`). Начисление инкрементит `users.bump_credits` в транзакции.
- Раздел в кабинете: реферальная ссылка с копированием + статистика (приглашено друзей / заработано поднятий / доступно из пула).

## Избранное

`FavoriteController` (см. [seller.md](seller.md)). Страница — сетка карточек с «сердечками».

## Уведомления

`Cabinet/NotificationController@index` + `cabinet/notifications.blade.php`. При открытии все помечаются прочитанными. Типы и логика — в [messaging.md](messaging.md).

## Общие данные для шапки

`app/Http/Middleware/ShareLayoutData.php` отдаёт во все view:
- `currentCity` (из сессии), `allCities` (для модалки выбора города);
- `favoriteIds` — id избранного (для отрисовки «сердец» одним запросом);
- `unreadNotifications`, `unreadMessages` — счётчики-бейджи в шапке и нижнем баре.

## Навигация

- Десктоп-шапка (`partials/header.blade.php`): иконки Сообщения / Уведомления / Избранное (с бейджами) + имя (ведёт на **дашборд** `/cabinet`). Для гостя «Войти»/«Подать объявление» открывают модалку авторизации.
- Мобильный нижний бар (`partials/bottom-nav.blade.php`): Главная, **Разделы** (модалка `partials/sections-modal.blade.php` с корневыми категориями), **+ Подать**, Сообщения (бейдж), Кабинет.
- **Плавающий виджет чатов** (`partials/chat-widget.blade.php` + Alpine `chatWidget`) — для авторизованных, внизу справа; разворачивается в список диалогов, подгружаемый из `GET /cabinet/chat-threads`.
