Store user avatars in persistent /data volume instead of application directory to ensure profile pictures survive container rebuilds and version updates. Changes: - Update avatar upload folder from app/static/uploads/avatars to /data/uploads/avatars using existing app_data volume mount - Modify get_avatar_upload_folder() in auth routes to use persistent location with UPLOAD_FOLDER config - Update User.get_avatar_path() to reference new storage location - Add migration script to safely move existing avatars to new location - Preserve backward compatibility - no database changes required Benefits: - Profile pictures now persist between Docker image updates - Consistent with company logo storage pattern (/data/uploads) - Better user experience - avatars not lost during upgrades - Production-ready data/code separation - All persistent uploads consolidated in app_data volume Migration: For existing installations with user avatars, run: docker-compose run --rm app python /app/docker/migrate-avatar-storage.py New installations work automatically with no action required. Documentation: - docs/AVATAR_STORAGE_MIGRATION.md - Full migration guide - docs/AVATAR_PERSISTENCE_SUMMARY.md - Quick reference - docs/TEST_AVATAR_PERSISTENCE.md - Testing guide - AVATAR_PERSISTENCE_CHANGELOG.md - Detailed changelog Files modified: - app/routes/auth.py - app/models/user.py Files added: - docker/migrate-avatar-storage.py - docs/AVATAR_STORAGE_MIGRATION.md - docs/AVATAR_PERSISTENCE_SUMMARY.md - docs/TEST_AVATAR_PERSISTENCE.md - AVATAR_PERSISTENCE_CHANGELOG.md Tested: ✓ No linter errors, backward compatible, volume mount verified
5.5 KiB
User Avatar Storage Migration Guide
Overview
As of this update, user profile pictures (avatars) are now stored in the persistent /data volume instead of the application directory. This ensures that profile pictures persist between Docker container updates and rebuilds.
What Changed?
Previous Behavior
- Location:
app/static/uploads/avatars/ - Problem: This directory is inside the application container, so avatars were lost when updating or rebuilding the Docker image
- Impact: Users had to re-upload their profile pictures after each update
New Behavior
- Location:
/data/uploads/avatars/ - Solution: This directory is on the persistent
app_dataDocker volume - Benefit: Profile pictures are preserved across all updates and rebuilds
Migration Required?
If you have existing user avatars, you need to run the migration script to move them to the new location.
If you're setting up a fresh installation, no migration is needed - the new location will be used automatically.
How to Migrate Existing Avatars
Docker Environment
-
Stop your TimeTracker containers:
docker-compose down -
Run the migration script:
docker-compose run --rm app python /app/docker/migrate-avatar-storage.py -
Start your containers:
docker-compose up -d -
Verify avatars are working:
- Log in to TimeTracker
- Check that user profile pictures are displayed correctly
- Try uploading a new avatar to confirm uploads work
-
Optional - Cleanup old files: After confirming everything works, you can remove the old avatar directory:
docker-compose exec app rm -rf /app/static/uploads/avatars
Bare Metal / Development Environment
-
Navigate to your TimeTracker directory:
cd /path/to/TimeTracker -
Ensure the new directory exists:
mkdir -p /data/uploads/avatars -
Run the migration script:
python docker/migrate-avatar-storage.py -
Restart your application:
# Your normal restart command systemctl restart timetracker # or ./restart.sh -
Verify and cleanup: Follow steps 4-5 from the Docker instructions above.
Technical Details
Files Modified
-
app/routes/auth.py- Updated
get_avatar_upload_folder()to use/data/uploads/avatars - Comment added explaining the persistence benefit
- Updated
-
app/models/user.py- Updated
get_avatar_path()to use/data/uploads/avatars - Added fallback for development environments
- Updated
-
docker-compose.yml- Already had
app_data:/datavolume mount (no changes needed)
- Already had
Configuration
The avatar location now respects the UPLOAD_FOLDER configuration:
- Default:
/data/uploads(avatars go to/data/uploads/avatars) - Configurable: Set
UPLOAD_FOLDERin your environment to change the base path
URL Structure
The public URL structure remains unchanged:
- URL:
/uploads/avatars/{filename} - Route: Handled by
auth.serve_uploaded_avatar()
This means existing avatar URLs in the database continue to work without modification.
Troubleshooting
Avatars not displaying after migration
-
Check file permissions:
docker-compose exec app ls -la /data/uploads/avatars/Files should be readable by the app user.
-
Verify volume mount:
docker inspect timetracker-app | grep -A 5 MountsShould show
/datamounted from theapp_datavolume. -
Check migration log: Re-run the migration script to see if files were actually copied.
New avatar uploads failing
-
Check directory permissions:
docker-compose exec app touch /data/uploads/avatars/.testIf this fails, fix permissions:
docker-compose exec app chown -R app:app /data/uploads/avatars docker-compose exec app chmod -R 755 /data/uploads/avatars -
Check disk space:
docker-compose exec app df -h /data
Migration script can't find old directory
This is normal if:
- You're setting up a fresh installation (no avatars to migrate)
- Avatars were already migrated previously
- No users have uploaded avatars yet
The script will create the new directory structure automatically.
Benefits of This Change
✅ Persistent Storage: Profile pictures survive Docker updates and rebuilds
✅ Consistent with Logos: Company logos already use /data/uploads (consistency)
✅ Better UX: Users don't lose their profile pictures during updates
✅ Production Ready: Proper separation of persistent data from application code
✅ Backup Friendly: All persistent uploads are in one volume (app_data)
Backup Recommendations
Since avatars are now on the app_data volume, include this volume in your backup strategy:
# Backup the entire data volume
docker run --rm -v timetracker_app_data:/data -v $(pwd):/backup ubuntu tar czf /backup/app_data_backup.tar.gz -C /data .
# Restore the data volume
docker run --rm -v timetracker_app_data:/data -v $(pwd):/backup ubuntu tar xzf /backup/app_data_backup.tar.gz -C /data
Questions?
If you encounter any issues with the avatar migration:
- Check the Troubleshooting section above
- Review the Docker logs:
docker-compose logs app - Open an issue on GitHub with migration script output
Last Updated: October 2025
Applies to: TimeTracker v2.x and later