# Search Module Publishes content indexing events to **Heimdall** — the Humand universal search service. This module is write-only: it sends CREATE, UPDATE, and DELETE messages to Heimdall's SQS FIFO queue. Search queries are handled directly by the Heimdall REST API from the client. **Heimdall repo:** `humand-heimdall` (`~/Documents/humand-heimdall`) **Client package:** `@humand/heimdall-client` (published to CodeArtifact, source at `humand-heimdall/client/sqs-typescript`) **Queue:** `humand-heimdall-service-content.fifo` — URL injected via `AWS_SQS_HEIMDALL_CONTENT_QUEUE_URL` ## Directory Structure ``` search/ ├── business/ │ ├── ports/ │ │ └── searchRepositoryPort.ts # Abstract port: indexDocument(message) │ └── services/ │ └── searchService.ts # create / update / delete / toAudienceQuery ├── infrastructure/ │ └── adapters/ │ └── searchAdapter.ts # Wraps ContentIndexClient, reads region + queue URL from env └── searchPortsDI.ts # Registers SearchRepositoryPort → SearchAdapter ``` ## SearchService The only service to inject into other modules. Four methods: | Method | Description | |--------|-------------| | `create(document)` | Sends a CREATE message to Heimdall | | `update(document)` | Sends an UPDATE message | | `delete(document)` | Sends a DELETE message — only `id`, `instanceId`, and `module` are required | | `toAudienceQuery(segmentable)` | Converts a `Segmentable` domain object into a `SegmentationExpressionConfig` for the `audienceQuery` field. Returns `undefined` if the object has no segmentations. | `toAudienceQuery` groups segmentations by `groupId` and builds an AND block over groups (OR within each group), matching the semantics Heimdall uses for percolation. ## ContentIndexDocument fields Built by the caller before passing to `create` / `update`. Key fields: | Field | Notes | |-------|-------| | `id` | String — use `String(entity.id)` | | `instanceId` | Company ID | | `module` | Use `ContentModule.*` const — never hardcode | | `permissionType` | Use `PermissionType.*` const | | `requiredPermission` | `string[]` — e.g. `[GenerallyAvailableInstanceCapabilityNames.VIEW_POSTS.toString()]` | | `audienceQuery` | Only set when `permissionType === PermissionType.AUDIENCE` — use `searchService.toAudienceQuery(entity)` | | `allowedEntityIds` | Group IDs — only for `MEMBERSHIP` type | `ContentIndexAction`, `ContentModule`, `PermissionType`, and `LogicalOperator` are exported as const objects from `@humand/heimdall-client` — use dot-access (`ContentModule.FEED`), never hardcode strings. ## Adding a new module to search 1. Inject `SearchService` into the relevant service (e.g. `ArticlesNotificationService`). 2. Build a `ContentIndexDocument` in a private helper (follow `postToSearchDocument` in `postsNotificationService.ts` as reference). 3. Call `searchService.create` / `update` / `delete` at the appropriate lifecycle points. 4. Add `sqs:SendMessage` on the Heimdall queue ARN to the caller's IAM policy in `infrastructure/modules/services/`. ## Env vars | Variable | Mapped key | |----------|-----------| | `AWS_SQS_HEIMDALL_CONTENT_QUEUE_URL` | `awsSqsHeimdallContentQueueUrl` | Defined in `humand-packages/common/src/infrastructure/config/variables.ts`. The value is resolved at deploy time via a `data "aws_sqs_queue"` Terraform data source (queue name `humand-heimdall-service-content.fifo`) and injected as an ECS environment variable in each service's `main.tf`. The IAM policy (`sqs:SendMessage` on the queue ARN) is defined in each service's `iam.tf`.