UC-CAL-010. Руководитель ПИН смотрит календари консультантов
Назначение
Описывает read-only обзор загрузки инвест-консультантов ПИН: руководитель (менеджер) компании ПИН видит
события и записи всех консультантов своей компании за период — кто когда занят консультациями и показами,
где пересечения расписаний, сколько записей ждёт решения и сколько встреч не закрыто исходом. Обзор нужен,
чтобы распределять входящие обращения инвесторов между свободными консультантами и контролировать занятость
(UC-OVR-002). Просмотр
строго внутри компании ПИН и без права управления: изменять чужое событие или запись может только его
владелец-консультант — он пользуется теми же операциями, что и агент агентства
(UC-CAL-001). Тот же read-only механизм в scope организации
обслуживает руководителей агентств (UC-CAL-009); данный
сценарий — его платформенный аналог поверх календарей ПИН. Связан с контекстом calendar.
| Поле | Значение |
|---|
| ID | UC-CAL-010 |
| Контекст | calendar (см. docs/06-services/calendar/) |
| Тип | основной |
| Статус | draft |
Актор
| Поле | Значение |
|---|
| Роль | Менеджер / руководитель ПИН (сотрудник компании ПИН, распределяющий входящие обращения) |
| Permissions / scope | calendar.team.view — назначено в scope компании ПИН (read-only обзор команды консультантов) |
| Tenant | TenantId = CompanyId компании ПИН, ADR-0052 |
| Record-level | Не применяется к чтению внутри компании ПИН (видны календари всех консультантов); управляющие операции остаются record-level у владельцев |
Предусловие
- Актор — сотрудник компании ПИН, авторизован и имеет
calendar.team.view в scope компании ПИН.
- Инвест-консультанты ПИН ведут собственные календари теми же операциями, что и агенты: события
(UC-CAL-001), слоты самозаписи и записи инвесторов
(UC-CAL-002, UC-CAL-003).
Триггер
| Поле | Значение |
|---|
| Источник | UI button |
| Триггерящий элемент | ЛК ПИН → «Календарь консультантов» (обзор событий; вкладка «Записи») |
Основной Поток
- Руководитель ПИН открывает «Календарь консультантов»; клиент вызывает
../api/pin-manager/list-events.md
с диапазоном From/To (UTC, To > From, окно ≤ 92 дня) и опциональным фильтром по консультанту
(ConsultantUserId), виду (Kind) и статусу (Status).
- Система проверяет
calendar.team.view в scope компании ПИН и то, что актор — сотрудник компании ПИН;
TenantId берётся из токена (не из query). Возвращаются события только компании ПИН: владелец-консультант
(display-данные из реплики identity), Kind, Origin, Status, Priority, StartAt/EndAt/TimeZone,
заголовок/место, признак HasConflicts (пересечения внутри календаря каждого консультанта, INV-CAL-6) —
руководитель видит и занятость, и конфликты расписаний, сгруппированные по OwnerUserId.
- Руководитель открывает вкладку «Записи»; клиент вызывает
../api/pin-manager/list-appointments.md
(фильтры: консультант, статус, период). Система возвращает записи консультантов компании ПИН: время
(снапшот слота), вид, статус, display-данные инвестора и консультанта — видны зависшие Pending (консультант
не отвечает, UC-CAL-004) и Confirmed с прошедшим StartAt без
исхода (встреча не закрыта, UC-CAL-006 A4).
- Руководитель использует картину для распределения нагрузки: направляет входящее обращение инвестора
свободному консультанту, инициирует разговор с перегруженным. Само назначение обращения ведётся вне
календаря (CRM/консультация); переназначение чужих событий/записей другому консультанту через календарь
в v1 не выполняется — управляют владельцы.
Альтернативные Потоки
A1. Попытка управлять чужим событием или записью
- Руководитель ПИН вызывает управляющую операцию (изменить/отменить событие, подтвердить запись) над объектом
консультанта → отказ
CAL_EVENT_ACCESS_DENIED / APPOINTMENT_ACCESS_DENIED (403): calendar.team.view
даёт только чтение; управляют владельцы (calendar.events.manage, calendar.appointments.decide). В
pin-manager-области управляющих операций нет — клиент их не отображает.
A2. Фильтр по консультанту другого tenant
- В
ConsultantUserId указан пользователь вне компании ПИН (агент агентства) — его данные не возвращаются
(tenant isolation применяется до фильтров, fail-closed); ответ содержит только события/записи консультантов
компании ПИН. Пустой результат — не ошибка (200, Items = []).
A3. Руководитель агентства пытается смотреть консультантов ПИН
- Актор — руководитель агентства с
calendar.team.view своего агентства — обращается к pin-manager-области
→ 403 FORBIDDEN: обзор консультантов ПИН доступен только сотрудникам компании ПИН. Своя команда — в
agency-области (UC-CAL-009).
A4. Нет права обзора
- У актора нет
calendar.team.view → 403; доступен только собственный календарь, если актор сам ведёт
приём (UC-CAL-001).
Постусловие
- Состояние системы не изменено (read-only сценарий); руководитель ПИН получил картину загрузки консультантов
за период: события с конфликтами, записи со статусами, незакрытые встречи — основу для распределения
входящих обращений.
Возможные Ошибки
| Код | HTTP | Условие | Поведение клиента |
|---|
VALIDATION_FAILED | 400 | Отсутствует/некорректен диапазон From/To; окно > 92 дней; enum/paging вне границ | Подсветить период/параметры |
UNAUTHORIZED | 401 | Нет/просрочен токен | Повторная аутентификация |
CAL_EVENT_ACCESS_DENIED / FORBIDDEN | 403 | Нет calendar.team.view в scope ПИН (A4); актор не сотрудник ПИН (A3); управляющая операция над чужим событием (A1) | Скрыть обзор / управляющие действия |
APPOINTMENT_ACCESS_DENIED | 403 | Управляющая операция над чужой записью (A1) | Скрыть действия |
Acceptance Criteria
| # | Критерий | Проверка |
|---|
| AC1 | Выборка возвращает события всех консультантов компании ПИН за диапазон и ни одного события другого tenant (агентства) | тест tenant isolation |
| AC2 | Фильтр ConsultantUserId с пользователем вне компании ПИН не возвращает его данных (A2) | негативный тест фильтра (fail-closed) |
| AC3 | Признак HasConflicts считается внутри календаря каждого консультанта (пересечения событий разных консультантов конфликтом не являются) | тест конфликтов per-owner |
| AC4 | Выборка записей показывает Pending и Confirmed с прошедшим StartAt без исхода | тест управленческих фильтров |
| AC5 | Актор с calendar.team.view, но без calendar.events.manage не может изменить чужое событие (403); состояние не меняется (A1) | негативный тест read-only |
| AC6 | Руководитель агентства получает 403 в pin-manager-области (A3); своя команда — в agency-области | негативный тест scope |
| AC7 | Выборки не отдают данные за пределами запрошенного диапазона From/To | тест диапазона |
Наблюдаемость
- Логи (без PII).
pin-team-calendar-viewed (tenantId = компания ПИН, actorUserId, from, to,
consultantsCount); содержимое событий (заголовки/описания/место) в логи не пишется.
- Метрики.
calendar_team_views_total; латентность выборок (SLO сервиса; выборка ограничена диапазоном и
компанией ПИН).
Обратные ссылки
Автоссылки: где используется этот документ.
Связанные Документы
- API:
../api/pin-manager/list-events.md, ../api/pin-manager/list-appointments.md; дом модели/правил —
../api/agent/list-events.md; agency-аналог — ../api/agency/list-team-events.md,
../api/agency/list-team-appointments.md.
- Domain: calendar-event.md (INV-CAL-6, permission-модель),
appointment.md (статусы записей).
- Permissions: permission.md (
calendar.team.view и набор
calendar.*).
- Сценарий: UC-OVR-002
(консультация у консультанта ПИН).
- Связанные UC: UC-CAL-009 (обзор команды агентства —
тот же механизм в scope организации), UC-CAL-001 (собственный
календарь консультанта), UC-CAL-004 (зависшие
Pending),
UC-CAL-006 (незакрытые встречи).