A feature-rich personal to-do web application built with Flask, PostgreSQL, and Twilio SMS integration. Manage your tasks efficiently with a clean, responsive interface and receive SMS reminders for important deadlines.
- Overview
- Features
- System Requirements
- Installation
- Configuration
- Usage
- Project Structure
- Database Schema
- API Endpoints
- Internationalization
- Development
- Deployment
- Troubleshooting
do2done is a personal task management web application that helps users organize their daily activities with an intuitive interface. Built using Flask and PostgreSQL, it offers user authentication, task CRUD operations, SMS notifications via Twilio, and multi-language support (English/Spanish).
- Create Tasks: Add new tasks with titles, descriptions, and due dates
- Edit Tasks: Update task details at any time
- Delete Tasks: Remove completed or unwanted tasks
- Task Status: Mark tasks as complete or incomplete
- Priority Levels: Organize tasks by priority
- Due Dates: Set deadlines for tasks
- User Authentication: Secure registration and login system
- User Profiles: Manage personal information
- Password Security: Encrypted password storage
- Session Management: Persistent login sessions
- Profile Customization: Update user details and preferences
- SMS Notifications: Twilio integration for task reminders
- Phone Number Validation: International phone number format support
- Customizable Notifications: Choose when to receive reminders
- Multi-language Support: English and Spanish translations
- Language Switching: Easy language toggle
- Localized Content: All UI elements translated
- Babel Integration: Professional translation management
- Python: 3.8 or higher
- PostgreSQL: 12 or higher
- pip: Latest version
- Web Browser: Modern browser (Chrome, Firefox, Safari, Edge)
- Twilio Account: For SMS functionality (free trial available)
- Storage: 100MB minimum
- RAM: 512MB minimum (1GB+ recommended)
git clone <repository-url>
cd do2donepython -m venv venv
# Windows
venv\Scripts\activate
# Linux/Mac
source venv/bin/activatepip install -r requirements.txtDependencies installed:
Flask==3.1.0- Web frameworkFlask-SQLAlchemy==3.1.1- ORM and database integrationFlask-Login==0.6.3- User session managementFlask-WTF==1.2.1- Form handling and validationFlask-Migrate==4.0.5- Database migrationspsycopg2-binary==2.9.10- PostgreSQL adaptertwilio==8.13.0- SMS integrationphonenumbers==8.13.32- Phone number validationpython-dotenv==1.0.1- Environment variable managementFlask-Babel- Internationalization support
Create Database:
# Access PostgreSQL
psql -U postgres
# Create database
CREATE DATABASE do2done;
# Create user (optional)
CREATE USER do2done_user WITH PASSWORD 'your_password';
GRANT ALL PRIVILEGES ON DATABASE do2done TO do2done_user;
# Exit
\qCreate a .env file in the project root:
# Database Configuration
DATABASE_URL=postgresql://postgres:your_password@localhost:5432/do2done
# Or use DB_PASSWORD if not using full DATABASE_URL
DB_PASSWORD=your_postgres_password
# Flask Secret Key (generate with: python -c "import os; print(os.urandom(24).hex())")
SECRET_KEY=your_secret_key_here
# Twilio Configuration (get from https://www.twilio.com/console)
TWILIO_ACCOUNT_SID=your_twilio_account_sid
TWILIO_AUTH_TOKEN=your_twilio_auth_token
TWILIO_PHONE_NUMBER=+1234567890# Run migrations
flask db upgrade
# If migrations don't exist, create them
flask db init
flask db migrate -m "Initial migration"
flask db upgradeflask runAccess at: http://127.0.0.1:5000/
Edit config.py for database settings:
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \
f"postgresql://postgres:{os.environ.get('DB_PASSWORD')}@localhost:5432/do2done"- Sign up for Twilio: Visit https://www.twilio.com/try-twilio
- Get Credentials: Find your Account SID and Auth Token in the console
- Get Phone Number: Acquire a Twilio phone number
- Add to .env: Update your environment variables
Configure session lifetime in app/__init__.py:
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(days=365)
app.config['SESSION_REFRESH_EACH_REQUEST'] = TrueSupported languages configured in config.py:
LANGUAGES = ['en', 'es']
BABEL_DEFAULT_LOCALE = 'en'- Navigate to registration page
- Enter username, email, and password
- Optionally add phone number for SMS notifications
- Submit to create account
- Enter username or email
- Enter password
- Check "Remember Me" for persistent session
- Click login
Create New Task:
- Click "New Task" button
- Enter task title (required)
- Add description (optional)
- Set due date (optional)
- Choose priority level
- Click "Save"
Edit Task:
- Click on task or "Edit" button
- Modify details
- Click "Update"
Complete Task:
- Check the checkbox next to task
- Task marked as complete
- Option to hide completed tasks
Delete Task:
- Click "Delete" button on task
- Confirm deletion
Setup:
- Go to Profile settings
- Add phone number with country code (e.g., +1234567890)
- Save profile
Receive Notifications:
- Automatic reminders for tasks due soon
- Manual notifications via task options
- Customizable notification timing
- Click language selector (EN/ES)
- Page refreshes with selected language
- Preference saved in cookies
do2done/
├── app/ # Application package
│ ├── __init__.py # App factory and configuration
│ ├── models/ # Database models
│ │ ├── users.py # User model
│ │ └── tasks.py # Task model
│ ├── routes/ # Route handlers
│ │ ├── users.py # User authentication routes
│ │ └── tasks.py # Task management routes
│ ├── static/ # Static files
│ │ ├── css/ # Stylesheets
│ │ ├── js/ # JavaScript files
│ │ └── images/ # Images
│ ├── templates/ # Jinja2 templates
│ │ ├── base.html # Base template
│ │ ├── login.html # Login page
│ │ ├── register.html # Registration page
│ │ ├── tasks.html # Task list page
│ │ └── profile.html # User profile page
│ └── translations/ # Language translations
│ ├── en/ # English translations
│ └── es/ # Spanish translations
├── migrations/ # Database migrations
├── config.py # Configuration file
├── requirements.txt # Python dependencies
├── .env # Environment variables (not in git)
└── README.md # This file
- id: Integer (Primary Key)
- username: String (Unique, Required)
- email: String (Unique, Required)
- password_hash: String (Required)
- phone_number: String (Optional)
- created_at: DateTime
- updated_at: DateTime
- tasks: Relationship to Task model- id: Integer (Primary Key)
- title: String (Required)
- description: Text (Optional)
- completed: Boolean (Default: False)
- priority: Integer (Default: 1)
- due_date: DateTime (Optional)
- created_at: DateTime
- updated_at: DateTime
- user_id: Integer (Foreign Key to User)
- user: Relationship to User modelRegistration:
GET /register- Display registration formPOST /register- Create new user account
Login:
GET /login- Display login formPOST /login- Authenticate user
Logout:
GET /logout- Log out current user
Profile:
GET /profile- View user profilePOST /profile- Update user profile
Task List:
GET /tasks- View all user tasksGET /tasks?filter=active- View active tasksGET /tasks?filter=completed- View completed tasks
Task CRUD:
POST /tasks/create- Create new taskGET /tasks/<id>/edit- Get task for editingPOST /tasks/<id>/update- Update existing taskPOST /tasks/<id>/delete- Delete taskPOST /tasks/<id>/toggle- Toggle task completion
SMS Notifications:
POST /tasks/<id>/notify- Send SMS reminder for task
Language:
GET /set-language/<lang>- Switch application language
Translation State:
GET /translation-state- Debug translation information
- English (en) - Default
- Spanish (es)
- Extract translatable strings:
pybabel extract -F babel.cfg -o messages.pot .- Initialize new language:
pybabel init -i messages.pot -d app/translations -l fr- Update existing translations:
pybabel update -i messages.pot -d app/translations-
Edit translation files:
- Navigate to
app/translations/<lang>/LC_MESSAGES/ - Edit
messages.pofile - Add translations for each
msgid
- Navigate to
-
Compile translations:
pybabel compile -d app/translationsIn Python:
from flask_babel import gettext as _
message = _('Hello World')In Templates:
{{ _('Welcome to do2done') }}# Set Flask environment
export FLASK_ENV=development # Linux/Mac
set FLASK_ENV=development # Windows
# Run with debug
flask run --debugCreate New Migration:
flask db migrate -m "Description of changes"Apply Migrations:
flask db upgradeRollback Migration:
flask db downgrade- Create Models: Define in
app/models/ - Create Routes: Add to
app/routes/ - Create Templates: Add to
app/templates/ - Register Blueprint: Update
app/__init__.py - Run Migrations: Create and apply database changes
- Test: Thoroughly test new functionality
from twilio.rest import Client
client = Client(account_sid, auth_token)
message = client.messages.create(
body="Test message",
from_=twilio_phone_number,
to=user_phone_number
)- Set Environment Variables:
export FLASK_ENV=production
export SECRET_KEY=<strong-secret-key>
export DATABASE_URL=<production-database-url>- Database Migration:
flask db upgrade- Use Production WSGI Server:
pip install gunicorn
gunicorn -w 4 -b 0.0.0.0:5000 app:app- Configure Reverse Proxy (nginx example):
server {
listen 80;
server_name your-domain.com;
location / {
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}Heroku:
# Create Procfile
echo "web: gunicorn app:app" > Procfile
# Deploy
heroku create your-app-name
heroku addons:create heroku-postgresql:hobby-dev
git push heroku main
heroku run flask db upgradeAWS/DigitalOcean:
- Set up Ubuntu server
- Install Python, PostgreSQL, nginx
- Clone repository
- Configure environment
- Set up systemd service
- Configure nginx reverse proxy
Docker:
FROM python:3.9
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:5000", "app:app"]Problem: Cannot connect to PostgreSQL
# Check PostgreSQL is running
sudo systemctl status postgresql # Linux
# Verify connection string in .env
# Check PostgreSQL allows connections from your IPProblem: Database doesn't exist
createdb do2done
flask db upgradeProblem: Migration conflicts
# Reset migrations
rm -rf migrations/
flask db init
flask db migrate -m "Initial migration"
flask db upgradeProblem: SMS not sending
- Verify Twilio credentials in .env
- Check account balance
- Verify phone numbers are in E.164 format (+1234567890)
- Check Twilio console for error messages
Problem: Invalid phone number
import phonenumbers
number = phonenumbers.parse(phone, "US")
if not phonenumbers.is_valid_number(number):
# Handle invalid numberProblem: Translations not appearing
# Recompile translations
pybabel compile -d app/translations
# Clear Flask cache
flask run # Restart applicationProblem: Users logged out unexpectedly
- Check SECRET_KEY is set and consistent
- Verify session configuration in
app/__init__.py - Check cookie settings
- Passwords hashed using Werkzeug security
- Never store plain-text passwords
- Use strong SECRET_KEY
- Never commit .env file to git
- Use strong, random values for secrets
- Rotate credentials regularly
- Use strong database passwords
- Limit database user permissions
- Regular backups
- Always use HTTPS in production
- Obtain SSL certificate (Let's Encrypt)
- Configure secure cookies
This is a personal project. For bug reports or feature requests, please open an issue.
See LICENSE file for details.
For issues or questions, please check existing documentation or open an issue on the repository.
Built with Flask - A personal task management solution