# Telegram-бот

# Техническая документация: Telegram-бот системы согласований

<span style="color: rgb(34, 34, 34); font-family: -apple-system, 'system-ui', 'Segoe UI', Oxygen, Ubuntu, Roboto, Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; font-size: 2.8275em; font-weight: 400;">Оглавление</span>

1. Техническое задание
2. Структура репозитория (package map)
3. Полная модель данных
4. Пакет `approvalflow` — дерево согласования и реестр тем
5. Пакет `state` — состояние диалога в Redis
6. `Handler` — инициализация и главное меню
7. Прохождение дерева — `HandleCallback`, `HandleTextInput`, `HandleBackCallback`
8. Цепочка дополнительных шагов — `continueFlowAfterInput`
9. Выбор согласующего (ручной и по роли)
10. Наблюдатели
11. Делегирование обязанностей
12. `submitApproval` — создание заявки, построчно
13. Решение согласующего — `handleDecision`
14. `processNextStepOrComplete`
15. Дополнительные согласующие (`add_approver.go`)
16. Задачи исполнителей (`tasks.go`)
17. Отзыв заявок
18. Уведомления (`Notifier`)
19. Устойчивость бота (прокси, ретраи)
20. `scheduler` — ежедневная сводка
21. Каталог `callback_data`
22. Каталог ключей Redis
23. Журнал багов с кодом до/после

---

## 0. Техническое задание: дерево тем согласования

Источник: карта согласований, содержащая полный перечень категорий и тем согласования с указанием инициаторов, согласующих и наблюдателей на момент постановки задачи.

> Обозначения: **Инициаторы** — кто может подавать заявку по данной ветке; **Согласующий N** — кто и в каком порядке принимает решение (порядковый номер соответствует шагу в последовательной цепочке согласования); **Наблюдатели** — кто получает уведомление о заявке без права решения.

Итоговое дерево включает 26 категорий верхнего уровня:

- Согласование отпусков\\отгулов
- Внебюджетные расходы
- Внебюджетные расходы ПЭТ Лайн
- Возвраты
- Изменение клиентов в ОКБ и 1С
- Заказ товаров
- Отгрузки на СОХ
- Паспорт сделки
- Ставки логистика
- Поступления по приходным документам
- Доставка клиентам\\на склад
- В. Отгрузки
- Менеджерские расходы
- Отгрузки
- Нестандартные условия договора поставки
- Вакансии
- Ставки доставки АП
- Утверждение фрилансеров
- Выход в нерабочий день
- Долгосрочные условия ОТК
- Остаток на кассах
- Продажи по клиенту
- Проведенные расходы по менеджеру
- Согласование удаленной работы
- Смена условий автоматического согласования сделок
- Утверждение оплат безнал

---

## Полное дерево категорий и тем

- Согласование отпусков\\отгулов 
    - Отгул 
        - На один день 
            - Весь день 
                - В счёт отпуска 
                    - Инициаторы: 
                        - Все
                    - Согласующий 1: 
                        - Непосредственный руководитель
                    - Наблюдатели: 
                        - Демченко Елена
                        - Вялкова Анна
                        - Шепко Лия
                - За свой счёт 
                    - Инициаторы: 
                        - Все
                    - Согласующий 1: 
                        - Непосредственный руководитель
                    - Наблюдатели: 
                        - Демченко Елена
                        - Вялкова Анна
                        - Шепко Лия
            - Частично 
                - Инициаторы: 
                    - Все
                - Согласующий 1: 
                    - Непосредственный руководитель
                - Наблюдатели: 
                    - Демченко Елена
                    - Вялкова Анна
                    - Шепко Лия
        - Диапазон дат 
            - Весь день 
                - В счёт отпуска 
                    - Инициаторы: 
                        - Все
                    - Согласующий 1: 
                        - Непосредственный руководитель
                    - Наблюдатели: 
                        - Демченко Елена
                        - Вялкова Анна
                        - Шепко Лия
                - За свой счёт 
                    - Инициаторы: 
                        - Все
                    - Согласующий 1: 
                        - Непосредственный руководитель
                    - Наблюдатели: 
                        - Демченко Елена
                        - Вялкова Анна
                        - Шепко Лия
            - Частично 
                - Инициаторы: 
                    - Все
                - Согласующий 1: 
                    - Непосредственный руководитель
                - Наблюдатели: 
                    - Демченко Елена
                    - Вялкова Анна
                    - Шепко Лия
        - Несколько дней 
            - Весь день 
                - В счёт отпуска 
                    - Инициаторы: 
                        - Все
                    - Согласующий 1: 
                        - Непосредственный руководитель
                    - Наблюдатели: 
                        - Демченко Елена
                        - Вялкова Анна
                        - Шепко Лия
                - За свой счёт 
                    - Инициаторы: 
                        - Все
                    - Согласующий 1: 
                        - Непосредственный руководитель
                    - Наблюдатели: 
                        - Демченко Елена
                        - Вялкова Анна
                        - Шепко Лия
            - Частично 
                - Инициаторы: 
                    - Все
                - Согласующий 1: 
                    - Непосредственный руководитель
                - Наблюдатели: 
                    - Демченко Елена
                    - Вялкова Анна
                    - Шепко Лия
    - Отпуск 
        - На один день 
            - Весь день 
                - В счёт отпуска 
                    - Инициаторы: 
                        - Все
                    - Согласующий 1: 
                        - Непосредственный руководитель
                    - Наблюдатели: 
                        - Демченко Елена
                        - Вялкова Анна
                        - Шепко Лия
                - За свой счёт 
                    - Инициаторы: 
                        - Все
                    - Согласующий 1: 
                        - Непосредственный руководитель
                    - Наблюдатели: 
                        - Демченко Елена
                        - Вялкова Анна
                        - Шепко Лия
            - Частично 
                - Инициаторы: 
                    - Все
                - Согласующий 1: 
                    - Непосредственный руководитель
                - Наблюдатели: 
                    - Демченко Елена
                    - Вялкова Анна
                    - Шепко Лия
        - Диапазон дат 
            - Весь день 
                - В счёт отпуска 
                    - Инициаторы: 
                        - Все
                    - Согласующий 1: 
                        - Непосредственный руководитель
                    - Наблюдатели: 
                        - Демченко Елена
                        - Вялкова Анна
                        - Шепко Лия
                - За свой счёт 
                    - Инициаторы: 
                        - Все
                    - Согласующий 1: 
                        - Непосредственный руководитель
                    - Наблюдатели: 
                        - Демченко Елена
                        - Вялкова Анна
                        - Шепко Лия
            - Частично 
                - Инициаторы: 
                    - Все
                - Согласующий 1: 
                    - Непосредственный руководитель
                - Наблюдатели: 
                    - Демченко Елена
                    - Вялкова Анна
                    - Шепко Лия
        - Несколько дней 
            - Весь день 
                - В счёт отпуска 
                    - Инициаторы: 
                        - Все
                    - Согласующий 1: 
                        - Непосредственный руководитель
                    - Наблюдатели: 
                        - Демченко Елена
                        - Вялкова Анна
                        - Шепко Лия
                - За свой счёт 
                    - Инициаторы: 
                        - Все
                    - Согласующий 1: 
                        - Непосредственный руководитель
                    - Наблюдатели: 
                        - Демченко Елена
                        - Вялкова Анна
                        - Шепко Лия
            - Частично 
                - Инициаторы: 
                    - Все
                - Согласующий 1: 
                    - Непосредственный руководитель
                - Наблюдатели: 
                    - Демченко Елена
                    - Вялкова Анна
                    - Шепко Лия
    - Больничный. Меняем на "официальный больничный". Следующим пунктом просим ввести дату открытия больничного листа. 
        - На один день 
            - Весь день 
                - В счёт отпуска 
                    - Инициаторы: 
                        - Все
                    - Согласующий 1: 
                        - Непосредственный руководитель
                    - Наблюдатели: 
                        - Демченко Елена
                        - Вялкова Анна
                        - Шепко Лия
                - За свой счёт 
                    - Инициаторы: 
                        - Все
                    - Согласующий 1: 
                        - Непосредственный руководитель
                    - Наблюдатели: 
                        - Демченко Елена
                        - Вялкова Анна
                        - Шепко Лия
                - Только оф. больничный 
                    - Инициаторы: 
                        - Все
                    - Согласующий 1: 
                        - Непосредственный руководитель
                    - Наблюдатели: 
                        - Демченко Елена
                        - Вялкова Анна
                        - Шепко Лия
            - Частично 
                - Инициаторы: 
                    - Все
                - Согласующий 1: 
                    - Непосредственный руководитель
                - Наблюдатели: 
                    - Демченко Елена
                    - Вялкова Анна
                    - Шепко Лия
        - Диапазон дат 
            - Весь день 
                - В счёт отпуска 
                    - Инициаторы: 
                        - Все
                    - Согласующий 1: 
                        - Непосредственный руководитель
                    - Наблюдатели: 
                        - Демченко Елена
                        - Вялкова Анна
                        - Шепко Лия
                - За свой счёт 
                    - Инициаторы: 
                        - Все
                    - Согласующий 1: 
                        - Непосредственный руководитель
                    - Наблюдатели: 
                        - Демченко Елена
                        - Вялкова Анна
                        - Шепко Лия
                - Официальный больничный 
                    - Инициаторы: 
                        - Все
                    - Согласующий 1: 
                        - Непосредственный руководитель
                    - Наблюдатели: 
                        - Демченко Елена
                        - Вялкова Анна
                        - Шепко Лия
            - Частично 
                - Инициаторы: 
                    - Все
                - Согласующий 1: 
                    - Непосредственный руководитель
                - Наблюдатели: 
                    - Демченко Елена
                    - Вялкова Анна
                    - Шепко Лия
        - Несколько дней 
            - Весь день 
                - В счёт отпуска 
                    - Инициаторы: 
                        - Все
                    - Согласующий 1: 
                        - Непосредственный руководитель
                    - Наблюдатели: 
                        - Демченко Елена
                        - Вялкова Анна
                        - Шепко Лия
                - За свой счёт 
                    - Инициаторы: 
                        - Все
                    - Согласующий 1: 
                        - Непосредственный руководитель
                    - Наблюдатели: 
                        - Демченко Елена
                        - Вялкова Анна
                        - Шепко Лия
                - Официальный больничный 
                    - Инициаторы: 
                        - Все
                    - Согласующий 1: 
                        - Непосредственный руководитель
                    - Наблюдатели: 
                        - Демченко Елена
                        - Вялкова Анна
                        - Шепко Лия
            - Частично 
                - Инициаторы: 
                    - Все
                - Согласующий 1: 
                    - Непосредственный руководитель
                - Наблюдатели: 
                    - Демченко Елена
                    - Вялкова Анна
                    - Шепко Лия
- Внебюджетные расходы 
    - Ф1 
        - ТМЦ (далее "Нужна ПП?") 
            - Да 
                - Инициаторы: 
                    - Турчина Варвара
                    - Горбачёва Оксана
                    - Демченко Елена
                    - Жуков Дмитрий
                    - Шведов Никита
                    - Романов Александр
                    - Свирень Максим
                    - Танашевич Анифе
                    - Щасливая Екатерина
                    - Шепко Лия
                    - Аблякимова Айше
                    - Халилов Дамур
                    - Анисимов Виталий
                    - Храпач Анастасия
                    - прикрепить файл
                - Согласующий 1: 
                    - Шепко Лия
                - Согласующий 2: 
                    - Тищенко Владимир
                - Наблюдатели: 
                    - Демченко Елена
                    - Вялкова Анна
                    - Жуков Дмитрий
                    - Сергатова Светлана
                    - Шведов Никита
                    - Романов Александр
                    - Рудник Алина
                - Исполнитель: 
                    - Рудь Анфиса
                    - задача 1: 
                        - Оплатить счет
                    - задача 2: 
                        - Отправить ПП сотруднику
                        - прикрепить файл
            - Нет 
                - Инициаторы: 
                    - Турчина Варвара
                    - Горбачёва Оксана
                    - Демченко Елена
                    - Жуков Дмитрий
                    - Шведов Никита
                    - Романов Александр
                    - Свирень Максим
                    - Танашевич Анифе
                    - Щасливая Екатерина
                    - Шепко Лия
                    - Аблякимова Айше
                    - Халилов Дамур
                    - Анисимов Виталий
                    - Храпач Анастасия
                    - прикрепить файл
                - Согласующий 1: 
                    - Шепко Лия
                - Согласующий 2: 
                    - Тищенко Владимир
                - Наблюдатели: 
                    - Демченко Елена
                    - Вялкова Анна
                    - Жуков Дмитрий
                    - Сергатова Светлана
                    - Шведов Никита
                    - Романов Александр
                    - Рудник Алина
                - Исполнитель: 
                    - Рудь Анфиса
                    - задача 1: 
                        - Оплатить счет
        - Расход (далее "Нужна ПП?") 
            - Да 
                - Инициаторы: 
                    - Турчина Варвара
                    - Горбачёва Оксана
                    - Демченко Елена
                    - Жуков Дмитрий
                    - Шведов Никита
                    - Романов Александр
                    - Свирень Максим
                    - Танашевич Анифе
                    - Щасливая Екатерина
                    - Шепко Лия
                    - Аблякимова Айше
                    - Халилов Дамур
                    - Анисимов Виталий
                    - Храпач Анастасия
                    - прикрепить файл
                - Согласующий 1: 
                    - Тищенко Владимир
                - Наблюдатели: 
                    - Демченко Елена
                    - Вялкова Анна
                    - Жуков Дмитрий
                    - Сергатова Светлана
                    - Шведов Никита
                    - Романов Александр
                    - Рудник Алина
                    - Шепко Лия
                - Исполнитель: 
                    - Рудь Анфиса
                    - задача 1: 
                        - Оплатить счет
                    - задача 2: 
                        - Отправить ПП сотруднику
                        - прикрепить файл
            - Нет 
                - Инициаторы: 
                    - Турчина Варвара
                    - Горбачёва Оксана
                    - Демченко Елена
                    - Жуков Дмитрий
                    - Шведов Никита
                    - Романов Александр
                    - Свирень Максим
                    - Танашевич Анифе
                    - Щасливая Екатерина
                    - Шепко Лия
                    - Аблякимова Айше
                    - Халилов Дамур
                    - Анисимов Виталий
                    - Храпач Анастасия
                    - прикрепить файл
                - Согласующий 1: 
                    - Тищенко Владимир
                - Наблюдатели: 
                    - Демченко Елена
                    - Вялкова Анна
                    - Жуков Дмитрий
                    - Сергатова Светлана
                    - Шведов Никита
                    - Романов Александр
                    - Рудник Алина
                    - Шепко Лия
                - Исполнитель: 
                    - Рудь Анфиса
                    - задача 1: 
                        - Оплатить счет
    - Ф2 
        - ТМЦ 
            - Инициаторы: 
                - Турчина Варвара
                - Горбачёва Оксана
                - Демченко Елена
                - Жуков Дмитрий
                - Шведов Никита
                - Романов Александр
                - Свирень Максим
                - Танашевич Анифе
                - Щасливая Екатерина
                - Шепко Лия
                - Аблякимова Айше
                - Халилов Дамур
                - Анисимов Виталий
                - Храпач Анастасия
            - Согласующий 1: 
                - Шепко Лия
            - Согласующий 2: 
                - Тищенко Владимир
            - Наблюдатели: 
                - Демченко Елена
                - Вялкова Анна
                - Жуков Дмитрий
                - Сергатова Светлана
                - Шведов Никита
                - Романов Александр
                - Рудник Алина
        - Расход 
            - Инициаторы: 
                - Турчина Варвара
                - Горбачёва Оксана
                - Демченко Елена
                - Жуков Дмитрий
                - Шведов Никита
                - Романов Александр
                - Свирень Максим
                - Танашевич Анифе
                - Щасливая Екатерина
                - Шепко Лия
                - Аблякимова Айше
                - Халилов Дамур
                - Анисимов Виталий
                - Храпач Анастасия
            - Согласующий 1: 
                - Тищенко Владимир
            - Наблюдатели: 
                - Демченко Елена
                - Вялкова Анна
                - Жуков Дмитрий
                - Сергатова Светлана
                - Шведов Никита
                - Романов Александр
                - Рудник Алина
                - Шепко Лия
    -
