B2B SaaS-платформа

B2B SaaS-платформа

Next.js 13TurborepoTanstack QueryChakra UI

Контекст

B2B SaaS-платформа, разработанная с нуля для автомобильной отрасли:

  • 🖥️ Специализированная CMS, позволяющая клиентским организациям (дилерам, реселлерам, лизинговым компаниям) создавать, управлять и публиковать транспортные средства и сделки.
  • 🤝 CRM для управления их бизнес-процессами.

Транспортные средства представляют собой полиморфные бизнес-объекты, используемые сквозным образом в экосистеме взаимосвязанных приложений, каждое из которых отображает и обрабатывает их в собственном контексте: бэкофис, динамически генерируемый публичный сайт, внутренний ERP, клиентский портал и т.д.

Я работал над всеми этими приложениями в течение 3 лет, включая несколько месяцев в роли единственного фронтенд-разработчика после запуска проекта.

Полиморфная модель

В основе проекта лежала дискриминированная и вложенная модель данных. Каждый ресурс, создаваемый через CMS, - это не просто общий объект, а типизированная сущность, структура которой зависит от дискриминатора.

Полиморфная модель данных

Плоская модель заставляет интерфейс работать с опциональными полями (всё присутствует, но ничего не гарантировано). Полиморфная модель с дискриминатором по типу позволяет каждому объекту содержать только релевантные свойства, обеспечивая строгую типизацию, надёжную валидацию и точное отображение без лишних условий.

Упрощённое представление модели:

  • Транспортное средство (автомобиль · мотоцикл · грузовик · и т.д.) имеет общую базу, но включает характеристики, специфичные для каждого типа.
  • У транспортного средства есть коммерческие условия (продажа · лизинг · аренда), которые также являются полиморфными.
Пример матрицы бизнес-кейсов

Такая модель формирует матрицу бизнес-кейсов, которую необходимо явно реализовать сквозным образом (формы создания/редактирования, валидация, отображение во всех приложениях). Каждая комбинация - это отдельный кейс. Именно эта полнота покрытия позволяет интерфейсу точно отражать все нюансы предметной области.

Реализация на фронтенде

Перенос дискриминированной модели в интерфейс - это не просто набор условий if/else. Ключевой архитектурный вопрос заключался в том: где размещать дискриминирующую логику и как инкапсулировать её так, чтобы она оставалась поддерживаемой по мере роста числа бизнес-кейсов.

Изоляция сложности и композиция

Цель состояла в том, чтобы держать дискриминирующую логику максимально близко к месту её использования, избегая избыточного распространения сложности по дереву компонентов.

Динамическая сборка компонента

Для каждого типа транспортного средства или сделки существуют собственные компоненты, которые динамически собираются в зависимости от дискриминатора.

В некоторых случаях (например, страница деталей транспортного средства или раздел характеристик в бэкофис-форме) дискриминация происходила на уровне всей страницы, определяя, какое представление нужно отобразить в зависимости от типа. Затем каждая страница комбинировала общие и специфические секции с помощью композиции.

Строгая типизация

Дискриминированные объединения в TypeScript гарантировали, что каждый бизнес-кейс обрабатывается полностью. Компилятор сигнализировал о любых необработанных комбинациях.

Контекстная валидация

Правила валидации зависели от типа. Форма лизинга не проверяет те же поля, что и форма продажи (и может иметь другие бизнес-правила). Ошибки обрабатывались отдельно для каждого случая.

Структура монорепозитория

Общая кодовая база (монорепозиторий) обеспечивала визуальную и поведенческую согласованность между приложениями: UI-компоненты, дизайн-система, инструменты. Каждое приложение имело собственный слой доступа к данным (выделенный BFF), а типы DTO автоматически генерировались из документации Swagger с помощью библиотеки Orval. Это устраняло ручное дублирование и при этом сохраняло чёткое разделение ответственности.

Методология и культура команды

Небольшая команда (2 фронтенд-разработчика, 2 бэкенд-разработчика). Систематические code review, agile-практики (standup с фокусом на снятие блокеров, а не отчётность, планирование спринтов, ретроспективы), регулярные демо для стейкхолдеров.

Итоги

3 года работы над полноценной SaaS-платформой, разработанной с нуля до версии 2.6. Этот проект научил меня:

  • 🧬 Поддерживать согласованность сложной модели в нескольких приложениях
  • 🤝 Работать в команде с сильной культурой качества (ревью, ответственность, демо)
  • 🕵️ Предвидеть архитектурные решения, а не реагировать на них постфактум
  • 🗄️ Погрузиться в backend-задачи и моделирование данных, что сегодня поддерживает мой переход к fullstack