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
This commit is contained in:
AI Assistant
2025-11-20 18:31:42 +03:00
parent 4c8fda5f55
commit 3621ae6021
25 changed files with 3120 additions and 181 deletions

199
SESSION_LOG_2025-11-19.md Normal file
View File

@@ -0,0 +1,199 @@
# 📋 Лог сессии 19.11.2025
## Основные задачи
1. ✅ Исправлен конфликт имён переменных в `loadDraft` (claimId → finalClaimId)
2. ✅ Убран `claim_id` из ранних этапов формы - используется только `session_id`
3. ✅ Настроен узел `claimsave` для сохранения первичного черновика
4. ✅ Исправлены ошибки в n8n Code узлах
---
## 1. Исправление ошибки загрузки черновика
**Проблема:** `ReferenceError: Cannot access 'claimId2' before initialization`
**Причина:** Конфликт имён - параметр функции `claimId` и локальная переменная `const claimId`
**Решение:**
- Переименована локальная переменная в `finalClaimId`
- Обновлены все использования переменной
**Файлы:**
- `ticket_form/frontend/src/pages/ClaimForm.tsx`
---
## 2. Убран `claim_id` из ранних этапов
**Решение:** Использовать только `session_id` на этапах до генерации `wizard_plan`
### Изменения в фронтенде:
#### `StepDescription.tsx`:
- ❌ Убрана проверка `if (!formData.claim_id)`
- ❌ Убран `claim_id` из запроса к `/api/v1/claims/description`
- ❌ Убран `claim_id` из mock данных
#### `Step1Phone.tsx`:
- ❌ Убран `claim_id` из сохранения данных после верификации телефона
- ✅ Сохраняется только `unified_id`, `contact_id`, `phone`
#### `StepWizardPlan.tsx`:
- ✅ Заменен `claim_id` на `session_id` для SSE подключения (`/events/${sessionId}`)
- ❌ Убрана проверка `claim_id` перед рендером
- ❌ Убран `claim_id` из отправки данных в n8n
### Изменения в backend:
#### `claims.py`:
-`claim_id` уже опциональный в модели `TicketFormDescriptionRequest`
- ✅ Обновлено логирование для работы с опциональным `claim_id`
**Файлы:**
- `ticket_form/frontend/src/components/form/StepDescription.tsx`
- `ticket_form/frontend/src/components/form/Step1Phone.tsx`
- `ticket_form/frontend/src/components/form/StepWizardPlan.tsx`
- `ticket_form/backend/app/api/claims.py`
---
## 3. Настройка узла `claimsave` для первичного черновика
**Задача:** Сохранить первичный черновик сразу после генерации `wizard_plan`
**Решение:**
- Создан SQL запрос для сохранения первичного черновика
- Используется `session_token` для связи (вместо `claim_id`)
- Сохраняются данные из AI Agent1 и AI Agent13
**Что сохраняется:**
-`wizard_plan` - план вопросов от AI Agent12
-`problem_description` - описание проблемы
-`answers_prefill` - предзаполненные ответы
-`coverage_report` - отчёт о покрытии
-`ai_agent1_facts` - факты из AI Agent1 (facts_short, facts_full, problem)
-`ai_agent13_rag` - RAG ответ от AI Agent13
-`session_token` - для связи
-`unified_id` - если есть (передается с фронта)
- ⚠️ `claim_id` - пока NULL, будет сгенерирован позже
**Документация:**
- `ticket_form/docs/CLAIMSAVE_PRIMARY_DRAFT_FIX.md` - полная инструкция
- `ticket_form/docs/SQL_CLAIMSAVE_PRIMARY_DRAFT.sql` - готовый SQL запрос
---
## 4. Исправления n8n Code узлов
### Узел `Code4` (подготовка данных для Redis)
**Проблема:** Использовался `claim_id` вместо `session_token` для Redis ключа
**Исправление:**
```javascript
// Было:
const sessionToken = $('Redis Trigger').first().json.message.claim_id
// Стало:
const sessionToken = $('Edit Fields11').first().json.session_token
|| $('Redis Trigger').first().json.message.session_id
|| null;
const redisKey = `ocr_events:${sessionToken || 'temp-' + Date.now()}`;
```
**Файл:** `ticket_form/docs/CODE4_FIXED.js`
### Узел создания контакта (CreateWebContact)
**Проблема:**
- Использовалась неопределённая переменная `session` в `redis_key`
- Генерировался `claim_id`, который не нужен на этих этапах
- Не было `unified_id` из ноды `user_get`
**Исправление:**
- Убрана генерация `claim_id`
- Добавлен `unified_id` из ноды `user_get`
- Убраны `voucher` и `event_type` из `sessionData`
- Исправлен `redis_key` на использование `session_id`
**Файл:** `ticket_form/docs/CODE_CREATE_WEB_CONTACT_FINAL.js`
**Что теперь в `redis_value`:**
```json
{
"unified_id": "usr_90599ff2-ac79-4236-b950-0df85395096c",
"contact_id": "396625",
"phone": "79262306381",
"is_new_contact": false,
"status": "draft",
"current_step": 1,
"created_at": "2025-11-19T20:30:00.000Z",
"updated_at": "2025-11-19T20:30:00.000Z",
"documents": {},
"email": null,
"bank_name": null
}
```
---
## 5. Анализ workflow `ticket_form:description`
**Workflow ID:** `b4K4u851b4JFivyD`
**Структура:**
- 35 узлов, 31 соединение
- Заканчивается узлом `push_wizard1` - пушит wizard plan в Redis
**Основной поток:**
1. Redis Trigger → получает событие из `ticket_form:description`
2. get_claime_data1 → получает данные из Redis
3. AI Agent1 → извлекает факты (полный и короткий)
4. AI Agent13 → генерирует RAG ответ
5. AI Agent12 → генерирует wizard_plan
6. Code4 → форматирует для Redis
7. **claimsave_primary** → сохраняет первичный черновик (нужно добавить)
8. push_wizard1 → пушит wizard_plan в Redis для SSE
**Что публикуется в `ticket_form:description`:**
```json
{
"type": "ticket_form_description",
"session_id": "sess-abc-123...",
"claim_id": null, // опционально
"phone": "79262306381",
"email": "user@example.com",
"description": "Текст описания проблемы",
"source": "ticket_form",
"timestamp": "2025-11-19T20:30:00.000Z"
}
```
---
## Коммиты
1. **de011efb** - `fix: исправлен конфликт имён переменных в loadDraft (claimId -> finalClaimId)`
2. **d2f37faa** - `fix: убран claim_id, используется только session_id на ранних этапах`
---
## Следующие шаги
1. ✅ Добавить узел `claimsave_primary` в workflow после `Code4`
2. ✅ Исправить узел `Code4` в n8n (использовать `session_token`)
3. ✅ Исправить узел создания контакта в n8n (убрать `claim_id`, добавить `unified_id`)
4. ⏳ Протестировать создание нового обращения
5. ⏳ Проверить сохранение первичного черновика
---
## Файлы документации
- `ticket_form/docs/CLAIMSAVE_PRIMARY_DRAFT_FIX.md` - инструкция по настройке `claimsave`
- `ticket_form/docs/SQL_CLAIMSAVE_PRIMARY_DRAFT.sql` - SQL запрос для первичного черновика
- `ticket_form/docs/CODE4_FIXED.js` - исправленный код узла Code4
- `ticket_form/docs/CODE_CREATE_WEB_CONTACT_FINAL.js` - исправленный код создания контакта