33 Commits
Author SHA1 Message Date
john-okeefe c2f72ca785 docs(bruno): correct rating scale and endpoint paths
The Bruno collection docs mislabeled the rating system and referenced
endpoints that do not exist.

- Update Media Rating.yml: the rating value is a 1-10 integer scale
  (displayed as 1-5 stars with half-star precision), not "typically 1-5".
- opencollection.yml: the rating routes live under
  /api/media-items/:id/rating (not /api/ratings/:media_id), GET returns
  null (not 0) when unrated, and document the PUT upsert route. Correct
  the scale to 1-10 here as well.
2026-07-30 13:08:14 -04:00
john-okeefe 58a30b6561 chore(bruno): add multi-library dev setup with scan-all and folder requests
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
2026-04-19 18:08:39 -04:00
john-okeefe 53cc674435 chore(testing): remove obsolete Bruno collection folder configurations
Remove unused folder.yml configuration files from media-items filters
and search collections as part of ongoing API collection cleanup.
2026-04-10 19:35:33 -04:00
john-okeefe 7f6c6d903e test: update Bruno test data for media items
Update Bruno API test collections with latest test data:

Bookhoard.yml environment:
- Update media_item_id to current database value after recent
  database recreation/schema updates

Create Media Rating test:
- Change test rating from 8 to 7 to test different rating value
  for validation

These are test infrastructure updates only, no application code changes.
2026-03-29 00:27:28 -04:00
john-okeefe 0c1a55d6e3 chore: remove obsolete documentation and API collection files
Cleanup of project files:
- Remove CALIBRE_OPF_IMPLEMENTATION.md (obsolete documentation)
- Remove Bruno API collection files for field value searches:
  - Field Values Search - Authors.yml
  - Field Values Search - Genres.yml
  - Field Values Search - Languages.yml
  - Field Values Search - Series.yml

These files are no longer needed as the functionality has been
implemented and the API has evolved.
2026-03-28 00:46:20 -04:00
john-okeefe 99f95d2ff1 test: update search API request parameters and sequence numbers
- Update Combined Search and Filters: change has_cover to true, tags_filter to fic
- Update sequence numbers for all search requests (1-7)
- Ensure consistent request ordering in search folder
2026-03-27 21:14:36 -04:00
john-okeefe af3c3019cf refactor: reorganize Bruno API collection for better structure
- Remove obsolete scenarios/ folder and move requests to root media-items/
- Create new filters/ folder for field value autocomplete searches
- Move Field Values Search requests from search/ to filters/ for clarity
- Move Search Media Items from scenarios/ to search/ for consistency
- Update sequence numbers across all media-items requests (2-13)
- Remove redundant folder configuration files
- Improve API collection organization for better discoverability
2026-03-27 21:14:34 -04:00
john-okeefe bac77312b4 test: update Bruno API collection for has_cover filter
Updated the Bruno API test collection to include tests for the new
3-state has_cover filter functionality.

Changes:
- Added test cases for has_cover=true, has_cover=false, and has_cover
  not specified to verify all three states work correctly
- Updated environment configuration to support the new filter parameter

These tests verify that the has_cover filter properly handles:
- NULL (not specified): Returns all books
- TRUE: Returns only books with cover images
- FALSE: Returns only books without cover images

This ensures the 3-state boolean implementation works correctly across
all scenarios and prevents regression of the bug where searches were
returning 0 results.
2026-03-27 18:08:18 -04:00
john-okeefe d8c63b8b8e test: update Bruno API collection with current database test values
Update test data values across Bruno API collection to reflect current
database state and improve test parameter relevance:

- Environment variables: Refresh library_id and job_id UUIDs to current
  database values for accurate testing
- Combined Search test: Update tags_filter from "scifi" to "fict" for
  broader genre coverage and extend year_max from 2000 to 2026 for
  modern title inclusivity
- Fuzzy Author Filter test: Change author_filter from "Conan" to
  "orwell" for consistent author search testing

These updates ensure API tests use valid reference data that matches
the development database state.
2026-03-26 21:01:47 -04:00
john-okeefe 6b518462f9 test: update Bruno API collection with new test data values
Update test environment and request files to use different test data:
- Update job_id variable to new test job UUID
- Change search test queries from Foundation/Asimov to 1984/Orwell
- Change series search from Foundation to Haley
- Add force parameter to scanner test

These updates provide fresh test data for API testing and
demonstrate search functionality with different media items.
2026-03-26 15:35:25 -04:00
john-okeefe 53046f5499 test: improve Bruno API collection formatting and automation
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
2026-03-26 10:34:23 -04:00
john-okeefe f28dca1334 refactor: reorganize Bruno API collection into subdirectories
- Move search-related requests into bruno/media-items/search/ subdirectory
- Rename Fuzzy Genre Filter.yml to Fuzzy Tags Filter.yml
- Keep scenario-based requests in bruno/media-items/scenarios/
- Improve collection organization and discoverability

