От нуля до сборки: пошаговое руководство

В этой теме представлен практический пошаговый гид по использованию Lino CLI в качестве основного инструмента при создании проекта: от установки и первоначальной настройки, через генерацию сервисов, модулей и сущностей, до продвинутых функций, таких как события, фоновые задачи, миграции, сборка Docker-образов и управление версиями.


Цель — показать интегрированным образом, как команды CLI вписываются в реальный процесс разработки — не просто перечислить их, а объяснить причины каждого выбора, что генерируется автоматически и каковы архитектурные последствия.


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


В ходе руководства мы объясним технические концепции, применяемые в Lino (например: CQRS, TypedResults, Source Generators, Outbox Pattern), покажем примеры команд и укажем лучшие практики для управления версиями, деплоя и непрерывной интеграции.

Установка и настройка Lino CLI

Первый шаг для начала работы с Lino CLI — установить инструмент в вашей среде разработки. Он распространяется как dotnet глобальный инструмент, что означает, что он будет доступен для любого проекта .NET на вашем компьютере.

Шаг 1: Установка

Чтобы установить (или обновить) Lino CLI, выполните следующую команду в терминале:

dotnet tool install --global Tolitech.Lino

Важные замечания:

  • Если версия уже установлена, можно использовать dotnet tool update --global Tolitech.Lino для обновления.
  • Убедитесь, что директория глобальных инструментов .NET находится в системном PATH, чтобы команда lino работала корректно.

Шаг 2: Настройка языка

После установки рекомендуется настроить язык (или культуру), который CLI будет использовать в сообщениях, подсказках и логах:

lino preferences culture set

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

Шаг 3: Аутентификация и регистрация

Чтобы получить доступ ко всем возможностям Lino, включая расширенные шаблоны, публикацию Docker-образов и интеграцию с внешними сервисами, необходимо пройти аутентификацию.

- Если у вас еще нет учетной записи, зарегистрируйтесь с помощью команды:

lino user register

- Если учетная запись уже есть, войдите с помощью:

lino auth login

Что происходит: CLI сохраняет токен аутентификации локально, позволяя выполнять команды, требующие доступа к защищённым ресурсам, без повторного входа.

Шаг 4: Проверка

Чтобы убедиться, что установка и аутентификация прошли успешно, выполните:

lino --version

Если команда вернула установленную версию, вы готовы начать использовать Lino CLI в своих проектах.

Создание проекта MyApp

На этом шаге мы создадим начальную структуру проекта с использованием Lino CLI. Этот проект будет служить основой для демонстрации создания сервисов, модулей, фронтенда и всей интеграции событий.

Шаг 1: Выполнение команды создания

Чтобы создать новый проект, выполните следующую команду в терминале:

lino project new

CLI будет пошагово направлять вас, запрашивая следующую информацию:

  • Название проекта: мы используем MyApp, но вы можете выбрать любое другое имя;
  • Дополнительные функции: анализаторы кода, распределённый кэш, поддержка асинхронных событий и др.

Шаг 2: Настройка основных функций

Для этого проекта рекомендуется включить следующие функции с самого начала:

  • Анализаторы кода: обеспечивают соблюдение кода лучших практик и единых стандартов, предотвращая распространённые ошибки реализации;
  • Распределённый кэш: улучшает производительность приложения в сценариях с несколькими сервисами, предотвращая ненужные запросы к базе данных;
  • Асинхронная коммуникация: включает использование событий и очередей для интеграции между сервисами, обеспечивая масштабируемость и разъединение компонентов.

Включение всех этих опций в проекте важно, так как мы будем создавать несколько сервисов, которые будут взаимодействовать через интеграционные события. Это позволит вам понять, как строить модульные и распределённые системы с использованием Lino.

Шаг 3: Сгенерированная структура

После выполнения команды и настройки функций CLI создаст начальную структуру проекта, которая будет включать:

  • Папки для сервисов и модулей;
  • Шаблоны для фронтенда (если применимо);
  • Начальные настройки кэша, событий и интеграций;
  • Файлы решения (.slnx) и проекта (.csproj), готовые к компиляции.

