Архитектура «Дневника самонаблюдений»

Документ описывает архитектуру функционала «Дневник самонаблюдений» и является техническим основанием для разработки. Функционал встраивается в существующий стек: Laravel CRM, Яндекс.Формы, чат-бот MAX.

Источник актуализации: /Users/masaltsev/Documents/dev/crm/docs/diary-architecture.md.


1. Контекст и цели

Дневник самонаблюдений — инструмент рефлексии для волонтёров. После каждого визита к подопечному волонтёр отвечает на 4–5 вопросов:

  1. Как прошла встреча? (факты, ключевые моменты)
  2. За что я благодарен подопечному?
  3. С какими трудностями столкнулся?
  4. За что могу себя похвалить?
  5. (Опционально, только для студентов) Какая психологическая теория помогла бы объяснить поведение подопечного?

Ключевое отличие от обычного отчёта: дневник — личный, рефлексивный, не обязательный для всех. Координатор видит записи только если волонтёр сам открыл доступ или поднял «красный флаг».


2. Архитектурные решения

2.1 Место дневника в системе

Вопрос Решение Обоснование
Где хранить? Отдельная таблица diary_entries в БД CRM Структурированные данные, связь с парой, поиск по записям координатором
Как вводить? Яндекс.Форма, открываемая из бота MAX Готовый инструмент, привычный UX, поддержка скрытых полей для prefill
Когда предлагать? Сразу после отправки обычного отчёта — как отдельный опциональный шаг Контекст ещё свежий; не навязываем, предлагаем
Кто видит в CRM? Координатор: только количество записей + «красные флаги»; куратор-психолог: полные записи с разрешения волонтёра Конфиденциальность — ключевое условие доверия
Как отображать в CRM? Отдельный раздел на странице пары, а не как тип PairEvent Дневник — не событие пары, а событие волонтёра; смешивать нельзя

2.2 Связь «волонтёр → дневник → пара»

Идентификация происходит через уже реализованный механизм: volunteer_profiles.max_user_idContact с type=volunteer → активные Pair.

Пара выбирается на этапе обычного отчёта (в боте). pair_id и volunteer_contact_id передаются в форму через GET-параметры в URL Яндекс.Формы (скрытые предзаполненные поля).

2.3 Механизм предзаполнения Яндекс.Форм

Яндекс.Формы поддерживают передачу значений через GET-параметры URL. Для скрытых полей нужно:

  1. Добавить вопрос типа «Короткий текст»
  2. Включить опцию Скрытый вопрос
  3. Задать Идентификатор вопроса (например, volunteer_id, pair_id)
  4. Формировать ссылку с параметрами: ?volunteer_id=42&pair_id=17

3. Поток данных (общая схема)

Волонтёр в боте MAX
  ↓ (выбирает пару, отправляет обычный отчёт)
  ↓ PairEvent сохраняется в CRM
  ↓
Бот: «Хотите заполнить дневник самонаблюдений? Это займёт 5 минут.»
  [📓 Открыть дневник]   [Пропустить]
  ↓ (нажатие кнопки «Открыть дневник»)
  ↓
CRM генерирует URL Яндекс.Формы с prefill-параметрами:
  https://forms.yandex.ru/u/{FORM_ID}/?volunteer_id=42&pair_id=17
  ↓
Волонтёр заполняет форму в браузере (или WebView)
  ↓
Яндекс.Форма → POST Webhook → CRM endpoint /api/diary/yandex-webhook
  ↓
CRM: создаёт DiaryEntry, связывает с Pair и Contact
  ↓
Бот: «Запись сохранена»

4. Модель данных (концептуально)

Ключевые поля записи дневника:

  • volunteer_contact_id (связь с волонтёром)
  • pair_id (связь с парой)
  • visit_date
  • ответы q1–q5
  • has_red_flag (автоматически по ключевым словам)
  • yandex_form_id (для идемпотентности)

Подробная SQL‑схема и чеклист реализации (миграции/контроллеры/политики/тесты) — в исходном документе из репозитория CRM.


5. Доступы и отображение в CRM

  • Координатор: видит сводку (кол-во записей, наличие/кол-во red‑flag) по своим парам.
  • Куратор‑психолог: видит полный текст записей (новая роль, отдельная политика доступа).
  • Волонтёр: видит только свои записи через MAX‑бот (последняя запись / экспорт).