This reorganization makes the Bruno API collection more organized by
grouping search endpoints together and updating genre filter to tags filter.
2026-03-25 20:40:25 -04:00
john-okeefe dc0d037e06 test: update Bruno requests for tags filter
- Update Combined Search and Filters to use tags_filter
- Update Field Values Search to cover tags autocomplete
- Add fuzzy matching examples for tags
- Update search scenarios to use tags instead of genre

Updates the Bruno API test collection to use the new tags filter
instead of the genre filter, including fuzzy matching examples.

Relates to IMPLEMENTATION_TAGS_FILTER.md Phase 6
2026-03-25 20:38:29 -04:00
john-okeefe 74009f66b5 refactor: restructure Bruno API collection for consistency
Standardize all Bruno API request files with consistent formatting and
structure to improve maintainability and readability.

Changes include:
- Consolidate URL parameters into main URL instead of separate definitions
- Standardize quote style (double quotes throughout)
- Add proper settings section with defaults (timeout, redirects, etc.)
- Improve YAML formatting with literal style for multi-line content
- Remove redundant fields (disabled: false)
- Clean up header and body structure
- Update sequence numbers for better organization
- Add scenarios folder structure for organized test groupings

Removes obsolete Search Invalid Library ID test case.

Environment configuration updated with new library_id for testing.

These changes improve the Bruno collection's maintainability and make
it easier to create new API requests following established patterns.
2026-03-25 18:03:00 -04:00
john-okeefe fc617c3e46 docs: update Bruno collection with unified search endpoints
- Update Search All Libraries.yml with expanded documentation
- Add Fuzzy Author Filter.yml (author_filter=asimov example)
- Add Fuzzy Genre Filter.yml (genre_filter=scifi example)
- Add Combined Search and Filters.yml (q=foundation&author_filter=asimov example)
- Add Exact Match With Quotes.yml (q="Foundation and Empire" example)
- Add Field Values Search - Authors.yml (autocomplete dropdown example)
- Add Field Values Search - Genres.yml (autocomplete dropdown example)
- Add Field Values Search - Series.yml (autocomplete dropdown example)
- Add Field Values Search - Languages.yml (autocomplete dropdown example)
- Remove deprecated Filter Media Items.yml scenario

All files include request config, params, examples, expected responses, and success criteria for API interaction during development.
2026-03-23 22:38:28 -04:00
john-okeefe 9b3d8cc949 feat: implement collection library filter with WebSocket improvements and test coverage
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.
2026-03-04 22:37:47 -05:00
john-okeefe f859b2714d refactor(bruno): reorganize file structure from bruno-yaml to flat bruno directory
- 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
2026-02-17 20:22:21 -05:00
john-okeefe 96730d9475 docs: add Carousel dashboard implementation plan 2026-02-17 17:00:46 -05:00
john-okeefe b364aee631 test(bruno): update API tests for /api/media-items/ endpoints
- Update bulk-delete test: endpoint URL, request field (book_ids → media_item_ids), response field (success → deleted), documentation
- Update bulk-update test: endpoint URL, request structure (updates → media_item_updates), response field (success → updated), documentation
- Update download test: endpoint URL (/api/books/ → /api/media-items/), documentation
2026-02-10 19:58:41 -05:00
john-okeefe 8f00bfba66 docs: Add library folder validation to Create Media Item Bruno test
- Add test_create_media_item_no_folders test case
- Document 400 error for libraries without folders
- Add prerequisites section explaining folder requirement
- Include setup workflow example
- Link to Add Library Folder Bruno request

Related: Handler validation and service layer changes
2026-02-09 14:29:09 -05:00
john-okeefe 3117ce54ec refactor(bruno): migrate API tests to Bruno DSL format
- Convert all existing .bru files from JSON to Bruno DSL format
- Remove obsolete files (conflicts/api.bru, kobo/Kobo Initialization.bru)
- Update auth configuration to use 'inherit' instead of explicit bearer tokens
- Add comprehensive documentation to all test files
- Improve test scripts with proper assertions and error handling
2026-02-08 20:49:06 -05:00
john-okeefe 798de7947a docs: update media item bruno docs with normalization info
Update Update Media Item.bru to document normalization behavior:
- Note that tags and contributors are auto-normalized (same as Create)
- Document response includes updated search fields

