Files
aiform_prod/docs/WORKFLOW_ANALYSIS.md

214 lines
8.8 KiB
Markdown
Raw Permalink Normal View History

# Анализ 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`
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