Files
TimeTracker/docs/TEST_AVATAR_PERSISTENCE.md
Dries Peeters 34946e1b80 feat: Make user profile pictures persistent across Docker updates
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
2025-10-22 11:12:11 +02:00

4.8 KiB
Raw Blame History

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

  1. Log in to TimeTracker
  2. Navigate to Profile → Edit Profile
  3. Upload a profile picture
  4. 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
  1. Log back in to TimeTracker
  2. 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
  1. Log in to TimeTracker
  2. Check if your profile picture still displays

Expected Result: Avatar persists even after container rebuild


5. Test New Avatar Upload

  1. Go to Profile → Edit Profile
  2. Upload a different profile picture
  3. Verify the new picture displays

Expected Result: New avatar displays correctly


6. Test Avatar Removal

  1. Go to Profile → Edit Profile
  2. Click "Remove current picture"
  3. 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