2025-10-16 21:22:51 -07:00
2025-10-16 21:22:51 -07:00
2025-10-16 21:22:51 -07:00
2025-10-16 21:22:51 -07:00
2025-10-16 21:22:51 -07:00
2025-10-16 21:22:51 -07:00
2025-10-16 21:22:51 -07:00
2025-10-16 21:45:17 -07:00
2025-10-16 21:22:51 -07:00
2025-10-16 21:22:51 -07:00
2024-11-01 19:28:32 -07:00
2025-10-16 21:22:51 -07:00
2025-10-16 21:22:51 -07:00
2025-10-16 21:22:51 -07:00

Notifier Microservice

A production-ready notification delivery microservice that supports multiple notification channels (Email, Slack, Ntfy, Stdout) with both REST and gRPC APIs running simultaneously.

Go Version License

Overview

Notifier is a cloud-native microservice designed to handle all your application's notification needs through a single, unified API. Send emails, Slack messages, push notifications, and more with a consistent interface and robust delivery guarantees.

Perfect for:

  • Microservices architectures needing centralized notifications
  • Applications requiring multiple notification channels
  • Systems needing reliable async notification delivery
  • Teams wanting to standardize notification handling

Features

Core Capabilities

  • 🔔 Multi-Channel Support: Email (SMTP), Slack, Ntfy.sh, and Stdout
  • 🚀 Dual API: REST and gRPC running simultaneously in one process
  • 📦 Queue-Based: Async processing with configurable worker pools
  • 🔄 Retry Logic: Exponential backoff with configurable attempts
  • Priority Levels: Low, Normal, High, and Critical
  • 📊 Batch Operations: Send multiple notifications efficiently
  • 🎯 Status Tracking: Monitor notification lifecycle and delivery

Production Features

  • ⚙️ Configuration: Viper-based with environment variable support
  • 🐳 Containerized: Multi-stage Docker builds with non-root user
  • ☸️ Kubernetes Ready: Complete manifests with HPA, health checks, and RBAC
  • 🔒 Secure: Token-based auth for ntfy, TLS support, secret management
  • 📈 Observable: Health endpoints, metrics support, structured logging
  • 🔌 Extensible: Clean interfaces for adding new notifiers

Quick Start

1. Install and Run

# Clone and install dependencies
git clone https://github.com/igodwin/notifier
cd notifier
go mod tidy

# Build and run
go build -o bin/server ./cmd/server
./bin/server

Server starts with:

  • REST API on http://localhost:8080
  • gRPC API on localhost:50051
  • Stdout notifier enabled by default

2. Send Your First Notification

curl -X POST http://localhost:8080/api/v1/notifications \
  -H "Content-Type: application/json" \
  -d '{
    "type": "stdout",
    "subject": "Hello from Notifier!",
    "body": "Your first notification",
    "recipients": ["console"]
  }'

The notification appears immediately in the server output.

3. Check Status

# Health check
curl http://localhost:8080/health

# Statistics
curl http://localhost:8080/api/v1/stats

Configuration

Basic Setup

Create config.yaml in the project root:

server:
  mode: "both"        # Options: both, rest, grpc
  rest_port: 8080
  grpc_port: 50051
  host: "0.0.0.0"

queue:
  type: "local"       # Local in-memory queue
  worker_count: 10    # Concurrent workers
  retry_attempts: 3
  retry_backoff: "exponential"

notifiers:
  stdout: true        # Always enabled for testing

Email Notifications (SMTP)

notifiers:
  smtp:
    host: "smtp.gmail.com"
    port: 587
    username: "your-email@gmail.com"
    password: "your-app-password"
    from: "notifications@yourservice.com"
    use_tls: true

Usage:

curl -X POST http://localhost:8080/api/v1/notifications \
  -H "Content-Type: application/json" \
  -d '{
    "type": "email",
    "subject": "Welcome!",
    "body": "Thanks for signing up",
    "recipients": ["user@example.com"]
  }'

Slack Notifications

notifiers:
  slack:
    webhook_url: "https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
    username: "Notifier Bot"
    icon_emoji: ":bell:"

Usage:

curl -X POST http://localhost:8080/api/v1/notifications \
  -H "Content-Type: application/json" \
  -d '{
    "type": "slack",
    "subject": "Deployment Complete",
    "body": "v2.0 deployed to production",
    "recipients": ["#alerts"]
  }'

Ntfy Push Notifications

notifiers:
  ntfy:
    server_url: "https://ntfy.sh"
    token: "tk_your_access_token"    # Optional, for private topics
    default_topic: "myapp-alerts"

Usage:

curl -X POST http://localhost:8080/api/v1/notifications \
  -H "Content-Type: application/json" \
  -d '{
    "type": "ntfy",
    "priority": 3,
    "subject": "Critical Alert",
    "body": "Server CPU at 95%",
    "recipients": ["alerts"],
    "metadata": {
      "tags": ["warning", "rotating_light"],
      "click": "https://dashboard.example.com"
    }
  }'

See docs/NTFY_GUIDE.md for advanced ntfy features (action buttons, attachments, delays, etc.).

Environment Variables

