Microsserviço consumidor responsável por processar eventos de alteração de preço de voos e notificar usuários por e-mail. Este projeto foi inspirado pelo Search Service do @maxsonferovante, que realiza a busca e monitoramento de preços de passagens aéreas.
O Alert Service atua como um worker assíncrono que consome eventos de mudança de preço publicados no RabbitMQ. Quando detecta que o preço de um voo caiu para o valor esperado pelo usuário, o serviço:
- Recebe eventos
price.updatedda fila RabbitMQ - Valida o payload e converte para entidades de domínio
- Gera links para o Google Flights com os dados do voo
- Busca o e-mail do usuário no banco de dados
- Envia notificação por e-mail via SMTP
O projeto segue os princípios da Clean Architecture (Arquitetura Limpa) e Hexagonal Architecture (Ports & Adapters), garantindo alta testabilidade, baixo acoplamento e independência de frameworks externos.
graph TD
A[Search Service] -->|Publica price.updated| B[RabbitMQ Queue]
B -->|Consume mensagem| C[Worker Consumer]
C -->|Deserializa JSON| D[Handler]
D -->|Converte para domínio| E[ProcessAlert UseCase]
E -->|Busca e-mail| F[PostgreSQL]
E -->|Gera link| G[Google Flights Provider]
E -->|Envia e-mail| H[SMTP Server]
style A fill:#4A90E2,stroke:#333,stroke-width:2px,color:#fff
style B fill:#FF6B6B,stroke:#333,stroke-width:2px,color:#fff
style C fill:#00D8B8,stroke:#333,stroke-width:2px,color:#fff
style E fill:#FFD93D,stroke:#333,stroke-width:2px
style F fill:#6C5CE7,stroke:#333,stroke-width:2px,color:#fff
style H fill:#A29BFE,stroke:#333,stroke-width:2px,color:#fff
Camada central contendo as regras de negócio e entidades puras, sem dependências externas.
internal/domain/
├── alert.go # Entidade principal do alerta de preço
├── alert_email.go # Entidade de e-mail de notificação
└── contract.go # Interfaces (ports) do domínio
Exemplo de Entidade:
type Alert struct {
ID int64
MessageID string
Origin string
Destination string
OutboundDate time.Time
ReturnDate time.Time
NewPrice float64
OldPrice float64
TargetPrice float64
Currency string
CheckedAt time.Time
Link string
}Contratos (Interfaces):
type LinkGenerator interface {
Generate(origin, dest string, out, ret time.Time) string
}
type AlertRepository interface {
GetUserEmail(ctx context.Context, alertID int64) (string, error)
}Orquestração da lógica de negócio através de casos de uso específicos.
internal/usecases/
├── process_alert.go # Caso de uso principal
└── process_alert_test.go # Testes unitários
Responsabilidades:
- Receber alerta do handler
- Gerar link do Google Flights
- Buscar e-mail do usuário
- Enviar notificação por e-mail
Responsável pela comunicação externa: consumo de mensagens e APIs HTTP (quando necessário).
internal/transport/
└── consumer/
├── worker.go # Worker RabbitMQ
├── handler.go # Handler de mensagens
├── payload.go # Estrutura do payload JSON
├── handler_test.go
└── payload_test.go
Exemplo de Payload:
{
"messageId": "abc-123",
"alertId": 42,
"origin": "GRU",
"destination": "JFK",
"outboundDate": "2025-12-15",
"returnDate": "2025-12-20",
"oldPrice": 2500.00,
"newPrice": 1800.00,
"currency": "BRL",
"targetPrice": 2000.00,
"toleranceUp": 100.00,
"checkedAt": "2025-12-02T10:00:00Z"
}Implementações concretas dos adapters (database, cache, SMTP, providers).
internal/infra/
├── cache/
│ └── connection.go # Conexão Redis (preparado para idempotência)
├── database/
│ ├── connection.go # Pool de conexões PostgreSQL
│ ├── repository.go # Implementação do AlertRepository
│ └── repository_test.go
├── messenger/
│ └── connection.go # Conexão RabbitMQ
├── providers/
│ ├── google_flights.go # Gerador de links do Google Flights
│ └── google_flights_test.go
└── smtp/
├── connection.go # Conexão SMTP
└── sender.go # Implementação do envio de e-mails
| Tecnologia | Versão | Uso |
|---|---|---|
| Go | 1.24.3 | Linguagem principal |
| RabbitMQ | 3.x | Mensageria assíncrona |
| PostgreSQL | Alpine | Banco de dados relacional |
| Redis | Alpine | Cache e idempotência (preparado) |
| SMTP | - | Envio de e-mails |
| Docker | - | Containerização |
| pgx | v5 | Driver PostgreSQL nativo |
| amqp091-go | v1.10 | Cliente RabbitMQ oficial |
Crie um arquivo .env na raiz do projeto baseado no .env.example:
# Ambiente
ENV=development
# Database
DATABASE_URL=postgres://admin:admin@localhost:5432/search_service?sslmode=disable
# RabbitMQ
MESSENGER_USERNAME=admin
MESSENGER_PASSWORD=admin
MESSENGER_HOST=localhost
MESSENGER_PORT=5672
QUEUE_NAME=price-alerts
# SMTP (exemplo com Gmail)
SMTP_SERVER=smtp.gmail.com
SMTP_PORT=587
SMTP_USERNAME=seu-email@gmail.com
SMTP_PASSWORD=sua-senha-de-app
# Redis (em desenvolvimento)
CACHE_ADDR=localhost:6379
CACHE_USERNAME=
CACHE_PASSWORD=
CACHE_DB=0O docker-compose.dev.yml sobe as dependências localmente:
docker-compose -f docker-compose.dev.yml up -dServiços disponíveis:
- PostgreSQL:
localhost:5432 - RabbitMQ:
localhost:5672(Management UI:http://localhost:15672) - Redis:
localhost:6379
- Go 1.24+
- Docker e Docker Compose
- Conta SMTP configurada (Gmail, SendGrid, etc.)
git clone https://github.com/Luzin7/alert-service.git
cd alert-servicecp .env.example .env
# Edite o arquivo .env com suas credenciaisdocker-compose -f docker-compose.dev.yml up -dgo mod downloadgo run cmd/worker/main.goVocê verá logs como:
Starting worker on queue: price-alerts
Esperando mensagens na fila price-alerts...
alert-service/
├── cmd/
│ └── worker/
│ └── main.go # Entrypoint do worker
├── internal/
│ ├── domain/ # Entidades e contratos
│ │ ├── alert.go
│ │ ├── alert_email.go
│ │ └── contract.go
│ ├── errors/ # Erros customizados
│ │ └── api_error.go
│ ├── infra/ # Implementações de infraestrutura
│ │ ├── cache/
│ │ │ └── connection.go
│ │ ├── database/
│ │ │ ├── connection.go
│ │ │ ├── repository.go
│ │ │ └── repository_test.go
│ │ ├── messenger/
│ │ │ └── connection.go
│ │ ├── providers/
│ │ │ ├── google_flights.go
│ │ │ └── google_flights_test.go
│ │ └── smtp/
│ │ ├── connection.go
│ │ └── sender.go
│ ├── transport/ # Camada de transporte
│ │ ├── consumer/
│ │ │ ├── handler.go
│ │ │ ├── handler_test.go
│ │ │ ├── payload.go
│ │ │ ├── payload_test.go
│ │ │ └── worker.go
│ │ └── http/
│ │ └── server.go
│ └── usecases/ # Casos de uso
│ ├── process_alert.go
│ └── process_alert_test.go
├── .env.example
├── .gitignore
├── docker-compose.dev.yml
├── go.mod
├── go.sum
└── README.md
go test ./...go test -cover ./...- Payload parsing e conversão para domínio
- Gerador de links do Google Flights
- Repository de alertas (com pgxmock)
- Handler de mensagens
Este serviço foi desenvolvido para trabalhar em conjunto com o Search Service, que realiza:
- Busca de preços de voos em APIs externas
- Monitoramento contínuo de alterações de preço
- Publicação de eventos
price.updatedno RabbitMQ
Fluxo completo:
- Search Service detecta mudança de preço
- Publica evento no RabbitMQ
- Alert Service consome e notifica usuário
- Estrutura básica da Clean Architecture
- Integração com RabbitMQ
- Estrutura para envio de e-mails via SMTP
- Geração de links do Google Flights
- Testes unitários
- Health check HTTP endpoint
- Implementar idempotência com Redis
- Métricas e observabilidade
- CI/CD pipeline