Skip to content

Global Search

Integration

Services integrate with Global Search through the GlobalSearchClientModule.

A service should implement this integration when it owns entities that need to be searchable from the shared Global Search feature.

The integration model is based on document maps:

  • the source service chooses which entities participate in Global Search
  • a document map defines how a source entity is transformed into a search document
  • the document map also defines which event triggers reindexing for that entity
  • the source service registers that map in its module configuration through the client module API

What the service must provide

To integrate an entity with Global Search, the service must provide:

  1. The source entity
    The domain or read-model entity that will be indexed.

  2. The triggering event
    The event that indicates the searchable representation should be created or updated.

  3. A document map
    A class that defines:

  4. how to extract the indexed document identifier
  5. how to extract the event identifier used to locate the entity
  6. how to shape the indexed payload
  7. which related data must be eagerly loaded before building the payload

  8. Module registration
    The module must register the document map through GlobalSearchClientModuleOptions.

Responsibilities

The source service is responsible for:

  • deciding which entities should be searchable
  • choosing which events should trigger reindexing
  • shaping a search-oriented payload
  • including any related data needed to build the search document

Global Search is responsible for:

  • receiving the indexing request
  • upserting the document into the appropriate search index
  • exposing search and autocomplete capabilities for consumers

Design guidance

The payload returned by the document map should be a search document, not a raw persistence model.

That means it should contain the fields that are useful for search scenarios, such as:

  • identifiers
  • names, codes, and descriptions
  • lightweight related data needed for matching or display

Avoid sending data that is:

  • large but not searchable
  • sensitive and not intended for discovery
  • shaped only for persistence concerns

Integration Example

The example below shows how a service can make WorkOrder searchable.

1. Source entity and event

C#
public class WorkOrder : ICorrelatedEntity
{
    public Guid CorrelationId { get; set; }

    public string Code { get; set; }

    public string Description { get; set; }

    public ICollection<OrderLine> Lines { get; set; } = new List<OrderLine>();
}

public class OrderLine : ICorrelatedEntity
{
    public Guid CorrelationId { get; set; }

    public int TotalPrice { get; set; }

    public WorkOrder Order { get; set; }
}

public record WorkOrderUpdated
{
    public Guid CorrelationId { get; set; }
}

In this case:

  • WorkOrder is the entity that should appear in Global Search
  • WorkOrderUpdated is the event that triggers reindexing

2. Document map

C#
public class WorkOrderDocumentMap : DocumentMap<WorkOrder, WorkOrderUpdated>
{
    public override object GetPayload(WorkOrder entity)
    {
        return new
        {
            entity.CorrelationId,
            entity.Code,
            entity.Description,
            entity.Lines
        };
    }

    public override Guid GetId(WorkOrder entity)
    {
        return entity.CorrelationId;
    }

    public override Guid GetEventIdField(WorkOrderUpdated @event)
    {
        return @event.CorrelationId;
    }

    public override IncludeSpecification<WorkOrder>[] UseIncludes()
    {
        return
        [
            new WorkOrderWithLinesIncludeSpecification()
        ];
    }
}

This map defines the integration contract for WorkOrder:

  • GetPayload shapes the document that will be indexed
  • GetId returns the document identifier used in Global Search
  • GetEventIdField extracts the entity identifier from the triggering event
  • UseIncludes ensures related data is loaded before the payload is built

3. Module registration

C#
public class WorkOrdersModule : SuiteModule
{
    public override void SetupModule(IModuleBuilder builder)
    {
        base.SetupModule(builder);

        // other module dependencies

        builder.DependsOn<GlobalSearchClientModule, GlobalSearchClientModuleOptions>(opts =>
        {
            opts.AddDocumentMap<WorkOrder, WorkOrderUpdated, WorkOrderDocumentMap>();
        });
    }
}

How to read this example

Using the previous example, the indexing flow is:

  1. A WorkOrder is updated in the owning service.
  2. The service publishes WorkOrderUpdated.
  3. The Global Search client integration handles that event.
  4. The configured WorkOrderDocumentMap is used to:
  5. locate the affected WorkOrder
  6. load the required related data
  7. build the payload to index
  8. The resulting search document is sent to Global Search and upserted into the search index.

This keeps the integration declarative: the service only needs to register the map, and the client module uses that configuration to drive indexing.

Practical notes

Keep payloads search-oriented

In the WorkOrder example, including Lines may be acceptable if line data is intentionally searchable or needed in the result payload.

However, services should avoid treating the payload as a raw entity dump. A better payload is usually one that contains only the fields needed for:

  • matching
  • ranking
  • rendering the search result

If the search document depends on navigation properties or related entities, those dependencies should be declared through UseIncludes() so the map can build a complete and consistent payload.