Теперь ваш проект MyApp готов для добавления сервисов, модулей, сущностей и фронтенда, которые мы будем настраивать на следующих шагах.

Добавление фронтенда

Теперь мы создадим интерфейс системы — фронтенд, который будет использоваться как Backoffice. Этот фронтенд не будет публичным приложением, а станет внутренним инструментом, позволяющим администраторам и менеджерам управлять продуктами, категориями, запасами, продажами и другой информацией системы.

Шаг 1: Выполнение команды создания

Чтобы добавить новый фронтенд в проект, используйте следующую команду в терминале:

lino webapp new

В процессе работы CLI запросит некоторые данные, например:

  • Имя веб-приложения: в этом примере мы используем Backoffice;

Шаг 2: Сгенерированная структура

По завершении процесса CLI сгенерирует начальную структуру фронтенда внутри папки WebApps/Backoffice. Стандартная структура включает:

  • Папки для страниц, компонентов и сервисов приложения;
  • HTTP-клиенты для работы с API сервисов проекта;
  • Начальные шаблоны;
  • Файлы конфигурации для интеграции с аутентификацией, авторизацией и системными событиями.

Важные замечания

  • Фронтенд будет автоматически интегрирован с выбранными сервисами и модулями, что позволит напрямую использовать данные о продуктах, категориях и продажах через API, сгенерированные Lino.
  • Можно создавать несколько фронтендов, например, один для администраторов (Backoffice) и другой — публичный (Site), используя тот же процесс.

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

Создание сервисов и модулей

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

Шаг 1: Определение сервисов

Сначала создадим следующие сервисы с чётко определёнными обязанностями:

  • Catalog (модульный) – управление продуктами, категориями и ценами;
  • Sales – обработка продаж и заказов;
  • Stock – управление складом и движением товаров;
  • Security – аутентификация, авторизация и управление пользователями.

Для создания нового сервиса выполните команду:

lino service new

Во время выполнения команды CLI запросит:

  • Имя сервиса: например, Catalog;
  • База данных: выберите технологию, наиболее подходящую для вашего проекта (SQL Server, PostgreSQL и т.д.);

Шаг 2: Создание модулей внутри сервисов

Не все сервисы должны быть модульными. В нашем проекте только сервис Catalog будет иметь модули, чтобы разделить обязанности, такие как мерчандайзинг и ценообразование.

Для сервиса Catalog определены следующие модули:

  • Merchandising – управление продуктами и категориями;
  • Pricing – управление ценами, акциями и историей изменений.

Для создания модуля выполните команду:

lino module new

Вы можете создать любое количество модулей внутри модульного сервиса Catalog. Кроме того, в зависимости от сложности, некоторые модули в будущем могут стать независимыми сервисами. Представленное здесь разделение носит учебный характер и служит примером модульной организации.

Окончательная структура проекта

После создания сервисов и модулей ваша структура решения должна быть примерно следующей:

MyApp/
└── src/
    ├── Aspire/
    ├── Integrations/
    ├── Services/
    │   ├── Catalog/
    │   │   ├── Modules/
    │   │   │   ├── Merchandising/
    │   │   │   └── Pricing/
    │   │   ├── MyApp.Catalog.Host
    │   │   └── MyApp.Catalog.Infrastructure
    │   ├── Sales/
    │   ├── Security/
    │   ├── Shared/
    │   └── Stock/
    └── WebApps/
        ├── Backoffice/
        │   ├── Services/
        │   │   ├── Catalog/
        │   │   ├── Sales/
        │   │   ├── Security/
        │   │   └── Stock/
        │   ├── MyApp.WebApp.Backoffice
        │   └── MyApp.WebApp.Backoffice.Client
        └── Shared/
            └── MyApp.WebApp.Shared
└── tests/
    └── Services/
        ├── Catalog/
        │   ├── Merchandising/
        │   └── Pricing/
        ├── Sales/
        ├── Security/
        ├── Shared/
        └── Stock/

