Skip to content

Partizap Backend — Отчёт о реализации

Дата: 05.02.2026 Этап: Инициализация скелета бэкенда Примечание: Этот отчёт описывает первоначальную конфигурацию на одном VPS (Debian 12, 185.73.215.246). С 10.03.2026 инфраструктура перенесена на два VPS (Ubuntu 24.04). Актуальная архитектура — в dev-prod-infrastructure.md.


1. Конфигурация сервера

Оборудование и ОС

ПараметрЗначение
ОСDebian 12 (bookworm)
CPU6 ядер
RAM11 ГБ
Swap2 ГБ (/swapfile, swappiness=10)
IP185.73.215.246

Установленное ПО

ПОВерсияПримечания
PHP8.3.30 (репозиторий Sury)Расширения: pdo_pgsql, redis, mbstring, xml, curl
Composer2.9.5/usr/local/bin/composer
PostgreSQL16.11Две базы: partizap_prod, partizap_dev
Redis7.0.15Один экземпляр, базы 0–3
PgBouncer1.25.1Transaction mode, scram-sha-256
Nginx1.22.1Все server-блоки в /etc/nginx/sites-available/default

Пулы PHP-FPM

ПулСокетmax_children
partizap-prod/run/php/php8.3-fpm-prod.sock20
partizap-dev/run/php/php8.3-fpm-dev.sock5

Изоляция окружений

РесурсProductionDevelopment
Доменpartizap.rudev.partizap.ru
PostgreSQLpartizap_prodpartizap_dev
Redis DB0 (префикс: prod:)1 (префикс: dev:)
PHP-FPM пулpartizap-prodpartizap-dev
PgBouncerпорт 6432прямое подключение, порт 5432
Каталог приложения/var/www/partizap/production//var/www/partizap/development/