- Внебюджетные расходы ПЭТ Лайн 
    - Ф1 
        - ТМЦ 
            - Инициаторы: 
                - Пирожников Павел
            - Согласующий 1: 
                - Тищенко Владимир
            - Наблюдатели: 
                - Демченко Елена
                - Вялкова Анна
        - Расход 
            - Инициаторы: 
                - Пирожников Павел
            - Согласующий 1: 
                - Тищенко Владимир
            - Наблюдатели: 
                - Демченко Елена
                - Вялкова Анна
    - Ф2 
        - ТМЦ 
            - Инициаторы: 
                - Пирожников Павел
            - Согласующий 1: 
                - Тищенко Владимир
            - Наблюдатели: 
                - Демченко Елена
                - Вялкова Анна
        - Расход 
            - Инициаторы: 
                - Пирожников Павел
            - Согласующий 1: 
                - Тищенко Владимир
            - Наблюдатели: 
                - Демченко Елена
                - Вялкова Анна
- Возвраты 
    - Возврат поставщику 
        - Крым 
            - Инициаторы: 
                - Чекальский Александр
                - Шевченко Виталий
                - Макаренко Александр
                - Михайлова Татьяна
                - Петрунин Кирилл
                - Гацолаева Наталья
                - Федосенко Вероника
                - Федосенко Иван
                - Свирень Максим
                - Бояджан Сергей
            - Согласующий 1: 
                - Щасливая Екатерина
            - Согласующий 2: 
                - Тищенко Владимир
            - Наблюдатели: 
                - Великожон Татьяна
                - Жуков Дмитрий
                - Сергатова Светлана
                - Шведов Никита
                - Романов Александр
                - Рудник Алина
                - Демченко Елена
                - Вялкова Анна
        - Краснодар 
            - Инициаторы: 
                - Чекальский Александр
                - Шевченко Виталий
                - Макаренко Александр
                - Михайлова Татьяна
                - Петрунин Кирилл
                - Стуков Павел
                - Бондаренко Михаил
                - Гацолаева Наталья
                - Сыпков Станислав
                - Федосенко Вероника
                - Федосенко Иван
                - Пирожников Павел
            - Согласующий 1: 
                - Щасливая Екатерина
            - Согласующий 2: 
                - Макаренко Александр
            - Согласующий 3: 
                - Тищенко Владимир
            - Наблюдатели: 
                - Великожон Татьяна
                - Жуков Дмитрий
                - Сергатова Светлана
                - Шведов Никита
                - Романов Александр
                - Рудник Алина
                - Демченко Елена
                - Вялкова Анна
    - Продажа другим менеджером 
        - Крым 
            - выбор из списка менеджеров Крыма: 
                - Чекальский Александр
                - Шевченко Виталий
                - Макаренко Александр
                - Петрунин Кирилл
                - Федосенко Иван
                - Свирень Максим
                - Бояджан Сергей
                - Инициаторы: 
                    - Чекальский Александр
                    - Шевченко Виталий
                    - Макаренко Александр
                    - Михайлова Татьяна
                    - Петрунин Кирилл
                    - Гацолаева Наталья
                    - Федосенко Вероника
                    - Федосенко Иван
                    - Свирень Максим
                    - Бояджан Сергей
                - Согласующий 1: 
                    - выбранный в прошлом шаге менеджер
                - Согласующий 2: 
                    - Тищенко Владимир
                - Наблюдатели: 
                    - Великожон Татьяна
                    - Жуков Дмитрий
                    - Сергатова Светлана
                    - Шведов Никита
                    - Романов Александр
                    - Рудник Алина
                    - Демченко Елена
                    - Вялкова Анна
        - Краснодар 
            - выбор из списка менеджеров Краснодара: 
                - Макаренко Александр
                - Петрунин Кирилл
                - Стуков Павел
                - Бондаренко Михаил
                - Сыпков Станислав
                - Федосенко Иван
                - Пирожников Павел
                - Инициаторы: 
                    - Чекальский Александр
                    - Шевченко Виталий
                    - Макаренко Александр
                    - Михайлова Татьяна
                    - Петрунин Кирилл
                    - Стуков Павел
                    - Бондаренко Михаил
                    - Гацолаева Наталья
                    - Сыпков Станислав
                    - Федосенко Вероника
                    - Федосенко Иван
                    - Пирожников Павел
                - Согласующий 1: 
                    - выбранный в прошлом шаге менеджер
                - Согласующий 2: 
                    - Макаренко Александр
                - Согласующий 3: 
                    - Тищенко Владимир
                - Наблюдатели: 
                    - Великожон Татьяна
                    - Жуков Дмитрий
                    - Сергатова Светлана
                    - Шведов Никита
                    - Романов Александр
                    - Рудник Алина
                    - Демченко Елена
                    - Вялкова Анна
    - Самостоятельная продажа 
        - Крым 
            - Инициаторы: 
                - Чекальский Александр
                - Шевченко Виталий
                - Макаренко Александр
                - Михайлова Татьяна
                - Петрунин Кирилл
                - Гацолаева Наталья
                - Федосенко Вероника
                - Федосенко Иван
                - Свирень Максим
                - Бояджан Сергей
            - Согласующий 1: 
                - Тищенко Владимир
            - Наблюдатели: 
                - Великожон Татьяна
                - Жуков Дмитрий
                - Сергатова Светлана
                - Шведов Никита
                - Романов Александр
                - Рудник Алина
                - Демченко Елена
                - Вялкова Анна
        - Краснодар 
            - Инициаторы: 
                - Чекальский Александр
                - Шевченко Виталий
                - Макаренко Александр
                - Михайлова Татьяна
                - Петрунин Кирилл
                - Стуков Павел
                - Бондаренко Михаил
                - Гацолаева Наталья
                - Сыпков Станислав
                - Федосенко Вероника
                - Федосенко Иван
                - Пирожников Павел
            - Согласующий 1: 
                - Макаренко Александр
            - Согласующий 2: 
                - Тищенко Владимир
            - Наблюдатели: 
                - Великожон Татьяна
                - Жуков Дмитрий
                - Сергатова Светлана
                - Шведов Никита
                - Романов Александр
                - Рудник Алина
                - Демченко Елена
                - Вялкова Анна
- Изменение клиентов в ОКБ и 1С 
    - Поменять название 
        - Крым 
            - ОКБ 
                - Инициаторы: 
                    - Чекальский Александр
                    - Шевченко Виталий
                    - Макаренко Александр
                    - Михайлова Татьяна
                    - Петрунин Кирилл
                    - Гацолаева Наталья
                    - Федосенко Вероника
                    - Федосенко Иван
                    - Свирень Максим
                    - Бояджан Сергей
                    - прикрепить файл
                - Согласующий 1: 
                    - Тищенко Владимир
                - Наблюдатели: 
                    - Демченко Елена
                    - Татьяна Савойская
                    - Степанов Сергей
                    - Селифанова Эльза
                - Исполнитель: 
                    - Руднева Надежда
                    - задача 1: 
                        - Внести изменение в название клиента
            - Битрикс 
                - Инициаторы: 
                    - Чекальский Александр
                    - Шевченко Виталий
                    - Макаренко Александр
                    - Михайлова Татьяна
                    - Петрунин Кирилл
                    - Гацолаева Наталья
                    - Федосенко Вероника
                    - Федосенко Иван
                    - Свирень Максим
                    - Бояджан Сергей
                    - прикрепить файл
                - Согласующий 1: 
                    - Тищенко Владимир
                - Наблюдатели: 
                    - Демченко Елена
                    - Татьяна Савойская
                    - Степанов Сергей
                    - Селифанова Эльза
                - Исполнитель: 
                    - Руднева Надежда
                    - задача 1: 
                        - Внести изменение в название клиента
            - 1С 
                - Инициаторы: 
                    - Чекальский Александр
                    - Шевченко Виталий
                    - Макаренко Александр
                    - Михайлова Татьяна
                    - Петрунин Кирилл
                    - Гацолаева Наталья
                    - Федосенко Вероника
                    - Федосенко Иван
                    - Свирень Максим
                    - Бояджан Сергей
                    - прикрепить файл
                - Согласующий 1: 
                    - Тищенко Владимир
                - Наблюдатели: 
                    - Демченко Елена
                    - Татьяна Савойская
                    - Степанов Сергей
                    - Селифанова Эльза
                - Исполнитель: 
                    - Вялкова Анна
                    - задача 1: 
                        - Внести изменение в название клиента
            - Подтвердить выбор 
                - при выборе нескольких, ставить совокупность всех задач по выбранным кнопкам
        - Краснодар 
            - ОКБ 
                - Инициаторы: 
                    - Чекальский Александр
                    - Шевченко Виталий
                    - Макаренко Александр
                    - Михайлова Татьяна
                    - Петрунин Кирилл
                    - Стуков Павел
                    - Бондаренко Михаил
                    - Гацолаева Наталья
                    - Сыпков Станислав
                    - Федосенко Вероника
                    - Федосенко Иван
                    - Пирожников Павел
                    - прикрепить файл
                - Согласующий 1: 
                    - Макаренко Александр
                - Согласующий 2: 
                    - Тищенко Владимир
                - Наблюдатели: 
                    - Демченко Елена
                    - Татьяна Савойская
                    - Степанов Сергей
                    - Селифанова Эльза
                - Исполнитель: 
                    - Руднева Надежда
                    - задача 1: 
                        - Внести изменение в название клиента
            - Битрикс 
                - Инициаторы: 
                    - Чекальский Александр
                    - Шевченко Виталий
                    - Макаренко Александр
                    - Михайлова Татьяна
                    - Петрунин Кирилл
                    - Стуков Павел
                    - Бондаренко Михаил
                    - Гацолаева Наталья
                    - Сыпков Станислав
                    - Федосенко Вероника
                    - Федосенко Иван
                    - Пирожников Павел
                    - прикрепить файл
                - Согласующий 1: 
                    - Макаренко Александр
                - Согласующий 2: 
                    - Тищенко Владимир
                - Наблюдатели: 
                    - Демченко Елена
                    - Татьяна Савойская
                    - Степанов Сергей
                    - Селифанова Эльза
                - Исполнитель: 
                    - Руднева Надежда
                    - задача 1: 
                        - Внести изменение в название клиента
            - 1С 
                - Инициаторы: 
                    - Чекальский Александр
                    - Шевченко Виталий
                    - Макаренко Александр
                    - Михайлова Татьяна
                    - Петрунин Кирилл
                    - Стуков Павел
                    - Бондаренко Михаил
                    - Гацолаева Наталья
                    - Сыпков Станислав
                    - Федосенко Вероника
                    - Федосенко Иван
                    - Пирожников Павел
                    - прикрепить файл
                - Согласующий 1: 
                    - Макаренко Александр
                - Согласующий 2: 
                    - Тищенко Владимир
                - Наблюдатели: 
                    - Демченко Елена
                    - Татьяна Савойская
                    - Степанов Сергей
                    - Селифанова Эльза
                - Исполнитель: 
                    - Вялкова Анна
                    - задача 1: 
                        - Внести изменение в название клиента
            - Подтвердить выбор 
                - при выборе нескольких, ставить совокупность всех задач по выбранным кнопкам
    - Сменить менеджера 
        - Крым 
            - ОКБ 
                - Инициаторы: 
                    - Чекальский Александр
                    - Шевченко Виталий
                    - Макаренко Александр
                    - Михайлова Татьяна
                    - Петрунин Кирилл
                    - Гацолаева Наталья
                    - Федосенко Вероника
                    - Федосенко Иван
                    - Свирень Максим
                    - Бояджан Сергей
                    - прикрепить файл
                - Согласующий 1: 
                    - Тищенко Владимир
                - Наблюдатели: 
                    - Демченко Елена
                    - Татьяна Савойская
                    - Степанов Сергей
                    - Селифанова Эльза
                - Исполнитель: 
                    - Руднева Надежда
                    - задача 1: 
                        - Сменить менеджера клиента
            - Битрикс 
                - Инициаторы: 
                    - Чекальский Александр
                    - Шевченко Виталий
                    - Макаренко Александр
                    - Михайлова Татьяна
                    - Петрунин Кирилл
                    - Гацолаева Наталья
                    - Федосенко Вероника
                    - Федосенко Иван
                    - Свирень Максим
                    - Бояджан Сергей
                    - прикрепить файл
                - Согласующий 1: 
                    - Тищенко Владимир
                - Наблюдатели: 
                    - Демченко Елена
                    - Татьяна Савойская
                    - Степанов Сергей
                    - Селифанова Эльза
                - Исполнитель: 
                    - Руднева Надежда
                    - задача 1: 
                        - Сменить менеджера клиента
            - 1С 
                - Инициаторы: 
                    - Чекальский Александр
                    - Шевченко Виталий
                    - Макаренко Александр
                    - Михайлова Татьяна
                    - Петрунин Кирилл
                    - Гацолаева Наталья
                    - Федосенко Вероника
                    - Федосенко Иван
                    - Свирень Максим
                    - Бояджан Сергей
                    - прикрепить файл
                - Согласующий 1: 
                    - Тищенко Владимир
                - Наблюдатели: 
                    - Демченко Елена
                    - Татьяна Савойская
                    - Степанов Сергей
                    - Селифанова Эльза
                - Исполнитель: 
                    - Вялкова Анна
                    - задача 1: 
                        - Сменить менеджера клиента
            - Подтвердить выбор 
                - при выборе нескольких, ставить совокупность всех задач по выбранным кнопкам
        - Краснодар 
            - ОКБ 
                - Инициаторы: 
                    - Чекальский Александр
                    - Шевченко Виталий
                    - Макаренко Александр
                    - Михайлова Татьяна
                    - Петрунин Кирилл
                    - Стуков Павел
                    - Бондаренко Михаил
                    - Гацолаева Наталья
                    - Сыпков Станислав
                    - Федосенко Вероника
                    - Федосенко Иван
                    - Пирожников Павел
                    - прикрепить файл
                - Согласующий 1: 
                    - Макаренко Александр
                - Согласующий 2: 
                    - Тищенко Владимир
                - Наблюдатели: 
                    - Демченко Елена
                    - Татьяна Савойская
                    - Степанов Сергей
                    - Селифанова Эльза
                - Исполнитель: 
                    - Руднева Надежда
                    - задача 1: 
                        - Сменить менеджера клиента
            - Битрикс 
                - Инициаторы: 
                    - Чекальский Александр
                    - Шевченко Виталий
                    - Макаренко Александр
                    - Михайлова Татьяна
                    - Петрунин Кирилл
                    - Стуков Павел
                    - Бондаренко Михаил
                    - Гацолаева Наталья
                    - Сыпков Станислав
                    - Федосенко Вероника
                    - Федосенко Иван
                    - Пирожников Павел
                    - прикрепить файл
                - Согласующий 1: 
                    - Макаренко Александр
                - Согласующий 2: 
                    - Тищенко Владимир
                - Наблюдатели: 
                    - Демченко Елена
                    - Татьяна Савойская
                    - Степанов Сергей
                    - Селифанова Эльза
                - Исполнитель: 
                    - Руднева Надежда
                    - задача 1: 
                        - Сменить менеджера клиента
            - 1С 
                - Инициаторы: 
                    - Чекальский Александр
                    - Шевченко Виталий
                    - Макаренко Александр
                    - Михайлова Татьяна
                    - Петрунин Кирилл
                    - Стуков Павел
                    - Бондаренко Михаил
                    - Гацолаева Наталья
                    - Сыпков Станислав
                    - Федосенко Вероника
                    - Федосенко Иван
                    - Пирожников Павел
                    - прикрепить файл
                - Согласующий 1: 
                    - Макаренко Александр
                - Согласующий 2: 
                    - Тищенко Владимир
                - Наблюдатели: 
                    - Демченко Елена
                    - Татьяна Савойская
                    - Степанов Сергей
                    - Селифанова Эльза
                - Исполнитель: 
                    - Вялкова Анна
                    - задача 1: 
                        - Сменить менеджера клиента
            - Подтвердить выбор 
                - при выборе нескольких, ставить совокупность всех задач по выбранным кнопкам
    - Внести нового клиента 
        - Крым 
            - ОКБ 
                - Инициаторы: 
                    - Чекальский Александр
                    - Шевченко Виталий
                    - Макаренко Александр
                    - Михайлова Татьяна
                    - Петрунин Кирилл
                    - Гацолаева Наталья
                    - Федосенко Вероника
                    - Федосенко Иван
                    - Свирень Максим
                    - Бояджан Сергей
                    - прикрепить файл
                - Согласующий 1: 
                    - Тищенко Владимир
                - Наблюдатели: 
                    - Демченко Елена
                    - Татьяна Савойская
                    - Степанов Сергей
                    - Селифанова Эльза
                - Исполнитель: 
                    - Руднева Надежда
                    - задача 1: 
                        - Внести нового клиента
            - Битрикс 
                - Инициаторы: 
                    - Чекальский Александр
                    - Шевченко Виталий
                    - Макаренко Александр
                    - Михайлова Татьяна
                    - Петрунин Кирилл
                    - Гацолаева Наталья
                    - Федосенко Вероника
                    - Федосенко Иван
                    - Свирень Максим
                    - Бояджан Сергей
                    - прикрепить файл
                - Согласующий 1: 
                    - Тищенко Владимир
                - Наблюдатели: 
                    - Демченко Елена
                    - Татьяна Савойская
                    - Степанов Сергей
                    - Селифанова Эльза
                - Исполнитель: 
                    - Руднева Надежда
                    - задача 1: 
                        - Внести нового клиента
            - 1С 
                - Инициаторы: 
                    - Чекальский Александр
                    - Шевченко Виталий
                    - Макаренко Александр
                    - Михайлова Татьяна
                    - Петрунин Кирилл
                    - Гацолаева Наталья
                    - Федосенко Вероника
                    - Федосенко Иван
                    - Свирень Максим
                    - Бояджан Сергей
                    - прикрепить файл
                - Согласующий 1: 
                    - Тищенко Владимир
                - Наблюдатели: 
                    - Демченко Елена
                    - Татьяна Савойская
                    - Степанов Сергей
                    - Селифанова Эльза
                - Исполнитель: 
                    - Вялкова Анна
                    - задача 1: 
                        - Внести нового клиента
            - Подтвердить выбор 
                - при выборе нескольких, ставить совокупность всех задач по выбранным кнопкам
        - Краснодар 
            - ОКБ 
                - Инициаторы: 
                    - Чекальский Александр
                    - Шевченко Виталий
                    - Макаренко Александр
                    - Михайлова Татьяна
                    - Петрунин Кирилл
                    - Стуков Павел
                    - Бондаренко Михаил
                    - Гацолаева Наталья
                    - Сыпков Станислав
                    - Федосенко Вероника
                    - Федосенко Иван
                    - Пирожников Павел
                    - прикрепить файл
                - Согласующий 1: 
                    - Макаренко Александр
                - Согласующий 2: 
                    - Тищенко Владимир
                - Наблюдатели: 
                    - Демченко Елена
                    - Татьяна Савойская
                    - Степанов Сергей
                    - Селифанова Эльза
                - Исполнитель: 
                    - Руднева Надежда
                    - задача 1: 
                        - Внести нового клиента
            - Битрикс 
                - Инициаторы: 
                    - Чекальский Александр
                    - Шевченко Виталий
                    - Макаренко Александр
                    - Михайлова Татьяна
                    - Петрунин Кирилл
                    - Стуков Павел
                    - Бондаренко Михаил
                    - Гацолаева Наталья
                    - Сыпков Станислав
                    - Федосенко Вероника
                    - Федосенко Иван
                    - Пирожников Павел
                    - прикрепить файл
                - Согласующий 1: 
                    - Макаренко Александр
                - Согласующий 2: 
                    - Тищенко Владимир
                - Наблюдатели: 
                    - Демченко Елена
                    - Татьяна Савойская
                    - Степанов Сергей
                    - Селифанова Эльза
                - Исполнитель: 
                    - Руднева Надежда
                    - задача 1: 
                        - Внести нового клиента
            - 1С 
                - Инициаторы: 
                    - Чекальский Александр
                    - Шевченко Виталий
                    - Макаренко Александр
                    - Михайлова Татьяна
                    - Петрунин Кирилл
                    - Стуков Павел
                    - Бондаренко Михаил
                    - Гацолаева Наталья
                    - Сыпков Станислав
                    - Федосенко Вероника
                    - Федосенко Иван
                    - Пирожников Павел
                    - прикрепить файл
                - Согласующий 1: 
                    - Макаренко Александр
                - Согласующий 2: 
                    - Тищенко Владимир
                - Наблюдатели: 
                    - Демченко Елена
                    - Татьяна Савойская
                    - Степанов Сергей
                    - Селифанова Эльза
                - Исполнитель: 
                    - Вялкова Анна
                    - задача 1: 
                        - Внести нового клиента
            - Подтвердить выбор 
                - при выборе нескольких, ставить совокупность всех задач по выбранным кнопкам