Relates to Tags & Contributors Migration documentation updates
2026-02-08 11:27:39 -05:00
john-okeefe 516cec5a7f feat: migrate tags and contributors from TEXT to TEXT[] arrays
Convert tags and contributors columns from comma-separated strings to PostgreSQL
TEXT[] arrays for better data normalization and query performance.

Database Changes:
- schema.sql: Change tags/contributors from TEXT to TEXT[]
- schema.sql: Add GIN indexes for fast array searches
- queries.sql: Update search queries to use ANY() operator
- queries.sql: Update fuzzy search with unnest() for arrays

Generated Code (sqlc):
- models.go: Auto-generated with []string types for tags/contributors
- queries.sql.go: Auto-generated with proper array handling

Handler Changes:
- media.go: Update request structs to use []string for tags/contributors
- media.go: Remove pgtype.Text wrapping, use direct array assignment
- media.go: Add tag normalization in CreateMediaItemHandler
- collections.go: Update tags evaluation to join arrays for comparison
- collections.go: Add strings import for Join() function

Service Changes:
- ebook_scanner.go: Update EbookMetadata struct to use []string
- ebook_scanner.go: Remove string Join(), assign arrays directly
- collection_service.go: Update tags rule evaluation to join arrays
- collection_service.go: Add strings import

New Utilities:
- internal/utils/tags.go: Create NormalizeTags(), JoinTags(), SplitTags()
- Normalizes tags by trimming, lowercasing, removing duplicates/empties

API Documentation:
- bruno/media-items/Create Media Item.bru: Update examples to use arrays
- bruno/media-items/Update Media Item.bru: Update examples to use arrays
- Update docs: tags/contributors now array of string

Breaking Change:
- JSON format changes from "tags": "tag1,tag2" to "tags": ["tag1", "tag2"]
- Tests already use array format (no changes needed)

Benefits:
- GIN indexes enable faster array searches
- Normalization prevents data quality issues (case, duplicates)
- Array operations use PostgreSQL native operators (ANY, &&, unnest)
- Better separation of concerns (no string parsing in application)
2026-02-07 22:53:12 -05:00
john-okeefe 96825e3bc2 Rename API test collection references: Bookmann → Bookhoard
Bruno API test updates:
- Update test assertions: X-Bookmann-* → X-Bookhoard-*
- Update variable names and references in test scripts
- Update documentation and comments in API tests

This is part 4 of the project rename to Bookhoard.
2026-02-01 16:12:05 -05:00
john-okeefe e28776c7a6 test(api): add Bruno API tests for devices, media items, and progress 2026-02-01 13:21:35 -05:00
john-okeefe 45ba922c68 test: add Bruno API test collections for Kobo and media endpoints 2026-01-31 00:29:40 -05:00
john-okeefe 75ff657e58 feat: add 16 missing Bruno requests for complete API coverage
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
2026-01-30 14:26:22 -05:00
john-okeefe ba31e1491e refactor: update Bruno API collection for media-items system
- 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
2026-01-30 13:52:06 -05:00
john-okeefe f5a01ece46 Add tests for sorting and filtering functionality
- Add integration tests for sorting (sorting_test.go)
  - Test sort by title, author, page_count, copyright_year, genre
  - Test pagination with sorting
  - Test invalid sort parameter defaults
  - Cover no user, user, and admin contexts
- Add integration tests for filtering (filtering_test.go)
  - Test filter by genre, language, year range, has_cover
  - Test combining multiple filters
  - Test filtering with pagination and sorting
  - Cover no user, user, and admin contexts
- Add Bruno API test for sorting
- Add Bruno API test for filtering
2026-01-30 08:33:03 -05:00
john-okeefe cec0b17bde test: add search tests and Bruno API collection
- Add comprehensive search integration tests (search_test.go)
- Test no user, user, and admin contexts
- Test partial matching, fuzzy fallback, special characters
- Add Bruno API test for search endpoint
- Fix missing closing parenthesis in test structure
2026-01-29 20:21:01 -05:00
john-okeefe 6ed69005b5 refactor(bruno): standardize all variables to snake_case naming convention
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
2026-01-29 10:06:00 -05:00
john-okeefe 8db5939892 refactor: standardize Bruno API requests with bruToJsonV2 format
- 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
2026-01-28 20:13:56 -05:00
john-okeefe 81fa177fe6 feat: create Bruno requests for library system API
- Add library management requests (CRUD operations)
- Create media items API requests for library content
- Implement library visibility controls
- Add user library access management
- Update deprecated ebook folder endpoints with migration guide
- Include comprehensive documentation and test cases
- Replace collection.bru with proper dashboard request

Complete Bruno collection supporting new multi-library architecture
2026-01-28 11:15:36 -05:00