- 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
5.0 KiB
Минимальный payload для ocr_events
Назначение
После сохранения первичного черновика в PostgreSQL через claimsave_primary, n8n должен пушить в Redis канал ocr_events:{session_token} только минимальный набор данных.
Важно: Канал формируется как ocr_events:{session_token}, где session_token - это токен сессии, который генерируется на фронтенде (например, sess-1763201209156-hyjye5u9h).
Бэкенд сам достанет полные данные из PostgreSQL по claim_id через эндпоинт /api/v1/claims/wizard/load/{claim_id}.
Формат данных для ocr_events
{
"event_type": "wizard_ready",
"status": "ready",
"message": "Wizard plan готов",
"data": {
"claim_id": "9d22d3f4-0306-4b77-a102-c0ca57b24a70",
"session_token": "sess-1763201209156-hyjye5u9h",
"status_code": "draft",
"unified_id": "usr_90599ff2-ac79-4236-b950-0df85395096c",
"contact_id": "320096",
"phone": "79262306381"
},
"timestamp": "2025-11-20T11:40:41Z"
}
Поля data
- claim_id (string, обязательное) - UUID заявки из PostgreSQL
- session_token (string, обязательное) - токен сессии пользователя
- status_code (string, опциональное) - статус заявки (обычно "draft")
- unified_id (string, опциональное) - unified_id пользователя
- contact_id (string, опциональное) - ID контакта в CRM
- phone (string, опциональное) - нормализованный номер телефона
Что НЕ нужно пушить
- ❌
wizard_plan- бэкенд достанет из PostgreSQL - ❌
problem_description- бэкенд достанет из PostgreSQL - ❌
wizard_answers- бэкенд достанет из PostgreSQL - ❌
ai_agent1_facts- бэкенд достанет из PostgreSQL - ❌
ai_agent13_rag- бэкенд достанет из PostgreSQL - ❌ Любые другие данные из
payload- всё в PostgreSQL
Как бэкенд получает данные
- Фронтенд подключается к SSE через
/events/{session_token}(например,/events/sess-1763201209156-hyjye5u9h) - Бэкенд подписывается на Redis канал
ocr_events:{session_token}(например,ocr_events:sess-1763201209156-hyjye5u9h) - n8n пушит событие в этот канал с минимальным payload (только
claim_id,session_tokenи т.д.) - Бэкенд получает событие, извлекает
claim_idизdata.claim_id - Бэкенд вызывает
GET /api/v1/claims/wizard/load/{claim_id}для получения полных данных из PostgreSQL - Бэкенд отправляет полные данные (wizard_plan, problem_description и т.д.) на фронтенд через SSE
Пример использования в n8n
После выполнения claimsave_primary:
- Code Node - формирует минимальный payload и определяет канал:
const claimData = $('claimsave_primary').first().json.claim;
const sessionToken = claimData.session_token;
const result = {
event_type: "wizard_ready",
status: "ready",
message: "Wizard plan готов",
data: {
claim_id: claimData.claim_id,
session_token: sessionToken,
status_code: claimData.status_code,
unified_id: $('propertyName').first().json.unified_id || null,
contact_id: $('Edit Fields10').first().json.contact_id || null,
phone: $('Edit Fields10').first().json.phone || null
},
timestamp: new Date().toISOString()
};
// Сохраняем session_token для использования в URL
return [{
json: result,
session_token: sessionToken // Для использования в следующей ноде
}];
-
HTTP Request Node - пушит в бэкенд:
- URL:
http://backend:8000/api/v1/events/{{ $json.session_token }} - Method: POST
- Body: JSON из Code Node (весь объект
result)
Важно: URL должен быть
http://backend:8000/api/v1/events/{session_token}, где{session_token}берётся из предыдущей ноды (например,sess-1763201209156-hyjye5u9h).Это создаст канал
ocr_events:sess-1763201209156-hyjye5u9h, к которому подключён фронтенд через SSE. - URL:
Преимущества
- ✅ Минимум данных в Redis (только идентификаторы)
- ✅ PostgreSQL как единственный источник истины
- ✅ Легче отлаживать (всё в одном месте)
- ✅ Меньше нагрузка на Redis
- ✅ Проще масштабировать