# Логика установки звонка через сервер (актуальная)

## 1) Ключевые API
- `CallInviteBroadcast` — широковещательный старт входящего звонка (`type=100`) по пользователю.
- `CallSignalToSession` — точечный сигнал в конкретную сессию (`RINGING/ACCEPT/DECLINE/TIMEOUT/HANGUP/OFFER/ANSWER/ICE`).

## 2) Базовый поток звонка
1. Инициатор отправляет `CallInviteBroadcast(toLogin, callId, type=100)`.
2. Сервер отправляет онлайн-сессиям callee событие `IncomingCallInvite` по WS.
3. Офлайн-сессиям callee сервер отправляет WebPush `incoming_call` (с TTL).
4. Любая сессия callee, получив invite, может отправить `RINGING`.
5. Инициатор после первого `RINGING` показывает «Вызываем…».
6. При `ACCEPT` выбирается одна целевая сессия, остальные получают `HANGUP/stop_call` и закрывают экран входящего.
7. Далее только выбранная пара сессий обменивается `OFFER/ANSWER/ICE`.

## 3) WebPush по звонкам
### `incoming_call`
- Используется как fallback для офлайн-сессий.
- Поля: `kind`, `callId`, `fromLogin`, `fromSessionId`, `toLogin`, `sentAtMs`, `expiresAtMs`.
- TTL сейчас: **10 секунд**.
- Если push пришёл после `expiresAtMs`, уведомление не показывается.

### `stop_call`
- Отправляется при завершении/отмене/принятии на другом устройстве.
- Поля: `kind`, `callId`, `reason`, `fromLogin`, `fromSessionId`, `toLogin`, `sentAtMs`.
- Service Worker закрывает уведомление по `tag=callId`.

## 4) Кнопки в push-уведомлении
- Для `incoming_call` есть actions:
- `accept` — «Ответить»
- `decline` — «Сбросить»
- По нажатию action:
- Service Worker шлёт событие в открытые вкладки,
- и открывает/фокусит UI с параметрами действия.
- UI пытается выполнить действие сразу (принять/отклонить), если сессия уже авторизована.

## 5) Важные ограничения
- Источник истины по звонку — серверный сигналинг (WS + серверные сигналы), push только вспомогательный канал.
- Push может прийти с задержкой и не по порядку, поэтому клиент фильтрует устаревшие события (`expiresAtMs` + `callId` + `stop_call`).
- Полноценный «автоответ в фоне без открытия UI» в web/PWA не гарантируется платформой.

## 6) Ограничение текущей архитектуры
- Сейчас звонки надёжно работают в рамках одного сигнального контура (когда обе стороны подключены к совместимому серверу/кластеру).
- Межсерверный сценарий «A и B на полностью разных серверах» пока не завершён и вынесен в TODO.