Override any config with environment variables:

export NOTIFIER_SERVER_MODE=both
export NOTIFIER_SERVER_REST_PORT=8080
export NOTIFIER_QUEUE_WORKER_COUNT=20
export NOTIFIER_NOTIFIERS_SMTP_HOST=smtp.gmail.com
export NOTIFIER_NOTIFIERS_SMTP_PASSWORD=secret
export NOTIFIER_NOTIFIERS_NTFY_TOKEN=tk_your_token

Format: NOTIFIER_<SECTION>_<KEY> (use _ for nested keys)

API Reference

REST Endpoints

Method Endpoint Description
GET /health Health check
POST /api/v1/notifications Send single notification
POST /api/v1/notifications/batch Send multiple notifications
GET /api/v1/notifications List notifications (with filters)
GET /api/v1/notifications/{id} Get notification by ID
DELETE /api/v1/notifications/{id} Cancel pending notification
POST /api/v1/notifications/{id}/retry Retry failed notification
GET /api/v1/stats Get service statistics

Request Format

{
  "type": "email|slack|ntfy|stdout",
  "priority": 0-3,
  "subject": "Notification title",
  "body": "Notification body",
  "recipients": ["email@example.com", "#channel", "topic"],
  "metadata": {
    "key": "value"
  },
  "max_retries": 3
}

Response Format

{
  "result": {
    "notification_id": "uuid",
    "success": true,
    "message": "notification queued successfully",
    "sent_at": "2025-10-16T21:05:27Z"
  }
}

Priority Levels

  • 0 - Low (background notifications)
  • 1 - Normal (default)
  • 2 - High (important updates)
  • 3 - Critical (urgent alerts)

Batch Operations

curl -X POST http://localhost:8080/api/v1/notifications/batch \
  -H "Content-Type: application/json" \
  -d '{
    "notifications": [
      {"type": "email", "subject": "Welcome", ...},
      {"type": "slack", "subject": "Alert", ...}
    ]
  }'

Filtering Notifications

# Get all sent email notifications
curl "http://localhost:8080/api/v1/notifications?type=email&status=sent&limit=10"

# Get recent failures
curl "http://localhost:8080/api/v1/notifications?status=failed&limit=20"

gRPC API

The gRPC service mirrors the REST API with full feature parity. See api/grpc/notifier.proto for definitions.

Generate Go code:

make proto-gen
# or
protoc --go_out=. --go-grpc_out=. api/grpc/notifier.proto

Note: gRPC server is running but handler implementation is pending. Protobuf definitions are complete.

Deployment

Docker

Build:

docker build -t notifier:latest .

Run:

docker run -d \
  --name notifier \
  -p 8080:8080 \
  -p 50051:50051 \
  -v $(pwd)/config.yaml:/app/config.yaml:ro \
  notifier:latest

Docker Compose:

docker-compose up -d

Includes optional services: Kafka, Prometheus, Grafana (commented out by default)

Kubernetes

Deploy:

kubectl apply -f k8s/

Included resources:

  • Deployment (3 replicas with rolling updates)
  • Services (separate for REST and gRPC)
  • ConfigMap (configuration management)
  • HPA (auto-scaling 3-10 pods based on CPU/memory)
  • Ingress (external access with TLS)
  • Secret template (for credentials)

Access locally:

kubectl port-forward svc/notifier-rest 8080:8080
kubectl port-forward svc/notifier-grpc 50051:50051

Using Kustomize:

kubectl apply -k k8s/

Architecture

High-Level Design

┌──────────────┐     ┌──────────────┐
│ REST Client  │────▶│  REST API    │
└──────────────┘     │  (port 8080) │
                     └──────┬───────┘
┌──────────────┐            │
│ gRPC Client  │────▶│  gRPC API    │
└──────────────┘     │ (port 50051) │
                     └──────┬───────┘
                            ▼
                  ┌──────────────────┐
                  │ Notification     │
                  │ Service          │
                  └────────┬─────────┘
                           ▼
                  ┌──────────────────┐
                  │ Queue (Local)    │◀──┐
                  └────────┬─────────┘   │
                           ▼              │
                  ┌──────────────────┐   │
                  │ Worker Pool      │───┘
                  │ (10 workers)     │
                  └────────┬─────────┘
                           ▼
        ┌─────────────────┼─────────────────┐
        ▼                 ▼                 ▼
   ┌────────┐       ┌──────────┐     ┌──────────┐
   │ SMTP   │       │  Slack   │     │   Ntfy   │
   │Notifier│       │ Notifier │     │ Notifier │
   └────────┘       └──────────┘     └──────────┘

Key Components

  • API Layer: REST (Gorilla mux) and gRPC (Protocol Buffers)
  • Service Layer: Business logic, validation, orchestration
  • Queue: In-memory with optional disk persistence (Kafka planned)
  • Workers: Concurrent processors with retry logic
  • Notifiers: Pluggable providers implementing domain.Notifier
  • Config: Viper-based with file + env var support

See ARCHITECTURE.md for detailed design documentation.

Project Structure

