Update NewDevDBSetup collection to create Ebook, Comic, and Manga
libraries with separate IDs (ebook_library_id, comic_library_id,
manga_library_id) instead of a single library_id.
- Fix CreateComicLibrary and CreateMangaLibrary to use correct
names, descriptions, and types instead of duplicating Ebook values
- Update NewDB.sh to run the full setup sequence: register user,
create all three libraries, add folders, then scan all
- Add AddEbookLibraryFolder, AddComicLibraryFolder, and
AddMangaLibraryFolder requests with per-type subfolder paths
- Add ScanAllLibraries request using bru.sendRequest() to scan
each library sequentially via the /api/scanner/scan endpoint
- Update Get Libraries (Admin) to save all three library IDs
- Update List Media Items requests to use ebook_library_id
- Rename library_id to ebook_library_id in Create Library and
Add Library Folder requests
- Add comic_library_id and manga_library_id to environment
Update all library API request files to the current Bruno format
with proper settings blocks, updated sequence numbers, and cleaner
YAML formatting.
Add NewDevDBSetup collection with requests for creating comic, ebook,
and manga libraries, user registration, and folder configuration to
speed up development environment setup.
Add environment variable persistence for library and folder IDs in
Bruno API collection scripts. Create Library and Add Library Folder
endpoints now automatically save their respective IDs to the
environment for use in subsequent requests.
- Update library_id in Bookhoard environment configuration
- Add post-response script to Get Libraries (Admin) endpoint
- Script automatically extracts and saves first library_id from response
- Enables seamless API testing without manual variable updates
This commit improves the Bruno API collection with better formatting,
updated test environment variables, and automation scripts for easier
API testing workflow.
## Environment Updates
- bruno/environments/Bookhoard.yml: Updated test IDs for library_id
and job_id to reflect latest test database state
## Formatting Improvements
Updated all Bruno collection files with consistent formatting:
- bruno/highlights/Create Media Highlight.yml
- bruno/highlights/Update Media Highlight.yml
- bruno/library/Add Library Folder.yml
- bruno/library/Create Library.yml
- bruno/library/Delete Library.yml
- bruno/library/Set Library Visibility.yml
- bruno/media-items/Create Media Item.yml
- bruno/media-items/Create Media Rating.yml
- bruno/media-items/Update Media Item.yml
- bruno/media-items/Update Media Rating.yml
- bruno/media-items/search/Combined Search and Filters.yml
- bruno/notes/Create Media Note.yml
- bruno/notes/Update Media Note.yml
- bruno/progress/Update Reading Progress.yml
- bruno/user/admin/Register Admin User.yml
- bruno/user/auth/Logout User.yml
- bruno/user/auth/Refresh Token.yml
Improvements include:
- Consistent YAML structure and indentation
- Proper multiline string format for JSON bodies
- Moved auth: inherit after headers for consistency
- Added descriptive comments in request bodies
## Automation Features
Added runtime scripts to Create Library.yml:
- after-response script automatically extracts and saves library_id
from API response to environment variables
- Persists library_id for use in subsequent requests
- Reduces manual copy-paste workflow during testing
Updated request bodies with example data:
- Create Media Item.yml: Added complete example with library_id
variable reference, title, author, file_path, file_size, mime_type
- Other files: Updated with proper JSON formatting
## Benefits
- More consistent API collection structure
- Automated workflow reduces manual steps
- Better readability with proper YAML formatting
- Example data makes requests easier to understand
This commit adds comprehensive functionality for filtering collections by library,
improves WebSocket real-time updates with user activity detection, and adds
extensive test coverage.
## Core Features
### Collection Library Filter
- Added library_id parameter to media-items search API
- Collections can now be filtered by specific library
- Toggle UI component for enabling/disabling library filter
- Default state is "checked" when library_id is present
- Consistent behavior across partial and fuzzy search modes
### WebSocket Auto-Reload Mitigation
- Added user activity detection to prevent disruptive page reloads
- Checks if user is actively typing in INPUT/TEXTAREA/SELECT elements
- Skips auto-reload when user is interacting with form elements
- Toast notifications still show for awareness
- Prevents data loss during editing operations
## Implementation Changes
### Backend
- internal/database/queries.sql.go: Added library filter support to search queries
- internal/handlers/media.go: Enhanced search with library_id parameter validation
- internal/handlers/collections.go: Updated collection handlers with library filtering
- internal/sync/websocket.go: Improved broadcast mechanism with user-scoped updates
- internal/router/frontend.go: Pass libraryID to collection templates
### Frontend
- templates/collections.templ: Added library filter toggle UI component
- web/src/collections.ts: TypeScript implementation with WebSocket integration
- templates/collections_templ.go: Generated template code
### Testing
- cmd/server/tests/search_test.go: Added TestCollectionSearchLibraryFilter
- cmd/server/tests/websocket_test.go: Added TestWebSocketUserScopedBroadcast
- New helper functions for creating libraries and media items via API
- Comprehensive test coverage for library filtering and user-scoped broadcasts
## API Documentation Updates
### Bruno Tests (Comprehensive Documentation)
- bruno/collections/*: Added detailed API documentation for all collection endpoints
- bruno/devices/*: Added device management and sync API documentation
- bruno/devices/kobo/api.yml: Kobo-specific sync protocol docs
- bruno/devices/koreader/api.yml: KOReader-specific sync protocol docs
- bruno/opds/*: Added OPDS feed and download endpoint documentation
- bruno/library/browse-folders.yml: Library folder browsing API docs
### New Bruno Tests
- bruno/media-items/Search All Libraries.yml: Test search without library filter
- bruno/media-items/Search Specific Library.yml: Test search with library filter
- bruno/media-items/Search Invalid Library ID.yml: Test error handling
## Documentation
- docs/developer/api/media-items/search_media_items.md: Updated with library_id parameter
- IMPLEMENTATION_COLLECTION_FIX.md: Comprehensive implementation guide with test scenarios
## Testing
### Integration Tests
- Library filter tests verify correct filtering across multiple libraries
- Invalid library_id tests ensure proper error handling
- WebSocket tests verify user-scoped broadcast behavior
- User A no longer receives User B's collection updates
### Manual Testing Scenarios
- Open collection in multiple tabs - updates propagate correctly
- Type in search box while another tab adds books - no disruptive reload
- Add/remove books from collection - toast notifications appear
- Toggle library filter - results update dynamically
## Technical Details
- WebSocket broadcasts are now user-scoped for privacy
- Active element detection uses tagName and contenteditable attributes
- Library ID validation uses UUID format checking
- Progressive enhancement maintained - page works without JavaScript
- All changes follow PROJECT_GUIDELINES.md conventions
- TypeScript only for frontend logic
- TailwindCSS only for styling
- Procedural programming style throughout
## Breaking Changes
None - all changes are additive and backward compatible.
- Update API field from scan_frequency_minutes to scan_poll_interval_seconds
- Update database schema default value key
- Update Bruno API collection requests and documentation
- Update OpenAPI documentation examples and field descriptions
- Update endpoint path in Get Scan Settings Bruno collection file
- Update endpoint path in Update Scan Settings Bruno collection file
- Update endpoint path in API reference documentation
This corrects a typo in the API path where 'library' was singular instead of plural.
Fix 1 - File modification time for created_at:
- Get file.ModTime() in processMediaFile and pass to CreateMediaItem
- Modified SQL INSERT to include created_at column
Fix 2 - Force rescan UPDATE instead of DELETE+INSERT:
- Changed force rescan logic to call updateMediaItem instead of delete + create
- Preserves created_at timestamp on force rescan
Fix 3 - GetMediaItemByFilePath filters by library_id:
- Added library_id to WHERE clause in SQL query
- Created GetMediaItemByFilePathAnyLibrary for cross-library lookups (KOReader)
- Added SetLibraryID method to MediaScanner
- Updated handler to call SetLibraryID for watch mode
Fix 4 - File deletion handling with persistent logging:
- Added fsnotify.Remove handler in WatchChanges
- Added orphan cleanup in ScanFolders after scan completes
- Created scanner_logger.go with daily log rotation (7 days)
- Logs to /app/logs/scanner-deletes-YYYY-MM-DD.log and scanner-errors-YYYY-MM-DD.log
- Individual deletes with enhanced safety logging
Note: Integration tests can now safely scan /app/uploads because
GetMediaItemByFilePath now filters by library_id, preventing
cross-library interference.
- Create bruno/library/browse-folders.yml
- Single manual test case for admin context
- Unit/integration tests cover all scenarios (no auth, user, admin)
- Bruno provides quick manual API contract verification
Fixes: Issue 2 (manual testing)
- Move all files from bruno-yaml/* to bruno/*
- Maintains existing directory structure within categories
- Updates bruno/user/auth files with OAuth2 refresh token flow
- Updates bruno/user/profile files for user profile management
- Adds bruno/dashboard/ directory with dashboard API tests
- Preserves all existing test scenarios and OpenCollection YAML format
- No functional changes - file reorganization only
- Rename ebook_id environment variable to media_item_id
- Update scanner endpoint example paths and documentation
- Update library endpoint documentation
- Keep library type 'ebooks' where appropriate (valid type value)
Add missing Bruno requests for all API endpoints:
Library Management:
- Get Library - retrieve single library details
- Update Library - modify existing library
- Delete Library - remove library and media items
- Delete Library Folder - remove folder from library
- Get Library Stats - retrieve library statistics
Media Items Management:
- Create Media Item - add new media with full metadata
- Update Media Item - modify existing media metadata
- Delete Media Item - remove media from library
- Get Media Rating - retrieve single media rating
- Delete Media Rating - remove user's media rating
Coverage now complete: 47/47 API endpoints have Bruno requests
Organized requests in proper folder structure for maintainability
- Remove all ebook-specific API requests (15 files deleted)
- Rename Scan Ebooks.bru to Scan Media Items.bru
- Update API paths from /api/ebooks to /api/media-items
- Update base URL and environment configuration
- Maintain all existing media-items, library, auth, and progress tests
Aligns Bruno collection with unified media-items API architecture
- Use c.Get("user").(database.Users) instead of c.Get("user_id").(string)
- Extract userUUID from user.ID.Bytes ([16]byte)
- Properly convert to pgtype.UUID for service layer
- Remove unnecessary uuid.Parse call
This fixes 500 Internal Server Error when creating libraries via API.
The JWT middleware sets user as database.Users struct, not string.
Related to Bruno Create Library request testing.
Standardize all Bruno environment variables to use snake_case convention
(aligned with Go naming practices) and remove duplicate camelCase variants.
Changes:
- Environment file cleanup:
- Remove: baseUrl, ebookid, fakebookid, libraryId, mediaItemId, isVisible, refreshToken
- Standardize: fakebookid → fake_book_id, isVisible → is_visible, refreshToken → refresh_token
- All variables now use consistent snake_case format
- Update all Bruno requests to use standardized variables:
- ebooks: {{ebookid}} → {{ebook_id}}
- library: {{libraryId}} → {{library_id}}
- media-items: {{mediaItemId}} → {{media_item_id}}
- visibility: {{isVisible}} → {{is_visible}}
- auth: {{refreshToken}} → {{refresh_token}}
Benefits:
- Single source of truth for each variable
- Consistent with Go naming conventions
- No ambiguity about which variable name to use
- Cleaner, more maintainable codebase
- Convert all JSON tests to JavaScript functions for bruToJsonV2 compatibility
- Update authentication to use 'inherit' instead of manual headers
- Fix hardcoded URLs to use {{base_url}} variables
- Standardize variable syntax from {{ _.var }} to {{var}}
- Add comprehensive API documentation to all requests
- Update environment variables with missing required fields
- Apply consistent structure: meta, http method, headers, tests, vars, settings, docs
- Enhanced validation with proper error handling and field checks
- Add admin dashboard at /admin route consolidating all user settings
- Move user preferences (username, email, password, theme) from separate page
- Add ebook library preferences section with folder management
- Add scan settings (frequency and auto-scan toggle) with database persistence
- Create database migration for scan_frequency_minutes and auto_scan_enabled columns
- Add API endpoints for scan settings management:
- PUT /api/library/scan-settings - Update scan preferences
- GET /api/library/scan-settings - Get current scan settings
- Update dashboard navigation to link to admin dashboard
- Remove old preferences.html template (functionality moved to admin)
- Create Bruno API testing files for library endpoints
- Add real-time folder loading and management in admin interface
- Implement scan settings persistence and retrieval from database