Объяснение структуры:

  • Services/: содержит все сервисы системы, каждый из которых изолирован и имеет свою бизнес-логику, инфраструктуру и хостинг;
  • Modules/: папки внутри модульных сервисов, позволяющие организовывать конкретные функции и поддерживать связный код;
  • WebApps/: фронтенды, связанные с системой и интегрированные с сервисами;
  • Shared/: библиотеки и ресурсы, общие для сервисов и фронтендов;
  • tests/: модульные и интеграционные тесты, организованные по сервисам и модулям.

Благодаря этой модульной структуре каждая команда или разработчик может работать независимо над разными частями системы, облегчая масштабирование, поддержку и тестирование.

Добавление аутентификации и авторизации

Аутентификация и авторизация являются ключевыми элементами любой современной системы. В Lino CLI их добавление в проект простое и быстрое.

Шаг 1: Выполнение команды аутентификации

Чтобы добавить функции аутентификации и авторизации, используйте команду:

lino features auth add

CLI проведет вас через следующие этапы:

  • Выбор сервиса или модуля: необходимо указать, куда будут установлены компоненты аутентификации. В нашем примере мы используем сервис Security, который централизует всю логику безопасности системы;
  • Дополнительные настройки: создание таблиц пользователей, ролей и прав, а также настройка политик доступа.

Шаг 2: Сгенерированная структура

После выполнения команды сервис Security будет содержать файлы и папки, такие как:

  • Entities: классы пользователей, ролей и прав;
  • Infrastructure: конфигурации базы данных и миграции для создания таблиц;
  • Application: сервисы аутентификации, управления пользователями и проверки учетных данных;
  • API/Host: конечные точки для входа, выхода, регистрации и управления ролями.

С этой настройкой ваше приложение будет иметь надежную аутентификацию и детализированный контроль доступа, готовое поддерживать нескольких пользователей и разные уровни прав.

Добавление фоновых задач

В распределённых и модульных системах, таких как та, что мы строим с помощью Lino CLI, не все сервисы общаются напрямую друг с другом. Для обеспечения согласованности и надёжности при обмене информацией мы используем интеграционные события. Однако для эффективной и асинхронной обработки этих событий нам нужны фоновые задачи (Background Jobs).

Lino использует Outbox Pattern, чтобы гарантировать, что все сообщения, создаваемые сервисами, надёжно фиксируются перед отправкой. Это позволяет:

  • Избежать потери событий в случае сбоя или перезапуска сервиса;
  • Обеспечить отправку одного и того же сообщения только один раз;
  • Позволить повторную обработку сообщений в случае сбоя доставки;
  • Разделить обработку событий и основную логику приложения, улучшая производительность и масштабируемость.

Шаг 1: Выполнение команды

Чтобы добавить поддержку фоновых задач в проект, выполните команду:

lino features background-job add

CLI попросит вас выбрать сервис, в котором будет установлен Background Job. Обычно выбирают сервис, который централизует создание событий, например Catalog или Sales.

Шаг 2: Настройка выполнения

Во время настройки вы можете определить:

  • Интервал проверки: определяет, как часто Background Job будет проверять таблицу Outbox на наличие новых сообщений. Слишком короткий интервал увеличивает использование ресурсов, слишком длинный может задерживать доставку событий;
  • Размер пакета обрабатываемых записей: контролирует, сколько событий будет прочитано и отправлено за одно выполнение. Большие пакеты могут повысить производительность, но требуют больше памяти и вычислительной мощности;
  • Политика повторной отправки: в случае сбоя доставки сообщений можно настроить количество повторных попыток отправки задачи.

Эти параметры зависят от размера системы, возможностей машины и ожидаемого объёма событий.

Шаг 3: Сгенерированная структура

После настройки проект будет иметь Background Job, готовый обрабатывать сообщения из таблиц Outbox в каждом сервисе.

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

Создание сущностей и перечислений

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

1. Создание сущности Category

Чтобы создать сущность, используйте команду:

lino entity new

Сущность будет создана в службе Catalog и модуле Merchandising со следующей структурой:

┌────┬────┬───────────────┬────────┬────────┬──────────┬────────────────┐
│ PK │ FK │ Property name │ Type   │ Length │ Required │ Auto-increment │
├────┼────┼───────────────┼────────┼────────┼──────────┼────────────────┤
│ x  │    │ Id            │ Guid   │        │    x     │       x        │
├────┼────┼───────────────┼────────┼────────┼──────────┼────────────────┤
│    │    │ Name          │ string │   50   │    x     │                │
└────┴────┴───────────────┴────────┴────────┴──────────┴────────────────┘

2. Создание сущности Product

Далее создаем сущность Product в той же службе и модуле, включая объекты-значения и перечисления:

┌────┬────┬───────────────┬─────────────┬────────┬──────────┬────────────────┐
│ PK │ FK │ Property name │ Type        │ Length │ Required │ Auto-increment │
├────┼────┼───────────────┼─────────────┼────────┼──────────┼────────────────┤
│ x  │    │ Id            │ Guid        │        │    x     │       x        │
├────┼────┼───────────────┼─────────────┼────────┼──────────┼────────────────┤
│    │    │ Name          │ string      │  100   │    x     │                │
├────┼────┼───────────────┼─────────────┼────────┼──────────┼────────────────┤
│    │    │ Description   │ string      │  500   │    x     │                │
├────┼────┼───────────────┼─────────────┼────────┼──────────┼────────────────┤
│    │    │ Price         │ decimal     │        │    x     │                │
├────┼────┼───────────────┼─────────────┼────────┼──────────┼────────────────┤
│    │ x  │ CategoryId    │ Category    │        │    x     │                │
├────┼────┼───────────────┼─────────────┼────────┼──────────┼────────────────┤
│    │    │ Dimensions    │ ValueObject │        │          │                │
├────┼────┼───────────────┼─────────────┼────────┼──────────┼────────────────┤
│    │    │ Status        │ Enum        │        │    x     │                │
└────┴────┴───────────────┴─────────────┴────────┴──────────┴────────────────┘

2.1 Создание объекта-значения ProductDimension

Этот объект-значение представляет размеры продукта:

┌───────────────┬─────────┬────────┬──────────┐
│ Property name │ Type    │ Length │ Required │
├───────────────┼─────────┼────────┼──────────┤
│ Width         │ decimal │        │    x     │
├───────────────┼─────────┼────────┼──────────┤
│ Height        │ decimal │        │    x     │
├───────────────┼─────────┼────────┼──────────┤
│ Depth         │ decimal │        │    x     │
└───────────────┴─────────┴────────┴──────────┘

2.2 Создание перечисления ProductStatus

Это перечисление определяет статус продукта:

┌───────┬──────────────┬──────────────┐
│ Value │ Name         │ Display Name │
├───────┼──────────────┼──────────────┤
│ 1     │ Active       │ Active       │
├───────┼──────────────┼──────────────┤
│ 2     │ Inactive     │ Inactive     │
├───────┼──────────────┼──────────────┤
│ 3     │ Discontinued │ Discontinued │
└───────┴──────────────┴──────────────┘

3. Добавление новых свойств

По мере развития проекта мы можем редактировать существующие сущности, чтобы добавлять новые свойства. Например, добавим список изображений в сущность Product:

lino entity edit

Создавая свойство Images типа List<ProductImage>, мы получим следующую структуру:

