Разработка интернет-магазина на Vendure

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Разработка интернет-магазина на Vendure
Сложная
от 2 недель до 3 месяцев
Часто задаваемые вопросы

Наши компетенции:

Этапы разработки

Последние работы

  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    874
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    851

Разработка интернет-магазина на Vendure

Vendure — headless commerce фреймворк на NestJS и TypeScript с GraphQL API. В отличие от commercetools, это open-source решение с self-hosted деплоем: вы контролируете инфраструктуру, данные и можете модифицировать ядро через плагины без форков. Архитектура основана на модулях NestJS, что делает расширение предсказуемым.

Когда Vendure — правильный выбор

  • Нужен self-hosted: данные не покидают вашу инфраструктуру
  • Требуется глубокая кастомизация бизнес-логики (налоги, доставка, промокоды)
  • TypeScript — основной язык команды
  • Бюджет не позволяет SaaS-платформы ($500+/мес на commercetools)
  • Нужен контроль над схемой БД (PostgreSQL/MySQL)

Архитектура проекта

vendure-project/
├── src/
│   ├── vendure-config.ts        # Главный конфиг
│   ├── plugins/                 # Кастомные плагины
│   │   ├── loyalty/
│   │   ├── b2b-pricing/
│   │   └── erp-sync/
│   ├── email-handlers/          # Шаблоны писем
│   └── payment-handlers/        # Обработчики оплаты
├── storefront/                  # Next.js / Nuxt
└── docker-compose.yml

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

// src/vendure-config.ts
import { VendureConfig } from "@vendure/core";
import { defaultEmailHandlers, EmailPlugin } from "@vendure/email-plugin";
import { AssetServerPlugin } from "@vendure/asset-server-plugin";
import { AdminUiPlugin } from "@vendure/admin-ui-plugin";

export const config: VendureConfig = {
  apiOptions: {
    port: 3000,
    adminApiPath: "admin-api",
    shopApiPath: "shop-api",
    adminApiPlayground: process.env.NODE_ENV === "development",
  },

  authOptions: {
    tokenMethod: ["bearer", "cookie"],
    superadminCredentials: {
      identifier: process.env.SUPERADMIN_USERNAME!,
      password: process.env.SUPERADMIN_PASSWORD!,
    },
    cookieOptions: {
      secret: process.env.COOKIE_SECRET!,
    },
  },

  dbConnectionOptions: {
    type: "postgres",
    host: process.env.DB_HOST,
    port: Number(process.env.DB_PORT),
    database: process.env.DB_NAME,
    username: process.env.DB_USER,
    password: process.env.DB_PASSWORD,
    synchronize: false, // только миграции в production
    migrations: ["dist/migrations/*.js"],
  },

  paymentOptions: {
    paymentMethodHandlers: [stripePaymentHandler, yookassaPaymentHandler],
  },

  taxOptions: {
    taxCalculationStrategy: new CustomTaxCalculationStrategy(),
  },

  shippingOptions: {
    shippingCalculators: [defaultShippingCalculator, tieredShippingCalculator],
    shippingEligibilityCheckers: [defaultShippingEligibilityChecker],
    fulfillmentHandlers: [manualFulfillmentHandler],
  },

  plugins: [
    AssetServerPlugin.init({
      route: "assets",
      assetUploadDir: path.join(__dirname, "../static/assets"),
    }),
    EmailPlugin.init({
      devMode: process.env.NODE_ENV === "development",
      handlers: defaultEmailHandlers,
      templatePath: path.join(__dirname, "../email/templates"),
      transport: {
        type: "smtp",
        host: process.env.SMTP_HOST!,
        port: 587,
        auth: {
          user: process.env.SMTP_USER!,
          pass: process.env.SMTP_PASS!,
        },
      },
    }),
    AdminUiPlugin.init({
      route: "admin",
      port: 3002,
    }),
    LoyaltyPlugin,
    B2bPricingPlugin,
    ErpSyncPlugin,
  ],
};

Модель каналов и мультитенантность

Vendure поддерживает Channels — аналог мультиарендности. Один инстанс обслуживает несколько магазинов с раздельным каталогом, ценами и заказами:

