Appearance
Busca Full-Text (Scout + Typesense)
Visao Geral
O sistema usa Laravel Scout com Typesense como engine de busca full-text. Cada tenant tem collections isoladas no Typesense com prefixo do tenant ID (ex: alfa_members, beta_transactions).
Models Pesquisaveis
| Model | Collection | Campos de busca | Filtros facetados |
|---|---|---|---|
| Member | {tenant}_members | nome, sobrenome, email, cpf | sexo, situacao, congregacao, congregacao_id |
| Transaction | {tenant}_transactions | descricao, observacao | tipo, status, categoria, categoria_id, valor, data_transacao |
| Event | {tenant}_events | titulo, descricao, local | tipo, status, congregacao_id, data_inicio |
TenantSearchable Trait
App\Domain\Shared\Traits\TenantSearchable — encapsula o Searchable do Scout com prefixo tenant no searchableAs().
Cada model pesquisavel usa este trait e implementa toSearchableArray() com os campos indexados.
Busca nos Controllers
Os controllers usam um padrao de fallback:
- Se ha termo de busca E o tenant tem a feature
full_text_search→ usa Scout - Se Scout falha (Typesense indisponivel) → cai no Eloquent automaticamente
- Sem feature ou sem termo → usa Eloquent diretamente
Controllers com busca: MemberController, TransactionController, EventController.
Feature Flag
full_text_search — disponivel nos planos Crescimento e Expansao. Plano Semente usa busca Eloquent (LIKE).
Typesense (Docker)
Servico typesense no docker-compose.yml:
- Imagem:
typesense/typesense:27.1 - Porta:
8108 - Volume:
./typesense_data:/data - Health:
curl http://localhost:8108/health
Variaveis de Ambiente
env
SCOUT_DRIVER=typesense
SCOUT_QUEUE=true
TYPESENSE_API_KEY=igreja-typesense-key
TYPESENSE_HOST=typesense
TYPESENSE_PORT=8108
TYPESENSE_PROTOCOL=httpComandos
bash
# Reindexar todos os tenants
docker compose exec app php artisan app:reindex-search
# Reindexar um tenant especifico
docker compose exec app php artisan app:reindex-search --tenant=alfaConfiguracao
Schemas dos models em config/scout.php → typesense.model-settings. Queue configurada como scout para nao competir com jobs de alta prioridade.
Testes
Testes usam SCOUT_DRIVER=collection (definido em phpunit.xml). Nao requer Typesense no CI.
Busca Global (Spotlight / Cmd+K)
Backend
Rota: GET /search?q={query} — qualquer usuário autenticado.
Controller: GlobalSearchController@search — busca em 3 models (Member, Transaction, Event) com o mesmo padrão Scout + fallback Eloquent. Retorna JSON agrupado por tipo, max 5 resultados por tipo.
json
{
"members": [{ "ulid": "...", "label": "João Silva", "sublabel": "Congregação Central", "url": "/members/..." }],
"transactions": [{ "ulid": "...", "label": "Dízimo Janeiro", "sublabel": "R$ 500,00 — Receita", "url": "/transactions/..." }],
"events": [{ "ulid": "...", "label": "Culto Especial", "sublabel": "15/03/2026 — Igreja Central", "url": "/events/..." }]
}Frontend
Componente: SpotlightSearch.vue — modal global ativado por Cmd+K (Mac) / Ctrl+K (Windows) ou botão no header.
- Debounce 300ms, mínimo 2 caracteres
- Resultados agrupados por seção com ícones (User, DollarSign, Calendar)
- Navegação por teclado (↑↓ Enter Esc)
- PrimeVue Dialog (unstyled) como container