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