- 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
226 lines
9.5 KiB
Markdown
226 lines
9.5 KiB
Markdown
# Инструкция: Добавление узла `claimsave_primary` в workflow b4K4u851b4JFivyD
|
||
|
||
## Позиция узла
|
||
|
||
**Между узлами:**
|
||
- **После:** `Code4` (форматирует данные для Redis)
|
||
- **Перед:** `push_wizard1` (пушит wizard_plan в Redis для SSE)
|
||
|
||
## Порядок узлов в workflow
|
||
|
||
```
|
||
1. Redis Trigger
|
||
2. get_claime_data1
|
||
3. Edit Fields8
|
||
4. Merge2
|
||
5. Get row(s) in sheet2
|
||
6. Edit Fields16
|
||
7. AI Agent1
|
||
8. пробрасываем факт фул и факт шорт1
|
||
9. AI Agent13
|
||
10. output_set1
|
||
11. Edit Fields11
|
||
12. AI Agent12
|
||
13. Code
|
||
14. Code4
|
||
15. ⭐ Code: Prepare Claimsave Data ← ВСТАВИТЬ ЗДЕСЬ (Code Node)
|
||
16. ⭐ claimsave_primary ← ВСТАВИТЬ ЗДЕСЬ (PostgreSQL)
|
||
17. push_wizard1
|
||
```
|
||
|
||
## Шаги настройки
|
||
|
||
### 1. Добавить Code Node для подготовки данных
|
||
|
||
**Рекомендуется:** Добавить Code Node перед PostgreSQL для удобства отладки и валидации данных.
|
||
|
||
1. Откройте workflow `b4K4u851b4JFivyD` в n8n
|
||
2. Найдите узел `Code4`
|
||
3. Добавьте новый узел **Code** после `Code4`
|
||
4. Назовите узел: `Code: Prepare Claimsave Data`
|
||
5. Подключите:
|
||
- **Вход:** от узла `Code4`
|
||
- **Выход:** к узлу `claimsave_primary` (PostgreSQL)
|
||
|
||
**Код для Code Node:** См. файл `docs/CODE_CLAIMSAVE_PRIMARY_PREPARE.js`
|
||
|
||
**Режим выполнения:** `Run Once for All Items`
|
||
|
||
### 2. Добавить новый узел PostgreSQL
|
||
|
||
1. Откройте workflow `b4K4u851b4JFivyD` в n8n
|
||
2. Найдите узел `Code4`
|
||
3. Добавьте новый узел **PostgreSQL** после `Code4`
|
||
4. Назовите узел: `claimsave_primary`
|
||
5. Подключите:
|
||
- **Вход:** от узла `Code4`
|
||
- **Выход:** к узлу `push_wizard1`
|
||
|
||
### 2. Настройка PostgreSQL узла
|
||
|
||
**Connection:** Выберите подключение к PostgreSQL (то же, что используется в других узлах)
|
||
|
||
**Operation:** `Execute Query`
|
||
|
||
**Query:** Вставьте SQL из файла `docs/SQL_CLAIMSAVE_PRIMARY_DRAFT_CLEAN.sql` (чистая версия без плейсхолдеров)
|
||
|
||
**⚠️ ВАЖНО:** Используйте файл `SQL_CLAIMSAVE_PRIMARY_DRAFT_CLEAN.sql`, а не `SQL_CLAIMSAVE_PRIMARY_DRAFT.sql`!
|
||
|
||
### 3. Параметры запроса
|
||
|
||
**Query Replacement:** Оставьте пустым (не используем)
|
||
|
||
**Parameters:** Добавьте 3 параметра (если используете Code Node для подготовки):
|
||
|
||
#### Параметр $1 (payload_json):
|
||
```javascript
|
||
{{ JSON.stringify($('Code: Prepare Claimsave Data').first().json.payload_json) }}
|
||
```
|
||
|
||
#### Параметр $2 (session_token):
|
||
```javascript
|
||
{{ $('Code: Prepare Claimsave Data').first().json.session_token }}
|
||
```
|
||
|
||
#### Параметр $3 (unified_id):
|
||
```javascript
|
||
{{ $('Code: Prepare Claimsave Data').first().json.unified_id }}
|
||
```
|
||
|
||
**Примечание:** Code Node берёт `unified_id` из ноды `propertyName` (приоритет: `propertyName` > `Edit Fields10` > `Redis Trigger`)
|
||
|
||
---
|
||
|
||
**Альтернатива (без Code Node):** Если не используете Code Node, можно собрать данные напрямую:
|
||
|
||
#### Параметр $1 (payload_json):
|
||
```javascript
|
||
{{ JSON.stringify({
|
||
problem_description: $('Edit Fields16').first().json.chatInput,
|
||
wizard_plan: $('Code4').first().json.redis_value.wizard_plan,
|
||
answers_prefill: $('Code4').first().json.redis_value.answers_prefill || [],
|
||
coverage_report: $('Code4').first().json.redis_value.coverage_report || {},
|
||
ai_agent1_facts: {
|
||
facts_short: $('пробрасываем факт фул и факт шорт1').first().json.facts_short,
|
||
facts_full: $('пробрасываем факт фул и факт шорт1').first().json.facts_full,
|
||
problem: $('пробрасываем факт фул и факт шорт1').first().json.problem
|
||
},
|
||
ai_agent13_rag: $('AI Agent13').first().json.output,
|
||
phone: $('Redis Trigger').first().json.message.phone,
|
||
email: $('Redis Trigger').first().json.message.email || null,
|
||
type_code: $('Code4').first().json.redis_value.wizard_plan?.case_type || 'consumer'
|
||
}) }}
|
||
```
|
||
|
||
#### Параметр $2 (session_token):
|
||
```javascript
|
||
{{ $('Edit Fields11').first().json.session_token || $('Redis Trigger').first().json.message.session_id }}
|
||
```
|
||
|
||
#### Параметр $3 (unified_id):
|
||
```javascript
|
||
{{ $('propertyName').first().json.unified_id || $('Edit Fields10').first().json.unified_id || $('Redis Trigger').first().json.message.unified_id || null }}
|
||
```
|
||
|
||
**Примечание:** Приоритет источников `unified_id`: `propertyName` > `Edit Fields10` > `Redis Trigger`
|
||
|
||
### 4. Проверка подключений
|
||
|
||
Убедитесь, что:
|
||
- ✅ Узел `Code: Prepare Claimsave Data` получает данные от `Code4`
|
||
- ✅ Узел `claimsave_primary` получает данные от `Code: Prepare Claimsave Data`
|
||
- ✅ Узел `push_wizard1` получает данные от `claimsave_primary` (или от `Code4`, если нужно)
|
||
- ✅ Все пути данных корректны
|
||
|
||
## Преимущества использования Code Node
|
||
|
||
✅ **Упрощение параметров PostgreSQL:** Вместо сложных выражений в параметрах SQL, используем простые ссылки на Code Node
|
||
|
||
✅ **Валидация данных:** Code Node проверяет наличие обязательных полей и выводит предупреждения
|
||
|
||
✅ **Отладка:** Легче отслеживать, какие данные собраны, через логи Code Node
|
||
|
||
✅ **Обработка edge cases:** Можно добавить fallback значения и обработку ошибок
|
||
|
||
✅ **Читаемость:** Код подготовки данных отделён от SQL запроса
|
||
|
||
## Что сохраняется
|
||
|
||
После выполнения узла `claimsave_primary` в БД будет создана/обновлена запись в `clpr_claims`:
|
||
|
||
- ✅ `session_token` - для связи
|
||
- ✅ `unified_id` - если передан
|
||
- ✅ `status_code = 'draft'` - статус черновика
|
||
- ✅ `payload.wizard_plan` - план вопросов
|
||
- ✅ `payload.problem_description` - описание проблемы
|
||
- ✅ `payload.answers_prefill` - предзаполненные ответы
|
||
- ✅ `payload.coverage_report` - отчёт о покрытии
|
||
- ✅ `payload.ai_agent1_facts` - факты из AI Agent1
|
||
- ✅ `payload.ai_agent13_rag` - RAG ответ
|
||
- ✅ `payload.phone`, `payload.email` - контакты
|
||
- ⚠️ `payload.claim_id = NULL` - будет сгенерирован позже
|
||
|
||
## Возвращаемое значение
|
||
|
||
Узел возвращает объект:
|
||
```json
|
||
{
|
||
"claim": {
|
||
"claim_id": "uuid-записи",
|
||
"session_token": "sess-...",
|
||
"status_code": "draft",
|
||
"payload": { ... }
|
||
}
|
||
}
|
||
```
|
||
|
||
## Важные замечания
|
||
|
||
1. **Узел работает в режиме UPSERT:**
|
||
- Если запись с таким `session_token` существует → обновляет её
|
||
- Если записи нет → создаёт новую
|
||
|
||
2. **`claim_id` генерируется позже:**
|
||
- На этом этапе `claim_id` в `payload` = `NULL`
|
||
- UUID записи (`clpr_claims.id`) используется как временный идентификатор
|
||
- Позже `claim_id` будет сгенерирован в формате `CLM-YYYY-MM-DD-XXXXXX`
|
||
|
||
3. **Данные из предыдущих узлов:**
|
||
- `wizard_plan` берётся из `Code4.redis_value.wizard_plan`
|
||
- `problem_description` берётся из `Edit Fields16.chatInput`
|
||
- `ai_agent1_facts` берётся из узла `пробрасываем факт фул и факт шорт1`
|
||
- `ai_agent13_rag` берётся из `AI Agent13.output`
|
||
|
||
## Тестирование
|
||
|
||
После добавления узла:
|
||
|
||
1. Запустите workflow с тестовыми данными
|
||
2. Проверьте, что узел выполняется без ошибок
|
||
3. Проверьте в БД, что запись создана/обновлена:
|
||
```sql
|
||
SELECT id, session_token, unified_id, status_code, payload->>'wizard_plan'
|
||
FROM clpr_claims
|
||
WHERE session_token = 'sess-...'
|
||
ORDER BY updated_at DESC
|
||
LIMIT 1;
|
||
```
|
||
|
||
## Если что-то не работает
|
||
|
||
1. **Ошибка "column does not exist":**
|
||
- Проверьте, что все поля в SQL запросе существуют в таблице `clpr_claims`
|
||
|
||
2. **Ошибка "invalid input syntax for type jsonb":**
|
||
- Проверьте, что параметр `$1` правильно сериализован через `JSON.stringify()`
|
||
- Убедитесь, что все вложенные объекты корректны
|
||
|
||
3. **Ошибка "session_token is null":**
|
||
- Проверьте, что `Edit Fields11` содержит `session_token`
|
||
- Проверьте fallback на `Redis Trigger.message.session_id`
|
||
|
||
4. **Данные не сохраняются:**
|
||
- Проверьте логи n8n на наличие ошибок
|
||
- Проверьте, что все узлы-источники данных выполнены успешно
|
||
|