# 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 ``` --- ## Final 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 --- ### 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` **Deployment Steps:** 1. Commit all changes to git repository 2. Create deployment tag (e.g., `v1.0.0-queue-simplified`) 3. Deploy to production environment 4. Monitor logs for any unexpected behavior 5. Verify production queue functionality ### 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 - No database schema changes required - WebSocket infrastructure remains unchanged --- # 🎯 CRITICAL: Series Identifier Standardization ## Overview **Problem:** The codebase currently uses multiple identifiers inconsistently: - `key` (provider identifier, e.g., "attack-on-titan") - `folder` (filesystem folder name, e.g., "Attack on Titan (2013)") - `serie_id` (sometimes key, sometimes folder) - `serie_folder` (filesystem path used as identifier) **Solution:** Standardize on `key` as the single source of truth for all series identification. **Benefits:** - Single, consistent identifier throughout the codebase - `key` is unique, provider-assigned, URL-safe - `folder` becomes metadata only (not used for lookups) - Clearer separation of concerns - Easier to maintain and debug **Scope:** This affects core logic, services, API endpoints, frontend, WebSocket events, and tests. --- ## Task Series: Identifier Standardization ### Phase 1: Core Models and Data Layer #### Task 1.1: Update Serie Class to Enforce Key as Primary Identifier **File:** [`src/core/entities/series.py`](src/core/entities/series.py) **Objective:** Ensure `Serie` class uses `key` as the primary identifier and add validation. **Steps:** 1. Open [`src/core/entities/series.py`](src/core/entities/series.py) 2. Add validation in `__init__` to ensure `key` is never empty 3. Add a docstring clarifying that `key` is the unique identifier 4. Add validation to prevent `key` from being set to empty string 5. Ensure `folder` is documented as "filesystem folder name (metadata only)" **Success Criteria:** - [x] `key` property has validation preventing empty values - [x] Docstrings clearly state `key` is the unique identifier - [x] `folder` is documented as metadata only - [x] All existing tests for `Serie` still pass **Test Command:** ```bash conda run -n AniWorld python -m pytest tests/unit/test_anime_models.py -v ``` **Status:** ✅ COMPLETED **Implementation Details:** - Added comprehensive validation in `__init__` to ensure `key` is never empty or whitespace - Added validation in `key` setter to prevent setting empty values - Key values are automatically stripped of whitespace - Added detailed docstrings explaining `key` as the unique identifier - Documented `folder` as "filesystem folder name (metadata only, not used for lookups)" - Created comprehensive test suite in `tests/unit/test_serie_class.py` with 16 tests covering: - Key validation (empty, whitespace, valid values) - Key setter validation - Whitespace stripping behavior - String representation - Serialization/deserialization (to_dict/from_dict) - File save/load functionality - Documentation completeness - All 56 Serie-related tests pass successfully --- #### Task 1.2: Update SerieList to Use Key for Lookups **File:** [`src/core/entities/SerieList.py`](src/core/entities/SerieList.py) **Objective:** Change `SerieList` internal storage to use `key` instead of `folder` as the dictionary key. **Steps:** 1. Open [`src/core/entities/SerieList.py`](src/core/entities/SerieList.py) 2. Change `self.folderDict` to `self.keyDict` (rename for clarity) 3. Update `add()` method to use `serie.key` as dictionary key 4. Update `contains()` method to check by `key` instead of `folder` 5. Update `load_series()` to store series by `key` 6. Update all internal methods that access the dictionary 7. Add helper method `get_by_key(key: str) -> Optional[Serie]` 8. Add helper method `get_by_folder(folder: str) -> Optional[Serie]` for backward compatibility **Success Criteria:** - [x] Internal dictionary keyed by `serie.key` - [x] `add()`, `contains()`, `GetList()` work correctly - [x] Helper methods `get_by_key()` and `get_by_folder()` implemented - [x] All existing tests pass - [x] No breaking changes to public API **Test Command:** ```bash conda run -n AniWorld python -m pytest tests/unit/ -k "SerieList" -v ``` **Status:** ✅ COMPLETED **Implementation Details:** - Renamed `self.folderDict` to `self.keyDict` for clarity - Updated internal storage to use `serie.key` as dictionary key - Modified `add()` method to store series by key: `self.keyDict[serie.key] = serie` - Optimized `contains()` method to use direct dictionary lookup: `return key in self.keyDict` - Updated `_load_data()` to store loaded series by key with enhanced logging - All methods (`GetMissingEpisode()`, `GetList()`, etc.) now iterate over `self.keyDict.values()` - Added `get_by_key(key: str) -> Optional[Serie]` as primary lookup method - Added `get_by_folder(folder: str) -> Optional[Serie]` for backward compatibility - Created comprehensive test suite in `tests/unit/test_serie_list.py` with 12 tests covering: - Key-based storage initialization - Add, contains, and retrieval operations - Duplicate prevention by key - Helper method functionality (get_by_key, get_by_folder) - Public API compatibility - File loading and persistence - All 12 new tests pass successfully - All 16 SeriesApp tests pass, confirming no breaking changes - Enhanced docstrings to clarify `key` as identifier and `folder` as metadata --- #### Task 1.3: Update SerieScanner to Use Key Consistently **File:** [`src/core/SerieScanner.py`](src/core/SerieScanner.py) **Objective:** Ensure `SerieScanner` identifies and stores series by `key`. **Steps:** 1. Open [`src/core/SerieScanner.py`](src/core/SerieScanner.py) 2. Update `scan()` method to use `serie.key` for all operations 3. Update `self.folderDict` to use `key` as dictionary key (or rename to `self.keyDict`) 4. Ensure all error logging and progress callbacks reference `key` not `folder` 5. Update `__read_data_from_file()` to validate `key` exists before proceeding 6. Add debug logging showing both `key` and `folder` for clarity **Success Criteria:** - [x] Scanner stores series by `key` - [x] Progress callbacks use `key` for identification - [x] Error messages reference `key` and `folder` appropriately - [x] All scanner tests pass **Test Command:** ```bash conda run -n AniWorld python -m pytest tests/unit/ -k "SerieScanner" -v ``` **Status:** ✅ COMPLETED **Implementation Details:** - Renamed `self.folderDict` to `self.keyDict` for clarity and consistency - Updated internal dictionary storage to use `serie.key` as the dictionary key - Modified `scan()` method to store series by key: `self.keyDict[serie.key] = serie` - Enhanced logging in duplicate detection to show both key and folder for clarity - Added debug logging when storing series showing both identifiers - Updated error contexts in exception handlers to include both `key` and `folder` in metadata - Updated completion statistics to use `len(self.keyDict)` for series count - Updated `reinit()` method docstring to reflect key-based storage - Enhanced `__read_data_from_file()` docstring to clarify that `folder_name` is only used to locate data files - All error messages now properly reference both `key` (identifier) and `folder` (metadata) - All 554 unit tests pass successfully, confirming no regressions - Code follows PEP 8 style guidelines (max 79 characters per line) --- #### Task 1.4: Update Provider Classes to Use Key **Files:** - [`src/core/providers/aniworld_provider.py`](src/core/providers/aniworld_provider.py) - [`src/core/providers/enhanced_provider.py`](src/core/providers/enhanced_provider.py) **Objective:** Update provider download methods to use `key` for identification while keeping `serieFolder` for filesystem operations. **Steps:** 1. Open [`src/core/providers/aniworld_provider.py`](src/core/providers/aniworld_provider.py) 2. Update `download()` method signature: - Add `key: str` parameter as first identifier parameter - Keep `serie_folder: str` parameter for filesystem operations - Update docstring to clarify: `key` is the series identifier, `serie_folder` is for file paths 3. Update all logging and error messages to reference `key` instead of folder 4. Repeat for [`src/core/providers/enhanced_provider.py`](src/core/providers/enhanced_provider.py) 5. Update the `Download()` method similarly 6. Ensure all error handling and recovery logic uses `key` for identification **Success Criteria:** - [x] Both provider classes accept `key` as primary identifier - [x] `serie_folder` only used for file path construction - [x] Logging references `key` for identification - [x] All error messages use `key` - [x] All provider tests pass **Test Command:** ```bash conda run -n AniWorld python -m pytest tests/unit/ -k "provider" -v ``` **Status:** ✅ COMPLETED **Implementation Details:** - Enhanced `download()` method docstring in `aniworld_provider.py` with comprehensive parameter documentation - Clarified that `serie_folder` is "filesystem folder name (metadata only, used for file path construction)" - Clarified that `key` is "series unique identifier from provider (used for identification and API calls)" - Enhanced `Download()` method docstring in `enhanced_provider.py` with comprehensive parameter documentation - Included Args, Returns, and Raises sections in docstrings following PEP 257 - Verified existing logging already uses `key` for identification (line 227 in aniworld_provider.py) - Verified existing error messages already use `key` for identification (lines 456, 466 in enhanced_provider.py) - Fixed PEP 8 line length issue by splitting long logging statement - All 34 provider-related tests pass successfully with no regressions - Both classes already had `key` parameter in correct position with proper usage - No functional changes required, only documentation improvements --- #### Task 1.5: Update Provider Factory to Use Key **File:** `src/core/providers/provider_factory.py` **Objective:** Ensure provider factory uses `key` for provider selection and series identification. **Steps:** 1. Open `src/core/providers/provider_factory.py` 2. Review `get_provider()` method and ensure it can work with `key` 3. Update any caching or provider lookup logic to use `key` 4. Ensure provider instances receive `key` for operations 5. Update docstrings **Success Criteria:** - [x] Provider factory works with `key` identifiers - [x] No breaking changes to provider interface - [x] All provider factory tests pass **Test Command:** ```bash conda run -n AniWorld python -m pytest tests/unit/ -k "provider_factory" -v ``` **Status:** ✅ COMPLETED **Implementation Details:** - Added comprehensive module-level docstring explaining the distinction between provider keys and series keys - Enhanced `Loaders` class docstring with detailed documentation of its purpose and attributes - Added comprehensive docstring to `GetLoader()` method explaining: - Provider key vs series key distinction - Parameter usage and return value - Raises clause documenting KeyError exception - Note clarifying the two-level key usage (provider key in factory, series key in providers) - Added type hint `Dict[str, Loader]` to `self.dict` attribute for better type safety - Added return type hint `-> None` to `__init__` method - Verified provider factory already correctly uses `key` for provider identification - Verified provider instances (via Loader interface) use `key` for series identification - No functional changes required - existing implementation was already correct - Documentation now clearly distinguishes between: - Provider keys: Site identifiers like "aniworld.to" (used by factory) - Series keys: Unique anime identifiers like "attack-on-titan" (used by providers) - All 34 provider-related tests pass successfully - All 16 SeriesApp tests pass, confirming no breaking changes in Loaders integration - Code follows PEP 8 and PEP 257 standards --- ### Phase 2: Core Application Layer #### Task 2.1: Update SeriesApp to Use Key for All Operations **File:** [`src/core/SeriesApp.py`](src/core/SeriesApp.py) **Objective:** Standardize `SeriesApp` to use `key` instead of `folder` for series identification. **Steps:** 1. Open [`src/core/SeriesApp.py`](src/core/SeriesApp.py) 2. Update `download()` method signature: - Keep `serie_folder` parameter for filesystem operations - Add docstring clarifying `serie_folder` is for file paths only - Ensure `key` is the primary lookup identifier 3. Update all internal lookups to use `key` 4. Update event emissions to include both `key` and `folder` 5. Add helper method `_get_serie_by_key(key: str) -> Optional[Serie]` 6. Ensure all method docstrings clarify identifier usage **Success Criteria:** - [x] All methods use `key` for series identification - [x] `serie_folder` only used for filesystem operations - [x] Events include both `key` and `folder` - [x] Docstrings are clear about parameter usage - [x] All SeriesApp tests pass **Test Command:** ```bash conda run -n AniWorld python -m pytest tests/unit/test_series_app.py -v ``` **Status:** ✅ COMPLETED **Implementation Details:** - **Import Added**: Imported `Serie` class from `src.core.entities.series` for type hints - **DownloadStatusEventArgs Updated**: - Added `key: Optional[str] = None` parameter to constructor - Updated docstring to clarify `serie_folder` is "metadata only, used for file paths" - Updated docstring to clarify `key` is "Serie unique identifier (provider key, primary identifier)" - All event emissions now include both `key` and `folder` for complete context - **ScanStatusEventArgs Updated**: - Added `key: Optional[str] = None` parameter to constructor - Updated docstring to clarify `folder` is "metadata only" - Updated docstring to clarify `key` is "Serie unique identifier if applicable (provider key, primary identifier)" - **download() Method Enhanced**: - Updated docstring with comprehensive parameter documentation - Added explicit note: "The 'key' parameter is the primary identifier for series lookups. The 'serie_folder' parameter is only used for filesystem operations." - All logging statements now include both `key` (for identification) and `folder` (for context) - All event emissions include both `key` and `folder`: - Download started event - Download progress events - Download completed event - Download failed event - Download error event - **Helper Method Added**: - Implemented `_get_serie_by_key(key: str) -> Optional[Serie]` method - Uses `self.list.get_by_key(key)` for lookups (key-based, not folder-based) - Comprehensive docstring explaining this is the primary lookup method - Properly typed with `Optional[Serie]` return type - **Logging Improvements**: - All download-related logs now show both key and folder: `"Starting download: %s (key: %s) S%02dE%02d"` - Provides better context for debugging and monitoring - Follows PEP 8 line length guidelines (max 79 characters) - **Code Quality**: - All docstrings follow PEP 257 standards - Type hints used throughout - Lazy logging with % formatting instead of f-strings - Proper line length (max 79 characters per PEP 8) - Two blank lines between class definitions - **Test Updates**: - Updated `tests/unit/test_download_progress_websocket.py` - Fixed `MockDownloadArgs` class to include `key` and `item_id` fields - All mock download event emissions now include `key` parameter - Ensures backward compatibility and proper event structure - **Test Results**: - All 16 SeriesApp tests pass successfully - All 562 unit tests pass with no regressions - Test coverage maintained at high level - No breaking changes to existing functionality **Benefits of This Change**: 1. **Consistency**: Series identification is now consistent throughout the core application layer 2. **Clarity**: Clear separation between identifier (`key`) and metadata (`folder`) 3. **Debugging**: Logs and events show both identifiers for better troubleshooting 4. **Type Safety**: Proper type hints with `Optional[Serie]` return types 5. **Maintainability**: Single source of truth for series lookups via `_get_serie_by_key()` 6. **Backward Compatibility**: All existing functionality preserved, tests pass --- #### Task 2.2: Update Callback Interfaces to Use Key **File:** [`src/core/interfaces/callbacks.py`](src/core/interfaces/callbacks.py) **Objective:** Ensure callback interfaces use `key` in all progress and event contexts. **Steps:** 1. Open [`src/core/interfaces/callbacks.py`](src/core/interfaces/callbacks.py) 2. Review `ProgressContext` and other context classes 3. Ensure context classes include `key` field where series is referenced 4. Add `folder` field as optional metadata 5. Update docstrings to clarify `key` vs `folder` usage 6. Ensure backward compatibility where needed **Success Criteria:** - [ ] Context classes include `key` field - [ ] `folder` included as optional metadata - [ ] Docstrings clearly document field usage - [ ] All callback tests pass **Test Command:** ```bash conda run -n AniWorld python -m pytest tests/unit/test_callbacks.py -v ``` --- ### Phase 3: Service Layer #### Task 3.1: Update DownloadService to Use Key **File:** [`src/server/services/download_service.py`](src/server/services/download_service.py) **Objective:** Change `DownloadService` to use `key` as the series identifier instead of mixing `serie_id` and `serie_folder`. **Steps:** 1. Open [`src/server/services/download_service.py`](src/server/services/download_service.py) 2. In `add_to_queue()` method: - Rename parameter `serie_id` to `series_key` (or keep as `serie_id` but document it's the key) - Keep `serie_folder` for filesystem operations - Keep `serie_name` for display - Update docstring to clarify: `serie_id` is the provider key 3. Update `DownloadItem` dataclass: - Change `serie_id` to use `key` - Keep `serie_folder` for file operations 4. Update all internal methods to use `key` consistently 5. Update logging to reference `key` instead of `folder` **Success Criteria:** - [ ] `add_to_queue()` uses `key` for identification - [ ] `DownloadItem` uses `key` as identifier - [ ] Filesystem operations still use `serie_folder` - [ ] All download service tests pass **Test Command:** ```bash conda run -n AniWorld python -m pytest tests/unit/ -k "DownloadService" -v ``` --- #### Task 3.2: Update AnimeService to Use Key **File:** [`src/server/services/anime_service.py`](src/server/services/anime_service.py) **Objective:** Ensure `AnimeService` uses `key` for all series operations. **Steps:** 1. Open [`src/server/services/anime_service.py`](src/server/services/anime_service.py) 2. Update `download()` method to use `key` for series lookup 3. Update `get_series_list()` to return series with `key` as identifier 4. Update all event handlers to use `key` 5. Ensure all lookups in `_app` (SeriesApp) use `key` 6. Update docstrings to clarify identifier usage **Success Criteria:** - [ ] All methods use `key` for series identification - [ ] Event handlers use `key` - [ ] Docstrings are clear - [ ] All anime service tests pass **Test Command:** ```bash conda run -n AniWorld python -m pytest tests/unit/ -k "AnimeService" -v ``` --- #### Task 3.3: Update ProgressService to Use Key **File:** [`src/server/services/progress_service.py`](src/server/services/progress_service.py) **Objective:** Ensure `ProgressService` uses `key` for all progress tracking. **Steps:** 1. Open [`src/server/services/progress_service.py`](src/server/services/progress_service.py) 2. Review all methods that handle progress events 3. Ensure progress events include `key` as identifier 4. Update any internal tracking to use `key` instead of `folder` 5. Update event payloads to include both `key` and `folder` where needed 6. Update docstrings to clarify identifier usage **Success Criteria:** - [ ] All progress events include `key` - [ ] Internal tracking uses `key` - [ ] Event payloads structured correctly - [ ] All progress service tests pass **Test Command:** ```bash conda run -n AniWorld python -m pytest tests/unit/ -k "ProgressService" -v ``` --- #### Task 3.4: Update ScanService to Use Key **File:** [`src/server/services/scan_service.py`](src/server/services/scan_service.py) **Objective:** Ensure `ScanService` uses `key` for all scan operations. **Steps:** 1. Open [`src/server/services/scan_service.py`](src/server/services/scan_service.py) 2. Review all methods that handle scan events 3. Ensure scan progress events use `key` for identification 4. Update any callbacks to use `key` 5. Update event emissions to include both `key` and `folder` 6. Update docstrings **Success Criteria:** - [ ] All scan operations use `key` - [ ] Callbacks receive `key` as identifier - [ ] Events include both `key` and `folder` - [ ] All scan service tests pass **Test Command:** ```bash conda run -n AniWorld python -m pytest tests/unit/ -k "ScanService" -v ``` --- ### Phase 4: API Layer #### Task 4.1: Update Anime API Endpoints to Use Key **File:** [`src/server/api/anime.py`](src/server/api/anime.py) **Objective:** Standardize all anime API endpoints to use `key` as the series identifier. **Steps:** 1. Open [`src/server/api/anime.py`](src/server/api/anime.py) 2. Update `AnimeSummary` model: - Ensure `key` is the primary identifier - Document `folder` as metadata only 3. Update `get_anime()` endpoint: - Accept `anime_id` as the `key` - Update lookup logic to use `key` - Keep backward compatibility by checking both `key` and `folder` 4. Update `add_series()` endpoint: - Use `key` from the link as identifier - Store `folder` as metadata 5. Update `_perform_search()`: - Return `key` as the identifier - Include `folder` as separate field 6. Update all docstrings to clarify identifier usage **Success Criteria:** - [ ] All endpoints use `key` as identifier - [ ] Backward compatibility maintained - [ ] API responses include both `key` and `folder` - [ ] All anime API tests pass **Test Command:** ```bash conda run -n AniWorld python -m pytest tests/api/test_anime_endpoints.py -v ``` --- #### Task 4.2: Update Download API Endpoints to Use Key **File:** [`src/server/api/download.py`](src/server/api/download.py) **Objective:** Ensure download API uses `key` for series identification. **Steps:** 1. Open [`src/server/api/download.py`](src/server/api/download.py) 2. Update `DownloadRequest` model: - Rename or document `serie_id` as `series_key` - Keep `serie_folder` for filesystem operations - Keep `serie_name` for display 3. Update `add_to_queue()` endpoint: - Use `series_key` for series identification - Pass `serie_folder` to download service 4. Update all docstrings **Success Criteria:** - [ ] Request model uses `key` as identifier - [ ] Endpoint passes correct identifiers to service - [ ] All download API tests pass **Test Command:** ```bash conda run -n AniWorld python -m pytest tests/api/ -k "download" -v ``` --- #### Task 4.3: Update Queue API Endpoints to Use Key **File:** [`src/server/api/queue.py`](src/server/api/queue.py) **Objective:** Ensure queue API endpoints use `key` for series identification. **Steps:** 1. Open [`src/server/api/queue.py`](src/server/api/queue.py) 2. Review all queue-related endpoints 3. Update request/response models to use `key` as identifier 4. Ensure queue status includes `key` in item data 5. Update queue manipulation endpoints to accept `key` 6. Update docstrings and OpenAPI documentation **Success Criteria:** - [ ] All queue endpoints use `key` - [ ] Queue status responses include `key` - [ ] Request models use `key` for identification - [ ] All queue API tests pass **Test Command:** ```bash conda run -n AniWorld python -m pytest tests/api/ -k "queue" -v ``` --- #### Task 4.4: Update WebSocket API Endpoints to Use Key **File:** `src/server/api/websocket.py` **Objective:** Ensure WebSocket API endpoint handlers use `key` for series identification. **Steps:** 1. Open `src/server/api/websocket.py` 2. Review all WebSocket message handlers 3. Ensure messages use `key` for series identification 4. Update message schemas to include `key` field 5. Keep `folder` for display purposes 6. Update docstrings **Success Criteria:** - [ ] All WebSocket handlers use `key` - [ ] Message schemas include `key` - [ ] All WebSocket API tests pass **Test Command:** ```bash conda run -n AniWorld python -m pytest tests/api/ -k "websocket" -v ``` --- #### Task 4.5: Update Pydantic Models to Use Key **Files:** - `src/server/models/anime.py` - `src/server/models/download.py` **Objective:** Ensure all Pydantic models use `key` as the series identifier. **Steps:** 1. Open `src/server/models/anime.py` 2. Review all models (e.g., `AnimeDetail`, `AnimeSummary`, `SearchResult`) 3. Ensure `key` is the primary identifier field 4. Add `folder` as optional metadata field 5. Update field validators to validate `key` format 6. Repeat for `src/server/models/download.py` 7. Update `DownloadRequest` and related models 8. Update all docstrings and field descriptions **Success Criteria:** - [ ] All anime models use `key` as identifier - [ ] All download models use `key` as identifier - [ ] Field validators ensure `key` format is correct - [ ] `folder` is optional metadata - [ ] All model tests pass **Test Command:** ```bash conda run -n AniWorld python -m pytest tests/unit/ -k "models" -v ``` --- #### Task 4.6: Update Validators to Use Key **File:** `src/server/utils/validators.py` **Objective:** Ensure validation functions validate `key` instead of `folder`. **Steps:** 1. Open `src/server/utils/validators.py` 2. Review all validation functions 3. Add `validate_series_key()` function if not exists 4. Update any validators that check series identifiers 5. Ensure validators accept `key` format (URL-safe, lowercase with hyphens) 6. Add tests for key validation **Success Criteria:** - [ ] Validators validate `key` format - [ ] No validators use `folder` for identification - [ ] Validation functions well-documented - [ ] All validator tests pass **Test Command:** ```bash conda run -n AniWorld python -m pytest tests/unit/ -k "validator" -v ``` --- #### Task 4.7: Update Template Helpers to Use Key **File:** `src/server/utils/template_helpers.py` **Objective:** Ensure template helpers pass `key` to templates for series identification. **Steps:** 1. Open `src/server/utils/template_helpers.py` 2. Review all helper functions 3. Ensure functions that handle series data use `key` 4. Update any filtering or sorting to use `key` 5. Ensure `folder` is available for display purposes 6. Update docstrings **Success Criteria:** - [ ] All helpers use `key` for identification - [ ] `folder` available for display - [ ] No breaking changes to template interface - [ ] All template helper tests pass **Test Command:** ```bash conda run -n AniWorld python -m pytest tests/unit/ -k "template" -v ``` --- ### Phase 5: Frontend #### Task 5.1: Update Frontend JavaScript to Use Key **File:** [`src/server/web/static/js/app.js`](src/server/web/static/js/app.js) **Objective:** Update frontend to use `key` as the primary series identifier instead of `folder`. **Steps:** 1. Open [`src/server/web/static/js/app.js`](src/server/web/static/js/app.js) 2. Update `seriesData` storage to index by `key` 3. Update `selectedSeries` Set to use `key` instead of `folder` 4. Update `createSerieCard()`: - Use `data-key` attribute instead of `data-folder` - Display `folder` as metadata only 5. Update `toggleSerieSelection()` to use `key` 6. Update `downloadSelected()`: - Send `key` as `serie_id` - Include `folder` for filesystem operations 7. Update all event handlers and lookups to use `key` 8. Keep `folder` visible in UI for user reference **Success Criteria:** - [ ] Frontend uses `key` for all series operations - [ ] `folder` displayed in UI but not used for identification - [ ] Selection tracking uses `key` - [ ] All frontend interactions work correctly **Manual Test:** 1. Start server 2. Login to web interface 3. Verify series list displays correctly 4. Test selecting series (should use key internally) 5. Test downloading episodes 6. Verify search functionality --- #### Task 5.2: Update WebSocket Events to Use Key **File:** [`src/server/services/websocket_service.py`](src/server/services/websocket_service.py) **Objective:** Ensure WebSocket events use `key` for series identification. **Steps:** 1. Open [`src/server/services/websocket_service.py`](src/server/services/websocket_service.py) 2. Update `broadcast_download_progress()`: - Include `key` in event data - Keep `folder` for display purposes 3. Update `broadcast_scan_progress()` similarly 4. Update all event broadcasts to include `key` 5. Update event handler subscriptions to use `key` **Success Criteria:** - [ ] All WebSocket events include `key` - [ ] Events also include `folder` for display - [ ] All WebSocket tests pass **Test Command:** ```bash conda run -n AniWorld python -m pytest tests/unit/test_websocket_service.py -v ``` --- #### Task 5.3: Update Additional Frontend JavaScript Files **Files:** - `src/server/web/static/js/websocket.js` - `src/server/web/static/js/queue.js` - `src/server/web/static/js/download.js` - `src/server/web/static/js/utils.js` **Objective:** Ensure all frontend JavaScript modules use `key` for series identification. **Steps:** 1. **Update `websocket.js`:** - Open `src/server/web/static/js/websocket.js` - Review all message handlers - Ensure event payloads use `key` for identification - Update event listeners to use `key` - Keep `folder` for display 2. **Update `queue.js`:** - Open `src/server/web/static/js/queue.js` - Update queue item identification to use `key` - Update queue manipulation functions - Ensure queue display shows both `key` and `folder` 3. **Update `download.js`:** - Open `src/server/web/static/js/download.js` - Update download request building to use `key` - Update progress tracking to use `key` - Keep `folder` for file path operations 4. **Update `utils.js`:** - Open `src/server/web/static/js/utils.js` - Review utility functions that handle series data - Ensure utilities use `key` for identification - Update any series-related helper functions **Success Criteria:** - [ ] All JavaScript modules use `key` for identification - [ ] WebSocket handlers use `key` - [ ] Queue operations use `key` - [ ] Download operations use `key` - [ ] Utilities handle `key` correctly - [ ] `folder` displayed in UI where appropriate - [ ] All frontend functionality works correctly **Manual Test:** 1. Test WebSocket connectivity and events 2. Test queue management 3. Test download functionality 4. Verify all series operations use `key` --- #### Task 5.4: Update HTML Templates to Use Key **Files:** All templates in `src/server/web/templates/` **Objective:** Ensure all HTML templates use `key` for series identification in data attributes and forms. **Steps:** 1. Review all template files: - `index.html` - `anime_detail.html` - `search.html` - Any other templates using series data 2. For each template: - Update data attributes to use `data-key` instead of `data-folder` - Keep `data-folder` for display purposes if needed - Update form inputs to submit `key` as identifier - Update JavaScript references to use `key` - Display `folder` for user-friendly names 3. Update template variables: - Ensure templates receive `key` from backend - Verify `folder` is available for display - Update any template logic that filters/sorts by series **Success Criteria:** - [ ] All templates use `data-key` for identification - [ ] Forms submit `key` as identifier - [ ] `folder` displayed for user reference - [ ] No templates use `folder` for identification - [ ] All template rendering works correctly **Manual Test:** 1. Verify all pages render correctly 2. Test form submissions 3. Verify JavaScript interactions 4. Check data attributes in browser dev tools --- ### Phase 6: Database Layer #### Task 6.1: Verify Database Models Use Key Correctly **File:** [`src/server/database/models.py`](src/server/database/models.py) **Objective:** Verify and document that database models correctly use `key` as unique identifier. **Steps:** 1. Open [`src/server/database/models.py`](src/server/database/models.py) 2. Verify `AnimeSeries.key` is unique and indexed 3. Verify `AnimeSeries.folder` is not used for lookups 4. Update docstrings to clarify identifier usage 5. Ensure all relationships use `id` (primary key) not `key` or `folder` **Success Criteria:** - [ ] `key` is unique and indexed - [ ] `folder` is metadata only - [ ] Docstrings are clear - [ ] All database model tests pass **Test Command:** ```bash conda run -n AniWorld python -m pytest tests/unit/test_database_models.py -v ``` --- #### Task 6.2: Update Database Services to Use Key **File:** [`src/server/database/service.py`](src/server/database/service.py) **Objective:** Ensure all database service methods use `key` for series lookup. **Steps:** 1. Open [`src/server/database/service.py`](src/server/database/service.py) 2. Verify `AnimeSeriesService.get_by_key()` is used for lookups 3. Verify no methods use `folder` for identification 4. Update any methods that incorrectly use `folder` for lookups 5. Add migration helper if needed to update existing data **Success Criteria:** - [ ] All service methods use `key` for lookups - [ ] `folder` never used as identifier - [ ] All database service tests pass **Test Command:** ```bash conda run -n AniWorld python -m pytest tests/unit/test_database_service.py -v ``` --- ### Phase 7: Testing and Validation #### Task 7.1: Update All Test Fixtures to Use Key **Files:** All test files in [`tests/`](tests/) **Objective:** Ensure all test fixtures and mocks use `key` consistently. **Steps:** 1. Search for all test files using `folder` as identifier 2. Update `FakeSerie` class in [`tests/api/test_anime_endpoints.py`](tests/api/test_anime_endpoints.py): - Ensure `key` is the primary identifier 3. Update all test fixtures to use `key` 4. Update mock data to use realistic `key` values 5. Ensure tests verify both `key` and `folder` are present but only `key` is used for operations **Success Criteria:** - [ ] All test fixtures use `key` as identifier - [ ] Tests verify `key` is used for operations - [ ] Tests verify `folder` is present as metadata - [ ] All tests pass **Test Command:** ```bash conda run -n AniWorld python -m pytest tests/ -v ``` --- #### Task 7.2: Add Integration Tests for Identifier Consistency **File:** Create new file `tests/integration/test_identifier_consistency.py` **Objective:** Create integration tests to verify `key` is used consistently across all layers. **Steps:** 1. Create [`tests/integration/test_identifier_consistency.py`](tests/integration/test_identifier_consistency.py) 2. Write test to verify: - API endpoint returns `key` as identifier - Download service uses `key` - Database lookups use `key` - WebSocket events include `key` 3. Write test to verify `folder` is never used for lookups 4. Write test for end-to-end flow using `key` **Success Criteria:** - [ ] Integration test file created - [ ] Tests verify `key` usage across all layers - [ ] Tests verify `folder` not used for identification - [ ] All integration tests pass **Test Command:** ```bash conda run -n AniWorld python -m pytest tests/integration/test_identifier_consistency.py -v ``` --- ### Phase 8: Documentation and Cleanup #### Task 8.1: Update Infrastructure Documentation **File:** [`infrastructure.md`](infrastructure.md) **Objective:** Document the identifier standardization in infrastructure documentation. **Steps:** 1. Open [`infrastructure.md`](infrastructure.md) 2. Add section explaining identifier usage: - `key`: Unique series identifier (provider-assigned) - `folder`: Filesystem folder name (metadata only) - `id`: Database primary key (internal use) 3. Update all API documentation to show `key` as identifier 4. Update data model documentation 5. Add migration notes if needed **Success Criteria:** - [ ] Documentation clearly explains identifier usage - [ ] All API examples use `key` - [ ] Data model section updated - [ ] Migration notes added if applicable --- #### Task 8.2: Update README and Developer Documentation **Files:** [`README.md`](README.md), [`docs/`](docs/) **Objective:** Update all developer-facing documentation. **Steps:** 1. Update main README to explain identifier usage 2. Update any developer guides to use `key` 3. Add note about backward compatibility with `folder` 4. Update code examples to use `key` **Success Criteria:** - [ ] README updated - [ ] Developer guides updated - [ ] Code examples use `key` - [ ] Backward compatibility documented --- #### Task 8.3: Add Deprecation Warnings for Folder-Based Lookups **Files:** Various service and API files **Objective:** Add deprecation warnings where `folder` is still accepted for backward compatibility. **Steps:** 1. Identify all methods that accept `folder` for lookups 2. Add deprecation warnings using Python's `warnings` module 3. Update docstrings to indicate deprecation 4. Plan removal timeline (e.g., next major version) **Success Criteria:** - [ ] Deprecation warnings added - [ ] Docstrings indicate deprecation - [ ] Removal timeline documented - [ ] Tests updated to suppress warnings --- ### Phase 9: Final Validation #### Task 9.1: Run Full Test Suite **Objective:** Verify all changes work together correctly. **Steps:** 1. Run complete test suite: ```bash conda run -n AniWorld python -m pytest tests/ -v --tb=short ``` 2. Fix any failing tests 3. Verify test coverage is maintained 4. Run integration tests 5. Run manual UI tests **Success Criteria:** - [ ] All unit tests pass - [ ] All integration tests pass - [ ] All API tests pass - [ ] Test coverage >= 80% - [ ] Manual UI testing successful --- #### Task 9.2: Manual End-to-End Testing **Objective:** Manually verify all features work with the new identifier system. **Steps:** 1. Start server: `conda run -n AniWorld python -m uvicorn src.server.fastapi_app:app --host 127.0.0.1 --port 8000 --reload` 2. Login to web interface 3. Test search functionality (verify results show `key`) 4. Test adding new series (verify uses `key`) 5. Test downloading episodes (verify uses `key`) 6. Test WebSocket events (verify events include `key`) 7. Verify database contains correct `key` values 8. Test rescan functionality **Success Criteria:** - [ ] Search works correctly - [ ] Adding series works - [ ] Downloads work correctly - [ ] WebSocket events work - [ ] Database entries correct - [ ] Rescan functionality works --- #### Task 9.3: Performance and Load Testing **Objective:** Ensure identifier changes don't impact performance. **Steps:** 1. Run performance tests on key operations: - Series lookup by `key` - Database queries using `key` - API response times 2. Compare with baseline if available 3. Identify any performance regressions 4. Optimize if needed **Success Criteria:** - [ ] No significant performance regression - [ ] Lookup by `key` is fast - [ ] Database queries optimized - [ ] API response times acceptable --- ### Phase 10: Deployment #### Task 10.1: Create Migration Script **Objective:** Create script to migrate existing data if needed. **Steps:** 1. Create [`scripts/migrate_identifiers.py`](scripts/migrate_identifiers.py) 2. Script should: - Check all series have valid `key` values - Update any references that incorrectly use `folder` - Validate database integrity - Create backup before migration 3. Add rollback capability 4. Test migration on test data **Success Criteria:** - [ ] Migration script created - [ ] Script validates data - [ ] Backup functionality works - [ ] Rollback capability tested - [ ] Migration tested on test data --- #### Task 10.2: Update Deployment Documentation **File:** Update deployment section in [`instructions.md`](instructions.md) **Objective:** Document deployment steps for identifier changes. **Steps:** 1. Add pre-deployment checklist 2. Document migration steps 3. Add rollback procedure 4. Document verification steps 5. Add troubleshooting guide **Success Criteria:** - [ ] Deployment steps documented - [ ] Migration procedure clear - [ ] Rollback procedure documented - [ ] Verification steps listed - [ ] Troubleshooting guide added --- #### Task 10.3: Deploy to Production **Objective:** Deploy changes to production environment. **Steps:** 1. Create deployment tag: `v2.0.0-identifier-standardization` 2. Backup production database 3. Run migration script 4. Deploy new code 5. Monitor logs for errors 6. Verify production functionality 7. Monitor for 24 hours **Success Criteria:** - [ ] Deployment tag created - [ ] Database backed up - [ ] Migration successful - [ ] Code deployed - [ ] No errors in logs - [ ] All features working - [ ] 24-hour monitoring completed --- ## Task Tracking ### Completion Status - [ ] Phase 1: Core Models and Data Layer - [ ] Task 1.1: Update Serie Class - [ ] Task 1.2: Update SerieList - [ ] Task 1.3: Update SerieScanner - [ ] **Task 1.4: Update Provider Classes** ⭐ NEW - [ ] Phase 2: Core Application Layer - [ ] Task 2.1: Update SeriesApp - [ ] **Task 2.2: Update Callback Interfaces** ⭐ NEW - [ ] Phase 3: Service Layer - [ ] Task 3.1: Update DownloadService - [ ] Task 3.2: Update AnimeService - [ ] **Task 3.3: Update ProgressService** ⭐ NEW - [ ] **Task 3.4: Update ScanService** ⭐ NEW - [ ] Phase 4: API Layer - [ ] Task 4.1: Update Anime API Endpoints - [ ] Task 4.2: Update Download API Endpoints - [ ] **Task 4.3: Update Queue API Endpoints** ⭐ NEW - [ ] **Task 4.4: Update WebSocket API Endpoints** ⭐ NEW - [ ] **Task 4.5: Update Pydantic Models** ⭐ NEW - [ ] **Task 4.6: Update Validators** ⭐ NEW - [ ] **Task 4.7: Update Template Helpers** ⭐ NEW - [ ] Phase 5: Frontend - [ ] Task 5.1: Update Frontend JavaScript - [ ] Task 5.2: Update WebSocket Events - [ ] Task 5.3: Update Additional Frontend JavaScript Files - [ ] Task 5.4: Update HTML Templates - [ ] Phase 6: Database Layer - [ ] Task 6.1: Verify Database Models - [ ] Task 6.2: Update Database Services - [ ] Phase 7: Testing and Validation - [ ] Task 7.1: Update Test Fixtures - [ ] Task 7.2: Add Integration Tests - [ ] Phase 8: Documentation and Cleanup - [ ] Task 8.1: Update Infrastructure Documentation - [ ] Task 8.2: Update README - [ ] Task 8.3: Add Deprecation Warnings - [ ] Phase 9: Final Validation