Files
aiform_dev/SESSION_LOG_2025-11-20.md
AI Assistant 3621ae6021 feat: Session persistence with Redis + Draft management fixes
- Implement session management API (/api/v1/session/create, verify, logout)
- Add session restoration from localStorage on page reload
- Fix session_id priority when loading drafts (use current, not old from DB)
- Add unified_id and claim_id to wizard payload sent to n8n
- Add Docker volume for frontend HMR (Hot Module Replacement)
- Add comprehensive session logging for debugging

Components updated:
- backend/app/api/session.py (NEW) - Session management endpoints
- backend/app/main.py - Include session router
- frontend/src/components/form/Step1Phone.tsx v2.0 - Create session after SMS
- frontend/src/pages/ClaimForm.tsx v3.8 - Session restoration & priority fix
- frontend/src/components/form/StepWizardPlan.tsx v1.4 - Add unified_id/claim_id
- docker-compose.yml - Add frontend volume for live reload

Session flow:
1. User verifies phone -> session created in Redis (24h TTL)
2. session_token saved to localStorage
3. Page reload -> session restored automatically
4. Draft selected -> current session_id used (not old from DB)
5. Wizard submit -> unified_id, claim_id, session_id sent to n8n
6. Logout -> session removed from Redis & localStorage

Fixes:
- Session token not persisting after page reload
- unified_id missing in n8n webhook payload
- Old session_id from draft overwriting current session
- Frontend changes requiring container rebuild
2025-11-20 18:31:42 +03:00

12 KiB
Raw Blame History

Лог сессии: 2025-11-20 - Session Persistence & Draft Management

Дата: 20 ноября 2025


🎯 Основные задачи

  1. Реализация сохранения сессии в Redis
  2. Восстановление сессии из localStorage после перезагрузки страницы
  3. Исправление передачи unified_id и claim_id в n8n при отправке визарда
  4. Исправление приоритета session_id при загрузке черновика

📝 Выполненные изменения

1. Backend - Session API (/api/v1/session)

Файл: ticket_form/backend/app/api/session.py Создан новый роутер для управления сессиями в Redis:

  • POST /api/v1/session/create - создание сессии с TTL 24 часа
  • POST /api/v1/session/verify - проверка валидности сессии
  • POST /api/v1/session/logout - удаление сессии

Данные сессии:

{
  "session_token": "sess_...",
  "unified_id": "usr_...",
  "phone": "79262306381",
  "contact_id": "320096",
  "verified_at": "2025-11-20T14:54:01.279Z",
  "expires_at": "2025-11-21T14:54:01.279Z"
}

Файл: ticket_form/backend/app/main.py

  • Добавлен импорт session роутера
  • Подключен роутер: app.include_router(session.router)

2. Frontend - Session Management

Файл: ticket_form/frontend/src/components/form/Step1Phone.tsx Версия: v2.0 - 2025-11-20 14:40

Изменения:

  • После успешной SMS-верификации вызывается POST /api/v1/session/create
  • session_token сохраняется в localStorage
  • Добавлены подробные debug логи для отладки сессии

Код:

// После получения unified_id от n8n
const sessionPayload = {
  session_token: finalSessionId,
  unified_id: unifiedIdToPass,
  phone: formData.phone!,
  contact_id: result.contact_id,
};

const sessionResponse = await fetch('/api/v1/session/create', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(sessionPayload),
});

if (sessionResponse.ok) {
  localStorage.setItem('session_token', finalSessionId);
}

3. Frontend - Session Restoration

Файл: ticket_form/frontend/src/pages/ClaimForm.tsx Версия: v3.8 - 2025-11-20 15:10

Изменения:

A. Проверка сессии при загрузке компонента:

useEffect(() => {
  const sessionToken = localStorage.getItem('session_token');
  if (!sessionToken) return;

  // Проверяем валидность сессии
  fetch('/api/v1/session/verify', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ session_token: sessionToken }),
  })
    .then(res => res.json())
    .then(data => {
      if (data.success && data.valid) {
        // Восстанавливаем данные сессии
        updateFormData({
          unified_id: data.unified_id,
          phone: data.phone,
          contact_id: data.contact_id,
        });
        setIsPhoneVerified(true);
        checkDrafts(data.unified_id, data.phone, formData.session_id);
      } else {
        localStorage.removeItem('session_token');
      }
    });
}, []);

B. Кнопка "Выход":

const handleExitToList = () => {
  const sessionToken = localStorage.getItem('session_token');
  if (sessionToken) {
    fetch('/api/v1/session/logout', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ session_token: sessionToken }),
    });
    localStorage.removeItem('session_token');
  }
  
  // Сброс формы
  updateFormData({
    unified_id: undefined,
    phone: '',
    contact_id: '',
  });
  setIsPhoneVerified(false);
  setCurrentStep(0);
};

C. Исправление приоритета session_id при загрузке черновика:

До:

session_id: claim.session_token || sessionIdRef.current,  // ❌ Старый из черновика

После:

session_id: sessionIdRef.current || formData.session_id,  // ✅ Текущий актуальный

Причина: При загрузке черновика старый session_id из БД перезаписывал новый, полученный от n8n после SMS-верификации.


4. Frontend - Wizard Payload Fix

Файл: ticket_form/frontend/src/components/form/StepWizardPlan.tsx Версия: v1.4 - 2025-11-20 15:00

Проблема: При отправке визарда в n8n не передавались unified_id и claim_id.

Исправление:

// Добавляем unified_id и claim_id (если есть)
if (formData.unified_id) formPayload.append('unified_id', formData.unified_id);
if (formData.claim_id) formPayload.append('claim_id', formData.claim_id);

Debug лог:

