Files
bookhoard/COMPLETE_MEDIA_CLEANUP_PLAN.md
T
john-okeefe aab7a0ae31 docs: add comprehensive media scanner cleanup plan
- Add detailed line-by-line plan for renaming EbookScanner to MediaScanner

- Include database cleanup (remove unused backward compatibility functions)

- Cover all test files, handlers, routers, and documentation

- 9 phases with specific file/line references for safe implementation

- Includes verification steps and rollback plan
2026-02-08 14:05:20 -05:00

29 KiB

Complete Media Scanner Renaming & Legacy Cleanup Plan

Overview

This comprehensive plan renames all legacy "ebook" naming to "media" terminology and removes unused backward compatibility code. Since the app has never been deployed, we can safely remove all legacy artifacts without migration concerns.

Scope:

  • File Renames: 5 files (handlers, services, tests)
  • Type Renames: 2 types (EbookScanner, EbookMetadata)
  • Method Renames: 5 methods + all receivers
  • Code Removal: 1 unused method + 3 unused DB functions
  • Variable Renames: 2 variables
  • Test Helper Rename: 1 function
  • Documentation Updates: All references
  • Bruno Updates: Environment variables and descriptions

Critical Constraints (from PROJECT_GUIDELINES.md):

  • Never break existing functionality
  • Post-edit verification mandatory (compile after each file)
  • Use cascading fix-up pattern prohibition
  • Multiple logical git commits
  • Verify no functionality loss

Pre-Implementation Safety Steps

Step 1: Create Safety Backup

# Create a backup branch before any changes
git branch backup-before-cleanup-$(date +%Y%m%d)

# Verify clean working tree
git status

# Run tests to establish baseline
make test

# Build to ensure everything compiles
go build ./cmd/server

Step 2: Document Current State

# List all files to be modified
git status --short > /tmp/pre-cleanup-status.txt

# Count current test coverage
go test ./... -cover 2>&1 | grep -E "coverage|ok|FAIL" > /tmp/pre-coverage.txt

Phase 1: Remove Unused Database Functions

Phase 1.1: Remove from queries.sql

File: internal/database/queries/queries.sql

Lines 473-487 - Remove entire EbookNote query section:

-- BEFORE (Lines 473-487):
-- Backward compatibility - Ebook Notes queries (using views)
-- name: CreateEbookNote :one
INSERT INTO media_notes (media_item_id, user_id, content, position)
VALUES ($1, $2, $3, $4)
RETURNING id, media_item_id, user_id, content, position, created_at, updated_at, percentage_location, character_start, character_end, epubcfi_location, chapter_reference, paragraph_reference, device_sync_data;

-- name: UpdateEbookNote :one
UPDATE media_notes
SET content = $2, position = $3, updated_at = NOW()
WHERE id = $1
RETURNING id, media_item_id, user_id, content, position, created_at, updated_at, percentage_location, character_start, character_end, epubcfi_location, chapter_reference, paragraph_reference, device_sync_data;

-- name: DeleteEbookNote :exec
DELETE FROM media_notes WHERE id = $1;

-- AFTER:
-- (Remove all of the above - use CreateMediaNote, UpdateMediaNote, DeleteMediaNote instead)

Phase 1.2: Regenerate SQLC Code

# After editing queries.sql, regenerate the Go code
sqlc generate

# Or if using Makefile:
make generate

Phase 1.3: Verify Removal

# Check that old functions are gone
grep -n "CreateEbookNote\|UpdateEbookNote\|DeleteEbookNote" internal/database/queries.sql.go
# Expected: No results (or only in historical comments)

# Check that new functions still exist
grep -n "CreateMediaNote\|UpdateMediaNote\|DeleteMediaNote" internal/database/queries.sql.go
# Expected: Should find the Media versions

# Compile to verify
go build ./internal/database

Phase 1.4: Remove from Querier Interface

File: internal/database/querier.go

Lines 52-53, 98, 286 - Remove interface methods:

// BEFORE (Line 52-53):
// Backward compatibility - Ebook Notes queries (using views)
CreateEbookNote(ctx context.Context, arg CreateEbookNoteParams) (MediaNotes, error)

// BEFORE (Line 98):
DeleteEbookNote(ctx context.Context, id pgtype.UUID) error

// BEFORE (Line 286):
UpdateEbookNote(ctx context.Context, arg UpdateEbookNoteParams) (MediaNotes, error)

// AFTER: Remove these lines completely

Phase 1.5: Verification

# Ensure database package compiles
go build ./internal/database

# Run database tests
go test ./internal/database/... -v

# Full build verification
go build ./cmd/server

Phase 2: Rename Service Layer

Phase 2.1: Rename ebook_scanner.go to media_scanner.go

File: internal/services/ebook_scanner.gointernal/services/media_scanner.go

git mv internal/services/ebook_scanner.go internal/services/media_scanner.go

Phase 2.2: Update Type Definitions

Line 36-52 - Rename EbookMetadata to MediaMetadata:

// BEFORE:
type EbookMetadata struct {
    Title        string
    Author       string
    Description  string
    Series       string
    SeriesNumber int32
    Publisher    string
    PublishDate  time.Time
    Contributors []string
    CoverPath    string
    ISBN         string
    ASIN         string
    Tags         []string

    Phase1HashInfo      *HashInfo
    Phase1FormatFormats []*FormatInfo
}

// AFTER:
// MediaMetadata contains extracted metadata for media files (ebooks, comics, manga)
type MediaMetadata struct {
    Title        string
    Author       string
    Description  string
    Series       string
    SeriesNumber int32
    Publisher    string
    PublishDate  time.Time
    Contributors []string
    CoverPath    string
    ISBN         string
    ASIN         string
    Tags         []string

    Phase1HashInfo      *HashInfo
    Phase1FormatFormats []*FormatInfo
}

Line 69-76 - Rename EbookScanner to MediaScanner:

// BEFORE:
type EbookScanner struct {
    db               *database.Queries
    watcher          *fsnotify.Watcher
    folders          []string
    adminID          pgtype.UUID
    defaultLibraryID pgtype.UUID
    libraryTypes     map[string][]string
}

// AFTER:
// MediaScanner scans library folders for media files (ebooks, comics, manga)
type MediaScanner struct {
    db               *database.Queries
    watcher          *fsnotify.Watcher
    folders          []string
    adminID          pgtype.UUID
    defaultLibraryID pgtype.UUID
    libraryTypes     map[string][]string
}

Phase 2.3: Update Constructor

Line 78 - Rename NewEbookScanner:

// BEFORE:
func NewEbookScanner(db *database.Queries) *EbookScanner {

// AFTER:
// NewMediaScanner creates a new media scanner instance
func NewMediaScanner(db *database.Queries) *MediaScanner {

Line 84 - Update return statement:

// BEFORE:
return &EbookScanner{

// AFTER:
return &MediaScanner{

Phase 2.4: Update All Method Receivers

Change all method receivers from (s *EbookScanner) to (s *MediaScanner):

Line 94: SetAdminID Line 98: SetFolders Line 148: ScanFolders Line 205: isEbookFile (being removed) Line 215: isScannableFile Line 251: extractFolderStructureMetadata Line 311: processEbookFileprocessMediaFile Line 521: extractMetadata Line 537: extractEPUBMetadata Line 623: extractPDFMetadata Line 944: updateEbookupdateMediaItem Line 949: getEbookByFilePathgetMediaItemByFilePath Line 953: getMimeType Line 981: WatchChanges Line 1023: Close Line 1035: calculateFileSHA256 Line 1066: extractOPFIdentifiers Line 1121: extractISBNFromIdentifier Line 1141: determineHashConfidence Line 1152: detectFormatType Line 1185: extractHashInfo

Phase 2.5: Remove Unused Method

Line 205-213 - Remove isEbookFile method:

// BEFORE (Lines 205-213):
func (s *EbookScanner) isEbookFile(path string) bool {
    ext := strings.ToLower(filepath.Ext(path))
    switch ext {
    case ".epub", ".pdf", ".mobi", ".azw3", ".fb2", ".txt":
        return true
    default:
        return false
    }
}

// AFTER: Remove this entire method

Phase 2.6: Rename Methods

Line 251 - Update extractFolderStructureMetadata return type:

// BEFORE:
func (s *EbookScanner) extractFolderStructureMetadata(path, rootFolder string) *EbookMetadata {
    metadata := &EbookMetadata{}

// AFTER:
func (s *MediaScanner) extractFolderStructureMetadata(path, rootFolder string) *MediaMetadata {
    metadata := &MediaMetadata{}

Line 311 - Rename processEbookFile to processMediaFile:

// BEFORE:
func (s *EbookScanner) processEbookFile(ctx context.Context, path string) error {
    fmt.Printf("Processing ebook file: %s\n", path)

// AFTER:
func (s *MediaScanner) processMediaFile(ctx context.Context, path string) error {
    fmt.Printf("Processing media file: %s\n", path)

Lines 323-339 - Update variable names and print statements:

// BEFORE:
// Check if ebook already exists in database
existingEbook, err := s.getEbookByFilePath(ctx, path)
if err == nil {
    fmt.Printf("Ebook already exists in database: %s (size: %d vs %d)\n", path, existingEbook.FileSize.Int64, info.Size())
    // Ebook exists, check if file has changed (by size)
    if existingEbook.FileSize.Int64 != info.Size() {
        fmt.Printf("File size changed, updating ebook: %s\n", path)
        return s.updateEbook(ctx, existingEbook.ID, path, info)
    }
    fmt.Printf("Ebook already exists with same size, skipping: %s\n", path)

// AFTER:
// Check if media item already exists in database
existingItem, err := s.getMediaItemByFilePath(ctx, path)
if err == nil {
    fmt.Printf("Media item already exists in database: %s (size: %d vs %d)\n", path, existingItem.FileSize.Int64, info.Size())
    // Media item exists, check if file has changed (by size)
    if existingItem.FileSize.Int64 != info.Size() {
        fmt.Printf("File size changed, updating media item: %s\n", path)
        return s.updateMediaItem(ctx, existingItem.ID, path, info)
    }
    fmt.Printf("Media item already exists with same size, skipping: %s\n", path)

Line 345 - Update metadata initialization:

// BEFORE:
metadata = &EbookMetadata{}

// AFTER:
metadata = &MediaMetadata{}

Line 521 - Update extractMetadata return type:

// BEFORE:
func (s *EbookScanner) extractMetadata(path string) (*EbookMetadata, error) {

// AFTER:
func (s *MediaScanner) extractMetadata(path string) (*MediaMetadata, error) {

Line 531 - Update extractMetadata default return:

// BEFORE:
return &EbookMetadata{

// AFTER:
return &MediaMetadata{

Line 537 - Update extractEPUBMetadata:

// BEFORE:
func (s *EbookScanner) extractEPUBMetadata(path string) (*EbookMetadata, error) {
    metadata := &EbookMetadata{}

// AFTER:
func (s *MediaScanner) extractEPUBMetadata(path string) (*MediaMetadata, error) {
    metadata := &MediaMetadata{}

Line 623 - Update extractPDFMetadata:

// BEFORE:
func (s *EbookScanner) extractPDFMetadata(path string) (*EbookMetadata, error) {
    return &EbookMetadata{

// AFTER:
func (s *MediaScanner) extractPDFMetadata(path string) (*MediaMetadata, error) {
    return &MediaMetadata{

Line 944 - Rename updateEbook to updateMediaItem:

// BEFORE:
func (s *EbookScanner) updateEbook(ctx context.Context, ebookID pgtype.UUID, filePath string, info os.FileInfo) error {

// AFTER:
func (s *MediaScanner) updateMediaItem(ctx context.Context, mediaItemID pgtype.UUID, filePath string, info os.FileInfo) error {

Line 949 - Rename getEbookByFilePath to getMediaItemByFilePath:

// BEFORE:
func (s *EbookScanner) getEbookByFilePath(ctx context.Context, filePath string) (database.MediaItems, error) {

// AFTER:
func (s *MediaScanner) getMediaItemByFilePath(ctx context.Context, filePath string) (database.MediaItems, error) {

Phase 2.7: Update Print Statements in ScanFolders

Line 156 - Rename counter variable:

// BEFORE:
ebookFiles := 0

// AFTER:
mediaFiles := 0

Lines 185-201 - Update print statements:

// BEFORE (Line 185-186):
ebookFiles++
fmt.Printf("Found ebook file: %s\n", path)

// AFTER:
mediaFiles++
fmt.Printf("Found media file: %s\n", path)

// BEFORE (Line 187-190):
if err := s.processEbookFile(ctx, path); err != nil {
    fmt.Printf("Error processing ebook %s: %v\n", path, err)
} else {
    fmt.Printf("Successfully processed ebook: %s\n", path)
}

// AFTER:
if err := s.processMediaFile(ctx, path); err != nil {
    fmt.Printf("Error processing media file %s: %v\n", path, err)
} else {
    fmt.Printf("Successfully processed media file: %s\n", path)
}

// BEFORE (Line 201):
fmt.Printf("Scan completed: %d total files scanned, %d ebook files found\n", totalFiles, ebookFiles)

// AFTER:
fmt.Printf("Scan completed: %d total files scanned, %d media files found\n", totalFiles, mediaFiles)

Phase 2.8: Update WatchChanges Method

Line 1005-1007 - Update print statements:

// BEFORE:
fmt.Printf("New/modified ebook detected: %s\n", event.Name)
if err := s.processEbookFile(ctx, event.Name); err != nil {
    fmt.Printf("Error processing modified ebook %s: %v\n", event.Name, err)

// AFTER:
fmt.Printf("New/modified media file detected: %s\n", event.Name)
if err := s.processMediaFile(ctx, event.Name); err != nil {
    fmt.Printf("Error processing modified media file %s: %v\n", event.Name, err)

Phase 2.9: Verification

# Compile services package
go build ./internal/services

# Run service tests
go test ./internal/services/... -v

# Check no Ebook references remain
grep -n "EbookScanner\|EbookMetadata" internal/services/media_scanner.go
# Expected: No results

Phase 3: Rename Test Files

Phase 3.1: Rename Test Files

# Rename all test files
git mv internal/services/ebook_scanner_library_type_test.go internal/services/media_scanner_library_type_test.go
git mv internal/services/ebook_scanner_comic_test.go internal/services/media_scanner_comic_test.go
git mv internal/services/ebook_scanner_hash_test.go internal/services/media_scanner_hash_test.go

Phase 3.2: Update Test Function Names

File: internal/services/media_scanner_library_type_test.go

Line 9-10:

// BEFORE:
// TestEbookScanner_LibraryTypeAwareScanning tests Phase 2: library-type-aware scanning
func TestEbookScanner_LibraryTypeAwareScanning(t *testing.T) {

// AFTER:
// TestMediaScanner_LibraryTypeAwareScanning tests Phase 2: library-type-aware scanning
func TestMediaScanner_LibraryTypeAwareScanning(t *testing.T) {

Line 124-125:

// BEFORE:
// TestEbookScanner_SetFolders_BuildsLibraryTypeCache tests Phase 2: SetFolders builds cache
func TestEbookScanner_SetFolders_BuildsLibraryTypeCache(t *testing.T) {

// AFTER:
// TestMediaScanner_SetFolders_BuildsLibraryTypeCache tests Phase 2: SetFolders builds cache
func TestMediaScanner_SetFolders_BuildsLibraryTypeCache(t *testing.T) {

Line 153-154:

// BEFORE:
// TestEbookScanner_LibraryTypeCrossContamination tests Phase 2: prevents cross-contamination
func TestEbookScanner_LibraryTypeCrossContamination(t *testing.T) {

// AFTER:
// TestMediaScanner_LibraryTypeCrossContamination tests Phase 2: prevents cross-contamination
func TestMediaScanner_LibraryTypeCrossContamination(t *testing.T) {

Line 188-189:

// BEFORE:
// TestEbookScanner_MultipleLibraryTypes tests Phase 2: multiple libraries with different types
func TestEbookScanner_MultipleLibraryTypes(t *testing.T) {

// AFTER:
// TestMediaScanner_MultipleLibraryTypes tests Phase 2: multiple libraries with different types
func TestMediaScanner_MultipleLibraryTypes(t *testing.T) {

File: internal/services/media_scanner_hash_test.go

Line 425:

// BEFORE:
func ExampleEbookScanner_calculateFileSHA256() {

// AFTER:
func ExampleMediaScanner_calculateFileSHA256() {

Phase 3.3: Verification

# Run all service tests
go test ./internal/services/... -v

# Verify no old test function names
grep -r "TestEbookScanner" internal/services/
# Expected: No results

Phase 4: Rename Handler Layer

Phase 4.1: Rename Handler File

git mv internal/handlers/ebook.go internal/handlers/scanner.go

Phase 4.2: Update Handler Struct

File: internal/handlers/scanner.go

Line 24 - Update scanner field type:

// BEFORE:
scanner           *services.EbookScanner

// AFTER:
scanner           *services.MediaScanner

Phase 4.3: Update Constructor

Line 45 - Update scanner initialization:

// BEFORE:
scanner:           services.NewEbookScanner(db),

// AFTER:
scanner:           services.NewMediaScanner(db),

Phase 4.4: Update StartScanner Method

Line 180 - Update comment:

// BEFORE:
// Set the admin ID for ebook association

// AFTER:
// Set the admin ID for media item association

Line 242 - Update scanner initialization:

// BEFORE:
scanner := services.NewEbookScanner(h.db)

// AFTER:
scanner := services.NewMediaScanner(h.db)

Phase 4.5: Verification

# Compile handlers package
go build ./internal/handlers

# Run handler tests
go test ./internal/handlers/... -v

Phase 5: Update Router Layer

Phase 5.1: Update Router Comments

File: internal/router/router.go

Line 135 - Update comment:

// BEFORE:
// Create ebook handler for scanner routes and progress routes

// AFTER:
// Create scanner handler for scanner routes and progress routes

Phase 5.2: Verification

# Compile router package
go build ./internal/router

Phase 6: Update Test Helpers

Phase 6.1: Rename Test Helper Function

File: cmd/server/tests/test_helpers.go

Line 272-273 - Rename function:

// BEFORE:
// createTestEbookID creates a test ebook and returns its ID
func createTestEbookID(t *testing.T, ts *httptest.Server, token string) string {

// AFTER:
// createTestMediaItemID creates a test media item and returns its ID
func createTestMediaItemID(t *testing.T, ts *httptest.Server, token string) string {

Line 277 - Update comment:

// BEFORE:
"description": "A test library for ebooks",

// AFTER:
"description": "A test library for media items",

Line 298-301 - Update comment and request:

// BEFORE:
// Create a test ebook
ebookReq := map[string]interface{}{
    "library_id": libData,
    "title":      "Test Ebook",

// AFTER:
// Create a test media item
mediaItemReq := map[string]interface{}{
    "library_id": libData,
    "title":      "Test Media Item",

Line 307 - Update variable name:

// BEFORE:
ebookBody, _ := json.Marshal(ebookReq)

// AFTER:
mediaItemBody, _ := json.Marshal(mediaItemReq)

Line 309 - Update request:

// BEFORE:
req2, _ := http.NewRequest("POST", ts.URL+"/api/media-items", bytes.NewBuffer(ebookBody))

// AFTER:
req2, _ := http.NewRequest("POST", ts.URL+"/api/media-items", bytes.NewBuffer(mediaItemBody))

Phase 6.2: Update All Test File References

Update all test files that call createTestEbookID:

Files to update:

  • cmd/server/tests/analytics_test.go
  • cmd/server/tests/book_matching_test.go
  • cmd/server/tests/collections_bulk_test.go
  • cmd/server/tests/kobo_test.go
  • cmd/server/tests/media_bulk_test.go

Example change (in each file):

// BEFORE:
bookID := createTestEbookID(t, ts, token)

// AFTER:
bookID := createTestMediaItemID(t, ts, token)

Phase 6.3: Verification

# Compile test package
go build ./cmd/server/tests

# Run integration tests (if available)
go test ./cmd/server/tests/... -v

Phase 7: Update Bruno Files

Phase 7.1: Update Environment Variable

File: bruno/environments/Bookmann.bru

Line 3 - Rename variable:

# BEFORE:
ebook_id: 02a535a4-19f8-43fa-b81b-89a226d19dd9

# AFTER:
media_item_id: 02a535a4-19f8-43fa-b81b-89a226d19dd9

Phase 7.2: Update Scanner Files

File: bruno/scanner/Scan Media Items.bru

Line 20 - Update example path:

# BEFORE:
"folder_paths": ["/path/to/ebooks"]

# AFTER:
"folder_paths": ["/path/to/media"]

File: bruno/scanner/Start Watch Mode.bru

Line 44 - Update documentation:

# BEFORE:
- Automatically detects new ebook files (CREATE events)

# AFTER:
- Automatically detects new media files (CREATE events)

Phase 7.3: Update Library Files

File: bruno/library/Update Scan Settings.bru

Line 32 - Update description:

# BEFORE:
Updates the user's ebook scanning settings.

# AFTER:
Updates the user's media scanning settings.

Phase 7.4: Update Media Items Files

File: bruno/media-items/Get Media Item.bru and List Media Items.bru

Update media_type examples if they use "ebook" as a generic term:

# BEFORE:
- `media_type` (string): Type of media (e.g., "ebook", "audiobook")

# AFTER (keep examples but make clear it's a type value):
- `media_type` (string): Type of media (e.g., "epub", "pdf", "cbz")

Note: Keep library type references like "type": "ebooks" - these are correct library type values.

Phase 7.5: Update Collection Documentation

File: bruno/collection.bru

Lines 175-176 - Update references:

# BEFORE:
- **Media Items vs Books**: The API uses "media items" (supports ebooks, comics, manga)

# AFTER:
- **Media Items**: The API uses "media items" (supports ebooks, comics, manga)

Phase 8: Update Documentation

Phase 8.1: Update Contributing Documentation

File: docs/contributing/development.md

Line 35 - Update file reference:

# BEFORE:
- `ebook.go` - Media item operations

# AFTER:
- `scanner.go` - Media scanning operations

Line 66 - Update file reference:

# BEFORE:
- `ebook_scanner.go` - File scanning & metadata extraction

# AFTER:
- `media_scanner.go` - File scanning & metadata extraction

Phase 8.2: Update API Documentation

Files:

  • docs/developer/api/scanner/scan_library.md
  • docs/developer/api/scanner/start_scanner.md
  • docs/developer/api/scanner/start_watch_mode.md
  • docs/developer/api/scanner/overview.md

Changes needed:

  • Update any "ebook scanning" → "media scanning"
  • Keep specific format mentions ("EPUB files", "comic files") where accurate
  • Keep library type "ebooks" where it's a type value

Phase 8.3: Update API Reference

File: docs/developer/api/api-reference.md

Line 12 - Update reference:

# BEFORE:
- [Media Items](media-items/) - Book/ebook operations

# AFTER:
- [Media Items](media-items/) - Media item operations

Phase 8.4: Remove Historical Comments from Schema

File: database/schema/schema.sql

Find and remove historical migration comments:

-- BEFORE:
-- Create media_items table (replaces ebooks table for broader media support)

-- AFTER:
-- Create media_items table
-- BEFORE:
-- Create media_ratings table (replaces ebook_ratings)

-- AFTER:
-- Create media_ratings table
-- BEFORE:
-- NOTE: All backward compatibility views (ebooks, ebook_ratings, ebook_reading_progress, ebook_notes, ebook_highlights) have been removed

-- AFTER (remove this line entirely - no longer relevant):

Phase 8.5: Remove Comments from Queries

File: internal/database/queries/queries.sql

Line 354 - Remove or update:

-- BEFORE:
-- Note: User ebook folders replaced by library folders system

-- AFTER (remove - this is historical):

Phase 9: Final Verification

Phase 9.1: Global Search for Remaining References

# Search for any remaining problematic references
echo "=== Checking for EbookScanner ==="
grep -r "EbookScanner" --include="*.go" . | grep -v ".git"

echo "=== Checking for EbookMetadata ==="
grep -r "EbookMetadata" --include="*.go" . | grep -v ".git"

echo "=== Checking for ebook_scanner ==="
grep -r "ebook_scanner" --include="*.go" . | grep -v ".git"

echo "=== Checking for isEbookFile ==="
grep -r "isEbookFile" --include="*.go" . | grep -v ".git"

echo "=== Checking for processEbookFile ==="
grep -r "processEbookFile" --include="*.go" . | grep -v ".git"

echo "=== Checking for createTestEbookID ==="
grep -r "createTestEbookID" --include="*.go" . | grep -v ".git"

# These should return nothing after completion

Phase 9.2: Full Build Verification

# Clean build
go clean -cache
go build ./cmd/server

# Run all tests
make test

# Run specific package tests
go test ./internal/services/... -v
go test ./internal/handlers/... -v
go test ./cmd/server/tests/... -v

Phase 9.3: Integration Test

# Start the application
make build

# Verify it runs
# (Manual check: Application should start without errors)

Git Commit Strategy

Commit 1: Remove Unused Database Functions

git add internal/database/queries/queries.sql
git add internal/database/querier.go
git add internal/database/queries.sql.go  # regenerated
git commit -m "chore(database): remove unused EbookNote backward compatibility functions

- Remove CreateEbookNote, UpdateEbookNote, DeleteEbookNote queries
- These were marked as backward compatibility but never used
- API uses CreateMediaNote, UpdateMediaNote, DeleteMediaNote instead
- Remove misleading backward compatibility comments
- Regenerate sqlc code"

Commit 2: Rename Service Layer

git add internal/services/media_scanner.go
git add internal/services/ebook_scanner.go  # deletion
git commit -m "refactor(services): rename EbookScanner to MediaScanner

- Rename EbookScanner struct to MediaScanner
- Rename EbookMetadata struct to MediaMetadata
- Rename NewEbookScanner to NewMediaScanner
- Rename processEbookFile to processMediaFile
- Rename updateEbook to updateMediaItem
- Rename getEbookByFilePath to getMediaItemByFilePath
- Remove unused isEbookFile method
- Update all method receivers
- Update variable names (ebookFiles → mediaFiles, existingEbook → existingItem)
- Update print statements to use 'media' terminology
- File renamed: ebook_scanner.go -> media_scanner.go"

Commit 3: Rename Service Test Files

git add internal/services/media_scanner_*_test.go
git add internal/services/ebook_scanner_*_test.go  # deletions
git commit -m "test(services): rename test files for MediaScanner

- Rename ebook_scanner_library_type_test.go -> media_scanner_library_type_test.go
- Rename ebook_scanner_comic_test.go -> media_scanner_comic_test.go
- Rename ebook_scanner_hash_test.go -> media_scanner_hash_test.go
- Update test function names (TestEbookScanner* -> TestMediaScanner*)"

Commit 4: Rename Handler Layer

git add internal/handlers/scanner.go
git add internal/handlers/ebook.go  # deletion
git commit -m "refactor(handlers): rename ebook.go to scanner.go

- Rename file: ebook.go -> scanner.go
- Update scanner field type to *services.MediaScanner
- Update NewMediaScanner call
- Update comments to use 'media' terminology
- File renamed: ebook.go -> scanner.go"

Commit 5: Update Router and Test Helpers

git add internal/router/router.go
git add cmd/server/tests/test_helpers.go
git add cmd/server/tests/*_test.go
git commit -m "refactor(tests): update test helpers and router comments

- Rename createTestEbookID to createTestMediaItemID
- Update all test file references to use new function name
- Update test helper comments and variable names
- Update router comments (ebook handler -> scanner handler)"

Commit 6: Update Bruno Files

git add bruno/
git commit -m "docs(bruno): update API test files for media terminology

- Rename ebook_id environment variable to media_item_id
- Update scanner endpoint documentation
- Update media scanning descriptions
- Keep library type 'ebooks' where appropriate (valid type value)"

Commit 7: Update Documentation

git add docs/
git add database/schema/schema.sql
git commit -m "docs: update documentation for media scanner naming

- Update development.md with new file names
- Update API documentation to use 'media' terminology
- Remove historical migration comments from schema
- Update scanner documentation references"

Commit 8: Final Cleanup (if needed)

git add -A
git commit -m "chore: final cleanup after media scanner rename

- Remove any remaining legacy references
- Verify all tests pass
- Clean up comments"

Rollback Plan

If anything goes wrong, rollback immediately:

# If you created a backup branch
git checkout backup-before-cleanup-$(date +%Y%m%d)

# Or reset to before changes
git reset --hard HEAD~N  # where N is number of commits to undo

# Or restore specific files
git checkout HEAD -- internal/services/ebook_scanner.go

Success Criteria

All files renamed correctly All types renamed (EbookScanner→MediaScanner, EbookMetadata→MediaMetadata) All methods renamed with updated receivers Unused code removed (isEbookFile, CreateEbookNote, etc.) All variables renamed (ebookFiles→mediaFiles, etc.) Test helper renamed (createTestEbookID→createTestMediaItemID) All test references updated Bruno files updated Documentation updated No legacy "ebook" references in code (except library type 'ebooks') Application builds successfully All tests pass Clean git history with logical commits


Notes for AI Implementation

  1. Verify compilation after EVERY file edit
  2. Use specific, narrow matches - avoid broad regex
  3. Read context (20 lines before/after) before editing
  4. If compilation fails, STOP and analyze with git diff
  5. Commit frequently - after each logical unit of work
  6. Test files are critical - don't skip them
  7. This is a pure refactor - no behavior changes
  8. Library type 'ebooks' is correct - don't change it
  9. MIME types are correct - don't change them
  10. When in doubt, preserve functionality

Post-Implementation Verification Checklist

  • All 5 files renamed
  • 2 types renamed
  • 5+ methods renamed
  • 1 unused method removed
  • 3 unused DB functions removed
  • 2+ variables renamed
  • Test helper renamed
  • Bruno files updated
  • Documentation updated
  • Build succeeds: go build ./cmd/server
  • Tests pass: make test
  • No EbookScanner references remain
  • No EbookMetadata references remain
  • Git commits are clean and logical
  • Working tree is clean