Skip to content

abeb021/Weather-Alert-Service

Repository files navigation

Weather Alert Service

Microservices-based weather alert system. Users register, create alert rules based on weather conditions, and receive email notifications when conditions are met.

Architecture

graph LR
    Client(["👤 Client"])

    subgraph GW["NGINX :80"]
        NGINX["auth_request\n+ X-User-ID"]
    end

    subgraph SVC["Microservices"]
        direction TB
        AUTH["auth-service :8001\nJWT · bcrypt · refresh"]
        WEATHER["weather-service :8002\nOpenWeatherMap · cache"]
        ALERT["alert-service :8003\nCRUD · worker"]
        NOTIFY["notification-service :8004\nKafka · SMTP"]
    end

    subgraph DATA["Storage"]
        direction TB
        AUTH_DB[("auth-db")]
        REDIS[("Redis")]
        ALERT_DB[("alert-db")]
    end

    KAFKA[["Kafka"]]
    OWM(["OpenWeatherMap"])
    Email(["📧 Email"])

    Client --> NGINX
    NGINX --> AUTH
    NGINX --> WEATHER
    NGINX --> ALERT

    AUTH --- AUTH_DB
    WEATHER --- REDIS
    WEATHER --- OWM
    ALERT --- ALERT_DB
    ALERT -->|"alert.triggered"| KAFKA
    KAFKA --> NOTIFY
    NOTIFY --> Email
Loading

Auth flow

sequenceDiagram
    participant C as Client
    participant N as NGINX
    participant A as auth-service
    participant S as weather/alert-service

    C->>N: GET /api/weather/current [Bearer token]
    N->>A: GET /api/auth/validate (internal)
    alt valid token
        A-->>N: 200 OK + X-User-ID
        N->>S: GET /api/weather/current [X-User-ID]
        S-->>C: 200 OK
    else invalid token
        A-->>N: 401 Unauthorized
        N-->>C: 401 Unauthorized
    end
Loading

Alert checker (background worker)

flowchart LR
    T(["⏱ every 15 min"])
    --> Q["ListActive()\nactive=true\nlast_triggered > 1h ago"]
    --> G["group by city"]
    --> W["FetchCurrent(city)\nweather-service"]
    --> CHK{"condition\nmet?"}

    CHK -->|no| T
    CHK -->|yes| K["Kafka\nalert.triggered"]
    --> M["MarkTriggered()\nlast_triggered = NOW()"]
    --> T
Loading

Services

Service Port DB Responsibilities
auth-service 8001 PostgreSQL Registration, login, JWT issue/validate, refresh token rotation
weather-service 8002 Redis (cache) Fetch current weather and forecast from OpenWeatherMap
alert-service 8003 PostgreSQL Alert CRUD, background condition checker, Kafka producer
notification-service 8004 Kafka consumer, SMTP email sender

API

Full spec: docs/openapi.yaml

Public endpoints (no auth)

Method Path Description
POST /api/auth/register Register, returns token pair
POST /api/auth/login Login, returns token pair
POST /api/auth/refresh Rotate refresh token

Protected endpoints (Bearer token required)

Method Path Description
GET /api/weather/current?city=London Current weather
GET /api/weather/forecast?city=London 5-day forecast
POST /api/alerts Create alert rule
GET /api/alerts List your alerts
GET /api/alerts/{id} Get alert by ID
PUT /api/alerts/{id} Update alert (partial)
DELETE /api/alerts/{id} Delete alert

Alert condition types

Type Description Threshold
temp_above Temperature exceeds threshold °C
temp_below Temperature drops below threshold °C
wind_above Wind speed exceeds threshold m/s
rain Condition is Rain or Drizzle ignored
snow Condition is Snow ignored

Error responses

All errors follow RFC 9457 (application/problem+json):

{
  "type": "about:blank",
  "title": "Not Found",
  "status": 404,
  "detail": "Alert not found.",
  "instance": "/api/alerts/873cd8e5-c2b8-417d-93db-7b4d42d90b33"
}

Quick start

# 1. Copy and fill environment file
cp infrastructure/.env.example .env
# Set: OPENWEATHER_API_KEY, JWT_SECRET, SMTP_* credentials

# 2. Start all services
cd infrastructure && docker-compose up -d --build

# 3. Run end-to-end tests
./scripts/test.sh

Kubernetes / minikube

Kubernetes manifests are stored in k8s/. They run the same application in the weather-app namespace: frontend, API gateway, Go services, PostgreSQL databases with PVCs, Redis, and Kafka.

For minikube with local images:

# Start minikube and build service images inside its Docker daemon
minikube start
eval $(minikube docker-env)

docker build -t weather-api-gateway:local ./api-gateway
docker build -t weather-frontend:local ./frontend
docker build -t weather-auth-service:local ./services/auth-service
docker build -t weather-weather-service:local ./services/weather-service
docker build -t weather-alert-service:local ./services/alert-service
docker build -t weather-notification-service:local ./services/notification-service

# Create namespace and secrets from the root .env file
kubectl apply -f k8s/namespace.yaml
kubectl create secret generic weather-secrets --from-env-file=.env -n weather-app