┌────┬────┬───────────────┬────────────────────┬────────┬──────────┬────────────────┐
│ PK │ FK │ Property name │ Type               │ Length │ Required │ Auto-increment │
├────┼────┼───────────────┼────────────────────┼────────┼──────────┼────────────────┤
│ x  │    │ Id            │ Guid               │        │    x     │       x        │
├────┼────┼───────────────┼────────────────────┼────────┼──────────┼────────────────┤
│    │    │ Name          │ string             │  100   │    x     │                │
├────┼────┼───────────────┼────────────────────┼────────┼──────────┼────────────────┤
│    │    │ Description   │ string             │  500   │    x     │                │
├────┼────┼───────────────┼────────────────────┼────────┼──────────┼────────────────┤
│    │    │ Price         │ decimal            │        │    x     │                │
├────┼────┼───────────────┼────────────────────┼────────┼──────────┼────────────────┤
│    │ x  │ CategoryId    │ EntityId           │        │    x     │                │
├────┼────┼───────────────┼────────────────────┼────────┼──────────┼────────────────┤
│    │    │ Dimensions    │ ValueObject        │        │          │                │
├────┼────┼───────────────┼────────────────────┼────────┼──────────┼────────────────┤
│    │    │ Status        │ Enum               │        │    x     │                │
├────┼────┼───────────────┼────────────────────┼────────┼──────────┼────────────────┤
│    │ x  │ Images        │ List<ProductImage> │        │          │                │
└────┴────┴───────────────┴────────────────────┴────────┴──────────┴────────────────┘

3.1 Создание сущности ProductImage

Эта сущность принадлежит агрегату Product и имеет следующую структуру:

┌────┬────┬───────────────┬────────────────┬────────┬──────────┬────────────────┐
│ PK │ FK │ Property name │ Type           │ Length │ Required │ Auto-increment │
├────┼────┼───────────────┼────────────────┼────────┼──────────┼────────────────┤
│ x  │    │ Id            │ Guid           │        │    x     │       x        │
├────┼────┼───────────────┼────────────────┼────────┼──────────┼────────────────┤
│    │ x  │ ProductId     │ EntityId       │        │    x     │                │
├────┼────┼───────────────┼────────────────┼────────┼──────────┼────────────────┤
│    │    │ UploadDate    │ DateTimeOffset │        │    x     │                │
├────┼────┼───────────────┼────────────────┼────────┼──────────┼────────────────┤
│    │    │ Image         │ File           │        │    x     │                │
└────┴────┴───────────────┴────────────────┴────────┴──────────┴────────────────┘

4. Создание сущностей для других служб

В службе Sales мы создаем сущность ProductSnapshot, которая будет наполняться событиями интеграции. Поскольку исходный Id сущности Product приходит из службы Catalog, здесь он не может быть автоинкрементным.

┌────┬────┬───────────────┬─────────┬────────┬──────────┬────────────────┐
│ PK │ FK │ Property name │ Type    │ Length │ Required │ Auto-increment │
├────┼────┼───────────────┼─────────┼────────┼──────────┼────────────────┤
│ x  │    │ Id            │ Guid    │        │    x     │                │
├────┼────┼───────────────┼─────────┼────────┼──────────┼────────────────┤
│    │    │ Name          │ string  │  100   │    x     │                │
├────┼────┼───────────────┼─────────┼────────┼──────────┼────────────────┤
│    │    │ Price         │ decimal │        │    x     │                │
└────┴────┴───────────────┴─────────┴────────┴──────────┴────────────────┘

Примечание: только необходимые поля были скопированы в ProductSnapshot для службы Sales. Дополнительные сущности, такие как Customer, Order и StockItem, здесь не рассматриваются для упрощения документации.

Создание событий и их обработчиков

Напомним, в предыдущем разделе мы создали в модульном сервисе Catalog.Merchandising сущности Product, Category и ProductImage, а в сервисе Sales — сущность ProductSnapshot.

Теперь мы создадим доменные события и интеграционные события. Цель состоит в том, чтобы при создании или обновлении продуктов в сервисе Catalog эти изменения реплицировались в потребляющие сервисы, такие как Sales и Stock.

1. Создание доменных событий

Первый шаг — создать доменные события ProductCreated и ProductUpdated с помощью команды:

lino event new

Во время создания можно связать событие с обработчиком и одновременно настроить триггер интеграционного события. Это централизует создание всего необходимого потока.

