Background
There is no full-text search abstraction. Modules wanting search currently fall back to LIKE '%term%', which doesn't scale and gives poor UX (no typo tolerance, no ranking, no facets). Laravel Scout abstracts indexing/searching across drivers (Meilisearch, Algolia, Elasticsearch, database).
Motivation
- AuditLogs, Users, Products, PageBuilder — all want fast search
- Avoid coupling each module to a specific engine
- Keep zero-config DX (
Database driver works for tests / tiny apps)
Design sketch
New library framework/SimpleModule.Search + driver packages.
public interface ISearchable
{
string IndexName { get; }
object ToSearchDocument();
}
public interface ISearcher
{
Task IndexAsync<T>(T entity, CancellationToken ct = default) where T : ISearchable;
Task RemoveAsync<T>(T entity, CancellationToken ct = default) where T : ISearchable;
Task<SearchResult<T>> SearchAsync<T>(string query, SearchOptions? opts = null, CancellationToken ct = default) where T : ISearchable;
}
public sealed record SearchOptions(int Page = 1, int PageSize = 20, IDictionary<string, object?>? Filters = null, string[]? Facets = null);
- EF Core
SaveChangesInterceptor auto-indexes/removes when T : ISearchable is changed (queue via BackgroundJobs to keep saves fast)
- Drivers:
SimpleModule.Search.Database (PG full-text / SQLite FTS5), SimpleModule.Search.Meilisearch (HTTP client), follow-up SimpleModule.Search.Algolia
- CLI:
sm search reindex <type> rebuilds an index from scratch
- Per-tenant index isolation (suffix index name with tenant id when multi-tenant)
Acceptance criteria
References
Background
There is no full-text search abstraction. Modules wanting search currently fall back to
LIKE '%term%', which doesn't scale and gives poor UX (no typo tolerance, no ranking, no facets). Laravel Scout abstracts indexing/searching across drivers (Meilisearch, Algolia, Elasticsearch, database).Motivation
Databasedriver works for tests / tiny apps)Design sketch
New library
framework/SimpleModule.Search+ driver packages.SaveChangesInterceptorauto-indexes/removes whenT : ISearchableis changed (queue viaBackgroundJobsto keep saves fast)SimpleModule.Search.Database(PG full-text / SQLite FTS5),SimpleModule.Search.Meilisearch(HTTP client), follow-upSimpleModule.Search.Algoliasm search reindex <type>rebuilds an index from scratchAcceptance criteria
ISearchable+ISearcherinframework/SimpleModule.SearchReferences