- Заказ товаров 
    - На месяц 
        - Крым 
            - Инициаторы: 
                - Чекальский Александр
                - Шевченко Виталий
                - Макаренко Александр
                - Михайлова Татьяна
                - Петрунин Кирилл
                - Гацолаева Наталья
                - Федосенко Вероника
                - Федосенко Иван
                - прикрепить файлы
            - Согласующий 1: 
                - Великожон Татьяна
                - внести текст
            - Согласующий 2: 
                - Тищенко Владимир
            - Наблюдатели: 
                - Щасливая Екатерина
                - Степанов Сергей
            - Исполнитель: 
                - Великожон Татьяна
                - задача 1: 
                    - Внести заказ в таблицу
                    - отправить менеджеру сообщение НЕ "исполнитель завершил задачу", а "Заказ принят, следи за статусом в гугл-таблице"
        - Краснодар 
            - Инициаторы: 
                - Чекальский Александр
                - Шевченко Виталий
                - Макаренко Александр
                - Михайлова Татьяна
                - Петрунин Кирилл
                - Стуков Павел
                - Бондаренко Михаил
                - Гацолаева Наталья
                - Сыпков Станислав
                - Федосенко Вероника
                - Федосенко Иван
                - Пирожников Павел
                - прикрепить файлы
            - Согласующий 1: 
                - Великожон Татьяна
                - внести текст
            - Согласующий 2: 
                - Макаренко Александр
            - Наблюдатели: 
                - Щасливая Екатерина
                - Степанов Сергей
            - Исполнитель: 
                - Великожон Татьяна
                - задача 1: 
                    - Внести заказ в таблицу
                    - отправить менеджеру сообщение НЕ "исполнитель завершил задачу", а "Заказ принят, следи за статусом в гугл-таблице"
    - Дополнительный заказ 
        - Крым 
            - Инициаторы: 
                - Чекальский Александр
                - Шевченко Виталий
                - Макаренко Александр
                - Михайлова Татьяна
                - Петрунин Кирилл
                - Гацолаева Наталья
                - Федосенко Вероника
                - Федосенко Иван
                - прикрепить скриншоты
            - Согласующий 1: 
                - Великожон Татьяна
                - внести текст
            - Согласующий 2: 
                - Тищенко Владимир
            - Наблюдатели: 
                - Щасливая Екатерина
                - Степанов Сергей
            - Исполнитель: 
                - Великожон Татьяна
                - задача 1: 
                    - Внести заказ в таблицу
                    - отправить менеджеру сообщение НЕ "исполнитель завершил задачу", а "Заказ принят, следи за статусом в гугл-таблице"
        - Краснодар 
            - Инициаторы: 
                - Чекальский Александр
                - Шевченко Виталий
                - Макаренко Александр
                - Михайлова Татьяна
                - Петрунин Кирилл
                - Стуков Павел
                - Бондаренко Михаил
                - Гацолаева Наталья
                - Сыпков Станислав
                - Федосенко Вероника
                - Федосенко Иван
                - Пирожников Павел
                - прикрепить скриншоты
            - Согласующий 1: 
                - Великожон Татьяна
                - внести текст
            - Согласующий 2: 
                - Макаренко Александр
            - Наблюдатели: 
                - Щасливая Екатерина
                - Степанов Сергей
            - Исполнитель: 
                - Великожон Татьяна
                - задача 1: 
                    - Внести заказ в таблицу
                    - отправить менеджеру сообщение НЕ "исполнитель завершил задачу", а "Заказ принят, следи за статусом в гугл-таблице"
- Отгрузки на СОХ 
    - Реальная 
        - Крым 
            - Инициаторы: 
                - Чекальский Александр
                - Шевченко Виталий
                - Макаренко Александр
                - Михайлова Татьяна
                - Петрунин Кирилл
                - Гацолаева Наталья
                - Федосенко Вероника
                - Федосенко Иван
            - Согласующий 1: 
                - Шепко Лия
                - внести текст
            - Согласующий 2: 
                - Тищенко Владимир
            - Наблюдатели: 
                - Демченко Елена
                - Вялкова Анна
                - Жуков Дмитрий
                - Сергатова Светлана
                - Рудь Анфиса
                - Романов Александр
                - Рудник Алина
                - Шепко Лия
            - Исполнитель 1: 
                - Сергатова Светлана
                - задача 1: 
                    - Составить договор СОХ и акт приема-передачи с клиентом
                - задача 2: 
                    - Подписать договор СОХ и акт приема-передачи с клиентом и прикрепить этот файл далее
                    - прикрепить файл 
                        - Исполнитель 2: 
                            - Шепко Лия
                            - задача 1: 
                                - Сверить договор и внести данные о лимите в таблицу
                                - Исполнитель 3: 
                                    - Романов Александр
                                    - задача 1: 
                                        - Убедиться, что отгрузка на СОХ согласована, проведена и не задублирована в 1С
        - Краснодар 
            - Инициаторы: 
                - Чекальский Александр
                - Шевченко Виталий
                - Макаренко Александр
                - Михайлова Татьяна
                - Петрунин Кирилл
                - Стуков Павел
                - Бондаренко Михаил
                - Гацолаева Наталья
                - Сыпков Станислав
                - Федосенко Вероника
                - Федосенко Иван
                - Пирожников Павел
            - Согласующий 1: 
                - Шепко Лия
                - внести текст
            - Согласующий 2: 
                - Макаренко Александр
            - Согласующий 3: 
                - Тищенко Владимир
            - Наблюдатели: 
                - Демченко Елена
                - Вялкова Анна
                - Жуков Дмитрий
                - Сергатова Светлана
                - Рудь Анфиса
                - Романов Александр
                - Рудник Алина
                - Шепко Лия
            - Исполнитель 1: 
                - Сергатова Светлана
                - задача 1: 
                    - Составить договор СОХ и акт приема-передачи с клиентом
                - задача 2: 
                    - Подписать договор СОХ и акт приема-передачи с клиентом и прикрепить этот файл далее
                    - прикрепить файл 
                        - Исполнитель 2: 
                            - Шепко Лия
                            - задача 1: 
                                - Сверить договор и внести данные о лимите в таблицу
                                - Исполнитель 3: 
                                    - Романов Александр
                                    - задача 1: 
                                        - Убедиться, что отгрузка на СОХ согласована, проведена и не задублирована в 1С
    - Для лимита 
        - Крым 
            - Инициаторы: 
                - Чекальский Александр
                - Шевченко Виталий
                - Макаренко Александр
                - Михайлова Татьяна
                - Петрунин Кирилл
                - Гацолаева Наталья
                - Федосенко Вероника
                - Федосенко Иван
            - Согласующий 1: 
                - Шепко Лия
                - внести текст
            - Согласующий 2: 
                - Тищенко Владимир
            - Наблюдатели: 
                - Шепко Лия
            - Исполнитель 1: 
                - Сергатова Светлана
                - задача 1: 
                    - Составить договор СОХ и акт приема-передачи с клиентом
                - задача 2: 
                    - Подписать договор СОХ и акт приема-передачи с клиентом и прикрепить этот файл далее
                    - прикрепить файл 
                        - Исполнитель 2: 
                            - Шепко Лия
                            - задача 1: 
                                - Сверить договор и внести данные о лимите в таблицу
        - Краснодар 
            - Инициаторы: 
                - Чекальский Александр
                - Шевченко Виталий
                - Макаренко Александр
                - Михайлова Татьяна
                - Петрунин Кирилл
                - Стуков Павел
                - Бондаренко Михаил
                - Гацолаева Наталья
                - Сыпков Станислав
                - Федосенко Вероника
                - Федосенко Иван
                - Пирожников Павел
            - Согласующий 1: 
                - Шепко Лия
                - внести текст
            - Согласующий 2: 
                - Макаренко Александр
            - Согласующий 3: 
                - Тищенко Владимир
            - Наблюдатели: 
                - Шепко Лия
            - Исполнитель 1: 
                - Сергатова Светлана
                - задача 1: 
                    - Составить договор СОХ и акт приема-передачи с клиентом
                - задача 2: 
                    - Подписать договор СОХ и акт приема-передачи с клиентом и прикрепить этот файл далее
                    - прикрепить файл 
                        - Исполнитель 2: 
                            - Шепко Лия
                            - задача 1: 
                                - Сверить договор и внести данные о лимите в таблицу
- Паспорт сделки 
    - Крым 
        - Инициаторы: 
            - Чекальский Александр
            - Шевченко Виталий
            - Макаренко Александр
            - Михайлова Татьяна
            - Петрунин Кирилл
            - Гацолаева Наталья
            - Федосенко Вероника
            - Федосенко Иван
            - прикрепить файлы
        - Согласующий 1: 
            - Тищенко Владимир
        - Наблюдатели: 
            - Коршунова Александра
            - Шепко Лия
            - Танашевич Анифе
    - Краснодар 
        - Инициаторы: 
            - Чекальский Александр
            - Шевченко Виталий
            - Макаренко Александр
            - Михайлова Татьяна
            - Петрунин Кирилл
            - Стуков Павел
            - Бондаренко Михаил
            - Гацолаева Наталья
            - Сыпков Станислав
            - Федосенко Вероника
            - Федосенко Иван
            - Пирожников Павел
            - прикрепить файлы
        - Согласующий 1: 
            - Макаренко Александр
        - Согласующий 2: 
            - Тищенко Владимир
        - Наблюдатели: 
            - Коршунова Александра
            - Шепко Лия
            - Танашевич Анифе
    - Беларусь 
        - Инициаторы: 
            - Пирожников Павел
            - Гацолаева Наталья
            - прикрепить файлы
        - Согласующий 1: 
            - Пирожников Павел
        - Согласующий 2: 
            - Тищенко Владимир
        - Наблюдатели: 
            - Коршунова Александра
            - Шепко Лия
            - Танашевич Анифе
