Files
aiform_dev/docs/N8N_OCR_EVENTS_MINIMAL_PAYLOAD.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

5.0 KiB
Raw Permalink Blame History

Минимальный 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

Как бэкенд получает данные

  1. Фронтенд подключается к SSE через /events/{session_token} (например, /events/sess-1763201209156-hyjye5u9h)
  2. Бэкенд подписывается на Redis канал ocr_events:{session_token} (например, ocr_events:sess-1763201209156-hyjye5u9h)
  3. n8n пушит событие в этот канал с минимальным payload (только claim_id, session_token и т.д.)
  4. Бэкенд получает событие, извлекает claim_id из data.claim_id
  5. Бэкенд вызывает GET /api/v1/claims/wizard/load/{claim_id} для получения полных данных из PostgreSQL
  6. Бэкенд отправляет полные данные (wizard_plan, problem_description и т.д.) на фронтенд через SSE

Пример использования в n8n

После выполнения claimsave_primary:

  1. 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  // Для использования в следующей ноде
}];
  1. 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.

Преимущества

  • Минимум данных в Redis (только идентификаторы)
  • PostgreSQL как единственный источник истины
  • Легче отлаживать (всё в одном месте)
  • Меньше нагрузка на Redis
  • Проще масштабировать