# Deploy everything
kubectl apply -f k8s/
kubectl get pods -n weather-app
kubectl get svc -n weather-app

The public entry point is api-gateway. For local browser access:

kubectl port-forward -n weather-app svc/api-gateway 8080:80

Then open http://localhost:8080. The frontend service itself is ClusterIP, so direct localhost:3000 access is only for temporary debugging and bypasses the gateway.

Useful checks:

kubectl get pods -n weather-app -l app=weather-service
kubectl get endpoints weather-service -n weather-app
kubectl logs -n weather-app -l app=api-gateway
kubectl logs -n weather-app -l app=auth-service

To stop the Kubernetes stack:

kubectl delete namespace weather-app
minikube stop

Environment variables

Variable Service Default Description
SERVER_ADDR auth :8001 Listen address
WEATHER_SERVICE_ADDR weather :8002 Listen address
ALERT_SERVICE_ADDR alert :8003 Listen address
GRACEFUL_SHUTDOWN_TIMEOUT all 10s Graceful shutdown timeout
JWT_SECRET auth Required. Shared with no other service (NGINX validates via auth-service)
JWT_ACCESS_TTL auth 1h Access token lifetime
BCRYPT_COST auth 12 bcrypt cost factor
USER_DB_URL auth PostgreSQL DSN for users
TOKEN_DB_URL auth PostgreSQL DSN for refresh tokens
OPENWEATHER_API_KEY weather Required
REDIS_URL weather redis:6379 Redis address (host:port)
DB_URL alert PostgreSQL DSN
WEATHER_SERVICE_URL alert http://weather-service:8002 Internal URL to weather-service
KAFKA_BROKER alert kafka:9092 Kafka broker address
ALERT_CHECK_INTERVAL alert 15m How often the checker runs
SMTP_HOST notification SMTP server hostname
SMTP_PORT notification 587 587 = STARTTLS, 465 = implicit TLS
SMTP_USERNAME notification SMTP login
SMTP_PASSWORD notification SMTP password
SMTP_FROM notification From address
SMTP_USE_TLS notification false Set true for port 465

Tech stack

Category Technology
Language Go 1.26, standard net/http
API Gateway NGINX (reverse proxy, JWT validation via auth_request)
Auth JWT (HS256) + bcrypt + opaque refresh tokens
Databases PostgreSQL (auth, alert), Redis (weather cache)
Messaging Apache Kafka
Notifications SMTP email
Containerization Docker, Docker Compose
Monitoring Prometheus (/metrics on each service)
External API OpenWeatherMap
Error format RFC 9457 Problem Details

Project structure

Weather-Alert-Service/
├── api-gateway/
│   ├── nginx.conf
│   └── conf.d/api-routes.conf
├── services/
│   ├── auth-service/
│   │   ├── cmd/main.go
│   │   ├── config/config.go
│   │   └── internal/
│   │       ├── api/handlers/     (auth, validate, health, response)
│   │       ├── api/middleware/   (logger, auth, problem)
│   │       ├── domain/           (models, errors)
│   │       ├── repository/       (postgres, migrations)
│   │       ├── service/
│   │       └── utils/            (jwt, bcrypt)
│   ├── weather-service/
│   │   ├── cmd/main.go
│   │   └── internal/
│   │       ├── api/handlers/
│   │       ├── api/middleware/
│   │       ├── cache/redis/
│   │       ├── clients/openweather/
│   │       └── domain/
│   ├── alert-service/
│   │   ├── cmd/main.go
│   │   └── internal/
│   │       ├── api/handlers/     (CRUD)
│   │       ├── api/middleware/   (logger, user_id, problem)
│   │       ├── clients/weather/  (internal HTTP client — worker only)
│   │       ├── domain/
│   │       ├── kafka/            (producer)
│   │       ├── repository/       (postgres, migrations)
│   │       ├── service/
│   │       └── worker/           (background checker)
│   └── notification-service/
│       ├── cmd/main.go
│       └── internal/
│           ├── client/smtp/
│           ├── consumer/kafka/
│           ├── domain/
│           └── service/
├── docs/
│   └── openapi.yaml
├── infrastructure/
│   ├── docker-compose.yml
│   └── .env.example
├── k8s/
│   ├── namespace.yaml
│   ├── api-gateway.yaml
│   ├── frontend.yaml
│   ├── auth-service.yaml
│   ├── weather-service.yaml
│   ├── alert-service.yaml
│   ├── notification-service.yaml
│   ├── auth-db.yaml
│   ├── alert-db.yaml
│   ├── redis.yaml
│   └── kafka.yaml
├── monitoring/
│   └── prometheus/prometheus.yml
└── scripts/
    ├── init-kafka-topics.sh
    └── test.sh

Testing

# End-to-end (requires running stack)
./scripts/test.sh

# Individual service build check
cd services/auth-service && go build ./...
cd services/weather-service && go build ./...
cd services/alert-service && go build ./...
cd services/notification-service && go build ./...

About

Microservices-based weather alert system. Users register, create alert rules based on weather conditions, and receive email notifications when conditions are met.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors