Commit Graph
9 Commits
Author SHA1 Message Date
john-okeefe 6a352a6afb refactor(services): accept optional libraryID for All Libraries support
- dashboard_service.go: Change libraryID parameter from uuid.UUID to
  pgtype.UUID across GetDashboardSections, GetDashboardPreferences,
  and all helper methods. pgtype.UUID{Valid: false} now signals
  "no library filter" (All Libraries), which gets passed through
  to sqlc.narg() in the SQL layer.

- series_service.go: Drop libraryID parameter from GetSeriesBooks
  entirely. Series are not library-specific — all books in a series
  are shown regardless of which library they belong to.
2026-05-18 17:52:24 -04:00
john-okeefe 9405afa2c5 feat(series): add SeriesService and wire continue-series into dashboard
Create SeriesService with methods for paginated series listing, cover
path resolution, series book listing, and a conversion helper for
GetContinueSeriesItemsRow to MediaItems.

Wire the continue-series query type into DashboardService's
getCollectionItemsByQueryType switch and add its metadata to the
RestoreSystemCollection default collection map.
2026-05-08 20:26:47 -04:00
john-okeefe e389df92c3 refactor: remove unnecessary type conversions and handle ignored errors across codebase
Remove redundant type conversions that Go 1.26 makes unnecessary or that
were already no-ops:

- uuid.UUID(x.Bytes) → x.Bytes (uuid.UUID is [16]byte, same as pgtype UUID Bytes)
- pgtype.UUID{Bytes: [16]byte(u), Valid: true} → pgtype.UUID{Bytes: u, Valid: true}
- (*time.Time)(&x.Time) → &x.Time
- json.RawMessage(x) → x where x is already []byte
- []byte(stringVal) → stringVal where []byte is expected
- int()/int64()/byte() casts on values already of the target type
- Decompressor(fn) → fn (type is identical)

Handle previously ignored error returns:

- collections.go: check json.Unmarshal error in GetCollection
- conversion_service.go: check fileSize.Scan() error
- app_test.go: check app.Shutdown() error in benchmark
2026-04-21 21:15:59 -04:00
john-okeefe 83ba24e31a Expose library_type_name in API and remove redundant empty fields
- Add library_type_name to GetMediaItem handler response in media.go
- Remove empty LibraryName and LibraryTypeName fields from:
  - ListMediaItemsRow in collections.go handler
  - ListMediaItemsRow in dashboard_service.go
- These fields are now populated at the database level via trigger

The library_type_name is now automatically populated in the database
when a media item is created, so we remove the manual empty string
assignments and expose the actual value in the API response.
2026-04-04 22:49:12 -04:00
john-okeefe 765123a545 Update default system collection names to Title Case format
Changed the 4 default system collection names from kebab-case to Title Case
with spaces for better readability and professional appearance:

Changes:
- "continue-reading" → "Continue Reading"
- "recently-added" → "Recently Added"
- "recently-read" → "Recently Read"
- "not-started" → "Not Started"

Implementation details:
- Collection Name field: Updated to Title Case (user-visible identifier)
- QueryType field: Unchanged, remains kebab-case (internal switch/case logic)
- All map keys updated to use new Title Case names as lookups
- Restore modal option values updated to match new names

Files modified:
- internal/handlers/auth.go: Default collection creation for new users
- internal/handlers/dashboard.go: Restore endpoint validation map
- internal/services/dashboard_service.go: System collection metadata map
- templates/restore_system_collection_modal.templ: Form option values

Benefits:
- Cleaner, more professional display names for end users
- Consistent with existing restore modal UI labels
- Improved user experience with properly formatted collection names
- Internal QueryType identifiers remain unchanged for code logic
2026-03-28 21:21:03 -04:00
john-okeefe 0b666f3fdd feat: Add collection detail page with /collections/:id route
Add comprehensive collection detail page that works for both system collections
(continue-reading, recently-added, not-started) and user collections.

Backend changes:
- Add new /collections/:id route in internal/router/frontend.go
  - Fetches collection using GetCollection with UUID parameter
  - Determines collection type from QueryType field
  - Resolves library_id for system collections
  - Converts database.MediaItems to handlers.BookInfo for display
  - Renders CollectionDetail template with collection and books data

- Update SectionData struct in internal/handlers/collections.go
  - Add CollectionID string field for view all links

- Update BuildSections() in internal/handlers/dashboard.go
  - Pass CollectionID to SectionData for proper link generation

- Simplify getViewAllURL() in internal/handlers/dashboard.go
  - Return /collections/{collectionID} instead of /section/{type}
  - Works uniformly for both system and user collections

Frontend changes:
- Fix CollectionDetail template in templates/collections.templ
  - Fix broken div nesting causing compilation error
  - Add null check for CoverImagePath to prevent broken images
  - Update aspect ratio to modern aspect-[3/4] syntax
  - Use responsive widths (w-16 sm:w-20) for mobile/desktop
  - Improve card layout with horizontal flex structure
  - Add placeholder image fallback for books without covers
  - Remove erroneous renderBooks() function call

This change aligns with the backend update where system collections are
now pre-made user collections in the database with query_type fields.
All collections can now use the same CollectionDetail template for a
consistent viewing experience.
2026-03-01 00:28:54 -05:00
john-okeefe 037e7c1189 feat(scanner): add debounced file watching with polling fallback
- Implement event queue with 3-second debouncing for file system events
- Add configurable polling fallback (default 3 min) via SCAN_POLL_INTERVAL_MINUTES
- Add SyncFilesystemWithDatabase to detect orphaned DB entries and new files
- Integrate utils.ResolveMediaURL for consistent media file path resolution
- Add COOKIE_SECURE env var with SameSite=LaxMode for session cookies
- Update media handler to properly decode URL paths for file serving
- Refactor scanner initialization to accept poll interval configuration
2026-02-28 01:16:27 -05:00
john-okeefe bb0970dfd0 feat(handlers): implement consolidated user profile endpoints
Implement DeleteUser, ResetUserPassword, and UpdateUserAdmin handlers.
Update collections handler to check soft-deleted users. Update dashboard
service to exclude deleted users from statistics.
2026-02-22 01:57:49 -05:00
john-okeefe 336f5fc6d4 feat(dashboard): implement Phase 2 dashboard service layer
Create DashboardService with business logic for Carousel-style dashboard:

Service Methods:
- NewDashboardService: Create service instance with injected dependencies
- GetDashboardSections: Fetch all collections (system + user) with their items
  * Gets system collections (user_id = NULL) by query type
  * Gets user collections with manual + auto-assigned items
  * Filters hidden collections based on user preferences
  * Reorders collections based on user custom order
  * Sorts by priority if no custom order exists
- GetDashboardPreferences: Fetch user dashboard preferences for library
- UpsertDashboardPreferences: Save or update user dashboard preferences
- RestoreSystemCollection: Reset user's copy of system collection to defaults

Helper Methods:
- filterHiddenCollections: Remove hidden collections from results
- reorderCollections: Reorder sections based on user preference
- sortByPriority: Sort sections by priority (lower numbers first)
- getCollectionItemsByQueryType: Return items for system collections by query type
- getUserCollectionItems: Return items for user collections (manual + auto-assign)

Type Conversion Helpers:
- mediaItemsToListMediaItemsRow: Convert MediaItems to ListMediaItemsRow for rule evaluation
- getCollectionItemsRowToMediaItems: Convert GetCollectionItemsForDashboardRow to MediaItems

Architecture Compliance:
- Service layer holds all business logic (reusable by SSR, API, mobile)
- Returns database types (type safety at DB layer)
- Handler converts to API types (clean JSON contracts)
- Uses existing database queries and collection service
- Procedural/imperative style (no OOP)
- Follows existing pattern from collections.go
2026-02-19 20:56:13 -05:00