Nashel Backend

Бэкенд для маркетплейса услуг "Nashel" — платформа для поиска мастеров и исполнителей.

🏗️ Архитектура

Проект построен на архитектуре Clean Architecture с модульным подходом:

nashel-backend/
├── src/
│   ├── BuildingBlocks/          # Общие блоки для всех модулей
│   │   ├── Application/         # Общие абстракции и поведения
│   │   ├── Domain/              # Базовые доменные сущности
│   │   └── Infrastructure/       # Общая инфраструктура
│   ├── Modules/                 # Модули бизнес-логики
│   │   ├── Identity/            # Модуль авторизации и профилей
│   │   └── Order/               # Модуль заказов
│   └── Host/                    # Точка входа приложения
└── tests/                       # Тесты

Модульность

Каждый модуль (Identity, Order) является автономным и содержит:

  • Domain — бизнес-логика, сущности, репозитории
  • Application — Use Cases, команды, запросы, валидация
  • Infrastructure — реализация репозиториев, EF Core
  • Presentation — API endpoints

🚀 Технологический стек

  • .NET 10 — фреймворк
  • ASP.NET Core — веб-фреймворк
  • Entity Framework Core — ORM
  • PostgreSQL — база данных
  • MediatR — паттерн CQRS/Mediator
  • FluentValidation — валидация
  • JWT — аутентификация
  • Docker — контейнеризация
  • Swagger/OpenAPI — документация API

📦 Установка и запуск

Требования

  • .NET 10 SDK
  • Docker и Docker Compose
  • PostgreSQL

Запуск через Docker Compose

# Клонирование репозитория
git clone <repository-url>
cd nashel-backend

# Запуск всех сервисов
docker-compose up -d

# Просмотр логов
docker-compose logs -f app

# Остановка сервисов
docker-compose down

Локальный запуск

# Восстановление зависимостей
dotnet restore

# Настройка переменных окружения
cp src/Host/appsettings.json src/Host/appsettings.Development.json
# Отредактируйте ConnectionStrings__DefaultConnection

# Применение миграций
dotnet ef database update --project src/Host --startup-project src/Host

# Запуск
dotnet run --project src/Host

🔧 Переменные окружения

Переменная Описание Пример
ASPNETCORE_ENVIRONMENT Окружение Development, Production
ConnectionStrings__DefaultConnection Строка подключения к БД Host=db;Port=5432;Database=nashel;Username=postgres;Password=postgres
JWT__Secret Секретный ключ JWT your-super-secret-key
JWT__Issuer Издатель токена nashel-api
JWT__Audience Аудитория токена nashel-client
JWT__ExpirationMinutes Время жизни токена (мин) 60

📚 API Документация

Swagger доступен по адресу: http://localhost:5000/swagger

Основные эндпоинты

Аутентификация

POST /api/auth/register
Content-Type: application/json

{
  "phone": "+79001234567",
  "firstName": "Иван",
  "lastName": "Иванов",
  "password": "password123",
  "confirmPassword": "password123",
  "isCompany": false,
  "companyName": "ООО 'Ромашка'",
  "inn": "1234567890"
}
POST /api/auth/login
Content-Type: application/json

{
  "phone": "+79001234567",
  "password": "password123"
}

Профиль пользователя

GET /api/profile
Authorization: Bearer {access_token}

PUT /api/profile
Authorization: Bearer {access_token}
Content-Type: application/json

{
  "firstName": "Иван",
  "lastName": "Иванов",
  "patronymic": "Иванович",
  "companyName": "ООО 'Ромашка'",
  "inn": "1234567890"
}

POST /api/profile/change-phone
Authorization: Bearer {access_token}
Content-Type: application/json

{
  "newPhone": "+79009876543"
}

POST /api/profile/become-performer
Authorization: Bearer {access_token}

POST /api/profile/avatar
Authorization: Bearer {access_token}
Content-Type: multipart/form-data

avatar: <file>

PUT /api/profile/competencies
Authorization: Bearer {access_token}
Content-Type: application/json

{
  "Competencies": ["сантехника", "электрика"]
}

Компетенции

GET /api/competencies/search?q=сантех
Authorization: Bearer {access_token}

