Аутентификация через SMS
Безопасная авторизация по номеру телефона с SMS-подтверждением
Ввод телефона
→
SMS код
→
JWT токен
→
Доступ к API
POST
/api/v1/auth/sms/send
Отправить SMS код
Запрос
{
"phone": "+79991234567"
}
Ответ (200 OK)
{
"success": true,
"message": "SMS код отправлен",
"expires_in": 300
}
POST
/api/v1/auth/sms/verify
Подтвердить SMS код
Запрос
{
"phone": "+79991234567",
"code": "1234"
}
Ответ (200 OK)
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "bearer",
"expires_in": 1800
}
POST
/api/v1/auth/refresh
Обновить токен
Запрос
{
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Ответ (200 OK)
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "bearer",
"expires_in": 1800
}
GET
/api/v1/auth/me
Получить текущего пользователя
Заголовки
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Ответ (200 OK)
{
"id": 1,
"phone": "+79991234567",
"name": "Иван Петров",
"email": "ivan@example.com",
"role": "user",
"is_active": true,
"created_at": "2024-01-15T10:30:00Z"
}
Управление пользователями
Профиль, настройки и данные пользователя
GET
/api/v1/users/profile
Получить профиль
Ответ (200 OK)
{
"id": 1,
"phone": "+79991234567",
"name": "Иван Петров",
"email": "ivan@example.com",
"avatar_url": "https://storage.example.com/avatars/1.jpg",
"address": "Москва, ул. Ленина 10",
"orders_count": 5,
"rating": 4.8
}
PUT
/api/v1/users/profile
Обновить профиль
Запрос
{
"name": "Иван Петров",
"email": "ivan@example.com",
"address": "Москва, ул. Пушкина 15"
}
Ответ (200 OK)
{
"success": true,
"message": "Профиль обновлен"
}
GET
/api/v1/users/orders
Мои заказы
Параметры запроса
?status=pending&limit=10&offset=0
Ответ (200 OK)
{
"items": [
{
"id": 1,
"title": "Ремонт смесителя",
"status": "pending",
"budget": 2000,
"created_at": "2024-01-15T10:30:00Z"
}
],
"total": 5,
"limit": 10,
"offset": 0
}
Управление заказами
Создание, поиск и управление заказами на услуги
POST
/api/v1/orders/
Создать заказ
Запрос
{
"category_id": 1, required
"title": "Ремонт смесителя на кухне", required
"description": "Течет смеситель, нужна замена прокладки или полная замена",
"budget": 3000,
"address": "Москва, ул. Ленина 10, кв. 5", required
"desired_date": "2024-01-20",
"photos": ["base64_image_data..."]
}
Ответ (201 Created)
{
"id": 42,
"title": "Ремонт смесителя на кухне",
"status": "pending",
"lat": 55.7558,
"lon": 37.6173,
"created_at": "2024-01-15T10:30:00Z"
}
GET
/api/v1/orders/nearby
Заказы рядом
Параметры запроса
?lat=55.7558&lon=37.6173&radius_km=10&category_id=1
Ответ (200 OK)
{
"items": [
{
"id": 42,
"title": "Ремонт смесителя",
"budget": 3000,
"distance_km": 2.5,
"address": "Москва, ул. Ленина 10"
},
{
"id": 43,
"title": "Установка розеток",
"budget": 2000,
"distance_km": 4.1,
"address": "Москва, пр. Мира 25"
}
],
"total": 15
}
GET
/api/v1/orders/{id}
Детали заказа
Ответ (200 OK)
{
"id": 42,
"title": "Ремонт смесителя на кухне",
"description": "Течет смеситель, нужна замена прокладки",
"category": {
"id": 1,
"name": "Сантехника"
},
"budget": 3000,
"status": "pending",
"address": "Москва, ул. Ленина 10",
"lat": 55.7558,
"lon": 37.6173,
"customer": {
"id": 1,
"name": "Иван П.",
"rating": 4.8
},
"responses_count": 3,
"created_at": "2024-01-15T10:30:00Z"
}
POST
/api/v1/orders/{id}/cancel
Отменить заказ
Запрос
{
"reason": "Нашел мастера сам"
}
Ответ (200 OK)
{
"success": true,
"message": "Заказ отменен"
}
Исполнители (Мастера)
Регистрация мастеров, отклики на заказы, портфолио
POST
/api/v1/specialists/register
Стать исполнителем
Запрос
{
"bio": "Профессиональный сантехник с опытом 10 лет",
"experience_years": 10,
"category_ids": [1, 2],
"work_radius_km": 15,
"base_address": "Москва, м. Таганская"
}
Ответ (201 Created)
{
"id": 1,
"user_id": 5,
"bio": "Профессиональный сантехник с опытом 10 лет",
"verified": false,
"status": "pending_verification"
}
POST
/api/v1/specialists/orders/{id}/respond
Откликнуться на заказ
Запрос
{
"price": 2500,
"message": "Здравствуйте! Могу приехать сегодня. Опыт работы 10 лет.",
"estimated_hours": 2
}
Ответ (201 Created)
{
"id": 15,
"order_id": 42,
"price": 2500,
"status": "pending",
"created_at": "2024-01-15T11:00:00Z"
}
GET
/api/v1/specialists/me
Мой профиль исполнителя
Ответ (200 OK)
{
"id": 1,
"bio": "Профессиональный сантехник",
"experience_years": 10,
"rating": 4.9,
"reviews_count": 87,
"completed_orders": 124,
"verified": true,
"balance": 15000,
"categories": [
{"id": 1, "name": "Сантехника"},
{"id": 2, "name": "Электрика"}
]
}
POST
/api/v1/specialists/portfolio
Добавить работу в портфолио
Запрос
{
"title": "Замена труб в ванной",
"description": "Полная замена водопроводных труб",
"photos": ["base64...", "base64..."],
"category_id": 1
}
Ответ (201 Created)
{
"id": 5,
"title": "Замена труб в ванной",
"photos": [
"https://storage.example.com/portfolio/5_1.jpg",
"https://storage.example.com/portfolio/5_2.jpg"
]
}
Архитектура системы
Технологический стек и архитектурные решения
React/Next.js
Frontend
Frontend
↔
FastAPI
Backend
Backend
↔
PostgreSQL
Database
Database
Backend
- FastAPI (Python 3.11+)
- SQLAlchemy 2.0 (async)
- Pydantic v2
- Alembic (миграции)
- JWT аутентификация
- Redis (кеширование)
Frontend
- React 18 / Next.js 14
- TypeScript
- Tailwind CSS
- React Query
- Zustand (состояние)
- React Hook Form
База данных
- PostgreSQL 15
- PostGIS (геолокация)
- 16 таблиц
- Полнотекстовый поиск
- Триггеры и индексы
- Автообновление updated_at
Инфраструктура
- Docker Compose
- Nginx (reverse proxy)
- Let's Encrypt SSL
- Yandex Cloud S3
- SMS.ru (верификация)
- YooMoney (платежи)
Бизнес-модель
Комиссия 15%
- 10% - с заказчика
- 5% - с исполнителя
- Escrow платежи
- Безопасные сделки
Монетизация
- Комиссия с заказов
- Премиум подписка
- Продвижение в поиске
- Верификация мастеров
Схема базы данных
16 таблиц с полной нормализацией
users
idSERIAL PK
phoneVARCHAR(20) UNIQUE
nameVARCHAR(100)
emailVARCHAR(255)
roleuser_role ENUM
is_activeBOOLEAN
created_atTIMESTAMP
specialists
idSERIAL PK
user_idINT FK → users
bioTEXT
experience_yearsINT
ratingDECIMAL(3,2)
verifiedBOOLEAN
work_radius_kmINT
orders
idSERIAL PK
customer_idINT FK → users
category_idINT FK → categories
titleVARCHAR(200)
descriptionTEXT
budgetDECIMAL(10,2)
statusorder_status ENUM
lat / lonDECIMAL(10,8)
categories
idSERIAL PK
nameVARCHAR(100)
slugVARCHAR(100) UNIQUE
parent_idINT FK → categories
iconVARCHAR(50)
is_activeBOOLEAN
order_responses
idSERIAL PK
order_idINT FK → orders
specialist_idINT FK → specialists
priceDECIMAL(10,2)
messageTEXT
statusresponse_status ENUM
reviews
idSERIAL PK
order_idINT FK → orders
author_idINT FK → users
target_idINT FK → users
ratingINT (1-5)
commentTEXT
payments
idSERIAL PK
order_idINT FK → orders
amountDECIMAL(10,2)
commissionDECIMAL(10,2)
statuspayment_status ENUM
yookassa_idVARCHAR(100)
messages
idSERIAL PK
chat_idINT FK → chats
sender_idINT FK → users
contentTEXT
is_readBOOLEAN
created_atTIMESTAMP