A robust and scalable distributed notification system designed to deliver timely and personalized communications across multiple channels. This project employs a microservices architecture, leveraging Node.js, Python, and Java, orchestrating various components for efficient message processing, templating, user management, and API gateway functionality.
- ✨ Polyglot Microservices: Seamless integration of services built with Node.js (NestJS), Python (FastAPI), and Java (Spring Boot) for specialized tasks.
- 🚀 Asynchronous Messaging: Utilizes RabbitMQ for reliable, asynchronous message queuing to decouple services and ensure high throughput.
- 💾 Persistent Data Storage: Employs PostgreSQL for robust user and template data management.
- ⚡ High-Performance Caching: Integrates Redis for caching, rate limiting, and temporary storage of notification statuses and idempotency keys.
- 🛡️ Resilient API Gateway: A central API gateway handles authentication (JWT), request routing, rate limiting, and implements a circuit breaker pattern for enhanced fault tolerance.
- 📧 Multi-Channel Delivery: Supports both email and push notifications, with dedicated services for each channel (SendGrid and Firebase Cloud Messaging).
- 🎨 Dynamic Templating: A dedicated template service allows for the creation and dynamic rendering of notification content with user-specific variables.
- 🔒 Secure Authentication: JWT-based authentication ensures secure access to user data and notification functionalities.
- 🐳 Containerized Deployment: Docker and Docker Compose enable easy setup, deployment, and scaling of all services.
To get this distributed notification system up and running on your local machine, follow these steps.
-
⬇️ Clone the Repository:
git clone https://github.com/Adedayo-Data/distributed-notification-system cd distributed-notification-system -
⚙️ Prepare Environment Variables: Create
.envfiles for theapi-gatewayanduser-serviceby copying their respective.env.examplefiles and filling in theJWT_SECRETvariable.For
api-gateway:cp api-gateway/.env.example api-gateway/.env # Open api-gateway/.env and set JWT_SECRET to a strong, random stringFor
user-service:# No .env.example for user-service, JWT_SECRET is set in docker-compose.yml but can be overridden # via environment variable. For local setup, the docker-compose.yml values are usually sufficient # or you can set it directly in your shell or global .env if you wish. # JWT_SECRET=your_super_secret_jwt_key
Ensure you set a strong
JWT_SECRETin yourdocker-compose.ymlor global.envthat is consistent across services relying on it (e.g.,api-gatewayanduser-service). Also,email-servicerequiresFROM_EMAILandSENDGRID_API_KEYto be set as environment variables for actual email sending. -
🚀 Start Services with Docker Compose: Navigate to the root directory of the project and run:
docker-compose up --build
This command will build the Docker images for all services and start them along with RabbitMQ, Redis, and PostgreSQL. It might take a few minutes for all services to become fully operational.
The project utilizes several environment variables across its services for configuration. Below is a consolidated list of critical variables and their examples.
-
Global (
docker-compose.ymlor global.env):JWT_SECRET:your-super-secret-jwt-key-change-in-production(A strong, secret key for JWT signing across services.)
-
API Gateway (
api-gateway/.env):SERVICE_PORT:8000RABBITMQ_HOST:rabbitmqREDIS_HOST:redisJWT_SECRET:your-super-secret-jwt-key-change-in-productionUSER_SERVICE_URL:http://user-service:3001RATE_LIMIT_REQUESTS:100RATE_LIMIT_WINDOW:60CIRCUIT_BREAKER_FAIL_MAX:5CIRCUIT_BREAKER_TIMEOUT:60NOTIFICATION_STATUS_TTL:604800IDEMPOTENCY_TTL:86400
-
User Service (
docker-compose.ymlenvironment section):SERVICE_PORT:3001DB_HOST:postgresDB_USERNAME:adminDB_PASSWORD:passwordDB_DATABASE:user_dbJWT_SECRET:your_super_secret_jwt_key
-
Template Service (
docker-compose.ymlenvironment section):SERVICE_PORT:8085SPRING_DATASOURCE_URL:jdbc:postgresql://postgres:5432/template_dbSPRING_DATASOURCE_PASSWORD:password
-
Push Service (
docker-compose.ymlenvironment section,application.properties):SPRING_RABBITMQ_HOST:rabbitmqSPRING_REDIS_HOST:redisUSER_SERVICE_URL:http://user-service:3001TEMPLATE_SERVICE_URL:http://template-service:8085STATUS_UPDATE_URL:http://api-gateway:8000/api/v1/push/status/app.firebase.config-path:classpath:firebase-service-account.json(Requiresfirebase-service-account.jsoninpush-service/src/main/resources/)
-
Email Service (
docker-compose.ymlenvironment section):RABBITMQ_URL:amqp://guest:guest@rabbitmq:5672/REDIS_URL:redis://redis:6379/0USER_SERVICE_URL:http://user-service:3001TEMPLATE_SERVICE_URL:http://template-service:8085STATUS_UPDATE_URL:http://api-gateway:8000/api/v1/email/status/FROM_EMAIL:your-sender-email@example.com(Environment variable foremail-service)SENDGRID_API_KEY:SG.YOUR_SENDGRID_API_KEY(Environment variable foremail-service)
Once all services are running via docker-compose up, the API Gateway will be accessible on http://localhost:8000. This gateway serves as the single entry point for all client interactions with the notification system.
First, you need to register a user. The API Gateway will proxy this request to the User Service.
Request:
{
"name": "Jane Doe",
"email": "jane.doe@example.com",
"password": "SecurePassword123",
"push_token": "optional_fcm_device_token_here",
"preferences": {
"email": true,
"push": true
}
}Response (Success):
{
"success": true,
"data": {
"id": "123e4567-e89b-12d3-a456-426614174001",
"name": "Jane Doe",
"email": "jane.doe@example.com",
"push_token": "optional_fcm_device_token_here",
"preferences": {
"id": "987f6543-a21b-87c6-d543-210098765432",
"email_notifications": true,
"push_notifications": true,
"created_at": "2023-10-26T10:00:00.000Z",
"updated_at": "2023-10-26T10:00:00.000Z"
},
"created_at": "2023-10-26T10:00:00.000Z",
"updated_at": "2023-10-26T10:00:00.000Z"
},
"message": "User created successfully",
"meta": {}
}After registration, log in to get an access_token required for other API calls.
Request:
{
"email": "jane.doe@example.com",
"password": "SecurePassword123"
}Response (Success):
{
"success": true,
"data": {
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": "123e4567-e89b-12d3-a456-426614174001",
"name": "Jane Doe",
"email": "jane.doe@example.com",
"push_token": "optional_fcm_device_token_here",
"preferences": {
"id": "987f6543-a21b-87c6-d543-210098765432",
"email_notifications": true,
"push_notifications": true,
"created_at": "2023-10-26T10:00:00.000Z",
"updated_at": "2023-10-26T10:00:00.000Z"
},
"created_at": "2023-10-26T10:00:00.000Z",
"updated_at": "2023-10-26T10:00:00.000Z"
}
},
"message": "Login successful",
"error": null,
"meta": null
}Important: Copy the access_token from the response. You will use it in the Authorization header for subsequent requests.
Before sending notifications, you need a template. This request goes directly to the Template Service.
Request:
{
"templateKey": "welcome_message",
"subjectTemplate": "Welcome, {{name}}!",
"bodyTemplate": "Hello {{name}},\n\nThank you for signing up! Here is your personalized link: {{link}}\n\nBest regards.",
"type": "EMAIL",
"version": 1
}Response (Success):
{
"id": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
"template_code": "welcome_message",
"subjectTemplate": "Welcome, {{name}}!",
"bodyTemplate": "Hello {{name}},\n\nThank you for signing up! Here is your personalized link: {{link}}\n\nBest regards.",
"type": "EMAIL",
"version": 1
}Now, you can send an email or push notification using the template created and the user ID obtained after registration. Use the access_token from login in the Authorization: Bearer <token> header.
Request:
{
"notification_type": "email",
"user_id": "123e4567-e89b-12d3-a456-426614174001",
"template_code": "welcome_message",
"variables": {
"name": "Jane Doe",
"link": "https://your-app.com/verify/token123",
"meta": {
"source": "web_signup"
}
},
"request_id": "unique-request-id-123456",
"priority": 3,
"metadata": {
"campaign": "onboarding"
}
}Response (Success, status 202 Accepted):
{
"success": true,
"data": {
"notification_id": "876e5432-d10c-b9a8-7654-3210fedcba98",
"status": "pending",
"request_id": "unique-request-id-123456",
"notification_type": "email"
},
"message": "Notification queued for processing",
"error": null,
"meta": null
}Important: The notification_id in the response is crucial for checking the status of the sent notification.
Use the notification_id from the previous step to check the delivery status.
Request (HTTP GET):
GET /api/v1/notifications/876e5432-d10c-b9a8-7654-3210fedcba98/status
(Remember to include Authorization: Bearer <token> header)
Response (Success):
{
"success": true,
"data": {
"notification_id": "876e5432-d10c-b9a8-7654-3210fedcba98",
"status": "delivered",
"notification_type": "email",
"created_at": "2023-10-26T10:05:00.000Z",
"updated_at": "2023-10-26T10:05:15.000Z",
"error_message": null,
"retry_count": 0
},
"message": "Notification status retrieved",
"error": null,
"meta": null
}Retrieve a paginated list of all notifications associated with the authenticated user.
Request (HTTP GET):
GET /api/v1/notifications?page=1&limit=10
(Remember to include Authorization: Bearer <token> header)
Response (Success):
{
"success": true,
"data": [
{
"notification_id": "876e5432-d10c-b9a8-7654-3210fedcba98",
"status": "delivered",
"notification_type": "email",
"created_at": "2023-10-26T10:05:00.000Z",
"user_id": "123e4567-e89b-12d3-a456-426614174001",
"template_code": "welcome_message",
"updated_at": "2023-10-26T10:05:15.000Z",
"error_message": null
}
// ... other notifications
],
"message": "Notifications retrieved",
"error": null,
"meta": {
"total": 1,
"limit": 10,
"page": 1,
"total_pages": 1,
"has_next": false,
"has_previous": false
}
}A Python-based API Gateway built with FastAPI, acting as the central entry point for the distributed notification system. It handles request authentication, routing to appropriate microservices, rate limiting, and manages notification status with Redis.
FastAPI: High-performance asynchronous web framework for routing.JWT Authentication: Validates JWT tokens issued by the User Service.Redis: Utilized for rate limiting, idempotency caching, and storing real-time notification statuses.RabbitMQ: Publishes notification requests to specific queues (email.queue,push.queue) for asynchronous processing.Circuit Breaker: Implements a fault tolerance mechanism to prevent cascading failures to downstream services.Idempotency: Prevents duplicate processing of requests usingrequest_idand Redis caching.
Managed by the root docker-compose.yml. No separate manual installation steps are typically needed after cloning the repository.
# From the project root, ensure api-gateway/.env is configured
# docker-compose up --build api-gateway
# (This command is for specific service, typically you'd run all with `docker-compose up --build`)SERVICE_NAME:api-gateway(Name of the service)SERVICE_PORT:8000(Port the service listens on)ENVIRONMENT:development(Application environment, e.g., development, production)DEBUG:true(Enable debug mode)RABBITMQ_HOST:rabbitmq(Hostname for RabbitMQ connection)RABBITMQ_PORT:5672(Port for RabbitMQ)RABBITMQ_USER:guest(Username for RabbitMQ)RABBITMQ_PASS:guest(Password for RabbitMQ)RABBITMQ_VHOST:/(Virtual host for RabbitMQ)RABBITMQ_EXCHANGE:notifications.direct(Main exchange name for notifications)RABBITMQ_EXCHANGE_TYPE:direct(Type of RabbitMQ exchange)REDIS_HOST:redis(Hostname for Redis connection)REDIS_PORT:6379(Port for Redis)REDIS_DB:0(Redis database index)REDIS_PASSWORD:None(Password for Redis, if any)REDIS_DECODE_RESPONSES:true(Decode Redis responses to Python strings)JWT_SECRET:your-super-secret-jwt-key-change-in-production-make-it-long-and-random(Secret key for JWT verification)JWT_ALGORITHM:HS256(Algorithm for JWT)JWT_EXPIRATION:3600(JWT expiration time in seconds)RATE_LIMIT_REQUESTS:100(Max requests allowed in the rate limit window)RATE_LIMIT_WINDOW:60(Time window in seconds for rate limiting)CIRCUIT_BREAKER_FAIL_MAX:5(Number of failures before circuit opens)CIRCUIT_BREAKER_TIMEOUT:60(Duration in seconds for circuit to stay open)USER_SERVICE_URL:http://user-service:3001(URL for the User Service)TEMPLATE_SERVICE_URL:http://template-service:8085(URL for the Template Service)EMAIL_SERVICE_URL:http://email-service:8003(URL for the Email Service)PUSH_SERVICE_URL:http://push-service:8084(URL for the Push Service)NOTIFICATION_STATUS_TTL:604800(Time-to-live for notification status in Redis in seconds)IDEMPOTENCY_TTL:86400(Time-to-live for idempotency keys in Redis in seconds)LOG_LEVEL:INFO(Logging level)
http://localhost:8000
Authenticates a user by proxying credentials to the User Service and returns an access token.
Request:
{
"email": "string",
"password": "string"
}Response:
{
"success": true,
"data": {
"access_token": "string",
"token_type": "bearer",
"expires_in": 3600
},
"error": null,
"message": "Login successful",
"meta": null
}Errors:
401 Unauthorized: Invalid credentials or token format.500 Internal Server Error: An unexpected error occurred.
Verifies the validity of a JWT access token.
Request:
Headers:
Authorization: Bearer <JWT_TOKEN>
Response:
{
"success": true,
"data": {
"valid": true,
"user_id": "string"
},
"error": null,
"message": "Token is valid",
"meta": null
}Errors:
401 Unauthorized: Invalid authorization header, invalid token format, or expired/invalid token.
Sends a notification via email or push, queuing it for asynchronous processing.
Request:
Headers:
Authorization: Bearer <JWT_TOKEN>
Body:
{
"notification_type": "email" | "push",
"user_id": "uuid",
"template_code": "string",
"variables": {
"name": "string",
"link": "https://example.com/verify/token",
"meta": {}
},
"request_id": "string",
"priority": 1,
"metadata": {}
}Response:
{
"success": true,
"data": {
"notification_id": "string",
"status": "pending",
"request_id": "string",
"notification_type": "email" | "push"
},
"error": null,
"message": "Notification queued for processing",
"meta": null
}Errors:
400 Bad Request: Invalid input (e.g., emptytemplate_code).401 Unauthorized: Invalid authorization header or invalid/expired token.429 Too Many Requests: Rate limit exceeded for the authenticated user.503 Service Unavailable: Notification service temporarily unavailable (e.g., RabbitMQ unreachable).500 Internal Server Error: Failed to process notification request.
Retrieves the current status of a specific notification.
Request:
Headers:
Authorization: Bearer <JWT_TOKEN>
Response:
{
"success": true,
"data": {
"notification_id": "string",
"status": "pending" | "delivered" | "failed",
"notification_type": "email" | "push",
"created_at": "ISO 8601 datetime string",
"updated_at": "ISO 8601 datetime string",
"error_message": "string",
"retry_count": 0
},
"error": null,
"message": "Notification status retrieved",
"meta": null
}Errors:
401 Unauthorized: Invalid authorization header or invalid/expired token.404 Not Found: Notification ID not found.500 Internal Server Error: Failed to retrieve status.
Updates the status of a notification. This endpoint is primarily for internal service-to-service communication (e.g., Email Service, Push Service updating the status via Gateway).
Request:
notification_preference can be email or push.
Body:
{
"notification_id": "string",
"status": "delivered" | "pending" | "failed",
"timestamp": "ISO 8601 datetime string (optional)",
"error": "string (optional)"
}Response:
{
"success": true,
"data": {
"notification_id": "string",
"status": "string",
"updated": true
},
"error": null,
"message": "Notification status updated successfully",
"meta": null
}Errors:
400 Bad Request: Invalid notification preference.404 Not Found: Notification ID not found.500 Internal Server Error: Failed to update notification status.
Lists all notifications for the authenticated user with pagination.
Request:
Headers:
Authorization: Bearer <JWT_TOKEN>
Query Parameters:
page:integer(Default: 1)limit:integer(Default: 10)
Response:
{
"success": true,
"data": [
{
"notification_id": "string",
"status": "string",
"notification_type": "string",
"created_at": "string",
"updated_at": "string",
"error_message": "string",
"retry_count": 0
}
],
"error": null,
"message": "Notifications retrieved",
"meta": {
"total": 100,
"limit": 10,
"page": 1,
"total_pages": 10,
"has_next": true,
"has_previous": false
}
}Errors:
401 Unauthorized: Invalid authorization header or invalid/expired token.500 Internal Server Error: Failed to retrieve notifications.
Performs a health check of the API Gateway and its critical dependencies (RabbitMQ, Redis).
Request: None.
Response:
{
"status": "healthy" | "degraded",
"service": "api-gateway",
"timestamp": "ISO 8601 datetime string",
"checks": {
"rabbitmq": true,
"redis": true,
"service": "up"
},
"version": "1.0.0"
}Errors:
500 Internal Server Error: If an unexpected error occurs during health check.
A Node.js microservice built with NestJS and TypeORM, responsible for managing user accounts, authentication (login, password hashing, JWT generation), and user preferences for notifications. It interacts with a PostgreSQL database.
NestJS: A progressive Node.js framework for building efficient and scalable server-side applications.TypeORM: An ORM for PostgreSQL database interaction, supporting entities and repositories.PostgreSQL: Relational database for storing user profiles and preferences.bcryptjs: Secure hashing for user passwords.JWT: Generates JSON Web Tokens for user authentication.User Management: Provides endpoints for creating, retrieving, updating, and deleting user accounts.User Preferences: Manages user-specific notification preferences (email, push).
Managed by the root docker-compose.yml.
# From the project root, ensure user-service/.env is configured (or environment variables are passed)
# docker-compose up --build user-service
# (This command is for specific service, typically you'd run all with `docker-compose up --build`)SERVICE_PORT:3001(Port the service listens on)DB_HOST:postgres(PostgreSQL database host)DB_USERNAME:admin(PostgreSQL username)DB_PASSWORD:password(PostgreSQL password)DB_DATABASE:user_db(PostgreSQL database name)JWT_SECRET:your_secret_key(Secret key for JWT signing)NODE_ENV:development(Application environment; affects database synchronization and logging)
http://localhost:3001
Authenticates a user and issues a JWT access token.
Request:
{
"email": "string",
"password": "string"
}Response:
{
"success": true,
"data": {
"access_token": "string",
"user": {
"id": "uuid",
"name": "string",
"email": "string",
"push_token": "string | null",
"preferences": {
"id": "uuid",
"email_notifications": true,
"push_notifications": true,
"created_at": "ISO 8601 datetime string",
"updated_at": "ISO 8601 datetime string"
},
"created_at": "ISO 8601 datetime string",
"updated_at": "ISO 8601 datetime string"
}
},
"message": "Login successful",
"meta": {}
}Errors:
400 Bad Request: Invalid credentials.500 Internal Server Error: An unexpected error occurred during login.
Verifies a JWT token and returns its payload.
Request:
{
"token": "string"
}Response:
{
"success": true,
"data": {
"sub": "uuid",
"email": "string",
"name": "string",
"iat": 1678886400,
"exp": 1678972800
},
"message": "Token is valid",
"meta": {}
}Errors:
400 Bad Request: Invalid token.500 Internal Server Error: An unexpected error occurred during token verification.
Registers a new user with their details and notification preferences.
Request:
{
"name": "string",
"email": "string",
"password": "string",
"push_token": "string (optional)",
"preferences": {
"email": true,
"push": true
}
}Response:
{
"success": true,
"data": {
"id": "uuid",
"name": "string",
"email": "string",
"push_token": "string | null",
"preferences": {
"id": "uuid",
"email_notifications": true,
"push_notifications": true,
"created_at": "ISO 8601 datetime string",
"updated_at": "ISO 8601 datetime string"
},
"created_at": "ISO 8601 datetime string",
"updated_at": "ISO 8601 datetime string"
},
"message": "User created successfully",
"meta": {}
}Errors:
400 Bad Request: Email already registered, or invalid input.500 Internal Server Error: Failed to create user.
Retrieves a paginated list of all registered users.
Request: Query Parameters:
page:number(Default: 1)limit:number(Default: 10)
Response:
{
"success": true,
"data": [
{
"id": "uuid",
"name": "string",
"email": "string",
"push_token": "string | null",
"preferences": {
"id": "uuid",
"email_notifications": true,
"push_notifications": true,
"created_at": "ISO 8601 datetime string",
"updated_at": "ISO 8601 datetime string"
},
"created_at": "ISO 8601 datetime string",
"updated_at": "ISO 8601 datetime string"
}
],
"message": "Users retrieved successfully",
"meta": {
"total": 1,
"limit": 10,
"page": 1,
"total_pages": 1,
"has_next": false,
"has_previous": false
}
}Errors:
500 Internal Server Error: Failed to retrieve users.
Retrieves a specific user by their ID.
Request: Path Parameter:
user_id:string(UUID of the user)
Response:
{
"success": true,
"data": {
"id": "uuid",
"name": "string",
"email": "string",
"push_token": "string | null",
"preferences": {
"id": "uuid",
"email_notifications": true,
"push_notifications": true,
"created_at": "ISO 8601 datetime string",
"updated_at": "ISO 8601 datetime string"
},
"created_at": "ISO 8601 datetime string",
"updated_at": "ISO 8601 datetime string"
},
"message": "User retrieved successfully",
"meta": {}
}Errors:
404 Not Found: User with the specified ID not found.500 Internal Server Error: Failed to retrieve user.
Updates an existing user's details or preferences.
Request: Path Parameter:
user_id:string(UUID of the user) Body:
{
"name": "string (optional)",
"email": "string (optional)",
"push_token": "string (optional)",
"preferences": {
"email": true,
"push": true
} (optional)
}Response:
{
"success": true,
"data": {
"id": "uuid",
"name": "string",
"email": "string",
"push_token": "string | null",
"preferences": {
"id": "uuid",
"email_notifications": true,
"push_notifications": true,
"created_at": "ISO 8601 datetime string",
"updated_at": "ISO 8601 datetime string"
},
"created_at": "ISO 8601 datetime string",
"updated_at": "ISO 8601 datetime string"
},
"message": "User updated successfully",
"meta": {}
}Errors:
400 Bad Request: Email already in use, or invalid input.404 Not Found: User with the specified ID not found.500 Internal Server Error: Failed to update user.
Updates the push notification token for a specific user.
Request: Path Parameter:
user_id:string(UUID of the user) Body:
{
"push_token": "string"
}Response:
{
"success": true,
"data": {
"id": "uuid",
"name": "string",
"email": "string",
"push_token": "string | null",
"preferences": {
"id": "uuid",
"email_notifications": true,
"push_notifications": true,
"created_at": "ISO 8601 datetime string",
"updated_at": "ISO 8601 datetime string"
},
"created_at": "ISO 8601 datetime string",
"updated_at": "ISO 8601 datetime string"
},
"message": "Push token updated successfully",
"meta": {}
}Errors:
404 Not Found: User with the specified ID not found.500 Internal Server Error: Failed to update push token.
Validates a user's password against their email.
Request: Body:
{
"email": "string",
"password": "string"
}Response:
{
"success": true,
"data": {
"id": "uuid",
"name": "string",
"email": "string",
"push_token": "string | null",
"preferences": {
"id": "uuid",
"email_notifications": true,
"push_notifications": true,
"created_at": "ISO 8601 datetime string",
"updated_at": "ISO 8601 datetime string"
},
"created_at": "ISO 8601 datetime string",
"updated_at": "ISO 8601 datetime string"
},
"message": "User validated successfully",
"meta": {}
}Errors:
400 Bad Request: Invalid credentials.404 Not Found: User with the specified email not found.500 Internal Server Error: Validation failed.
Deletes a user account.
Request: Path Parameter:
user_id:string(UUID of the user)
Response:
{
"success": true,
"data": {
"message": "User deleted successfully"
},
"message": "User deleted successfully",
"meta": {}
}Errors:
404 Not Found: User with the specified ID not found.500 Internal Server Error: Failed to delete user.
Checks the health status of the User Service.
Request: None.
Response:
{
"status": "UP",
"service": "user-service",
"timestamp": "ISO 8601 datetime string"
}Errors:
500 Internal Server Error: If an unexpected error occurs during health check.
A Python microservice built with FastAPI, responsible for consuming email notification messages from RabbitMQ, rendering templates with the Template Service, and sending emails via SendGrid. It also updates the notification status back to the API Gateway.
FastAPI: Provides a minimal API for health checks and status retrieval.aio_pika: Asynchronously consumes messages from RabbitMQ'semail.queue.SendGrid: External service for sending emails.Redis: Stores temporary email notification statuses.Template Service Integration: Fetches and renders email templates dynamically.Status Reporting: Updates notification status (sent,failed,skipped) to the API Gateway.Dead Letter Queue (DLQ): Unprocessed or failed messages are routed to a DLQ for later inspection and retry.
Managed by the root docker-compose.yml.
# From the project root
# docker-compose up --build email-service
# (This command is for specific service, typically you'd run all with `docker-compose up --build`)RABBITMQ_URL:amqp://guest:guest@rabbitmq:5672/(RabbitMQ connection URL)REDIS_URL:redis://redis:6379/0(Redis connection URL)USER_SERVICE_URL:http://user-service:3001(URL for the User Service, though not directly used for email sending, present in the context)TEMPLATE_SERVICE_URL:http://template-service:8085(URL for the Template Service)STATUS_UPDATE_URL:http://api-gateway:8000/api/v1/email/status/(URL for reporting status to API Gateway)FROM_EMAIL:your-sender-email@example.com(Sender email address for SendGrid)SENDGRID_API_KEY:SG.YOUR_SENDGRID_API_KEY(API key for SendGrid)
http://localhost:8003
Checks the health status of the Email Service.
Request: None.
Response:
{
"status": "ok"
}Errors:
500 Internal Server Error: If an unexpected error occurs during health check.
Retrieves the current status of an email notification by its ID.
Request: Path Parameter:
notification_id:string(Unique identifier for the email notification)
Response:
{
"notification_id": "string",
"status": "string"
}Errors:
500 Internal Server Error: If an unexpected error occurs during status retrieval.
A Java microservice built with Spring Boot, responsible for consuming push notification messages from RabbitMQ, fetching user push tokens and preferences from the User Service, rendering templates with the Template Service, and sending push notifications via Firebase Cloud Messaging (FCM). It reports status updates back to the API Gateway.
Spring Boot: Framework for building robust Java applications.RabbitMQ: Consumes messages from thepush.queuefor asynchronous processing.Redis: Stores temporary push notification statuses and prevents duplicate processing.Firebase Cloud Messaging (FCM): Sends push notifications to mobile devices.User Service Integration: Fetches user's push tokens and notification preferences.Template Service Integration: Renders push notification content (title, body, image, action link) dynamically.Status Reporting: Updates notification status (delivered,failed,skipped) to the API Gateway.
Managed by the root docker-compose.yml.
# From the project root, ensure firebase-service-account.json is in push-service/src/main/resources/
# docker-compose up --build push-service
# (This command is for specific service, typically you'd run all with `docker-compose up --build`)SERVICE_PORT:8084(Port the service listens on, internally used by other services)SPRING_RABBITMQ_HOST:rabbitmq(RabbitMQ host for Spring Boot)SPRING_REDIS_HOST:redis(Redis host for Spring Boot)USER_SERVICE_URL:http://user-service:3001(URL for the User Service)TEMPLATE_SERVICE_URL:http://template-service:8085(URL for the Template Service)STATUS_UPDATE_URL:http://api-gateway:8000/api/v1/push/status/(URL for reporting status to API Gateway)app.firebase.config-path:classpath:firebase-service-account.json(Path to Firebase service account key)
http://localhost:8084
Checks the health status of the Push Service.
Request: None.
Response:
{
"Status": "UP",
"Service": "push-service"
}Errors:
500 Internal Server Error: If an unexpected error occurs during health check.
A Java microservice built with Spring Boot and Spring Data JPA, responsible for managing notification templates and rendering their content dynamically using provided variables. It persists templates in a PostgreSQL database.
Spring Boot: Framework for building Java-based microservices.Spring Data JPA: Simplifies database access and persistence for PostgreSQL.PostgreSQL: StoresNotificationTemplateentities.Template Management: Provides API for creating, retrieving, and updating notification templates.Template Rendering: Dynamically replaces placeholders in subject and body templates with actual variable values.NotificationType: Supports different template types (e.g., EMAIL, PUSH) to ensure proper rendering for each channel.
Managed by the root docker-compose.yml.
# From the project root
# docker-compose up --build template-service
# (This command is for specific service, typically you'd run all with `docker-compose up --build`)SERVICE_PORT:8085(Port the service listens on)SPRING_DATASOURCE_URL:jdbc:postgresql://postgres:5432/template_db(JDBC URL for PostgreSQL)SPRING_DATASOURCE_USERNAME:admin(PostgreSQL username)SPRING_DATASOURCE_PASSWORD:password(PostgreSQL password)SPRING_JPA_HIBERNATE_DDL_AUTO:update(Hibernate DDL generation strategy)SPRING_JPA_PROPERTIES_HIBERNATE_DIALECT:org.hibernate.dialect.PostgreSQLDialect(Hibernate dialect for PostgreSQL)
http://localhost:8085
Creates a new notification template.
Request:
{
"templateKey": "string",
"subjectTemplate": "string",
"bodyTemplate": "string",
"type": "EMAIL" | "PUSH",
"version": 1
}Response:
{
"id": "uuid",
"template_code": "string",
"subjectTemplate": "string",
"bodyTemplate": "string",
"type": "EMAIL",
"version": 1
}Errors:
500 Internal Server Error: Failed to create template.
Retrieves a notification template by its unique key.
Request: Path Parameter:
templateKey:string(Unique identifier for the template)
Response:
{
"id": "uuid",
"template_code": "string",
"subjectTemplate": "string",
"bodyTemplate": "string",
"type": "EMAIL" | "PUSH",
"version": 1
}Errors:
500 Internal Server Error: Failed to retrieve template or template key not applicable.
Renders a template by replacing placeholders with provided variables.
Request:
{
"notificationType": "EMAIL" | "PUSH",
"templateKey": "string",
"variables": {
"key1": "value1",
"key2": "value2"
}
}Response:
{
"success": true,
"message": "Template rendered successfully",
"data": {
"renderedSubject": "string",
"renderedBody": "string"
},
"error": null,
"meta": null
}Errors:
400 Bad Request: Template rendering failed (e.g., template not found for key/type, missing variables).
Checks the health status of the Template Service.
Request: None.
Response:
{
"Status": "UP",
"Service": "template-service"
}Errors:
500 Internal Server Error: If an unexpected error occurs during health check.
| Category | Technology | Description |
|---|---|---|
| Languages | Node.js (TypeScript), Python, Java | Core programming languages for microservices. |
| Frameworks | NestJS, FastAPI, Spring Boot | Robust frameworks for building scalable backend services. |
| Databases | PostgreSQL, Redis | Relational database for persistent storage and in-memory data store/cache. |
| Messaging | RabbitMQ | Message broker for asynchronous communication between services. |
| Authentication | JWT | JSON Web Tokens for secure API authentication. |
| Containerization | Docker, Docker Compose | For containerizing services and orchestrating multi-container applications. |
| Email Service | SendGrid | Third-party service for sending emails. |
| Push Notifications | Firebase Cloud Messaging (FCM) | Cross-platform messaging solution for sending push notifications. |
| ORM/ODM | TypeORM (for NestJS), Spring Data JPA (for Spring Boot) | Object-Relational Mapping for database interactions. |
- LinkedIn: Your LinkedIn Profile
- Twitter: Your Twitter Profile
- Portfolio: Your Portfolio Site