Files
aiform_dev/docs/N8N_USER_CREATION_INSTRUCTIONS.md
AI Assistant 0978e485dc feat: Add claim plan confirmation flow via Redis SSE
Problem:
- After wizard form submission, need to wait for claim data from n8n
- Claim data comes via Redis channel claim:plan:{session_token}
- Need to display confirmation form with claim data

Solution:
1. Backend: Added SSE endpoint /api/v1/claim-plan/{session_token}
   - Subscribes to Redis channel claim:plan:{session_token}
   - Streams claim data from n8n to frontend
   - Handles timeouts and errors gracefully

2. Frontend: Added subscription to claim:plan channel
   - StepWizardPlan: After form submission, subscribes to SSE
   - Waits for claim_plan_ready event
   - Shows loading message while waiting
   - On success: saves claimPlanData and shows confirmation step

3. New component: StepClaimConfirmation
   - Displays claim confirmation form in iframe
   - Receives claimPlanData from parent
   - Generates HTML form (placeholder - should call n8n for real HTML)
   - Handles confirmation/cancellation via postMessage

4. ClaimForm: Added conditional step for confirmation
   - Shows StepClaimConfirmation when showClaimConfirmation=true
   - Step appears after StepWizardPlan
   - Only visible when claimPlanData is available

Flow:
1. User fills wizard form → submits
2. Form data sent to n8n via /api/v1/claims/wizard
3. Frontend subscribes to SSE /api/v1/claim-plan/{session_token}
4. n8n processes data → publishes to Redis claim:plan:{session_token}
5. Backend receives → streams to frontend via SSE
6. Frontend receives → shows StepClaimConfirmation
7. User confirms → proceeds to next step

Files:
- backend/app/api/events.py: Added stream_claim_plan endpoint
- frontend/src/components/form/StepWizardPlan.tsx: Added subscribeToClaimPlan
- frontend/src/components/form/StepClaimConfirmation.tsx: New component
- frontend/src/pages/ClaimForm.tsx: Added confirmation step to steps array
2025-11-24 13:36:14 +03:00

3.9 KiB
Raw Blame History

Инструкция для n8n: Создание/поиск пользователя web_form

Контекст

После создания контакта в CRM через CreateWebContact, нужно найти или создать пользователя в PostgreSQL и получить unified_id для связи с черновиками.

Шаги в n8n workflow

1. После CreateWebContact

  • Получен contact_id из CRM
  • Есть phone из запроса

2. PostgreSQL Node: Find or Create User

Настройки:

  • Operation: Execute Query
  • Query: Использовать запрос из SQL_FIND_OR_CREATE_USER_WEB_FORM.sql
  • Parameters:
    • $1 = {{$json.phone}} (или {{$('CreateWebContact').item.json.phone}})

Запрос:

WITH existing AS (
  SELECT u.id AS user_id, u.unified_id
  FROM clpr_user_accounts ua
  JOIN clpr_users u ON u.id = ua.user_id
  WHERE ua.channel = 'web_form'
    AND ua.channel_user_id = $1
  LIMIT 1
),
create_user AS (
  INSERT INTO clpr_users (unified_id, phone, created_at, updated_at)
  SELECT 
    'usr_' || gen_random_uuid()::text,
    $1,
    now(),
    now()
  WHERE NOT EXISTS (SELECT 1 FROM existing)
  RETURNING id AS user_id, unified_id
),
final_user AS (
  SELECT * FROM existing
  UNION ALL
  SELECT * FROM create_user
),
update_unified AS (
  UPDATE clpr_users
  SET unified_id = COALESCE(
    unified_id,
    'usr_' || gen_random_uuid()::text
  ),
  updated_at = now()
  WHERE id = (SELECT user_id FROM final_user LIMIT 1)
    AND unified_id IS NULL
  RETURNING id AS user_id, unified_id
),
final_unified_id AS (
  SELECT unified_id FROM update_unified
  UNION ALL
  SELECT unified_id FROM final_user
  WHERE NOT EXISTS (SELECT 1 FROM update_unified)
  LIMIT 1
),
create_account AS (
  INSERT INTO clpr_user_accounts(user_id, channel, channel_user_id)
  SELECT
    (SELECT user_id FROM final_user LIMIT 1),
    'web_form',
    $1
  ON CONFLICT (channel, channel_user_id) DO UPDATE
    SET user_id = EXCLUDED.user_id
  RETURNING user_id, channel, channel_user_id
)
SELECT
  (SELECT unified_id FROM final_unified_id LIMIT 1) AS unified_id,
  (SELECT user_id FROM final_user LIMIT 1) AS user_id;

Результат:

{
  "unified_id": "usr_b2fd7f73-c238-4fde-949b-c404cded12f3",
  "user_id": 106
}

3. Сохранение unified_id в Redis

Set Node (Redis) или Code Node:

const unified_id = $input.item.json.unified_id;
const claim_id = $('CreateWebContact').item.json.claim_id; // или откуда берете claim_id

// Сохранить в Redis
await redis.set(`claim:${claim_id}`, JSON.stringify({
  ...existing_data,
  unified_id: unified_id
}));

4. Возврат unified_id в ответе frontend

Response Node или в Code Node перед возвратом:

return {
  success: true,
  result: {
    contact_id: $('CreateWebContact').item.json.contact_id,
    claim_id: $('CreateWebContact').item.json.claim_id,
    unified_id: $('PostgreSQL').item.json.unified_id,  // ← ВАЖНО!
    is_new_contact: $('CreateWebContact').item.json.is_new_contact
  }
};

Важно!

  1. unified_id должен быть в ответе - frontend сохраняет его в formData.unified_id
  2. При создании/обновлении черновика - заполнять clpr_claims.unified_id = unified_id
  3. Формат телефона: 79991234567 (11 цифр, начинается с 7)

Проверка работы

После выполнения запроса проверьте:

SELECT u.unified_id, u.phone, ua.channel, ua.channel_user_id 
FROM clpr_users u 
JOIN clpr_user_accounts ua ON u.id = ua.user_id 
WHERE ua.channel = 'web_form' 
  AND ua.channel_user_id = '79991234567';

Должна быть запись с unified_id в формате usr_....