- Ставки логистика 
    - Разово 
        - Инициаторы: 
            - Танашевич Анифе
            - Минаджиева Залина
            - Чалышева Ление
            - прикрепить файлы (не обяз.)
        - Согласующий 1: 
            - Тищенко Владимир
        - Наблюдатели: 
            - Танашевич Анифе
            - Минаджиева Залина
            - Чалышева Ление
            - Храпач Анастасия
            - Шепко Лия
    - Надолго 
        - Инициаторы: 
            - Танашевич Анифе
            - Минаджиева Залина
            - Чалышева Ление
            - прикрепить файлы (не обяз.)
        - Согласующий 1: 
            - Тищенко Владимир
        - Наблюдатели: 
            - Танашевич Анифе
            - Минаджиева Залина
            - Чалышева Ление
            - Храпач Анастасия
            - Шепко Лия
        - Исполнитель 1: 
            - Коршунова Александра
            - задача 1: 
                - Внести изменения в гугл-таблицу Ставки логистики (с обязательным указанием, с какого срока начинает действовать ставка)
- Поступления по приходным документам 
    - Ф1 
        - Инициаторы: 
            - Щасливая Екатерина
            - Великожон Татьяна
            - Сергатова Светлана
            - Широков Михаил
            - прикрепить файлы (обяз.)
        - Согласующий 1: 
            - Щасливая Екатерина
            - внести текст, который будет виден и исполнителю тоже
        - Наблюдатели: 
            - Щасливая Екатерина
            - Великожон Татьяна
            - Демченко Елена
            - Вялкова Анна
            - Шведов Никита
        - Исполнитель 1: 
            - Сергатова Светлана
            - задача 1: 
                - Проверить и подтвердить, что приход проведен по 1С:Бухгалтерия
        - Исполнитель 2: 
            - Романов Александр
            - задача 1: 
                - Проверить и подтвердить, что приход проведен по 1С:УТ
    - Ф2 
        - Инициаторы: 
            - Щасливая Екатерина
            - Великожон Татьяна
            - Широков Михаил
            - прикрепить файлы (обяз.)
        - Согласующий 1: 
            - Щасливая Екатерина
            - внести текст, который будет виден и исполнителю тоже
        - Наблюдатели: 
            - Щасливая Екатерина
            - Великожон Татьяна
            - Демченко Елена
            - Вялкова Анна
            - Шведов Никита
        - Исполнитель 1: 
            - Романов Александр
            - задача 1: 
                - Проверить и подтвердить, что приход проведен по 1С:УТ
- Доставка клиентам\\на склад 
    - выбор менеджера/зав склада из списка согласующих: 
        - все менеджеры, помощники и зав складов
        - Инициаторы: 
            - Танашевич Анифе
            - Чалышева Ление
            - Минаджиева Залина
            - прикрепить файлы
        - Согласующий 1 (на выбор): 
            - Макаренко Александр
            - Петрунин Кирилл
            - Стуков Павел
            - Федосенко Иван
            - Сыпков Станислав
            - Бондаренко Михаил
            - Михайлова Татьяна
            - Широков Михаил
            - Чекальский Александр
            - Шевченко Виталий
            - Халилов Дамур
        - Наблюдатели: 
            - Танашевич Анифе
            - Щасливая Екатерина
            - Великожон Татьяна
            - Рудник Алина
            - Жуков Дмитрий
            - Сергатова Светлана
        - Исполнитель 1: 
            - Романов Александр
            - задача 1: 
                - Клиент забрал товар, менеджер подтвердил. Проверить и подтвердить, что отгрузка записана И ПРОВЕДЕНА в 1С
- В. Отгрузки 
    - Инициаторы: 
        - Чекальский Александр
        - Шевченко Виталий
        - Макаренко Александр
        - Михайлова Татьяна
        - Петрунин Кирилл
        - Стуков Павел
        - Бондаренко Михаил
        - Сыпков Станислав
        - Федосенко Иван
    - Согласующий 1: 
        - Тищенко Владимир
    - Наблюдатели: 
        - Демченко Елена
        - Вялкова Анна
        - Жуков Дмитрий
        - Шепко Лия
    - Исполнитель 1: 
        - Сергатова Светлана
        - задача 1: 
            - Создать реализацию и отправить клиенту на подпись
            - задача 2: 
                - Убедиться, что клиент подписал реализацию
                - задача 3: 
                    - Перепроверить, что клиент подписал реализацию и поступила оплата. Если подписано И оплата поступила, нажмите, чтобы подтвердить (менеджеру придет уведомление о том, что документ подписан и деньги получены)
- Менеджерские расходы 
    - Крым 
        - Инициаторы: 
            - Чекальский Александр
            - Шевченко Виталий
            - Макаренко Александр
            - Михайлова Татьяна
            - Петрунин Кирилл
            - Гацолаева Наталья
            - Федосенко Вероника
            - Федосенко Иван
            - Свирень Максим
            - Бояджан Сергей
        - Согласующий 1: 
            - Тищенко Владимир
        - Наблюдатели: 
            - Демченко Елена
            - Вялкова Анна
            - Романов Александр
            - Рудник Алина
            - Шепко Лия
    - Краснодар 
        - Инициаторы: 
            - Макаренко Александр
            - Михайлова Татьяна
            - Петрунин Кирилл
            - Стуков Павел
            - Бондаренко Михаил
            - Гацолаева Наталья
            - Сыпков Станислав
            - Федосенко Вероника
            - Федосенко Иван
        - Согласующий 1: 
            - Макаренко Александр
        - Согласующий 2: 
            - Тищенко Владимир
        - Наблюдатели: 
            - Демченко Елена
            - Вялкова Анна
            - Романов Александр
            - Рудник Алина
            - Шепко Лия
- Отгрузки 
    - МНОЖЕСТВЕННЫЙ выбор менеджера из списка наблюдателей: 
        - все менеджеры, помощники
        - Инициаторы: 
            - Романов Александр
            - Рудник Алина
            - прикрепить файлы (обяз.)
        - Согласующий 1: 
            - Коршунова Александра
            - сделать текстовую приписку для этого согласующего: 
                - Если не входит в рамки согласованного лимита, добавь руководителя соответствующего филиала к согласованию через кнопку "Добавить согласующего"
        - Наблюдатели (всегда логисты и Лия + на выбор из кнопки менеджер): 
            - Танашевич Анифе
            - Чалышева Ление
            - Минаджиева Залина
            - Шепко Лия
            - 
            - на выбор из предыдущего шага:
            - Макаренко Александр
            - Петрунин Кирилл
            - Стуков Павел
            - Федосенко Иван
            - Сыпков Станислав
            - Бондаренко Михаил
            - Михайлова Татьяна
            - Гацолаева Наталья
            - Чекальский Александр
            - Шевченко Виталий
- Нестандартные условия договора поставки 
    - Крым 
        - Инициаторы: 
            - Чекальский Александр
            - Шевченко Виталий
            - Макаренко Александр
            - Михайлова Татьяна
            - Петрунин Кирилл
            - Гацолаева Наталья
            - Федосенко Вероника
            - Федосенко Иван
            - Свирень Максим
            - Бояджан Сергей
            - прикрепить файлы
        - Согласующий 1: 
            - Аблякимова Айше
            - внести текст
        - Согласующий 2: 
            - Тищенко Владимир
        - Наблюдатели: 
            - Жуков Дмитрий
            - Сергатова Светлана
            - Шепко Лия
    - Краснодар 
        - Инициаторы: 
            - Макаренко Александр
            - Михайлова Татьяна
            - Петрунин Кирилл
            - Стуков Павел
            - Бондаренко Михаил
            - Гацолаева Наталья
            - Сыпков Станислав
            - Федосенко Вероника
            - Федосенко Иван
            - прикрепить файлы
        - Согласующий 1: 
            - Аблякимова Айше
            - внести текст
        - Согласующий 2: 
            - Макаренко Александр
        - Согласующий 3: 
            - Тищенко Владимир
        - Наблюдатели: 
            - Жуков Дмитрий
            - Сергатова Светлана
            - Михайлова Татьяна
            - Шепко Лия
    - Беларусь 
        - Инициаторы: 
            - Пирожников Павел
            - Гацолаева Наталья
            - прикрепить файлы
        - Согласующий 1: 
            - Аблякимова Айше
            - внести текст
        - Согласующий 2: 
            - Тищенко Владимир
        - Наблюдатели: 
            - Жуков Дмитрий
            - Сергатова Светлана
            - Михайлова Татьяна
            - Шепко Лия
- Вакансии 
    - выбор рук отдела из списка согласующих 
        - Инициаторы: 
            - Турчина Варвара
            - прикрепить файлы
        - Согласующий 1 (на выбор): 
            - Щасливая Екатерина
            - Танашевич Анифе
            - Халилов Дамур
            - Ковтун Игорь
            - Шепко Лия
            - Свирень Максим
            - Макаренко Александр
            - Жуков Дмитрий
            - Демченко Елена
            - Савойская Татьяна
            - Родюшкин Артем
            - Тищенко Владимир
        - Наблюдатели: 
            - Горбачёва Оксана
            - Стрижак Виолетта
            - Демченко Елена
            - Вялкова Анна
            - Шепко Лия
- Ставки доставки АП 
    - Инициаторы: 
        - Макаренко Александр
        - Михайлова Татьяна
        - Петрунин Кирилл
        - Стуков Павел
        - Бондаренко Михаил
        - Гацолаева Наталья
        - Сыпков Станислав
        - Федосенко Вероника
        - Федосенко Иван
    - Согласующий 1: 
        - Танашевич Анифе
    - Наблюдатели: 
        - Танашевич Анифе
        - Чалышева Ление
        - Минаджиева Залина
- Утверждение фрилансеров 
    - Инициаторы: 
        - Халилов Дамур
    - Согласующий 1: 
        - Тищенко Владимир
    - Наблюдатели: 
        - Танашевич Анифе
        - Вялкова Анна
        - Храпач Анастасия
- Выход в нерабочий день 
    - Инициаторы: 
        - Танашевич Анифе
        - Романов Александр
        - Шведов Никита
    - Согласующий 1: 
        - Тищенко Владимир
    - Наблюдатели: 
        - Халилов Дамур
        - Танашевич Анифе
        - Вялкова Анна
        - Храпач Анастасия
- Долгосрочные условия ОТК 
    - Крым 
        - Инициаторы: 
            - Чекальский Александр
            - Шевченко Виталий
            - Макаренко Александр
            - Михайлова Татьяна
            - Петрунин Кирилл
            - Гацолаева Наталья
            - Федосенко Вероника
            - Федосенко Иван
            - Свирень Максим
            - Бояджан Сергей
        - Согласующий 1: 
            - Тищенко Владимир
        - Наблюдатели: 
            - Шепко Лия
        - Исполнитель 1: 
            - Ковтун Игорь
            - задача 1: 
                - Зафиксировать согласованные условия в файле ОТК
    - Краснодар 
        - Инициаторы: 
            - Макаренко Александр
            - Михайлова Татьяна
            - Петрунин Кирилл
            - Стуков Павел
            - Бондаренко Михаил
            - Гацолаева Наталья
            - Сыпков Станислав
            - Федосенко Вероника
            - Федосенко Иван
        - Согласующий 1: 
            - Макаренко Александр
        - Согласующий 2: 
            - Тищенко Владимир
        - Наблюдатели: 
            - Шепко Лия
        - Исполнитель 1: 
            - Ковтун Игорь
            - задача 1: 
                - Зафиксировать согласованные условия в файле ОТК
    - Беларусь 
        - Инициаторы: 
            - Пирожников Павел
            - Гацолаева Наталья
        - Согласующий 1: 
            - Тищенко Владимир
        - Наблюдатели: 
            - Шепко Лия
        - Исполнитель 1: 
            - Ковтун Игорь
            - задача 1: 
                - Зафиксировать согласованные условия в файле ОТК
- Остаток на кассах 
    - выбор сотрудника из списка согласующих 
        - Инициаторы: 
            - Романов Александр
            - Рудник Алина
            - прикрепить файлы
        - Согласующий 1 (на выбор): 
            - все сотрудники
        - Наблюдатели: 
            - Демченко Елена
            - Вялкова Анна
- Продажи по клиенту 
    - выбор менеджера из списка согласующих 
        - Инициаторы: 
            - Романов Александр
            - Рудник Алина
            - Вялкова Анна
            - прикрепить файлы
        - Согласующий 1 (на выбор): 
            - Макаренко Александр
            - Петрунин Кирилл
            - Стуков Павел
            - Федосенко Иван
            - Сыпков Станислав
            - Бондаренко Михаил
            - Чекальский Александр
            - Шевченко Виталий
            - Свирень Максим
            - Бояджан Сергей
            - Пирожников Павел
        - Наблюдатели: 
            - Демченко Елена
            - Вялкова Анна
- Проведенные расходы по менеджеру 
    - выбор менеджера из списка согласующих 
        - Инициаторы: 
            - Вялкова Анна
            - прикрепить файлы
        - Согласующий 1 (на выбор): 
            - Макаренко Александр
            - Петрунин Кирилл
            - Стуков Павел
            - Федосенко Иван
            - Сыпков Станислав
            - Бондаренко Михаил
            - Чекальский Александр
            - Шевченко Виталий
            - Свирень Максим
            - Бояджан Сергей
            - Пирожников Павел
        - Наблюдатели: 
            - Демченко Елена
            - Вялкова Анна
- Согласование удаленной работы
- Смена условий автоматического согласования сделок 
    - повысить лимит дебеторской задолженности от Владимира лично 
        - Инициаторы: 
            - Макаренко Александр
            - Петрунин Кирилл
            - Стуков Павел
            - Федосенко Иван
            - Сыпков Станислав
            - Бондаренко Михаил
            - Чекальский Александр
            - Шевченко Виталий
            - Свирень Максим
            - Бояджан Сергей
            - Пирожников Павел
        - Согласующий 1: 
            - Тищенко Владимир
        - Наблюдатели: 
            - нет
        - Исполнитель: 
            - Шепко Лия
            - задача 1: 
                - Внести изменения в таблицу "Условия автоматического согласования"
    - увеличить кол-во возможных долгов по документам, сумм этих документов, кол-во возможных дней просрочки оплаты 
        - Инициаторы: 
            - Макаренко Александр
            - Петрунин Кирилл
            - Стуков Павел
            - Федосенко Иван
            - Сыпков Станислав
            - Бондаренко Михаил
            - Чекальский Александр
            - Шевченко Виталий
            - Свирень Максим
            - Бояджан Сергей
            - Пирожников Павел
        - Согласующий 1: 
            - Тищенко Владимир
        - Наблюдатели: 
            - нет
        - Исполнитель: 
            - Ковтун Игорь
            - задача 1: 
                - Внести изменения в гугл-таблицу
- Утверждение оплат безнал 
    - Нужна ПП? 
        - Да 
            - Инициаторы: 
                - Жуков Дмитрий
                - Свирень Максим
                - Танашевич Анифе
                - Шепко Лия
                - прикрепить файл (обяз)
            - Согласующий 1: 
                - Тищенко Владимир
            - Наблюдатели: 
                - Демченко Елена
                - Вялкова Анна
                - Жуков Дмитрий
                - Сергатова Светлана
                - Шведов Никита
                - Романов Александр
                - Рудник Алина
                - Шепко Лия
            - Исполнитель: 
                - Рудь Анфиса
                - задача 1: 
                    - Оплатить счет
                - задача 2: 
                    - Отправить ПП сотруднику
                    - прикрепить файл
        - Нет 
            - Инициаторы: 
                - Жуков Дмитрий
                - Свирень Максим
                - Танашевич Анифе
                - Шепко Лия
                - прикрепить файл (обяз)
            - Согласующий 1: 
                - Тищенко Владимир
            - Наблюдатели: 
                - Демченко Елена
                - Вялкова Анна
                - Жуков Дмитрий
                - Сергатова Светлана
                - Шведов Никита
                - Романов Александр
                - Рудник Алина
                - Шепко Лия
            - Исполнитель: 
                - Рудь Анфиса
                - задача 1: 
                    - Оплатить счет