┌──────────────────────────────────────────────────────┬────────────────────────────────┐
│ Question                                             │ Answer                         │
├──────────────────────────────────────────────────────┼────────────────────────────────┤
│ Select a service:                                    │ Catalog                        │
├──────────────────────────────────────────────────────┼────────────────────────────────┤
│ Select a module:                                     │ Merchandising                  │
├──────────────────────────────────────────────────────┼────────────────────────────────┤
│ Select a entity:                                     │ Product                        │
├──────────────────────────────────────────────────────┼────────────────────────────────┤
│ Select the event type:                               │ Domain Event                   │
├──────────────────────────────────────────────────────┼────────────────────────────────┤
│ Enter the name of the event:                         │ ProductCreated                 │
├──────────────────────────────────────────────────────┼────────────────────────────────┤
│ Do you want to create an associated event handler?   │ Yes                            │
├──────────────────────────────────────────────────────┼────────────────────────────────┤
│ Trigger a integration event?                         │ Yes                            │
├──────────────────────────────────────────────────────┼────────────────────────────────┤
│ Choose the integration event to be triggered:        │ (Create new integration event) │
├──────────────────────────────────────────────────────┼────────────────────────────────┤
│ Enter the name of the event:                         │ ProductCreated                 │
├──────────────────────────────────────────────────────┼────────────────────────────────┤
│ Which model will be used for this integration event? │ Creation model                 │
└──────────────────────────────────────────────────────┴────────────────────────────────┘

Аналогично создаём событие ProductUpdated:

┌──────────────────────────────────────────────────────┬────────────────────────────────┐
│ Question                                             │ Answer                         │
├──────────────────────────────────────────────────────┼────────────────────────────────┤
│ Select a service:                                    │ Catalog                        │
├──────────────────────────────────────────────────────┼────────────────────────────────┤
│ Select a module:                                     │ Merchandising                  │
├──────────────────────────────────────────────────────┼────────────────────────────────┤
│ Select a entity:                                     │ Product                        │
├──────────────────────────────────────────────────────┼────────────────────────────────┤
│ Select the event type:                               │ Domain Event                   │
├──────────────────────────────────────────────────────┼────────────────────────────────┤
│ Enter the name of the event:                         │ ProductUpdated                 │
├──────────────────────────────────────────────────────┼────────────────────────────────┤
│ Do you want to create an associated event handler?   │ Yes                            │
├──────────────────────────────────────────────────────┼────────────────────────────────┤
│ Trigger a integration event?                         │ Yes                            │
├──────────────────────────────────────────────────────┼────────────────────────────────┤
│ Choose the integration event to be triggered:        │ (Create new integration event) │
├──────────────────────────────────────────────────────┼────────────────────────────────┤
│ Enter the name of the event:                         │ ProductUpdated                 │
├──────────────────────────────────────────────────────┼────────────────────────────────┤
│ Which model will be used for this integration event? │ Update model                   │
└──────────────────────────────────────────────────────┴────────────────────────────────┘

Таким образом, мы имеем:

  • Созданные доменные события (ProductCreated и ProductUpdated);
  • Соответствующие обработчики доменных событий;
  • Интеграционные события, автоматически зарегистрированные в Outbox обработчиком доменных событий.

2. Создание обработчиков интеграционных событий

Следующий шаг — определить, какие сервисы будут потреблять интеграционные события. Для этого используется команда:

lino event-handler new

Поток создания включает:

  • Выбор сервиса, модуля и сущности, в которой будет находиться обработчик;
  • Выбор интеграционного события, которое будет потребляться, и из какого сервиса/модуля/сущности оно пришло.

Например, в сервисе Sales мы создаём обработчики для ProductCreated и ProductUpdated, которые будут потреблять события, генерируемые Catalog.Merchandising.Product:

┌────────────────────────────────────────────┬───────────────────┐
│ Question                                   │ Answer            │
├────────────────────────────────────────────┼───────────────────┤
│ Select a service:                          │ Sales             │
├────────────────────────────────────────────┼───────────────────┤
│ Select a entity:                           │ ProductSnapshot   │
├────────────────────────────────────────────┼───────────────────┤
│ Select the event type:                     │ Integration Event │
├────────────────────────────────────────────┼───────────────────┤
│ Select the event's service to be consumed: │ Catalog           │
├────────────────────────────────────────────┼───────────────────┤
│ Select the event's module to be consumed:  │ Merchandising     │
├────────────────────────────────────────────┼───────────────────┤
│ Select the event's entity to be consumed:  │ Product           │
├────────────────────────────────────────────┼───────────────────┤
│ Choose the event to be consumed:           │ ProductCreated    │
├────────────────────────────────────────────┼───────────────────┤
│ Enter the name of the event handler:       │ ProductCreated    │
└────────────────────────────────────────────┴───────────────────┘
┌────────────────────────────────────────────┬───────────────────┐
│ Question                                   │ Answer            │
├────────────────────────────────────────────┼───────────────────┤
│ Select a service:                          │ Sales             │
├────────────────────────────────────────────┼───────────────────┤
│ Select a entity:                           │ ProductSnapshot   │
├────────────────────────────────────────────┼───────────────────┤
│ Select the event type:                     │ Integration Event │
├────────────────────────────────────────────┼───────────────────┤
│ Select the event's service to be consumed: │ Catalog           │
├────────────────────────────────────────────┼───────────────────┤
│ Select the event's module to be consumed:  │ Merchandising     │
├────────────────────────────────────────────┼───────────────────┤
│ Select the event's entity to be consumed:  │ Product           │
├────────────────────────────────────────────┼───────────────────┤
│ Choose the event to be consumed:           │ ProductUpdated    │
├────────────────────────────────────────────┼───────────────────┤
│ Enter the name of the event handler:       │ ProductUpdated    │
└────────────────────────────────────────────┴───────────────────┘

Таким образом, в сервисе Sales мы имеем два обработчика интеграционных событий, которые потребляют только необходимые поля из интеграционных событий Catalog.Merchandising. Это гарантирует, что реплицированные таблицы содержат только ключевые данные, оптимизируя хранение и производительность.

Генерация веб-страниц, API, Commands и Queries

Одним из больших преимуществ Lino CLI является возможность автоматизированного создания веб-страниц, API, Commands и Queries, упрощая весь процесс разработки. Чтобы начать, просто выполните команду:

lino page new

В процессе вы:

  • Выберете сервис, модуль и сущность, которые хотите опубликовать;
  • Выберете поля, которые будут отображаться в списке;
  • Автоматически создадите страницы списка (пагинированная сетка) и формы создания/редактирования;
  • Сгенерируете классы HttpClient для использования на фронтенде;
  • Создадите все необходимые REST API (POST, PUT, PATCH, DELETE и GET);
  • Создадите Commands и Queries с соответствующими Handlers, которые взаимодействуют с базой данных, обеспечивая полный CRUD-процесс.

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

Для этого проекта мы можем сгенерировать интегрированные страницы для следующих сущностей:

  • Catalog.Merchandising.Category
  • Catalog.Merchandising.Product
  • Sales.ProductSnapshot

После генерации страниц, API и Commands/Queries приложение будет готово для полной интеграции между фронтендом и бэкендом, с проверками, маршрутами и сохранением данных, уже настроенными автоматически Lino CLI.

Создание миграций базы данных

Теперь, когда все сущности созданы, пора сгенерировать миграции, чтобы базы данных были созданы или обновлены в соответствии с определённой моделью. Lino CLI автоматизирует этот процесс, интегрируясь с Entity Framework и создавая готовые к выполнению скрипты.

Чтобы создать новую миграцию, выполните команду:

lino database migrations new

Во время выполнения вам потребуется:

  • Выбрать сервис и модуль, для которых будет создана миграция;
  • Указать описание миграции, например, "Initial migration".

┌───────────────────────────────────────────┬───────────────────┐
│ Question                                  │ Answer            │
├───────────────────────────────────────────┼───────────────────┤
│ Select a service:                         │ Catalog           │
├───────────────────────────────────────────┼───────────────────┤
│ Select a module:                          │ Merchandising     │
├───────────────────────────────────────────┼───────────────────┤
│ Current version of the service:           │ 0.1.0             │
├───────────────────────────────────────────┼───────────────────┤
│ Provide a description for this migration: │ Initial migration │
└───────────────────────────────────────────┴───────────────────┘

