Commit Graph
91 Commits
Author SHA1 Message Date
john-okeefe adc7acbe0f refactor(api): rename ScanEbooks to ScanLibrary for clarity
- Rename ScanEbooks method to ScanLibrary to reflect generic media scanning

- Rename ScanEbooksRequest to ScanLibraryRequest

- Update route handlers in scanner.go and library.go

- Rename scan_ebooks.md to scan_library.md

- No breaking changes: API endpoint remains POST /api/scanner/scan
2026-02-08 13:33:04 -05:00
john-okeefe 75cc26d5d1 feat: update handlers to normalize tags and contributors
Update CreateMediaItem handler:
- Normalize tags for display using NormalizeTags()
- Normalize contributors for display using NormalizeContributors()
- Generate tags_search using NormalizeTagsSearch()
- Generate contributors_search using NormalizeContributorsSearch()
- Pass search fields to database

Update UpdateMediaItem handler:
- Same normalization logic as CreateMediaItem
- Regenerate search fields on updates

Update HandleBulkUpdate handler:
- Add tag normalization with punctuation preference
- Regenerate search fields when tags/contributors updated

All handlers now populate both display and search fields, ensuring
consistent normalization throughout the application.

Relates to Tags & Contributors Migration Phase 6
2026-02-08 11:05:22 -05:00
john-okeefe 5ccbc8cb2c fix(handlers): improve tags validation in bulk update
Changed HandleBulkUpdate to check tags array length before assignment
instead of checking for nil, improving consistency with array handling
and preparing for dual-field normalization implementation.
2026-02-08 00:43:18 -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 eb73e4a9f9 refactor(handlers): Phase 7 - cleanup ebook.go, remove duplicate methods
- Remove 24 duplicate media CRUD methods from ebook.go (884 lines removed)
- Keep 12 scanner/watch/scheduler methods on Handler
- Move request type declarations to media.go:
  * CreateMediaItemRequest
  * UpdateMediaItemRequest
  * CreateMediaNoteRequest
  * UpdateMediaNoteRequest
  * CreateMediaHighlightRequest
  * UpdateMediaHighlightRequest
- Remove unused imports from ebook.go (strconv, pgx)
- Fix library.go to use MediaHandler.ListMediaItems instead of Handler

ebook.go reduced from 1266 lines to 382 lines (70% reduction)
Handler now has focused responsibility: scanner and scheduler operations only

This completes Phase 7 of the ebook.go refactoring plan.

Result: Clean separation of concerns with no duplicate code
2026-02-07 19:56:52 -05:00
john-okeefe f87d8fdff5 refactor(handlers): Phase 4 - create MatchingHandler for sync operations
- Create MatchingHandler struct with db and connManager fields
- Add NewMatchingHandler constructor
- Add getMatchingService helper method
- Move 12 matching methods from book_matching.go:
  * Core matching: QueryBooks, LinkBook, GetUnlinkedBooks, GetBookMatches
  * File aliases: GetDeviceFileAliases, CreateDeviceFileAlias, UpdateDeviceFileAlias, DeleteDeviceFileAlias
  * Bulk operations: BulkLinkBooks, AutoLinkBooks, GetUnlinkedBookSuggestions

Methods copied (not moved) to maintain backward compatibility.
Duplicates will be removed in Phase 7.

This is Phase 4 of the ebook.go refactoring plan.
2026-02-07 19:49:47 -05:00
john-okeefe c2a0ab26b8 refactor(handlers): Phase 3 - create SearchHandler for query operations
- Create SearchHandler struct with db field
- Add NewSearchHandler constructor
- Note: SearchMediaItems already moved to MediaHandler in Phase 2
- SearchHandler reserved for future search-specific operations

