This microservice handles sending notifications (email, SMS) for a Rental Management System. It integrates with User Management, Payment Processing, and Property Listing services.
- Send notifications for various events (payment success/failure, listing approval, tenant updates).
- Multilingual templates (English, Amharic, Afaan Oromo) based on user's preferred language.
- Notification logging for auditing and retries.
- Admin endpoints for viewing and managing notifications.
- Secure with JWT authentication and Pydantic validation.
- Rate limiting for
/sendendpoint. - Asynchronous operations with
asyncpgandFastAPI. - Retry mechanism for failed notification sends.
+-------------------+ +-------------------+ +-------------------+
| User Service | | Payment Service | | Property Service |
| (Manages Users) | | (Handles Payments)| | (Manages Listings)|
+---------+---------+ +---------+---------+ +---------+---------+
| | |
| 1. User Registration | 2. Payment Event | 3. Listing Update
| (New User) | (Success/Failure) | (Approval/Change)
v v v
+-----------------------------------------------------------------------+
| Notification Microservice |
| (Sends Emails/SMS based on events, integrates with external services) |
+-----------------------------------------------------------------------+
|
| 4. Notification Trigger (Internal API Call)
v
+-------------------+ +-------------------+
| AWS SES | | Mock SMS |
| (Sends Emails) | | (Simulates SMS) |
+-------------------+ +-------------------+
- Python 3.10+
- FastAPI
- PostgreSQL (asyncpg)
- SQLAlchemy (ORM)
- AWS SES (for email)
httpx(for internal service calls)python-jose(for JWT)apscheduler(for cron jobs)structlog(for structured logging)fastapi-limiter(for rate limiting)boto3(for AWS SES)
-
Clone the repository:
git clone <repository_url> cd Notification Microservice
-
Create and activate a virtual environment:
python3.10 -m venv venv source venv/bin/activate -
Install dependencies:
pip install -r requirements.txt
-
Configure environment variables: Copy
.env.exampleto.envand fill in the details.cp .env.example .env
Edit
.env:DATABASE_URL="postgresql+asyncpg://user:password@host:port/database" USER_MANAGEMENT_URL="http://user-management:8000/api/v1" AWS_ACCESS_KEY_ID="YOUR_AWS_ACCESS_KEY_ID" AWS_SECRET_ACCESS_KEY="YOUR_AWS_SECRET_ACCESS_KEY" AWS_REGION_NAME="us-east-1" JWT_SECRET="YOUR_SUPER_SECRET_JWT_KEY" ALGORITHM="HS256" ACCESS_TOKEN_EXPIRE_MINUTES=30 -
Run Migrations and Seed Data: Ensure your PostgreSQL database is running and accessible via
DATABASE_URL.chmod +x migrate.sh ./migrate.sh
-
Run the application:
uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
The API documentation will be available at
http://localhost:8000/docs.
- Method:
POST - Path:
/api/v1/notifications/send - Permissions: Admin or Internal Services
- Description: Sends an email/SMS notification for a specific event to a user.
- Parameters (Request Body):
Example
{ "user_id": "UUID", "event_type": "str", "context": "dict" }context:{"property_title": "Luxury Apartment", "location": "Addis Ababa", "amount": 1500} - Example Response:
{ "status": "sent", "notification_id": "UUID" }
- Method:
GET - Path:
/api/v1/notifications/{id} - Permissions: Admin
- Description: Retrieves details of a specific notification.
- Example Response:
{ "id": "UUID", "user_id": "UUID", "event_type": "str", "status": "str", "sent_at": "datetime" }
- Method:
GET - Path:
/api/v1/notifications - Permissions: Admin
- Description: Retrieves a list of notifications, with optional filtering.
- Query Parameters:
user_id:UUID(Optional)event_type:str(Optional)
- Example Response:
[ { "id": "UUID", "user_id": "UUID", "event_type": "str", "status": "str", "sent_at": "datetime" } ]
-
Method:
GET -
Path:
/api/v1/notifications/stats -
Permissions: Admin
-
Description: Retrieves aggregated statistics about notifications.
-
Example Response:
{ "total_notifications": 105, "total_sent": 50, "total_failed": 30, "total_pending": 25, "by_status": { "SENT": 50, "FAILED": 30, "PENDING": 25 }, "by_event_type": { "payment_success": { "SENT": 20, "FAILED": 10, "PENDING": 5 }, "listing_approved": { "SENT": 15, "FAILED": 5, "PENDING": 10 }, "payment_failed": { "SENT": 5, "FAILED": 10, "PENDING": 5 }, "tenant_update": { "SENT": 10, "FAILED": 5, "PENDING": 5 } } }ASCII Chart (Sample Data):
Total: |||||||||| 105 Sent: ||||||||| 50 Failed: |||||| 30 Pending: ||||| 25
- Method:
POST - Path:
/api/v1/notifications/retry - Permissions: Internal (typically called by a cron job)
- Description: Retries sending failed notifications.
-
Start the services: Ensure User Management and Notification Microservices are running.
-
Seed Data: Run
./migrate.shto create theNotificationstable and seed it with test data. -
Send a test notification (as Admin/Internal):
curl -X POST "http://localhost:8000/api/v1/notifications/send" \ -H "Authorization: Bearer YOUR_ADMIN_JWT_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "user_id": "a1b2c3d4-e5f6-7890-1234-567890abcdef", "event_type": "payment_success", "context": { "property_title": "Modern Studio", "location": "Bole, Addis Ababa", "amount": 2500 } }'
(Replace
YOUR_ADMIN_JWT_TOKENanduser_idwith actual values from your User Management service.) -
View notifications (as Admin):
curl -X GET "http://localhost:8000/api/v1/notifications" \ -H "Authorization: Bearer YOUR_ADMIN_JWT_TOKEN"
-
View a specific notification (as Admin):
curl -X GET "http://localhost:8000/api/v1/notifications/YOUR_NOTIFICATION_ID" \ -H "Authorization: Bearer YOUR_ADMIN_JWT_TOKEN"
-
Trigger retry (simulated cron job):
curl -X POST "http://localhost:8000/api/v1/notifications/retry" \ -H "Authorization: Bearer YOUR_INTERNAL_SERVICE_JWT_TOKEN"
(This endpoint is typically called by
apschedulerinternally, but can be triggered manually for testing.)
To showcase the robustness and error handling of the microservice, you can simulate the following scenarios:
-
Unauthorized Access (403 Forbidden): Attempt to access an admin-only endpoint (e.g.,
/stats) with a non-admin JWT token.# Ensure you have a non-admin JWT token for this test curl -X GET "http://localhost:8000/api/v1/notifications/stats" \ -H "Authorization: Bearer YOUR_NON_ADMIN_JWT_TOKEN"
Expected Response:
{"detail":"Forbidden"} -
Send to a Non-Existent User (404 Not Found): Attempt to send a notification to a
user_idthat does not exist in theUserstable.curl -X POST "http://localhost:8000/api/v1/notifications/send" \ -H "Authorization: Bearer YOUR_ADMIN_JWT_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "user_id": "00000000-0000-0000-0000-000000000000", "event_type": "payment_success", "context": { "property_title": "Non-existent User Test", "location": "Unknown", "amount": 100 } }'
Expected Response:
{"detail":"User with ID 00000000-0000-0000-0000-000000000000 not found."}(This will also log a FAILED notification in the database.) -
Trigger Rate Limit (429 Too Many Requests): Rapidly execute the
POST /api/v1/notifications/sendcommand more than 10 times within a minute.# Run this command in a loop or multiple times in quick succession for i in {1..15}; do curl -X POST "http://localhost:8000/api/v1/notifications/send" \ -H "Authorization: Bearer YOUR_ADMIN_JWT_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "user_id": "123e4567-e89b-12d3-a456-426614174000", "event_type": "listing_approved", "context": { "property_title": "Rate Limit Test", "location": "Fast Lane" } }' & done
Expected Response (after 10 requests):
{"error":"Too Many Requests"}Rate Limit Error Example:
curl -X POST "http://localhost:8000/api/v1/notifications/send" \ -H "Authorization: Bearer YOUR_ADMIN_JWT_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "user_id": "123e4567-e89b-12d3-a456-426614174000", "event_type": "payment_success", "context": {"amount": 100} }'
Expected Response:
{"detail": "Too Many Requests"} -
Simulate SES Failure and Retry: To demonstrate SES failure and the retry mechanism, you can temporarily provide invalid AWS credentials in your
.envfile (e.g.,AWS_ACCESS_KEY_ID="INVALID").- Send a notification. The initial request will hang for a moment and then log a
FAILEDnotification. - The
apschedulerjob runningretry_failed_notificationswill automatically pick up this failed notification every 5 minutes. - Check the logs to see the retry attempts. After 3 failed attempts, the notification will be permanently marked as failed.
- Send a notification. The initial request will hang for a moment and then log a
The Dockerfile is configured for containerized deployment. You can build and push this image to AWS ECR, then deploy it as a service on AWS ECS/Fargate. Ensure your ECS Task Definition includes the necessary environment variables from .env and IAM roles for AWS SES access.
To run tests:
pytest