A .NET 8 Web API backend for managing procrastination reminders with smart scheduling. This is a one-way API where clients send reminders to the server, and the server handles them internally.
- User Management: Create users by phone number (auto-created when needed)
- Smart Reminders: Create reminders with intelligent scheduling based on timeline preferences
- Database Integration: PostgreSQL database with Entity Framework Core
- One-Way Communication: Clients send data, server processes internally
- Automatic Message Dispatch: Background service automatically sends reminders via configurable messaging providers
- Extensible Architecture: Easy to swap between SMS, email, push notifications, etc.
- Smart Scheduling: Calculates optimal reminder times based on timeline preferences
- Simple Retry Logic: Implicit interval-based retries through service cycle with configurable max attempts
- .NET 8 SDK
- PostgreSQL database
- Entity Framework Core tools
- Messaging service account (Twilio for SMS, SendGrid for email, etc.)
- Create a PostgreSQL database:
CREATE DATABASE procrastinator;
CREATE DATABASE procrastinator_dev;-
Update the connection strings in
appsettings.jsonandappsettings.Development.jsonwith your database credentials. -
Run the database creation script:
psql -d procrastinator -f Scripts/CreateTables.sql- (Optional) Insert sample data:
psql -d procrastinator -f Scripts/InsertSampleData.sql- Create a Twilio account at twilio.com
- Get your Account SID and Auth Token from the Twilio Console
- Get a Twilio phone number for sending SMS
- Update the Twilio configuration in
appsettings.json:
"Twilio": {
"AccountSid": "your_actual_account_sid",
"AuthToken": "your_actual_auth_token",
"FromPhoneNumber": "+1234567890"
}- To use email instead, change the service registration in
Program.cs:
// Change this line:
builder.Services.AddScoped<IMessageService, TwilioService>();
// To this:
builder.Services.AddScoped<IMessageService, EmailMessageService>();- Implement
IMessageServiceinterface - Register your service in
Program.cs - No changes needed to the dispatch service!
Configure application behavior in appsettings.json:
"AppSettings": {
"MaxRetries": 3,
"ServiceCheckIntervalMinutes": 1,
"DefaultTimeZone": "UTC"
}- MaxRetries: Maximum number of delivery attempts (default: 3)
- ServiceCheckIntervalMinutes: Minutes between service cycles (default: 1)
- DefaultTimeZone: Default timezone for the application (default: UTC)
- Install EF Core tools globally:
dotnet tool install --global dotnet-ef- Create initial migration:
dotnet ef migrations add InitialCreate- Update database:
dotnet ef database updatedotnet runThe API will be available at https://localhost:7000 (or your configured port).
POST /api/User- Create a new user
POST /api/Reminder- Create a new reminder (auto-creates user if needed)
- Client sends reminder request to
POST /api/Reminder - Server processes the request:
- Finds or creates user based on phone number
- Calculates optimal reminder time using smart scheduling
- Stores reminder in database with retry tracking
- Background service runs every configured interval:
- Checks for all incomplete reminders that haven't exhausted retries
- Sends messages via configured messaging provider
- Implements simple retry logic with implicit intervals
- Marks reminders as completed after successful delivery
- Server handles everything internally (no client retrieval needed)
- Runs every configured interval (default: 1 minute) to check for due reminders
- Automatically sends messages via configured messaging provider when reminders are due
- Implements simple retry logic with configurable max attempts
- Implicit intervals - natural service cycle provides retry timing
- Configurable timing - adjust service check interval via AppSettings
- Marks reminders as completed after successful dispatch
- Handles errors gracefully with comprehensive logging
- Provider-agnostic - works with any messaging service
The system uses a centralized configuration approach with multiple settings:
"AppSettings": {
"MaxRetries": 3,
"ServiceCheckIntervalMinutes": 1,
"DefaultTimeZone": "UTC"
}- Centralized settings - All app configuration in one place
- Easy to adjust - Change behavior without code changes
- Environment-specific - Different settings per environment
- Type-safe access - Strongly typed configuration values
MaxRetries: Maximum delivery attempts (configurable in AppSettings)
- Implicit intervals: Service runs every configured interval, providing natural retry timing
- Simple logic: Just increment retry count on failure
- No complex scheduling: Failed reminders get retried on next service cycle
- Service overload protection: Natural delays prevent overwhelming messaging services
RetryCount: Number of failed attempts (starts at 0)IsCompleted: Set to true after successful delivery
- Initial delivery: When
ReminderDateTimeis reached - On failure: Increment
RetryCount, save to database - Next service cycle: Service finds all incomplete reminders with
RetryCount < MaxRetries - Natural interval: Configured service cycle provides retry timing
- After max retries: Reminder marked as permanently failed
The system uses a generic IMessageService interface that can be implemented by different providers:
public interface IMessageService
{
Task<bool> SendMessageAsync(string recipient, string message);
}TwilioService- Sends SMS via Twilio (current default)EmailMessageService- Sends emails (example implementation)- Easy to add more - Slack, Discord, Push Notifications, etc.
To change messaging providers, just update one line in Program.cs:
// For SMS:
builder.Services.AddScoped<IMessageService, TwilioService>();
// For Email:
builder.Services.AddScoped<IMessageService, EmailMessageService>();
// For Custom Provider:
builder.Services.AddScoped<IMessageService, YourCustomService>();Id: Primary keyPhoneNumber: Unique phone number identifierCreatedAt: User creation timestampUpdatedAt: Last update timestamp
Id: Primary keyUserId: Foreign key to UserMessage: Reminder message textReminderDateTime: Calculated reminder timeReminderTimeline: Timeline preference (Today, Tomorrow, ThisWeek, etc.)IsCompleted: Completion status (set to true after successful delivery)RetryCount: Number of failed delivery attemptsCreatedAt: Reminder creation timestampUpdatedAt: Last update timestamp
The system automatically calculates optimal reminder times based on the selected timeline:
- Today: Random time between now and midnight
- Tomorrow: Random time tomorrow
- ThisWeek: Random time between now and end of week
- NextWeek: Random time next week
- ThisMonth: Random time between now and end of month
- NextMonth: Random time next month
- LaterThisYear: Random time between now and end of year
- NextYear: Random time next year
- Automatic: No manual intervention required
- Reliable: Background service ensures delivery with retry logic
- Tracked: All message attempts and retries are logged and tracked
- Error Handling: Failed attempts trigger retries on next service cycle
- Service Protection: Natural service intervals prevent overwhelming messaging services
- Provider-agnostic: Works with any messaging service
- Configurable: Adjustable retry limits and service timing via AppSettings
Once running, visit /swagger to see the interactive API documentation.
- One-way communication: Clients only send data, never retrieve it
- Automatic user creation: Users are created automatically when creating reminders
- Internal processing: All reminder management happens server-side
- Background processing: Reminders are automatically dispatched via configurable messaging
- Simple retry logic: Implicit interval-based retries through service cycle
- Centralized configuration: All app settings in one place
- Extensible architecture: Easy to add new messaging providers
- All timestamps are stored in UTC
- Database includes automatic triggers for updating
UpdatedAtfields - Proper indexing for performance on common queries