notifier/
├── api/
│   ├── grpc/
│   │   └── notifier.proto          # gRPC service definition
│   └── rest/
│       ├── handlers.go              # HTTP handlers
│       ├── router.go                # Route configuration
│       └── types.go                 # Request/response types
├── cmd/
│   ├── server/main.go              # Combined server (recommended)
│   ├── grpcserver/main.go          # gRPC only
│   └── restserver/main.go          # REST only
├── internal/
│   ├── config/
│   │   └── config.go               # Configuration management
│   ├── domain/
│   │   ├── notification.go         # Core types
│   │   ├── notifier.go            # Notifier interface
│   │   └── queue.go               # Queue interface
│   ├── notifier/
│   │   ├── notifier.go            # Factory & base
│   │   ├── smtp.go                # Email notifier
│   │   ├── slack.go               # Slack notifier
│   │   ├── ntfy.go                # Ntfy notifier
│   │   └── stdout.go              # Stdout notifier
│   ├── queue/
│   │   └── local.go               # In-memory queue
│   └── service/
│       └── service.go             # Business logic
├── k8s/
│   ├── deployment.yaml
│   ├── service.yaml
│   ├── configmap.yaml
│   ├── ingress.yaml
│   ├── hpa.yaml
│   └── kustomization.yaml
├── docs/
│   └── NTFY_GUIDE.md              # Ntfy integration guide
├── config.yaml                     # Default configuration
├── docker-compose.yaml
├── Dockerfile
├── Makefile
├── QUICKSTART.md                   # API examples
├── ARCHITECTURE.md                 # Design documentation
└── README.md                       # This file

Development

Build Commands

make build          # Build binaries
make run-rest       # Run REST server
make run-grpc       # Run gRPC server (when implemented)
make test           # Run tests
make lint           # Run linter
make proto-gen      # Generate protobuf code
make docker-build   # Build Docker image
make clean          # Clean artifacts

Adding a New Notifier

  1. Create internal/notifier/mynotifier.go
  2. Implement domain.Notifier interface
  3. Add config struct to internal/config/config.go
  4. Register in cmd/server/main.go
  5. Update config.yaml with example config
  6. Add tests

Example:

type MyNotifier struct {
    BaseNotifier
    config *MyNotifierConfig
}

func (m *MyNotifier) Send(ctx context.Context, n *domain.Notification) (*domain.NotificationResult, error) {
    // Implementation
}

See ARCHITECTURE.md for detailed guide.

Documentation

Testing

# Run all tests
go test ./...

# Run with coverage
go test -cover ./...

# Run specific package
go test ./internal/notifier/...

Current Status: Core implementation complete, tests pending.

Monitoring & Operations

Health Checks

curl http://localhost:8080/health

Returns:

{
  "status": "healthy",
  "service": "notifier",
  "time": "2025-10-16T21:05:27Z"
}

Statistics

curl http://localhost:8080/api/v1/stats

Returns:

{
  "total_sent": 1234,
  "total_failed": 5,
  "total_pending": 0,
  "total_queued": 2,
  "by_type": {
    "email": 800,
    "slack": 400,
    "ntfy": 34
  },
  "by_status": {
    "sent": 1234,
    "failed": 5
  }
}

Graceful Shutdown

The server handles SIGINT and SIGTERM gracefully:

  • Stops accepting new requests
  • Completes in-flight notifications
  • Drains the queue
  • Closes all connections
  • 30-second timeout

Roadmap

Completed

  • Core notification system
  • REST API (fully functional)
  • gRPC API (protobuf defined)
  • Local queue with workers
  • Multiple notifiers (SMTP, Slack, Ntfy, Stdout)
  • Priority and retry logic
  • Batch operations
  • Docker support
  • Kubernetes manifests with HPA
  • Health checks and stats
  • Configuration management

Planned 🚧

  • gRPC handler implementation
  • Kafka queue adapter
  • Database persistence (PostgreSQL)
  • Notification templates
  • Webhook callbacks
  • Authentication/Authorization (API keys, OAuth)
  • Rate limiting (per client, per notifier)
  • Prometheus metrics
  • OpenTelemetry tracing
  • Comprehensive test suite
  • Circuit breakers for notifiers
  • Dead letter queue
  • Admin dashboard

Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Write tests for your changes
  4. Ensure tests pass (go test ./...)
  5. Commit your changes (git commit -m 'Add amazing feature')
  6. Push to the branch (git push origin feature/amazing-feature)
  7. Open a Pull Request

Please follow Go best practices and maintain test coverage.

Security

Reporting Vulnerabilities

Please report security vulnerabilities privately via GitHub Security Advisories.

Best Practices

  • Store credentials in environment variables or secrets managers
  • Use TLS for production deployments
  • Enable authentication for ntfy private topics
  • Rotate tokens regularly
  • Follow principle of least privilege for K8s RBAC
  • Keep dependencies updated

License

This project is licensed under the MIT License - see LICENSE for details.

Support & Community

Acknowledgments

Built with:


Made with ❤️ for reliable notifications

S
Description
A modular, extensible notifier project supporting multiple notification modes
Readme MIT 22 MiB
Languages
Go 97.3%
Makefile 2.2%
Dockerfile 0.5%