This is Phase 3 of the ebook.go refactoring plan.
2026-02-07 19:49:40 -05:00
john-okeefe f4e06e60c6 refactor(handlers): Phase 2 - create MediaHandler with CRUD operations
- Add worker field to MediaHandler struct
- Make NewMediaHandler accept optional worker parameter
- Move 24 media CRUD methods from ebook.go to MediaHandler:
  * Media CRUD: ListMediaItems, GetMediaItem, ListMediaItemsFiltered, CreateMediaItem, UpdateMediaItem, DeleteMediaItem, SearchMediaItems
  * Ratings: CreateMediaRating, GetMediaRating, UpdateMediaRating, DeleteMediaRating
  * Progress: GetMediaReadingProgress, UpdateMediaReadingProgress, DeleteMediaReadingProgress
  * Notes: GetMediaNotes, CreateMediaNote, GetMediaNote, UpdateMediaNote, DeleteMediaNote
  * Highlights: GetMediaHighlights, CreateMediaHighlight, GetMediaHighlight, UpdateMediaHighlight, DeleteMediaHighlight

Methods are copied (not moved) to maintain backward compatibility during refactoring.
Duplicates will be removed in Phase 7.

This is Phase 2 of the ebook.go refactoring plan.
2026-02-07 19:49:35 -05:00
john-okeefe 1be4ea24f2 refactor(handlers): Phase 1 - simplify SetupRoutes to factory function
- Remove all route registration from SetupRoutes
- Make SetupRoutes a pure factory function that only returns Handler
- Routes will be registered via router package in Phase 5
- Maintains backward compatibility with existing function signature

This is Phase 1 of the ebook.go refactoring plan to split the monolithic
Handler into focused handlers (MediaHandler, SearchHandler, MatchingHandler).
2026-02-07 19:49:07 -05:00
john-okeefe 46a03ebfda refactor(router): organize scanner routes into dedicated file
Phase 4 of code organization plan

Changes:
- Create internal/router/scanner.go with registerScannerRoutes()
- Move scanner route registration from handlers to router package
- Update internal/router/router.go to call registerScannerRoutes
- Remove inline scanner routes from internal/handlers/ebook.go

Scanner routes now centralized in router/scanner.go:
- POST /scanner/scan - Scan ebooks
- POST /scanner/start - Start scanner
- POST /scanner/stop - Stop scanner
- GET /scanner/status/:jobId - Get scan status
- POST /scanner/watch/start - Start watch mode
- POST /scanner/watch/stop - Stop watch mode
- GET /scanner/watch/status - Get watch mode status

This improves code organization by separating route registration
from handler logic, making the codebase easier to maintain and
follows the established pattern of organizing routes by feature.
2026-02-07 17:08:00 -05:00
john-okeefe a75cd7e51a refactor: simplify router configuration and handler setup
- Move JWT middleware creation to shared function
- Simplify library route registration
- Add bulk-add-books endpoint to collections
- Clean up duplicate handler setup code
- Improve route organization and maintainability
2026-02-06 17:04:17 -05:00
john-okeefe d9c6be1429 docs: rename DEVELOPMENT.md to development.md and update links
- Rename docs/contributing/DEVELOPMENT.md to development.md (lowercase)
- Update all references from DEVELOPMENT.md to Development.md (titlecase links)
- Update docs/contributing/contributing.md
- Update docs/index.md
2026-02-03 13:54:11 -05:00
john-okeefe 7c4a37175b feat: add SSR data helpers to library handler
- Add GetUserVisibleLibrariesData() method for server-side rendering
- Add GetLibraryTypeData() method for SSR type fetching
- These helpers return data directly instead of JSON responses
- Enables Hybrid SSR pattern while preserving API endpoints
- Add context import for new methods
2026-02-02 16:46:22 -05:00
john-okeefe 6592db2c65 Update Go struct field names: BookmannUuid → BookhoardUuid
Complete the rename by updating:
- DeviceCatalogs struct field: BookmannUuid → BookhoardUuid (models.go)
- Generated queries: Update all references (queries.sql.go)
- Local variables: bookmannUUID → bookhoardUUID (kobo.go)
- Struct field access: catalog.BookmannUuid → catalog.BookhoardUuid

All "bookmann" and "BOOKMANN" references are now eliminated from the codebase.

