mirror of
https://github.com/DRYTRIX/TimeTracker.git
synced 2026-01-06 03:30:25 -06:00
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
4.8 KiB
4.8 KiB
Testing Avatar Persistence
Quick Test Checklist
Use this checklist to verify that profile pictures persist correctly across container updates.
Prerequisites
- TimeTracker is running
- At least one user account exists
- You have admin access (if testing other users)
Test Steps
1. Upload a Profile Picture
- Log in to TimeTracker
- Navigate to Profile → Edit Profile
- Upload a profile picture
- Save and verify the picture displays
Expected Result: ✅ Avatar displays in header and profile page
2. Verify Storage Location
# Check that the avatar was saved to /data volume
docker-compose exec app ls -la /data/uploads/avatars/
# You should see files like: avatar_1_a1b2c3d4.png
Expected Result: ✅ Avatar file exists in /data/uploads/avatars/
3. Test Persistence Across Restart
# Restart the container
docker-compose restart app
# Wait for container to be healthy
docker-compose ps
- Log back in to TimeTracker
- Check if your profile picture still displays
Expected Result: ✅ Avatar still displays after restart
4. Test Persistence Across Rebuild
# Stop and remove containers
docker-compose down
# Rebuild the image (simulates an update)
docker-compose build app
# Start containers
docker-compose up -d
# Wait for startup
sleep 10
- Log in to TimeTracker
- Check if your profile picture still displays
Expected Result: ✅ Avatar persists even after container rebuild
5. Test New Avatar Upload
- Go to Profile → Edit Profile
- Upload a different profile picture
- Verify the new picture displays
Expected Result: ✅ New avatar displays correctly
6. Test Avatar Removal
- Go to Profile → Edit Profile
- Click "Remove current picture"
- Verify the avatar is removed and initials are shown
Expected Result: ✅ Avatar removed, fallback to initials display
7. Verify Old Location is Empty (After Migration)
# Check old location (should be empty after migration)
docker-compose exec app ls -la /app/static/uploads/avatars/ 2>&1
Expected Result: ✅ Directory doesn't exist or is empty
Test Matrix
| Test Case | Expected Behavior | Status |
|---|---|---|
| Upload avatar | Saved to /data/uploads/avatars/ |
⬜ |
| Display avatar | Shows in header & profile | ⬜ |
| Container restart | Avatar persists | ⬜ |
| Container rebuild | Avatar persists | ⬜ |
| Upload new avatar | Old file removed, new file saved | ⬜ |
| Remove avatar | File deleted, fallback to initials | ⬜ |
| Volume check | Files in /data/uploads/avatars/ |
⬜ |
Troubleshooting
Avatar doesn't display after upload
# Check file permissions
docker-compose exec app ls -la /data/uploads/avatars/
# Fix permissions if needed
docker-compose exec app chown -R app:app /data/uploads/avatars/
docker-compose exec app chmod -R 755 /data/uploads/avatars/
Avatar lost after rebuild
# Verify volume is mounted
docker inspect timetracker-app | grep -A 10 Mounts
# Check if app_data volume exists
docker volume ls | grep app_data
# Inspect volume
docker volume inspect timetracker_app_data
Migration didn't work
# Re-run migration script with verbose output
docker-compose run --rm app python /app/docker/migrate-avatar-storage.py
# Manually check both locations
docker-compose exec app ls -la /app/static/uploads/avatars/
docker-compose exec app ls -la /data/uploads/avatars/
Automated Test Script
You can also run this automated test (save as test_avatar_persistence.sh):
#!/bin/bash
echo "Testing Avatar Persistence..."
echo ""
# Test 1: Check volume mount
echo "1. Checking volume mount..."
if docker inspect timetracker-app | grep -q "/data"; then
echo " ✅ Volume mounted"
else
echo " ❌ Volume NOT mounted"
exit 1
fi
# Test 2: Check directory exists
echo "2. Checking avatar directory..."
if docker-compose exec -T app test -d /data/uploads/avatars; then
echo " ✅ Directory exists"
else
echo " ❌ Directory NOT found"
exit 1
fi
# Test 3: Check write permissions
echo "3. Checking write permissions..."
if docker-compose exec -T app touch /data/uploads/avatars/.test 2>/dev/null; then
docker-compose exec -T app rm /data/uploads/avatars/.test
echo " ✅ Directory is writable"
else
echo " ❌ Directory NOT writable"
exit 1
fi
# Test 4: Count avatars
echo "4. Counting avatar files..."
count=$(docker-compose exec -T app sh -c 'ls -1 /data/uploads/avatars/ 2>/dev/null | wc -l')
echo " ℹ️ Found $count avatar file(s)"
echo ""
echo "✅ All automated checks passed!"
echo "📝 Manual testing required: Upload, restart, rebuild tests"
Run with: bash test_avatar_persistence.sh
Date: October 2025
Purpose: Verify profile picture persistence across updates