- Replace hardcoded /app/uploads with getUploadPath()
- Update assertions to use dynamic paths
- Improve test log message to show actual path used
- Ensures tests work in both container and host environments
- Add isRunningInContainer() to detect test runtime environment
- Add getUploadPath() to resolve upload paths (container vs host)
- Add getCachePath() to resolve cache paths appropriately
- Update setupTestServer() to use dynamic path helpers
- Support environment variable overrides for flexibility
- Add os import for file system checks
- Create worker for background tasks (3 concurrent workers)
- Create CollectionHandler for collection endpoints
- Create MediaHandler with worker for media CRUD operations
- Create SearchHandler for query operations
- Create MatchingHandler for book matching/linking operations
- Update routerConfig to include new handlers instead of EbookHandler
All handlers properly initialized and passed to router package.
System is fully operational with new handler architecture.
This is Phase 6 of the ebook.go refactoring plan.
Remove the CollectionHandler field from router.Config struct literal
in cmd/server/tests/test_helpers.go. This field was removed from
the Config struct in a previous commit.
The collection routes are registered directly in handlers.SetupRoutes()
and don't need to be passed through the router config.
Remove the CollectionHandler field from router.Config struct and its
initialization in main.go. This field was never used - collections are
registered directly in handlers.SetupRoutes() where a CollectionHandler
is created locally.
Changes:
- Remove CollectionHandler field from internal/router/router.go Config
- Remove CollectionHandler: nil line from cmd/server/main.go
This cleans up dead code from the router refactoring. Collections
continue to work correctly as they are registered in SetupRoutes().
Related: Router refactoring completion
Phase 5: Application Lifecycle Management
Creates internal/app package for proper lifecycle management, signal
handling, and graceful shutdown of all services.
Changes:
- Create internal/app/app.go with App lifecycle manager
- Handles SIGINT, SIGTERM, SIGQUIT signals
- Graceful shutdown with 30-second timeout
- Manages HTTP server shutdown
- Manages scheduler start/stop
- Update cmd/server/main.go to use app lifecycle manager
- Replace defer-based cleanup with proper signal handling
- Server starts in background goroutine
- Blocks on app.Start() until shutdown signal
- Clean shutdown of all services
Benefits:
- Proper signal handling (Ctrl+C, kill, docker stop)
- Graceful shutdown prevents data corruption
- No more os.Exit(1) bypassing defer cleanup
- All services stopped in correct order
- Server stops accepting new connections first
- Then scheduler and background services stopped
Technical details:
- Uses sync.Mutex for shutdown safety
- Context with timeout for shutdown operations
- Channel-based coordination for shutdown completion
- Logs all lifecycle events for debugging
Fixes issue where e.Logger.Fatal() would call os.Exit(1)
immediately, skipping defer cleanup and causing unclean shutdown.
Phase 1 of scanner restoration plan
Changes:
- cmd/server/main.go: Capture ebookHandler from router.RegisterRoutes
- cmd/server/main.go: Start scheduler in background goroutine
- cmd/server/main.go: Defer StopScheduler() for graceful shutdown
- cmd/server/main.go: Start watch mode for all libraries after 2-second delay
- internal/router/router.go: Return ebookHandler from RegisterRoutes
This restores critical functionality that was removed during router refactor:
- Auto-scanning now works again
- Watch mode starts automatically for all libraries
- Graceful shutdown properly stops scheduler
Fixes issue where scheduler and watch mode were not starting on server boot.
- Rename phase1_integration_test.go to universal_progress_integration_test.go
(tests universal reading progress feature)
- Rename ebook_scanner_phase2_test.go to ebook_scanner_hash_test.go
(tests hash calculation and file identification utilities)
These renames make the test suite more maintainable and self-documenting.
- Fix float64 type assertions for JSON numbers in conflicts bulk operations
- Create fresh HTTP request body for duplicate book tests
- Add nil checks for type assertions in device cap tests
- Properly extract user_id from JWT for existing users
- Trim trailing whitespace from response bodies
- All 3 previously failing tests now passing
Test results: 19/22 passing (86.4%)
Fixes: TestCollectionsBulkOperations, TestConflictsBulkDismiss, TestUpdateUserMaxDevices
- Remove handler parameter from test function calls
- Update test signatures to match new setupTestServer return values
- Fix compilation errors after test helper refactoring
- Maintain websocket test functionality
- Remove handler parameter from test function calls
- Update test signatures to match new setupTestServer return values
- Fix compilation errors after test helper refactoring
- Ensure test consistency for opds, queue, and auth endpoints
- Remove handler parameter from test function calls
- Update test signatures to match new setupTestServer return values
- Fix compilation errors after test helper refactoring
- Maintain test functionality for kobo and media endpoints
- Remove handler parameter from test function calls
- Update test signatures to match new setupTestServer return values
- Fix compilation errors after test helper refactoring
- Ensure test consistency across all test files
- Remove handler parameter from test function calls
- Update test signatures to use new return values from setupTestServer
- Fix compilation errors after test helper refactoring
- Maintain test functionality while simplifying setup
- Replace manual config construction with config.LoadConfig()
- Remove problematic password validation logic
- Apply test-specific overrides after loading config
- Clean up unused imports (os, strings)
- Tests now use same configuration method as main application
- Fixes database authentication issues in integration tests
Changed login test password from 'Test@Pass123!' to 'testpass123' and updated
bcrypt hash to use Go's golang.org/x/crypto/bcrypt library instead of Python's bcrypt.
Changes to test_helpers.go:
- Import router package and use router.RegisterRoutes()
- Create all necessary handlers (auth, device, koreader, ws, conflict, analytics, queue, opds)
- Add proper validator setup
- Add CustomValidator type
- Remove unused pgtype import
This makes integration tests use the same router configuration as production,
ensuring tests cover the actual API behavior and route structure.
Health check endpoint:
- Add /health endpoint that pings database with 2-second timeout
- Returns 200 when DB connected, 503 when unavailable
- Provides true end-to-end health verification
Frontend routes restoration (routes removed in c5f327b):
- Add public routes: /, /login, /register with smart auth detection
- Add redirect routes: /bookshelf, /dashboard
- Add admin routes: /admin, /admin/profile, /admin/library
- Add SSR routes: /api/devices-page, /api/conflicts-page
- Add 'FRONTEND ROUTES - DO NOT DELETE' comment block to prevent future removal
Docker Compose healthcheck:
- Update to use curl on /health endpoint (pg_isready not in Alpine)
- Add 10s start_period for app initialization
- Accurately reflects app + database health status
All changes maintain backward compatibility and existing API behavior.
- Add LibraryData type to templates/types.go
- Update bookshelf template to accept libraries parameter
- Render libraries server-side for faster initial page load
- Libraries now populated from server data instead of AJAX fetch
- JavaScript still uses API for dynamic content (bookshelf items)
- Update /bookshelf route to fetch libraries server-side before render
- Properly handle UUID and pgtype.Text conversions
- Maintain API endpoint compatibility for JavaScript calls
This improves initial page load performance while preserving
dynamic functionality via API calls.
Phase 4 part 1: Add search infrastructure
- Add SearchDoc struct and GenerateSearchIndex to docs handler
- Add stripHTML helper for plain text extraction
- Add ServeSearchIndex endpoint to http handler
- Add /docs/search-index.json route in main.go
- Search index includes all documentation files with ID, title, content, URL
- Add internal/docs package with markdown renderer (goldmark)
- Create docs layout template with sidebar navigation
- Implement hierarchical navigation auto-generated from docs folder
- Add table of contents generator (extract ## headings)
- Add syntax highlighting for code blocks (highlight.js)
- Add mobile responsive design
- Add /docs routes to main.go
The documentation system features:
- Dark theme matching app design
- Collapsible sidebar sections (Getting Started, User Guide, Device Setup, API Reference, Contributing)
- Table of contents for each page
- Breadcrumb navigation
- Full-text search (client-side JavaScript, API endpoint ready)
- Syntax highlighting for code blocks
- Mobile-friendly with hamburger menu
All documentation is served from /docs route, no authentication required.
Markdown files are rendered using goldmark with GFM extensions and syntax highlighting.
Test file updates:
- Update import paths in test files: bookmann/internal → bookhoard/internal
- Update test helper functions and references
- Update test comments and documentation
This is part 6 of the project rename to Bookhoard.
New test file with 5 test suites:
- TestMediaItemISBNNormalization (8 test cases)
- TestMediaItemISBNEdgeCases (3 test cases)
- TestMediaItemsPagination (5 test cases)
- TestMediaItemLibraryRequirement (2 test cases)
- TestUpdateMediaItemISBN (1 test case)
Features:
- Tests use /api/media-items endpoint (not deprecated /api/ebooks)
- Real API calls (not mock handlers)
- Comprehensive ISBN-10/ISBN-13 normalization coverage
- Pagination validation with limit/offset edge cases
- Library requirement validation
This replaces the functionality lost from isbn_and_library_test.go
with modern, working tests using current API endpoints.
Phase 3: Test Suite Cleanup - Replacement Tests
- Deleted isbn_and_library_test.go (507 lines)
- All tests used deprecated /api/ebooks endpoint
- Tests were mock-based, not real API calls
- Functionality will be replaced with modern tests
This is part of legacy code cleanup Phase 3.
Phase 3: Test Suite Cleanup
- Removed TestPaginationAndFiltering function
- Deleted 4 test cases using deprecated /api/ebooks endpoint
- Tests for pagination already exist in library_test.go using /api/media-items
This is part of legacy code cleanup Phase 3.
Phase 3: Test Suite Cleanup
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
Add SSR routes for collections, progress, and devices pages:
Progress Page (/api/progress):
- Fetches all user progress with device sync sources
- Maps device types to icons (Kobo, KOReader, Web, Mobile)
- Server-renders progress visualization with real data
Collections Pages (/api/collections):
- GET /collections: List all user collections with SSR
- GET /collections/🆔 Collection detail page with books SSR
- Fetches collection metadata and book listings
- Converts database models to template data structures
Helper Functions:
- getTemplateUserWithTheme: Fetches user with theme preference
- Proper error handling for missing data
All routes use JWT authentication and fetch data server-side
for better SEO and initial page load performance. Client-side
enhancements can be added via HTMX for interactive features.
These routes support the Phase 9 frontend implementation with
proper SSR rendering for improved performance and accessibility.
- Update conflicts.templ to accept pre-rendered data
- Update queue.templ to accept pre-rendered data
- Update /conflicts and /queue routes in main.go for SSR
- Update stats rendering to use server-side values
- Add server-side conflict list rendering
- Add server-side queue list rendering
- Update conflicts.js to use location.reload() after operations
- Update queue.js to use location.reload() after operations
- Remove initial load calls from JavaScript files
Preserves all API endpoints and backward compatibility
- Add /devices route for device management interface
- Add /conflicts route for sync conflict resolution
- Add /queue route for sync queue management
- Add comprehensive tests for device cap management
- Add test suite for queue management
- Test successful updates (5, 10, 50, 100 devices)
- Test validation failures (0, -1, 101, 1000 devices)
- Test authentication requirements (no token, non-admin)
- Test non-existent user ID
- Test missing user ID in URL
- Test max_devices field in user list response
- Add 20+ test cases across 7 test functions
- Helper functions for admin user creation and login
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
- Test login returns both access_token and refresh_token
- Test refresh endpoint accepts UUID token and returns new access_token
- Verifies end-to-end refresh token flow works correctly
- 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
Add WebSocket infrastructure to main server:
- Import sync package for ConnectionManager
- Create and start ConnectionManager with cleanup task
- Initialize WSHandler with auth dependencies
- Add /ws/sync WebSocket endpoint
- Update handler initialization to pass ConnectionManager
The WebSocket endpoint at /ws/sync enables real-time progress
updates across all connected clients (web, mobile, devices).
- Add KOReader sync endpoints to main application router
- Create Bruno API collection for testing KOReader endpoints
- Add integration tests for KOReader functionality
- Include comprehensive README with setup instructions
- Test coverage for progress, metadata, library, and bookmarks sync
- Part of Phase 3 KOReader Integration implementation
- 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
- Remove manual device ID generation, use database-generated IDs
- Add comprehensive test helpers (setupTestServer, loginTestUser, getTestUserID)
- Add cleanup step for existing test users in integration tests
- Fix UUID parsing from database responses
Test Files Added:
- integration_test.sh: Automated integration test script
* Tests full user flow: register, login, library creation, scanning
* Tests device registration and management
* Color-coded output with pass/fail tracking
* Generates detailed test results report
- cmd/server/tests/device_test.go: Unit tests for device endpoints
* TestDeviceRegistrationFlow: Full registration flow test
* TestListDevices: Device listing functionality
* TestUpdateDevice: Device settings updates
* TestDeleteDevice: Device removal
* TestDeviceAuthentication: Device auth middleware test
- cmd/server/tests/phase1_integration_test.go: Phase 1 integration tests
* Tests universal progress tracking
* Tests format group detection
* Tests progress conversion
Test Coverage:
- Device registration with web-based approval flow
- Device management (list, update, delete)
- Device authentication and token validation
- User authentication and authorization
- Library creation and management
- Scanner integration
- Media items listing
Notes:
- Tests designed to run against live server on localhost:8765
- Integration test script uses bash/curl for endpoint testing
- Device tests require helper functions to be implemented