Part of project rename to Bookhoard.
2026-02-01 16:26:59 -05:00
john-okeefe 5b9f21a592 Final cleanup: Update remaining comments and variable names
Changes:
- Update comments: "Bookmann UUID" → "Bookhoard UUID"
- Rename sidecar struct field: Bookmann → Bookhoard
- Update type names: SidecarBookmannConfig → SidecarBookhoardConfig
- Fix test database name in queue_test.go
- Fix uppercase env var examples in KOBO_SETUP.md

Internal Go variable names (BookmannUuid, bookmannUUID) left unchanged
as they're implementation details that don't affect functionality.

Part of project rename to Bookhoard.
2026-02-01 16:24:58 -05:00
john-okeefe 655ed9225f Update code references and tests: Bookmann → Bookhoard
Code changes:
- main.go: Update cache directory path
- sidecar.go: Update file extension (.bookmann.json → .bookhoard.json)
- security.go: Update CORS example URLs
- queue_test.go: Update test database name
- feed_test.go: Update test assertions
- phase1_integration_test.go: Update test email addresses
- TEST_COVERAGE.md: Update project references

Part of project rename to Bookhoard.
2026-02-01 16:21:10 -05:00
john-okeefe 00a083b60b Rename backend code references: Bookmann → Bookhoard
Backend changes:
- Update import paths: bookmann/internal → bookhoard/internal
- Rename struct fields: BookmannUUID → BookhoardUUID
- Update handler function names: mapContentIdToBookmannUUID → mapContentIdToBookhoardUUID
- Update HTTP response headers: X-Bookmann-* → X-Bookhoard-*
- Update service and middleware references
- Update main.go imports and references

This is part 2 of the project rename to Bookhoard.
2026-02-01 16:11:54 -05:00
john-okeefe 6bdf4bfcd4 refactor: remove deprecated ebook folder handlers and restore auth functions
Phase 2: Dead Code Removal

Removed:
- AddEbookFolder handler (deprecated)
- GetEbookFolders handler (deprecated)
- DeleteEbookFolder handler (deprecated)
- AddEbookFolderRequest struct
- DeleteEbookFolderRequest struct
- EbookFolderResponse struct

Fixed:
- Restored Register function (user registration)
- Restored Login function (user authentication)
- Restored GetProfile function
- Restored UpdateProfile function
- Restored UserProfile struct
- Restored UpdateProfileRequest struct

Note: Critical auth functions were accidentally deleted during cleanup
and have been restored to maintain application functionality.
2026-02-01 14:10:57 -05:00
john-okeefe a67fa0f142 docs: remove backward compatibility comments from ebook handler
- Removed comment about 'Ebook notes handlers (backward compatibility using views)'
- Removed comment references to non-existent GetEbookNotes and GetEbookHighlights
- Cleaned up misleading legacy documentation

This is part of legacy code cleanup Phase 1.
Phase 1: Documentation Cleanup
2026-02-01 14:09:34 -05:00
john-okeefe 4fe8a81f66 feat(opds): add on-the-fly KEPUB conversion for downloads
- Integrate conversion service with OPDS handler
- Convert EPUB to KEPUB format on download request
- Cache converted files to reduce processing time
- Support per-device catalog with format availability
- Maintain backward compatibility with existing downloads
2026-02-01 12:15:49 -05:00
john-okeefe 82ff6356b5 feat(collections,media): add bulk operations for books and collections
Collections:
- HandleBulkAddBooks: add multiple books to multiple collections

Media:
- HandleBulkDelete: delete multiple media items
- HandleBulkUpdate: bulk update book metadata (tags, status)
- Individual result tracking for each operation
- WebSocket broadcasts for collection updates
2026-02-01 12:15:47 -05:00
john-okeefe 924254689c feat(sync): add bulk book linking and auto-linking features
- BulkLinkBooks: manually link multiple unlinked books to media items
- AutoLinkBooks: automatically link books above confidence threshold
- GetUnlinkedBookSuggestions: get match suggestions for specific unlinked book
- Support batch operations with individual result tracking
- Configurable confidence thresholds and limits
2026-02-01 12:15:44 -05:00
john-okeefe c1b3f51380 feat(conflicts): add bulk resolve and dismiss operations
- BulkResolveConflicts: resolve multiple conflicts with configurable strategies
  - most_recent: choose most recently updated source
  - highest_progress: choose source with highest reading progress
  - manual: use specified winning source
- BulkDismissConflicts: dismiss multiple resolved conflicts at once
- ResolveHighestProgress: convenience endpoint for high-progress strategy
- Return detailed results for each operation
2026-02-01 12:15:42 -05:00
john-okeefe eb97a0ef4b feat(analytics): add reading statistics dashboard
- Add reading stats endpoint with daily/monthly history
- Add device usage statistics (sync count, time spent)
- Add popular books view with completion rates
- Server-side rendered analytics page with HTMX
- Date range filtering for reading history
2026-02-01 12:15:38 -05:00
john-okeefe 6e843c93d0 test(collections): add comprehensive rule evaluation test suite
Add extensive unit tests for collection rule matching logic:

Test Coverage (30+ tests):
1. Rule Evaluation Tests:
   - Equals operator (match and no match)
   - Not equals operator (match and no match)
   - Contains operator (case-insensitive)
   - Not contains operator
   - Starts with operator
   - Ends with operator
   - Greater than operator (numeric)
   - Less than operator (numeric)
   - NULL field handling

2. Comparison Function Tests:
   - Case-insensitive string matching
   - Empty string edge cases
   - Numeric edge cases (0, negative, large numbers)
   - Type conversion validation

3. Multi-Rule Tests:
   - Matches first rule
   - Matches second rule (first fails)
   - No matches across all rules
   - Empty rules array

4. Complex Rule Scenarios:
   - Multiple conditions on same book
   - Different field types (genre, author, year, series)
   - Various operators tested
   - Table-driven test for 8 scenarios

5. Edge Cases and Error Handling:
   - Invalid operator returns false
   - Non-existent field returns false
   - Invalid numeric strings handled
   - Type conversion failures

Test Structure:
- Clear test names explaining what's being tested
- Assertion messages explain expected vs actual
- Uses testify/assert for better error messages
- Table-driven tests for multiple scenarios
- Comprehensive edge case coverage

Code Coverage:
- evaluateRule() function
- compareValues() function
- checkRulesAgainstBook() function
- All operators: equals, not_equals, contains, not_contains,
  starts_with, ends_with, greater_than, less_than
- All field types: genre, author, series, copyright_year

Test Results:
- All 30+ tests passing
- Coverage of critical collection rule logic
- Prevents regressions in rule matching
- Validates edge case handling

