docs: Лог сессии 01 ноября - CreateWebProject + SMS валидация + n8n интеграция

- Создана операция CreateWebProject для vTiger CRM
- Исправлена валидация SMS кодов (нормализация телефона)
- Добавлен вызов n8n webhook после SMS верификации
- Backend подключён к внешнему Redis
- Frontend пересобран с интеграцией CRM
- Протестировано: создание/поиск проектов, SMS коды, n8n workflow
- Все изменения задокументированы
This commit is contained in:
AI Assistant
2025-11-01 13:39:16 +03:00
parent 89a182bc7b
commit 6b1979c93f

723
SESSION_LOG_2025-11-01.md Normal file
View File

@@ -0,0 +1,723 @@
# 📋 Лог сессии: CreateWebProject + Интеграция SMS → CRM
**Дата:** 01 ноября 2025 (10:00 - 13:30 MSK)
**Задачи:**
1. Создание операции CreateWebProject для vTiger CRM
2. Исправление валидации SMS кодов
3. Интеграция n8n webhook для создания контакта после SMS верификации
**Статус:** ✅ Успешно завершено
---
## 🎯 Основные задачи
### Задача 1: CreateWebProject
Создать операцию vTiger webservice для создания проекта по аналогии с CreateWebContact.
**Требования:**
- Обязательные поля: `policy_number` (cf_1885), `contact_id`
- Опциональные: `period_start` (cf_1887), `period_end` (cf_1889)
- Логика: если проект с таким полисом существует → возврат ID без обновления
- Если не существует → создание нового
- Возврат: `{"project_id": "123", "is_new": true/false}`
### Задача 2: SMS валидация
Исправить проблему с валидацией SMS кодов (формат телефона).
### Задача 3: n8n интеграция
Добавить вызов n8n webhook после SMS верификации для создания контакта в CRM.
---
## ✅ Выполненные задачи
### 1. CreateWebProject.php - Операция vTiger Webservice
**Файл:** `include/Webservices/CreateWebProject.php`
**Обязательные параметры:**
- `policy_number` - номер полиса ERV (cf_1885)
- `contact_id` - ID контакта для привязки
**Опциональные параметры:**
- `period_start` - дата начала страхования (cf_1887)
- `period_end` - дата окончания страхования (cf_1889)
**Логика работы:**
```php
1. Ищем проект по номеру полиса (cf_1885):
SELECT p.projectid FROM vtiger_project p
INNER JOIN vtiger_projectcf pcf ON p.projectid = pcf.projectid
WHERE e.deleted = 0 AND pcf.cf_1885 = 'E1000-123456789'
2. Если найден возвращаем ID БЕЗ обновления:
{"project_id": "396865", "is_new": false}
3. Если НЕ найден создаём новый:
- projectname: "ERV E1000-123456789 цифровой адвокат"
- projectstatus: "модерация"
- projecttype: "ерв урегулирование"
- linktoaccountscontacts: "12x{contact_id}"
- cf_1994: "11x67458" (Заявитель - контрагент)
- cf_1885: номер полиса
{"project_id": "396866", "is_new": true}
```
**Регистрация в БД:**
```sql
-- vtiger_ws_operation
INSERT INTO vtiger_ws_operation (
operationid, name, handler_path, handler_method, type, prelogin
) VALUES (
51,
'CreateWebProject',
'include/Webservices/CreateWebProject.php',
'vtws_createwebproject',
'POST',
0
);
-- vtiger_ws_operation_parameters
INSERT INTO vtiger_ws_operation_parameters (operationid, name, type, sequence)
VALUES
(51, 'policy_number', 'String', 1),
(51, 'contact_id', 'String', 2),
(51, 'period_start', 'String', 3),
(51, 'period_end', 'String', 4);
```
**Тестирование:**
```bash
# Тест 1: Создание нового проекта
Policy: E1000-TEST-1761990646
Contact: 396625
Result: {"project_id":"396865","is_new":true}
# Тест 2: Повторный вызов (поиск существующего)
Policy: E1000-TEST-1761990646
Contact: 396625
Result: {"project_id":"396865","is_new":false}
```
**Логи:** `logs/CreateWebProject.log`
---
### 2. Исправление валидации SMS кодов
**Проблема:**
```
При отправке: ключ в Redis = erv:sms_verify:+79262306381 (С ПЛЮСОМ)
При проверке: поиск ключа = sms_verify:79262306381 (БЕЗ ПЛЮСА)
Результат: "No verification code found" ❌
```
**Причина:** Несоответствие формата телефона между отправкой и проверкой.
**Решение:**
**Файл:** `backend/app/services/sms_service.py`
```python
async def send_verification_code(self, phone: str) -> Optional[str]:
# Нормализуем формат телефона (убираем + если есть)
phone = phone.replace("+", "").replace("-", "").replace(" ", "")
verification_key = f"sms_verify:{phone}" # → sms_verify:79262306381
await redis_service.set(verification_key, code, expire=600)
...
async def verify_code(self, phone: str, code: str) -> bool:
# Нормализуем формат телефона (убираем + если есть)
phone = phone.replace("+", "").replace("-", "").replace(" ", "")
verification_key = f"sms_verify:{phone}" # → sms_verify:79262306381
stored_code = await redis_service.get(verification_key)
...
```
**Дополнительно:**
- Отключен rate limiting (60 сек задержка) для тестирования
- Добавлено детальное логирование сравнения кодов
- Backend подключён к внешнему Redis: `crm.clientright.ru:6379`
**Проверка:**
```bash
# До исправления
redis-cli> GET "erv:sms_verify:+79262306381" # Ключ с +
"123456"
# Проверка ищет без + → не находит ❌
# После исправления
redis-cli> GET "erv:sms_verify:79262306381" # Ключ без +
"123456"
# Проверка ищет без + → находит ✅
```
---
### 3. Интеграция n8n webhook после SMS верификации
**Проблема:** После SMS верификации контакт не создавался в CRM автоматически.
**Решение:**
**Файл:** `frontend/src/components/form/Step1Phone.tsx`
```typescript
// После успешной SMS верификации
if (response.ok) {
addDebugEvent?.('sms', 'success', `✅ Телефон подтвержден успешно`);
message.success('Телефон подтвержден!');
setIsPhoneVerified(true);
// 🆕 Вызов n8n webhook для создания контакта
try {
addDebugEvent?.('crm', 'info', '📞 Создание контакта в CRM...');
const crmResponse = await fetch(
'https://n8n.clientright.pro/webhook/511fde97-88bb-4fb4-bea5-cafdc364be27',
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ phone }) // 79001234567
}
);
const crmResult = await crmResponse.json();
if (crmResponse.ok) {
addDebugEvent?.('crm', 'success', `✅ Контакт создан/найден в CRM`, crmResult);
// Сохраняем данные из CRM в форму
updateFormData({
phone,
contact_id: crmResult.contact_id,
claim_id: crmResult.claim_id,
is_new_contact: crmResult.is_new_contact
});
message.success(crmResult.is_new_contact ? 'Контакт создан!' : 'Контакт найден!');
onNext();
} else {
addDebugEvent?.('crm', 'error', '❌ Ошибка создания контакта в CRM');
message.error('Ошибка создания контакта в CRM');
}
} catch (crmError) {
addDebugEvent?.('crm', 'error', '❌ Ошибка соединения с CRM');
message.error('Ошибка соединения с CRM');
}
}
```
**Workflow n8n (get_contact_CRM):**
```
Webhook: https://n8n.clientright.pro/webhook/511fde97-88bb-4fb4-bea5-cafdc364be27
Input: {"phone": "79001234567"}
Флоу:
1. Edit Fields (извлечение phone)
2. Get Challenge (vTiger webservice)
3. Execute a command (md5 hash)
4. Login to CRM
5. CreateWebContact (создание/поиск контакта)
6. Code in JavaScript (парсинг JSON + генерация claim_id)
7. Redis (сохранение session:claim:{claim_id})
8. Respond to Webhook
Output: {
"claim_id": "CLM-2025-11-01-XXXXX",
"contact_id": "396625",
"is_new_contact": false,
"phone": "79001234567"
}
```
**Redis Session:**
```
Ключ: claim:CLM-2025-11-01-IWR1U2
TTL: 604800 секунд (7 дней)
Значение: {
"claim_id": "CLM-2025-11-01-IWR1U2",
"contact_id": "396625",
"phone": "79001234567",
"is_new_contact": false,
"status": "draft",
"current_step": 1,
"created_at": "2025-11-01T10:15:32.123Z",
"updated_at": "2025-11-01T10:15:32.123Z",
"voucher": null,
"event_type": null,
"documents": {}
}
```
---
### 4. Обновлён FormData интерфейс
**Файл:** `frontend/src/pages/ClaimForm.tsx`
```typescript
interface FormData {
// 🆕 Шаг 1: Phone
phone?: string;
contact_id?: string;
is_new_contact?: boolean;
// Шаг 2: Policy
voucher: string;
claim_id?: string;
session_id?: string;
// Шаг 3: Event Type
eventType?: string;
// Шаги 4+: Documents
documents?: Record<string, {...}>;
// Последний шаг: Payment
fullName?: string;
email?: string;
paymentMethod?: string;
bankName?: string;
cardNumber?: string;
accountNumber?: string;
}
```
---
### 5. Исправлён docker-compose.yml
**Проблемы:**
1. Backend пытался подключиться к локальному Redis (localhost:6379)
2. Попытка запуска локальных контейнеров redis/postgres, которые не нужны
**Решение:**
```yaml
backend:
build: ./backend
ports:
- "8100:8100"
environment:
# 🆕 Подключение к внешнему Redis
- REDIS_HOST=crm.clientright.ru
- REDIS_PORT=6379
- REDIS_PASSWORD=CRM_Redis_Pass_2025_Secure!
- POSTGRES_URL=postgresql://erv_user:erv_password@postgres:5432/erv_db
- RABBITMQ_URL=amqp://admin:tyejvtej@185.197.75.249:5672
# 🆕 Убраны зависимости от локальных сервисов
# depends_on:
# - redis
# - postgres
networks:
- erv-network
restart: unless-stopped
```
**Статус сервисов:**
- ✅ Backend подключён к внешнему Redis (crm.clientright.ru:6379)
- ✅ Backend подключён к внешнему PostgreSQL (147.45.189.234:5432)
- ✅ RabbitMQ подключён (185.197.75.249:5672)
- ✅ S3 подключён (Timeweb Cloud Storage)
---
## 🐛 Исправленные проблемы
### Проблема 1: UNKNOWN_OPERATION для CreateWebProject
**Симптом:**
```json
{"success":false,"error":{"code":"UNKNOWN_OPERATION","message":"Unknown operation requested"}}
```
**Причина:** Неправильная структура регистрации в БД.
**Было:**
```sql
INSERT INTO vtiger_ws_operation
VALUES (51, 'CreateWebProject', 'include/Webservices/CreateWebProject.php', ...)
-- Поле 'handler' вместо 'handler_path' и 'handler_method'
```
**Стало:**
```sql
INSERT INTO vtiger_ws_operation (
operationid, name, handler_path, handler_method, type, prelogin
) VALUES (
51,
'CreateWebProject',
'include/Webservices/CreateWebProject.php',
'vtws_createwebproject', -- ⭐ Имя функции!
'POST',
0
);
```
**Решение:** Используем правильные поля `handler_path` и `handler_method`.
---
### Проблема 2: BOM символ в CreateWebProject.php
**Симптом:**
```json
{"success":true,"result":...}
```
**Причина:** Файл сохранён с UTF-8 BOM.
**Решение:**
```bash
sed -i '1s/^\xEF\xBB\xBF//' include/Webservices/CreateWebProject.php
```
---
### Проблема 3: SMS код не валидируется
**Симптом:**
```
Отправка: +79262306381
Redis key: erv:sms_verify:+79262306381
Проверка: 79262306381
Redis key: sms_verify:79262306381
Результат: "No verification code found"
```
**Решение:** Нормализация телефона в обоих методах (убираем `+`, `-`, пробелы).
---
### Проблема 4: Backend не подключается к Redis
**Симптом:**
```
❌ Redis connection error: Error connecting to localhost:6379
```
**Причина:**
- `docker-compose.yml` имел `REDIS_URL=redis://redis:6379`
- Backend пытался подключиться к локальному Redis
- Локальный Redis конфликтовал с внешним на порту 6379
**Решение:**
```yaml
environment:
- REDIS_HOST=crm.clientright.ru
- REDIS_PORT=6379
- REDIS_PASSWORD=CRM_Redis_Pass_2025_Secure!
```
---
### Проблема 5: Step1Phone не отображается на первом шаге
**Симптом:** Поле телефона пропало с первой страницы.
**Причина:** Забыл добавить импорт и регистрацию в `steps` массиве.
**Решение:**
```typescript
// ClaimForm.tsx
import Step1Phone from '../components/form/Step1Phone';
const steps = useMemo(() => {
const stepsArray: any[] = [];
// 🆕 Шаг 1: Phone
stepsArray.push({
title: 'Телефон',
description: 'Подтверждение по SMS',
content: <Step1Phone ... />
});
// Шаг 2: Policy
stepsArray.push({
title: 'Проверка полиса',
...
});
...
}, [...]);
```
---
### Проблема 6: n8n webhook не вызывается
**Симптом:** После SMS верификации контакт не создаётся в CRM.
**Причина:**
1. Код добавлен на хосте, но не попал в Docker контейнер
2. Frontend не был пересобран
**Решение:**
```bash
cd erv_platform
docker-compose down frontend
docker-compose up -d --build frontend
```
**Проверка:**
```bash
docker exec -i erv_platform_frontend_1 sh -c \
"grep -n 'n8n.clientright.pro/webhook' /app/src/components/form/Step1Phone.tsx"
# Результат:
94: const crmResponse = await fetch('https://n8n.clientright.pro/webhook/511fde97-88bb-4fb4-bea5-cafdc364be27', {
```
---
## 📊 Итоговая архитектура
### Флоу создания заявки:
```
┌─────────────────────────────────────────────────────────────┐
│ Шаг 1: Телефон + SMS │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 1. Пользователь вводит телефон: 9001234567 │ │
│ │ 2. Frontend → POST /api/v1/sms/send │ │
│ │ 3. Backend генерирует код → Redis │ │
│ │ 4. Пользователь вводит код из SMS │ │
│ │ 5. Frontend → POST /api/v1/sms/verify │ │
│ │ 6. Backend проверяет код в Redis │ │
│ │ 7. ✅ Код верный → вызов n8n webhook │ │
│ │ 8. n8n → CreateWebContact (CRM) │ │
│ │ 9. n8n генерирует claim_id │ │
│ │ 10. n8n сохраняет сессию в Redis │ │
│ │ 11. n8n → Response: {contact_id, claim_id, is_new} │ │
│ │ 12. Frontend сохраняет данные в formData │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ Шаг 2: Полис │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 1. Пользователь вводит номер полиса │ │
│ │ 2. Frontend → n8n webhook (проверка полиса) │ │
│ │ 3. n8n → CreateWebProject (CRM) │ │
│ │ 4. n8n обновляет Redis session │ │
│ │ 5. Response: {project_id, is_new, period_start/end} │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ Шаг 3: Тип события → Шаги 4+: Документы → Последний: Оплата│
└─────────────────────────────────────────────────────────────┘
```
---
## 📁 Структура файлов
### CRM (vTiger):
```
include/Webservices/
├── CreateWebContact.php (operation_id: 50) ✅
├── CreateWebProject.php (operation_id: 51) 🆕
└── CreateERVTicket.php (будущее)
logs/
├── CreateWebContact.log
└── CreateWebProject.log 🆕
CREATE_WEB_PROJECT_DOCS.md 🆕
```
### ERV Platform:
```
backend/app/services/
└── sms_service.py 🔧 Исправлена нормализация телефона
frontend/src/components/form/
├── Step1Phone.tsx 🔧 Добавлен вызов n8n webhook
├── Step1Policy.tsx
├── Step2EventType.tsx
├── StepDocumentUpload.tsx
└── Step3Payment.tsx
frontend/src/pages/
└── ClaimForm.tsx 🔧 Добавлен Step1Phone на первый шаг
docker-compose.yml 🔧 Redis подключён к внешнему серверу
```
---
## 🧪 Тестирование
### CreateWebProject:
**Тест 1: Создание нового проекта**
```bash
curl -X POST "https://crm.clientright.ru/webservice.php" \
-d "operation=CreateWebProject" \
-d "sessionName=xyz123" \
-d "policy_number=E1000-TEST-1761990646" \
-d "contact_id=396625" \
-d "period_start=01-01-2025" \
-d "period_end=31-12-2025"
Response: {"success":true,"result":"{\"project_id\":\"396865\",\"is_new\":true}"}
✅ Проект создан
```
**Тест 2: Повторный вызов (поиск существующего)**
```bash
curl -X POST "https://crm.clientright.ru/webservice.php" \
-d "operation=CreateWebProject" \
-d "sessionName=xyz123" \
-d "policy_number=E1000-TEST-1761990646" \
-d "contact_id=396625"
Response: {"success":true,"result":"{\"project_id\":\"396865\",\"is_new\":false}"}
✅ Проект найден (дубликат НЕ создан!)
```
### SMS Validation:
**До исправления:**
```
Отправка кода → ключ: erv:sms_verify:+79262306381
Проверка кода → ключ: sms_verify:79262306381
Результат: ❌ "No verification code found"
```
**После исправления:**
```
Отправка кода → ключ: erv:sms_verify:79262306381
Проверка кода → ключ: sms_verify:79262306381
Результат: ✅ "Code verified"
```
### n8n Integration:
**Frontend → n8n webhook:**
```
POST https://n8n.clientright.pro/webhook/511fde97-88bb-4fb4-bea5-cafdc364be27
Body: {"phone": "79001234567"}
Response: {
"claim_id": "CLM-2025-11-01-IWR1U2",
"contact_id": "396625",
"is_new_contact": false,
"phone": "79001234567"
}
```
**Redis Session (проверка):**
```bash
redis-cli -h crm.clientright.ru -a 'CRM_Redis_Pass_2025_Secure!' \
GET "claim:CLM-2025-11-01-IWR1U2"
{
"claim_id": "CLM-2025-11-01-IWR1U2",
"contact_id": "396625",
"phone": "79001234567",
"is_new_contact": false,
"status": "draft",
...
}
```
---
## 📝 Git История
### erv_platform (main):
```
89a182b - fix: Интеграция n8n webhook для создания контакта после SMS
8c21450 - docs: Лог сессии 30 октября - Телефон на шаг 1 + интеграция CRM
7b554c0 - feat: Полный флоу для создания контакта через CreateWebContact
```
### CRM (master):
```
f720c14e - chore: Обновлён submodule erv_platform
c34f7c9b - docs: Документация для CreateWebProject
af802149 - feat: Добавлена операция CreateWebProject для vTiger webservice
d7941ac8 - feat: CreateWebContact возвращает is_new флаг
09c1fbd1 - feat: Добавлена операция CreateWebContact для vTiger webservice
```
---
## 🔗 Важные URL
**Frontend:** http://147.45.146.17:5173
**Backend API:** http://147.45.146.17:8100
**CRM:** https://crm.clientright.ru
**CRM Webservice:** https://crm.clientright.ru/webservice.php
**n8n Production:** https://n8n.clientright.pro
**n8n Webhook (contact):** https://n8n.clientright.pro/webhook/511fde97-88bb-4fb4-bea5-cafdc364be27
**Gitea ERV:** http://147.45.146.17:3002/negodiy/erv-platform
---
## 🎯 Следующие шаги
1. **Тестирование полного флоу:**
- Телефон → SMS → CRM контакт → Полис → CRM проект → Документы → Тикет
2. **Доработка Step1Policy:**
- Вызов n8n webhook для проверки полиса
- Создание проекта через CreateWebProject
- Обновление Redis session
3. **Создание операции CreateERVTicket:**
- Финальный шаг создания тикета в HelpDesk
- Привязка к проекту и контакту
4. **Личный кабинет:**
- Вход по телефону + SMS
- Список незавершённых заявок
- Возможность продолжить заявку
---
## 📊 Метрики
**Время выполнения сессии:** ~3.5 часа
**Количество коммитов:**
- erv_platform: 3 коммита
- CRM: 3 коммита
**Созданных файлов:** 2
- `include/Webservices/CreateWebProject.php`
- `CREATE_WEB_PROJECT_DOCS.md`
**Изменённых файлов:** 4
- `backend/app/services/sms_service.py`
- `frontend/src/components/form/Step1Phone.tsx`
- `frontend/src/pages/ClaimForm.tsx`
- `docker-compose.yml`
**Строк добавлено:** ~350
**Строк удалено:** ~30
**Frontend rebuilds:** 4
**Backend rebuilds:** 3
**Тестовых запросов:** 15+
---
**Статус:** ✅ Успешно завершено
**Автор:** AI Assistant (Claude Sonnet 4.5)
**Дата:** 01 ноября 2025, 13:30 MSK