8af25def83
New search module: a message index (Meilisearch, MEILI_URL-gated; no-op when unset), a SearchProjector that indexes on message.sent, and a SearchService whose permission fence runs server-side — a query only touches the caller's own scope AND the threads they currently belong to (resolved live from participant rows, so membership changes reflect immediately). Every conversation kind (chat/mail/sms) is a message with a TEXT part, so all are searchable through one index. POST /v1/search + /reindex (backfill). 5 fence tests green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
25 lines
951 B
TypeScript
25 lines
951 B
TypeScript
import { Module } from '@nestjs/common';
|
|
import { OutboxModule } from '../outbox/outbox.module';
|
|
import { SearchService } from './search.service';
|
|
import { SearchProjector } from './search.projector';
|
|
import { SearchController } from './search.controller';
|
|
import { MESSAGE_SEARCH_PORT } from './message-search.port';
|
|
import { messageSearchFromEnv } from './meili.adapter';
|
|
|
|
/**
|
|
* Message search (Meilisearch). The engine binds from MEILI_URL; unset → a no-op port so search
|
|
* returns empty rather than erroring. The projector indexes on `message.sent`; the service enforces
|
|
* the permission fence (scope + caller's threads). SessionVerifier + ActorResolver are global.
|
|
*/
|
|
@Module({
|
|
imports: [OutboxModule],
|
|
controllers: [SearchController],
|
|
providers: [
|
|
SearchService,
|
|
SearchProjector,
|
|
{ provide: MESSAGE_SEARCH_PORT, useFactory: () => messageSearchFromEnv() },
|
|
],
|
|
exports: [SearchService],
|
|
})
|
|
export class SearchModule {}
|