// Канал создаётся через Admin API или скрипт заполнения
await channelService.create(ctx, {
  code: "ru-channel",
  token: "ru-token-abc123",
  defaultCurrencyCode: CurrencyCode.RUB,
  defaultLanguageCode: LanguageCode.ru,
  defaultTaxZone: taxZoneRU,
  defaultShippingZone: shippingZoneRU,
  pricesIncludeTax: false,
});

Каждый запрос к Shop API должен содержать заголовок vendure-token: <channel-token>.

Checkout flow через Shop API

# 1. Добавить товар в заказ
mutation AddToOrder($productVariantId: ID!, $quantity: Int!) {
  addItemToOrder(productVariantId: $productVariantId, quantity: $quantity) {
    ... on Order {
      id
      code
      totalWithTax
      lines {
        id
        quantity
        productVariant { name sku }
        unitPriceWithTax
      }
    }
    ... on ErrorResult {
      errorCode
      message
    }
  }
}

# 2. Установить адрес доставки
mutation SetShippingAddress($input: CreateAddressInput!) {
  setOrderShippingAddress(input: $input) {
    ... on Order { id shippingAddress { fullName streetLine1 city } }
    ... on NoActiveOrderError { errorCode message }
  }
}

# 3. Получить методы доставки и выбрать
query GetShippingMethods {
  eligibleShippingMethods {
    id
    name
    price
    priceWithTax
    description
  }
}

mutation SetShippingMethod($id: [ID!]!) {
  setOrderShippingMethod(shippingMethodId: $id) {
    ... on Order { id shipping shippingWithTax }
  }
}

Платёжная интеграция (YooKassa)

// src/payment-handlers/yookassa.handler.ts
import { CreatePaymentResult, PaymentMethodHandler, LanguageCode } from "@vendure/core";

export const yookassaPaymentHandler = new PaymentMethodHandler({
  code: "yookassa",
  description: [{ languageCode: LanguageCode.ru, value: "YooKassa" }],
  args: {
    shopId: { type: "string" },
    secretKey: { type: "string", ui: { component: "password-form-input" } },
  },

  async createPayment(ctx, order, amount, args, metadata): Promise<CreatePaymentResult> {
    const yookassa = new YooKassa({
      shopId: args.shopId,
      secretKey: args.secretKey,
    });

    const payment = await yookassa.createPayment({
      amount: {
        value: (amount / 100).toFixed(2),
        currency: order.currencyCode,
      },
      capture: true,
      confirmation: {
        type: "redirect",
        return_url: `${process.env.SHOP_URL}/checkout/confirmation`,
      },
      description: `Заказ #${order.code}`,
      metadata: { vendure_order_id: order.id },
    });

    return {
      amount,
      state: "Authorized",
      transactionId: payment.id,
      metadata: { confirmationUrl: payment.confirmation.confirmation_url },
    };
  },

  async settlePayment(ctx, order, payment, args) {
    // YooKassa с capture=true — оплата снимается автоматически
    return { success: true };
  },

  async refundPayment(ctx, order, payment, args, lines, adjustment) {
    const yookassa = new YooKassa({ shopId: args.shopId, secretKey: args.secretKey });
    const refund = await yookassa.createRefund(payment.transactionId, {
      amount: { value: (adjustment / 100).toFixed(2), currency: order.currencyCode },
    });
    return { state: "Settled", transactionId: refund.id };
  },
});

Производительность и масштабирование

Vendure поддерживает Worker/Server разделение: тяжёлые задачи (email, экспорт, indexing) обрабатываются в отдельном Worker-процессе через Bull:

// server.ts
import { bootstrap } from "@vendure/core";
bootstrap(config);

// worker.ts — запускается отдельно
import { bootstrapWorker } from "@vendure/core";
bootstrapWorker(config);

Для Production: 2+ инстанса сервера (load balanced), 1+ воркера, Redis для очередей.

Этапы разработки и сроки

Этап Срок
Установка, конфигурация, БД, миграции 2–3 дня
Импорт каталога (Products, Variants, Assets) 3–7 дней
Кастомные плагины (налоги, доставка, промокоды) 5–10 дней
Storefront (Next.js + GraphQL) 10–20 дней
Платёжные интеграции (2–3 провайдера) 4–6 дней
Admin UI кастомизация 2–4 дня
Итого 26–50 дней