# Мобильное приложение — Администрирование

## Обзор

Администрирование мобильного приложения охватывает:

1. **Контейнеры** — структура экранов (TabBar, Dashboard, MainMenu), блоки, доступность по группам, порядок выбора.
2. **Шаблоны блоков** — параметры плиток, лент, стеков, кнопок.
3. **Шаблоны задач** — привязка к категориям, контексты Cell/MTF/NTF/Calendar/Grid.
4. **Навигация onTap** — действия при нажатии (более 22 действий).
5. **Push-уведомления** — настройка APNs/FCM (в домене «Уведомления»).
6. **Пользователи и доступ** — политики паролей МП, роли, первичные сценарии входа.
7. **Статистика устройств** — мониторинг установок и сессий.
8. **Геолокация** — сбор координат устройства и отчёт по трекам движения.
9. **Глобальные mobile settings** — ключи `CustomSettings`, влияющие на поведение клиента.

## Быстрый старт настройки МП

Минимальный сценарий первичной настройки мобильного клиента у нового заказчика:

1. Создать контейнер `TabBar` с шаблоном `toolbar` и собрать нижнее меню.
2. Создать контейнер `Dashboard` с шаблоном `dashboard` и наполнить его плитками `dashboardItem` или `taskSourceDashboardItem`.
3. Создать контейнер `MainMenu` с шаблоном `menu` и настроить боковое меню.
4. При наличии кастомных категорий описать мобильные шаблоны задач для контекстов `Cell`, `NTF` и `MTF`.
5. Проверить результат под тестовой учётной записью в реальном клиенте; при проблемах — [support-guide.md](https://help.1forma.ru/domains/mobile/support-guide.md).

Где описаны связанные темы:

- обзор контейнеров (роль, типы экранов, доступность по группам) — этот файл; модель контейнеров (типы, таблицы БД, наследование настроек) — [Контейнеры](https://help.1forma.ru/domains/mobile/reference/containers.md);
- навигация и JSON-ключи `onTap`, `action`, `type` — этот файл;
- привязка и автогенерация шаблонов — [Автогенерация шаблонов](https://help.1forma.ru/domains/mobile/reference/template-generation.md);
- источники данных задач (`taskSource`) — [Источники данных задач](https://help.1forma.ru/domains/mobile/reference/tasksources.md);
- push-уведомления — [Push-уведомления](https://help.1forma.ru/domains/mobile/reference/notifications.md) и [Уведомления — администрирование](https://help.1forma.ru/domains/notifications/admin.md);
- доступ, роли, повторный вход и пароль безопасности — [Доступ и авторизация](https://help.1forma.ru/domains/mobile/reference/access.md);
- виджет в карточке задачи (JS/CSS-вставка) — [JS/CSS-вставки](https://help.1forma.ru/domains/mobile/reference/template-web-widgets.md);
- глобальные mobile settings (`openInBrowserDomains`, `EmptyFeedPlaceholderURL`, `mspaByDefault`) — этот файл, раздел «CustomSettings».

---

## 1. Контейнеры

Контейнер — корневой объект экрана мобильного приложения. Контейнер содержит блоки (иерархия вложенная), блоки отрисовываются как плитки, кнопки, списки.

![Схема основных областей интерфейса МП](https://help.1forma.ru/help-images/mobile/interface_zones_diagram.png)

### API

Редактор контейнеров обращается к отдельному админскому API — маршруты с префиксом `api/containers`: чтение контейнера, блока и папки по идентификатору, чтение ключей шаблона блока и папки, копирование контейнера и копирование блока. Ответы на эти маршруты: отказ в доступе — для пользователя без прав администратора (проверка идёт до чтения данных, поэтому срабатывает и для несуществующего объекта); «не найдено» — если контейнер, блок или папка отсутствуют, например объект удалён в другой вкладке, в теле ответа приходит идентификатор, по которому искали; отказ по самому запросу — если ошибка в параметрах операции, например указан несуществующий блок при перемещении.

`POST /app/v1.2/api/mobile/containers/` (тело запроса — массив `id` контейнеров, `string[]`) — возвращает массив контейнеров с вложенными `blocks`.

Для запроса конкретного контейнера — передать его `id` в body запроса (например, `"Tabbar"`).

`POST /app/v1.2/api/mobile/containers/task/{containerId}/{taskId}` — контейнер в контексте задачи (например, `ReportsList` для отчётов задачи). Данные собираются только при доступе пользователя к задаче контекста: без доступа категория задачи не запрашивается, в контейнере остаются лишь отчёты, привязанные ко всем категориям, а по ответу нельзя отличить недоступную задачу от несуществующей. `404` возвращается только когда не найден сам контейнер.

### Фиксированные ID контейнеров

> **Id контейнера — не уникальный идентификатор.** Для некоторых контейнеров Id строго фиксированы и **регистрозависимы** (`TabBar` ≠ `tabBar`).

| Id | Шаблон | Назначение |
|----|--------|-----------|
| `TabBar` | `toolbar` | Нижнее меню (таббар) — вкладки внизу экрана |
| `Dashboard` | `dashboard` | Главный рабочий стол |
| `MainMenu` | `menu` | Боковое меню (гамбургер) |

Если для разных групп настроены разные контейнеры с одинаковым Id (например, несколько Dashboard) — отображается тот, у которого наименьший «Порядок» и совпадение по группам/смарт-фильтру.

### Структура ответа

Пример структуры ответа API контейнеров:

```json
{
  "data": [
    {
      "blocks": [ ... ],
      "buttons": null,
      "isGroupFavourite": false,
      "parentNodeId": null,
      "id": "Tabbar",
      "template": {
        "badgeItemColor": "#496acc",
        "containerBackgroundColor": "",
        "itemColor": "#404040",
        "selectedItemColor": "#555555",
        "id": "toolbar"
      }
    }
  ],
  "total": 1,
  "aggregates": null
}
```

Блок внутри контейнера:

```json
{
  "type": "Syndicate",
  "data": {
    "counter": 22,
    "type": "Feed",
    "title": "Лента"
  },
  "action": "Syndicate",
  "isGroupFavourite": false,
  "parentNodeId": null,
  "id": "Feed",
  "template": { ... }
}
```

### Типы блоков (12 типов)

Палитра блоков в редакторе контейнера:

| Тип блока | Описание | Возможные значения ID блока |
|-----------|----------|---------------------------|
| **Папка** | Вложенные блоки, иерархия. `type = null`. | `Stack` (для шаблона `dashboardStack` — списка дашбордов). ID плиток не уникален. |
| **Синдикат** | Набор данных (счётчик, список, заголовок). Платформа автоматически поставляет данные. | См. таблицу «ID блоков-синдикатов» ниже |
| **Настройки** | Переход к экрану настроек МП | `Settings` |
| **Задача** | Данные конкретной задачи (текст, номер) | `TaskNNN` (NNN = номер задачи) |
| **Контакт** | Данные пользователя (ФИО, ID, открытые ДП профиля) | `UserNNN` (NNN = ID пользователя). Работает как элемент бокового меню. |
| **Ссылка** | Ссылка внутри 1Формы или на внешний ресурс | Произвольный |
| **Форма новой задачи** | Открытие формы постановки задачи | `NewTaskNNN` (NNN = ID категории) |
| **Дашборд** | Открытие вложенного рабочего стола | ID контейнера с шаблоном `dashboard` |
| **Группа пользователей** | Все пользователи группы — плитки с контактами | `UserGroupNNN` (NNN = ID группы) |
| **Отчёт** | Web-версия отчёта | Произвольный |
| **Избранное** | Ссылки из блока «Избранное» пользователя | Только в контейнерах с шаблоном `menu` |
| **Избранное РМГ** | Рабочие места групп | Только в контейнерах с шаблоном `menu` |

> **Важно:** для корректной работы нужно выбрать правильный элемент в палитре. Неверный тип → блок не отображает данные или не совершает действие.

#### ID блоков-синдикатов

Блоки типа «Синдикат» (платформа автоматически поставляет данные — счётчик, заголовки, ID сущностей):

| ID блока | Данные |
|----------|--------|
| `Calls` | Звонки и история звонков |
| `Chats` | Список чатов |
| `Contacts` | Список контактов |
| `CustomTaskSource` | Содержимое [публикации](https://help.1forma.ru/domains/publications/admin.md) |
| `Feed` | Лента (вопросы, комментарии и т.д.) |
| `DemoSpeech` | Голосовая постановка задачи (временно используемый ключ) |
| `TasksFeed` | Лента задач (новые, просроченные, личные и т.д.) |
| `MyQuestions` | Мои вопросы |
| `QuestionsToMe` | Вопросы мне |
| `OwnTasks` | Личные задачи |
| `OverdueTasks` | Просроченные задачи |
| `ToSign` | На подписи |
| `Reports` | Отчёты |
| `UserProfile` | Профиль текущего пользователя (работает корректно как блок рабочего стола) |
| `TaskSourceNNN` | Задачи из источника данных, NNN = ID источника |
| `SubcatNNN` | Задачи из категории, NNN = ID категории |
| `SubcatAll` | Задачи из всех категорий |
| `separator` | Заголовок — визуальный разделитель между элементами |
| `MyQuestionsAndAnswers` | Исходящие вопросы и ответы на них |
| `QuestionToMeAndAnswers` | Входящие вопросы и ответы на них |

### Доступность контейнеров и блоков

Доступность определяется **группами пользователей** и **смарт-фильтром**.

**Настройка:** кнопка «Группы» в строке контейнера → создать привязку «контейнер → группа». Для каждой группы — отдельная запись.

**Логика выбора контейнера** (при нескольких с одинаковым Id):

1. Контейнер с наименьшим «Порядок», для которого указана группа пользователя И смарт-фильтр = true.
2. Если ни одна группа не подошла — контейнер с наименьшим «Порядок» без указанных групп И смарт-фильтр = true.
3. Если и такого нет — произвольный контейнер с этим Id.

> **Рекомендация:** всегда настраивать контейнер по умолчанию (пустые группы + наименьший порядок), чтобы пользователи не видели произвольный контейнер.

### Права администратора в редакторе

В обычной выдаче контейнеров (`POST /app/v1.2/api/mobile/containers/`) фильтры по группам (`APIContainerToGroups`) и смарт-выражению применяются единообразно ко всем пользователям, включая администраторов. Особого «обходного» доступа в выдаче нет — администратор получает в мобильном приложении ровно те же контейнеры, что прошли бы групповой и смарт-фильтр для обычного пользователя.

Открыть **любой** контейнер независимо от привязки к группам можно только в редакторе контейнера в админке. Для этого используется отдельный маршрут предпросмотра `api/containers/preview`: если администратор не входит в группу контейнера, для предпросмотра пропускаются фильтры по группам и смарт-выражениям и отдаётся первая активная запись с заданным ClientId. На этот маршрут переключён редактор контейнера (`administration/containers`). Редактор открывается по прямому адресу `/administration/containers/{id}`; переход по адресу `/administration/containers` без идентификатора не предусмотрен и возвращает 404 (Not Found).

**Что показывает предпросмотр в редакторе.** Превью — макет контейнера «как настроено», а не вид конкретного пользователя. Кроме отбора контейнеров по группам (см. выше) в превью не применяются и ограничения по группам у самих плиток: плитка с непустым `groups` видна в макете, даже если администратор не входит ни в одну из указанных групп, — и на верхнем уровне, и внутри папки. Признак скрытия блока (`hideBlock`) в превью не выставляется, поэтому не пропадает и папка, все блоки которой были бы скрыты по группам.

Условие «не показывать блок при нулевом счётчике» (`hideOnZeroCount`) работает иначе: у верхних плиток оно в превью продолжает действовать — плитка с нулевым счётчиком в макет не попадёт, — а у блоков внутри папки не применяется.

В мобильном приложении поведение прежнее: блок с непустым `groups` показывается только пользователям, входящим хотя бы в одну из указанных групп. Поэтому реальную видимость плитки проверяют не в редакторе, а в приложении под учётной записью участника нужной группы; если плитка нужна всем — поле `groups` оставляют пустым.

**Доступность блоков** (внутри контейнера):
- Ключ `groups` — массив ID групп через запятую. При непустом значении МП проверяет пересечение групп пользователя и массива. Если пересечение пустое — блок не отображается.
- Фильтрация по группам может быть на уровне стека (папки) целиком. Внутри папки — дополнительные фильтрации и скрытия.
- Отображение не меняется при замещении — только группы реального пользователя.

- В превью редактора контейнера ограничение по `groups` не применяется — плитка с непустым `groups` видна в макете.

### Счётчики и скрытие

`counter` — число, рассчитываемое сервером в зависимости от конфигурации блока (кол-во задач, вопросов, подписей и т.д.). Ненулевое значение отображается как значок-счётчик на плитке.

Структура `data.tasksCounters`:

```json
{
  "tasksCounters": {
    "allTasksCount": null,
    "newTasksCount": 0,
    "overdueTasksCount": 0,
    "allTasksUserOwns": 2,
    "allTasksUserPerforms": 0
  }
}
```

> Если в шаблоне блока `hideOnZeroCount = 1` и `counter = 0` или `null` — блок не отображается.

### Кнопки верхней панели (rightBarButtons)

Ключ `rightBarButtons` в шаблоне контейнера — JSON-строка с массивом объектов onTap. Настраивается в настройках главного контейнера.

Пример:

```json
[
  {
    "action": "openCallHistory",
    "icon": "RecentTasks"
  },
  {
    "action": "openTaskSource",
    "dataSourceUrl": "/app/v1.2/api/publications/action/mob-notifications",
    "icon": "Notification",
    "tickerAlias": "badge"
  }
]
```

Основные action для rightBarButton:

| Action | Описание |
|--------|----------|
| `openCalendar` | Открыть календарь встреч |
| `openCallHistory` | История звонков ВКС (последние 100 звонков) |
| `openVideoConferenceRoom` | Открыть ВКС-комнату |

Ключ `tickerAlias` — название системного счётчика (или номер пользовательского). Прикрепляет произвольный счётчик для отображения на иконке.

Ключ `tickerColor` — цвет значка счётчика (hex, например `"E05040"`).

Пример настройки истории звонков:

```json
{
  "action": "openCallHistory",
  "icon": "RecentTasks",
  "tickerAlias": "missedCalls",
  "tickerColor": "E05040"
}
```

### TabBar (нижнее меню)

TabBar — контейнер с фиксированным Id = `TabBar`, шаблон `toolbar`.

| Параметр | Значение |
|----------|----------|
| Id контейнера | `TabBar` |
| Шаблон | `toolbar` |
| Макс. блоков | 6 |
| Шаблон блоков | `toolbaritem` |
| Макс. элементов | 5 |

> В таббаре возможно настроить только один элемент с `type: "dashboard"`.

#### Допустимые ID элементов TabBar

Допустимые ID элементов нижнего меню:

| ID | Экран при нажатии |
|----|-------------------|
| `Calls` | История звонков |
| `Chats` | Список чатов |
| `Contacts` | Контакты пользователя |
| `Settings` | Настройки МП |
| `Feed` | Лента комментариев |
| `Dashboard` | Главный дашборд |
| `TasksFeed` | Лента задач |
| `ToSign` | Список подписей |
| `Folder` | Папка (группировка элементов) |
| `SubcatNNN` | Категория (NNN = ID системной категории) |
| `TaskSourceNNN` | Источник данных задач |
| `CustomTaskSource` | Пользовательский TaskSource |

Кнопка «Лента» (`Feed`) меняет заголовок в зависимости от выбранной категории/раздела (если выбраны задачи — заголовок «Задачи» и т.д.).

#### Настройка календаря в TabBar

Чтобы вывести календарь во вкладку нижнего меню:

1. Выбрать шаблон **Синдикат**.
2. Указать Id = `SubcatXXX`, где XXX = номер системной категории календаря.

#### Настройка пользовательского source в TabBar

Чтобы вывести пользовательский источник задач во вкладку:

1. Выбрать шаблон **Синдикат**.
2. Указать Id = `CustomTaskSource`.
3. В ключе `dataSourceUrl` указать ссылку на пользовательский source.

#### Ключи шаблона toolbaritem (блок TabBar)

Ключи шаблона `toolbaritem` (элемент нижнего меню):

| Ключ | Описание |
|------|----------|
| `badgeItemColor` | Цвет фона счётчика (hex `#123456`, с опциональной альфой `#123456FF`, краткие `#000` / `#000F`) |
| `fallBackTitle` | Подпись под иконкой |
| `groups` | ID групп через запятую (массив чисел) |
| `icon` | Название иконки вкладки |
| `isDefault` | `1` — вкладка открывается при старте приложения. Если у всех `0` — дефолтная `Dashboard` или первая по порядку |
| `topTitle` | Текст заголовка экрана. Если пустой — берётся `fallBackTitle` |
| `id` | Название шаблона (`toolbaritem`, `tasksFeed`) |

> **Локализация.** В шаблоне `toolbaritem` локализуем только `topTitle` (`Localizable = true`); `fallBackTitle` — не локализуем. См. § «Локализация ключей шаблона контейнера».

#### addButton — меню создания задач

`addButton` — массив объектов onTap для создания задачи (`openNewTask`). Настраивается как в шаблоне cell категории, так и в элементе контейнера toolbar'а.

```json
{
  "addButton": [
    {
      "icon": "GroupChat",
      "action": "openNewTask",
      "title": "Групповой чат",
      "id": 978
    },
    {
      "icon": "Chat",
      "action": "openNewTask",
      "title": "Чат",
      "id": 969
    },
    {
      "icon": "Calendar",
      "action": "openNewTask",
      "title": "Встреча",
      "id": 1507
    },
    {
      "icon": "Task",
      "action": "openNewTask",
      "title": "Личная задача",
      "id": 43350
    }
  ]
}
```

> Важен только `action: "openNewTask"` и `id` — номер категории, куда будет ставиться задача.

### Операции с контейнерами

Доступные операции с контейнерами в редакторе:

| Операция | Как |
|----------|-----|
| **Создать** | Кнопка «Создать». Id должен начинаться с латинской буквы. Выбрать шаблон. |
| **Редактировать** | Клик по строке → изменить название, шаблон, группы, активность, смарт-фильтр. Сохранить. |
| **Копировать** | Кнопка «Создать копию» → полный дубль контейнера. |
| **Удалить** | Кнопка «Удалить» на форме или в контекстном меню строки. |
| **Редактор** | Кнопка «Редактор» → дерево блоков + макет. Блоки перетаскиваются мышкой. |

Для блоков «Избранное» и «Избранное РМГ» — можно добавлять только в контейнеры с шаблоном `menu`.

**Контекстное меню дерева блоков.** В редакторе контейнера по правому клику на элементе левого дерева блоков открывается меню из двух пунктов: «Скрыть» — прячет блок или папку в контейнере (то же, что снять галку у элемента; пункт неактивен, если элемент уже скрыт) и «Настройка» — открывает панель настроек выбранного виджета.

### Локализация ключей шаблона контейнера

На странице «Значение ключей шаблона для контейнера» (`administration/mobile-container-template/{ID}`) рядом с текстовыми ключами, у которых `APITemplateKey.Localizable = true`, отображается стандартная кнопка локализации (иконка глобуса). Переводы хранятся в `APIContainerTemplateValue` и подтягиваются по языку интерфейса мобильного приложения.

**Локализуемые ключи** (по `APITemplateKey.Localizable = true`):

| Шаблон | Локализуемые ключи |
|---|---|
| `dashboard` | `fallBackTitle` |
| `dashboardItem` | `fallBackTitle` |
| `tasksFeed` | `fallBackTitle` |
| `dashboardStack` | `fallBackTitle` |
| `dashboardSignatures` | `fallBackTitle` |
| `taskSourceDashboardItem` | `fallBackTitle` |
| `toolbaritem` | `topTitle` |

Для шаблонов `menu`, `menuitem`, `webPortal` и других текстовые ключи не локализуются — кнопка не отображается. Для новых, ещё не сохранённых значений ключа кнопка также недоступна — сначала сохраните значение, затем локализуйте.

---

## 2. Шаблоны блоков

> Полный справочник 12 шаблонов блоков с 60+ ключами, справочник иконок (80+), локализация — см. [Мобильное приложение — шаблоны](https://help.1forma.ru/domains/mobile/mobile-templates.md) § Часть 2.

> **Критично:** обработка шаблона — в коде приложения. **Новые ключи при обновлении платформы не добавляются автоматически** — администратор должен вручную добавить ключ в JSON шаблона.

Подтипы шаблонов, выделявшиеся отдельно, отражены в Части 2 справочника шаблонов:

| Подтип | Содержание | Где в справочнике шаблонов |
|--------|-----------|--------------------------|
| Карусель | Горизонтальная прокрутка (`slideShow = 1` в `dashboardItem`) | Секция `dashboardItem`, ключ `slideShow` |
| Стек | Вертикальный / горизонтальный стек (`dashboardStack`, ключ `style`) | Секция `dashboardStack`, подразделы vertical/horizontal |

---

## 3. Шаблоны задач

> Полный справочник шаблонов задач (Cell/MTF/NTF контексты, статические/динамические, локализация, JSON-редактор) — см. [Мобильное приложение — шаблоны](https://help.1forma.ru/domains/mobile/mobile-templates.md) § Часть 1.

### Привязка шаблонов к категориям

Для одной категории можно настроить несколько шаблонов задач — статических и/или динамических.

**Как открыть.** На странице категории в настройках есть чип **«Мобильные шаблоны»** — он ведёт на разводящую страницу со ссылками на экраны мобильных шаблонов. Ссылка **«Шаблонизация»** открывает экран шаблонов задач этой категории, где настраиваются контексты, параметры привязки и генерация шаблонов; новая категория передаётся на экран автоматически, выбирать её заново не нужно.

#### Быстрая генерация шаблонов

Кнопки на форме привязки:

| Кнопка | Что делает |
|--------|-----------|
| «Генерация шаблона по умолчанию для карточки задачи» | Создаёт стандартный шаблон для MTF-контекста текущей категории |
| «Генерация шаблона по умолчанию для карточки новой задачи» | Создаёт стандартный шаблон для NTF-контекста |

При необходимости — указать дополнительные языки. Название шаблона автоматически = название категории.

После создания шаблон доступен через кнопку «Шаблон из списка».

#### Параметры привязки

Параметры привязки шаблона к категории:

| Параметр | Значения | Описание |
|----------|----------|----------|
| **Тип клиента** | `mobile` | Только в мобильном приложении |
| \ | `web` | Только в веб-интерфейсе (в настоящее время не используется) |
| \ | `all` | Везде (фактически = `mobile`) |
| **Контекст** | `NTF` | Карточка новой задачи (при создании) |
| \ | `MTF` | Карточка задачи (при просмотре) |
| \ | `Cell` | Краткое представление (в списке задач) |
| **Активность** | вкл/выкл | Временно отключить шаблон без удаления |
| **Смарт-фильтр** | условия | Условия для использования шаблона. Если ни одно условие не выполнено — используется стандартный шаблон приложения |

#### Динамические шаблоны

Для динамического шаблона кнопка редактора открывает окно настроек (секции → блоки → элементы, порядок кнопками со стрелками). Кнопка «JSON» — просмотр и редактирование в формате JSON.

---

## 4. Навигация onTap

Через onTap-события настраивается навигация в мобильном приложении: переход в карточку задачи, логика перехода по плиткам, меню создания (addButton, rightBarButton).

### Ключи onTap

Ключи объекта onTap:

| Ключ | Значение | Описание |
|------|----------|----------|
| `id` | Число (234) | ID объекта (категории, пользователя, задачи, таблицы BI и т.д.) |
| `action` | См. таблицу ниже | Действие при нажатии |
| `context` | `"название шаблона контекста"` | Открыть определённый контекст объекта из его шаблона |
| `epId` | Число (2345) | ID ДП, из которого берётся значение для обработки. Если `id` не задан явно — значение берётся из указанного ДП. |
| `dataSourceUrl` | `"/app/v1.2/api/publications/action/mob-rest-basket"` | Ссылка на пользовательский TaskSource (публикацию, отдающую ленту задач) |
| `type` | См. типы лент | Тип ленты задач или комментариев |
| `items` | Массив объектов | Список пунктов модального меню |

#### Правило epId

Если указан `action`, но не указан `id`:
- `openTaskSource` → id берётся из ДП с epId
- `openTask` → номер задачи из ДП с epId
- `openLink` → ссылка из ДП с epId

### Значения action (более 22)

Доступные значения ключа `action`:

| Action | Описание |
|--------|----------|
| `openTask` | Открыть карточку задачи (по умолчанию) |
| `openUsedBlock` | Открыть список задач блока «Используется» из категории |
| `forbidOpen` | Запрет перехода при нажатии на ячейку задачи |
| `openSignatures` | Открыть список подписей |
| `openCommentsFeed` | Открыть ленту комментариев |
| `openNewTask` | Открыть форму создания новой задачи |
| `openTaskSource` | Открыть TaskSource. Используется с `dataSourceUrl` |
| `openSubcategory` | Открыть категорию. Используется с `id` |
| `openTaskFeed` | Открыть ленту задач указанного типа |
| `openUserProfile` | Открыть профиль пользователя |
| `showAlert` | Показать уведомление |
| `openLink` | Открыть ссылку |
| `openCallHistory` | Открыть историю звонков ВКС |
| `openVideoConferenceRoom` | Открыть ВКС-комнату |
| `openCalendar` | Открыть календарь встреч |
| `openMenu` | Открыть модальное меню со списком пунктов (используется с `items`) |
| `openMail` | Открыть почтовый клиент. Аккаунты добавляются в веб-версии 1Формы |
| `openCategoryTree` | Открыть дерево категорий |
| `scanCode` | Сканер: QR + EAN13 (все коды) |
| `scanEAN13Code` | Сканер: только EAN13 |
| `scanQRCode` | Сканер: только QR |
| `openGlobalSearch` | Глобальный поиск по задачам/чатам/сотрудникам |
| `openTaskHistory` | История задач текущего пользователя |
| `openDisk` | Дисковое хранилище текущего пользователя |

### Типы лент (type)

Доступные значения ключа `type` (тип ленты):

| Значение | Описание |
|----------|----------|
| `All` | Все задачи |
| `New` | Новые |
| `Created` | Созданные |
| `Discussions` | Обсуждения |
| `Owner` | Заказчик |
| `Performer` | Исполнитель |
| `Favorites` | Избранные |
| `Overdue` | Просроченные |
| `LastCommented` | Последние с комментариями |
| `PinnedToChat` | Все закреплённые переписки |
| `PrivateChat` | Личные чаты |
| `GroupChat` | Групповые чаты |

### Пример interactions (longTap)

Пример обработки долгого нажатия (`longTap`):

```json
{
  "longTap": {
    "action": "openMenu",
    "items": [
      {"title": "История", "action": "openTaskSource", "id": 67, "icon": "RecentTasks"},
      {"title": "Все категории", "action": "openCategoryTree", "icon": "AllCategories"}
    ]
  }
}
```

---

## 5. Push-уведомления

> Push-уведомления для мобильных приложений настраиваются в домене notifications.
>
> См. [Уведомления — администрирование](https://help.1forma.ru/domains/notifications/admin.md) — конфигурация APNs/FCM, сертификаты iOS, отправка с сервера.
>
> Бизнес-логика — [Уведомления — бизнес-логика](https://help.1forma.ru/domains/notifications/business.md).

Ключи и сертификаты мобильных приложений администратор ведёт на странице **«МП» → «Настройка PUSH»** (`/administration/push-settings`): в гриде видны подключённые приложения и их идентификаторы, ключ скачивается из строки; при создании выбирается тип приложения из справочника и прикладывается файл ключа или сертификата, при редактировании файл можно заменить, не выбранный — сохраняется прежний. Автоформа прежнего вида осталась доступна по прямому адресу. Подробности — в [администрировании уведомлений](https://help.1forma.ru/domains/notifications/admin.md).

---

## 6. Политики паролей мобильного приложения

Доступ в мобильное приложение можно защитить дополнительным паролем (помимо пароля учётной записи). Пароль запрашивается при каждом входе в МП.

### Типы политик

Доступные типы парольных политик:

| Политика | Описание |
|----------|----------|
| Пароль не обязателен | Дополнительный пароль не запрашивается |
| 4 цифры | 4-значный PIN-код |
| 6 цифр | 6-значный PIN-код |
| Буквенно-цифровой пароль | Произвольный пароль по регулярному выражению |

При выборе «Буквенно-цифровой пароль» — заполнить поля:

| Поле | Описание | Пример |
|------|----------|--------|
| Регулярное выражение | Паттерн валидации | `((?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%]).{6,20})` |
| Сообщение | Текст ошибки для пользователя | `Пароль должен содержать от 6 до 20 символов, включая цифры, строчные и прописные буквы, а также один из спец символов @ # $ %` |

### Привязка к группам

Политики привязываются к **группам пользователей** (кнопка «Группы» в строке политики). Для каждой группы — отдельная запись.

> **Если пользователь входит в несколько групп с разными политиками — применяется наиболее строгая политика.**

### Добавление политики

Чтобы добавить политику пароля:

1. Нажать «Создать».
2. Выбрать тип политики.
3. Для буквенно-цифрового — заполнить regex и сообщение.
4. Кнопка «Группы» → добавить привязки групп.

---

## 7. Статистика устройств

Страница «Статистика использования мобильных приложений» — мониторинг установок, сессий и активности пользователей. Она открывается из пунктов меню администрирования «Статистика использования МП» и «МП» (маршрут `/administration/mobile-client-stat`). Таблица тех же данных в автоадминке доступна по прямому адресу `/admin-ds/forms/{alias}/grid` для форм `mobile-client-stat` и `log-mobile`.

### Типы данных

Типы собираемых данных статистики:

| Тип | Описание |
|-----|----------|
| **Install** | Установка МП и обновления |
| **Session** | Сессии пользователей |
| **Work** | Действия пользователей в МП (просмотр ленты, задач, комментариев, чатов и т.д.) |

### Поля записи

Каждая запись статистики содержит:

- Платформа (iOS / Android)
- Версия приложения
- Версия ОС (прошивка)
- Дата последнего входа
- Приложение — клиент, от которого пришло событие

Колонка «Приложение» хранит числовой код клиента (`MobileClientStats.AppID`) и привязана к системному перечислению `AppType`, поэтому в ячейке выводится имя члена перечисления, а не число. Состав членов: `OneFChat` (1), `AndroidOneFChat` (3), `HuaweiOneFChat` (4), `RustoreOneFChat` (5), `OneFChat_AppStore_1f` (8), `DirectorsClub` (9), `DirectorsClub_AppStore_1f` (10), `iOSMobile_1`…`iOSMobile_5` (12, 14, 16, 18, 20) и парные им `iOSMobile_N_AppStore` (13, 15, 17, 19, 21), `AnyClient` (22), `Web` (23). Имена членов не переведены — во всех языках интерфейса показывается латинский идентификатор. Если в записи встретился код, которого в перечислении нет, в ячейке остаётся исходное число.

Над таблицей есть переключатель типа логов: «Все» (по умолчанию), «WEB» — только события веб-версии, «МП» — только события мобильных приложений. Телеметрию присылает и веб-клиент, поэтому в одной таблице собраны события обоих видов; переключатель задаёт отбор по колонке «Приложение», собственного фильтра у этой колонки нет.

Записи отображаются в обратном хронологическом порядке (последние — сверху). Сортировка изменяется кликом по заголовку колонки.

> Все данные — **только для чтения**.

---

## 8. Геолокация

Геолокация собирает координаты пользователей с мобильных устройств и отображает их на карте в виде траекторий (провайдер — Microsoft Bing).

> ⚠️ Доступно только в **брендированном мобильном приложении** (white-label).

**Путь:** Администрирование → Мобильное приложение → Геоданные

### Предварительные требования

Перед включением геолокации выполните:

1. Настроить **Bing API-ключ** в Общих настройках → «Провайдер карт» (см. [Системные настройки](https://help.1forma.ru/domains/system/admin.md)).
2. Настроить группу отслеживания и параметры сбора (см. ниже).
3. В **профилях пользователей** группы отслеживания не должен быть включён флаг «Не использовать геолокацию».
4. На мобильных устройствах пользователей выдать **разрешение на передачу геоданных**.
5. В БД должна существовать хранимая процедура **`tc_LocationReport`**.

### Параметры сбора геоданных

Параметры сбора геоданных задаются в настройках группы отслеживания:

| Параметр | Тип | Описание |
|----------|-----|----------|
| **Группа для отслеживания** | Группа пользователей | Группа, для которой автоматически включается сбор координат при входе через МП. Если не задана — автоматический сбор не запускается. |
| **Группа-администратор** | Группа пользователей | Группа, которой разрешён просмотр истории местоположения всех пользователей. |
| **Интервал слежения** (начало / конец) | Время суток | Диапазон, в котором ведётся сбор (только в рабочие дни). Логика: начало < конца → сбор внутри промежутка (09:00–19:00); начало > конца → сбор «снаружи» (19:00–09:00); начало = концу → круглосуточно. Незаполненные поля — сбор не ведётся (предпочтительнее отключать флажками ниже). |
| **Хранить геоданные, дней** | Число | Срок хранения собранных точек в системе. |
| **Собирать при активных действиях** | Флажок | Отправка координат при активных действиях в задаче: изменение ДП, переход по маршруту, отправка сообщения, IP-звонок. |
| **Собирать периодически** | Флажок | Отправка по таймеру с интервалом из поля «Частота отправки». |
| **Показывать настройки в МП** | Флажок | Пользователь видит параметры сбора в настройках мобильного приложения. |
| **Частота логирования, мин** | Число | Интервал (в минутах), с которым координаты фиксируются в журнале устройства. |
| **Частота отправки на сервер, мин** | Число | Интервал (в минутах), с которым координаты отправляются на сервер. |
| **Смарт-выражение** | Смарт-выражение | Возвращает строку с параметрами для всплывающего окна на карте (по клику на точку траектории). |

> ⚠️ При изменении состава группы отслеживания или любых других настроек сбора всем участникам группы-администратора отправляются «тихие» push-уведомления (без звукового сигнала).

### Отчёт геолокации

SPA-ссылка: `/spaex.aspx/geo-location/history`. Данные формируются хранимой процедурой `tc_LocationReport` (параметры: `@userId`, `@filter` в XML — `DateFrom`, `DateTo`, `group`, `user`).

![Отчёт геолокации: траектории перемещений сотрудников на карте](https://help.1forma.ru/help-images/mobile/geo_report.png)

---

## CustomSettings — глобальные ключи мобильного клиента

Глобальные ключи CustomSettings, влияющие на мобильный клиент:

| Ключ | Тип | Назначение |
|------|-----|------------|
| `MobileAppSettings.mspaByDefault` | bool | Если `true` — в МП в боковом меню «Настройки» **скрывается** кнопка «Перейти в Desktop версию». Если `false` — кнопка отображается |
| `MobileAppSettings.openInBrowserDomains` | array | Список доменов (без `https://`), для которых ссылки из МП открываются во **внешнем** браузере устройства, а не во встроенном WebView. Можно указывать и более узкие варианты с путём (`2ip.ru/article/privat`): тогда перехватываются только ссылки с этим путём, а ссылки с базовым доменом продолжают открываться внутри МП. Перехват действует во всех местах приложения. Пример: `["2ip.ru","ya.ru"]` |
| `MobileAppSettings.EmptyFeedPlaceholderURL` | string (URL) | Картинка-заглушка пустой ленты задач. Если не задана — отображается слово «Пусто» |

![Экран настройки ключей MobileAppSettings](https://help.1forma.ru/help-images/mobile/mobile_app_settings_domains_admin.png)

Каталог остальных ключей CustomSettings (влияющих на интерфейс вне МП) — [Администрирование интерфейса](https://help.1forma.ru/domains/user-ui/admin.md).

### Глобальный плейсхолдер пустой ленты (EmptyFeedPlaceholderURL)

Ключ `MobileAppSettings.EmptyFeedPlaceholderURL` задаёт картинку, которая показывается вместо надписи «Пусто», когда список задач в МП пуст.

- Ключ действует **глобально** — на все источники данных задач (`taskSource`), плитки, ленты и контейнеры, у которых список на момент отрисовки пуст. Переопределения на отдельную ленту (per-feed override) нет.
- Ресурс должен быть доступен **по анонимной ссылке**, без авторизации, — иначе картинка в МП не загрузится.
- Формат — `PNG` или `JPG`. Рекомендуется квадратное изображение (например, `512×512`): картинка масштабируется внутри плейсхолдера, поэтому вытянутые «полосы» лучше не использовать.
- Видимость самой плитки при нулевом счётчике регулирует не этот ключ, а `emptyContentTitle` / `hideOnZeroCount` шаблона блока, — настройку плейсхолдера имеет смысл рассматривать совместно с ними.
- Изменение применяется после повторного входа пользователя в МП (или при следующем получении конфигурации с сервера).

```json
{
  "EmptyFeedPlaceholderURL": "https://example.com/img-public/Guest/empty.png"
}
```

---

## Связанные документы

См. также:

- [Мобильное приложение — бизнес-логика](https://help.1forma.ru/domains/mobile/business.md)
- [Мобильное приложение — шаблоны задач и блоков](https://help.1forma.ru/domains/mobile/mobile-templates.md) — полный справочник

- [Контейнеры](https://help.1forma.ru/domains/mobile/reference/containers.md) — модель контейнеров, таблицы БД, наследование настроек
- [Источники данных задач](https://help.1forma.ru/domains/mobile/reference/tasksources.md)
- [Доступ и авторизация](https://help.1forma.ru/domains/mobile/reference/access.md)
- [Уведомления — администрирование](https://help.1forma.ru/domains/notifications/admin.md) — push-уведомления
- [Уведомления — бизнес-логика](https://help.1forma.ru/domains/notifications/business.md)