## 1. Структура репозитория (package map)

```
telegram_service/
├── approvalflow/
│   ├── FlowNode / BuildTree / FindNode         — модель дерева
│   ├── DynamicTopic.go                          — тема категории, шаблоны, подписи
│   └── registry.go                              — Registry, LoadFromDB, алиасы
├── state/
│   └── state.go                                 — ApprovalFlowState, StateManager (Redis)
├── keyboard/
│   ├── *.go (BuildApprovalMenu, BuildApprovalStep, BuildMultiSelectStep, ...)
│   └── delegation_keyboard.go                   — 🆕 клавиатуры делегирования
├── handlers/approval/
│   ├── handler.go                                — Handler, NewHandler, HandleMenu*, HandleCallback, HandleTextInput, HandleBackCallback, continueFlowAfterInput
│   ├── decision.go                                — HandleDecision, handleDecision, processNextStepOrComplete
│   ├── add_approver.go                            — доп. согласующие: добавление, список категорий/заявок
│   ├── tasks.go                                   — задачи исполнителей, отзыв связанных задач
│   ├── delegation.go                              — 🆕 делегирование обязанностей
│   ├── helpers.go 
│   └── revoke.go 
├── lib/internally/redis/                          — обёртка над Redis-клиентом
└── ...

core/lib/external/tgkit/
└── client.go                                      — HTTP-клиент бота, прокси, ретраи

proxy/
└── main.go                                        — внешний прокси-сервис к Telegram Bot API

scheduler/
└── daily_reminder.go                               — ежедневная сводка (9:00 МСК, будни)

```

---

## 2. Полная модель данных

### 2.1. `ApprovalTopicCategory`

```go
type ApprovalTopicCategory struct {
    ID          *uint64
    Name        *string
    Code        *string
    Description *string
    IsActive    *bool
    CreatedAt   *time.Time
    UpdatedAt   *time.Time
}

```

Примеры реальных категорий, встретившихся в данных: `sickleave` («Больничный», ID=3), `vacation` («Отпуск», ID=2), `timeoff` («Отгул», ID=1). Алиас `absence` в `Registry` объединяет все три для целей проверки прав доступа в главном меню.

### 2.2. `ApprovalTopic`

```go
type ApprovalTopic struct {
    ID           *uint64
    CategoryID   *uint64
    Name         *string
    Code         *string
    ApprovalMode *string   // "sequential" | "any_of"

    DurationType          *string   // single_day | multi_day | date_range | sl_single_day | sl_date_range
    TimeType              *string   // full_day | partial
    PaymentType           *string   // own_expense | vacation_account | official
    Template              *string   // текст-подсказка формата ввода, напр. "22.02.2022"
    FirstApproverRoleCode *string

    AllowsFile             *bool
    AllowApproverSelection *bool
    AllowObserverSelection *bool
    AllowDelegationSelection *bool

    RequireApproverComment   *bool
    RequiresFile             *bool
    RequireObserverSelection *bool

    IsActive     *bool
    CreatedAt    *time.Time
    UpdatedAt    *time.Time
    Instructions *string
    Category     *ApprovalTopicCategory   // populated-связь
}

```

Реальный пример из БД (тема id=19, категория «Больничный»):

```json
{
  "id": 19, "category_id": 3,
  "name": "Больничный — диапазон официальный",
  "code": "sickleave_date_range_full_day_official",
  "ApprovalMode": "sequential",
  "duration_type": "date_range", "time_type": "full_day",
  "payment_type": "official",
  "template": "22.02.2022 - 25.02.2022",
  "allows_file": true, "requires_file": false,
  "allow_approver_selection": false, "allow_observer_selection": false,
  "require_approver_comment": false, "require_observer_selection": false,
  "is_active": true
}

```

### 2.3. `ApprovalFlowNode` (дерево согласования)

```go
type ApprovalFlowNode struct {
    ID              *uint64
    ParentID        *uint64   // nil = корневой узел
    CategoryID      *uint64
    Key             string    // технический ключ, участвует в callback_data
    Label           string    // видимый текст кнопки / источник {{.key_label}}
    DataKey         string    // "" если не кнопка с данными
    DataValue       string
    IsInput         bool
    InputKey        string    // обычно "content"
    InputHint       string
    IsMultiSelect   bool
    MultiSelectKey  string
    MultiSelectValue string
    TopicCode       string    // опционально: ограничение видимости узла по правам
    MessageTemplate *string   // только на корневом узле
    CodeTemplate    *string   // только на корневом узле
    Children        []*ApprovalFlowNode  // заполняется BuildTree()
}

```

**Инвариант**: `Key` корневого узла (`ParentID == nil`) **обязан** совпадать с `ApprovalTopicCategory.Code` — иначе `HandleCallback` не найдёт начало дерева при нажатии кнопки раздела в главном меню (симптом в логах: `node not found`).

### 2.4. `Approval`

```go
type Approval struct {
    ID            *uint64
    InitiatorID   *uint64
    TopicID       *uint64
    DepartmentID  *uint64
    Content       *string           // свободный текст, финальный ввод сотрудника
    Status        *string           // draft|pending|approved|rejected|revoked|revision
    Metadata      *string           // JSON: {"extra": {...}}
    RevisionCount int
    RevokedByID   *uint64
    RevokedAt     *time.Time
    CreatedAt     *time.Time
    UpdatedAt     *time.Time

    // populated-связи (не всегда присутствуют, зависит от запроса)
    Initiator  *User
    Topic      *ApprovalTopic
    Department *Department
    Steps      []*ApprovalStep
    Files      []*ApprovalFile
    RevokedBy  *User
}

```

`Metadata` — JSON вида `{"extra": {"time_type": "full_day", "absence_type": "sickleave", "payment_type": "official", "duration_type": "sl_date_range", "open_date": "11.07.2026"}}`. Обратите внимание: `open_date` присутствует не всегда и не является надёжным источником полного диапазона дат — единственный надёжный источник дат — свободнотекстовое поле `Content` (см. раздел про разбор дат в scheduler, §19).

### 2.5. `ApprovalStep`

```go
type ApprovalStep struct {
    ID                    *uint64
    ApprovalID            *uint64
    ApproverID            *uint64
    StepOrder             *int
    Status                *string   // waiting|pending|approved|rejected|cancelled_any_of|cancelled
    ApproverNameSnapshot  *string   // ФИО на момент назначения — не меняется при делегации
    ActedAt               *time.Time
    Comment                *string
    CreatedAt              *time.Time
    UpdatedAt               *time.Time
}

```

`ApproverNameSnapshot` заполняется реальным исполнившим действие пользователем (`actualExecutor.FullName`) в момент решения — то есть после одобрения делегатом в снапшоте окажется имя делегата, а не исходного согласующего.

### 2.6. `ApprovalAdditionalApprover`

```go
type ApprovalAdditionalApprover struct {
    ID          *uint64
    ApprovalID  *uint64
    ApproverID  *uint64
    AddedByID   *uint64
    Status      *string    // pending|approved|rejected
    Comment     *string
    ActedAt     *time.Time
}

```

Независим от `ApprovalStep` — у доп. согласующего **нет** собственной строки в `ApprovalStep` (источник одного из ключевых багов, §22).

### 2.7. `ApprovalTask` и `ApprovalTopicExecutor`

```go
type ApprovalTask struct {
    ID              *uint64
    ApprovalID      *uint64
    ExecutorID      *uint64
    TaskText        *string
    Status          *string  // pending|waiting|completed|cancelled
    StepOrder       *int
    RequireFile     *bool
    TopicExecutorID *uint64
    CreatedAt       *time.Time
    CompletedAt     *time.Time
}

type ApprovalTopicExecutor struct {
    ID            *uint64
    TopicID       *uint64
    UserID        *uint64
    TargetSystem  *string   // "all" | "okb" | "1c" — фильтр по выбранной сотрудником системе
    TaskText      *string
    RequireFile   *bool
}

```

`createTasksForApproval` создаёт по одной задаче на каждую `(система × исполнитель)` комбинацию, где `TargetSystem` совпадает (`"all"` matчит любую систему). Первая созданная задача сразу `pending`, остальные `waiting` — активируются последовательно по мере выполнения предыдущей (`activateNextTask`).

### 2.8. `UserHierarchy`

```go
type UserHierarchy struct {
    ID              *uint64
    SubordinateID   *uint64
    ApproverID      *uint64
    DepartmentID    *uint64
    TopicCategoryID *uint64   // взаимоисключающе с TopicID
    TopicID         *uint64
    Priority        int
}

```

Область действия правила определяется по заполненным полям: `TopicID` задан → правило только для этой темы; иначе `TopicCategoryID` задан → для всей категории; оба `nil` → глобальное правило («для всех тем согласований»).

### 2.9. `ApprovalDelegation` (реальная структура, прислана пользователем)

```go
type ApprovalDelegation struct {
    ID          *uint64
    DelegatorID *uint64    // not null
    DelegateID  *uint64    // not null
    CategoryID  *uint64    // nullable
    TopicID     *uint64    // nullable
    ApprovalID  *uint64    // 🆕 nullable — привязка к заявке-отсутствию
    ValidUntil  *time.Time // not null
    IsActive    *bool      // not null, default true
    NotifiedDay *bool      // not null, default false
    Notified2h  *bool      // not null, default false
    CreatedAt   *time.Time
    UpdatedAt   *time.Time

    Delegator *User
    Delegate  *User
    Category  *ApprovalTopicCategory
    Topic     *ApprovalTopic
}

```

### 2.10. Прочие сущности (кратко, по факту использования)

- `ApprovalComment { ApprovalID, UserID, Comment }`
- `ApprovalObserver` / `ApprovalAdditionalObserver { ApprovalID, UserID, AddedByID }`
- `ApprovalFile { ApprovalID, TaskID(nullable), FileBase64, FileName, AttachedByID }`
- `User { ID, TelegramID, Username, FullName, LanguageCode, DepartmentID, IsBlocked, IsFired }`
- `Department { ID, Name, Code, Description, IsActive }`

---

## 3. Пакет `approvalflow`

### 3.1. `FlowNode.BuildTree()` / `FindNode(tree, key)`

`Registry` хранит **плоский список** узлов на категорию; `BuildTree()` превращает его в дерево по `ParentID`. `FindNode` — рекурсивный поиск по `Key` внутри уже построенного дерева (используется и в `HandleCallback`, и в `HandleBackCallback`, и в `HandleTextInput` при переходе к следующему уровню после текстового ввода).

### 3.2. `DynamicTopic`

```go
type DynamicTopic struct {
    category *typescore.ApprovalTopicCategory
    nodes    []*typescore.ApprovalFlowNode

    codeTemplate    string
    messageTemplate string

    // 🆕 dataValueLabels: "data_key\x00data_value" -> Label узла с такими
    // DataKey/DataValue (или MultiSelectKey/MultiSelectValue).
    dataValueLabels map[string]string
}

```

**`NewDynamicTopic(category, nodes)`** — единственный проход по всем узлам: если узел корневой — забирает `CodeTemplate`/`MessageTemplate`; **независимо от этого** (без `break`, в отличие от исходной версии до правки) — если у узла есть `Label` и `DataKey`+`DataValue` (или `MultiSelectKey`+`MultiSelectValue`) — кладёт подпись в `dataValueLabels` под составным ключом `data_key + "\x00" + data_value`.

**`applyMessageTemplate(tmpl, initiatorName, data)`**:

1. Копирует `data` (собранная карта `data_key → data_value`) в `templateData`.
2. Добавляет `initiator_name`, `topic_name`.
3. `addLabelMappings(templateData, data)` — старый захардкоженный список соответствий (region: crimea→«Крым» и т.п., branch: f1→«Ф1» и т.п. — полный список хардкода не воспроизведён дословно в этой документации, см. исходный файл `DynamicTopic.go`).
4. **`addTreeLabelMappings(templateData, data)`** — 🆕 перекрывает значения из п.3, если для конкретного `(key, value)` есть узел дерева с `Label`. Для мультивыбора (значение вида `"a,b"`) при отсутствии точного совпадения разбивает по запятой и подписывает каждую часть отдельно, объединяя через `", "`.
5. Выполняет Go-шаблон (`text/template`), при ошибке парсинга/выполнения — `defaultMessage(initiatorName, data)` (запасной вариант).

**`TopicCodeFromCollected(collected)`** — если `code_template` непустой, выполняет его как Go-шаблон над `collected`; иначе — запасной вариант: сортирует ключи `collected` алфавитно и склеивает значения через `_`.

### 3.3. `Registry`

```go
type Registry struct {
    topics             map[string]Topic       // код темы → DynamicTopic
    order               []string
    topicCodeToCategory map[string]string      // алиасы
}

```

**`NewRegistry(ipc)`** — единственное место, где заполняются алиасы:

```go
r.topicCodeToCategory["timeoff"]   = "absence"
r.topicCodeToCategory["vacation"]  = "absence"
r.topicCodeToCategory["sickleave"] = "absence"

```

**`LoadFromDB(ctx)`** — пересобирает `topics`/`order` с нуля, **не трогает** `topicCodeToCategory` — алиасы, заданные в `NewRegistry`, переживают любое количество перезагрузок автоматически.

**`watchRegistryReload()`** (горутина, запускается в `NewHandler`) — опрашивает Redis-ключ `approval_flow:version` каждые 5 секунд; при изменении значения вызывает `LoadFromDB`. Админ-панель обязана вызывать `bumpFlowVersion()` после любой мутации дерева/тем/категорий — иначе бот продолжит работать со старой версией дерева до перезапуска.

---

## 4. Пакет `state`

### 4.1. `ApprovalFlowState` (реальная структура, прислана пользователем)

```go
type ApprovalFlowState struct {
    TopicCode               string
    NodeKey                 string
    Collected               map[string]string
    AwaitInput               bool
    InputKey                 string
    History                  []string
    AwaitFileInput            bool
    Files                     []FileAttachment
    FileStatusMsgID           int
    FilesStepCompleted        bool
    MultiSelected             map[string][]string
    AwaitMultiSelectConfirm   bool
    MultiSelectNodeKey        string

    AwaitFirstApproverSelection bool
    SelectedFirstApproverID     uint64

    AwaitApproverSelection bool
    SelectedApproverID     uint64

    AwaitObserverSelection bool
    ObserverSelectionDone  bool
    SelectedObserverIDs    []uint64

    // Делегирование
    AwaitDelegationChoice   bool
    AwaitDelegateSelection  bool
    DelegationSelectionDone bool
    SelectedDelegateID      uint64
}

type FileAttachment struct {
    Base64    string
    FileName  string
    MessageID int
}

```

### 4.2. `StateManager`

- Redis-ключ: `approval_flow:{telegramID}`.
- TTL: **30 минут** (`stateTTL`) — если пользователь бросил диалог дольше этого времени, состояние теряется, при попытке продолжить бот просит начать заново («⚠️ Состояние утеряно. Начните заново.»).
- `Get` трактует отсутствие ключа как штатную ситуацию (`nil, nil`), не как ошибку.
- Помимо `ApprovalFlowState`, `StateManager` управляет и другими, отдельными видами состояний, встретившимися по коду: `AddApproverFlowState` (флоу добавления доп. согласующего, ключи `SetAddApprover`/`GetAddApprover`/ `ClearAddApprover`), `AttachmentSession` (сессия прикрепления файла к задаче, поля `ApprovalID`, `TaskID`, `Files`, `Stage`), состояния комментариев (`GetCommentFlow`/`GetCommentReply`, `Stage: "await_text"`)