После подтверждения Lino CLI сгенерирует:

  • Новую миграцию базы данных для текущей версии сервиса;
  • Соответствующий SQL-скрипт, расположенный в слое Infrastructure.Persistence, по пути /scripts/<version>/<имя файла>;
  • Запись версии миграции в истории сервиса, обеспечивая отслеживаемость и согласованность.

Рекомендуемые практики:

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

Следуя этому процессу, вы обеспечиваете, что база данных всегда актуальна и соответствует модели домена, определённой в Lino CLI, снижая количество ошибок и упрощая сопровождение.

Создание Docker-образов

После завершения генерации кода для конкретной версии, проведения тестов и реализации всех необходимых бизнес-правил, вы можете создать Docker-образы для сервисов и веб-приложений вашего проекта для последующей публикации в реестре контейнеров.

Lino CLI упрощает этот процесс с помощью команды:

lino build

При выполнении вы увидите список всех доступных в проекте сервисов и веб-приложений с их текущими версиями:

Select the services or web applications you want to include in the build:

> [ ] Services
    [ ] Catalog |0.1.0|
    [ ] Sales |0.1.0|
    [ ] Security |0.1.0|
    [ ] Stock |0.1.0|
  [ ] Web applications
    [ ] Backoffice |0.1.0|

Вы можете выбрать один или несколько сервисов и веб-приложений для одновременного создания образов. Просто отметьте нужные элементы.

Далее потребуется выбрать, как обновлять версию создаваемых образов. Доступные варианты:

  • Сохранить текущую версию – версия не изменяется;
  • Patch – увеличить патч-версию (например: 0.1.0 → 0.1.1);
  • Minor – увеличить минор-версию (например: 0.1.0 → 0.2.0);
  • Major – увеличить мажор-версию (например: 0.1.0 → 1.0.0).

После выбора сервисов и способа увеличения версии, Lino CLI выполнит:

  • Сборку кода каждого сервиса и веб-приложения;
  • Создание соответствующего Docker-образа;
  • Присвоение тегов с указанной версией;
  • Предоставление образов для публикации в вашем реестре контейнеров.

В конце процесса, если все сервисы и веб-приложения были выбраны, созданные образы будут иметь следующую структуру:

  • my-app/services/catalog-host - tag: 0.1.0
  • my-app/services/sales-api - tag: 0.1.0
  • my-app/services/security-api - tag: 0.1.0
  • my-app/services/stock-api - tag: 0.1.0
  • my-app/webapps/backoffice - tag: 0.1.0

Примечание: Этот процесс обеспечивает согласованность между кодом и версиями Docker-образов, облегчая деплой и обслуживание нескольких окружений, а также позволяя каждому сервису работать в отдельном контейнере.

Создание версий в приложении

Увеличение версий сервисов или веб-приложений — это простой процесс, централизованный в Lino CLI. Достаточно выполнить команду:

lino version bump

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

Select the services or web applications that will have version changes:

> [ ] Services
    [ ] Catalog |0.1.0|
    [ ] Sales |0.1.0|
    [ ] Security |0.1.0|
    [ ] Stock |0.1.0|
  [ ] Web applications
    [ ] Backoffice |0.1.0|

После выбора необходимых элементов вам будет предложено выбрать тип увеличения версии. Доступные варианты:

  • Patch – небольшие исправления без функционального воздействия;
  • Minor – добавление новых функций, совместимых с предыдущими версиями;
  • Major – изменения, которые могут нарушить совместимость с предыдущими версиями.

Важно отметить, что версии сервисов и веб-приложений напрямую влияют на:

  • Теги Docker-образов;
  • Папки для хранения скриптов, сгенерированных при миграциях базы данных;
  • Контроль релизов и история проекта.

На этом мы завершаем пошаговое руководство по всем основным командам для создания веб-проекта с использованием Lino CLI, включая установку, создание сервисов, сущностей, событий и страниц, а также генерацию Docker-образов и управление версиями.

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

Произошла необработанная ошибка. Обновить 🗙