- Added 5 new service methods for complete database coverage:
* get_series_without_nfo()
* count_all()
* count_with_nfo()
* count_with_tmdb_id()
* count_with_tvdb_id()
- Eliminated all direct database queries from business logic:
* series_manager_service.py - now uses AnimeSeriesService
* anime_service.py - now uses service layer methods
- Documented architecture decision in ARCHITECTURE.md:
* Service layer IS the repository layer
* No direct SQLAlchemy queries allowed outside service layer
- All database access must go through service methods
- 1449 tests passing, repository pattern enforced
Critical bug fix: The filter was returning the wrong series because of
a misunderstanding of the episode table semantics.
ISSUE:
- Episodes table contains MISSING episodes (from episodeDict)
- is_downloaded=False means episode file not found in folder
- Original query logic was backwards - returned series with NO missing
episodes instead of series WITH missing episodes
SOLUTION:
- Simplified query to directly check for episodes with is_downloaded=False
- Changed from complex join with count aggregation to simple subquery
- Now correctly returns series that have at least one undownloaded episode
CHANGES:
- src/server/database/service.py: Rewrote get_series_with_no_episodes()
method with corrected logic and clearer documentation
- tests/unit/test_series_filter.py: Updated test expectations to match
corrected behavior with detailed comments explaining episode semantics
- docs/API.md: Enhanced documentation explaining filter behavior and
episode table meaning
TESTS:
All 5 unit tests pass with corrected logic
- Added get_series_with_no_episodes() method to AnimeSeriesService
- Updated list_anime endpoint to support filter='no_episodes' parameter
- Added comprehensive unit tests for the new filtering functionality
- All tests passing successfully
- Add selectinload for episode relationship in get_all()
- Prevents MissingGreenlet error during queue initialization
- Both series and episode are now eagerly loaded
- Add loading status fields to AnimeSeries model
- Create BackgroundLoaderService for async task processing
- Update POST /api/anime/add to return 202 Accepted immediately
- Add GET /api/anime/{key}/loading-status endpoint
- Integrate background loader with startup/shutdown lifecycle
- Create database migration script for loading status fields
- Add unit tests for BackgroundLoaderService (10 tests, all passing)
- Update AnimeSeriesService.create() to accept loading status fields
Architecture follows clean separation with no code duplication:
- BackgroundLoader orchestrates, doesn't reimplement
- Reuses existing AnimeService, NFOService, WebSocket patterns
- Database-backed status survives restarts
- Add year property to Serie entity with name_with_year
- Add year column to AnimeSeries database model
- Add get_year() method to AniworldLoader provider
- Extract year from folder names before fetching from API
- Update SerieScanner to populate year during rescan
- Update add_series endpoint to fetch and store year
- Optimize: check folder name for year before API call
- Update _update_series_in_db to sync missing episodes bidirectionally
- Add delete_by_series_and_episode method to EpisodeService
- Remove downloaded episodes from DB after successful download
- Clear anime service cache when episodes are removed
- Fix tests to use 'message' instead of 'detail' in API responses
- Mock DB operations in rescan tests
- Updated AnimeSeries model docstring to clarify key is primary identifier
- Updated folder field to indicate metadata-only usage
- Updated AnimeSeriesService docstring and get_by_key method
- Updated infrastructure.md with database identifier documentation
- All 996 tests passing