---

## 5. `Handler` — инициализация

```go
type Handler struct {
    ipc      *types.InternalProviderControl
    Registry *Registry
    States   *state.StateManager
}

func NewHandler(ipc *types.InternalProviderControl) *Handler {
    h := &Handler{
        ipc:      ipc,
        Registry: NewRegistry(ipc),
        States:   state.NewStateManager(ipc.RedisClient),
    }
    ctx, cancel := context.WithTimeout(context.Background(), variables.ContextTimeoutLong)
    if err := h.Registry.LoadFromDB(ctx); err != nil {
        logrus.Errorf("Failed to load topics from DB: %v", err)
    }
    cancel()

    go h.watchRegistryReload()   // см. §3.3
    return h
}

```

Обратите внимание: ошибка первичной загрузки дерева **только логируется**, не приводит к остановке бота — при полностью пустом/ неудачно загруженном реестре бот запустится, но не сможет провести ни одного согласования до успешной перезагрузки через `watchRegistryReload`.

### 5.1. Меню и подменю

- `HandleMenu(bot, chatID, telegramID)` → `HandleMenuPage(..., page=0, prevMessageID=0)`.
- `HandleMenuPage`: находит пользователя, вызывает `getAllowedTopicCodes`, фильтрует `h.Registry.All()` по разрешённым кодам, строит клавиатуру `keyboard.BuildApprovalMenu(visibleTopics, page)`. Если разрешённых тем нет — сообщение «У вас нет доступных тем для согласования» без клавиатуры.
- `HandleInitiatorSubmenu` / `HandleApproverSubmenu` / `HandleObserverSubmenu` — статичные подменю без БД-логики, просто разные клавиатуры (`BuildInitiatorSubmenu`/`BuildApproverSubmenu`/`BuildObserverSubmenu`).

### 5.2. `getAllowedTopicCodes(ctx, user)`

Возвращает `map[string]bool`. Логика:

1. Тянет разрешения (`Permission`, `action="create"`) пользователя.
2. Если разрешений нет вообще — возвращает пустую карту (доступа нет никуда).
3. Для каждой темы из реестра ищет категорию по коду; если это код `"absence"` (агрегирующий алиас) — **отдельно** проверяет три дочерние категории (`timeoff`/`vacation`/`sickleave`) — по прямому разрешению на категорию **или** по разрешению на конкретную тему внутри неё.
4. Для остальных (не-`absence`) тем — обычная проверка: разрешение на категорию целиком, либо на конкретную тему.

---

## 6. Прохождение дерева

### 6.1. `HandleCallback(bot, cq, topicCode, nodeKey)`

Формат входящего `callback_data`: `appr:{topicCode}:{nodeKey}`.

```
1. Отвечает на callback, удаляет предыдущее сообщение с кнопками.
2. topic := Registry.Get(topicCode)  — если не найдено, warn-лог и return.
3. flowState := States.Get(telegramID)
   isNew := flowState == nil
   если isNew — создаёт новый ApprovalFlowState{TopicCode, NodeKey, Collected: {}}
4. tree := topic.BuildTree(); node := FindNode(tree, nodeKey)
   если nil — warn-лог "node not found", return (см. инвариант §2.3 про Key корня)
5. если НЕ isNew — History = append(History, flowState.NodeKey)  (пуш текущего перед переходом)
6. если node.DataKey != "" — Collected[node.DataKey] = node.DataValue
7. если у node нет детей И это не IsInput — warn "leaf node without IsInput", return
   (защита от некорректно построенного дерева)
8. Особый случай: у узла РОВНО один ребёнок, и это IsInput —
   пропускает промежуточный экран, сразу переходит в режим ожидания
   текста: AwaitInput=true, InputKey=inputNode.InputKey, NodeKey=nodeKey (!),
   показывает InputHint, клавиатура BuildApprovalInputPrompt(topicCode).
   (NodeKey указывает на РОДИТЕЛЯ input-узла, не на сам input — важно
   для последующей логики в HandleTextInput, см. §6.2)
9. Иначе: NodeKey = nodeKey, State.Set(...)
   visibleChildren := filterNodesByAccess(ctx, telegramID, node.Children)
   если пусто после фильтрации — "⚠️ У вас нет доступа к подкатегориям
   этого раздела.", States.Clear (!) — весь диалог сбрасывается.
10. Детект мультивыбора: если у первого видимого ребёнка IsMultiSelect —
    переходит в режим AwaitMultiSelectConfirm, MultiSelectNodeKey=nodeKey,
    клавиатура BuildMultiSelectStep(..., nil, nil).
11. Иначе — обычная клавиатура BuildApprovalStep(topicCode, visibleChildren).

```

### 6.2. `HandleTextInput(bot, msg) bool`

Вызывается на **любое** текстовое сообщение от пользователя (не callback), возвращает `bool` — обработано ли сообщение этим хендлером (если `false` — сообщение не относится к диалогу согласования, дальше по цепочке обработчиков может пойти что-то другое).

```
1. Проверка Redis-ключа appr_approve_comment_pending:{telegramID} —
   если есть, это ввод ОБЯЗАТЕЛЬНОГО комментария к решению (см. §12.4),
   не к созданию заявки. Удаляет ключ, вызывает HandleDecisionWithChat
   с approved=true и введённым текстом. return true.
2. Проверка состояния комментариев к заявке (GetCommentFlow) —
   делегирует в HandleCommentTextInput, если Stage == "await_text".
3. Проверка состояния ответа на комментарий (GetCommentReply) —
   аналогично, HandleCommentReplyInput.
4. flowState := States.Get(telegramID) — если nil или !AwaitInput —
   return false (не наш случай).
5. Collected[flowState.InputKey] = msg.Text;  AwaitInput = false
6. Особый случай "текст → сразу следующий уровень кнопок, минуя лишний
   Set+показ":
     topic := Registry.Get(flowState.TopicCode)
     parentNode := FindNode(tree, flowState.NodeKey)  ← это тот самый
       родитель input-узла, сохранённый в п.8 §6.1
     если у parentNode ровно один ребёнок IsInput и у ЭТОГО inputNode
     ЕСТЬ дети — сразу показывает их (с фильтрацией по правам,
     NodeKey переключается на inputNode.Key), return true.
7. Иначе (input — реальный лист дерева, дальше веток нет):
     States.Set(...); continueFlowAfterInput(...) — переход к
     дополнительным шагам (§7). return true.

```

### 6.3. `HandleBackCallback(bot, cq, topicCode)`

- Если `flowState.AwaitFileInput` — сбрасывает режим файлового ввода, удаляет статусное сообщение (`FileStatusMsgID`), если было.
- Если `flowState.AwaitInput` — сбрасывает режим текстового ввода.
- Если `History` пуста — полный сброс состояния, `HandleMenu` (возврат к выбору темы).
- Иначе — `pop()` из `History`, `FindNode` по этому ключу, показывает его детей (с фильтрацией по правам). **Важно**: при возврате назад фильтр мультивыбора/input повторно не применяется — всегда показывает обычную клавиатуру кнопок, даже если по факту это узел с одним input-ребёнком.

---

## 7. `continueFlowAfterInput` — цепочка дополнительных шагов

Единая точка, куда сходятся: конец ввода текста (§6.2), любой из дополнительных шагов ниже (каждый в конце сам вызывает эту функцию снова, чтобы проверить следующий шаг в цепочке).

```go
func (h *Handler) continueFlowAfterInput(bot, ctx, chatID, telegramID, flowState) {
    topic := Registry.Get(flowState.TopicCode)
    если topic == nil { States.Clear(); return }

    topicCode, err := topic.TopicCodeFromCollected(flowState.Collected)
    если err != nil { warn-лог; States.Clear(); return }

    approvalTopic := GetApprovalTopicByCodeDB(ctx, topicCode)
    // approvalTopic может остаться nil при ошибке — часть проверок ниже
    // построена как `approvalTopic != nil && approvalTopic.X != nil && *approvalTopic.X`,
    // то есть при ошибке получения темы бот тихо пропускает ВСЕ
    // дополнительные шаги и уходит сразу к финализации.

    // --- Шаг 1: файл ---
    если approvalTopic != nil && !flowState.FilesStepCompleted:
        requiresFile := RequiresFile
        allowsFile   := AllowsFile
        isOfficial   := Collected["payment_type"] == "official"
        needFileStep := requiresFile || allowsFile || isOfficial
        если needFileStep && !AwaitFileInput:
            AwaitFileInput = true; FilesStepCompleted = false
            States.Set(...)
            showFileStatus(bot, chatID, telegramID, flowState, required=requiresFile||isOfficial)
            return

    // --- Шаг 2: первый согласующий по роли ---
    если approvalTopic != nil && FirstApproverRoleCode не пусто
        && SelectedFirstApproverID == 0 && !AwaitFirstApproverSelection:
        AwaitFirstApproverSelection = true; States.Set(...)
        показать список пользователей с этой ролью (showFirstApproverSelection)
        return

    // --- Шаг 3: ручной выбор согласующего ---
    если approvalTopic != nil && AllowApproverSelection
        && SelectedApproverID == 0 && !AwaitApproverSelection:
        AwaitApproverSelection = true; States.Set(...)
        showApproverSelection(...)   // §8
        return

    // --- Шаг 4: наблюдатели ---
    если approvalTopic != nil && AllowObserverSelection && !ObserverSelectionDone:
        ObserverSelectionDone = true; AwaitObserverSelection = true; States.Set(...)
        showObserverSelection(...)   // §9
        return

    // --- Шаг 5 (🆕): делегирование ---
    если approvalTopic != nil && AllowDelegationSelection && !DelegationSelectionDone:
        AwaitDelegationChoice = true; States.Set(...)
        showDelegationChoice(...)    // §10
        return

    // --- Финализация ---
    States.Clear(ctx, telegramID)
    finalizeAndSubmit(bot, ctx, chatID, telegramID, flowState)
}

```

**Порядок фиксирован и важен**: файл → первый согласующий по роли → ручной выбор согласующего → наблюдатели → делегирование → отправка. Каждый шаг проверяет соответствующий флаг `ApprovalTopic` независимо — можно включить любую комбинацию на конкретной теме, они не исключают друг друга.

---

## 8. Выбор согласующего

### 8.1. Ручной выбор (`showApproverSelection`)

```
getAvailableApproversForTopic(ctx, userID, departmentID, approvalTopic):
    hierarchies := GetUserHierarchyListDB(Filtering: {SubordinateID: userID, DepartmentID: departmentID})
    approverIDs := {}
    для каждой hier:
        если hier.TopicID == approvalTopic.ID → approverIDs[hier.ApproverID] = true; continue
        если hier.TopicCategoryID == approvalTopic.CategoryID → approverIDs[hier.ApproverID] = true
    подгружает User по каждому approverID

```

⚠️ Обратите внимание: здесь фильтрация по иерархии идёт **только** по `TopicID`/`TopicCategoryID` — глобальные правила иерархии (оба поля `nil` в `UserHierarchy`) **не учитываются** этой функцией. Это согласуется с общей логикой (глобальное правило — это правило «по умолчанию для всех тем», а не «выбор из списка вариантов»), но стоит иметь в виду при диагностике «почему в списке выбора согласующего никого нет», если для сотрудника настроено только глобальное правило.

Если список пуст — «⚠️ Нет доступных согласующих для этой темы.», `States.Clear`.

`HandleApproverSelectionCallback(bot, cq, approverID)` — сохраняет `SelectedApproverID`, `AwaitApproverSelection=false`, показывает подтверждение с ФИО, вызывает `continueFlowAfterInput`.

`HandleApproverSelectionPageCallback` — пагинация того же списка, перестраивает `GetApprovalTopicByCodeDB` заново по актуальному `TopicCodeFromCollected` (не кэширует).

---

## 9. Наблюдатели

### 9.1. `showObserverSelection`

```
observers := getAvailableObservers(ctx)   // все пользователи с ролью "observer"
isRequired := RequireObserverSelection == true

если observers пуст:
    если isRequired:
        "⚠️ Для этой темы обязательно выбрать наблюдателя, но в системе
         нет пользователей с ролью наблюдателя. Обратитесь к администратору."
        AwaitObserverSelection=false; ObserverSelectionDone=false (!) — специально
        НЕ помечается выполненным, чтобы не позволить создать заявку в
        нарушение обязательного требования; States.Set; return (диалог
        застревает здесь до вмешательства администратора)
    иначе:
        AwaitObserverSelection=false; ObserverSelectionDone=true
        States.Clear(); finalizeAndSubmit(...)   — пропускает шаг, сразу отправляет
    return

иначе показывает мультивыбор (BuildObserverSelectionMenu(observers,
SelectedObserverIDs, page=0, isRequired)), текст различается в
зависимости от isRequired (для обязательного — с уточнением
«Выберите менеджера, чья это отгрузка», это доменная формулировка,
специфичная для конкретных тем с обязательными наблюдателями).

```

### 9.2. Остальные хендлеры наблюдателей

- `HandleObserverToggleCallback` — toggle одного ID в `SelectedObserverIDs` (добавить, если не было; убрать, если было), перерисовывает клавиатуру через `EditMessageReplyMarkup` (не новое сообщение).
- `HandleObserverPageCallback` — пагинация, та же логика `isRequired`, пересчитанная заново по текущему `flowState`.
- `HandleObserverConfirmCallback` — если `isRequired` и выбор пуст — показывает alert через `callback` («⚠️ Выберите хотя бы одного наблюдателя»), **не закрывает** экран выбора. Иначе — `States.Clear`, `finalizeAndSubmit`.
- `getAvailableObservers` — `GetUsersByRoleCodeDB(ctx, "observer")`.
- `saveSelectedObservers(ctx, approvalID, addedByID, observerIDs)` — вызывается из `submitApproval` **после** создания заявки, создаёт по одной строке `ApprovalAdditionalObserver` на каждого выбранного.
- `getAdditionalObserversForApproval(ctx, approvalID)` — используется админкой/карточкой заявки для отображения списка наблюдателей.

---

## 10. Делегирование обязанностей (детально)

### 10.1. `showDelegationChoice`

Простой экран Да/Нет (`keyboard.BuildDelegationChoiceMenu()`, callback\_data `appr_deleg_yes`/`appr_deleg_no`), с пояснением, что делегирование активируется только после согласования этой заявки и отменяется при её отзыве.

### 10.2. `HandleDelegationChoiceCallback(bot, cq, wantsDelegate)`

- `wantsDelegate == false`: `DelegationSelectionDone=true`, сообщение «обязанности не делегируются», `continueFlowAfterInput`.
- `wantsDelegate == true`: 
    - `getAvailableDelegateCandidates` — все активные сотрудники (не заблокированы, не уволены, есть `TelegramID`), кроме самого пользователя.
    - Если кандидатов нет — сообщение «Нет доступных сотрудников для делегирования», `DelegationSelectionDone=true`, идёт дальше без делегирования.
    - Иначе — `AwaitDelegateSelection=true`, показывает `BuildDelegateSelectionMenu(candidates, page=0)`.

### 10.3. `HandleDelegateSelectionCallback(bot, cq, delegateID)`

**Важно: здесь запись в БД НЕ создаётся.** Только сохраняет выбор (`SelectedDelegateID`), показывает предварительный расчёт `delegationValidUntil` для UX («Ориентировочно до: ...») и вызывает `continueFlowAfterInput`. Реальная запись появляется позже, вместе с самой заявкой (§11.4) — потому что `flowState` в Redis живёт всего 30 минут (§4.2), а решение по заявке может занять дни, поэтому долгосрочные данные (делегирование) не могут храниться только в `flowState` — они переносятся в постоянное хранилище (БД) при первой возможности, то есть в момент отправки заявки.