Конфигурация Nginx

  • HTTPS с сертификатами Let's Encrypt
  • try_files $uri /index.php$is_args$args — все запросы направляются в Slim
  • Basic auth на dev.partizap.ru (файл /etc/nginx/.htpasswd)
  • Заголовки безопасности: X-Frame-Options, X-Content-Type-Options
  • Блокировка: .env, .git, composer.json, composer.lock
  • Исправление: Исходная конфигурация содержала location ~ /(composer\.(json|lock)|vendor/), которая блокировала API-маршруты /vendor/*. Заменена на location ~ /composer\.(json|lock)$ в обоих блоках (production и development).

Учётные данные

ДанныеРасположение
Пароли PostgreSQL/var/www/partizap/{production,development}/.env
Userlist PgBouncer/etc/pgbouncer/userlist.txt
Basic auth Nginx/etc/nginx/.htpasswd

2. Структура Git-репозиториев

Репозиторий бэкенда

Расположение: /var/www/partizap/ (сервер), git@gitlab.partizap.ru:team/partizap.git (remote)

Стратегия ветвления

ВеткаОкружениеДоменНазначение
mainproductionpartizap.ruСтабильные релизы
developdevelopmentdev.partizap.ruАктивная разработка
feature/*только CIФича-ветки, сливаются в develop

Содержимое репозитория (ветка develop)

/var/www/partizap/
├── .gitignore
├── development/           ← Приложение бэкенда (Slim 4)
│   ├── .env               ← Реальные данные (в .gitignore)
│   ├── .env.example        ← Шаблон
│   ├── .gitignore
│   ├── composer.json
│   ├── composer.lock       ← (в .gitignore)
│   ├── vendor/             ← (в .gitignore)
│   ├── var/                ← (в .gitignore: кэш, прокси)
│   ├── public/index.php
│   ├── bin/console
│   ├── config/
│   ├── app/
│   ├── migrations/
│   ├── tests/
│   ├── phpstan.neon
│   ├── phpunit.xml
│   └── .php-cs-fixer.php
└── production/             ← Продакшен-деплой (только ветка main)
    ├── .env
    ├── .env.example
    └── public/index.php

Репозиторий фронтенда

Ещё не создан. Будет отдельным Git-репозиторием (например, team/partizap-frontend), инициализируется при начале разработки фронтенда. Фронтенд запланирован как приложение на Nuxt 4, взаимодействующее с API бэкенда по HTTPS.

Подключение к GitLab

  • Remote: git@gitlab.partizap.ru:team/partizap.git
  • Аутентификация: по SSH-ключу
  • Ключ хоста добавлен в ~/.ssh/known_hosts
  • Ветки main и develop загружены в origin

3. Архитектура бэкенда

Стек технологий

  • Фреймворк: Slim 4.15 + PHP-DI 7.1 (через php-di/slim-bridge)
  • ORM: Doctrine ORM 3.6 + DBAL 4.4 + Migrations 3.9
  • БД: PostgreSQL 16 (SERIAL PK, не UUID)
  • Кэш/Сессии: Redis 7 через нативный ext-redis
  • Логирование: Monolog 3.10
  • CLI: Symfony Console 7.4
  • Тестирование: PHPUnit 11.5
  • Статический анализ: PHPStan 2.1 (уровень 8) + phpstan-doctrine
  • Стиль кода: PHP-CS-Fixer 3.93

Структура каталогов

development/
├── public/index.php                    ← Точка входа (bootstrap Slim)
├── bin/console                         ← CLI (Doctrine Migrations)
├── config/
│   ├── app.php                         ← Загрузка .env, массив настроек
│   ├── container.php                   ← Сборка контейнера PHP-DI
│   ├── cors.php                        ← Настройки CORS
│   ├── doctrine.php                    ← Фабрика EntityManager
│   ├── redis.php                       ← Фабрика RedisConnectionFactory
│   ├── logging.php                     ← Фабрика Monolog
│   ├── middleware.php                  ← Регистрация middleware
│   ├── migrations.php                  ← Конфигурация Doctrine Migrations
│   └── routes.php                      ← 4 группы маршрутов
├── app/
│   ├── Actions/                        ← Один класс на эндпоинт
│   │   ├── Store/                      ← Публичный API покупателей
│   │   ├── Auth/                       ← Аутентификация
│   │   ├── Vendor/                     ← Эндпоинты продавцов (требуют авторизации)
│   │   └── Admin/                      ← Административные эндпоинты (авторизация + админ)
│   ├── Application/
│   │   ├── Middleware/                 ← 8 классов middleware
│   │   ├── Response/JsonResponder.php  ← Стандартный билдер JSON-ответов
│   │   └── Exception/                 ← Иерархия исключений (5 классов)
│   ├── Domain/
│   │   ├── Entity/User.php            ← Doctrine-сущность с PHP 8 атрибутами
│   │   └── Repository/               ← Интерфейсы репозиториев
│   └── Infrastructure/
│       ├── Persistence/               ← Doctrine-реализации репозиториев
│       ├── Redis/                     ← RedisConnectionFactory
│       └── Logging/                   ← RequestIdGenerator
├── migrations/                         ← Сгенерированные миграции Doctrine
├── tests/
│   ├── bootstrap.php
│   ├── Feature/HealthCheckTest.php
│   └── Unit/JsonResponderTest.php
└── var/
    ├── doctrine/proxies/              ← Прокси-классы Doctrine
    └── cache/                         ← Кэш компиляции DI

Конфигурационный слой (8 файлов)

ФайлНазначение
config/app.phpЗагрузка .env через phpdotenv, валидация обязательных переменных, возврат массива настроек
config/cors.phpРазрешённые origins (partizap.ru, dev.partizap.ru, localhost:3000), методы, заголовки
config/redis.phpФабрика, возвращающая экземпляр RedisConnectionFactory
config/doctrine.phpФабрика, возвращающая EntityManagerInterface (метаданные через атрибуты, каталог прокси)
config/logging.phpФабрика, возвращающая LoggerInterface Monolog (файл + stderr)
config/container.phpContainerBuilder PHP-DI со всеми определениями сервисов
config/middleware.phpРегистрация middleware на $app (порядок: ErrorHandler → CORS → Security → JSON → Routing)
config/routes.phpРегистрация 4 групп маршрутов с привязкой middleware

Инфраструктурный слой (3 класса)

RedisConnectionFactory — Создаёт экземпляры \Redis для 4 логических баз:

КонстантаБДНазначение
DB_SESSIONS0PHP-сессии (критичные данные)
DB_CACHE1Кэш приложения (можно сбросить)
DB_QUEUES2Транспорт Symfony Messenger
DB_RATE_LIMITS3Счётчики rate limiting

Соединения создаются лениво и кэшируются по номеру базы. Префикс из .env (dev: или prod:).

DoctrineUserRepository — Реализация UserRepositoryInterface с методами findById(), findByEmail(), save().

RequestIdGenerator — Генерация 16-символьных hex-идентификаторов запросов через random_bytes(8).

Прикладной слой

Иерархия исключений

КлассHTTPКод ошибкиПрименение
AppException(базовый)(настраиваемый)Абстрактный базовый класс
NotFoundException404not_foundРесурс не найден
ValidationException422validation_errorОшибки валидации (содержит ошибки полей)
AuthenticationException401authentication_requiredОтсутствует/невалидная сессия
AuthorizationException403access_deniedНедостаточно прав

JsonResponder

Стандартизированный билдер JSON-ответов с двумя методами:

  • respond($data, $status, $meta){"data": ..., "meta": {...}}
  • error($code, $message, $status, $details){"error": {"code": ..., "message": ..., "details": ...}}

Middleware (8 классов)

MiddlewareПозицияПоведение
ErrorHandlerMiddlewareВнешнийПерехватывает все исключения → JSON-ответы, логирует ошибки
CorsMiddleware2-йДобавляет CORS-заголовки, обрабатывает OPTIONS preflight (204)
SecurityHeadersMiddleware3-йДобавляет X-Content-Type-Options, X-Frame-Options, Referrer-Policy
JsonContentTypeMiddleware4-йОтклоняет POST/PUT/PATCH без application/json Content-Type (415)
CsrfMiddlewareЗаглушкаПлейсхолдер для будущей CSRF-валидации
RateLimitMiddlewareЗаглушкаПлейсхолдер для будущего rate limiting через Redis
AuthMiddlewareГруппа маршрутовПроверяет $_SESSION['user_id'], выбрасывает AuthenticationException
AdminMiddlewareГруппа маршрутовПроверяет $_SESSION['is_admin'], выбрасывает AuthorizationException

Доменный слой

Сущность User — Doctrine ORM сущность, маппинг на таблицу users:

КолонкаТипПримечания
idSERIAL (INT IDENTITY)Автогенерируемый PK
emailVARCHAR(255)Уникальный индекс
password_hashVARCHAR(255)Хэш bcrypt
display_nameVARCHAR(100)
phoneVARCHAR(20)Nullable
is_activeBOOLEANПо умолчанию true
is_adminBOOLEANПо умолчанию false
created_atTIMESTAMPImmutable, устанавливается при создании
updated_atTIMESTAMPImmutable, обновляется через @PreUpdate

Группы маршрутов и экшены (12 эндпоинтов)

ГруппаМаршрутМетодЭкшенСтатус
/healthGETHealthCheckActionРаботает (проверка БД + Redis)
/store/store/productsGETListProductsActionЗаглушка
/store/store/products/{id}GETGetProductActionЗаглушка (404)
/store/store/categoriesGETListCategoriesActionЗаглушка
/auth/auth/loginPOSTLoginActionЗаглушка (501)
/auth/auth/registerPOSTRegisterActionЗаглушка (501)
/auth/auth/logoutPOSTLogoutActionЗаглушка (501)
/auth/auth/meGETMeActionЗаглушка (501)
/vendor/vendor/productsGETListMyProductsActionЗаглушка (требует авторизации)
/vendor/vendor/productsPOSTCreateProductActionЗаглушка (требует авторизации)
/admin/admin/dashboardGETDashboardActionЗаглушка (требует авторизации + админ)
/admin/admin/usersGETListUsersActionЗаглушка (требует авторизации + админ)

Точки входа

public/index.php — Последовательность инициализации Slim 4:

  1. Загрузка автозагрузчика Composer
  2. Загрузка настроек из config/app.php (который загружает .env)
  3. Сборка контейнера PHP-DI из config/container.php
  4. Создание приложения Slim через DI\Bridge\Slim\Bridge::create()
  5. Регистрация middleware из config/middleware.php
  6. Регистрация маршрутов из config/routes.php
  7. $app->run()

bin/console — Symfony Console с командами Doctrine Migrations:

  • Использует DependencyFactory::fromEntityManager() с провайдером ExistingEntityManager
  • Команды зарегистрированы с префиксом migrations: (не doctrine:migrations:)
  • Доступные команды: diff, migrate, generate, latest, list, status, version, execute, rollup

Инструменты

ИнструментКонфигурацияСтатус
PHPUnit 11.5phpunit.xml8 тестов, 20 ассертов — все проходят
PHPStan 2.1phpstan.neon (уровень 8)0 ошибок
PHP-CS-Fixer 3.93.php-cs-fixer.php (набор правил PER-CS)Настроен

Миграция базы данных

Первая миграция Version20260205195100 сгенерирована и применена:

  • Создаёт таблицу users со всеми колонками
  • Создаёт уникальный индекс на email
  • Таблица трекинга миграций: doctrine_migration_versions

4. Стратегия интеграции фронтенда и бэкенда

Фронтенд (Nuxt 4) ещё не реализован. Этот раздел описывает, как бэкенд подготовлен к интеграции с фронтендом и планируемую архитектуру.

Структура репозиториев

Планируются два отдельных Git-репозитория:

РепозиторийСтекСтратегия ветвления
team/partizapБэкенд (Slim 4)main → production, develop → development
team/partizap-frontend (планируется)Фронтенд (Nuxt 4)main → production, develop → development

Репозиторий фронтенда будет создан при начале разработки фронтенда.

Готовность API бэкенда

Бэкенд предоставляет JSON REST API, готовый к потреблению фронтендом:

Фронтенд (Nuxt 4)  →  HTTPS  →  Nginx  →  PHP-FPM  →  Slim 4 API

Формат запросов:

  • Content-Type: application/json
  • CSRF: заголовок X-CSRF-TOKEN (значение из cookie CSRF_TOKEN)
  • SSR: Nitro будет проксировать cookie браузера через useRequestHeaders(['cookie'])

Формат ответов:

  • Успех: {"data": T, "meta": {"has_more": bool, "next_cursor": string|null}}
  • Ошибка: {"error": {"code": string, "message": string, "details?": object}}

Конфигурация CORS

Уже настроена в config/cors.php для приёма запросов от фронтенда:

Разрешённые origins: partizap.ru, dev.partizap.ru, localhost:3000
Разрешённые методы: GET, POST, PUT, PATCH, DELETE, OPTIONS
Credentials: включены (для session cookies)

Планируемый рабочий процесс разработки

После инициализации фронтенда:

  1. Бэкенд работает на dev.partizap.ru через Nginx + PHP-FPM (всегда активен на сервере)
  2. Фронтенд запускается на localhost:3000 через npm run dev (Nuxt dev-сервер, на машине разработчика)
  3. Обёртка $fetch фронтенда отправляет API-запросы на dev.partizap.ru
  4. CORS разрешает origin localhost:3000

Деплой бэкенда

Development (ветка develop)

git push origin develop

GitLab CI (опционально: тесты, PHPStan)

Деплой в /var/www/partizap/development/

composer install --optimize-autoloader
php bin/console migrations:migrate --no-interaction

Доступно на dev.partizap.ru (за basic auth)

Production (ветка main)

git checkout main
git merge develop
git push origin main

GitLab CI (полный набор тестов)

Деплой в /var/www/partizap/production/

composer install --no-dev --optimize-autoloader
php bin/console migrations:migrate --no-interaction

Доступно на partizap.ru

Стратегия тестирования

УровеньИнструментСтатусЧто тестируется
Unit бэкендPHPUnitРеализованоJsonResponder, сервисы, валидаторы, доменная логика
Feature бэкендPHPUnitРеализованоКлассы экшенов с замоканными зависимостями
Статический анализ бэкендPHPStan уровень 8РеализованоТипобезопасность всей кодовой базы
Unit фронтендVitestПланируетсяComposables, логика хранилищ, утилиты
Компонентные фронтенд@nuxt/test-utilsПланируетсяVue-компоненты с мок-API
E2E фронтендTBDПланируетсяПолные пользовательские сценарии на dev.partizap.ru

Контракты API

Контракты API задокументированы в каталоге docs проекта:

  • docs/autoparts-contracts-v5.md — Связи сущностей и модели данных
  • docs/partizap_mvp-design.md — Полная спецификация API с форматами запросов/ответов
  • docs/partizap_DB-structure.json — Схема базы данных (27 таблиц)

При реализации фронтенда Zod-схемы и правила валидации бэкенда должны строиться на основе этих контрактов для синхронизации.


5. Известные проблемы и замечания

ПроблемаПодробности
Префикс CLI DoctrineКоманды: migrations:diff, не doctrine:migrations:diff (автономный DependencyFactory)
Мокирование final-классовRedisConnectionFactory изменён с final на обычный класс для тестируемости в PHPUnit
https_proxy на сервереИспользуйте --noproxy '*' с curl для локального тестирования
Несоответствие в документацииdev-prod-infrastructure.md ссылается на PHP 8.2, реально установлен 8.3
Nginx productionПравило блокировки vendor/ исправлено (блокировало API-маршруты /vendor/*)
Воркеры очередейsystemd-сервисы включены, но НЕ запущены (нет задач в очереди)
Middleware-заглушкиCsrfMiddleware и RateLimitMiddleware — pass-through, будут реализованы позже