🎓 НИУ ИТМО ребят люблю вас
Бэкач крутится на PHP 8.4 + Symfony 7. Но фишка не в фреймворке, а в том, как мы его закрутили.
Бизнес-логика жестко распилена по слоям. У нас есть толстый слой Domain (вылизанные чистые PHP классы, которые плевать хотели на то, используем мы Symfony или голый пых). Если завтра придет приказ переписать всё на Laravel — наша бизнес-логика вообще не поменяется.
Мы разводим чтение и запись по разным трубам через Symfony Messenger:
- Commands: Легковесные мутации стейта. Кидаются в шину (
CommandBus), где их ловят обработчики (Handlers), валидируют права (через ABAC воутеры) и дергают доменные сущности. - Queries: Тяжелое чтение. Идет напрямую в ElasticSearch или заточенные SQL-вьюхи, вообще минуя жирный слой ORM (Doctrine). Работает как тесла, но лучше
У нас внедрены DomainEvents. Состояние поменялось — сущность плюет дельта-событием (например, NotificationDispatched или ProductUpdated) во внешний мир (RabbitMQ). На эти ивенты подписаны проекторы (Projectors), которые асинхронно обновляют индексы для быстрого чтения.
Импорты/Экспорты каталогов на сотни мегабайт? Легко. Мы распиливаем гигантские файлы на чанки с помощью RedisChunkedOrchestrator.
- Ждем 'items' в пейлоаде.
- Стейт пуляем в Редиску: трекаем сколько чанков всего и сколько уже сожрали воркеры.
- Атомарно инкрементим счетчики (Redis
INCRстрахует от состояний гонки - race conditions). - Когда все чанки прожеваны — дергаем рубильник финиша.
Авторизация через Google и GitHub запилена по бронебойной концепции.
- Отбиваемся от CSRF атак как джедаи, используя динамический State и PKCE Code Challenge.
- Стратегия А (Жесткий блок авто-мержа): Если мыло из Гугла совпало с локальным юзером — шлем пришельца лесом на экран логина. Мамкины хакеры не угонят аккаунт через фейковый GitHub!
- Сносим сессионный мусор, генерим жирный JWT токен и кладем его в
HttpOnlyкуку. JS до токена фиг дотянется, XSS уходят курить бамбук.
- Стек: Next.js 14, React 18, TypeScript, TailwindCSS + Radix UI (@omnipim/ui).
- FSD (Feature-Sliced Design): Код не валяется в куче, всё строго разбито по слайсам, фичам и сущностям.
- State & Data:
Zustandдля глобального стейта иTanstack React Queryдля кэширования серверных ответов. - Micro-animations: Щепотка
framer-motion, чтобы UI отзывался на каждое действие. - Ощущение будто споткнулся в магазине — вроде кликнул, а данные уже тут (оптимистик апдейты тащат). Фейкуем сетевую задержку только шоб UI выглядел живым
API — это не тупая CRUD-машина. Это шлюз для интеграции с внешним миром
GET /api/v1/products/search: ДергаетProductSearchQuery, который прокидывает хитрый запрос в Elasticsearch, бустит SKU (шоб артикулы летали) и динамически тащит фасеты. Изящно хендлит отвал эластика (отдаем пустоту, чтоб фронт не сложился как карточный домик с 500-й).POST /api/v1/auth/{provider}/start: Ручка хард-редиректа на Google/GitHub. Заставляет браузер схаватьPHPSESSIDкуку.GET /api/v1/auth/{provider}/callback: Точка возврата, которая меняет код на токен через гугл, проверяет Policy A и отдает HttpOnly куку с BEARER.GET /api/v1/me: Пинг бэкача для секьюрной проверки текущей сессии по HttpOnly куке.
- Shopify: Транслируем наши модели OmniPIM в хипстерские мутации Shopify GraphQL.
- SAP ERP: Мапим ламповые данные в обозленный легаси-корпоративный формат SAP OData.
- Вебхуки: Сходу плюемся ивентами в шину очередей (
WebhookReceiver), чтобы моментально откинуть 200 OK экстернал-ботам. Спасаем вебхуки от отвалов по таймауту, пока в бэке молотится жирная нормализация.