Files
aiform_dev/docs/DATABASE_SCHEMA.md
AI Assistant d6b17baa7d feat: Add PostgreSQL fields and workflow for form without files
Database changes:
- Add unified_id, contact_id, phone columns to clpr_claims table
- Create indexes for fast lookup by these fields
- Migrate existing data from payload to new columns
- SQL migration: docs/SQL_ALTER_CLPR_CLAIMS_ADD_FIELDS.sql

SQL improvements:
- Simplify claimsave query: remove complex claim_lookup logic
- Use UPSERT (INSERT ON CONFLICT) with known claim_id
- Always return claim (fix NULL issue)
- Store unified_id, contact_id, phone directly in table columns
- SQL: docs/SQL_CLAIMSAVE_UPSERT_SIMPLE.sql

Workflow enhancements:
- Add branch for form submissions WITHOUT files
- Create 6 new nodes: extract, prepare, save, redis, respond
- Separate flow for has_files=false in IF node
- Instructions: docs/N8N_FORM_GET_NO_FILES_INSTRUCTIONS.md
- Node config: docs/N8N_FORM_GET_NO_FILES_BRANCH.json

Migration stats:
- Total claims: 81
- With unified_id: 77
- Migrated from payload: 2

Next steps:
1. Add 6 nodes to n8n workflow form_get (ID: 8ZVMTsuH7Cmw7snw)
2. Connect TRUE branch of IF node to extract_webhook_data_no_files
3. Test form submission without files
4. Verify PostgreSQL save and Redis event
2025-11-21 15:57:18 +03:00

185 lines
5.3 KiB
Markdown
Raw 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.

# Схема базы данных clpr_*
## Основные таблицы
### 1. `clpr_users` - Основная таблица пользователей
```
id (integer, PK)
universal_id (uuid)
unified_id (varchar) ← КЛЮЧЕВОЕ ПОЛЕ для связи
phone (varchar)
created_at, updated_at
```
### 2. `clpr_user_accounts` - Связь пользователей с каналами
```
id (integer, PK)
user_id (integer) → FK на clpr_users.id
channel (text) - 'telegram', 'web_form'
channel_user_id (text) - ID в канале (telegram_id для telegram, phone для web_form)
```
**Связь:**
- `clpr_user_accounts.user_id``clpr_users.id`
- Уникальность: `(channel, channel_user_id)` - один пользователь может быть в нескольких каналах
### 3. `clpr_claims` - Заявки/черновики
```
id (uuid, PK)
session_token (varchar)
unified_id (varchar) ← СВЯЗЬ С clpr_users.unified_id (должен заполняться n8n!)
telegram_id (bigint)
channel (text) - 'telegram', 'web_form'
user_id (integer) - возможно FK на clpr_users.id
type_code (text)
status_code (text) - 'draft', 'in_work', etc.
policy_number (text)
payload (jsonb) - содержит phone, claim_id, wizard_plan, answers, documents_meta и т.д.
is_confirmed (boolean)
created_at, updated_at, expires_at
```
**Связь:**
- `clpr_claims.unified_id``clpr_users.unified_id` (логическая связь)
- `clpr_claims.user_id``clpr_users.id` (возможно, не всегда заполнено)
### 4. `clpr_users_tg` - Данные Telegram пользователей
```
telegram_id (bigint, PK)
unified_id (varchar) → clpr_users.unified_id
phone_number (varchar)
first_name_tg, last_name_tg, username, language_code, is_premium
first_name, last_name, middle_name, birth_date, etc.
```
### 5. `clpr_claim_documents` - Документы заявок
```
id (uuid, PK)
claim_id (varchar) → clpr_claims.id (логическая связь через payload->>'claim_id')
field_name (text)
file_id (text)
uploaded_at (timestamp)
file_name, original_file_name
```
### 6. `clpr_documents` - Хранилище документов
```
id (uuid, PK)
source (text)
content (text)
metadata (jsonb)
created_at
```
## Логика работы с черновиками для web_form
### Шаг 1: Проверка пользователя в CRM
- n8n вызывает `CreateWebContact` с phone
- Получает `contact_id` из CRM
### Шаг 2: Поиск/создание пользователя в PostgreSQL
SQL запрос (аналогично Telegram):
```sql
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 = '{phone}'
LIMIT 1
),
create_user AS (
INSERT INTO clpr_users (unified_id, phone, created_at, updated_at)
SELECT 'usr_' || gen_random_uuid()::text, '{phone}', 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
),
create_account AS (
INSERT INTO clpr_user_accounts(user_id, channel, channel_user_id)
SELECT
(SELECT user_id FROM final_user),
'web_form',
'{phone}'
ON CONFLICT (channel, channel_user_id) DO NOTHING
)
SELECT unified_id FROM final_user LIMIT 1;
```
### Шаг 3: Создание/обновление заявки
- n8n создает/обновляет запись в `clpr_claims`
- **ВАЖНО:** заполняет `unified_id` из результата шага 2
- Сохраняет `phone` в `payload->>'phone'`
- `channel = 'web_form'`
- `status_code = 'draft'` для черновиков
### Шаг 4: Поиск черновиков
```sql
SELECT
c.id,
c.payload->>'claim_id' as claim_id,
c.session_token,
c.status_code,
c.payload,
c.created_at,
c.updated_at
FROM clpr_claims c
WHERE c.status_code = 'draft'
AND c.channel = 'web_form'
AND c.unified_id = '{unified_id}' -- ← ПОИСК ПО unified_id!
ORDER BY c.updated_at DESC
LIMIT 20;
```
## Проблема в текущей реализации
**Текущее состояние:**
- В `clpr_claims` поле `unified_id` **ПУСТОЕ** для всех черновиков web_form
- Поиск идет по `payload->>'phone'` или `session_token`, что не надежно
**Решение:**
- n8n должен заполнять `unified_id` при создании/обновлении заявки
- Backend должен искать черновики по `unified_id`, а не по phone/session_id
## Связи между таблицами
```
clpr_users (unified_id)
| (через unified_id)
|
clpr_claims (unified_id)
|
| (через user_id)
clpr_user_accounts (user_id → clpr_users.id)
|
| (channel='web_form', channel_user_id=phone)
clpr_claims (payload->>'phone')
```
## Для Telegram (для сравнения)
```
clpr_users (unified_id)
| (через unified_id)
|
clpr_users_tg (unified_id)
|
| (telegram_id)
clpr_user_accounts (channel='telegram', channel_user_id=telegram_id)
|
| (user_id)
clpr_users (id)
```