- Update all test URLs from /api/books/ to /api/media-items/
- Update request structures: book_ids → media_item_ids
- Update bulk-update request format to array of operations
- Update response assertions: success → deleted/updated
- Update result assertions: book_id → media_item_id
The test was sending a single object with a "meta" field, but the handler
expects an array of KoboAnalyticsTest objects (matching other Kobo endpoints).
Changed:
- Removed unsupported "meta" field
- Converted single object to array format
- Now matches Kobo protocol pattern used by /markup and /bookmark endpoints
All Kobo tests now pass:
- TestKoboInitialization ✅
- TestKoboLibrarySync ✅
- TestKoboMarkupSync ✅
- TestKoboBookmarkSync ✅
- TestKoboAnalyticsGettests ✅
- TestKoboDeviceHeaderParsing ✅
The TestKoboInitialization test was calling getTestUserID() explicitly
on line 25, but loginTestUser() already calls this internally. This caused
the test user to be deleted and recreated after login, leading to
inconsistent state and HTTP 500 errors when creating libraries.
After removing the redundant call:
- TestKoboInitialization now passes
- All Kobo sync tests pass successfully
- Add DROP TRIGGER IF EXISTS before CREATE TRIGGER
- Fixes 'trigger already exists' error during schema initialization
- Allows schema to run multiple times safely
- Try multiple locations for schema.sql file
- Support both local dev and containerized deployment paths
- Add informative logging when schema is loaded
- Prevent runtime.Caller issues in containers
Locations checked:
- database/schema/schema.sql (working directory)
- /app/database/schema/schema.sql (container)
- ../database/schema/schema.sql (relative)
- ../../database/schema/schema.sql (relative)
This fixes the 'no such file or directory' error in production containers.
- Add schema initialization call after database connection
- Initialize schema before handler creation
- Fatal on failure (schema is critical for app to function)
- Clear log messages show initialization progress
Server startup flow:
1. Load config
2. Connect to database
3. Initialize schema (NEW - ensures all tables/functions exist)
4. Create handlers and services
5. Start server
- Create internal/database/schema.go with full initialization logic
- Parse table names from schema.sql using regex (handles both formats)
- Execute schema in atomic transaction
- Verify all expected tables exist
- Verify all critical functions exist (6 functions)
- PostgreSQL advisory locking with 30-second timeout
- Self-healing from partial/corrupted state
- Load schema.sql from filesystem at runtime
Features:
- Defensive regex handles IF NOT EXISTS and legacy CREATE TABLE
- Lock timeout prevents indefinite hangs
- Function verification ensures sync operations work
- Clear error messages with debug hints
- Convert 18 CREATE TABLE → CREATE TABLE IF NOT EXISTS (27 total)
- Convert 62 CREATE INDEX → CREATE INDEX IF NOT EXISTS (82 total)
- Add ON CONFLICT to 2 INSERT statements (3 total)
- Verify 8 ALTER TABLE already have IF NOT EXISTS
- Verify 6 CREATE FUNCTION use OR REPLACE
Schema is now fully idempotent and safe for automatic initialization on every startup.
- Fix regex pattern to handle both IF NOT EXISTS and legacy CREATE TABLE formats
- Add 30-second lock timeout to prevent indefinite hangs
- Add function verification (6 critical functions checked)
- Document 8 ALTER TABLE statements already idempotent
- Document 6 CREATE FUNCTION statements use OR REPLACE
- Add time import for timeout support
- Update verification checklist with new requirements
- Update log messages to show table and function counts
The first GetReadingStats_WithAuth_DefaultDates test was expecting
'total_books' and 'total_reading_time' fields that don't exist in the
API response. The second duplicate test correctly expects
'total_books_read' and 'total_reading_time_minutes'.
This resolves the TestAnalyticsReadingStats failure.
Finish migrating all test files to the new TestServerSetup pattern
introduced by the goroutine cleanup refactoring. This resolves all
remaining compilation errors in the test suite.
Changes:
- device_cap_test.go: Fix undefined ts references (7 instances)
* Replace ts.URL with setup.Server.URL in all test functions
* Fix URL references in t.Run subtest closures
- queue_test.go: Fix undefined db and helper function issues (5 instances)
* Replace db.CreateDevice with setup.DB.CreateDevice
* Fix loginAdminUser() to use ts/db parameters instead of setup
* Fix loginUserWithID() to use ts parameter instead of setup
- websocket_test.go: Convert 5 tests to new TestServerSetup pattern
* Replace old pattern (ts, queries, _) with new pattern (setup)
* Update all resource references to use setup.Server and setup.DB
* Fix getTestUserID calls to include t parameter
Build Impact:
- All compilation errors resolved
- Integration tests now compile successfully
- No functional changes to test logic
Related: TestServerSetup cleanup pattern (TEST_CLEANUP_PATTERN.md)
BREAKING CHANGE: setupTestServer() now returns *TestServerSetup instead of (*httptest.Server, *database.Queries, *config.Config)
This fixes the database connection and goroutine leak issues where:
- Each test created a new pgxpool (default max_conns = 4)
- connManager.StartCleanupTask() goroutine was never stopped
- queueProcessor.Start() goroutine was never stopped
- ~160 tests = potential 640+ leaked connections
New TestServerSetup struct provides:
- Automatic cleanup via t.Cleanup()
- Proper goroutine cancellation
- Database pool closing
- Thread-safe close() method with mutex
Phase 1 of test cleanup refactor.
- Fix TestKoboInitialization: use setupDeviceTest() for device creation
- Fix TestKoboLibrarySync: remove /test-token/ route path, add device auth
- Fix TestKoboMarkupSync: add device auth and last-read-place test case
- Fix TestKoboBookmarkSync: add device auth and last-read-place test case
- Fix TestKoboAnalyticsGettests: add device authentication
- Add debug logging to all test functions
- Remove unused imports (config, database, middleware, router, services, sync)
Phase 3 of KOBO_IMPLEMENTATION_PLAN.md completed (Steps 7-12).
All tests now use proper device authentication (Bearer tokens + x-kobo-device headers)
and include test cases for the new last-read-place bookmark feature.
- Add nil UUID checks after mapContentIdToBookhoardUUID in all handlers
- Add ContentType detection for Kobo EPUB/PDF sync (EPUB=6, PDF=5)
- Add "last-read-place" bookmark type support with EPUB CFI position tracking
- Restore broken mapContentIdToBookhoardUUID function with UUID parsing
- Restore mapBookhoardUUIDToKoboContentId helper function
- Restore getCollectionMetadataForBook helper function
This fixes the catastrophic file corruption from commit 2200720 which
deleted 414 lines and inserted code in the wrong location.
Phase 1-3 of KOBO_IMPLEMENTATION_PLAN.md completed:
- Step 4: Nil UUID checks in Markup, Bookmark, AnalyticsGettests, SyncFromServer
- Step 5: ContentType field added to KoboReadingSync struct
- Step 6: last-read-place case added to Markup handler switch statement
Testing: Code compiles successfully, all handlers properly structured
- Fix string(rune(remaining)) to strconv.Itoa(remaining) in device_auth.go
- Prevents garbage characters in X-RateLimit-Remaining header
- No functionality changes, only fixes broken headers
Testing: Verified with code inspection that headers return proper integers
- Fix TestUpdateDevice: Use correct JSON field name and handle float64 type
- Fix TestRejectDeviceRegistration: Expect message response instead of boolean
- Update approve device docs: Add missing response fields
- Update reject device docs: Correct message text and format
- Update Bruno API: Fix example response for reject endpoint
Both integration tests now pass while maintaining API consistency.
System Settings Bruno Tests (new):
- bruno/system/get-scan-settings.bru
- bruno/system/update-scan-settings.bru
- Test GET endpoint for retrieving system scan settings
- Test PUT endpoint for updating system scan settings
- Include admin authentication requirements
- Document response structures
List Users Bruno Test (update):
- bruno/user/admin/List Users.bru
- Add max_devices to response documentation
- Add device_count to response documentation
- Update feature descriptions
These Bruno tests provide API contract verification for the new
system settings endpoints and document the enhanced user list response.
System Settings API Documentation (new):
- docs/developer/api/system/settings.md
- Document GET /api/libraries/scan-settings endpoint
- Document PUT /api/libraries/scan-settings endpoint
- Include request/response examples
- Document validation rules and error codes
- Include migration notes from per-user to system-wide
User List API Documentation (update):
- docs/developer/api/admin/list_users.md
- Add max_devices field to response
- Add device_count field to response
- Include complete response field descriptions table
- Update example to show new fields
Documentation covers both the new system-wide scan settings feature
and the enhanced user list with device monitoring capabilities.
System Settings Tests (new file):
- Create system_settings_test.go with comprehensive test coverage
- Test admin-only access control
- Test validation (15-1440 minute range)
- Test error handling scenarios
- Test integration with scheduler
User Tests Cleanup:
- Remove old TestScanSettings from user_test.go
- Scan settings moved to system-wide (no longer per-user)
Device Cap Tests Enhancement:
- Update TestListUsersIncludesMaxDevices
- Add assertion for device_count field
- Verify both max_devices and device_count in response
All tests verify the migration from per-user to system-wide scan settings.
Add SystemSettingsHandler initialization in main.go:
- Create systemSettingsHandler instance with queries
- Add to router.Config for route registration
- Properly wired with existing dependencies
This enables the system settings endpoints to be registered and functional.
Update scheduler to use system-wide settings instead of per-user:
- Change Database interface to use GetSystemSetting
- Remove GetScanSettings (per-user method)
- Update checkAndScheduleScans to read system settings
- Apply system-wide scan frequency to all libraries
Scheduler now respects global scan settings for all library scanning,
enabling consistent system-wide scan behavior.
Clean up auth.go after migrating to system-wide settings:
- Remove UpdateScanSettings handler (moved to system_settings.go)
- Remove GetScanSettings handler (moved to system_settings.go)
- Remove UpdateScanSettingsRequest type (now in system_settings.go)
These handlers are now in SystemSettingsHandler with system-wide scope
instead of per-user functionality.
Create new SystemSettingsHandler for managing system-wide scan settings:
- GetScanSettings: retrieve scan frequency and auto-scan status
- UpdateScanSettings: update scan settings (15-1440 minutes range)
- Admin-only access (no user-specific data)
- Key-value based storage instead of per-user settings
Replaces per-user scan settings with centralized system configuration.
This handler is used by /api/libraries/scan-settings endpoints.
Auto-generated changes from running 'sqlc generate' after query updates:
- models.go: updated with SystemSettings struct, removed scan fields from Users
- querier.go: updated interface with new system settings methods
- queries.sql.go: regenerated with new query methods
Generated via: cd internal/database && sqlc generate
System Settings Migration:
- Add GetSystemSetting query for single setting retrieval
- Add UpdateSystemSetting query for updating settings
- Add GetAllSystemSettings query for all settings
- Remove UpdateScanSettings and GetScanSettings (per-user queries)
User Query Enhancement:
- Add max_devices field to GetUser query
- Add device_count computed field to GetUser query
- Add max_devices field to ListUsers query
- Add device_count computed field to ListUsers query
These changes support:
1. System-wide scan settings instead of per-user settings
2. Users can now see their device count and limits
3. Admins can monitor device usage across all users
- Check if returned user record is null (user not found)
- Return 404 Not Found instead of 200 OK
- Provides accurate REST API semantics
- Fixes TestUpdateUserMaxDevicesNonExistentUser
Related: Database query change commit
- Change query from :exec to :one with RETURNING *
- Allows handler to detect when user doesn't exist
- Follows pattern established by UpdateMediaItem
- Required for 404 response on non-existent user
Related: Fix for TestUpdateUserMaxDevicesNonExistentUser
- Add explicit note that this is pre-production (no deployments)
- Document two options for updating local databases after schema changes
- Option 1: Recreate database (recommended, loses data)
- Option 2: Manual SQL migration (preserves data)
- Explicitly state: DO NOT create migration files
- Update checklist to include database update step
- Cross-reference from full-stack tasks section
Clarifies the 'no migration needed' philosophy for future developers
- API validates folder exists before adding to library
- /app/uploads is mounted volume in container
- Avoids need to create subdirectories
- Simplifies test setup
- Add POST /api/media-items prerequisite documentation
- Document 400 error for libraries without folders
- Update API reference with validation rules
- Include usage example showing proper setup order
Related: Media item validation changes
- 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