From Zero to Build: Step-by-Step Guide
This topic provides a practical, step-by-step guide on using Lino CLI as the main tool for building a project: from installation and initial setup, through generating services, modules, and entities, to advanced features such as events, background jobs, migrations, Docker image builds, and versioning.
The goal is to show, in an integrated way, how CLI commands fit into the real development workflow β not just listing them, but explaining the reasoning behind each choice, what is generated automatically, and the architectural implications.
Even though each command has its own documentation, here you will see the end-to-end process β a reproducible roadmap that saves hours of repetitive work and helps maintain consistent, testable code.
Throughout the guide, we will explain technical concepts applied by Lino (e.g., CQRS, TypedResults, Source Generators, Outbox Pattern), provide command examples, and indicate best practices for versioning, deployment, and continuous integration.
Installing and Configuring Lino CLI
The first step to start working with Lino CLI is to install the tool in your development environment. It is distributed as a dotnet global tool, which means it will be available for any .NET project on your computer.
Step 1: Installation
To install (or update) Lino CLI, run the following command in the terminal:
dotnet tool install --global Tolitech.Lino
Important notes:
- If a version is already installed, you can use
dotnet tool update --global Tolitech.Linoto update it. - Ensure that the .NET global tools directory is in your system
PATHso thelinocommand works correctly.
Step 2: Configure Language
After installation, it is recommended to configure the language (or culture) that the CLI will use for messages, prompts, and logs:
lino preferences culture set
You will be prompted to choose from the available languages. This setting ensures that all instructions and prompts appear consistently in the desired language.
Step 3: Authentication and Registration
To access all Lino features, including advanced templates, Docker image publishing, and integration with external services, authentication is required.
- If you donβt have an account yet, register with the command:
lino user register
- If you already have an account, log in with:
lino auth login
What happens: The CLI stores an authentication token locally, allowing you to run commands that require access to protected resources without logging in each time.
Step 4: Verification
To confirm that installation and authentication were successful, run:
lino --version
If the command returns the installed version, you are ready to start using Lino CLI in your projects.
Creating the MyApp Project
In this step, we will create the initial project structure using Lino CLI. This project will serve as a base to demonstrate the creation of services, modules, front-end, and event integration.
Step 1: Executing the creation command
To create a new project, run the following command in your terminal:
lino project new
The CLI will guide you step by step, asking for information such as:
- Project name: we will use
MyApp, but you can choose any name you like; - Additional features: code analyzers, distributed caching, asynchronous event support, etc.
Step 2: Configuring essential features
For this project, we recommend enabling the following features from the start:
- Code analyzers: to ensure that code follows best practices and consistent standards, preventing common implementation errors;
- Distributed caching: improves application performance in multi-service scenarios, avoiding unnecessary database queries;
- Asynchronous communication: enables the use of events and queues for service integration, ensuring scalability and decoupling.
It is important to enable all of these options in this project, as we will create multiple services that communicate via integration events. This will allow you to understand how to structure modular and distributed systems using Lino.
Step 3: Generated structure
After executing the command and configuring the features, the CLI will generate the initial project structure. It will include:
- Folders for services and modules;
- Templates for the front-end (if applicable);
- Initial configurations for caching, events, and integrations;
- Solution files (.slnx) and project files (.csproj) ready for compilation.
Your MyApp project is now ready to receive the services, modules, entities, and front-end that we will configure in the following steps.
Adding the frontend
Now let's create the system interface, the frontend, which will be used as the Backoffice. This frontend will not be a public application, but rather an internal tool for administrators and managers to manage products, categories, stock, sales, and other system information.
Step 1: Running the creation command
To add a new frontend to the project, use the following command in the terminal:
lino webapp new
The CLI will ask for some information during the process, such as:
- Web application name: we will use
Backofficefor this example;
Step 2: Generated structure
At the end of the process, the CLI will generate the initial frontend structure inside the WebApps/Backoffice folder.
The default structure includes:
- Folders for the application's pages, components, and services;
- HTTP clients to consume APIs from the project services;
- Initial templates;
- Configuration files for integration with authentication, authorization, and system events.
Important notes
- The frontend will be automatically integrated with the selected services and modules, allowing product, category, and sales data to be consumed directly via APIs generated by Lino.
- You can create multiple frontends, for example, one for administrators (Backoffice) and another public one (Site), following the same process.
With the frontend created, we are ready to move forward to the creation of the services and modules that will provide the data and business rules for this application.
Creating Services and Modules
In this step, we will build the services and modules that will compose the application. The goal is to create a modular and scalable architecture, allowing different areas of the system, such as products, categories, stock, sales, and media, to evolve independently while maintaining cohesion and facilitating maintenance.
Step 1: Defining the Services
Initially, we will create the following services, each with clearly defined responsibilities:
- Catalog (modular) β responsible for managing products, categories, and pricing;
- Sales β responsible for processing sales and orders;
- Stock β responsible for managing inventory and stock movements;
- Security β responsible for authentication, authorization, and user management.
To create a new service, run the command:
lino service new
During command execution, the CLI will ask for:
- Service name: e.g.,
Catalog; - Database: choose the technology that best fits your project (SQL Server, PostgreSQL, etc.);
Step 2: Creating Modules within Services
Not all services need to be modular. In our project, only the Catalog service will have modules, to separate responsibilities such as merchandising and pricing.
For the Catalog service, we defined the following modules:
- Merchandising β managing products and categories;
- Pricing β managing prices, promotions, and change history.
To create a module, run the command:
lino module new
You can create as many modules as you want within the modular Catalog service. Additionally, depending on complexity, some modules could become independent services in the future. The separation shown here is purely educational and serves as an example of modular organization.
Final Project Structure
After creating the services and modules, your solution should have a structure similar to the following:
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/
Structure explanation:
Services/: contains all system services, each isolated with its own business logic, infrastructure, and hosting;Modules/: folders inside modular services, allowing organization of specific functionalities and maintaining cohesive code;WebApps/: frontends associated with the system, already integrated with the services;Shared/: libraries and resources shared between services and frontends;tests/: unit and integration tests organized by service and module.
With this modular structure, each team or developer can work independently on different parts of the system, facilitating scalability, maintenance, and testing.
Adding Authentication and Authorization
Authentication and authorization are essential elements of any modern system. In Lino CLI, adding them to your project is simple and quick.
Step 1: Running the authentication command
To add authentication and authorization features, use the command:
lino features auth add
The CLI will guide you through the following steps:
- Choosing the service or module: you need to indicate where the authentication artifacts will be installed. In our example project, we use the Security service, which centralizes all system security logic;
- Additional configurations: creating user, role, and permission tables, and setting up access policies.
Step 2: Generated structure
After executing the command, the Security service will contain files and folders such as:
- Entities: user, role, and permission classes;
- Infrastructure: database configurations and migrations to create tables;
- Application: authentication services, user management, and credential validation;
- API/Host: endpoints for login, logout, registration, and role management.
With this setup, your application will have robust authentication and granular access control, ready to support multiple users and different permission levels.
Adding Background Jobs
In distributed and modular systems, like the one we are building with the Lino CLI, not all services communicate directly with each other. To ensure consistency and reliability in information exchange, we use integration events. However, to process these events efficiently and asynchronously, we need Background Jobs.
Lino uses the Outbox Pattern to ensure that all messages generated by services are reliably recorded before being sent. This allows us to:
- Avoid losing events in case of service failures or restarts;
- Ensure that the same message is sent only once;
- Allow reprocessing of messages in case of delivery failure;
- Separate event processing from the application's main logic, improving performance and scalability.
Step 1: Running the command
To add Background Jobs support to your project, run the command:
lino features background-job add
The CLI will ask you to select the service where the Background Job will be installed. Typically, you will choose the service that centralizes event production, such as Catalog or Sales.
Step 2: Configuring execution
During configuration, you can define:
- Check interval: determines how often the Background Job will check the Outbox table for new messages. A very short interval may increase resource usage, while a long interval may delay event delivery;
- Batch of records processed at a time: controls how many events will be read and sent per execution. Larger batches can increase performance but require more memory and processing power;
- Retry policy: in case of message delivery failure, you can configure how many times the job will attempt to resend.
These parameters depend on the size of your system, the machine's capacity, and the expected event volume.
Step 3: Generated structure
After configuration, the project will have a Background Job ready to process messages from the Outbox tables in each service.
This ensures that all integration events are processed reliably and efficiently, allowing multiple services and modules to communicate asynchronously without impacting the main system's performance.
Creating Entities and Enumerations
In this section, we will detail the design of entities, enumerations, and value objects in the application, showing in which services and modules each item will be created.
1. Creating the Category Entity
To create the entity, use the command:
lino entity new
The entity will be created in the Catalog service and the Merchandising module with the following structure:
ββββββ¬βββββ¬ββββββββββββββββ¬βββββββββ¬βββββββββ¬βββββββββββ¬βββββββββββββββββ β PK β FK β Property name β Type β Length β Required β Auto-increment β ββββββΌβββββΌββββββββββββββββΌβββββββββΌβββββββββΌβββββββββββΌβββββββββββββββββ€ β x β β Id β Guid β β x β x β ββββββΌβββββΌββββββββββββββββΌβββββββββΌβββββββββΌβββββββββββΌβββββββββββββββββ€ β β β Name β string β 50 β x β β ββββββ΄βββββ΄ββββββββββββββββ΄βββββββββ΄βββββββββ΄βββββββββββ΄βββββββββββββββββ
2. Creating the Product Entity
Next, we create the Product entity in the same service and module, including value objects and enumerations:
ββββββ¬βββββ¬ββββββββββββββββ¬ββββββββββββββ¬βββββββββ¬βββββββββββ¬βββββββββββββββββ β 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 Creating the Value Object ProductDimension
This Value Object represents the product dimensions:
βββββββββββββββββ¬ββββββββββ¬βββββββββ¬βββββββββββ β Property name β Type β Length β Required β βββββββββββββββββΌββββββββββΌβββββββββΌβββββββββββ€ β Width β decimal β β x β βββββββββββββββββΌββββββββββΌβββββββββΌβββββββββββ€ β Height β decimal β β x β βββββββββββββββββΌββββββββββΌβββββββββΌβββββββββββ€ β Depth β decimal β β x β βββββββββββββββββ΄ββββββββββ΄βββββββββ΄βββββββββββ
2.2 Creating the Enum ProductStatus
This enum defines the product status:
βββββββββ¬βββββββββββββββ¬βββββββββββββββ β Value β Name β Display Name β βββββββββΌβββββββββββββββΌβββββββββββββββ€ β 1 β Active β Active β βββββββββΌβββββββββββββββΌβββββββββββββββ€ β 2 β Inactive β Inactive β βββββββββΌβββββββββββββββΌβββββββββββββββ€ β 3 β Discontinued β Discontinued β βββββββββ΄βββββββββββββββ΄βββββββββββββββ
3. Adding New Properties
As the project evolves, we can edit existing entities to add new properties.
For example, we will add a list of images to the Product entity:
lino entity edit
Creating the Images property of type List<ProductImage>, we will generate the following structure:
ββββββ¬βββββ¬ββββββββββββββββ¬βββββββββββββββββββββ¬βββββββββ¬βββββββββββ¬βββββββββββββββββ β 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 Creating the ProductImage Entity
This entity belongs to the Product aggregate and has the following structure:
ββββββ¬βββββ¬ββββββββββββββββ¬βββββββββββββββββ¬βββββββββ¬βββββββββββ¬βββββββββββββββββ β 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. Creating Entities for Other Services
In the Sales service, we create the ProductSnapshot entity, which will be populated by integration events.
Since the original Id of the Product entity comes from the Catalog service, it cannot be auto-incremented here.
ββββββ¬βββββ¬ββββββββββββββββ¬ββββββββββ¬βββββββββ¬βββββββββββ¬βββββββββββββββββ β PK β FK β Property name β Type β Length β Required β Auto-increment β ββββββΌβββββΌββββββββββββββββΌββββββββββΌβββββββββΌβββββββββββΌβββββββββββββββββ€ β x β β Id β Guid β β x β β ββββββΌβββββΌββββββββββββββββΌββββββββββΌβββββββββΌβββββββββββΌβββββββββββββββββ€ β β β Name β string β 100 β x β β ββββββΌβββββΌββββββββββββββββΌββββββββββΌβββββββββΌβββββββββββΌβββββββββββββββββ€ β β β Price β decimal β β x β β ββββββ΄βββββ΄ββββββββββββββββ΄ββββββββββ΄βββββββββ΄βββββββββββ΄βββββββββββββββββ
Note: Only the essential fields were replicated in the ProductSnapshot for the Sales service. Complementary entities such as Customer, Order, and StockItem will not be detailed here to simplify the documentation.
Creating Events and Their Handlers
To recap, in the previous topic we created the entities Product, Category, and ProductImage in the modular service Catalog.Merchandising, while in the Sales service we created the entity ProductSnapshot.
Now we will create domain events and integration events. The goal is that when products are created or updated in the Catalog service, these changes are replicated to consuming services such as Sales and Stock.
1. Creating Domain Events
The first step is to create the domain events ProductCreated and ProductUpdated using the command:
lino event new
During creation, we can associate the event with a handler and simultaneously configure the triggering of an integration event. This centralizes the creation of the entire necessary flow.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββ β 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 β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ΄βββββββββββββββββββββββββββββββββ
Similarly, we create the ProductUpdated event:
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββ β 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 β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ΄βββββββββββββββββββββββββββββββββ
With this, we have:
- Domain events created (
ProductCreatedandProductUpdated); - Corresponding domain event handlers;
- Integration events automatically registered in the Outbox by the domain event handler.
2. Creating Integration Event Handlers
The next step is to define which services will consume the integration events. For this, we use:
lino event-handler new
The creation flow involves:
- Selecting the service, module, and entity that will contain the handler;
- Selecting the integration event to be consumed and from which service/module/entity it comes.
For example, in the Sales service, we create handlers for ProductCreated and ProductUpdated that will consume the events triggered by 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 β ββββββββββββββββββββββββββββββββββββββββββββββ΄ββββββββββββββββββββ
With this, we have two integration event handlers in the Sales service, consuming only the necessary fields from the integration events of Catalog.Merchandising. This ensures that the replicated tables contain only essential data, optimizing storage and performance.
Generating Web Pages, APIs, Commands, and Queries
One of the major advantages of Lino CLI is the ability to create web pages, APIs, Commands, and Queries in an integrated and automated way, simplifying the entire development workflow. To get started, simply run the command:
lino page new
During the process, you will:
- Select the service, module, and entity you want to expose;
- Choose the fields to include in the listing;
- Automatically generate listing pages (paginated grid) and create/edit forms;
- Generate HttpClient classes for frontend consumption;
- Create all necessary REST APIs (POST, PUT, PATCH, DELETE, and GET);
- Create Commands and Queries with their respective Handlers, interacting with the database to ensure a complete CRUD flow.
With this command, you get a functional application without manually writing the interface layer, APIs, and business logic, maintaining standards and consistency across services.
For this project, we can generate integrated pages for the following entities:
- Catalog.Merchandising.
Category - Catalog.Merchandising.
Product - Sales.
ProductSnapshot
After generating pages, APIs, and Commands/Queries, the application will be ready for full interaction between frontend and backend, with validations, routes, and persistence already configured automatically by Lino CLI.
Creating Database Migrations
Now that all entities have been created, it's time to generate migrations so that the databases are created or updated according to the defined model. Lino CLI automates this process, integrating with Entity Framework and generating ready-to-run scripts.
To create a new migration, run the following command:
lino database migrations new
During execution, you will need to:
- Select the service and module that will receive the migration;
- Provide a description for the migration, for example, "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 β βββββββββββββββββββββββββββββββββββββββββββββ΄ββββββββββββββββββββ
After confirming, Lino CLI will generate:
- A new database migration for the current version of the service;
- A corresponding SQL script, located in the Infrastructure.Persistence layer, at /scripts/<version>/<filename>;
- Recording the migration version in the service history, ensuring traceability and consistency.
Best practices:
- Create new migrations whenever the data model changes (new entities, properties, or relationship modifications);
- Review the generated SQL scripts before applying them in production;
- Keep database versioning aligned with the application version to avoid conflicts and synchronization issues.
By following this workflow, you ensure that the database is always up-to-date and consistent with the domain model defined in Lino CLI, reducing errors and simplifying maintenance.
Generating Docker Images
After completing the code generation for a specific version, performing tests, and implementing all necessary business rules, you can generate Docker images for your project's services and web applications for subsequent publishing to a container registry.
Lino CLI simplifies this process with the command:
lino build
When executed, you will see a list of all available services and web applications in the project along with their current versions:
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|
You can select one or more services and web applications to generate images simultaneously. Simply check the desired items.
Next, you will be prompted to choose how to update the version of the generated images. The available options are:
- Keep current version β does not change the existing version;
- Patch β increments the patch version (e.g., 0.1.0 β 0.1.1);
- Minor β increments the minor version (e.g., 0.1.0 β 0.2.0);
- Major β increments the major version (e.g., 0.1.0 β 1.0.0).
After selecting the services and setting the version increment, Lino CLI will:
- Build the code for each service and web application;
- Generate the corresponding Docker image;
- Apply the tag with the defined version;
- Make the images available for publishing to your container registry.
At the end of the process, assuming all services and web applications were selected, the generated images will have the following structure:
- 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
Note: This process ensures consistency between the code and Docker image versions, facilitates deployment and maintenance across multiple environments, and allows each service to run isolated in independent containers.
Creating Versions in the Application
Incrementing new versions for services or web applications is a simple, centralized process in Lino CLI. Just run the command:
lino version bump
Just like when generating Docker images, running this command will display a complete list of all services and web applications in your project. Only the items you select will have their version incremented, while the others will remain unchanged.
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|
After selecting the desired items, you will be prompted to choose the type of version increment. The available options are:
- Patch β small fixes with no functional impact;
- Minor β adding new features compatible with previous versions;
- Major β changes that may break compatibility with previous versions.
It is important to note that the versions of services and web applications directly affect:
- Docker image tags;
- Folders used to store scripts generated by database migrations;
- Release control and project history.
With this, we conclude the step-by-step guide to all essential commands for building a web project using Lino CLI, from installation, creation of services, entities, events, and pages, to generating Docker images and versioning.
Donβt forget to follow our YouTube channel for detailed tutorials, practical demonstrations, and tips on using the tool, from basic operations to advanced features.
