Files
aiform_prod/PROJECT_ARCHITECTURE.md
AI Assistant 0f82eef08d 🚀 MVP: FastAPI + React форма с SMS верификацией
 Инфраструктура: PostgreSQL, Redis, RabbitMQ, S3
 Backend: SMS сервис + API endpoints
 Frontend: React форма (3 шага) + SMS верификация
2025-10-24 16:19:58 +03:00

588 lines
20 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.

# 🏗️ ERV Insurance Platform - Архитектура проекта
**Дата создания**: 24.10.2025
**Технологии**: Python FastAPI + React TypeScript
**Статус**: 🚧 В разработке
---
## 📊 Обзор архитектуры
### **Технологический стек:**
```
┌─────────────────────────────────────────────────────────────┐
│ Frontend Layer (React) │
│ ├─ React 18 + TypeScript │
│ ├─ Vite (сборка) │
│ ├─ Ant Design (UI компоненты) │
│ ├─ React Query (API кеш) │
│ ├─ Zustand (state) │
│ └─ WebSocket для real-time │
└─────────────────────────────────────────────────────────────┘
│ REST API + WebSocket
┌─────────────────────────────────────────────────────────────┐
│ Backend Layer (Python FastAPI) │
│ ├─ FastAPI (асинхронный web framework) │
│ ├─ Pydantic (валидация данных) │
│ ├─ SQLAlchemy (PostgreSQL ORM) │
│ ├─ Redis (кеш, rate limiting) │
│ ├─ RabbitMQ (очереди задач) │
│ ├─ Celery (воркеры) │
│ └─ pytest (тесты) │
└─────────────────────────────────────────────────────────────┘
├─► PostgreSQL (147.45.189.234) - логи, данные
├─► Redis (localhost:6379) - кеш
├─► RabbitMQ (185.197.75.249) - очереди
├─► MySQL (localhost) - проверка полисов
├─► OCR Service (147.45.146.17:8001)
├─► OpenRouter AI (Gemini Vision)
├─► FlightAware API
└─► S3 Timeweb Cloud
```
---
## 📁 Структура проекта
```
erv_platform/
├─ backend/ ← Python FastAPI
│ ├─ app/
│ │ ├─ main.py ← Точка входа FastAPI
│ │ ├─ config.py ← Настройки из .env
│ │ │
│ │ ├─ api/ ← API endpoints
│ │ │ ├─ __init__.py
│ │ │ ├─ deps.py ← Зависимости (auth, db)
│ │ │ └─ endpoints/
│ │ │ ├─ documents.py ← OCR, Vision
│ │ │ ├─ flights.py ← Проверка рейсов
│ │ │ ├─ claims.py ← Создание обращений
│ │ │ ├─ policies.py ← Проверка полисов
│ │ │ └─ analytics.py ← Статистика
│ │ │
│ │ ├─ services/ ← Бизнес-логика
│ │ │ ├─ ocr_service.py
│ │ │ ├─ ai_service.py ← OpenRouter Vision
│ │ │ ├─ flight_service.py ← FlightAware
│ │ │ ├─ s3_service.py ← Timeweb S3
│ │ │ ├─ crm_service.py ← Интеграция с Vtiger
│ │ │ ├─ cache_service.py ← Redis
│ │ │ └─ queue_service.py ← RabbitMQ
│ │ │
│ │ ├─ models/ ← Pydantic модели
│ │ │ ├─ claim.py ← Обращение
│ │ │ ├─ document.py ← Документ
│ │ │ ├─ passport.py ← Паспорт
│ │ │ ├─ ticket.py ← Билет
│ │ │ └─ flight.py ← Рейс
│ │ │
│ │ ├─ db/ ← База данных
│ │ │ ├─ postgres.py ← PostgreSQL session
│ │ │ ├─ mysql.py ← MySQL session (полисы)
│ │ │ └─ models.py ← SQLAlchemy модели
│ │ │
│ │ ├─ workers/ ← RabbitMQ воркеры
│ │ │ ├─ ocr_worker.py
│ │ │ ├─ flight_worker.py
│ │ │ └─ notification_worker.py
│ │ │
│ │ ├─ core/ ← Утилиты
│ │ │ ├─ security.py ← Rate limiting
│ │ │ ├─ logger.py ← Логирование
│ │ │ └─ exceptions.py
│ │ │
│ │ └─ tests/ ← Тесты
│ │ ├─ test_api.py
│ │ └─ test_services.py
│ │
│ ├─ migrations/ ← SQL миграции
│ │ ├─ 001_create_logs.sql
│ │ ├─ 002_create_documents.sql
│ │ └─ 003_create_claims.sql
│ │
│ ├─ requirements.txt ← Python зависимости
│ ├─ .env.example
│ ├─ Dockerfile
│ └─ pyproject.toml
├─ frontend/ ← React TypeScript
│ ├─ src/
│ │ ├─ App.tsx ← Главный компонент
│ │ ├─ main.tsx ← Точка входа
│ │ │
│ │ ├─ components/ ← UI компоненты
│ │ │ ├─ layout/
│ │ │ │ ├─ Header.tsx
│ │ │ │ └─ Footer.tsx
│ │ │ ├─ form/
│ │ │ │ ├─ FormWizard.tsx ← Многошаговая форма
│ │ │ │ ├─ StepPersonal.tsx ← Шаг 1
│ │ │ │ ├─ StepFlight.tsx ← Шаг 2
│ │ │ │ └─ StepDocuments.tsx ← Шаг 3
│ │ │ ├─ upload/
│ │ │ │ ├─ PassportUpload.tsx ← Загрузка паспорта + OCR
│ │ │ │ ├─ TicketUpload.tsx ← Загрузка билета + OCR
│ │ │ │ └─ DocumentUpload.tsx ← Общий компонент
│ │ │ ├─ flight/
│ │ │ │ ├─ FlightChecker.tsx ← Проверка рейса
│ │ │ │ └─ FlightStatus.tsx ← Показ статуса
│ │ │ └─ common/
│ │ │ ├─ Loading.tsx
│ │ │ ├─ ErrorBoundary.tsx
│ │ │ └─ Notification.tsx
│ │ │
│ │ ├─ pages/ ← Страницы
│ │ │ ├─ ClaimForm.tsx ← Главная форма
│ │ │ ├─ Success.tsx ← Успех
│ │ │ └─ Error.tsx ← Ошибка
│ │ │
│ │ ├─ api/ ← API клиент
│ │ │ ├─ client.ts ← Axios instance
│ │ │ ├─ documents.ts ← API документов
│ │ │ ├─ flights.ts ← API рейсов
│ │ │ └─ claims.ts ← API обращений
│ │ │
│ │ ├─ hooks/ ← React hooks
│ │ │ ├─ useOCR.ts
│ │ │ ├─ useFlightCheck.ts
│ │ │ └─ useWebSocket.ts
│ │ │
│ │ ├─ types/ ← TypeScript типы
│ │ │ ├─ claim.ts
│ │ │ ├─ document.ts
│ │ │ └─ flight.ts
│ │ │
│ │ └─ utils/ ← Утилиты
│ │ ├─ validators.ts
│ │ └─ formatters.ts
│ │
│ ├─ public/
│ │ ├─ index.html
│ │ └─ favicon.ico
│ │
│ ├─ package.json
│ ├─ tsconfig.json
│ ├─ vite.config.ts
│ └─ .env.example
├─ docker/
│ ├─ Dockerfile.backend
│ ├─ Dockerfile.frontend
│ ├─ docker-compose.dev.yml
│ ├─ docker-compose.prod.yml
│ └─ nginx.conf
├─ docs/
│ ├─ API.md ← API документация
│ ├─ DEPLOYMENT.md ← Деплой
│ └─ ARCHITECTURE.md ← Этот файл
├─ .gitignore
├─ README.md
└─ docker-compose.yml ← Главный compose
```
---
## 🔄 Поток данных (детально):
### **1. Загрузка паспорта с OCR:**
```
[React] Пользователь загружает passport.jpg
[React] PassportUpload.tsx
↓ FormData
[FastAPI] POST /api/v1/documents/scan
[FastAPI] DocumentService
├─► S3Service.upload() → s3_url
├─► RabbitMQ.publish('ocr_queue', {s3_url, type: 'passport'})
└─► return {"job_id": "abc-123", "status": "processing"}
[React] Показывает: "⏳ Распознаём паспорт..."
[React] WebSocket подключение: ws://api/ws/jobs/abc-123
[Worker] OCR Worker получает из RabbitMQ
├─► OCRService.analyze(s3_url) → текст (3 сек)
├─► AIService.extract_passport(text) → JSON (2 сек)
├─► PostgreSQL.log(processing_result)
└─► WebSocket.send_to_client(session_id, result)
[React] WebSocket получает результат
[React] Автозаполняет поля:
form.setFieldsValue({
lastname: "Иванов",
firstname: "Иван",
...
})
[React] Показывает: "✅ Паспорт распознан! Проверьте данные."
```
**Время**: ~5 секунд, но пользователь видит прогресс!
---
### **2. Проверка рейса:**
```
[React] Пользователь ввёл "SU1234" и дату
[React] FlightChecker.tsx
↓ debounce 500ms (не дёргаем API на каждый символ)
[FastAPI] GET /api/v1/flights/check?number=SU1234&date=2025-10-24
[FastAPI] FlightService
├─► Redis.get('flight:SU1234:2025-10-24')
│ └─► Если есть → возврат из кеша (0.001 сек)
└─► Если нет:
├─► FlightAwareAPI.check() (1-2 сек)
├─► Redis.set('flight:...', result, ttl=3600) ← Кеш на час
└─► return result
[React] Показывает красивую карточку:
┌─────────────────────────────────────┐
│ ✈️ Рейс SU1234 │
│ Moscow (SVO) → Ufa (UFA) │
│ Статус: ⚠️ Задержка 45 минут │
│ Вылет: 09:25 (план: 08:40) │
└─────────────────────────────────────┘
```
---
### **3. Отправка обращения:**
```
[React] Пользователь заполнил всё, жмёт "Подать обращение"
[FastAPI] POST /api/v1/claims/submit
{
client: {lastname, firstname, ...},
flight: {number, date, type: "delay_flight"},
documents: [s3_urls],
sbp_phone: "+79991234567"
}
[FastAPI] ClaimService
├─► Валидация (Pydantic)
├─► PostgreSQL: сохранение claim (для аналитики)
├─► Формирование payload для CRM
│ {
│ "client": {...},
│ "contractor": {...}, ← Из конфига
│ "project": {...},
│ "ticket": {...}
│ }
├─► POST → https://form.clientright.ru/server_webservice2.php
│ └─► PHP Bridge → Vtiger Webservices (PHP 7.3)
│ └─► CRM создаёт тикет
├─► RabbitMQ.publish('notifications', {...}) ← Email в фоне
└─► return {"success": true, "ticket_id": "TT12345"}
[React] Редирект на Success.tsx
"✅ Ваше обращение #TT12345 принято!"
```
---
## 🔌 Интеграции (детально):
### **OCR + Vision Pipeline:**
```python
# services/document_processor.py
async def process_passport(file_url: str) -> PassportData:
# 1. OCR (ваш сервис)
ocr_response = await ocr_service.analyze(
file_url=file_url,
file_type="auto" # Автоопределение
)
ocr_text = ocr_response['pages_data'][0]['ocr_text']
# 2. Vision AI (OpenRouter Gemini)
vision_prompt = """
Извлеки из текста паспорта РФ следующие данные в формате JSON:
{
"surname": "...",
"name": "...",
"patronymic": "...",
"birthdate": "DD.MM.YYYY",
"passport_series": "XXXX",
"passport_number": "XXXXXX"
}
Текст паспорта:
{ocr_text}
"""
vision_result = await ai_service.extract_structured_data(
prompt=vision_prompt.format(ocr_text=ocr_text)
)
# 3. Валидация через Pydantic
passport = PassportData(**vision_result)
# 4. Логирование в PostgreSQL
await db.execute("""
INSERT INTO document_processing
(file_url, document_type, ocr_text, vision_result, processing_time_ms)
VALUES ($1, $2, $3, $4, $5)
""", file_url, 'passport', ocr_text, vision_result, elapsed_ms)
return passport
```
---
## 📡 API Спецификация:
### **Базовый URL:**
```
DEV: http://localhost:8000/api/v1
PROD: https://api.erv-claims.clientright.ru/api/v1
```
### **Endpoints:**
| Method | Endpoint | Описание | Время |
|--------|----------|----------|-------|
| POST | `/documents/upload` | Загрузка в S3 | ~500ms |
| POST | `/documents/scan` | OCR + Vision | ~5s (async) |
| GET | `/flights/check` | Проверка рейса | ~200ms (cache) |
| GET | `/policies/verify` | Проверка полиса | ~5ms (cache) |
| POST | `/claims/submit` | Создание обращения | ~1s |
| WS | `/ws/jobs/{job_id}` | Real-time статусы | - |
### **Пример: Scan Passport**
**Request:**
```http
POST /api/v1/documents/scan
Content-Type: application/json
{
"file_url": "https://s3.twcstorage.ru/.../passport.jpg",
"document_type": "passport"
}
```
**Response (сразу):**
```json
{
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "processing",
"estimated_time_seconds": 5
}
```
**WebSocket update (через 5 сек):**
```json
{
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "completed",
"data": {
"surname": "Иванов",
"name": "Иван",
"patronymic": "Иванович",
"birthdate": "01.01.1990",
"passport_series": "4510",
"passport_number": "123456"
}
}
```
---
## 🗄️ Структура баз данных:
### **PostgreSQL (новые данные):**
```sql
-- Обращения (дубликат для аналитики)
CREATE TABLE claims (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
session_id VARCHAR(100),
insurance_type VARCHAR(50), -- erv_flight, erv_train, etc.
-- Данные клиента (JSONB)
client_data JSONB,
-- Данные события (JSONB)
event_data JSONB,
-- Документы
documents JSONB, -- [{type, s3_url, ocr_result, vision_result}]
-- Статус
status VARCHAR(20), -- processing, submitted, completed, error
crm_ticket_id VARCHAR(50),
-- Метаданные
ip_address INET,
user_agent TEXT,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX idx_claims_status ON claims(status);
CREATE INDEX idx_claims_created ON claims(created_at);
CREATE INDEX idx_claims_crm_ticket ON claims(crm_ticket_id);
-- Обработка документов
CREATE TABLE document_processing (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
claim_id UUID REFERENCES claims(id),
file_url TEXT,
s3_url TEXT,
document_type VARCHAR(50), -- passport, ticket, etc.
-- OCR результат
ocr_text TEXT,
ocr_confidence NUMERIC,
-- Vision результат
vision_result JSONB,
-- Метрики
processing_time_ms INTEGER,
ocr_time_ms INTEGER,
vision_time_ms INTEGER,
created_at TIMESTAMP DEFAULT NOW()
);
-- Логи
CREATE TABLE logs (
id BIGSERIAL PRIMARY KEY,
level VARCHAR(10), -- INFO, WARNING, ERROR
logger VARCHAR(50), -- ocr_service, flight_service, etc.
message TEXT,
context JSONB,
session_id VARCHAR(100),
ip_address INET,
created_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX idx_logs_level ON logs(level);
CREATE INDEX idx_logs_created ON logs(created_at DESC);
CREATE INDEX idx_logs_session ON logs(session_id);
-- Кеш API (fallback)
CREATE TABLE api_cache (
cache_key VARCHAR(255) PRIMARY KEY,
cache_value JSONB,
expires_at TIMESTAMP,
created_at TIMESTAMP DEFAULT NOW()
);
```
### **MySQL (существующая CRM база):**
```sql
-- НЕ трогаем! Только читаем
ci20465_erv.lexrpiority
├─ voucher
├─ insured_from
└─ insured_to
```
---
## 🚀 Deployment стратегия:
### **Development (сейчас):**
```bash
# 1. Backend
cd backend
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
uvicorn app.main:app --reload --port 8000
# 2. Frontend
cd frontend
npm install
npm run dev # Vite dev server на :5173
# 3. Доступ:
Frontend: http://localhost:5173
Backend: http://localhost:8000
API Docs: http://localhost:8000/docs ← Swagger UI!
```
### **Production (потом):**
```bash
# Вариант 1: Тот же сервер, другой домен
cd /var/www/erv-claims.clientright.ru/
git clone http://147.45.146.17:3002/fedya/erv-platform.git .
docker-compose -f docker/docker-compose.prod.yml up -d
# Nginx конфиг:
server {
server_name erv-claims.clientright.ru;
# Frontend (статика)
location / {
root /var/www/erv-claims/frontend/dist;
try_files $uri $uri/ /index.html;
}
# Backend API
location /api/ {
proxy_pass http://localhost:8000;
}
# WebSocket
location /ws/ {
proxy_pass http://localhost:8000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
```
---
## 🎯 Что делаю СЕЙЧАС (следующие 2-3 часа):
### **Создаю базу:**
1. ✅ Структура проекта (сделано)
2. ✅ requirements.txt (Python зависимости)
3. ✅ package.json (React зависимости)
4. ✅ .env.example
5. ✅ Базовый FastAPI app
6. ✅ Базовый React app
7. ✅ SQL миграции для PostgreSQL
8. ✅ Docker compose для dev
9. ✅ README с инструкциями
**Время**: ~1 час на базовую настройку
---
## 💪 Готов?
Сейчас создам всю базовую структуру и запущу оба приложения (FastAPI + React).
**Начинаю прямо сейчас!** 🚀