A comprehensive backend system for businesses (such as accounting firms) to manage and send reminders to their clients via email, SMS, and WhatsApp, with integrated payment capabilities.
- User & Client Management: Register, authenticate, and manage business users and their clients
- Business Management: Create and manage business accounts with customized settings
- Reminder System: Set up one-time or recurring reminders with different types (deadlines, payments, etc.)
- Multi-channel Notifications: Send reminders via email, SMS, or WhatsApp
- Scheduling: Automated reminder delivery at specified times with manual trigger option
- Payment Integration: Include payment links (Stripe) in reminders for easy client transactions
- Dashboard & Analytics: Monitor notification history and payment status
- Error Handling: Robust error handling for notification delivery and payment processing
Component | Technology |
---|---|
Backend API | FastAPI (Python) |
Database | AWS RDS (MySQL) |
ORM | SQLAlchemy |
Migrations | Alembic |
Notifications | SMTP (Email), Twilio (SMS), WhatsApp Business API |
Payment Processing | Stripe API |
Deployment | Docker + AWS EC2/ECS |
Load Balancing | AWS Application Load Balancer |
Task Scheduling | APScheduler (integrated in application) |
Authentication | JWT (OAuth2) |
API Documentation | Swagger/OpenAPI |
Testing | Pytest |
reminder_backend/
├── README.md # Project documentation
├── requirements.txt # Python dependencies
├── env/ # Environment configuration directory
│ ├── .env.example # Example environment variables
│ ├── .env.development # Development environment variables
│ ├── .env.testing # Testing environment variables
│ ├── .env.production # Production environment variables
│ └── README.md # Environment setup instructions
├── docker-compose.yml # Docker Compose configuration
├── Dockerfile # Docker configuration
├── main.py # Application entry point
├── alembic/ # Database migrations
├── app/ # Main application package
│ ├── api/ # API endpoints
│ │ ├── endpoints/ # Route handlers by resource
│ │ ├── dependencies.py # API dependencies (auth, etc.)
│ │ └── routes.py # API router configuration
│ ├── core/ # Core functionality
│ │ ├── security/ # Authentication & authorization
│ │ ├── encryption.py # Data encryption utilities
│ │ ├── exceptions.py # Custom exception types
│ │ └── settings/ # Environment-based configuration
│ ├── models/ # SQLAlchemy ORM models
│ │ ├── users.py # User models
│ │ ├── clients.py # Client models
│ │ ├── reminders.py # Reminder models
│ │ ├── notifications.py # Notification models
│ │ └── ... # Other data models
│ ├── repositories/ # Data access layer
│ │ ├── user.py # User data operations
│ │ ├── client.py # Client data operations
│ │ ├── reminder.py # Reminder data operations
│ │ └── ... # Other data repositories
│ ├── schemas/ # Pydantic schemas for validation
│ │ ├── users.py # User schemas
│ │ ├── clients.py # Client schemas
│ │ ├── reminders.py # Reminder schemas
│ │ └── ... # Other schemas
│ ├── services/ # Business logic & external integrations
│ │ ├── user.py # User service
│ │ ├── client.py # Client service
│ │ ├── reminder.py # Reminder service
│ │ ├── email_service.py # Email notification service
│ │ ├── sms_service.py # SMS notification service
│ │ ├── whatsapp_service.py # WhatsApp notification service
│ │ └── scheduler_service.py # APScheduler integration for reminders
│ └── database.py # Database connection and session management
├── scripts/ # Utility scripts
└── tests/ # Test suite
The application follows a layered architecture with clear separation of concerns:
- Endpoints: Handle HTTP requests and responses
- Dependencies: Shared components like authentication
- Routes: API routing configuration
- Business Logic: Core application functionality
- External Services: Integration with email, SMS, etc.
- Scheduling: Background tasks and reminder processing
- Data Access: Abstraction over database operations
- Query Logic: Complex data retrieval patterns
- Transaction Management: Ensuring data consistency
- Database Models: SQLAlchemy ORM definitions
- Schemas: Pydantic models for validation and serialization
- Domain Objects: Business entities and relationships
- Settings: Environment-specific configuration
- Security: Authentication, authorization, and encryption
- Exceptions: Custom exception types and handling
This architecture provides several benefits:
- Testability: Each layer can be tested in isolation
- Maintainability: Clear separation of concerns
- Scalability: Modular design allows for easier scaling
- Security: Centralized security controls and validation
The Reminder App is designed to be deployed as a centralized service that can manage multiple businesses and their clients. The deployment architecture includes:
- App Server: AWS EC2 or ECS for hosting the FastAPI application
- Database: AWS RDS MySQL for data persistence
- Load Balancing: AWS Application Load Balancer (for scaling)
- Monitoring: AWS CloudWatch for logs and metrics
- Networking: VPC configuration for security
Each business using the platform (such as accounting firms) will have their own account within the application but will use the same centralized infrastructure.
- Business Setup: Businesses register and configure their notification preferences
- Client Management: Businesses import or manually add their clients
- Reminder Configuration: Businesses create reminders with specified schedules, messages, and notification channels
- Client Assignment: Clients are associated with specific reminders
- Notification Delivery:
- Automated delivery based on schedule
- Manual trigger option for immediate delivery
- Client Experience:
- Clients receive notifications via preferred channels
- Clients can view documents/invoices via included links
- Clients can make payments via Stripe integration
- Monitoring:
- Businesses track notification history
- Payment status updates are recorded
- Error handling for failed notifications or payments
- Python 3.11+
- MySQL database (or SQLite for development/testing)
- AWS account for production deployment
- Twilio account (for SMS)
- SMTP server (for Email)
- WhatsApp Business API access
- Stripe account (for payment processing)
git clone https://github.com/yourusername/reminder-backend.git
cd reminder-backend
Using venv:
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
Or using uv (faster):
uv venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
Using pip:\
pip install -r requirements.txt
Or using uv (faster):
uv pip sync requirements.txt
# Create development environment file
cp env/.env.example env/.env.development
# Edit with your development settings
# Set SQLALCHEMY_DATABASE_URI to your database connection
# For quick development: SQLALCHEMY_DATABASE_URI=sqlite:///./dev.db
# Set environment
export ENV=development # Linux/Mac
set ENV=development # Windows CMD
$env:ENV = "development" # PowerShell
# Run migrations
alembic upgrade head
python main.py
# Or directly with uvicorn:
# uvicorn app.main:app --reload
# Create testing environment file
cp env/.env.example env/.env.testing
# Important settings for testing:
# SQLALCHEMY_DATABASE_URI=sqlite:///./test.db
# DISABLE_SCHEDULER=false # Will only run if reminders exist
# Set environment
export ENV=testing # Linux/Mac
set ENV=testing # Windows CMD
$env:ENV = "testing" # PowerShell
# Run tests
pytest
# Create production environment file securely
cp env/.env.example env/.env.production
# Configure all required settings for production:
# - Strong SECRET_KEY
# - Production database credentials
# - Stripe API keys
# - Twilio credentials
# - CORS settings
# - SSL configuration
# Build the Docker image
docker build -t reminder-backend:latest .
# Run with Docker
docker run -p 8000:8000 --env-file env/.env.production reminder-backend:latest
# Or use docker-compose
docker-compose up -d
# View container logs
docker logs -f reminder-backend
The application uses environment-specific configuration files located in the env/
directory:
- Development (
ENV=development
): For local development with debugging features enabled - Testing (
ENV=testing
): For automated tests with SQLite and minimal external dependencies - Production (
ENV=production
): For deployed instances with security features and optimizations
Each environment has its own configuration file:
env/.env.development
- Development environment settingsenv/.env.testing
- Testing environment settingsenv/.env.production
- Production environment settings
Create environment files from the example template:
# Create environment files from example
cp env/.env.example env/.env.development
cp env/.env.example env/.env.testing
cp env/.env.example env/.env.production
# Edit files with appropriate settings for each environment
Some important environment variables include:
- Database Connection:
SQLALCHEMY_DATABASE_URI
or individual DB_* variables - Security Keys:
SECRET_KEY
for JWT tokens (unique per environment) - API Configuration:
API_V1_STR
,CORS_ORIGINS
, etc. - External Services: Twilio, SMTP, Stripe credentials
- Scheduler Settings:
DISABLE_SCHEDULER
,SCHEDULER_TIMEZONE
- Validation Mode:
STRICT_VALIDATION
(True/False)
# Set environment before running
export ENV=development # Linux/Mac
set ENV=development # Windows CMD
$env:ENV = "development" # Windows PowerShell
# Then run the application
python main.py
Or specify directly when running:
ENV=development python main.py
The application includes a robust scheduler service for processing reminders automatically:
- Automatic Processing: Checks for due reminders at regular intervals
- Smart Recurrence: Handles various recurrence patterns (daily, weekly, monthly)
- Multi-channel Delivery: Sends notifications via email, SMS, or WhatsApp
- Error Handling: Robust error handling and retry mechanisms
The scheduler service can be configured through environment variables:
# Set timezone for scheduler operations
SCHEDULER_TIMEZONE=UTC
# Completely disable the scheduler (useful for certain testing scenarios)
DISABLE_SCHEDULER=false
In testing environments (ENV=testing
), the scheduler has special behavior:
- Auto-Detection: Checks for existing reminders before starting
- Smart Disable: Automatically disables itself if no reminders exist
- Reduced Logging: Minimizes log output for cleaner test runs
- Manual Override: Can be completely disabled via
DISABLE_SCHEDULER=true
The scheduler implementation detects the testing environment and adjusts its behavior:
# Example from scheduler_service.py
def start(self):
"""Start the scheduler service."""
logger.info("Starting reminder scheduler service")
# Check if scheduler should be disabled via configuration
if getattr(settings, "DISABLE_SCHEDULER", False):
logger.info("Scheduler disabled via DISABLE_SCHEDULER setting")
return
# In testing environment, only start if there are reminders
if settings.ENV == "testing":
db = SessionLocal()
try:
reminder_count = db.query(Reminder).count()
if reminder_count == 0:
logger.info("No reminders found in testing environment. Scheduler will not start.")
return
logger.info(f"Found {reminder_count} reminders in testing environment. Starting scheduler.")
finally:
db.close()
# Continue with regular scheduler initialization...
This behavior makes testing more efficient by:
- Preventing unnecessary background processing during tests
- Reducing log noise in test output
- Allowing control over scheduler behavior in different test scenarios
You can verify the scheduler is running correctly by:
- Checking the application logs for "Scheduler service started" message
- Monitoring the "Processing due reminders" log messages (every minute)
- Creating a test reminder with a date in the past and verifying it's processed
The application implements the Repository Pattern to separate data access logic from business logic:
Each model has a corresponding repository class that handles all database operations:
# Example repository method
async def get_reminder_by_id(db: Session, reminder_id: int) -> Optional[Reminder]:
return db.query(Reminder).filter(Reminder.id == reminder_id).first()
This pattern provides several advantages:
- Abstraction: Services don't need to know how data is stored or retrieved
- Testability: Repositories can be mocked for service testing
- Maintainability: Database queries are centralized and reusable
Services use repositories to interact with the database:
# Example service using repository
async def process_reminder(reminder_id: int):
with db_session() as db:
reminder = await reminder_repository.get_reminder_by_id(db, reminder_id)
if reminder:
# Process the reminder...
Common methods implemented across repositories:
create_*
- Create new recordsget_*_by_id
- Retrieve single recordsget_*_by_*
- Filter based on criterialist_*
- Retrieve collections with filtering/paginationupdate_*
- Update existing recordsdelete_*
- Remove records
The service layer contains business logic and coordinates across multiple repositories:
- Stateless Services: All functions are stateless and take explicit dependencies
- Transaction Management: Services manage database transactions
- External Integration: Services handle external API calls
- Error Handling: Centralized error handling and retries