### 10.4. `delegationValidUntil(collected map[string]string) (time.Time, bool)`

Проходит по **всем** значениям `flowState.Collected` (не только по ключу `"content"` — на случай нестандартной настройки дерева, где дата могла осесть под другим ключом), ищет через regexp `(\d{1,2})[.,](\d{1,2})\.(\d{4})` (запятая вместо точки после дня учтена специально — реальная опечатка встречалась в проде). Берёт максимальную найденную дату, время `23:59:59`. Если дат не найдено — возвращает `now + 30 дней` и `false` (вызывающий код логирует warning).

### 10.5. `createPendingDelegation` / `activatePendingDelegation` / `deactivatePendingDelegation`

См. документ 1 (версия 1.0), раздел 5 — логика не изменилась, здесь фиксируется дополнительно точная последовательность вызовов:

<table id="bkmrk-%D0%A4%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D1%8F-%D0%92%D1%8B%D0%B7%D1%8B%D0%B2%D0%B0%D0%B5%D1%82%D1%81%D1%8F-%D0%B8"><thead><tr><th>Функция</th><th>Вызывается из</th><th>Момент</th></tr></thead><tbody><tr><td>`createPendingDelegation`</td><td>`submitApproval`</td><td>сразу после создания `Approval` и сохранения файлов, до создания `ApprovalStep`</td></tr><tr><td>`activatePendingDelegation`</td><td>`processNextStepOrComplete`</td><td>в ветке финального `approved` (НЕ в ветке передачи следующему шагу)</td></tr><tr><td>`deactivatePendingDelegation`</td><td>`performActualRevoke`</td><td>между `UpdateApprovalDB` (статус → `revoked`) и `handleRevokeCancellationTask`</td></tr></tbody></table>

Каждая из активации/деактивации сначала делает `GetApprovalDelegationsListDB(Filtering: {ApprovalID: approval.ID})` — если пусто, тихо ничего не делает (делегирование не настраивалось при подаче этой заявки).

---

# Техническая документация: Telegram-бот (детальная версия) — часть 3

> Продолжение частей 1–2. Разделы 11–23.

---

## 11. `submitApproval` построчно

```go
func (h *Handler) submitApproval(bot, ctx, chatID, telegramID, flowState) {

```

1. **Пользователь и тема.** `initiator := GetUserByTelegramIDDB`; `topic := Registry.Get(flowState.TopicCode)`; `topicCode := topic.TopicCodeFromCollected(Collected)`; `approvalTopic := GetApprovalTopicByCodeDB(ctx, topicCode)`. Если `approvalTopic == nil` — сообщение об ошибке пользователю, `States.Clear`, **заявка не создаётся**.
2. **Формирование `Content` и `Metadata`.** Из `flowState.Collected` в `Approval.Content` уходит **только** значение под ключом `content` (если есть). Все остальные пары `key: value` из `Collected` уходят в `metadata.extra` как есть (сериализуется в JSON).
3. **Создание `Approval`** — статус сразу `pending` (не `draft`), `InitiatorID`, `TopicID = approvalTopic.ID`, `DepartmentID = initiator.DepartmentID`, `CreatedAt = now`.
4. **Сохранение файлов** (`flowState.Files`, если были) — `ApprovalFile` на каждый, `AttachedByID = initiator.ID`, `TaskID = nil` (файлы уровня заявки, не задачи — в отличие от файлов, прикрепляемых исполнителем к конкретной задаче, см. §15). Подгружает файлы обратно в `created.Files` для последующих уведомлений (чтобы не делать отдельный запрос).
5. **`createPendingDelegation(ctx, initiator, flowState, created)`** — см. §10.5. Вызывается безусловно; сама функция не делает ничего, если `flowState.SelectedDelegateID == 0`.
6. **Определение списка согласующих** (`var approvers []*User`):
    
    
    - Если `flowState.SelectedApproverID != 0` (ручной выбор, §8.1) — единственный согласующий, весь дальнейший блок иерархии пропускается.
    - Иначе: `GetUserHierarchyListDB(Filtering: {SubordinateID: initiator.ID, DepartmentID: initiator.DepartmentID})`, из них отбираются подходящие под тему записи (по тому же принципу `TopicID` → `TopicCategoryID` → глобальное — в этой ветке **уже включая** глобальные правила, в отличие от §8.1, где глобальные не участвуют).
    - Если `flowState.SelectedFirstApproverID != 0` (§8.2) — вставляется **первым элементом** списка, перед определёнными через иерархию (дедупликация по ID, если случайно совпал).
7. **Группировка по приоритету** (`priorityGroups`) — сортировка найденных `UserHierarchy` по `Priority` по возрастанию, элементы с одинаковым `Priority` попадают в одну группу.
    
    
    - `ApprovalMode == "any_of"`: **все** согласующие (из всех групп) помещаются в группу 0 — любой один может решить за всех.
    - Иначе (`"sequential"`, по умолчанию): группы обрабатываются по порядку индекса — сначала все из группы 0 параллельно, затем группа 1, и т.д. (в текущей реализации внутри одной группы больше одного согласующего на практике не наблюдалось, но код группировки это допускает).
8. **Создание `ApprovalStep`** — по одному на каждого согласующего. Первая группа (индекс 0) сразу получает `Status = "pending"`, остальные группы — `"waiting"`. `ApproverNameSnapshot` заполняется сразу по имени назначенного (не делегата — см. §2.5, снапшот переписывается только в момент решения).
9. **Наблюдатели** — `saveSelectedObservers(ctx, created.ID, initiator.ID, flowState.SelectedObserverIDs)` (§9.2), если список непуст.
10. **Уведомление контролёров** о создании новой заявки (см. §17.5).
11. **Уведомление согласующих первой группы** — для каждого: сначала проверка активного делегирования по теме/категории (`GetActiveDelegationForUser`-подобная логика, тот же приоритет TopicID → CategoryID, что и в поиске согласующих) — если есть, сообщение о новой заявке уходит **делегату**, а не исходному согласующему; в остальных случаях — обычному согласующему.
12. **Сообщение инициатору** — подтверждение отправки, с итоговым текстом (через `topic.FormatApproverMessage`/аналог), список назначенных согласующих первой группы.
13. **`States.Clear`** — на этом этапе уже вызван из `continueFlowAfterInput` перед вызовом `finalizeAndSubmit` (см. §7), повторного вызова здесь не требуется.

---

## 12. `handleDecision` (решение согласующего)

### 12.1. Определение контекста вызова

```go
func (h *Handler) handleDecision(bot, ctx, chatID, telegramID, approvalID, approved bool, comment string) {
    approval := GetApprovalByIDDB(ctx, approvalID)
    currentUser := GetUserByTelegramIDDB(ctx, telegramID)

    // Проверка: это доп. согласующий?
    additionalRecord := найти pending ApprovalAdditionalApprover для
        (ApprovalID: approvalID, ApproverID: currentUser.ID)
    isAdditionalApprover := additionalRecord != nil

    mainStep := GetActiveStepDB(ctx, approvalID)  // текущий активный ОСНОВНОЙ шаг, вне зависимости от того, кто сейчас решает

```

### 12.2. Ветка «дополнительный согласующий»

```
если isAdditionalApprover:
    если approved:
        additionalRecord.Status = "approved"; UpdateApprovalAdditionalApproverDB
        actualExecutorID := currentUser.ID  // 🩹 см. §22, п.3 — раньше сюда
                                              // ошибочно попадал не тот ID
        если allAdditionalApproved(ctx, approvalID) И mainStep.Status == "approved":
            processNextStepOrComplete(ctx, bot, approval, mainStep, actualExecutorID)
            // 🩹 §22 п.1: раньше вместо mainStep сюда передавался результат
            // findStepForCurrentApprover(currentUserID) — всегда nil для
            // доп. согласующего (у него нет строки в ApprovalStep, есть
            // только в ApprovalAdditionalApprover) → заявка «зависала»
        иначе:
            // ждём либо основного согласующего, либо остальных доп.
            уведомление доп. согласующему "Ваше решение принято, заявка
            продолжит движение после решения остальных участников"
    иначе (rejected):
        additionalRecord.Status = "rejected"; UpdateApprovalAdditionalApproverDB
        approval.Status = "rejected"; UpdateApprovalDB
        // отклонение ЛЮБОГО доп. согласующего — блокирующее для всей заявки,
        // в отличие от основной последовательности, где при any_of
        // достаточно одного одобрения
        уведомления инициатору, остальным согласующим (заявка закрыта)
    return

```

### 12.3. Ветка «основной согласующий»

```
иначе (не доп. согласующий):
    если approved:
        если RequireApproverComment == true И mainStep.Comment пуст И comment == "":
            // запрашиваем комментарий отдельным сообщением, СОХРАНЯЕМ
            // решение "в подвешенном" виде через Redis-ключ
            // appr_approve_comment_pending:{telegramID} = approvalID
            // (см. §6.2, п.1 — HandleTextInput ловит следующий текстовый
            // ввод и вызывает HandleDecisionWithChat(approved=true, text))
            return

        mainStep.Status = "approved"; mainStep.Comment = comment;
        mainStep.ActedAt = now; mainStep.ApproverNameSnapshot = currentUser.FullName
        UpdateApprovalStepDB

        actualExecutorID := currentUser.ID
        если allAdditionalApproved(ctx, approvalID):
            processNextStepOrComplete(ctx, bot, approval, mainStep, actualExecutorID)
        иначе:
            // основной шаг одобрен, но есть неотвеченные доп. согласующие —
            // заявка НЕ двигается дальше, ждём их
    иначе (rejected):
        mainStep.Status = "rejected"; ...; UpdateApprovalStepDB
        если approval ApprovalMode == "any_of":
            // отменяет ОСТАЛЬНЫЕ шаги той же группы приоритета
            для каждого другого step в той же priority-группе со
            статусом pending/waiting:
                step.Status = "cancelled_any_of"; UpdateApprovalStepDB
                уведомление этому согласующему "участие больше не требуется"
        approval.Status = "rejected"; UpdateApprovalDB
        уведомления инициатору, наблюдателям, директорам

```

### 12.4. Обязательный комментарий (детали флоу)

Redis-ключ `appr_approve_comment_pending:{telegramID}` хранит `approvalID` (строкой). При следующем текстовом сообщении от этого пользователя (**независимо от того, есть ли активный `ApprovalFlowState`** — проверка в `HandleTextInput` идёт первой, до проверки `flowState`, см. §6.2 п.1) — ключ удаляется, вызывается `HandleDecisionWithChat(bot, chatID, telegramID, approvalID, approved=true, comment=msg.Text)`, которая и приводит к обычной ветке §12.3 уже с непустым `comment`.

---

## 13. `processNextStepOrComplete`

```go
func (h *Handler) processNextStepOrComplete(ctx, bot, approval, currentStep, actualExecutorID uint64) {
    nextStep := следующий ApprovalStep этой заявки с наименьшим
                StepOrder среди тех, что ещё Status == "waiting"
                (то есть первый шаг следующей приоритетной группы)

    если nextStep != nil:
        // --- Заявка ПЕРЕДАНА следующему согласующему, ещё НЕ одобрена целиком ---
        nextStep.Status = "pending"; UpdateApprovalStepDB
        // проверка делегирования следующего согласующего — та же логика,
        // что при первичной отправке (§11 п.11)
        уведомление следующему согласующему (или его делегату)
        return  // ⚠️ activatePendingDelegation НЕ вызывается здесь —
                // делегирование активируется только при полном
                // одобрении, см. ниже

    // --- nextStep == nil: заявка ПОЛНОСТЬЮ одобрена ---
    approvedStatus := "approved"
    approval.Status = &approvedStatus
    UpdateApprovalDB(ctx, nil, approval)

    // 🆕 Активация делегирования — см. §10.5
    activatePendingDelegation(ctx, approval)

    lastStepIsDelegate := currentStep.ApproverID != nil &&
                           *currentStep.ApproverID != actualExecutorID
    // ^ используется для формулировки уведомлений: "решение принято
    // делегатом Х вместо назначенного Y" против обычного "одобрено Y"

    createTasksForApproval(ctx, bot, approval)   // §14, ApprovalTopicExecutor → ApprovalTask
    уведомление инициатору (одобрено)
    уведомления директорам, подписанным на категорию
    уведомления наблюдателям
}

```

---

## 14. Дополнительные согласующие (`add_approver.go`)

### 14.1. `HandleAddApproverFromApproval(bot, chatID, telegramID, approvalID)`

- Проверяет права добавляющего (должен сам быть согласующим этой заявки — основным или дополнительным).
- Показывает список кандидатов, исключая уже назначенных (и основных, и дополнительных).

### 14.2. `getApproverCategoriesWithPendingApprovals`

**Было**: проверяло только `topic`-scoped иерархию (пропускало правила, заданные на уровне категории или глобально), и **если у пользователя была хоть одна pending-запись где угодно** — ошибочно помечало сразу **все** категории как имеющие ожидающие заявки (некорректная агрегация).

**Стало**: переписано по образцу соседней рабочей функции `getPendingApprovalsByCategory` — категории определяются напрямую из **фактических** pending-шагов пользователя (`ApprovalStep` + `ApprovalAdditionalApprover` со статусом pending, у которых сама заявка ещё pending), без обращения к иерархии вообще — иерархия для этой задачи была лишним, ошибочным уровнем косвенности.

---

## 15. Задачи исполнителей (`tasks.go`)

Полный список хендлеров и их назначение:

<table id="bkmrk-%D0%A4%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D1%8F-%D0%9D%D0%B0%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B5-h"><thead><tr><th>Функция</th><th>Назначение</th></tr></thead><tbody><tr><td>`HandleMyTasks`</td><td>Список pending-задач текущего исполнителя (проверка роли через `IsExecutorDB`)</td></tr><tr><td>`sendTaskCard`</td><td>Карточка одной задачи: инициатор, тема, текст заявки, дата, текст задачи, прикреплённые именно к этой задаче файлы (`TaskID` совпадает), секция комментариев</td></tr><tr><td>`HandleCompleteTask`</td><td>Проверка `RequireFile` (если файл обязателен и не прикреплён — блокирует завершение, просит прикрепить), `Status → "completed"`, `CompletedAt = now`, `activateNextTask`, уведомление инициатору (включая текст самой задачи — 🩹 см. §22 последняя строка)</td></tr><tr><td>`activateNextTask`</td><td>Следующая задача этой же заявки с `StepOrder = завершённая.StepOrder + 1` и статусом `waiting` → переводит в `pending`, уведомляет её исполнителя</td></tr><tr><td>`handleRevokeCancellationTask`</td><td>Вызывается при отзыве заявки: отменяет pending/waiting `ApprovalStep`/`ApprovalAdditionalApprover`; по каждой задаче — если `completed` → `createReversalTask`, если `pending` → `askExecutorAboutChanges`, если `waiting` → просто `cancelled` с уведомлением</td></tr><tr><td>`createReversalTask`</td><td>Новая задача «Обратить изменения по заявке #N», тот же исполнитель, `Status = pending` сразу</td></tr><tr><td>`askExecutorAboutChanges`</td><td>Вопрос исполнителю Да/Нет «вносили ли уже изменения» через `BuildRevokeTaskConfirmation`</td></tr><tr><td>`HandleRevokeTaskNoChanges` / `HandleRevokeTaskHasChanges`</td><td>Обработка ответа: первое — просто `cancelled`; второе — создаёт reversal-задачу (§ выше)</td></tr><tr><td>`HandleExecutorAttachStart`</td><td>Начало сессии прикрепления файла к задаче (`state.AttachmentSession`)</td></tr></tbody></table>

---

## 16. Отзыв заявок

- `HandleRevokeWithComment` — точка входа с комментарием причины отзыва.
- Правила, кто может отозвать: 
    - `pending`/`revision` — инициатор или директор.
    - `approved`, отзывает **не-директор**-инициатор — `startApprovalRevocationRequest` — отдельный флоу запроса согласия у всех, кто участвовал в согласовании
    - `approved`, отзывает директор — сразу, без запроса согласия.
- `performActualRevoke` — единственное место, где `Approval.Status` реально становится `"revoked"`: ```
    approval.Status = "revoked"; RevokedByID = revoker.ID; RevokedAt = nowUpdateApprovalDBdeactivatePendingDelegation(ctx, approval)   // 🆕 §10.5handleRevokeCancellationTask(bot, ctx, approval)  // §15уведомления инициатору, директорам, согласующим, наблюдателям
    
    ```

---

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

Список типов уведомлений:

<table id="bkmrk-%23-%D0%9A%D0%BE%D0%BC%D1%83-%D0%9A%D0%BE%D0%B3%D0%B4%D0%B0-%D0%9E%D1%82%D0%BA%D1%83%D0%B4%D0%B0-"><thead><tr><th>\#</th><th>Кому</th><th>Когда</th><th>Откуда</th></tr></thead><tbody><tr><td>1</td><td>Согласующему первой группы (или его делегату)</td><td>Заявка создана</td><td>`submitApproval`</td></tr><tr><td>2</td><td>Инициатору</td><td>Заявка отправлена (подтверждение)</td><td>`submitApproval`</td></tr><tr><td>3</td><td>Контролёрам категории</td><td>Заявка создана</td><td>`submitApproval`</td></tr><tr><td>4</td><td>Следующему согласующему (или делегату)</td><td>Предыдущий шаг одобрен, есть следующий</td><td>`processNextStepOrComplete`</td></tr><tr><td>5</td><td>Инициатору</td><td>Заявка полностью одобрена</td><td>`processNextStepOrComplete`</td></tr><tr><td>6</td><td>Директорам, подписанным на категорию</td><td>Заявка полностью одобрена</td><td>`processNextStepOrComplete`</td></tr><tr><td>7</td><td>Наблюдателям</td><td>Заявка полностью одобрена</td><td>`processNextStepOrComplete`</td></tr><tr><td>8</td><td>Инициатору, наблюдателям, директорам</td><td>Заявка отклонена</td><td>`handleDecision` (rejected-ветки)</td></tr><tr><td>9</td><td>Остальным согласующим той же any\_of-группы</td><td>Их участие больше не требуется</td><td>`handleDecision`</td></tr><tr><td>10</td><td>Исполнителю следующей задачи</td><td>Предыдущая задача выполнена</td><td>`activateNextTask`</td></tr><tr><td>11</td><td>Инициатору</td><td>Исполнитель завершил задачу (включая текст задачи)</td><td>`HandleCompleteTask`</td></tr><tr><td>12</td><td>Исполнителю</td><td>Заявка отозвана — просьба обратить/подтвердить изменения</td><td>`handleRevokeCancellationTask`</td></tr><tr><td>13</td><td>Инициатору, директорам, согласующим, наблюдателям</td><td>Заявка отозвана</td><td>`performActualRevoke`</td></tr></tbody></table>

---

## 18. Устойчивость бота

- `buildHTTPClient` — сборка `http.Client` для Telegram Bot API, подключает `CustomAPIProxyTransport`, если задан `proxyCfg` (🩹 ранее конфиг прокси передавался, но фактически не использовался при сборке транспорта — исправлено).
- Ретраи на старте — при недоступности Telegram API во время запуска бот повторяет попытку подключения вместо немедленного падения.
- Отдельный `proxy/main.go` — вынесенный прокси-сервис перед реальным Telegram Bot API, с собственной логикой ретраев на запросы (`doWithRetry` — упоминается как существующий, детали реализации не входили в присланные файлы).

---

## 19. `scheduler/daily_reminder.go` — построчно

### 19.1. `Start()`

```go
func (dr *DailyReminder) Start() {
    go dr.sendReminders()   // 🧪 см. журнал — временная строка для
                              // тестирования, должна быть удалена после
                              // проверки в проде (немедленный запуск при
                              // старте сервиса, а не ожидание 9:00 МСК)
    go dr.scheduleLoop()
}

```

### 19.2. `scheduleLoop()`

Бесконечный цикл: вычисляет ближайшие 9:00 по `Europe/Moscow` (fallback — фиксированная зона UTC+3, если `LoadLocation` не удался), переносит на понедельник, если выпадает на субботу/воскресенье (`skipWeekends`), спит до этого момента, вызывает `sendReminders()`, повторяет.

### 19.3. `sendReminders()`

1. Получает всех пользователей (`GetUsersListDB`, без фильтра — все, в т.ч. потенциально заблокированные/уволенные — фильтрация по пригодности отправки происходит ниже, по наличию `TelegramID`).
2. **Один раз** на всю рассылку — `getAbsentEmployeesToday` (§19.4).
3. Для каждого пользователя с непустым `TelegramID` — `sendReminderToUser`.
4. 🧪 Временный фильтр по конкретному `telegramID` — использовался для тестирования на одном аккаунте без риска разослать всем; должен быть удалён из продовой версии.

### 19.4. `getAbsentEmployeesToday(ctx, mskLocation) []AbsentEmployeeInfo`

```go
type AbsentEmployeeInfo struct {
    Name            string
    TimeDescription string
    Contact         string   // делегат, если есть активное делегирование, иначе сам сотрудник
}

```

1. `GetApprovalsListDB(Filtering: {Status: "approved"})` — **все** одобренные заявки компании одним запросом (не по пользователю — так один раз на всю рассылку, а не N запросов).
2. Для каждой заявки: 
    - Пропуск, если `Metadata`/`Content` пусты, или `metadata.extra.absence_type` пуст (не заявка на отсутствие — поле есть только у отгула/отпуска/больничного), или инициатор уже встречен ранее (дедупликация — сотрудник с несколькими пересекающимися заявками попадёт в сводку один раз).
    - `parseAbsenceDates(content)` — все совпадения regex `(\d{1,2})[.,](\d{1,2})\.(\d{4})`. Если ни одной даты не найдено — warning в лог с ID заявки и содержимым, пропуск.
    - `absenceCoversDate(dates, content, today)` — если дат ровно 2 **и** в тексте есть дефис — трактует как диапазон (с меньшей по большую дату, независимо от порядка написания); иначе — сверяет точное совпадение с любой из распознанных дат (список отдельных дней).
    - Формулировка `TimeDescription` по `absence_type`: 
        - `timeoff` + `time_type == "partial"` → парсит время через `(\d{1,2}):(\d{2}).*?(\d{1,2}):(\d{2})` (строго через двоеточие, не точку — специально, чтобы не путать с датами), формат `"отгул с HH:MM до HH:MM"`; при неудаче парсинга времени — `"отгул весь день"`.
        - `timeoff` (не partial) → `"отгул весь день"`.
        - `vacation` → `"отпуск до " + maxDate(dates)`.
        - `sickleave` → `"больничный до " + maxDate(dates)`.
    - `Contact` — поиск активных `ApprovalDelegation` по `DelegatorID = InitiatorID`, `IsActive = true`, с дополнительной проверкой `ValidUntil` (подстраховка на случай, если фоновая задача деактивации по времени ещё не отработала) — первая подходящая даёт имя делегата, иначе — имя самого сотрудника.

### 19.5. `sendReminderToUser`

Считает 4 персональных счётчика (доработки/задачи/согласования, плюс неявный «есть ли вообще что показать»), формирует текст, добавляет блок «Сотрудники в отгуле/больничном/отпуске» если `absentToday` непуст. Отправляет, **если** есть хоть один личный пункт **или** список отсутствующих непуст (осознанное решение — раньше отправляли только при личных пунктах).

---

## 20. Каталог `callback_data`

<table id="bkmrk-%D0%9F%D1%80%D0%B5%D1%84%D0%B8%D0%BA%D1%81%2F%D1%84%D0%BE%D1%80%D0%BC%D0%B0%D1%82-%D0%9E%D0%B1%D1%80%D0%B0%D0%B1"><thead><tr><th>Префикс/формат</th><th>Обработчик</th><th>Назначение</th></tr></thead><tbody><tr><td>`appr:{topicCode}:{nodeKey}`</td><td>`HandleCallback`</td><td>Переход по дереву</td></tr><tr><td>`appr_back:{topicCode}`</td><td>`HandleBackCallback`</td><td>Кнопка «Назад»</td></tr><tr><td>`appr_decision:{approvalID}:1|0`</td><td>`handleDecision` (через диспетчер)</td><td>Одобрить/отклонить</td></tr><tr><td>`appr_approver_sel:{userID}`</td><td>`HandleApproverSelectionCallback`</td><td>Выбор согласующего вручную</td></tr><tr><td>`appr_approver_pg:{page}`</td><td>`HandleApproverSelectionPageCallback`</td><td>Пагинация списка согласующих</td></tr><tr><td>`appr_obs_toggle:{userID}`</td><td>`HandleObserverToggleCallback`</td><td>Toggle наблюдателя</td></tr><tr><td>`appr_obs_pg:{page}`</td><td>`HandleObserverPageCallback`</td><td>Пагинация наблюдателей</td></tr><tr><td>`appr_obs_confirm`</td><td>`HandleObserverConfirmCallback`</td><td>Подтверждение выбора наблюдателей</td></tr><tr><td>`appr_deleg_yes` / `appr_deleg_no`</td><td>`HandleDelegationChoiceCallback`</td><td>🆕 Да/Нет делегирования</td></tr><tr><td>`appr_deleg_sel:{userID}`</td><td>`HandleDelegateSelectionCallback`</td><td>🆕 Выбор делегата</td></tr><tr><td>`appr_deleg_pg:{page}`</td><td>`HandleDelegateSelectionPageCallback`</td><td>🆕 Пагинация делегатов</td></tr><tr><td>`add_appr_to_approval:{approvalID}`</td><td>`HandleAddApproverFromApproval`</td><td>Добавление доп. согласующего (кнопка сейчас закомментирована)</td></tr><tr><td>`revoke_task_no_changes:{taskID}:{approvalID}`</td><td>`HandleRevokeTaskNoChanges`</td><td>Подтверждение отсутствия изменений при отзыве</td></tr><tr><td>`revoke_task_has_changes:{taskID}:{approvalID}`</td><td>`HandleRevokeTaskHasChanges`</td><td>Подтверждение наличия изменений</td></tr></tbody></table>

⚠️ Все ключи держатся в пределах 64 байт вручную (лимит Telegram) — особенно важно для `Key` узлов дерева (§2.3), которые входят в `appr:{topicCode}:{nodeKey}`.

---

## 21. Каталог ключей Redis

<table id="bkmrk-%D0%9A%D0%BB%D1%8E%D1%87-%D0%A4%D0%BE%D1%80%D0%BC%D0%B0%D1%82%2Fttl-%D0%9D%D0%B0%D0%B7%D0%BD"><thead><tr><th>Ключ</th><th>Формат/TTL</th><th>Назначение</th></tr></thead><tbody><tr><td>`approval_flow:{telegramID}`</td><td>JSON `ApprovalFlowState`, TTL 30 мин</td><td>Состояние диалога создания заявки</td></tr><tr><td>`approval_flow:version`</td><td>Произвольное значение, без TTL</td><td>Триггер перезагрузки `Registry` (опрос раз в 5 сек)</td></tr><tr><td>`appr_approve_comment_pending:{telegramID}`</td><td>`approvalID` строкой</td><td>Ожидание обязательного комментария к одобрению</td></tr><tr><td>(без точного имени) — `AddApproverFlowState`, `AttachmentSession`, comment-flow состояния</td><td>JSON, управляются через `StateManager`</td><td>Прочие второстепенные диалоговые состояния (§4.2)</td></tr></tbody></table>

---

## 22. Полный журнал багов с кодом до/после

### 22.1. `handleDecision`: тема не найдена для timeoff/vacation/sickleave

**Симптом**: при попытке согласующего принять решение по заявке категории «Отгул»/«Отпуск»/«Больничный» — ошибка «unknown topic code».

**Причина**: `topicCodeToCategory` в `Registry` инициализировалась пустой картой, алиасы никогда не заполнялись.

**Исправление** — в `NewRegistry`:

```go
r := &Registry{
    ipc: ipc, topics: make(...), order: nil,
    topicCodeToCategory: map[string]string{
        "timeoff":   "absence",
        "vacation":  "absence",
        "sickleave": "absence",
    },
}

```

### 22.2. 64-байтный лимит `callback_data` — падение конструктора/бота

**Причина**: `r.Route("/api/approvals/{id}", ...)` в `chi` **перекрывал** уже существующий `GET`-хендлер базового пути `/api/approvals` — новые под-маршруты (`/comments`, `/additional-approvers` и т.п.) логически переносили туда весь роутинг, ломая существующий список заявок.

**Исправление**: заменено на `r.Group(...)` с полными абсолютными путями вместо вложенного `r.Route`.

### 22.3. Заявка «зависает» после одобрения доп. согласующим

**Причина**: ветка доп. согласующего в `handleDecision` искала «свой» шаг через `findStepForCurrentApprover(ctx, approvalID, currentUserID)` — эта функция ищет запись в `ApprovalStep`, а у доп. согласующего такой записи никогда не было (он есть только в `ApprovalAdditionalApprover`) → всегда `nil` → заявка молча переставала двигаться дальше после его одобрения, при этом никакой ошибки не логировалось.

**Было**:

```go
step := findStepForCurrentApprover(ctx, approvalID, currentUserID)
processNextStepOrComplete(ctx, bot, approval, step, currentUserID)
// step == nil здесь всегда для доп. согласующего

```

**Стало**: переиспользование уже корректно полученного `mainStep` (результат `GetActiveStepDB`, взятого в начале функции, см. §12.1):

```go
processNextStepOrComplete(ctx, bot, approval, mainStep, currentUserID)

```

Заодно исправлен передаваемый `actualExecutorID` — раньше туда уходил ID самого доп. согласующего, из-за чего в `processNextStepOrComplete` (`lastStepIsDelegate` проверка, §13) он ошибочно трактовался как «делегат основного согласующего», хотя это два независимых, не связанных друг с другом человека.

### 22.4. Прокси бота фактически не использовался

**Причина**: `buildHTTPClient` принимал `proxyCfg` аргументом, но не подключал его к транспорту `http.Client`.

**Исправление**: подключён `CustomAPIProxyTransport`, добавлены ретраи на подключение при старте.

### 22.5. `getApproverCategoriesWithPendingApprovals` — неверные категории

См. §14.2 — полностью переписана функция.

### 22.6. Уведомление о выполненной задаче не содержало текст задачи

**Было**: сообщение инициатору формировалось только из `approval.Content` (текст всей заявки).

**Стало**: добавлена отдельная строка `🎯 Задача: {task.TaskText}` — конкретно то, что исполнитель фактически делал.

### 22.7. `DynamicTopic` — подписи `{{.key_label}}` только для захардкоженных ключей

**Причина**: `addLabelMappings` содержала фиксированный список соответствий «ключ+значение → подпись», не расширяемый без правки кода.

**Исправление**: добавлен `dataValueLabels`, заполняемый при `NewDynamicTopic` из `Label` **любого** узла дерева с соответствующими `DataKey`/`DataValue`, и метод `addTreeLabelMappings`, вызываемый **после** `addLabelMappings` (приоритет — у дерева). Теперь переименование узла в конструкторе автоматически меняет и текст в шаблоне сообщения, без правки Go-кода.