This test suite ensures the collection auto-assignment
feature works correctly for all supported rule types and operators.
2026-02-01 01:02:42 -05:00
john-okeefe 40c732481a feat(collections): add real-time updates via WebSocket (Limitation #4)
Implement real-time collection updates when books are added/removed:

Backend Changes:
- Added connManager to CollectionHandler struct
- Updated constructor to accept ConnectionManager
- Updated all NewCollectionHandler() calls in ebook.go and main.go
- Added WebSocket broadcasts in AddBooks() handler
- Added WebSocket broadcasts in BulkRemoveBooks() handler
- Broadcasts collection_updated events with:
  - collection_id: Which collection changed
  - action: books_added or books_removed
  - book_ids: Array of affected book IDs
  - count: Number of books changed

Frontend Changes:
- Added WebSocket connection in collections UI
- connectWebSocket() establishes connection to /ws/sync
- Listens for collection_updated events
- Shows toast notification on collection change
- Auto-reloads page after 1 second to show updated book list
- Auto-reconnect on disconnect (5s delay)
- Error handling for WebSocket failures

WebSocket Event Format:
{
  "type": "collection_updated",
  "timestamp": "2026-02-01T12:00:00Z",
  "data": {
    "collection_id": "uuid",
    "action": "books_added",
    "book_ids": ["uuid1", "uuid2"],
    "count": 2
  }
}

User Experience:
- When another user adds books to a collection, all connected clients see:
  1. Toast notification: "Collection updated: books_added (2 books)"
  2. Page auto-refreshes after 1 second
  3. Updated book list displays
- Same for book removal
- Works across multiple browser tabs/devices
- No manual refresh needed

Technical Notes:
- Broadcasts to ALL connected WebSocket clients
- Client-side filtering by collection_id
- Existing progress/conflict broadcasts continue to work
- Connection manager handles broadcast distribution

Resolves Limitation #4: Real-time Collection Updates
2026-02-01 00:54:41 -05:00
john-okeefe 508bfb0387 feat(collections): implement bulk add and remove books (Limitations #2 & #5)
Complete bulk operations for collections management:

BULK ADD BOOKS:
- Implemented searchBooks() with real API integration
- Multi-select checkboxes for book selection
- SelectedBooks Set tracks chosen books
- AddSelectedBooks() sends array to existing endpoint
- Uses existing POST /api/collections/:id/books endpoint

BULK REMOVE BOOKS:
- New endpoint: POST /api/collections/:id/books/bulk-remove
- Checkboxes on each book card for selection
- BooksToRemove Set tracks selections
- Live counter showing selected count
- BulkRemoveBooks() handler removes all in one API call
- More efficient than N individual DELETE requests

Frontend Changes:
- Selected counter badge shows number selected
- Bulk remove button (enabled when books selected)
- Checkboxes on all books for multi-select
- Confirmation dialog for bulk operations
- Toast notifications with counts

Backend Changes:
- BulkRemoveBooks() handler in collections.go
- Accepts book_ids array, returns removed/total counts
- Iterates and removes, counting successes
- Route: POST /api/collections/:id/books/bulk-remove

API Request:
{
  "book_ids": ["uuid1", "uuid2", "uuid3"]
}

API Response:
{
  "removed": 3,
  "total": 3
}

Tests Added:
- TestCompareValues_* (existing)
- TestEvaluateRule_* (existing)

Resolves Limitations #2 (Bulk Operations) and #5 (Bulk Remove)
2026-02-01 00:52:09 -05:00
john-okeefe 592ccddf65 feat(collections): implement rule testing/preview functionality (Limitation #1)
Add ability to test collection rules before saving:
- New API endpoint: POST /api/collections/test-rules
- Evaluates rules against all media items
- Returns matching books with reasons
- Supports all operators: equals, contains, greater_than, etc.
- Works with all fields: genre, author, series, etc.

Backend Implementation:
- TestRules() handler in collections.go
- evaluateRule() matches book properties against rule criteria
- compareValues() handles string/numeric comparisons
- Case-insensitive matching for contains operator

Frontend Integration:
- Updated testRule() function in collection_rules.templ
- Displays matching books with covers and authors
- Shows match reason (which rule criteria matched)
- Limits preview to 20 results with count indicator

Tests Added:
- TestCompareValues_Equals: Exact match validation
- TestCompareValues_Contains: Substring matching
- TestCompareValues_GreaterThan: Numeric comparison
- TestCompareValues_NotEquals: Negation
- TestEvaluateRule_Genre: Genre field matching
- TestEvaluateRule_Author: Author field matching
- TestEvaluateRule_CopyrightYear: Year field matching

API Request Format:
{
  "rules": [{
    "field": "genre",
    "operator": "equals",
    "value": "Science Fiction"
  }]
}

API Response Format:
{
  "matches": [{
    "media_item_id": "uuid",
    "title": "Book Title",
    "author": "Author Name",
    "cover_image_path": "/path/to/cover.jpg",
    "match_reason": "Matched rule: genre equals Science Fiction"
  }],
  "total": 42
}

Resolves Limitation #1: Rule Testing Preview
2026-02-01 00:49:22 -05:00
john-okeefe ed31755a54 feat(api): add collections and device mapping API endpoints
Add comprehensive API support for Phase 9 features:

Collections API (/api/collections):
- GET /collections: List all user collections
- POST /collections: Create new collection
- GET /collections/🆔 Get collection details
- PUT /collections/🆔 Update collection
- DELETE /collections/🆔 Delete collection
- GET /collections/:id/books: Get books in collection
- POST /collections/:id/books: Add books to collection
- DELETE /collections/:id/books/:bookId: Remove book from collection

Device Shelf Mapping API (/api/devices/:id/collections):
- GET: Get all collection-to-shelf mappings for device
- POST: Create new mapping
- PUT /:collectionId: Update mapping
- DELETE /:collectionId: Delete mapping

Book Matching API:
- POST /sync/books/query: Query books by identifiers
- POST /devices/:deviceId/sync/link-book: Manual book linking
- GET /devices/:deviceId/sync/unlinked-books: List unmatched books
- GET /devices/:id/file-aliases: Get device file aliases
- POST /devices/:id/file-aliases: Create file alias
- PUT /devices/:id/file-aliases/:aliasId: Update alias
- DELETE /devices/:id/file-aliases/:aliasId: Delete alias
- GET /books/match: Search for book matches

All new endpoints - no existing APIs modified.
2026-02-01 00:26:27 -05:00
john-okeefe b1ca813ba4 feat(collections): add helper functions for template rendering
Add data retrieval helpers for SSR template rendering:
- GetDeviceMappingsData: Fetch device shelf mappings for device settings UI
- GetUserCollectionsList: Get all user collections for dropdowns and listings
- GetCollectionData: Get single collection with metadata
- GetCollectionBooksData: Get books in a collection

These functions support the Phase 9 frontend features by providing
efficient data access for template rendering without modifying
existing API endpoints.
2026-02-01 00:26:20 -05:00
john-okeefe 7828371c9c feat(progress): implement progress visualization page with sync source tracking (Phase 9-3)
Add progress list page showing reading progress across all devices:
- GetAllProgress API endpoint: Returns all user progress with media details
- GetAllProgressData helper: Fetches progress data for SSR rendering
- ProgressWithMedia struct: Combines progress with book metadata
- Progress page template: Displays progress bars, device icons, sync sources

Features:
- Visual progress bars with percentage
- Device-specific icons (Kobo, KOReader, Web, Mobile)
- Last sync timestamp and device attribution
- EPUB CFI location display
- Cover image support with fallback
- Responsive grid layout

This gives users a unified view of their reading progress across all synced devices.
2026-02-01 00:25:15 -05:00
john-okeefe b3c0c0c225 feat(handlers): Add GetDevicesData helper and update devices template for SSR
- Add GetDevicesData() to DeviceHandler (returns raw data, not JSON)
- Update devices template signature to accept pre-rendered data
- Add server-side rendering of devices and pending registrations
- Update JavaScript to use location.reload() after CRUD operations
- Remove getDeviceIcon dependency on JavaScript function
- Use templ if/else instead of ternary operators for device status

Preserves all API endpoints and backward compatibility
2026-01-31 22:42:21 -05:00
john-okeefe 86eaee5a25 lint(handlers): Use strings.EqualFold for case-insensitive comparison
Fix SA6005 staticcheck warning in OPDS handler
2026-01-31 22:34:48 -05:00
john-okeefe 6495cc2c7c feat(handlers): Add OPDS, collections, book matching, and sync handlers
- Add OPDS handler for device catalog and book downloads
- Add collections handler for collection CRUD
- Add book matching service for cross-device book linking
- Add sidecar handler for Kobo metadata sync
- Add sync handler for device synchronization
2026-01-31 22:32:23 -05:00
john-okeefe d28002e4cb feat(sync): Add Kobo/Koreader sync and conflict handling
- Add Kobo markup/sync endpoints for bookshelves
- Add Koreader progress sync with SHA-256 support
- Add sync conflict detection and resolution
- Update ebook scanner for better file matching
2026-01-31 22:32:09 -05:00
john-okeefe cd8f313b16 feat(handlers): Add helper methods for hybrid SSR
- Add GetPendingRegistrationsData() to DeviceHandler
- Add GetQueueData() to QueueHandler
- Add template types: DeviceData, PendingRegistrationData, ConflictData, QueueItemData
- Add collection types: CollectionData, CollectionDetailData, BookData

All changes are non-breaking and preserve API compatibility
2026-01-31 22:31:33 -05:00
john-okeefe a7f2b83bdd Integrate sync queue system and device cap API
- Start queue processor as background goroutine
- Initialize and register queue handler
- Add queue management routes (7 endpoints)
- Update KOReader handler to use checkpoint sync mode
- Add device cap management route (PUT /api/auth/users/:id/max-devices)
- Register all new endpoints with proper middleware
2026-01-31 13:06:56 -05:00
john-okeefe 5039071ea3 Add admin-configurable device cap per user
- Add max_devices column to users table (default: 10)
- Add UpdateUserMaxDevices database query
- Add CountUserDevices database query
- Add UpdateUserMaxDevices handler with validation (1-100 devices)
- Add PUT /api/auth/users/:id/max-devices endpoint (admin only)
- Update UserList struct to include max_devices field
- Validate user ID format and max_devices range
- Return appropriate errors for invalid requests
2026-01-31 13:06:21 -05:00
john-okeefe 030d30a225 Add queue management API and database queries
- Add 7 new database queries for queue management
- GetStuckSyncQueueItems - Detect stuck items
- GetSyncQueueStats - Queue statistics
- GetNextRetryTime - Exponential backoff calc
- ListAllSyncQueueItems - Admin view
- IncrementSyncQueueAttempts - Retry counter
- Add queue handler with 7 REST endpoints
- GET /api/queue/devices/:id/stats - Queue statistics
- GET /api/queue/devices/:id/items - List device queue
- POST /api/queue/items/:id/retry - Retry failed item
- DELETE /api/queue/items/:id - Delete queue item
- DELETE /api/queue/devices/:id/clear - Clear device queue
- GET /api/queue/items - List all items (admin)
- Add full user/admin access control
2026-01-31 13:06:12 -05:00
john-okeefe 2d2d643873 Add sync conflict detection and resolution system
Implement conflict detection for concurrent reading progress updates from different devices. Adds conflict management endpoints for listing, viewing, and resolving conflicts.

- Add ConflictHandler with CRUD endpoints for conflict management
- Implement automatic conflict detection in KOReader progress updates
- Add WebSocket broadcast for real-time conflict notifications
- Add database query for listing user conflicts by status
- Add integration tests and Bruno API test collection
2026-01-31 11:45:52 -05:00
john-okeefe d440e55f05 Update handlers to work with UUID refresh tokens
- Add parseTokenUUID() helper to convert string to pgtype.UUID
- Update RefreshAccessToken to parse token string to UUID before validation
- Update Logout to parse token string to UUID before revoking
- Update CreateRefreshToken to pass UUID directly to database
- Update auth.go: fix return value order from CreateRefreshToken
- Remove unnecessary comments for cleaner code
2026-01-31 11:44:35 -05:00
john-okeefe 42c3168fcf feat: add server sync to Kobo endpoint and media routes 2026-01-31 00:29:39 -05:00
john-okeefe fef41dc168 feat: add media handler for book download and shelf management 2026-01-31 00:29:38 -05:00
john-okeefe a3aa9f67ac feat: add Kobo device sync support and fix device route protection
- Add Kobo sync handler with markup, bookmark, analytics, and initialization endpoints
- Add Kobo integration tests and Bruno API test collection
- Move device approve/reject routes from public to protected routes
- Enhance test infrastructure with DATABASE_URL support and helper functions
- Fix device GetDevice handler nil pointer handling
- Clean up test reports and session files
2026-01-30 23:58:34 -05:00
john-okeefe 885cbd5d47 feat: broadcast progress updates from KOReader sync
Add WebSocket broadcast to KOReader progress sync:
- Integrate ConnectionManager into KOReaderHandler
- Broadcast progress updates on successful sync
- Include source device information (model, type)
- Real-time updates to all connected clients

When KOReader devices sync reading progress, all connected
WebSocket clients (web browsers, mobile apps, other devices)
receive instant updates.
2026-01-30 21:48:14 -05:00
john-okeefe 4681fb474e feat: integrate ConnectionManager into Handler struct
Add WebSocket ConnectionManager to Handler:
- Add connManager field to Handler struct
- Update NewHandler to accept ConnectionManager parameter
- Update SetupRoutes to pass ConnectionManager through
- Import sync package with alias to avoid conflicts

This enables progress handlers to broadcast updates via WebSocket.
2026-01-30 21:47:56 -05:00
john-okeefe 317a4e82a0 feat: add WebSocket handler with dual authentication
Add WSHandler for WebSocket connection management:
- Upgrade HTTP to WebSocket connections
- Dual authentication support:
  - JWT token via query parameter (web clients)
  - Bearer token via Authorization header (devices)
- Client info extraction for users and devices
- Separate read and write pumps for concurrent I/O
- Ping/pong heartbeat mechanism (30s interval)
- Initial state delivery on connection
- Connection cleanup on disconnect

Implements Week 9 WebSocket endpoint functionality from
Universal Sync Implementation Guide.
2026-01-30 21:47:11 -05:00
john-okeefe 7a5d38b886 Phase 3 Week 7: Implement KOReader sync protocol handlers
- Create SyncProgress for bidirectional progress synchronization
- Create GetMetadata for book progress and annotation retrieval
- Create GetLibrary for user library sync
- Create SyncBookmarks for annotation management
- Support device matching by UUID, file path, or title/author
- Implement immediate and checkpoint sync modes
- Handle bookmarks, highlights, and notes synchronization
- Part of Phase 3 KOReader Integration implementation
2026-01-30 20:55:04 -05:00
john-okeefe a9fdd44471 Add library-based scanning and media item endpoints
- Add POST /api/libraries/:id/scan endpoint for admin library scanning
- Add GET /api/libraries/:id/media-items endpoint for library media items
- Move /api/libraries/types to public endpoint (no auth required)
- Update ScanEbooks handler to support library_id parameter
2026-01-30 20:16:22 -05:00
john-okeefe 23ad70158c Phase 2 Week 5: Device Registration & Management
Implement device registration and management system for universal sync.

Database Changes:
- Add device queries to queries.sql (CRUD operations, registration, auth)
- Add sync queue management queries
- Add conflict resolution queries
- Regenerate sqlc models with new device-related types

Device Handler (devices.go):
- InitiateRegistration: Start device registration with auth URL and QR code
- CheckRegistrationStatus: Poll for registration approval
- ListDevices: Get all devices for current user
- GetDevice: Get specific device details
- UpdateDevice: Update device settings (name, sync settings, frequency)
- DeleteDevice: Remove device from account
- ApproveDevice: User approves device registration via web
- RejectDevice: Reject pending device registration
- ListPendingRegistrations: Show all pending registrations
- generateDeviceToken: Generate secure Bearer token for devices

Device Authentication Middleware (device_auth.go):
- Authenticate: Validate device Bearer tokens
- RequirePermission: Check device permissions by type
- hasPermission: Define permissions per device type
- UpdateLastSeen: Auto-update device last_seen timestamp

Configuration:
- Add BaseURL field to Config for device setup URLs

API Endpoints:
POST /api/devices/register - Initiate device registration
POST /api/devices/register/status - Check registration status
GET /api/devices/approve/:id - Approve device (web UI)
POST /api/devices/reject/:id - Reject device
GET /api/devices - List user's devices
GET /api/devices/:id - Get device details
PUT /api/devices/:id - Update device settings
DELETE /api/devices/:id - Delete device
GET /api/devices/pending - List pending registrations

Bruno API Collection:
- Initiate Device Registration
- Check Registration Status
- List Devices
- Get Device
- Update Device
- Delete Device

Dependencies:
- github.com/skip2/go-qrcode for QR code generation

Device Types Supported:
- koreader: Calibre-compatible sync
- kobo: Kobo sync protocol
- web: Web interface
- mobile: Mobile apps

Device Permissions:
- sync:progress
- sync:annotations
- sync:metadata
- device:manage (web only)
2026-01-30 16:45:10 -05:00