Files
aiform_prod/docs/WORKFLOW_ANALYSIS.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

214 lines
8.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Анализ workflow 8ZVMTsuH7Cmw7snw и предложения
## Текущая структура
### Основные ноды PostgreSQL:
1. **`claimsave`** (строка 190-210)
- Использует обновленный SQL с `$2::text` (строка claim_id)
- **ПРОБЛЕМА**: SQL запрос не использует `claim_final` CTE, который я добавил в исправленной версии
- Это основная нода для сохранения данных визарда
2. **`claimsave_final`** (строка 428-450)
- Использует другой SQL запрос с `$2::uuid`
- Используется после конвертации файлов в PDF
- **ПРОБЛЕМА**: Ожидает UUID, но может получать строку
3. **`claimsave1`** (строка 634-655)
- Использует старый SQL запрос с `$2::uuid`
- **ПРОБЛЕМА**: Не работает со строковым claim_id
## Проблемы
### 1. SQL запрос в `claimsave` неполный
Текущий SQL в ноде `claimsave`:
- ✅ Использует `$2::text` (правильно)
- ✅ Имеет `claim_lookup` и `claim_created` CTE
-**НЕ использует `claim_final` CTE** (который я добавил в исправленной версии)
- ❌ Использует `claim_lookup.claim_uuid` напрямую, что может не работать, если запись была создана в `claim_created`
### 2. Несоответствие типов данных
- `claimsave` ожидает строку (`$2::text`)
- `claimsave_final` ожидает UUID (`$2::uuid`)
- `claimsave1` ожидает UUID (`$2::uuid`)
Но везде передается `claim_id` как строка `"CLM-2025-11-18-GEQ3KL"`.
### 3. Проблема с `existing` CTE
В текущем SQL запросе `existing` может не найти запись, если она была создана в `claim_created`, потому что:
- `claim_lookup` выполняется ДО `claim_created`
- `existing` использует `claim_lookup.claim_uuid`, но запись может быть создана в `claim_created`
## Решения
### Решение 1: Обновить SQL в ноде `claimsave`
Заменить SQL запрос на исправленную версию из `FIXED_SQL_QUERY.md`:
**Ключевые изменения:**
1. Добавить `claim_final` CTE для получения правильного UUID
2. Использовать `claim_final.claim_uuid` вместо `claim_lookup.claim_uuid`
3. Исправить `old` CTE, чтобы он всегда возвращал строку
### Решение 2: Унифицировать типы данных
**Вариант A**: Все ноды используют строку `claim_id`
- Изменить `claimsave_final` и `claimsave1` на `$2::text`
- Добавить логику поиска UUID по строке `claim_id`
**Вариант B**: Все ноды используют UUID
- Перед SQL запросами добавить Code Node, который:
- Находит запись в `clpr_claims` по `payload->>'claim_id'`
- Извлекает её `id` (UUID)
- Передает UUID в SQL запрос
**Рекомендую Вариант A** (использовать строку везде), т.к.:
- Проще реализовать
- Меньше изменений в workflow
- `claim_id` в формате `CLM-YYYY-MM-DD-XXXXXX` - это основной идентификатор
### Решение 3: Упростить логику
Можно упростить SQL запрос, убрав сложную логику слияния:
```sql
WITH partial AS (
SELECT $1::jsonb AS p, $2::text AS claim_id_str
),
-- Находим или создаем запись
claim_final AS (
SELECT
COALESCE(
(SELECT id FROM clpr_claims WHERE payload->>'claim_id' = partial.claim_id_str LIMIT 1),
gen_random_uuid()
) AS claim_uuid
FROM partial
),
-- Создаем запись, если её нет
claim_created AS (
INSERT INTO clpr_claims (
id, session_token, channel, type_code, status_code, payload, created_at, updated_at, expires_at
)
SELECT
claim_final.claim_uuid,
COALESCE(partial.p->>'session_id', 'sess-' || gen_random_uuid()::text),
'web_form',
COALESCE(partial.p->>'type_code', 'consumer'),
'draft',
jsonb_build_object(
'claim_id', partial.claim_id_str,
'answers', COALESCE(partial.p->'answers', '{}'::jsonb),
'documents_meta', COALESCE(partial.p->'documents_meta', '[]'::jsonb),
'wizard_plan', partial.p->'wizard_plan',
'wizard_answers', partial.p->'wizard_answers',
'form_data', partial.p
),
now(), now(), now() + interval '14 days'
FROM partial, claim_final
WHERE NOT EXISTS (SELECT 1 FROM clpr_claims WHERE id = claim_final.claim_uuid)
ON CONFLICT (id) DO NOTHING
RETURNING id
),
-- Сохраняем документы
inserted_docs AS (
INSERT INTO clpr_claim_documents
(claim_id, field_name, file_id, uploaded_at, file_name, original_file_name)
SELECT
claim_final.claim_uuid::text,
doc.field_name, doc.file_id,
(doc.uploaded_at)::timestamptz,
doc.file_name, doc.original_file_name
FROM partial, claim_final
CROSS JOIN LATERAL jsonb_to_recordset(
COALESCE(partial.p->'documents_meta','[]'::jsonb)
) AS doc(field_name text, file_id text, file_name text, original_file_name text, uploaded_at text)
ON CONFLICT (claim_id, field_name) DO UPDATE
SET file_id = EXCLUDED.file_id,
uploaded_at = EXCLUDED.uploaded_at,
file_name = EXCLUDED.file_name,
original_file_name = EXCLUDED.original_file_name
RETURNING id, claim_id, field_name, file_id
),
-- Обновляем запись (простое слияние)
upd AS (
UPDATE clpr_claims c
SET
payload = COALESCE(c.payload, '{}'::jsonb) || partial.p,
status_code = CASE
WHEN (partial.p->'answers'->>'docs_exist' = 'true') THEN 'in_work'
ELSE COALESCE(c.status_code, 'draft')
END,
updated_at = now(),
expires_at = now() + interval '14 days'
FROM partial, claim_final
WHERE c.id = claim_final.claim_uuid
RETURNING c.id, c.status_code, c.payload
)
SELECT
(SELECT jsonb_build_object(
'claim_id', u.id::text,
'claim_id_str', (u.payload->>'claim_id'),
'status_code', u.status_code,
'payload', u.payload
) FROM upd u LIMIT 1) AS claim,
(SELECT jsonb_agg(jsonb_build_object(
'id', id,
'field_name', field_name,
'file_id', file_id
)) FROM inserted_docs) AS documents;
```
## Рекомендации
### Немедленные действия:
1. **Обновить SQL в ноде `claimsave`**
- Заменить на исправленную версию из `FIXED_SQL_QUERY.md`
- Или использовать упрощенную версию выше
2. **Проверить параметры**
- Убедиться, что `queryReplacement` правильный: `={{ $json.payload_partial_json }}, {{ $json.claim_id }}`
- `payload_partial_json` должен быть JSON объектом
- `claim_id` должен быть строкой
3. **Протестировать**
- Запустить workflow с тестовыми данными
- Проверить, что `claim` не возвращает `null`
- Проверить, что документы сохраняются правильно
### Долгосрочные улучшения:
1. **Унифицировать все SQL запросы**
- Привести `claimsave_final` и `claimsave1` к единому формату
- Использовать строковый `claim_id` везде
2. **Добавить обработку ошибок**
- Проверять результат SQL запроса
- Логировать ошибки
- Возвращать понятные сообщения об ошибках
3. **Оптимизировать workflow**
- Упростить логику слияния payload
- Использовать транзакции для атомарности операций
## Готовый SQL для копирования
Полный исправленный SQL запрос находится в файле `FIXED_SQL_QUERY.md`.
Основные изменения:
- ✅ Использует `claim_final` CTE для правильного получения UUID
-`old` CTE всегда возвращает строку (даже если запись не найдена)
-Все подзапросы используют `LIMIT 1` для гарантии одной строки
- ✅ Правильное слияние `answers` и `documents_meta`