# Aniworld Web Application Development Instructions This document provides detailed tasks for AI agents to implement a modern web application for the Aniworld anime download manager. All tasks should follow the coding guidelines specified in the project's copilot instructions. ## Project Overview The goal is to create a FastAPI-based web application that provides a modern interface for the existing Aniworld anime download functionality. The core anime logic should remain in `SeriesApp.py` while the web layer provides REST API endpoints and a responsive UI. ## Architecture Principles - **Single Responsibility**: Each file/class has one clear purpose - **Dependency Injection**: Use FastAPI's dependency system - **Clean Separation**: Web layer calls core logic, never the reverse - **File Size Limit**: Maximum 500 lines per file - **Type Hints**: Use comprehensive type annotations - **Error Handling**: Proper exception handling and logging ## Additional Implementation Guidelines ### Code Style and Standards - **Type Hints**: Use comprehensive type annotations throughout all modules - **Docstrings**: Follow PEP 257 for function and class documentation - **Error Handling**: Implement custom exception classes with meaningful messages - **Logging**: Use structured logging with appropriate log levels - **Security**: Validate all inputs and sanitize outputs - **Performance**: Use async/await patterns for I/O operations ## ๐Ÿ“ž Escalation If you encounter: - Architecture issues requiring design decisions - Tests that conflict with documented requirements - Breaking changes needed - Unclear requirements or expectations **Document the issue and escalate rather than guessing.** --- ## ๐Ÿ“š Helpful Commands ```bash # Run all tests conda run -n AniWorld python -m pytest tests/ -v --tb=short # Run specific test file conda run -n AniWorld python -m pytest tests/unit/test_websocket_service.py -v # Run specific test class conda run -n AniWorld python -m pytest tests/unit/test_websocket_service.py::TestWebSocketService -v # Run specific test conda run -n AniWorld python -m pytest tests/unit/test_websocket_service.py::TestWebSocketService::test_broadcast_download_progress -v # Run with extra verbosity conda run -n AniWorld python -m pytest tests/ -vv # Run with full traceback conda run -n AniWorld python -m pytest tests/ -v --tb=long # Run and stop at first failure conda run -n AniWorld python -m pytest tests/ -v -x # Run tests matching pattern conda run -n AniWorld python -m pytest tests/ -v -k "auth" # Show all print statements conda run -n AniWorld python -m pytest tests/ -v -s #Run app conda run -n AniWorld python -m uvicorn src.server.fastapi_app:app --host 127.0.0.1 --port 8000 --reload ``` --- ## Implementation Notes 1. **Incremental Development**: Implement features incrementally, testing each component thoroughly before moving to the next 2. **Code Review**: Review all generated code for adherence to project standards 3. **Documentation**: Document all public APIs and complex logic 4. **Testing**: Maintain test coverage above 80% for all new code 5. **Performance**: Profile and optimize critical paths, especially download and streaming operations 6. **Security**: Regular security audits and dependency updates 7. **Monitoring**: Implement comprehensive monitoring and alerting 8. **Maintenance**: Plan for regular maintenance and updates ## Task Completion Checklist For each task completed: - [ ] Implementation follows coding standards - [ ] Unit tests written and passing - [ ] Integration tests passing - [ ] Documentation updated - [ ] Error handling implemented - [ ] Logging added - [ ] Security considerations addressed - [ ] Performance validated - [ ] Code reviewed - [ ] Task marked as complete in instructions.md - [ ] Infrastructure.md updated - [ ] Changes committed to git; keep your messages in git short and clear - [ ] Take the next task --- ### Prerequisites 1. Server is running: `conda run -n AniWorld python -m uvicorn src.server.fastapi_app:app --host 127.0.0.1 --port 8000 --reload` 2. Password: `Hallo123!` 3. Login via browser at `http://127.0.0.1:8000/login` ### Notes - This is a simplification that removes complexity while maintaining core functionality - Improves user experience with explicit manual control - Easier to understand, test, and maintain - Good foundation for future enhancements if needed --- ## โœ… Completed: Download Queue Migration to SQLite Database The download queue has been successfully migrated from JSON file to SQLite database: | Component | Status | Description | | ---------------------- | --------- | ------------------------------------------------ | | QueueRepository | โœ… Done | `src/server/services/queue_repository.py` | | DownloadService | โœ… Done | Refactored to use repository pattern | | Application Startup | โœ… Done | Queue restored from database on startup | | API Endpoints | โœ… Done | All endpoints work with database-backed queue | | Tests Updated | โœ… Done | All 1104 tests passing with MockQueueRepository | | Documentation Updated | โœ… Done | `infrastructure.md` updated with new architecture| **Key Changes:** - `DownloadService` no longer uses `persistence_path` parameter - Queue state is persisted to SQLite via `QueueRepository` - In-memory cache maintained for performance - All tests use `MockQueueRepository` fixture --- ## ๐Ÿงช Tests for Download Queue Database Migration ### Unit Tests **File:** `tests/unit/test_queue_repository.py` ```python """Unit tests for QueueRepository database adapter.""" import pytest from unittest.mock import AsyncMock, MagicMock, patch from datetime import datetime, timezone from src.server.services.queue_repository import QueueRepository from src.server.models.download import DownloadItem, DownloadStatus, DownloadPriority from src.server.database.models import DownloadQueueItem as DBDownloadQueueItem class TestQueueRepository: """Test suite for QueueRepository.""" @pytest.fixture def mock_db_session(self): """Create mock database session.""" session = AsyncMock() return session @pytest.fixture def repository(self, mock_db_session): """Create repository instance with mock session.""" return QueueRepository(db_session_factory=lambda: mock_db_session) @pytest.fixture def sample_download_item(self): """Create sample DownloadItem for testing.""" return DownloadItem( id="test-uuid-123", series_key="attack-on-titan", series_name="Attack on Titan", season=1, episode=5, status=DownloadStatus.PENDING, priority=DownloadPriority.NORMAL, progress_percent=0.0, downloaded_bytes=0, total_bytes=None, ) # === Conversion Tests === async def test_convert_to_db_model(self, repository, sample_download_item): """Test converting DownloadItem to database model.""" # Arrange series_id = 42 # Act db_item = repository._to_db_model(sample_download_item, series_id) # Assert assert db_item.series_id == series_id assert db_item.season == sample_download_item.season assert db_item.episode_number == sample_download_item.episode assert db_item.status == sample_download_item.status assert db_item.priority == sample_download_item.priority async def test_convert_from_db_model(self, repository): """Test converting database model to DownloadItem.""" # Arrange db_item = MagicMock() db_item.id = 1 db_item.series_id = 42 db_item.series.key = "attack-on-titan" db_item.series.name = "Attack on Titan" db_item.season = 1 db_item.episode_number = 5 db_item.status = DownloadStatus.PENDING db_item.priority = DownloadPriority.NORMAL db_item.progress_percent = 25.5 db_item.downloaded_bytes = 1024000 db_item.total_bytes = 4096000 # Act item = repository._from_db_model(db_item) # Assert assert item.series_key == "attack-on-titan" assert item.series_name == "Attack on Titan" assert item.season == 1 assert item.episode == 5 assert item.progress_percent == 25.5 # === CRUD Operation Tests === async def test_save_item_creates_new_record(self, repository, mock_db_session, sample_download_item): """Test saving a new download item to database.""" # Arrange mock_db_session.execute.return_value.scalar_one_or_none.return_value = MagicMock(id=42) # Act result = await repository.save_item(sample_download_item) # Assert mock_db_session.add.assert_called_once() mock_db_session.flush.assert_called_once() assert result is not None async def test_get_pending_items_returns_ordered_list(self, repository, mock_db_session): """Test retrieving pending items ordered by priority.""" # Arrange mock_items = [MagicMock(), MagicMock()] mock_db_session.execute.return_value.scalars.return_value.all.return_value = mock_items # Act result = await repository.get_pending_items() # Assert assert len(result) == 2 mock_db_session.execute.assert_called_once() async def test_update_status_success(self, repository, mock_db_session): """Test updating item status.""" # Arrange mock_item = MagicMock() mock_db_session.execute.return_value.scalar_one_or_none.return_value = mock_item # Act result = await repository.update_status("test-id", DownloadStatus.DOWNLOADING) # Assert assert result is True assert mock_item.status == DownloadStatus.DOWNLOADING async def test_update_status_item_not_found(self, repository, mock_db_session): """Test updating status for non-existent item.""" # Arrange mock_db_session.execute.return_value.scalar_one_or_none.return_value = None # Act result = await repository.update_status("non-existent", DownloadStatus.DOWNLOADING) # Assert assert result is False async def test_update_progress(self, repository, mock_db_session): """Test updating download progress.""" # Arrange mock_item = MagicMock() mock_db_session.execute.return_value.scalar_one_or_none.return_value = mock_item # Act result = await repository.update_progress( item_id="test-id", progress=50.0, downloaded=2048000, total=4096000, speed=1024000.0 ) # Assert assert result is True assert mock_item.progress_percent == 50.0 assert mock_item.downloaded_bytes == 2048000 async def test_delete_item_success(self, repository, mock_db_session): """Test deleting download item.""" # Arrange mock_db_session.execute.return_value.rowcount = 1 # Act result = await repository.delete_item("test-id") # Assert assert result is True async def test_clear_completed_returns_count(self, repository, mock_db_session): """Test clearing completed items returns count.""" # Arrange mock_db_session.execute.return_value.rowcount = 5 # Act result = await repository.clear_completed() # Assert assert result == 5 class TestQueueRepositoryErrorHandling: """Test error handling in QueueRepository.""" @pytest.fixture def mock_db_session(self): """Create mock database session.""" return AsyncMock() @pytest.fixture def repository(self, mock_db_session): """Create repository instance.""" return QueueRepository(db_session_factory=lambda: mock_db_session) async def test_save_item_handles_database_error(self, repository, mock_db_session): """Test handling database errors on save.""" # Arrange mock_db_session.execute.side_effect = Exception("Database connection failed") # Act & Assert with pytest.raises(Exception): await repository.save_item(MagicMock()) async def test_get_items_handles_database_error(self, repository, mock_db_session): """Test handling database errors on query.""" # Arrange mock_db_session.execute.side_effect = Exception("Query failed") # Act & Assert with pytest.raises(Exception): await repository.get_pending_items() ``` --- **File:** `tests/unit/test_download_service_database.py` ```python """Unit tests for DownloadService with database persistence.""" import pytest from unittest.mock import AsyncMock, MagicMock, patch from datetime import datetime, timezone from src.server.services.download_service import DownloadService from src.server.models.download import DownloadItem, DownloadStatus, DownloadPriority class TestDownloadServiceDatabasePersistence: """Test DownloadService database persistence.""" @pytest.fixture def mock_anime_service(self): """Create mock anime service.""" return AsyncMock() @pytest.fixture def mock_queue_repository(self): """Create mock queue repository.""" repo = AsyncMock() repo.get_pending_items.return_value = [] repo.get_active_item.return_value = None repo.get_completed_items.return_value = [] repo.get_failed_items.return_value = [] return repo @pytest.fixture def download_service(self, mock_anime_service, mock_queue_repository): """Create download service with mocked dependencies.""" return DownloadService( anime_service=mock_anime_service, queue_repository=mock_queue_repository, ) # === Persistence Tests === async def test_add_to_queue_saves_to_database( self, download_service, mock_queue_repository ): """Test that adding to queue persists to database.""" # Arrange mock_queue_repository.save_item.return_value = MagicMock(id="new-id") # Act result = await download_service.add_to_queue( series_key="test-series", season=1, episode=1, ) # Assert mock_queue_repository.save_item.assert_called_once() async def test_startup_loads_from_database( self, mock_anime_service, mock_queue_repository ): """Test that startup loads queue state from database.""" # Arrange pending_items = [ MagicMock(id="1", status=DownloadStatus.PENDING), MagicMock(id="2", status=DownloadStatus.PENDING), ] mock_queue_repository.get_pending_items.return_value = pending_items # Act service = DownloadService( anime_service=mock_anime_service, queue_repository=mock_queue_repository, ) await service.initialize() # Assert mock_queue_repository.get_pending_items.assert_called() async def test_download_completion_updates_database( self, download_service, mock_queue_repository ): """Test that download completion updates database status.""" # Arrange item = MagicMock(id="test-id") # Act await download_service._mark_completed(item) # Assert mock_queue_repository.update_status.assert_called_with( "test-id", DownloadStatus.COMPLETED, error=None ) async def test_download_failure_updates_database( self, download_service, mock_queue_repository ): """Test that download failure updates database with error.""" # Arrange item = MagicMock(id="test-id") error_message = "Network timeout" # Act await download_service._mark_failed(item, error_message) # Assert mock_queue_repository.update_status.assert_called_with( "test-id", DownloadStatus.FAILED, error=error_message ) async def test_progress_update_persists_to_database( self, download_service, mock_queue_repository ): """Test that progress updates are persisted.""" # Arrange item = MagicMock(id="test-id") # Act await download_service._update_progress( item, progress=50.0, downloaded=2048, total=4096, speed=1024.0 ) # Assert mock_queue_repository.update_progress.assert_called_with( item_id="test-id", progress=50.0, downloaded=2048, total=4096, speed=1024.0, ) async def test_remove_from_queue_deletes_from_database( self, download_service, mock_queue_repository ): """Test that removing from queue deletes from database.""" # Arrange mock_queue_repository.delete_item.return_value = True # Act result = await download_service.remove_from_queue("test-id") # Assert mock_queue_repository.delete_item.assert_called_with("test-id") assert result is True async def test_clear_completed_clears_database( self, download_service, mock_queue_repository ): """Test that clearing completed items updates database.""" # Arrange mock_queue_repository.clear_completed.return_value = 5 # Act result = await download_service.clear_completed() # Assert mock_queue_repository.clear_completed.assert_called_once() assert result == 5 class TestDownloadServiceNoJsonFile: """Verify DownloadService no longer uses JSON files.""" async def test_no_json_file_operations(self): """Verify no JSON file read/write operations exist.""" import inspect from src.server.services.download_service import DownloadService source = inspect.getsource(DownloadService) # Assert no JSON file operations assert "download_queue.json" not in source assert "_load_queue" not in source or "database" in source.lower() assert "_save_queue" not in source or "database" in source.lower() ``` --- ### Integration Tests **File:** `tests/integration/test_queue_database_integration.py` ```python """Integration tests for download queue database operations.""" import pytest from datetime import datetime, timezone from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession from sqlalchemy.orm import sessionmaker from src.server.database.base import Base from src.server.database.models import AnimeSeries, DownloadQueueItem, DownloadStatus, DownloadPriority from src.server.database.service import DownloadQueueService, AnimeSeriesService from src.server.services.queue_repository import QueueRepository @pytest.fixture async def async_engine(): """Create async test database engine.""" engine = create_async_engine("sqlite+aiosqlite:///:memory:", echo=False) async with engine.begin() as conn: await conn.run_sync(Base.metadata.create_all) yield engine await engine.dispose() @pytest.fixture async def async_session(async_engine): """Create async session for tests.""" async_session_maker = sessionmaker( async_engine, class_=AsyncSession, expire_on_commit=False ) async with async_session_maker() as session: yield session await session.rollback() @pytest.fixture async def test_series(async_session): """Create test anime series.""" series = await AnimeSeriesService.create( db=async_session, key="test-anime", name="Test Anime", site="https://example.com/test-anime", folder="Test Anime (2024)", ) await async_session.commit() return series class TestQueueDatabaseIntegration: """Integration tests for queue database operations.""" async def test_create_and_retrieve_queue_item(self, async_session, test_series): """Test creating and retrieving a queue item.""" # Create item = await DownloadQueueService.create( db=async_session, series_id=test_series.id, season=1, episode_number=5, priority=DownloadPriority.HIGH, ) await async_session.commit() # Retrieve retrieved = await DownloadQueueService.get_by_id(async_session, item.id) # Assert assert retrieved is not None assert retrieved.series_id == test_series.id assert retrieved.season == 1 assert retrieved.episode_number == 5 assert retrieved.priority == DownloadPriority.HIGH assert retrieved.status == DownloadStatus.PENDING async def test_update_download_progress(self, async_session, test_series): """Test updating download progress.""" # Create item item = await DownloadQueueService.create( db=async_session, series_id=test_series.id, season=1, episode_number=1, ) await async_session.commit() # Update progress updated = await DownloadQueueService.update_progress( db=async_session, item_id=item.id, progress_percent=75.5, downloaded_bytes=3072000, total_bytes=4096000, download_speed=1024000.0, ) await async_session.commit() # Assert assert updated.progress_percent == 75.5 assert updated.downloaded_bytes == 3072000 assert updated.total_bytes == 4096000 assert updated.download_speed == 1024000.0 async def test_status_transitions(self, async_session, test_series): """Test download status transitions.""" # Create pending item item = await DownloadQueueService.create( db=async_session, series_id=test_series.id, season=1, episode_number=1, ) await async_session.commit() assert item.status == DownloadStatus.PENDING # Transition to downloading item = await DownloadQueueService.update_status( async_session, item.id, DownloadStatus.DOWNLOADING ) await async_session.commit() assert item.status == DownloadStatus.DOWNLOADING assert item.started_at is not None # Transition to completed item = await DownloadQueueService.update_status( async_session, item.id, DownloadStatus.COMPLETED ) await async_session.commit() assert item.status == DownloadStatus.COMPLETED assert item.completed_at is not None async def test_failed_download_with_retry(self, async_session, test_series): """Test failed download with error message and retry count.""" # Create item item = await DownloadQueueService.create( db=async_session, series_id=test_series.id, season=1, episode_number=1, ) await async_session.commit() # Mark as failed with error item = await DownloadQueueService.update_status( async_session, item.id, DownloadStatus.FAILED, error_message="Connection timeout", ) await async_session.commit() # Assert assert item.status == DownloadStatus.FAILED assert item.error_message == "Connection timeout" assert item.retry_count == 1 async def test_get_pending_items_ordered_by_priority(self, async_session, test_series): """Test retrieving pending items ordered by priority.""" # Create items with different priorities await DownloadQueueService.create( async_session, test_series.id, 1, 1, priority=DownloadPriority.LOW ) await DownloadQueueService.create( async_session, test_series.id, 1, 2, priority=DownloadPriority.HIGH ) await DownloadQueueService.create( async_session, test_series.id, 1, 3, priority=DownloadPriority.NORMAL ) await async_session.commit() # Get pending items pending = await DownloadQueueService.get_pending(async_session) # Assert order: HIGH -> NORMAL -> LOW assert len(pending) == 3 assert pending[0].priority == DownloadPriority.HIGH assert pending[1].priority == DownloadPriority.NORMAL assert pending[2].priority == DownloadPriority.LOW async def test_clear_completed_items(self, async_session, test_series): """Test clearing completed download items.""" # Create items item1 = await DownloadQueueService.create( async_session, test_series.id, 1, 1 ) item2 = await DownloadQueueService.create( async_session, test_series.id, 1, 2 ) item3 = await DownloadQueueService.create( async_session, test_series.id, 1, 3 ) # Complete first two await DownloadQueueService.update_status( async_session, item1.id, DownloadStatus.COMPLETED ) await DownloadQueueService.update_status( async_session, item2.id, DownloadStatus.COMPLETED ) await async_session.commit() # Clear completed cleared = await DownloadQueueService.clear_completed(async_session) await async_session.commit() # Assert assert cleared == 2 # Verify pending item remains remaining = await DownloadQueueService.get_all(async_session) assert len(remaining) == 1 assert remaining[0].id == item3.id async def test_cascade_delete_with_series(self, async_session, test_series): """Test that queue items are deleted when series is deleted.""" # Create queue items await DownloadQueueService.create( async_session, test_series.id, 1, 1 ) await DownloadQueueService.create( async_session, test_series.id, 1, 2 ) await async_session.commit() # Delete series await AnimeSeriesService.delete(async_session, test_series.id) await async_session.commit() # Verify queue items are gone all_items = await DownloadQueueService.get_all(async_session) assert len(all_items) == 0 ``` --- ### API Tests **File:** `tests/api/test_queue_endpoints_database.py` ```python """API tests for queue endpoints with database persistence.""" import pytest from httpx import AsyncClient from unittest.mock import patch, AsyncMock class TestQueueAPIWithDatabase: """Test queue API endpoints with database backend.""" @pytest.fixture def auth_headers(self): """Get authentication headers.""" return {"Authorization": "Bearer test-token"} async def test_get_queue_returns_database_items( self, client: AsyncClient, auth_headers ): """Test GET /api/queue returns items from database.""" response = await client.get("/api/queue", headers=auth_headers) assert response.status_code == 200 data = response.json() assert "pending" in data assert "active" in data assert "completed" in data async def test_add_to_queue_persists_to_database( self, client: AsyncClient, auth_headers ): """Test POST /api/queue persists item to database.""" payload = { "series_key": "test-anime", "season": 1, "episode": 1, "priority": "normal", } response = await client.post( "/api/queue", json=payload, headers=auth_headers, ) assert response.status_code == 201 data = response.json() assert "id" in data async def test_remove_from_queue_deletes_from_database( self, client: AsyncClient, auth_headers ): """Test DELETE /api/queue/{id} removes from database.""" # First add an item add_response = await client.post( "/api/queue", json={"series_key": "test-anime", "season": 1, "episode": 1}, headers=auth_headers, ) item_id = add_response.json()["id"] # Then delete it response = await client.delete( f"/api/queue/{item_id}", headers=auth_headers, ) assert response.status_code == 200 # Verify it's gone get_response = await client.get("/api/queue", headers=auth_headers) queue_data = get_response.json() item_ids = [item["id"] for item in queue_data.get("pending", [])] assert item_id not in item_ids async def test_queue_survives_server_restart( self, client: AsyncClient, auth_headers ): """Test that queue items persist across simulated restart.""" # Add item add_response = await client.post( "/api/queue", json={"series_key": "test-anime", "season": 1, "episode": 5}, headers=auth_headers, ) item_id = add_response.json()["id"] # Simulate restart by clearing in-memory cache # (In real scenario, this would be a server restart) # Verify item still exists response = await client.get("/api/queue", headers=auth_headers) queue_data = response.json() item_ids = [item["id"] for item in queue_data.get("pending", [])] assert item_id in item_ids async def test_clear_completed_endpoint( self, client: AsyncClient, auth_headers ): """Test POST /api/queue/clear-completed endpoint.""" response = await client.post( "/api/queue/clear-completed", headers=auth_headers, ) assert response.status_code == 200 data = response.json() assert "cleared_count" in data ``` --- ### Performance Tests **File:** `tests/performance/test_queue_database_performance.py` ```python """Performance tests for database-backed download queue.""" import pytest import asyncio import time from datetime import datetime class TestQueueDatabasePerformance: """Performance tests for queue database operations.""" @pytest.mark.performance async def test_bulk_insert_performance(self, async_session, test_series): """Test performance of bulk queue item insertion.""" from src.server.database.service import DownloadQueueService start_time = time.time() # Insert 100 queue items for i in range(100): await DownloadQueueService.create( async_session, test_series.id, season=1, episode_number=i + 1, ) await async_session.commit() elapsed = time.time() - start_time # Should complete in under 2 seconds assert elapsed < 2.0, f"Bulk insert took {elapsed:.2f}s, expected < 2s" @pytest.mark.performance async def test_query_performance_with_many_items(self, async_session, test_series): """Test query performance with many queue items.""" from src.server.database.service import DownloadQueueService # Setup: Create 500 items for i in range(500): await DownloadQueueService.create( async_session, test_series.id, season=(i // 12) + 1, episode_number=(i % 12) + 1, ) await async_session.commit() # Test query performance start_time = time.time() pending = await DownloadQueueService.get_pending(async_session) elapsed = time.time() - start_time # Query should complete in under 100ms assert elapsed < 0.1, f"Query took {elapsed*1000:.1f}ms, expected < 100ms" assert len(pending) == 500 @pytest.mark.performance async def test_progress_update_performance(self, async_session, test_series): """Test performance of frequent progress updates.""" from src.server.database.service import DownloadQueueService # Create item item = await DownloadQueueService.create( async_session, test_series.id, 1, 1 ) await async_session.commit() start_time = time.time() # Simulate 100 progress updates (like during download) for i in range(100): await DownloadQueueService.update_progress( async_session, item.id, progress_percent=i, downloaded_bytes=i * 10240, total_bytes=1024000, download_speed=102400.0, ) await async_session.commit() elapsed = time.time() - start_time # 100 updates should complete in under 1 second assert elapsed < 1.0, f"Progress updates took {elapsed:.2f}s, expected < 1s" ``` --- ## Summary These tasks will migrate the download queue from JSON file persistence to SQLite database, providing: 1. **Data Integrity**: ACID-compliant storage with proper relationships 2. **Query Capability**: Efficient filtering, sorting, and pagination 3. **Consistency**: Single source of truth for all application data 4. **Scalability**: Better performance for large queues 5. **Recovery**: Robust handling of crashes and restarts The existing database infrastructure (`DownloadQueueItem` model and `DownloadQueueService`) is already in place, making this primarily an integration task rather than new development.