console.log('📤 Отправка в n8n:', {
  session_id: formData.session_id,
  unified_id: formData.unified_id,
  claim_id: formData.claim_id,
  contact_id: formData.contact_id,
  phone: formData.phone,
});

5. Docker Volumes для Hot Module Replacement

Файл: ticket_form/docker-compose.yml

Добавлен volume для фронтенда:

ticket_form_frontend:
  volumes:
    - ./frontend/src:/app/src:ro

Цель: Включить live reload (HMR) при изменении файлов фронтенда без пересборки контейнера.


🔄 Workflow изменений

Полный цикл работы с сессией:

  1. Пользователь вводит телефон и SMS-код

    • → Step1Phone вызывает n8n для верификации
    • → n8n возвращает unified_id, contact_id, session_id
    • → Step1Phone создаёт сессию в Redis через POST /api/v1/session/create
    • session_token сохраняется в localStorage
  2. Пользователь закрывает/обновляет страницу

    • → ClaimForm при загрузке проверяет localStorage
    • → Вызывается POST /api/v1/session/verify
    • → Если сессия валидна, восстанавливаются unified_id, phone, contact_id
    • → Автоматически загружаются черновики
  3. Пользователь продолжает черновик

    • → При загрузке черновика используется ТЕКУЩИЙ session_id (не старый из БД)
    • → При отправке визарда передаются unified_id, claim_id, актуальный session_id
  4. Пользователь нажимает "Выход"

    • → Вызывается POST /api/v1/session/logout
    • → Сессия удаляется из Redis
    • session_token удаляется из localStorage
    • → Редирект на Step1Phone

🐛 Исправленные проблемы

Проблема #1: Session token not found in localStorage

Причина: Backend эндпоинт /api/v1/session/create не был подключен. Решение: Добавлен импорт и подключение роутера в main.py.

Проблема #2: unified_id не передавался в n8n

Причина: В StepWizardPlan.tsx не было строки formPayload.append('unified_id', ...). Решение: Добавлена передача unified_id и claim_id в FormData.

Проблема #3: Старый session_id перезаписывал новый

Причина: При загрузке черновика приоритет был у claim.session_token из БД. Решение: Изменён приоритет на sessionIdRef.current (текущая сессия).

Проблема #4: Frontend не обновлялся без пересборки

Причина: Docker контейнер не монтировал исходники фронтенда. Решение: Добавлен volume ./frontend/src:/app/src:ro для HMR.


📊 Результаты

Payload в n8n после исправлений:

{
  "stage": "wizard",
  "form_id": "ticket_form",
  "session_id": "sess_e6e3f447-8770-47af-ae87-8c022c686d9f",   Актуальный от n8n
  "unified_id": "usr_90599ff2-ac79-4236-b950-0df85395096c",     Добавлен
  "claim_id": "19572ab7-cad5-4f8d-a622-4617487c07ce",           Добавлен
  "contact_id": "320096",
  "phone": "79262306381",
  "wizard_plan": "{...}",
  "wizard_answers": "{...}",
  "wizard_skipped_documents": "[]"
}

Сессия в Redis (TTL 24 часа):

Key: crm:session:sess_e6e3f447-8770-47af-ae87-8c022c686d9f
Value: {
  "session_token": "sess_e6e3f447-8770-47af-ae87-8c022c686d9f",
  "unified_id": "usr_90599ff2-ac79-4236-b950-0df85395096c",
  "phone": "79262306381",
  "contact_id": "320096",
  "verified_at": "2025-11-20T14:54:01.279Z",
  "expires_at": "2025-11-21T14:54:01.279Z"
}
TTL: 86400 секунд

📦 Изменённые файлы

  1. ticket_form/backend/app/api/session.py (создан)
  2. ticket_form/backend/app/main.py (добавлен импорт session)
  3. ticket_form/frontend/src/components/form/Step1Phone.tsx (v2.0)
  4. ticket_form/frontend/src/pages/ClaimForm.tsx (v3.8)
  5. ticket_form/frontend/src/components/form/StepWizardPlan.tsx (v1.4)
  6. ticket_form/docker-compose.yml (добавлен volume)

🧪 Тестирование

Сценарий 1: Новая сессия

  • Ввод телефона и SMS-кода
  • Создание сессии в Redis
  • Сохранение session_token в localStorage
  • Отображение черновиков (если есть)

Сценарий 2: Восстановление сессии

  • Ctrl+F5 (hard refresh)
  • Автоматическая верификация сессии
  • Восстановление unified_id, phone, contact_id
  • Автоматическое отображение черновиков

Сценарий 3: Продолжение черновика

  • Выбор черновика из списка
  • Загрузка данных черновика
  • Сохранение актуального session_id (не старого из БД)
  • Отправка в n8n с unified_id, claim_id, session_id

Сценарий 4: Выход

  • Нажатие кнопки "🚪 Выход"
  • Удаление сессии из Redis
  • Удаление session_token из localStorage
  • Редирект на Step1Phone

🎉 Итоги

Реализован полноценный механизм управления сессиями:

  • Персистентность через Redis (TTL 24 часа)
  • Восстановление после перезагрузки страницы
  • Корректная передача идентификаторов в n8n
  • Безопасный выход с очисткой данных

Все изменения протестированы и готовы к продакшену! 🚀


📝 Следующие шаги (опционально)

  1. Добавить обновление TTL сессии при активности пользователя
  2. Реализовать уведомление о скором истечении сессии (за 5 минут)
  3. Добавить мониторинг активных сессий в админке
  4. Реализовать "запомнить меня" с увеличенным TTL (7 дней)

Автор: AI Assistant
Дата: 2025-11-20
Статус: Завершено