🎯 Реализованный функционал

Модуль Identity

Аутентификация и авторизация

  • Регистрация пользователей (частные лица и компании)
  • Вход в систему (JWT токены)
  • Обновление токенов
  • Выход из системы
  • Ролевая модель (Client, Master, Candidate, Company, Admin)

Профиль пользователя

  • Получение профиля
  • Редактирование профиля
  • Изменение номера телефона
  • Загрузка аватара с кропом
  • Управление компетенциями
  • Стать исполнителем

Компетенции

  • Поиск компетенций по подстроке
  • Общий пул компетенций для всех исполнителей
  • Автоматическое создание новых компетенций

Компании

  • Регистрация компаний с ИНН
  • Управление данными компании
  • Отдельная логика для компаний

Модуль Order (в разработке)

  • Создание заказов
  • Поиск заказов на карте
  • SLA таймер для отклика на заказы

🗄️ База данных

Схема

accounts (аккаунты пользователей)
├── id (PK)
├── phone (уникальный)
├── password_hash
├── roles (массив ролей)
└── profile_id (FK)

user_profiles (профили пользователей)
├── id (PK)
├── account_id (FK)
├── first_name
├── last_name
├── patronymic
├── company_name
├── inn (для компаний)
├── avatar_url
└── competency_profiles (связь с компетенциями)

competencies (компетенции/навыки)
├── id (PK)
├── name (уникальное, в нижнем регистре)

competency_profiles (связь профилей и компетенций)
├── id (PK)
├── profile_id (FK)
├── competency_id (FK)

Миграции

# Создание новой миграции
dotnet ef migrations add AddNewFeature --project src/Infrastructure --startup-project src/Host

# Применение миграций
dotnet ef database update --project src/Infrastructure --startup-project src/Host

# Откат последней миграции
dotnet ef database update --project src/Infrastructure --startup-project src/Host

🔐 Безопасность

  • Хеширование паролей (BCrypt)
  • JWT токены с refresh token
  • Валидация входных данных (FluentValidation)
  • CORS политика
  • Rate limiting (в планах)

🧪 Тестирование

# Запуск всех тестов
dotnet test

# Запуск тестов с покрытием
dotnet test --collect:"XPlat Code Coverage"

# Запуск конкретного теста
dotnet test --filter "FullyQualifiedName~TestName"

📝 Конвенции кода

CQRS Pattern

Используем MediatR для реализации CQRS:

// Команда (Command)
public record UpdateProfileCommand(...) : IRequest;

// Обработчик команды (Handler)
public class UpdateProfileCommandHandler : IRequestHandler<UpdateProfileCommand>
{
    public async Task Handle(UpdateProfileCommand request, CancellationToken cancellationToken)
    {
        // Логика
    }
}

Валидация

Используем FluentValidation:

public class UpdateProfileCommandValidator : AbstractValidator<UpdateProfileCommand>
{
    public UpdateProfileCommandValidator()
    {
        RuleFor(x => x.FirstName).NotEmpty().MinimumLength(2);
        RuleFor(x => x.LastName).NotEmpty().MinimumLength(2);
    }
}

🚨 Обработка ошибок

  • Глобальный exception handler
  • Стандартные HTTP статусы (400, 401, 403, 404, 500)
  • Подробные сообщения об ошибках в Development режиме
  • Обобщенные сообщения в Production режиме

📦 Статические файлы

Загруженные аватары хранятся в wwwroot/uploads/ и доступны по URL:

http://localhost:5000/uploads/{filename}

🔄 CI/CD

  • GitHub Actions для автоматического тестирования
  • Docker Hub для хранения образов
  • Автоматический деплой (в планах)

📞 Контакты

  • Проект: Nashel
  • Версия: 1.0.0
  • Лицензия: MIT

🤝 Вклад в проект

  1. Fork репозитория
  2. Создайте ветку для фичи (git checkout -b feature/AmazingFeature)
  3. Закоммитьте изменения (git commit -m 'Add some AmazingFeature')
  4. Запушьте в ветку (git push origin feature/AmazingFeature)
  5. Откройте Pull Request
Description
No description provided
Readme 737 KiB
Languages
C# 99.8%
Dockerfile 0.2%