Skip to content

Stats and Goals pages have inconsistent orphan book handling #354

@masonfox

Description

@masonfox

Problem

The Stats page and Goals page use different logic for counting completed books, leading to potential count mismatches when orphaned books (books removed from Calibre but preserved in Tome) have reading sessions.

Stats Page

Uses sessionRepository methods that INNER JOIN books and filter orphaned = false OR IS NULL:

  • countByStatus() — total books read, currently reading count
  • countCompletedByYear() — books read this year
  • countCompletedByYearMonth() — books read this month

Result: Orphaned books are excluded from all counts.

Goals Page

Uses readingGoalRepository methods that query reading_sessions directly with no book join:

  • getBooksCompletedInYear() — yearly goal progress
  • getBooksCompletedByMonth() — monthly breakdown
  • getBooksByCompletionYear() — joins books for display but does not filter orphans

Result: Orphaned books are included in all counts.

Inconsistency

If a user completes a book and it later becomes orphaned (removed from Calibre), the Stats page will show a lower count than the Goals page for the same time period.

Current Impact

Low — all 34 orphaned books in the current database have to-read status with no completed sessions, so the counts match today. This becomes a real issue if a user completes a book and then removes it from their Calibre library.

Considerations

  • The constitution principle of preserving reading history suggests orphans should be counted (the reading happened)
  • However, this is a product-level decision with trade-offs in both directions
  • Page read counts (progress repository) already include orphans everywhere since they query progress_logs directly
  • Book lists (currently reading, read-next) should likely continue excluding orphans regardless, since those are actionable views

Relevant Code

  • lib/repositories/session.repository.tscountByStatus(), countCompletedByYear(), countCompletedByYearMonth()
  • lib/repositories/reading-goals.repository.tsgetBooksCompletedInYear(), getBooksCompletedByMonth(), getBooksByCompletionYear()
  • lib/services/reading-stats.service.tsgetOverview() (Stats page)
  • lib/services/reading-goals.service.ts — Goals page service

Related

Part of the #349 investigation. Identified during code review of PR #353.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingrefactorInternal quality-oriented changes

    Projects

    Status

    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions