Files
bookhoard/CAROUSEL_DASHBOARD_VERIFICATION_CHECKLIST.md
T
john-okeefe 9c34a45ba6 docs: Add verification checklist for Phase 4.6
Update the verification checklist to cover all aspects of Phase 4.6
(CreateCollection manual books support).

New verification sections:
- Section 6.4: Verify CreateCollection Endpoint Manual Books Support
  - Struct field verification (ManualBookIDs)
  - Validation tag verification (validate:"max=50")
  - Handler implementation verification
  - Error handling and logging verification
  - Graceful degradation verification

- Section 19.1b: Verify Collections Bruno Tests Created
  - New bruno/collections/ directory structure
  - All 5 required test files
  - Test coverage verification

- Section 19.1b: Verify Collections API Documentation
  - manual_book_ids field documentation
  - Validation limits (max 50)
  - Example requests
  - Error handling explanation
  - Backward compatibility notes

Bug fix:
- Fixed BuildSections function signature to match actual service
  (services.DashboardSection instead of services.SectionItems)

All verification includes:
- Step-by-step verification commands
- Common pitfalls to avoid
- Success criteria for each section
2026-02-19 20:48:40 -05:00

113 KiB

Carousel Dashboard Plan Verification Checklist

Use this checklist to comprehensively audit the Carousel Dashboard Plan in a single pass. Each item includes verification steps to confirm accuracy.


⚠️ CLARIFICATION: Plan vs Checklist Discrepancies Resolved

After thorough analysis, the following discrepancies have been resolved:

1. Preview Endpoint - IS in the plan

  • Checklist concern: "Missing Collection Preview Endpoint"
  • Reality: Endpoint is specified in Phase 4.5 of the plan
  • Why required: Web UI custom section builder + future mobile apps need to preview filter rules before saving
  • Location: internal/handlers/collections.go - PreviewCollection method
  • Route: POST /api/collections/preview
  • Documentation: Explained in Phase 4.5 why client-side preview is a bad idea

2. Custom Section Builder - IS in the plan

  • Checklist concern: "Missing Custom Builder sections 10.5.2 and 10.5.3"
  • Reality: Both sections exist in the plan:
    • 10.5.2: Custom Section Builder Template (templates/custom_section.templ)
    • 10.5.3: Custom Section Builder TypeScript (web/src/custom-section-builder.ts)
  • This is a major feature with 13+ filter fields

3. Service Method Names - Plan is correct

  • Checklist expects: GetSectionItems, filterHiddenSections, reorderSections
  • Plan implements: GetDashboardSections, filterHiddenCollections, reorderCollections
  • Plan names are better: More descriptive, uses "collections" terminology consistently
  • Action taken: Updated checklist to match plan's actual method names

4. Config Struct Updates - Documented with line numbers

  • Concern: "Touching Config breaks dozens of functions"
  • Reality: Only 3 files need updates, all with exact line numbers specified:
    • internal/router/router.go line 58-59
    • cmd/server/main.go lines 123-124, 172-173
    • cmd/server/tests/test_helpers.go lines 419-420, 458-459
  • 18 router functions accept *Config but don't need changes (just receive pointer)

5. DashboardService in Config - Why both Service and Handler?

  • DashboardService: Used by SSR routes (frontend.go) for data fetching
  • DashboardHandler: Used by API routes (dashboard.go) for JSON endpoints
  • Mobile apps: Will use DashboardHandler
  • Web UI: Uses both (SSR via Service, interactions via Handler)

⚠️ CRITICAL DISTINCTION: Type Duplication

Before using this checklist, understand this important guideline:

UNACCEPTABLE: Duplicate Go Types

// WRONG: Creating duplicate types in Go templates package
package templates

type SectionData struct { ... }  // DON'T DO THIS - duplicates handlers.SectionData

ACCEPTABLE: TypeScript Type Recreation (MUST BE COMPLETE)

// OKAY: Recreating types in TypeScript .d.ts files
// Go's pgtype fields cannot auto-convert, so manual recreation is necessary
// CRITICAL: Must include ALL fields from Go handler (no partial types)

interface SectionData {
    id: string;                    // matches Go's json:"id"
    is_system: boolean;            // matches Go's json:"is_system" (was "type" string)
    title: string;                 // matches Go's json:"title"
    description: string;           // matches Go's json:"description"
    icon: string;                  // matches Go's json:"icon"
    items: BookInfo[];             // matches Go's json:"items"
    view_all_url: string;          // matches Go's json:"view_all_url"
    priority: number;              // matches Go's json:"priority"
}
// All 8 fields from Go struct included - COMPLETE TYPE MATCHING

interface BookInfo {
    media_item_id: string;         // matches Go's json:"media_item_id" (NOT "id")
    title: string;                 // matches Go's json:"title"
    author: string;                // matches Go's json:"author"
    cover_image_path: string;      // matches Go's json:"cover_image_path"
}
// All 4 fields from Go struct included - COMPLETE TYPE MATCHING

UNACCEPTABLE: Partial TypeScript Types

// WRONG: TypeScript interface with only subset of Go fields (breaks type safety)
interface SectionData {
    id: string;
    type: string;                  // WRONG: should be is_system: boolean
    title: string;
    items: BookInfo[];
    // Missing: description, icon, view_all_url, priority
    // This is a PARTIAL type and violates type safety guidelines
}

// WRONG: Using wrong field name for BookInfo
interface BookInfo {
    id: string;                    // WRONG: should be media_item_id
    title: string;
    author: string;
    cover_image_path: string;
}

Key Points:

  • In Go: Templates MUST use handlers.* types directly (no duplication)
  • In TypeScript: .d.ts files recreate complete handler JSON structure (all fields)
  • Reason: Go's pgtype.Text, pgtype.UUID, etc. don't map cleanly to TypeScript
  • Type Safety: Partial TypeScript types break type safety and can cause runtime errors
  • Verification: Field counts must match (Go struct has N fields = TypeScript has N fields)

This checklist enforces NO Go duplication while requiring complete TypeScript duplication.


1. Prerequisites Verification

1.1 Verify TypeScript Conversion Plan Completed

Before starting Carousel Dashboard:

  • TypeScript Conversion Plan (20-25.5 days) is fully completed
  • All infrastructure modules exist in web/src/:
    • api.ts - Centralized API client with auth
    • toast.ts - Toast notification system
    • events.ts - Event delegation utilities
    • storage.ts - localStorage wrapper
    • dom.ts - DOM utilities (escapeHtml, etc.)
    • types/api.d.ts - Type definitions for all API responses
  • Event delegation pattern established (data attributes)
  • TypeScript compilation pipeline working (npm run build:ts)
  • All inline JavaScript removed from templates
  • Progressive enhancement maintained across all features

Verification Commands:

# Verify TypeScript modules exist
ls -la web/src/{api,toast,events,storage,dom}.ts

# Verify type definitions exist
ls -la web/src/types/api.d.ts

# Verify build works
npm run build:ts

# Check for remaining inline JavaScript
rg '<script>' templates/*.templ | grep -v 'src="/static/'

Common Pitfalls:

  • Starting dashboard implementation before TypeScript conversion completes
  • Missing utility modules that dashboard depends on
  • TypeScript compilation errors blocking dashboard development

1.2 Verify Database Schema Readiness

Before modifying schema:

  • Current schema.sql is backed up
  • Database is in pre-production state (can be recreated)
  • No critical data in database that needs migration
  • Volume deletion is acceptable (podman compose down -v)
  • Team understands data will be lost

Verification:

# Check if database is pre-production
# (no production data, can be safely recreated)

# Backup current schema
cp database/schema/schema.sql database/schema/schema.sql.backup

# Verify schema.sql syntax
psql -f database/schema/schema.sql --dry-run

2. Database Schema Verification

2.1 Verify Schema Changes Are Atomic

For each table/alteration in schema.sql:

  • All changes are in single transaction
  • No partial updates possible (all-or-nothing)
  • Foreign key constraints are correct
  • Indexes are created after tables
  • Default values are appropriate
  • NOT NULL constraints are correct

Verification Commands:

# Check schema.sql syntax
psql -f database/schema/schema.sql --dry-run

# Test schema creation in isolated environment
createdb test_bookhoard
psql test_bookhoard -f database/schema/schema.sql

# Verify tables created
psql test_bookhoard -c "\dt"
psql test_bookhoard -c "\d user_dashboard_preferences"
psql test_bookhoard -c "\d smart_section_types"

# Verify indexes created
psql test_bookhoard -c "\di"

# Cleanup
dropdb test_bookhoard

2.2 Verify New Tables Match Plan

For user_dashboard_preferences:

  • All required columns exist:
    • id UUID PRIMARY KEY DEFAULT gen_random_uuid()
    • user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE
    • library_id UUID REFERENCES libraries(id) ON DELETE CASCADE
    • hidden_collections TEXT[] DEFAULT '{}'
    • collection_order TEXT[] DEFAULT '{}'
    • items_per_section INT DEFAULT 20
    • created_at TIMESTAMP DEFAULT NOW()
    • updated_at TIMESTAMP DEFAULT NOW()
    • Unique constraint on (user_id, library_id)
    • Index on (user_id, library_id) for fast lookups

For collections table modifications:

  • user_id UUID NULL REFERENCES users(id) added (NULL for system collections)
  • show_on_dashboard BOOLEAN DEFAULT false added
  • query_type TEXT DEFAULT 'filter' added
  • priority INT DEFAULT 100 added
  • is_system_collection BOOLEAN DEFAULT false added
  • Index created on (user_id, show_on_dashboard, priority) WHERE show_on_dashboard = true
  • 4 system collections pre-seeded with user_id = NULL:
    • continue-reading (priority 1, query_type='continue-reading')
    • recently-added (priority 2, query_type='recently-added')
    • recently-read (priority 3, query_type='recently-read')
    • not-started (priority 4, query_type='not-started')

For collections.show_on_dashboard column:

  • Column added with ALTER TABLE collections ADD COLUMN
  • IF NOT EXISTS clause included
  • Default value is false
  • Index created on `(user_id, show_on_dashboard, priority) WHERE show_on_dashboard = true

For collection_items.excluded column:

  • Column added with ALTER TABLE collection_items ADD COLUMN
  • IF NOT EXISTS clause included
  • Default value is false
  • Index created on (collection_id, excluded) WHERE excluded = true
  • Allows users to exclude auto-assigned items from filter-based collections

Verification:

# Check table definitions
psql bookhoard -c "\d user_dashboard_preferences"
psql bookhoard -c "\d collections" | grep -E "show_on_dashboard|query_type|priority|is_system_collection"

# Check system collections exist
psql bookhoard -c "SELECT name, query_type, priority, is_system_collection FROM collections WHERE user_id IS NULL"

2.3 Verify No Migration Files

Critical for pre-production app:

  • Changes are in database/schema/schema.sql (NOT migration files)
  • No migration files in database/migrations/
  • Plan explicitly states to recreate database
  • Volume deletion instructions are clear
  • Warning about data loss is prominent

Check:

# Should return no files or only old/unused migrations
ls -la database/migrations/

# Verify schema.sql has latest changes
rg "user_dashboard_preferences" database/schema/schema.sql
rg "show_on_dashboard" database/schema/schema.sql
rg "smart_section_types" database/schema/schema.sql

3. Service Layer Verification

3.1 Verify Service Follows Guidelines

For internal/services/dashboard_service.go:

  • All business logic in service (not in handlers)
  • Procedural/imperative style (no OOP)
  • No classes or methods
  • Functions accept context as first parameter
  • Uses database.Queries interface (not direct db access)
  • Returns raw data (not formatted for templates/API)
  • Error handling is consistent
  • No HTTP concerns in service

Verification:

# Check for OOP patterns (should find nothing)
rg "class " internal/services/dashboard_service.go
rg "this\.|self\." internal/services/dashboard_service.go

# Verify function signatures
rg "^func \(" internal/services/dashboard_service.go

# Check that service uses database.Queries
rg "db\." internal/services/dashboard_service.go | grep -v "pgtype\."

# Verify no HTTP imports
rg "import.*net/http" internal/services/dashboard_service.go
# Should return nothing

3.2 Verify Service Methods Match Plan

Required methods:

  • NewDashboardService(db *database.Queries) *DashboardService
  • GetDashboardSections(ctx, userID, libraryID, limit, collectionOrder, hiddenCollections) ([]DashboardSection, error)
  • filterHiddenCollections(sections []DashboardSection, hidden []string) []DashboardSection
  • reorderCollections(sections []DashboardSection, order []string) []DashboardSection
  • sortByPriority(sections []DashboardSection) []DashboardSection
  • getCollectionItemsByQueryType(ctx, coll, userID, libraryID, limit) ([]MediaItems, error)
  • getUserCollectionItems(ctx, coll, userID, libraryID, limit) ([]MediaItems, error)
  • GetDashboardPreferences(ctx, userID, libraryID) (UserDashboardPreferences, error)
  • UpsertDashboardPreferences(ctx, params) (UserDashboardPreferences, error)
  • RestoreSystemCollection(ctx, userID, collectionName) error

Verification:

# List all exported functions
rg "^func [A-Z]" internal/services/dashboard_service.go

# Verify return types match plan
rg "GetDashboardSections.*\[\]DashboardSection" internal/services/dashboard_service.go

# Verify method names match plan (not checklist)
rg "filterHiddenCollections|reorderCollections|sortByPriority" internal/services/dashboard_service.go

3.3 Verify Section Logic Correctness

For each smart section:

  • Continue Reading: Progress > 0 AND progress < 1
  • Recently Added: ORDER BY created_at DESC
  • Recently Read: Progress >= 1 (completed)
  • Not Started: Progress = 0 OR no reading_progress record
  • User Collections: WHERE show_on_dashboard = true AND is_system_collection = false

Check:

# Find SQL queries in service
rg "SELECT.*FROM media_items" internal/services/dashboard_service.go
rg "WHERE.*progress" internal/services/dashboard_service.go

# Verify ordering
rg "ORDER BY" internal/services/dashboard_service.go

3.4 Verify User Preference Logic

Filter hidden collections:

  • Empty hidden list returns all collections
  • Non-empty hidden list filters matching collections
  • Comparison is case-sensitive
  • No errors on empty collection list

Reorder collections:

  • Empty order returns collections as-is
  • Ordered collections come first
  • Unordered collections appended at end
  • No collections are lost
  • No duplicate collections in result

Verification:

# Find preference logic
rg "filterHiddenSections|reorderSections" internal/services/dashboard_service.go -A 20

# Check edge cases
rg "if len.*== 0" internal/services/dashboard_service.go

3.4 Verify Auto-Assign Rule Evaluation

For getUserCollectionItems method:

  • Fetches collections with show_on_dashboard = true
  • Parses auto_assign_rules JSONB from collection
  • Fetches all library items via GetLibraryItems
  • Evaluates rules for each library item using collectionService.EvaluateRules
  • Merges manual items (not excluded) + auto-matched items
  • Filters out excluded items (where excluded = true)
  • Applies limit after merging
  • Only adds collection if it has items in current library

Excluded items handling:

  • Manual items query returns excluded column from collection_items
  • Filters out items where excluded = true
  • Auto-matched items checked against manual items to avoid duplicates
  • Excluded items not added even if they match rules

Rule evaluation logic:

  • Calls collectionService.EvaluateRules(item, rules)
  • Checks if eval.Matches && eval.Confidence > 0.7
  • Adds matching items to collection
  • Respects priority (higher priority rules evaluated first)

Merge logic:

// Pseudo-code for merge logic
manualItems := getManualItems(collectionID) // with excluded=false filter
autoItems := evaluateAutoAssignRules(libraryItems, rules)
finalItems := merge(manualItems, autoItems)
finalItems = applyLimit(finalItems, limit)

Verification:

# Check getUserCollectionItems implementation
rg "func.*getUserCollectionItems" internal/services/dashboard_service.go -A 100

# Verify auto-assign rules parsing
rg "json.Unmarshal.*AutoAssignRules" internal/services/dashboard_service.go

# Verify EvaluateRules usage
rg "collectionService.EvaluateRules" internal/services/dashboard_service.go

# Check GetLibraryItems query
rg "GetLibraryItems" internal/services/dashboard_service.go

# Verify excluded items filtering
rg "Excluded.*Bool" internal/services/dashboard_service.go
rg "!item.Excluded.Valid || !item.Excluded.Bool" internal/services/dashboard_service.go

# Check manual + auto merge logic
rg "manualNonExcluded.*append.*autoItems" internal/services/dashboard_service.go

# Verify limit applied after merge
rg "len.*finalItems.*limit" internal/services/dashboard_service.go

Edge case verification:

  • Collection with no auto-assign rules (manual only)
  • Collection with auto-assign rules but no matches
  • Collection where all manual items are excluded
  • Collection with auto-assign rules + manual additions
  • Collection with excluded items that match rules
  • Large library (performance check)

Integration with CollectionService:

  • DashboardService has collectionService dependency
  • NewDashboardService creates CollectionService instance
  • Reuses existing EvaluateRules from collection_service.go
  • No duplicate rule evaluation logic

4. Database Queries Verification

4.1 Verify Queries Match Schema

For each query in internal/database/queries/queries.sql:

  • Query name follows sqlc naming convention
  • :one, :many, or :exec suffix is correct
  • Parameters use $1, $2, etc. (PostgreSQL syntax)
  • Table names match schema.sql
  • Column names match schema.sql
  • ON CONFLICT clause is correct for upserts
  • RETURNING clause returns all modified columns

Verification:

# Check query syntax
cat internal/database/queries/queries.sql | rg "dashboard"

# Verify queries compile
cd internal/database && sqlc generate

# Check generated code
cat internal/database/dashboard.go  # Should exist after sqlc generate)
rg "GetDashboardPreferences|UpsertDashboardPreferences|UpdateDashboardPreferences" internal/database/queries.sql

4.2 Verify Query Correctness

For GetDashboardPreferences:

  • Selects all columns from user_dashboard_preferences
  • WHERE clause matches on user_id AND library_id
  • Returns single row or error

For UpsertDashboardPreferences:

  • INSERTs on conflict with (user_id, library_id)
  • Updates all preferences columns
  • Updates updated_at to NOW()
  • Returns inserted/updated row

For GetCollectionsForDashboard:

  • Two separate queries for system and user collections
  • System collections: WHERE user_id IS NULL AND show_on_dashboard = true
  • User collections: WHERE user_id = $1 AND show_on_dashboard = true AND is_system_collection = false
  • Both ordered by priority ASC
  • Returns multiple rows

For RestoreSystemCollection:

  • Deletes user-owned copy of system collection
  • WHERE user_id = $1 AND name = $2 AND is_system_collection = true
  • System collection (user_id = NULL) automatically appears after deletion

Verification:

# Test queries in isolation
psql bookhoard <<EOF
-- Test GetDashboardPreferences
SELECT * FROM user_dashboard_preferences WHERE user_id = '$1' AND library_id = '$2';

-- Test GetCollectionsForDashboard
SELECT c.* FROM collections c
WHERE c.user_id = '$1'
  AND c.show_on_dashboard = true
ORDER BY c.created_at DESC;
EOF

4.3 Verify Queries Generated

After running sqlc generate:

  • internal/database/models.go has new structs
  • internal/database/dashboard.go has query functions
  • No compilation errors in generated code
  • All query functions are exported
  • Parameter types are correct (UUID, TEXT[], INT, etc.)

Check:

# Regenerate queries
cd internal/database && sqlc generate

# Check generated files
ls -la internal/database/*.go | grep -E "(models|dashboard|queries)"

# Look for compilation errors
go build ./internal/database/...

5. API Handler Verification

5.1 Verify Handler Follows Guidelines

For internal/handlers/dashboard.go:

  • Uses service layer (no direct database access)
  • Returns JSON responses
  • Uses proper HTTP status codes
  • Error responses are consistent
  • Authentication required (JWT middleware)
  • Input validation is performed
  • No HTML responses (API only)
  • Reusable by SSR, API, mobile
  • Uses shared types from collections.go (SectionData, BookInfo)
  • No duplicate type definitions

Verification:

# Check for direct database access (should find nothing)
rg "Queries\." internal/handlers/dashboard.go
# Only service calls should exist

# Check HTTP status codes
rg "http\.Status" internal/handlers/dashboard.go

# Check error responses
rg "c\.JSON.*error" internal/handlers/dashboard.go

# Verify authentication
rg "c\.Get\(\"user\"\)" internal/handlers/dashboard.go

# Verify no duplicate types in dashboard.go
rg "type (SectionData|BookInfo) struct" internal/handlers/dashboard.go
# Should return nothing - these are in collections.go

# Verify types imported from collections.go
rg "collections\.go" internal/handlers/dashboard.go

5.2 Verify GetSections Endpoint

Request parameters:

  • library_id query parameter (required)
  • limit query parameter (optional, default 20, max 100)
  • User from JWT context
  • User preferences applied (order, hidden collections)

Response format:

  • Returns JSON object with sections array
  • Each section has:
    • id (collection key or name)
    • is_system (boolean: true for system collections, false for user collections)
    • title
    • description
    • icon
    • items (array of books)
    • Each book item has:
      • media_item_id (NOT id)
      • title
      • author
      • cover_image_path
    • view_all_url (empty for user collections)
    • priority
    • id (UUID string)
    • title
    • author
    • cover_image_path

Error cases:

  • 400 if library_id missing
  • 400 if library_id invalid UUID
  • 401 if not authenticated
  • 500 if service fails

Verification:

# Check endpoint implementation
rg "func.*GetSections" internal/handlers/dashboard.go -A 50

# Verify response structure
rg "buildJSONSections" internal/handlers/dashboard.go -A 30

# Test with Bruno
cd bruno/dashboard/
# Run: GET /api/dashboard/sections?library_id=...

5.3 Verify BuildSections Function

Required function:

  • BuildSections(sections []services.DashboardSection) []SectionData in dashboard.go

Key requirements:

  • Converts service SectionItems to handler SectionData (from collections.go)
  • Maps database.MediaItems to handlers.BookInfo (from collections.go)
  • Uses MediaItemID field (not ID) when creating BookInfo
  • Uses IsSystem boolean directly from database (no string conversion)
  • No helper functions needed for type/title/icon (use database values directly)
  • getViewAllURL() helper for system collection URLs only

System collections data (from database):

  • continue-reading → is_system: true, title from DB, icon from DB
  • recently-added → is_system: true, title from DB, icon from DB
  • recently-read → is_system: true, title from DB, icon from DB
  • not-started → is_system: true, title from DB, icon from DB

User collections:

  • is_system: false (from database is_system_collection field)
  • Title uses collection name from database
  • Icon uses collection icon from database
  • view_all_url is empty string

Verification:

# Check BuildSections function
rg "func BuildSections" internal/handlers/dashboard.go -A 50

# Verify MediaItemID field usage
rg "MediaItemID.*String\(\)" internal/handlers/dashboard.go

# Verify IsSystem boolean used directly
rg "IsSystem.*si\.IsSystem" internal/handlers/dashboard.go

# Verify no type conversion helpers
rg "getSectionType|getSectionTitle|getSectionIcon" internal/handlers/dashboard.go
# Should return nothing - no longer needed

6. Routing Verification

6.1 Verify API Routes

For internal/router/dashboard.go:

  • Route group registered at /api/dashboard
  • JWT middleware applied
  • GET /api/dashboard/sectionsGetSections
  • Handler injected via Config struct
  • Route registration called from main router

Verification:

# Check route definition
rg "registerDashboardRoutes" internal/router/dashboard.go -A 20

# Verify handler registered
rg "DashboardHandler" internal/router/router.go

# Check middleware
rg "jwtMiddleware" internal/router/dashboard.go

6.2 Verify Frontend Routes

For internal/router/frontend.go:

  • GET /dashboard route exists
  • Uses DashboardService for data
  • Renders templates.Dashboard
  • Passes sections, libraries, currentLibraryID
  • Gets user from context
  • Applies user preferences
  • Library switching supported

For /settings route:

  • GET /settings → renders settings form
  • POST /settings → updates user and preferences
  • Handles profile fields (email, username, name)
  • Handles theme selection
  • Handles dashboard preferences
  • Returns JSON on success

Verification:

# Check dashboard route
rg 'GET.*"/dashboard"' internal/router/frontend.go -A 50

# Check settings route
rg 'GET.*"/settings"' internal/router/frontend.go -A 20
rg 'POST.*"/settings"' internal/router/frontend.go -A 40

For /custom-section route:

  • GET /custom-section → renders custom section builder form
  • Passes libraries for selector
  • Renders templates.CustomSectionBuilder
  • Links from dashboard settings modal
  • No POST route (form submits via JSON to /api/collections)

Verification:

# Check custom-section route
rg 'GET.*"/custom-section"' internal/router/frontend.go -A 20

# Verify template rendering
rg "templates.CustomSectionBuilder" internal/router/frontend.go

# Verify libraries passed to template
rg "CustomSectionBuilder.*libraries" internal/router/frontend.go

6.3 Verify Collections Preview Endpoint

IMPORTANT: This endpoint is REQUIRED for both web UI and mobile apps

Why this endpoint is necessary:

  • Web UI: Custom section builder needs to test filter rules before saving
  • Mobile apps: Will need this endpoint for future custom section creation
  • No duplication: Reuses existing collectionService.EvaluateRules() logic
  • Single source of truth: Rule evaluation logic stays in Go service layer

Why NOT client-side preview?

  • Would require downloading entire library (10,000+ books) to browser
  • Would duplicate 500+ lines of rule evaluation logic in TypeScript
  • Maintenance nightmare (keeping Go and TypeScript in sync)
  • Risk of client/server evaluating rules differently

For internal/handlers/collections.go:

  • PreviewCollection method exists
  • POST /api/collections/preview route registered in collections.go
  • Accepts library_id, rules, manual_book_ids, limit in request body
  • Evaluates filter rules against library items
  • Merges filter matches + manually selected books
  • Deduplicates items (no duplicates in final result)
  • Applies limit after merging
  • Uses existing collectionService.EvaluateRules()
  • Returns handlers.BookInfo format with media_item_id field

Request format:

{
  "library_id": "uuid",
  "rules": [
    {
      "id": "rule1",
      "field": "genre",
      "operator": "equals",
      "value": "Sci-Fi",
      "priority": 5
    }
  ],
  "manual_book_ids": ["uuid1", "uuid2"],
  "limit": 20
}

Response format:

{
  "items": [
    {
      "media_item_id": "uuid",
      "title": "Dune",
      "author": "Frank Herbert",
      "cover_image_path": "/path/to/cover.jpg"
    }
  ]
}

Verification:

# Check handler method exists (Phase 4.5 of plan)
rg "func.*PreviewCollection" internal/handlers/collections.go -A 30

# Check route registration (Phase 4.5 of plan)
rg 'POST.*"/preview"' internal/router/collections.go

# Verify EvaluateRules usage
rg "collectionService.EvaluateRules" internal/handlers/collections.go

# Check BookInfo conversion with MediaItemID
rg "MediaItemID.*String\(\)" internal/handlers/collections.go

# Verify manual book ID handling
rg "manual_book_ids" internal/handlers/collections.go

# Check Bruno test exists
ls -la bruno/dashboard/preview-collection.bru

6.4 Verify CreateCollection Endpoint Manual Books Support

IMPORTANT: Custom Section Builder requires this feature

Why this endpoint update is necessary:

  • Custom Section Builder allows users to select books manually + use filter rules
  • Single API call creates collection + adds books (cleaner than separate calls)
  • Reuses existing AddBookToCollection service method

For internal/handlers/collections.go:

Struct updates:

  • ManualBookIDs []string field added to CreateCollectionRequest struct (after line 40)
  • Field has JSON tag: json:"manual_book_ids"
  • Field has validation tag: validate:"max=50"

Handler updates:

  • CreateCollection function updated (after line 97)
  • Parses and validates req.ManualBookIDs
  • Loops through manual book IDs
  • Calls h.collectionService.AddBookToCollection for each valid book ID
  • Logs errors for invalid book IDs but continues processing
  • Logs summary of added books

Error handling:

  • Invalid book IDs are skipped (not added to collection)
  • Errors are logged using c.Logger().Errorf
  • Collection is still created even if some books fail to add
  • Returns 201 on success (even if some books failed)

Validation:

  • Request validation checks manual_book_ids array length ≤ 50
  • Returns 400 if more than 50 book IDs provided
  • Validation tag enforces max limit: validate:"max=50"

Verification commands:

# Check ManualBookIDs field exists in struct
rg "ManualBookIDs.*\[\]string" internal/handlers/collections.go

# Check validation tag is present
rg 'validate:"max=50"' internal/handlers/collections.go

# Check CreateCollection handler processes manual books
rg "ManualBookIDs" internal/handlers/collections.go -A 30

# Verify AddBookToCollection is called
rg "AddBookToCollection.*ManualBookIDs" internal/handlers/collections.go -A 5

# Check error logging for invalid book IDs
rg "Logger.*Errorf.*Invalid book ID" internal/handlers/collections.go

Common pitfalls:

  • Forgetting to validate array length (DoS vulnerability)
  • Returning error on first invalid book ID (should continue processing)
  • Not logging errors (makes debugging difficult)
  • Creating separate service method (unnecessary - reuse existing)

6.5 Verify Config Setup

CRITICAL: Config struct must be updated in 3 files

For internal/router/router.go:

  • DashboardService *services.DashboardService added to Config struct (after line 56)
  • DashboardHandler *handlers.DashboardHandler added to Config struct (after line 57)
  • Field order matches other service/handler fields

For cmd/server/main.go:

  • dashboardService := services.NewDashboardService(queries) initialized (after line 123)
  • dashboardHandler := handlers.NewDashboardHandler(queries) initialized (after line 124)
  • DashboardService: dashboardService, added to routerConfig (after line 172)
  • DashboardHandler: dashboardHandler, added to routerConfig (after line 173)
  • Both initialized before router.RegisterRoutes() call

For cmd/server/tests/test_helpers.go:

  • dashboardService := services.NewDashboardService(queries) initialized (after line 419)
  • dashboardHandler := handlers.NewDashboardHandler(queries) initialized (after line 420)
  • DashboardService: dashboardService, added to routerConfig (after line 458)
  • DashboardHandler: dashboardHandler, added to routerConfig (after line 459)

Why both DashboardService AND DashboardHandler?

  • DashboardService: Used by SSR routes in frontend.go for data fetching
  • DashboardHandler: Used by API routes for JSON endpoints
  • Mobile apps: Will use DashboardHandler API endpoints
  • Web UI: Uses DashboardService for SSR + DashboardHandler for interactions

Verification:

# Check Config struct has both fields
rg "DashboardService|DashboardHandler" internal/router/router.go

# Check main.go initialization (should find 2 initializations + 2 config assignments)
rg "dashboardService|dashboardHandler" cmd/server/main.go

# Check test_helpers.go initialization (should find 2 initializations + 2 config assignments)
rg "dashboardService|dashboardHandler" cmd/server/tests/test_helpers.go

# Verify service is used in frontend.go
rg "DashboardService" internal/router/frontend.go

# Verify handler is used in dashboard.go router
rg "DashboardHandler" internal/router/dashboard.go

7. Template Types Verification

7.1 Verify No Duplicate Types in Go

CRITICAL GUIDELINE COMPLIANCE (Go side):

  • NO templates.SectionData or templates.BookCardData created in Go
  • Dashboard sections use handler types directly (e.g., handlers.CollectionData, handlers.BookInfo)
  • OR use existing database types (e.g., database.MediaItems)
  • Template-only types are ONLY for UI-specific concerns (e.g., PageData, UnsafeHTML)
  • No parallel type systems in Go

CORRECT (Go):

// Handler type defined once in handlers package
// Reused directly in template
templ Dashboard(sections []handlers.SectionData, books []handlers.BookInfo)

WRONG (Go):

// Handler type defined in handlers
// Duplicate type defined in templates - VIOLATES GUIDELINES
type SectionData struct { ... }  // DON'T DO THIS in Go

When template-specific fields needed:

// ✅ ENHANCE handler type (don't create new type)
type BookInfo struct {
    MediaItemID string
    Title       string
    Author      string
    // Add template-specific fields to handler struct
    Icon        string  // Template enhancement
}

TypeScript Side (.d.ts files) - ACCEPTABLE DUPLICATION:

  • TypeScript type definitions in .d.ts files ARE acceptable
  • Go's pgtype fields cannot auto-convert to TypeScript
  • Manual recreation of types in web/src/types/*.d.ts is necessary
  • TypeScript types must match Go handler JSON responses (snake_case)
  • This is cross-language duplication, not Go duplication

CORRECT (TypeScript):

// web/src/types/dashboard.d.ts
// Acceptable: Recreate types to match Go JSON responses
// Go's pgtype.Text, pgtype.UUID, etc. need manual mapping

interface SectionData {
    id: string;                    // matches Go's json:"id"
    title: string;                 // matches Go's json:"title"
    items: BookCardData[];         // matches Go's json:"items"
}

Verification:

# Check for duplicate Go types (should find none)
rg "type (SectionData|BookCardData) struct" templates/types.go
# Should return nothing - use handler types instead

# Verify handler types exist
rg "type.*Data struct" internal/handlers/*.go

# Check template imports handler package
rg 'import.*handlers' templates/*.templ

# Check template uses handler types
rg 'handlers\.(CollectionData|BookInfo|UserProfile)' templates/*.templ

# TypeScript types (acceptable to exist)
ls -la web/src/types/dashboard.d.ts  # OK - .d.ts file
ls -la web/static/dashboard.d.ts     # Should NOT exist - no JS output

Common Pitfalls:

  • Creating templates.SectionData in Go when handlers.SectionData should be enhanced
  • Creating templates.BookCardData in Go when handlers.BookInfo should be used
  • Adding conversion helper functions (unnecessary - use handler types directly)
  • Parallel type systems in Go (handlers + templates with same data)
  • NOT a pitfall: TypeScript .d.ts files recreating types (necessary due to pgtype)

7.2 Verify Handler Type Tags

All handler struct fields:

  • Have json:"" tags for API responses
  • Use snake_case in JSON tags
  • Matching Go field names are PascalCase
  • No duplicate tags
  • No missing tags
  • Template-specific fields added to handler structs when needed

Check:

# Verify JSON tags in handler types
rg 'json:"' internal/handlers/*.go

# Check for snake_case
rg 'json:"[A-Z]' internal/handlers/*.go
# Should return nothing (no camelCase in JSON tags)

# Verify handler types used in templates
rg 'handlers\.' templates/*.templ

8. Template Implementation Verification

8.1 Verify Dashboard Template

For templates/dashboard.templ:

  • Uses handler types directly (e.g., handlers.SectionData, handlers.BookInfo)
  • OR uses database types (e.g., database.MediaItems)
  • NO templates.SectionData or templates.BookCardData (violates guidelines)
  • SSR data pre-populated (sections, libraries)
  • TailwindCSS classes only (no custom CSS)
  • HTMX for library switching
  • Event delegation (no inline onclick)
  • Data attributes for TypeScript hooks
  • Includes all required scripts:
    • /static/htmx.min.js
    • /static/toast.js
    • /static/api.js
    • /static/events.js
    • /static/dashboard.js

Template structure:

  • Sticky header with library selector
  • Settings button (data-action="open-dashboard-settings")
  • Refresh button (data-action="reload-page")
  • Sections container (#sections-container)
  • HTMX loading indicator
  • Dashboard settings modal

Verification:

# Check template structure
rg "templ Dashboard" templates/dashboard.templ -A 100

# Verify TailwindCSS usage
rg 'class="[^"]*"' templates/dashboard.templ | rg -v 'style='
# Should have many Tailwind classes

# Check for inline styles (should use CSS variables)
rg 'style=' templates/dashboard.templ

# Verify event delegation
rg 'data-action=' templates/dashboard.templ

# Check for inline onclick (should be none)
rg 'onclick=' templates/dashboard.templ
# Should return nothing

# Verify script includes
rg '<script src=' templates/dashboard.templ

8.2 Verify Component Templates

For CollectionCarousel:

  • Accepts handler type parameter (e.g., handlers.SectionData)
  • OR accepts database type (e.g., []database.MediaItems)
  • NOT templates.SectionData (violates guidelines)
  • Renders collection header (title, icon, view-all link)
  • Renders carousel container
  • Navigation buttons (left/right)
  • Carousel track (overflow-x-auto)
  • Book cards (snap-start)
  • Data attributes:
    • data-collection-id
    • data-is-system (boolean: "true" or "false")
    • data-action="scroll-carousel"
  • Accessibility attributes:
    • aria-label on nav buttons
    • tabindex="0" on book cards
    • role="button" on book cards
  • For system collections: Shows "Restore" button

For BookCard:

  • Accepts handler type parameter (e.g., handlers.BookInfo)
  • OR accepts database type (e.g., database.MediaItems)
  • NOT templates.BookCardData (violates guidelines)
  • Aspect ratio 2:3 for cover
  • Lazy loading on images
  • Fallback placeholder image
  • Title line-clamp (2 lines)
  • Author line-clamp (1 line)
  • Hover effects (scale-105)
  • Data attributes:
    • data-action="view-book"
    • data-book-id

For DashboardSettingsModal:

  • Fixed overlay with backdrop
  • Draggable collection list
  • Toggle switches for visibility
  • Per-collection "Restore" buttons for system collections
  • Items per collection slider
  • Save/Cancel buttons
  • Data attributes:
    • data-action="close-dashboard-settings"
    • data-action="toggle-collection-visibility"
    • data-action="restore-system-collection" (for system collections)
    • data-action="update-items-count"
    • data-action="save-dashboard-settings"

Verification:

# Check component structure
rg "templ (SectionCarousel|BookCard|DashboardSettingsModal)" templates/ -A 50

# CRITICAL: Verify templates use handler types
rg 'handlers\.(SectionData|BookInfo|CollectionData)' templates/*.templ

# CRITICAL: Check for template types (should find none)
rg "templates\.(SectionData|BookCardData)" templates/*.templ
# Should return nothing

# Verify accessibility
rg 'aria-|role=|tabindex' templates/

# Check data attributes
rg 'data-(action|section|book)=' templates/

8.3 Verify Library Selector (TypeScript, Not HTMX)

Library selector attributes:

  • Select element has id="library-select" and name="library_id"
  • NO HTMX attributes (no hx-get, hx-target, etc.)
  • Uses data-action="switch-library" or change event listener
  • Options rendered from SSR data (libraries parameter)
  • Current library selected by default

Loading indicator:

  • #loading-spinner element exists (hidden by default)
  • Used by TypeScript during library switching
  • Shows/hides via CSS class manipulation

Verification:

# Check library selector (should NOT have HTMX)
rg 'id="library-select"' templates/dashboard.templ -A 5

# Verify NO HTMX attributes on library selector
rg 'id="library-select"' templates/dashboard.templ -A 5 | rg 'hx-'
# Should return nothing

# Check loading indicator exists
rg 'loading-spinner' templates/dashboard.templ

# Verify data-action for library switching
rg 'data-action="switch-library"' templates/dashboard.templ

8.4 Verify Settings Template

For templates/settings.templ:

  • Uses handler/database types (database.Users, database.UserDashboardPreferences)
  • Profile section (email, username, name)
  • Theme selector (tokyo-night, light, dark)
  • Dashboard preferences (items per section)
  • Form uses data-action="save-settings"
  • TailwindCSS only
  • Event delegation
  • Includes required scripts
  • NO template types for user data (use database.Users directly)

Verification:

# Check settings template
rg "templ Settings" templates/settings.templ -A 100

# Verify form handling
rg 'data-action="save-settings"' templates/settings.templ

# CRITICAL: Verify database types used, not template types
rg "database\.(Users|UserDashboardPreferences)" templates/settings.templ

8.5 Verify Custom Section Builder Template

IMPORTANT: Custom Section Builder IS in the plan (Phase 10.5)

This is a major feature allowing users to create filter-based custom dashboard sections with 13+ filter fields.

For templates/custom_section.templ:

  • SSR page for creating filter-based custom sections
  • Uses handler types (handlers.User, templates.LibraryData)
  • Section details form (name, icon, description, library selector)
  • Filter rules section with dynamic rule addition
  • Manual book selection section with search
  • Live preview section showing matching books
  • TailwindCSS only
  • Includes required script (custom-section-builder.js)
  • Links to /custom-section route (registered in Phase 8)

Form structure verification:

  • Name input (required)
  • Icon input (optional, emoji)
  • Description textarea (optional)
  • Library selector (required, populated from SSR)
  • Filter rules container with id="rules-container"
  • "Add Rule" button with id="add-rule-btn"
  • Match type selector (ALL/ANY)
  • Manual book selection section
  • Book search input with id="book-search"
  • Search button with id="search-books-btn"
  • Search results container with id="search-results"
  • Selected books container with id="selected-books"
  • Preview button with id="preview-btn"
  • Preview container with id="preview-container"
  • Save button (form submit)
  • Cancel button with id="cancel-btn"

Rule fields (13+ filter fields):

  • Field selector (title, author, genre, series, progress, rating, date_added, last_read, publisher, language, format, tags, narrators)
  • Operator selector (varies by field type)
  • Value input (text, number, date, or select)
  • Remove button for each rule

Manual book selection:

  • Search input with debounced autocomplete
  • Search results display with "+" button to add
  • Selected books displayed as removable chips
  • Search results hidden by default

Preview section:

  • Shows loading state while fetching
  • Displays matching books in carousel layout
  • Shows count of matching books
  • Handles empty results gracefully

Verification:

# Check template exists
ls -la templates/custom_section.templ

# Check template structure
rg "templ CustomSectionBuilder" templates/custom_section.templ -A 100

# Verify SSR data (libraries, user parameters)
rg "CustomSectionBuilder.*user.*libraries" templates/custom_section.templ

# Verify form fields
rg 'name="name".*required' templates/custom_section.templ
rg 'name="library_id".*required' templates/custom_section.templ
rg 'name="icon"' templates/custom_section.templ
rg 'name="description"' templates/custom_section.templ

# Verify filter rules container
rg 'id="rules-container"' templates/custom_section.templ
rg 'id="add-rule-btn"' templates/custom_section.templ

# Verify match type selector
rg 'name="match_type"' templates/custom_section.templ

# Verify manual book selection
rg 'id="book-search"' templates/custom_section.templ
rg 'id="search-books-btn"' templates/custom_section.templ
rg 'id="search-results"' templates/custom_section.templ
rg 'id="selected-books"' templates/custom_section.templ

# Verify preview section
rg 'id="preview-container"' templates/custom_section.templ
rg 'id="preview-btn"' templates/custom_section.templ

# Verify TailwindCSS only (no custom CSS)
rg '<style' templates/custom_section.templ
# Should return nothing

# Verify no inline event handlers (flexible - inline onclick acceptable)
# Event delegation preferred but not strictly required

# Verify script includes
rg 'custom-section-builder.js' templates/custom_section.templ

# Check for 13+ filter field options in plan
rg "title|author|genre|series|progress|rating|date_added|last_read|publisher|language|format|tags|narrators" CAROUSEL_DASHBOARD_PLAN.md

JavaScript integration verification:

  • Event delegation handles all form actions
  • Rules dynamically added to DOM
  • Book search with debounce (300ms)
  • Selected books stored in Map for deduplication
  • Form submission prevented, JSON sent via API
  • Preview updates DOM without page reload
  • Global functions for inline onclick (addBookToSelection, removeBookFromSelection)

9. TypeScript Implementation Verification

9.1 Verify TypeScript Module Structure

For web/src/dashboard.ts:

  • Procedural style (no classes, no this)
  • Functions exported to window object
  • Event delegation via data-action attributes
  • Uses shared modules:
    • (window as any).api from api.ts
    • (window as any).showToast from toast.ts
    • (window as any).events from events.ts
  • Type definitions imported from types/api.d.ts or types/dashboard.d.ts
  • No ES module imports/exports (browser globals)

Verification:

# Check for OOP patterns (should find nothing)
rg "class |this\." web/src/dashboard.ts

# Verify window exports
rg "window\." web/src/dashboard.ts

# Check for ES modules (should use 'import type' only)
rg "^import " web/src/dashboard.ts
rg "import type " web/src/dashboard.ts

# Verify shared module usage
rg "api\.|showToast\.|events\." web/src/dashboard.ts

9.2 Verify TypeScript Dashboard Functions

Required functions:

  • scrollCarousel(collectionId: string, direction: number): void
  • switchLibrary(libraryId: string): Promise<void> - Fetches JSON and re-renders collections
  • renderCollections(sections: SectionData[]): void - Renders collections from JSON
  • renderBookCard(book: BookInfo): string - Renders single book card HTML
  • openDashboardSettings(): void
  • closeDashboardSettings(): void
  • saveDashboardSettings(): Promise<void>
  • toggleCollectionVisibility(collectionId: string): void
  • restoreSystemCollection(collectionName: string, collectionTitle: string): Promise<void>
  • viewBook(bookId: string): Promise<void>
  • reloadPage(): void
  • updateItemsCount(count: number): void

Behavior verification:

  • Scroll amount is 300px (SCROLL_AMOUNT constant)
  • Smooth scrolling enabled
  • Modal show/hide toggles CSS classes
  • Settings saved via API call
  • Toast notifications on success/error
  • Error handling for network failures

Verification:

# Check function definitions
rg "^function (scroll|open|close|save|toggle|update|view|reload)" web/src/dashboard.ts

# Verify scroll behavior
rg "scrollBy|scrollLeft" web/src/dashboard.ts

# Check API calls
rg "api\.(get|post|put|delete)" web/src/dashboard.ts

# Verify toast usage
rg "showToast\.(error|success|info)" web/src/dashboard.ts

9.3 Verify Event Delegation

Event listeners:

  • Single click listener for all dashboard actions
  • Library select change event listener (for switchLibrary)
  • Uses data-action attributes
  • Handles:
    • switch-library (library select changes)
    • scroll-carousel
    • open-dashboard-settings
    • close-dashboard-settings
    • save-dashboard-settings
    • toggle-section-visibility
    • update-items-count
    • view-book
    • reload-page

Verification:

# Check event listener setup
rg "addEventListener\('click'" web/src/dashboard.ts -A 50

# Verify data-action checks
rg 'dataset\.action|getAttribute\("data-action"\)' web/src/dashboard.ts

9.4 Verify Settings TypeScript

For web/src/settings.ts:

  • Form submission handler
  • Profile field updates
  • Theme selection
  • Dashboard preferences updates
  • Client-side validation
  • Error handling
  • Toast notifications
  • Progressive enhancement (works without JS)

Verification:

# Check settings module
rg "^function " web/src/settings.ts

# Verify form handling
rg "addEventListener\('submit'" web/src/settings.ts

# Check validation
rg "validity|checkValidity" web/src/settings.ts

9.4 Verify Custom Section Builder TypeScript

IMPORTANT: Custom Section Builder TypeScript IS in the plan (Phase 10.5.3)

This file implements the custom section builder UI with 13+ filter fields and live preview functionality.

For web/src/custom-section-builder.ts:

  • Procedural style (no classes, no this)
  • Uses shared API client and toast
  • Event delegation or inline onclick (flexible)
  • Dynamic rule addition/removal
  • Live preview functionality using /api/collections/preview endpoint
  • Manual book selection with search
  • 13+ filter fields with various operators

Type definitions:

  • FilterField interface with id, label, operators, valueType, options
  • Operator interface with id, label, requiresValue
  • FilterRule interface with id, field, operator, value, priority
  • FILTER_FIELDS const array with 13+ fields

Required functions:

  • initCustomSectionBuilder(): void - Sets up event listeners
  • addFilterRule(): void - Adds new rule row to form
  • onFieldChange(ruleElement: HTMLElement): void - Updates operators/value input based on field
  • removeFilterRule(ruleId: string): void - Removes rule row
  • searchBooks(): Promise<void> - Searches for books by title/author
  • onBookSearchInput(): void - Debounced search handler
  • displaySearchResults(books: BookInfo[]): void - Shows search results
  • addBookToSelection(bookId, title, author): void - Global function for onclick
  • removeBookFromSelection(bookId: string): void - Global function for onclick
  • updateSelectedBooksDisplay(): void - Updates selected books UI
  • gatherFilterRules(): FilterRule[] - Collects all rules from form
  • loadPreview(): Promise<void> - Calls preview API, displays results
  • saveCustomSection(event: Event): Promise<void> - Creates collection
  • escapeHtml(text: string): string - Utility for HTML escaping

13+ Filter fields verification:

  • title - text field (contains, equals, starts_with, ends_with, regex)
  • author - text field (contains, equals)
  • genre - select field (equals, not_equals, in, not_in)
  • series - text field (is_set, is_not_set, equals, contains)
  • progress - number field (equals, not_equals, greater_than, less_than, between, is_set, is_not_set)
  • rating - number field (equals, not_equals, greater_than, less_than, is_set, is_not_set)
  • date_added - date field (equals, not_equals, before, after, between, last_x_days)
  • last_read - date field (equals, before, after, between, last_x_days, is_set, is_not_set)
  • publisher - text field (contains, equals)
  • language - select field (equals, not_equals, in)
  • format - select field (equals, in)
  • tags - text field (contains, not_contains, equals)
  • narrators - text field (contains, equals, is_set, is_not_set)

Preview functionality:

  • Validates library_id is selected
  • Calls /api/collections/preview endpoint
  • Sends rules array and manual_book_ids array
  • Displays matching books in carousel layout
  • Shows count of matching books
  • Handles loading state
  • Handles errors with toast notification

Verification:

# Check file exists
ls -la web/src/custom-section-builder.ts

# Check for OOP patterns (should find nothing)
rg "class |this\." web/src/custom-section-builder.ts

# Verify type definitions
rg "interface (FilterField|Operator|FilterRule)" web/src/custom-section-builder.ts

# Check FILTER_FIELDS const has 13+ fields
rg "FILTER_FIELDS.*=.*\[" web/src/custom-section-builder.ts -A 100
rg "id:.*title|id:.*author|id:.*genre|id:.*series|id:.*progress|id:.*rating" web/src/custom-section-builder.ts

# Check required functions exist
rg "^function (initCustomSectionBuilder|addFilterRule|onFieldChange|removeFilterRule|searchBooks|loadPreview|saveCustomSection)" web/src/custom-section-builder.ts

# Verify global functions for inline onclick
rg "window\.addBookToSelection|window\.removeBookFromSelection" web/src/custom-section-builder.ts

# Verify API integration
rg "api\.post.*collections/preview" web/src/custom-section-builder.ts

# Verify toast usage
rg "showToast\.(error|success|warning|info)" web/src/custom-section-builder.ts

# Verify rule HTML generation
rg "insertAdjacentHTML|createElement" web/src/custom-section-builder.ts

# Verify search debounce
rg "searchTimeout|setTimeout|clearTimeout" web/src/custom-section-builder.ts

# Verify selected books tracking
rg "selectedBooks.*Map|new Map\(\)" web/src/custom-section-builder.ts

# Verify escapeHtml utility
rg "function escapeHtml" web/src/custom-section-builder.ts

Form verification:

  • Event delegation handles actions OR inline onclick used (flexible)
  • Rules dynamically added to DOM
  • Book search with debounce (300ms timeout)
  • Selected books stored in Map for deduplication
  • Form submission prevented, JSON sent via API
  • Preview updates DOM without page reload

9.5 Verify TypeScript Compilation

Build verification:

  • npm run build:ts succeeds
  • web/static/dashboard.js generated
  • web/static/settings.js generated
  • No compilation errors
  • No type errors
  • Source maps generated (if configured)

Check:

# Compile TypeScript
npm run build:ts

# Verify output
ls -la web/static/dashboard.js
ls -la web/static/settings.js

# Check for errors
echo $?  # Should be 0

10. Type Definition Verification

10.1 Verify Dashboard Type Definitions

For web/src/types/api.d.ts (.d.ts = no JS output):

  • TypeScript interfaces recreate complete handler JSON structure (acceptable - necessary due to pgtype)
  • SectionData interface matches ALL fields from handlers.SectionData JSON response
  • BookInfo interface matches ALL fields from handlers.BookInfo JSON response
  • DashboardPreferences interface matches request/response structure
  • NO missing fields - TypeScript must include every field from Go handler
  • NO partial type definitions - if Go struct has 10 fields, TypeScript must have 10 fields
  • Field names use snake_case (matching JSON responses exactly)
  • pgtype fields mapped correctly:
    • pgtype.Textstring
    • pgtype.UUIDstring
    • pgtype.Timestampstring (ISO datetime)
    • pgtype.Int4number
    • pgtype.Boolboolean
    • pgtype.TextArraystring[]
  • Field order doesn't matter (TypeScript interfaces are unordered)

TypeScript Duplication is ACCEPTABLE:

  • .d.ts files recreate types from Go handlers (necessary)
  • Go's pgtype fields cannot auto-convert to TypeScript
  • Manual type mapping is required and acceptable
  • This is cross-language duplication, not in-Go duplication
  • NOT acceptable: Creating templates.SectionData in Go (violates guidelines)
  • CRITICAL: TypeScript types must match in full the Go handler return types
    • All fields from Go struct included in TypeScript interface
    • No partial type definitions (missing fields)
    • Field names match exactly (snake_case JSON tags)
    • Types match correctly (pgtype mapped to TypeScript types)

Custom Section Builder type definitions:

  • FilterField interface in custom-section-builder.ts (not in api.d.ts - UI-specific)
  • FilterRule interface matches Go services.Rule struct
  • Rule fields: id (string), field (string), operator (string), value (string | string[]), priority (number)
  • 13+ field options defined in FILTER_FIELDS const
  • Each field has appropriate operators based on type

Verification:

# Check TypeScript type definitions
cat web/src/types/dashboard.d.ts

# Verify .d.ts extension (no JS output)
ls -la web/src/types/dashboard.d.ts

# Ensure it doesn't compile to JS
npm run build:ts
ls -la web/static/dashboard.d.ts  # Should not exist

# CRITICAL: Verify handler types exist in Go
rg "type.*SectionData|type.*BookData|type.*BookInfo" internal/handlers/*.go

# Check plan references handler types, not Go template types
rg "handlers\." CAROUSEL_DASHBOARD_PLAN.md | rg -i "section|book"

# TypeScript types can mirror handler types (acceptable)
rg "interface.*Data" web/src/types/*.d.ts

# CRITICAL: Verify TypeScript types match Go types IN FULL

# Step 1: Extract Go handler struct with JSON tags
# NOTE: SectionData and BookInfo are in internal/handlers/collections.go
rg "type (SectionData|BookInfo) struct" internal/handlers/collections.go -A 30 | grep 'json:"'

# Step 2: Extract TypeScript interface
rg "interface (SectionData|BookInfo)" web/src/types/dashboard.d.ts -A 30

# Step 3: Manually compare - Go should have same fields as TypeScript
# Example verification:

# Go handler struct (internal/handlers/collections.go):
# type SectionData struct {
#     ID          string     `json:"id"`
#     IsSystem    bool       `json:"is_system"`        // Changed from Type string
#     Title       string     `json:"title"`
#     Description string     `json:"description"`
#     Icon        string     `json:"icon"`
#     Items       []BookInfo `json:"items"`
#     ViewAllURL  string     `json:"view_all_url"`
#     Priority    int        `json:"priority"`
# }
# // 8 fields total

# TypeScript interface (web/src/types/dashboard.d.ts) - MUST HAVE ALL 8 FIELDS:
# interface SectionData {
#     id: string;
#     is_system: boolean;      // Changed from type: string
#     title: string;
#     description: string;
#     icon: string;
#     items: BookInfo[];
#     view_all_url: string;
#     priority: number;
# }

# Go handler struct (internal/handlers/collections.go):
# type BookInfo struct {
#     MediaItemID    string `json:"media_item_id"`    // NOT "id"
#     Title          string `json:"title"`
#     Author         string `json:"author"`
#     CoverImagePath string `json:"cover_image_path"`
# }
# // 4 fields total

# TypeScript interface (web/src/types/dashboard.d.ts) - MUST HAVE ALL 4 FIELDS:
# interface BookInfo {
#     media_item_id: string;        // ✅ matches (NOT "id")
#     title: string;                // ✅ matches
#     author: string;               // ✅ matches
#     cover_image_path: string;     // ✅ matches
# }

# ❌ WRONG - Wrong field names:
# interface BookInfo {
#     id: string;                   // WRONG: should be media_item_id
#     title: string;
#     author: string;
#     cover_image_path: string;
# }
# ❌ WRONG - Wrong type field:
# interface SectionData {
#     id: string;
#     type: string;                 // WRONG: should be is_system: boolean
#     title: string;
#     // ... other fields
# }

# Check for missing fields (manual verification required):
# 1. List all Go struct fields with JSON tags
# 2. List all TypeScript interface fields
# 3. Verify 1:1 correspondence (same field names, correct types)

10.2 Verify Type Consistency

Across layers:

  • Database schema → Go structs (models.go)
  • Go structs → Handler types (with template-specific fields added)
  • Handler types → Template usage (direct import, no conversion in Go)
  • Handler JSON responses → TypeScript interfaces (manual recreation in .d.ts)
  • All use snake_case for JSON

Key Pattern:

Database (models.go) → Handler (enhanced) → Template (uses handlers.Type) → TypeScript (.d.ts recreates handlers.Type JSON IN FULL)

CRITICAL REQUIREMENT: TypeScript Types Must Match Go Types IN FULL

  • TypeScript interfaces include ALL fields from Go handler structs
  • No partial type definitions (e.g., Go has 10 fields, TypeScript has 10 fields)
  • Field names match exactly (snake_case from JSON tags)
  • Types map correctly (pgtype → TypeScript types)
  • Missing fields break type safety and can cause runtime errors

Example of Full Type Matching:

// Go handler (internal/handlers/collections.go)
type SectionData struct {
    ID          string     `json:"id"`
    IsSystem    bool       `json:"is_system"`        // Changed from Type string
    Title       string     `json:"title"`
    Description string     `json:"description"`
    Icon        string     `json:"icon"`
    Items       []BookInfo `json:"items"`
    ViewAllURL  string     `json:"view_all_url"`
    Priority    int        `json:"priority"`
}
// 8 fields total
// TypeScript (web/src/types/dashboard.d.ts)
// ✅ CORRECT - All 8 fields present
interface SectionData {
    id: string;
    is_system: boolean;      // Changed from type: string
    title: string;
    description: string;
    icon: string;
    items: BookInfo[];
    view_all_url: string;
    priority: number;
}

// ❌ WRONG - Missing fields (partial type, breaks type safety)
interface SectionData {
    id: string;
    is_system: boolean;
    title: string;
    items: BookInfo[];
    // Missing: description, icon, view_all_url, priority
}

// ❌ WRONG - Wrong field name and type
interface SectionData {
    id: string;
    type: string;             // WRONG: should be is_system: boolean
    title: string;
    // ... other fields
}

IMPORTANT DISTINCTIONS:

  • Acceptable: TypeScript .d.ts recreates handlers.SectionData (cross-language)
  • Unacceptable: Go templates.SectionData duplicates handlers.SectionData (in-language)

Verification:

# Compare field names across layers
# Database
rg "show_on_dashboard" database/schema/schema.sql

# Go struct (database)
rg "ShowOnDashboard" internal/database/models.go

# Handler type (enhanced)
rg "ShowOnDashboard|Icon|FormattedDate" internal/handlers/*.go

# Template (uses handler types directly - no Go duplication)
rg 'handlers\.' templates/*.templ

# TypeScript (matches handler JSON - acceptable cross-language duplication)
rg "show_on_dashboard" web/src/types/api.d.ts
rg "show_on_dashboard|icon" web/src/types/dashboard.d.ts

# CRITICAL: Check for duplicate Go types (should find none)
rg "type.*Data struct" templates/types.go | rg -v "PageData|UnsafeHTML"

# TypeScript types are OK (different language)
ls -la web/src/types/*.d.ts  # Should exist

# CRITICAL: Verify TypeScript has same number of fields as Go handler

# Count Go struct fields (example: SectionData)
rg "type SectionData struct" internal/handlers/*.go -A 30 | grep 'json:' | wc -l
# Output: 11 (for example)

# Count TypeScript interface fields
rg "interface SectionData" web/src/types/dashboard.d.ts -A 30 | rg '^\s+[a-z_]+:' | wc -l
# Output: Should also be 11 (matching Go struct)

# If counts don't match, TypeScript is missing fields (CRITICAL ISSUE)

# List all fields for manual comparison
# Go fields:
rg "type SectionData struct" internal/handlers/*.go -A 30 | grep 'json:' | sed 's/.*`json:"//; s/".*//'

# TypeScript fields:
rg "interface SectionData" web/src/types/dashboard.d.ts -A 30 | rg '^\s+[a-z_]+:' | sed 's/.*://; s/:.*//'

11. Accessibility Verification

11.1 Verify Keyboard Navigation

For dashboard carousel:

  • Tab key focuses book cards
  • Enter/Space on focused card opens book
  • Arrow keys navigate between cards
  • Focus visible indicators
  • No keyboard traps
  • Logical tab order

Verification:

# Check tabindex attributes
rg 'tabindex=' templates/

# Check aria labels
rg 'aria-label=' templates/

# Test in browser (manual)
# 1. Load dashboard
# 2. Press Tab repeatedly
# 3. Verify focus moves through books
# 4. Press Enter on focused book
# 5. Verify book opens

11.2 Verify Screen Reader Support

ARIA attributes:

  • Buttons have aria-label
  • Sections have semantic headings
  • Book cards have role="button"
  • Live regions for dynamic updates
  • Alt text on cover images

Verification:

# Check ARIA attributes
rg 'aria-' templates/

# Check image alt text
rg '<img' templates/ | rg 'alt='

# Test with screen reader (manual)
# macOS: VoiceOver
# Windows: NVDA

11.3 Verify Touch Gestures

Mobile/carousel:

  • Swipe gestures work on carousels
  • Tap to open book
  • Long press for options
  • Scroll with momentum
  • No accidental clicks

Verification:

# Check overflow behavior
rg 'overflow-x-auto' templates/

# Test on mobile device (manual)
# 1. Open dashboard on phone
# 2. Swipe carousel left/right
# 3. Tap book card
# 4. Verify smooth scrolling

12. SSR + TypeScript Hybrid Verification

12.1 Verify SSR Initial Load

Critical paths:

  • Dashboard loads with pre-populated SSR data (sections rendered by server)
  • All sections and books visible in initial HTML (view source to verify)
  • No client-side fetching on initial page load
  • Library selector options rendered server-side
  • Current library pre-selected in HTML

Test procedure:

  1. Open DevTools → Network tab
  2. Navigate to /dashboard?library_id=<id>
  3. Verify in HTML response:
    • Sections present in initial HTML (not added via JS)
    • Books present in initial HTML
    • Library selector has all options
  4. View page source (Ctrl+U) and verify:
    • Section HTML present in source
    • Book cards present in source

Verification:

# Check template has sections parameter (SSR)
rg "templ Dashboard.*sections" templates/dashboard.templ -A 5

# Verify frontend route passes data to template
rg "templates.Dashboard.*sections" internal/router/frontend.go -A 5

# Check for initial load fetching (should be NONE)
rg "fetch.*onload|DOMContentLoaded.*fetch" web/src/dashboard.ts
# Should return nothing - no fetch on initial load

12.2 Verify TypeScript Updates

Critical paths:

  • Library switching triggers JSON fetch
  • Loading indicator shows during fetch
  • Sections re-render after library switch
  • Settings save via API, then page reload
  • Error handling with toast notifications

Test procedure:

  1. Load dashboard (verify SSR data present)
  2. Change library selector
  3. Verify:
    • Loading spinner appears
    • Network tab shows /api/dashboard/sections?library_id=<new> request
    • Sections update without full page reload
    • URL updates with ?library_id=<new>
  4. Open settings, change items per section
  5. Verify:
    • API POST to /dashboard/settings
    • Success toast appears
    • Page reloads with new settings applied

Verification:

# Check TypeScript has switchLibrary function
rg "function switchLibrary|async switchLibrary" web/src/dashboard.ts -A 10

# Verify it fetches JSON
rg "fetch.*api/dashboard/sections" web/src/dashboard.ts

# Verify renderSections function exists
rg "function renderSections" web/src/dashboard.ts -A 10

# Check settings API call
rg "api.post.*settings|fetch.*settings" web/src/dashboard.ts

13. Performance Verification

13.1 Verify Database Query Performance

Index verification:

  • idx_dashboard_prefs_user_library exists
  • idx_collections_dashboard exists (partial index)
  • Queries use indexes (EXPLAIN ANALYZE)
  • No full table scans
  • Limit parameters respected

Verification:

# Check indexes
psql bookhoard -c "\di" | grep dashboard

# Explain queries
psql bookhoard -c "EXPLAIN ANALYZE SELECT * FROM user_dashboard_preferences WHERE user_id = '...' AND library_id = '...'"

# Check query plans for sections
# (simulate GetSectionItems queries)
psql bookhoard -c "EXPLAIN ANALYZE SELECT * FROM media_items WHERE ... ORDER BY created_at DESC LIMIT 20"

13.2 Verify Frontend Performance

Bundle size:

  • dashboard.js < 50 KB (unminified)
  • settings.js < 30 KB (unminified)
  • No duplicate dependencies
  • Code splitting by page
  • Lazy loading for images

Loading performance:

  • Initial page load < 2 seconds (3G)
  • Time to Interactive < 3 seconds
  • Lighthouse score > 90
  • No layout shifts
  • Smooth scrolling

Verification:

# Check bundle sizes
ls -lh web/static/dashboard.js
ls -lh web/static/settings.js

# Check for duplicate code
rg "function " web/src/*.ts | wc -l

# Test loading (manual)
# 1. Open Chrome DevTools → Lighthouse
# 2. Run audit
# 3. Check Performance score
# 4. Check Metrics (FCP, LCP, TTI)

13.3 Verify Image Optimization

Cover images:

  • Lazy loading enabled (loading="lazy")
  • Fallback placeholder
  • Error handling (onerror)
  • Aspect ratio reserved
  • No layout shift

Verification:

# Check lazy loading
rg 'loading="lazy"' templates/

# Check fallback images
rg 'onerror=' templates/ | grep placeholder

# Check aspect ratio
rg 'aspect-\[' templates/

14. Testing Verification

14.1 Verify Bruno Tests Exist

For dashboard endpoints:

  • bruno/dashboard/get-sections-success.bru exists
  • bruno/dashboard/get-sections-missing-library-id.bru exists
  • bruno/dashboard/get-sections-unauthorized.bru exists
  • bruno/dashboard/put-preferences-success.bru exists
  • bruno/dashboard/restore-system-collection-success.bru exists
  • bruno/dashboard/restore-system-collection-invalid-name.bru exists
  • Tests for:
    • No user (401)
    • Regular user (200)
    • Admin user (200)
    • Missing library_id (400)
    • Invalid library_id (400)
    • Limit parameter (default, min, max)
    • User preferences applied
  • Environment variables configured
  • JSON response validation

For collections preview endpoint:

  • bruno/dashboard/preview-collection-success.bru exists
  • bruno/dashboard/preview-collection-manual-selection.bru exists
  • bruno/dashboard/preview-collection-combined.bru exists
  • bruno/dashboard/preview-collection-invalid-library.bru exists
  • bruno/dashboard/preview-collection-unauthorized.bru exists
  • Tests verify:
    • Filter rules evaluate correctly
    • Manual book selection works
    • Combined filters + manual selection
    • Invalid library_id returns 400
    • Unauthorized request returns 401
    • Response has items array (not books)
    • Response uses media_item_id field

Verification:

# Check dashboard test files
ls -la bruno/dashboard/

# Verify collections preview tests exist
ls -la bruno/dashboard/preview-collection-*.bru

# Run tests
cd bruno/dashboard && bru run --env local

# Verify test coverage
rg "test|assert" bruno/dashboard/*.bru

# Verify response field names
rg "media_item_id" bruno/dashboard/preview-collection-*.bru

14.2 Verify Manual Testing Checklist

Critical user flows:

  • View dashboard (SSR data loaded)
  • Switch library (HTMX update)
  • Scroll carousel (left/right buttons)
  • Open book (click card)
  • Customize dashboard (settings modal)
  • Hide/show sections
  • Reorder sections
  • Change items per section
  • Update profile settings
  • Change theme
  • Save preferences

Edge cases:

  • Empty sections (no books)
  • All sections hidden
  • Very long titles (truncate)
  • Missing cover images (placeholder)
  • Network errors (toast shown)
  • Invalid library_id (error handled)
  • Unauthorized (redirect to login)

Verification:

# Create test plan document
cat > TESTING_CHECKLIST.md <<EOF
# Dashboard Testing Checklist

## Smoke Tests
- [ ] Dashboard loads
- [ ] Sections render
- [ ] Books display

## Functionality Tests
- [ ] Library switching
- [ ] Carousel scrolling
- [ ] Book opening
- [ ] Settings modal

## Edge Cases
- [ ] Empty sections
- [ ] Missing covers
- [ ] Network errors

## Accessibility Tests
- [ ] Keyboard navigation
- [ ] Screen reader
- [ ] Touch gestures

## Performance Tests
- [ ] Page load time
- [ ] Lighthouse score
- [ ] Bundle size
EOF

14.3 Verify Browser Compatibility

Test in browsers:

  • Chrome/Edge (Chromium)
  • Firefox
  • Safari (if available)
  • Mobile browsers (iOS Safari, Chrome Android)

Features to test:

  • CSS Grid/Flexbox
  • CSS variables (theme)
  • HTMX attributes
  • Event delegation
  • Touch events
  • Smooth scrolling

Verification:

# Check for browser-specific features
rg "webkit|moz|ms" web/src/dashboard.ts
# Should be minimal (use standard APIs)

# Check CSS compatibility
rg "backdrop-filter|aspect-ratio|snap" templates/
# Verify fallbacks if needed

14.4 Verify Backend Tests Exist

Unit tests for dashboard service:

  • internal/services/dashboard_service_test.go exists
  • Tests for:
    • TestDashboardService_GetSystemCollectionsForDashboard - System collections
    • TestDashboardService_GetUserCollectionsForDashboard - User collections
    • TestDashboardService_AutoAssignRules - Rule evaluation
    • TestDashboardService_ExcludedItems - Excluded items filtering
    • Uses testify/assert and testify/require
    • Tests cover edge cases (empty arrays, nil values, duplicates)

Unit tests for dashboard handler:

  • internal/handlers/dashboard_test.go exists
  • Tests for:
    • TestBuildSectionsFromDB_ConvertsDatabaseTypes - Type conversion
    • TestBuildSectionsFromDB_FilterHiddenCollections - Hidden filtering
    • TestBuildSectionsFromDB_ReorderCollections - Custom ordering
    • TestBuildSectionsFromDB_SortByPriority - Priority sorting
    • Validates pgtype field conversion to handler types

Integration tests with test_helpers:

  • internal/handlers/dashboard_integration_test.go exists
  • Uses test_helpers.TestSuite for database setup/teardown
  • Tests for:
    • TestGetSections_EndToEndFlow - Full dashboard sections API
    • TestGetSections_WithUserCollections - User + system collections
    • TestRestoreSystemCollection - System collection restore
    • TestRestoreSystemCollection_InvalidName - Error handling
    • Creates test fixtures (users, libraries, media items)
    • Tests reading progress (in progress, completed, unread)
    • Tests manual + auto-matched items merging
    • Tests excluded items filtering

Integration tests for collections preview:

  • internal/handlers/collections_preview_test.go exists
  • Uses test_helpers.TestSuite for database setup/teardown
  • Tests for:
    • TestPreviewCollection_FilterRules - Filter rule evaluation
    • TestPreviewCollection_ManualBookSelection - Manual selection
    • TestPreviewCollection_CombinedFiltersAndManual - Combined approach
    • TestPreviewCollection_LimitRespected - Limit enforcement
    • TestPreviewCollection_InvalidLibraryID - Error handling
    • Validates 13+ filter fields work correctly
    • Validates deduplication of items

Verification:

# Check test files exist
ls -la internal/services/dashboard_service_test.go
ls -la internal/handlers/dashboard_test.go
ls -la internal/handlers/dashboard_integration_test.go
ls -la internal/handlers/collections_preview_test.go

# Run tests
go test ./internal/services/dashboard_service_test.go -v
go test ./internal/handlers/dashboard_test.go -v
go test ./internal/handlers/dashboard_integration_test.go -v
go test ./internal/handlers/collections_preview_test.go -v

# Run with coverage
go test ./internal/services/... ./internal/handlers/... -coverprofile=coverage.out
go tool cover -html=coverage.out

# Verify test helpers usage
rg "test_helpers.TestSuite" internal/handlers/dashboard_integration_test.go
rg "test_helpers.TestSuite" internal/handlers/collections_preview_test.go

# Verify 13+ filter fields tested
rg "genre|author|series|progress|rating|date_added|last_read|publisher|language|format|tags|narrators" internal/handlers/collections_preview_test.go
ls -la internal/handlers/dashboard_integration_test.go

# Run tests
go test ./internal/services/dashboard_service_test.go -v
go test ./internal/handlers/dashboard_handler_test.go -v
go test ./internal/handlers/dashboard_integration_test.go -v

# Run with coverage
go test ./internal/... -cover -coverprofile=coverage.out
go tool cover -html=coverage.out

# Verify test helpers usage
rg "test_helpers.TestSuite" internal/handlers/dashboard_integration_test.go
rg "CreateTestUser|CreateTestLibrary|CreateTestMediaItem" internal/handlers/dashboard_integration_test.go

Test coverage requirements:

  • Unit tests for all service methods (filterHiddenSections, reorderSections)
  • Unit tests for all helper functions
  • Integration tests for all API endpoints
  • Integration tests use test_helpers
  • Coverage > 80% for new code

15. Cross-Reference Verification

15.1 Verify Database → Go Types

Schema.sql → models.go:

  • Column names match
  • Types match (UUID, TEXT[], INT, TIMESTAMP, etc.)
  • NULL constraints match (pgtype vs required)
  • Default values match
  • Foreign keys match

Verification:

# Compare schema with generated types
# Schema
rg "user_dashboard_preferences" database/schema/schema.sql -A 15

# Generated type
rg "type UserDashboardPreferences struct" internal/database/models.go -A 15

# Check field matching
rg "pgtype\.(UUID|Text|Int4|TextArray)" internal/database/models.go

15.2 Verify Go → Template Types

Handlers → Templates:

  • Handler calls service
  • Service returns database types
  • Frontend router passes handler types to template
  • Template uses handler types directly (no conversion)
  • No type mismatches
  • NO templates.SectionData created (use handlers.SectionData if needed)

CRITICAL GUIDELINE:

  • Templates import handlers package
  • Templates use handlers.CollectionData, handlers.BookInfo directly
  • Handler types enhanced with template-specific fields (Icon, etc.)
  • No conversion helper functions
  • No parallel type systems

Verification:

# Check handler to template flow
# Handler
rg "GetSectionItems" internal/router/frontend.go -B 5 -A 20

# Template uses handler types (NOT template types)
rg 'handlers\.(CollectionData|BookInfo|SectionData)' templates/*.templ

# CRITICAL: Check for duplicate types in templates (should be none)
rg "type.*Data struct" templates/types.go | grep -v "PageData|UnsafeHTML"

# Check for conversion functions (should be none)
rg "func.*ToTemplate|func.*Convert" internal/router/frontend.go

15.3 Verify Handler → TypeScript Types

Handler JSON → TypeScript (.d.ts):

  • Handler types have JSON tags (snake_case)
  • TypeScript interfaces recreate handler JSON structure
  • Field names use snake_case in both
  • Types match (pgtype correctly mapped to TypeScript)
  • No missing fields
  • Template-specific fields in handler types reflected in TypeScript
  • ACCEPTABLE: TypeScript duplicates handler types (cross-language, necessary)

pgtype Mapping Verification:

// Go handler
type BookInfo struct {
    MediaItemID  pgtype.UUID      `json:"media_item_id"`
    Title        pgtype.Text      `json:"title"`
    CoverImage   pgtype.Text      `json:"cover_image"`
    IsFeatured   pgtype.Bool      `json:"is_featured"`
    Tags         pgtype.TextArray `json:"tags"`
}
// TypeScript .d.ts (acceptable recreation)
// Source: handlers.BookInfo in collections.go
interface BookInfo {
    media_item_id: string;        // string field in Go
    title: string;                // string field in Go
    author: string;               // string field in Go
    cover_image_path: string;     // string field in Go
}

Verification:

# Handler type with JSON tags (in collections.go)
rg "type BookInfo struct" internal/handlers/collections.go -A 10

# TypeScript type matches handler JSON
rg "interface BookInfo" web/src/types/dashboard.d.ts -A 10

# Compare field names (manual verification)
# Handler (collections.go): json:"media_item_id"
# TypeScript: media_item_id: string

# Verify correct field names (NOT "id")
rg "json:\"id\"" internal/handlers/collections.go | grep BookInfo -A 5
# Should return nothing - BookInfo uses MediaItemID

# TypeScript should use media_item_id (not id)
rg "id: string" web/src/types/dashboard.d.ts | grep -i bookinfo
# Should return nothing for BookInfo - uses media_item_id

# CRITICAL: No Go template types in TypeScript (this is wrong)
rg "templates\." web/src/types/dashboard.d.ts
# Should return nothing - TypeScript references handler JSON, not Go template types

# TypeScript types are OK (acceptable cross-language duplication)
ls -la web/src/types/*.d.ts

15.4 Verify TypeScript → API Responses

API → TypeScript:

  • Handler returns JSON
  • JSON structure matches TypeScript interface IN FULL
  • All fields from Go handler present in TypeScript
  • Field names match (snake_case)
  • Types match (pgtype correctly mapped)
  • Null handling consistent (pgtype.Text → string | undefined)
  • No missing fields (complete type safety)

Verification:

# API response structure
rg "buildJSONSections" internal/handlers/dashboard.go -A 30

# TypeScript interface
rg "interface (SectionData|BookCardData)" web/src/types/dashboard.d.ts

# Test API response and compare with TypeScript
curl -H "Authorization: Bearer $TOKEN" \
  "http://localhost:8080/api/dashboard/sections?library_id=..." | jq '.sections[0]'

# Compare API response fields with TypeScript interface
# API response example:
# {
#   "id": "continue-reading",
#   "type": "system",
#   "title": "Continue Reading",
#   "description": "Books you're currently reading",
#   "icon": "📖",
#   "items": [...],
#   "view_all_url": "/section/continue-reading",
#   "priority": 1
# }

# TypeScript interface MUST have all 8 fields above
interface SectionData {
    id: string;
    is_system: boolean;     // true for system collections, false for user collections
    title: string;
    description: string;
    icon: string;
    items: BookInfo[];
    view_all_url: string;
    priority: number;
    // Missing any of these = CRITICAL TYPE SAFETY ISSUE
}

# TypeScript interface MUST have all 4 fields for BookInfo
interface BookInfo {
    media_item_id: string;  // NOT "id"
    title: string;
    author: string;
    cover_image_path: string;
    // Missing any of these = CRITICAL TYPE SAFETY ISSUE
}

# CRITICAL: Count fields in API response vs TypeScript
# Count API response fields
curl -s -H "Authorization: Bearer $TOKEN" \
  "http://localhost:8080/api/dashboard/sections?library_id=..." | jq '.sections[0] | keys | length'

# Count TypeScript interface fields
rg "interface SectionData" web/src/types/dashboard.d.ts -A 30 | rg '^\s+[a-z_]+:' | wc -l

# Both counts MUST match (example: 9 = 9)

16. Architecture Compliance Verification

16.1 Verify Project Guidelines Adherence

Frontend standards:

  • TailwindCSS classes only (no custom CSS)
  • TypeScript in web/src/ (no inline JavaScript)
  • Procedural/imperative style (no OOP)
  • SSR for initial data
  • Progressive enhancement
  • HTMX for updates
  • Event delegation pattern
  • API client usage
  • Toast notification usage
  • NO duplicate type definitions (use handler types directly)
  • Handler types enhanced with template fields (not parallel types)
  • NO conversion helper functions (use handler types directly)

Backend standards:

  • All business logic in services
  • Handlers use service layer
  • No direct database access from handlers
  • Atomic schema changes
  • No migration files
  • Bruno tests for API endpoints

Code organization:

  • Handler types defined in internal/handlers/*.go
  • Templates import handlers package
  • Templates use handler types directly
  • Template-only types for UI concerns only (PageData, UnsafeHTML)

Verification:

# Check for custom CSS (should be none)
rg "<style>" templates/dashboard.templ

# Check for inline JS (should be none)
rg "<script>" templates/dashboard.templ | grep -v "src="

# Check for OOP (should be none)
rg "class |this\." web/src/dashboard.ts

# Verify TailwindCSS usage
rg 'class="[^"]*"' templates/dashboard.templ | head -20

# CRITICAL: Check for duplicate type definitions
rg "type.*Data struct" templates/types.go
# Should have NO dashboard data types - use handler types

# Verify templates use handler types
rg 'handlers\.' templates/*.templ

# Check for conversion helpers (should be none)
rg "func.*ToTemplate|func.*Convert.*To" templates/*.go
# Should return nothing - use handler types directly

16.2 Verify Service Layer Pattern

All business logic in services:

  • Handlers don't query database directly
  • Service methods are reusable
  • Same service used by SSR and API
  • Service has no HTTP concerns
  • Service returns raw data
  • Handler formats for templates/API

Verification:

# Check handler for direct DB access (should be none)
rg "Queries\." internal/handlers/dashboard.go

# Check service usage
rg "dashboardService\." internal/router/frontend.go
rg "dashboardService\." internal/handlers/dashboard.go

16.3 Verify Single Source of Truth

Service layer is source of truth:

  • SSR uses DashboardService
  • API handler uses DashboardService
  • No duplicate logic
  • Same data for all clients

Verification:

# Find all service usage
rg "DashboardService" internal/ -r

# Verify no duplicate queries in handlers
rg "SELECT.*FROM" internal/handlers/dashboard.go
# Should return nothing

17. Contradiction Detection

17.1 Check for Internal Contradictions

Search for conflicting statements:

  • Timeline estimates consistent (3-4 days, not 2 weeks)
  • Architecture description consistent throughout
  • Type definitions match in all sections
  • Code examples follow guidelines
  • Phase dependencies are acyclic
  • No "do X" in one section, "don't do X" in another

CRITICAL: Type Definition Contradictions

  • NO templates/types.go types that duplicate handler types in Go
  • Plan does NOT create templates.SectionData or templates.BookCardData in Go
  • Plan DOES use handler types directly or enhance them
  • No conversion helper functions mentioned for Go
  • Handler types are source of truth in Go
  • ACCEPTABLE: TypeScript .d.ts files recreate types (cross-language, necessary)
  • Plan distinguishes between Go duplication (wrong) and TypeScript duplication (acceptable)
  • CRITICAL: TypeScript types must include ALL fields from Go handlers (no partial types)
  • Plan doesn't mention TypeScript types with "optional" or "partial" fields
  • Field counts match between Go structs and TypeScript interfaces
  • No "TypeScript has subset of fields for UI only" (violates type safety)

Common contradictions:

  • "Procedural style only" but examples show classes
  • "No inline JavaScript" but templates have <script> blocks
  • "SSR first" but initial load uses AJAX
  • "Progressive enhancement" but forms require JavaScript
  • "3-4 days" but tasks estimate 10+ days
  • "No duplicate types" but plan creates templates.SectionData
  • "Use handler types" but plan has conversion functions

Verification:

# Search for class usage
rg "class " CAROUSEL_DASHBOARD_PLAN.md
# Should be in examples of what NOT to do

# Search for timeline
rg "day|days|week|weeks" CAROUSEL_DASHBOARD_PLAN.md
# Verify consistency

# Check for inline JS mentions
rg "<script>" CAROUSEL_DASHBOARD_PLAN.md
# Should only mention external script tags

# CRITICAL: Check for duplicate type creation
rg "templates/types.go|templates\.SectionData|templates\.BookCardData" CAROUSEL_DASHBOARD_PLAN.md
# Should find nothing - use handler types instead

# Check for enhancement pattern (correct)
rg "Enhance.*handler|template-specific fields" CAROUSEL_DASHBOARD_PLAN.md
# Should mention enhancing handler types

# Check for conversion functions (wrong)
rg "convert|ToTemplate|MapTo" CAROUSEL_DASHBOARD_PLAN.md -i
# Should be minimal or none for type conversions

# CRITICAL: Check for partial TypeScript types (violates guidelines)
rg "partial|subset|fields.*needed|UI.*only" CAROUSEL_DASHBOARD_PLAN.md -i
# Should not mention TypeScript having fewer fields than Go

# Check if plan documents full type matching
rg "all fields|complete|full.*match|every field" CAROUSEL_DASHBOARD_PLAN.md -i
# Should mention TypeScript matching Go types completely

17.2 Check for Contradictions with TypeScript Plan

Carousel Dashboard assumes TypeScript Conversion completed:

  • No conflicts with TypeScript architecture
  • Uses same event delegation pattern
  • Uses same shared modules
  • Follows same procedural style
  • No duplicate type definitions

Verification:

# Compare event delegation patterns
rg "data-action" TYPESCRIPT_CONVERSION_PLAN.md
rg "data-action" CAROUSEL_DASHBOARD_PLAN.md
# Should be consistent

# Compare module structure
rg "web/src/" TYPESCRIPT_CONVERSION_PLAN.md
rg "web/src/" CAROUSEL_DASHBOARD_PLAN.md
# Carousel should use existing modules

# Check for duplicate type definitions
rg "interface.*Data" TYPESCRIPT_CONVERSION_PLAN.md
rg "interface.*Data" CAROUSEL_DASHBOARD_PLAN.md
# Carousel types should be new, not duplicates

17.3 Check for Contradictions with Codebase

Verify plan matches existing patterns:

  • Router pattern matches existing routes
  • Service pattern matches existing services
  • Template pattern matches existing templates
  • Handler pattern matches existing handlers
  • TypeScript pattern matches existing TS

Verification:

# Compare with existing router
rg "func register" internal/router/*.go
# Carousel should follow same pattern

# Compare with existing service
rg "type.*Service struct" internal/services/*.go
# Carousel should follow same pattern

# Compare with existing handler
rg "type.*Handler struct" internal/handlers/*.go
# Carousel should follow same pattern

# Compare with existing TypeScript
rg "^function " web/src/*.ts
# Carousel should follow same pattern

18. Realism Verification

18.1 Verify Timeline Estimates

Phase duration estimates:

  • Phase 1 (Schema): 2-3 hours
  • Phase 2 (Service): 3-4 hours
  • Phase 3 (Queries): 1-2 hours
  • Phase 4 (Handler): 1-2 hours
  • Phase 5 (Bruno Tests): 1 hour
  • Phase 6 (TypeScript Types): 30 min
  • Phase 7 (Router): 30 min
  • Phase 8 (SSR Routes): 1-2 hours
  • Phase 9 (Template): 2 hours
  • Phase 10 (TypeScript): 2-3 hours
  • Phase 11 (Unit Tests): 3-4 hours
  • Phase 12 (Documentation): 2-3 hours

Total: 20-28 hours = 3-4 days

Verification:

# Sum phase durations
# (Manual calculation from plan)

# Check for missing tasks
rg "TODO|TBD|FIXME" CAROUSEL_DASHBOARD_PLAN.md
# Should return nothing

18.2 Verify Effort Estimates

For each phase:

  • Line counts are accurate (if mentioned)
  • File counts are accurate
  • Complexity matches duration
  • No phase exceeds 1 day (except maybe templates)
  • Parallel work is possible where stated

Verification:

# Check for unrealistic estimates
# (Manual review of each phase)

18.3 Verify Technical Feasibility

Check for over-ambitious goals:

  • No entirely new architecture (uses existing patterns)
  • No unproven technologies (uses Go, templ, HTMX, TailwindCSS)
  • No breaking changes to existing systems
  • Rollback is possible (delete files, revert schema)
  • Testing is feasible within timeline
  • No blocking dependencies

Red flags:

  • "Need to refactor entire X"
  • "Rewrite Y from scratch"
  • "New framework Z"
  • "Breaking change to W"

Verification:

# Search for red flags
rg "refactor|rewrite|breaking" CAROUSEL_DASHBOARD_PLAN.md -i

# Should only mention positive changes

19. Bruno Tests Verification

19.1 Verify Bruno Test Directory Created

Required files in bruno/dashboard/:

  • get-sections-success.bru - Happy path test
  • get-sections-missing-library-id.bru - Missing required parameter
  • get-sections-invalid-library-id.bru - Invalid UUID format
  • get-sections-unauthorized.bru - No authentication
  • put-preferences-success.bru - Update preferences
  • put-preferences-unauthorized.bru - No authentication
  • restore-system-collection-success.bru - Restore collection
  • restore-system-collection-invalid-name.bru - Invalid collection name
  • restore-system-collection-unauthorized.bru - No authentication

Verification:

# Check Bruno test directory exists
ls -la bruno/dashboard/ || echo "Directory does not exist yet"

# Verify test files exist (after Phase 12 of plan)
ls -la bruno/dashboard/*.bru 2>/dev/null | wc -l
# Should return at least 9 after Phase 12

# Run Bruno tests
cd bruno/dashboard && bru run --env local

19.1b Verify Collections Bruno Tests Created

Required files in bruno/collections/ (NEW directory):

  • create-collection-with-manual-books.bru - Create collection with manual books
  • create-collection-too-many-books.bru - Validation test (max 50 books)
  • create-collection-invalid-book-id.bru - Invalid UUID handling
  • create-collection-rules-only.bru - Auto-assign rules only
  • create-collection-unauthorized.bru - No authentication

Verification:

# Check Bruno collections directory exists
ls -la bruno/collections/ || echo "Directory does not exist yet"

# Verify test files exist (after Phase 12.5 of plan)
ls -la bruno/collections/*.bru 2>/dev/null | wc -l
# Should return at least 5 after Phase 12.5

# Run Bruno tests for collections
cd bruno/collections && bru run --env local

Test coverage verification:

  • manual_book_ids field included in request body
  • Validation test sends 51+ book IDs, expects 400
  • Invalid UUID test verifies graceful handling
  • All tests verify 201 status on success
  • Unauthorized tests verify 401 status

19.2 Verify Bruno Test Response Structure

For get-sections-success.bru:

  • Response includes is_system field (boolean)
  • Response does NOT include type field (old field name)
  • Books have media_item_id field (not id)
  • Response structure matches Go handler JSON tags
  • Assertions verify correct field types

For restore-system-collection-success.bru:

  • Request body uses collection_name parameter
  • Valid collection names: continue-reading, recently-added, recently-read, not-started
  • Invalid names return 400 status
  • Success returns 200 status with message

Verification:

# Check Bruno test files for correct field names
rg "is_system" bruno/dashboard/*.bru
rg "media_item_id" bruno/dashboard/*.bru
rg "hidden_collections|collection_order" bruno/dashboard/*.bru

# Verify no old field names
rg "\"type\":\s*\"smart\"|\"type\":\s*\"collection\"" bruno/dashboard/*.bru
# Should return nothing

# Verify no old id field (except media_item_id which is correct)
rg "\"id\":\s*\"[^\"]*\"" bruno/dashboard/*.bru | grep -v "media_item_id"
# Should return nothing

# Check collection_name in restore tests
rg "collection_name" bruno/dashboard/restore-system-collection-*.bru

20. Documentation Verification

19.1 Verify Developer API Documentation

File: docs/developer/api/dashboard.md:

  • Updated to show is_system: boolean (not type: string)
  • Updated to show 4 system collections (removed "In Progress")
  • Books use media_item_id field (not id)
  • Field names updated: hidden_collections, collection_order
  • Restore System Collection endpoint documented
  • Response examples match Bruno tests
  • Error cases documented
  • Table of system collections shows correct 4 entries

Verification:

# Check API documentation has correct field names
rg "is_system.*boolean" docs/developer/api/dashboard.md
rg "media_item_id" docs/developer/api/dashboard.md
rg "hidden_collections|collection_order" docs/developer/api/dashboard.md

# Verify no old field names
rg "\"type\":\s*\"smart\"" docs/developer/api/dashboard.md
# Should return nothing

# Verify only 4 system collections (no "In Progress")
rg "In Progress" docs/developer/api/dashboard.md
# Should return nothing

# Count system collections mentioned
rg "continue-reading|recently-added|recently-read|not-started" docs/developer/api/dashboard.md | wc -l
# Should return at least 4

19.1b Verify Collections API Documentation

File: docs/developer/api/collections/create_collection.md (UPDATE existing):

  • manual_book_ids field added to request body documentation
  • Field type documented as array of strings (book UUIDs)
  • Field marked as optional
  • Validation limit documented (max 50 items)
  • Error case documented (400 if > 50 items)
  • Example request shows manual_book_ids usage
  • Notes explain combining with auto_assign_rules
  • Notes explain invalid book IDs are skipped gracefully

Documentation requirements:

  • Example shows both auto_assign_rules AND manual_book_ids
  • Error handling explained for invalid book IDs
  • Validation rule clearly stated (max 50)
  • Backward compatibility noted (field is optional)

Verification:

# Check manual_book_ids in documentation
rg "manual_book_ids" docs/developer/api/collections/create_collection.md

# Verify validation is documented
rg "max.*50|50.*items" docs/developer/api/collections/create_collection.md -i

# Check example request
rg "manual_book_ids.*\[" docs/developer/api/collections/create_collection.md -A 5

# Verify error cases documented
rg "400.*invalid|validation" docs/developer/api/collections/create_collection.md -i

19.2 Verify User Documentation

File: docs/user/dashboard.md:

  • Lists only 4 smart sections (no "In Progress")
  • Explains system collections can be restored to defaults
  • Customization instructions mention "System" badge
  • Uses "collection" terminology consistently
  • No references to "smart sections" concept
  • Keyboard navigation documented
  • Touch gestures documented

Verification:

# Check user documentation
rg "In Progress" docs/user/dashboard.md
# Should return nothing

# Verify 4 sections listed
rg "Continue Reading|Recently Added|Recently Read|Not Started" docs/user/dashboard.md
# Should return all 4

# Check for collection terminology
rg "collection" docs/user/dashboard.md | wc -l
# Should appear multiple times

# Verify system collection restore mentioned
rg "restore|System.*badge" docs/user/dashboard.md -i
# Should mention restoration feature

# Verify no old smart sections references
rg "smart section" docs/user/dashboard.md -i
# Should return nothing

19.3 Verify Contributing Documentation

File: docs/contributing/development.md:

  • dashboard.go added to handlers list
  • dashboard_service.go added to services list
  • Handler types mentioned use handlers.SectionData and handlers.BookInfo
  • Notes about shared types in collections.go
  • No duplicate type definitions mentioned

Verification:

# Check development guide
rg "dashboard\.go" docs/contributing/development.md
rg "dashboard_service\.go" docs/contributing/development.md

# Verify handler types mentioned correctly
rg "handlers\.(SectionData|BookInfo)" docs/contributing/development.md

# Verify collections.go mentioned as shared types
rg "collections\.go.*SectionData|collections\.go.*BookInfo" docs/contributing/development.md

19.4 Verify API Reference

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

  • Dashboard section added to index
  • Links to ./dashboard.md documentation
  • Endpoints listed in correct section
  • All three endpoints mentioned:
    • Get Dashboard Sections
    • Update Dashboard Preferences
    • Restore System Collection

Verification:

# Check API reference index
rg "Dashboard" docs/developer/api/api-reference.md -A 5
rg "\./dashboard\.md" docs/developer/api/api-reference.md

# Verify all three endpoints mentioned
rg "Get Dashboard Sections|Update Dashboard Preferences|Restore System Collection" docs/developer/api/api-reference.md

19.5 Verify Custom Section Builder Documentation

File: docs/developer/api/custom-section-builder.md:

  • File exists or is planned
  • Preview Collection endpoint documented
  • Create Custom Section endpoint documented
  • 13+ filter fields documented with operators
  • Request/response examples provided
  • Filter rule structure explained
  • Manual book selection explained
  • Field types (text, number, date, select) documented
  • Response format matches Bruno tests

Verification:

# Check custom section builder documentation
ls -la docs/developer/api/custom-section-builder.md

# Verify filter fields documented
rg "title|author|genre|series|progress|rating|date_added|last_read|publisher|language|format|tags|narrators" docs/developer/api/custom-section-builder.md | wc -l
# Should be 13 or more

# Verify preview endpoint documented
rg "Preview Collection|POST.*preview" docs/developer/api/custom-section-builder.md

# Verify operators documented
rg "equals|contains|greater_than|less_than|is_set|between" docs/developer/api/custom-section-builder.md

# Verify response format
rg "media_item_id" docs/developer/api/custom-section-builder.md

File: docs/user/dashboard.md:

  • Custom Sections section added or planned
  • Step-by-step instructions for creating custom sections
  • Examples of filter rules provided
  • 13+ filter fields listed with descriptions
  • Manual book selection explained
  • Preview functionality explained
  • Example custom sections provided

Verification:

# Check user documentation has custom sections
rg "Custom Section|custom section" docs/user/dashboard.md -i

# Verify filter fields listed for users
rg "genre|author|series|progress|rating" docs/user/dashboard.md | wc -l
# Should mention several fields

# Verify examples provided
rg "example|For example|e\.g\." docs/user/dashboard.md -A 2 | rg "Sci-Fi|Fiction"

19.6 Verify Operations Documentation

File: docs/operations/operations.md (if exists):

  • Database recreation process documented
  • Schema change warnings included
  • System collection restoration process documented
  • Troubleshooting guide updated if needed

Verification:

# Check operations docs for dashboard-related content
rg "dashboard|system collection|schema.*recreate" docs/operations/operations.md -i

# Check if documentation exists
ls -la docs/operations/operations.md || echo "File may not exist yet"

21. Type Definition Documentation

20.1 Verify Type Definition Documentation

For each type in web/src/types/dashboard.d.ts:

  • Comment explains purpose
  • Comments reference source (Go handler file)
  • Comments reference Go struct name
  • All fields documented (not just some)
  • Fields have inline comments if purpose unclear
  • Complex types have usage examples
  • Document field count (e.g., "// 11 fields from handlers.SectionData")

Example:

// web/src/types/dashboard.d.ts

// Matches handlers.SectionData from internal/handlers/collections.go
// JSON response from /api/dashboard/sections
// All 8 fields from Go struct included
export interface SectionData {
    id: string;                       // Section identifier
    is_system: boolean;               // true for system collections, false for user collections
    title: string;                    // Section display title
    description: string;              // Section description
    icon: string;                     // Section icon (emoji)
    items: BookInfo[];                // Books in this section
    view_all_url: string;             // Link to view all items
    priority: number;                 // Display order priority
}

// Matches handlers.BookInfo from internal/handlers/collections.go
// All 4 fields from Go struct included
export interface BookInfo {
    media_item_id: string;            // Book identifier (NOT "id")
    title: string;                    // Book title
    author: string;                   // Book author
    cover_image_path: string;         // Path to cover image
}

For Go handler types (internal/handlers/*.go):

  • All struct fields have JSON tags
  • Comments explain purpose if not obvious
  • Exported types have package-level documentation
  • pgtype fields documented if behavior is unclear

Verification:

# Check TypeScript type documentation
cat web/src/types/dashboard.d.ts | rg "//"

# Verify field count mentioned in comments
rg "All.*fields included|fields from" web/src/types/dashboard.d.ts

# Check Go handler documentation
rg "type.*struct" internal/handlers/*.go -B 5 | rg "//"

# Verify all Go fields have JSON tags
rg "type.*struct" internal/handlers/*.go -A 30 | grep -v 'json:"'
# Should return nothing (all fields should have json tags)

Verification:

# Check for comments
rg "// " templates/types.go | rg -A 5 "SectionData|BookCardData"

# Check TypeScript comments
rg "// " web/src/types/dashboard.d.ts

19.2 Verify Code Example Accuracy

For each code example in plan:

  • Code compiles/runs without errors
  • Imports are correct
  • Type annotations are accurate
  • Variable names match plan's conventions
  • No syntax errors

Test by:

  • Copying example to actual file
  • Running go build or npm run build:ts
  • Checking for compilation errors

Verification:

# Extract Go code examples and test
# (Manual testing)

# Extract TypeScript code examples and test
# (Manual testing)

19.3 Verify Template Examples

For each template example:

  • Valid Go template syntax (templ)
  • Correct handler type references
  • Script tags use correct paths
  • No inline JavaScript
  • HTMX attributes are correct
  • TailwindCSS classes are valid

Verification:

# Check template syntax
rg "templ " templates/
# Should use `templ` keyword

# Check HTMX attributes
rg "hx-" templates/dashboard.templ
# Should be valid HTMX attributes

# Check TailwindCSS classes
rg "class=\"" templates/dashboard.templ | head -10
# Should be valid Tailwind classes

22. Missing Information Detection

20.1 Check for Unaddressed Features

Features mentioned but not implemented:

  • All dashboard sections implemented
  • All API endpoints implemented
  • All template components implemented
  • All TypeScript modules implemented
  • All settings options implemented

Verification:

# Find features mentioned
rg "Section|Carousel|Settings|Modal" CAROUSEL_DASHBOARD_PLAN.md

# Check if all have implementation
rg "Phase.*:" CAROUSEL_DASHBOARD_PLAN.md
# Verify all features covered in phases

20.2 Check for Missing API Endpoints

For each operation:

  • API endpoint exists
  • Endpoint is registered
  • Handler implements endpoint
  • Bruno test exists
  • Type definition matches

Find all API calls:

# Find fetch calls in plan
rg "fetch\(|api\.(get|post|put|delete)" CAROUSEL_DASHBOARD_PLAN.md

# Verify endpoints exist
rg "GET|POST|PUT|DELETE" internal/router/dashboard.go

20.3 Check for Missing Build Steps

Verify plan includes:

  • Database schema recreation instructions
  • sqlc generate command
  • Go build command
  • TypeScript compilation command
  • Template generation command
  • Docker integration

Check:

# Find build commands
rg "sqlc generate|go build|templ generate|npm run build:ts" CAROUSEL_DASHBOARD_PLAN.md

Summary Checklist

Before approving the Carousel dashboard plan, verify:

Critical (Must Pass)

  • TypeScript Conversion Plan completed first
  • Database schema changes are atomic
  • No migration files (direct schema.sql modification)
  • All business logic in service layer
  • Procedural/imperative style (no OOP)
  • SSR for initial data
  • Progressive enhancement maintained
  • Event delegation pattern used
  • TailwindCSS only (no custom CSS)
  • NO duplicate Go types (use handlers.* types, not templates.* types)
  • Handler types enhanced with template fields (not parallel Go type systems)
  • NO Go conversion helper functions (templates use handlers.* types directly)
  • TypeScript .d.ts types acceptable (necessary due to pgtype, cross-language)
  • TypeScript interfaces match Go handler types IN FULL (all fields, no partial types)
  • Field count matches (Go struct has N fields = TypeScript has N fields)
  • pgtype mappings correct (Text→string|undefined, UUID→string, Timestamp→string, etc.)
  • API endpoints match TypeScript interfaces
  • Bruno tests exist for all endpoints
  • Database indexes created
  • No breaking changes to existing systems

Important (Should Pass)

  • Timeline estimates are realistic (3-4 days)
  • Code examples are accurate
  • Template examples compile
  • TypeScript modules compile
  • Accessibility attributes present
  • Keyboard navigation works
  • Touch gestures work
  • Performance is acceptable (< 2s load time)
  • Bundle sizes are reasonable (< 50 KB)
  • Browser compatibility verified
  • No internal contradictions
  • No contradictions with TypeScript plan
  • No contradictions with codebase
  • Documentation is clear
  • Rollback strategy is defined

Nice to Have

  • Common pitfalls documented
  • Verification commands provided
  • Testing checklist comprehensive
  • Examples follow guidelines
  • Plan is easy to follow
  • Success criteria are measurable

Usage Instructions

  1. Before Starting Review: Read the entire CAROUSEL_DASHBOARD_PLAN.md
  2. During Review: Go through each section of this checklist systematically
  3. For Each Item: Run the provided verification commands
  4. Document Findings: Note any issues found with file/line references
  5. Categorize Issues: Mark as Critical, Important, or Nice to Have
  6. Verify Fixes: After fixing issues, re-run relevant checklist sections

Common Issues Found

  1. Duplicate Go Types: Creating templates.SectionData when handlers.SectionData should be used (CRITICAL VIOLATION in Go)
  2. Partial TypeScript Types: TypeScript interfaces missing fields from Go handler structs (TYPE SAFETY ISSUE)
  3. Conversion Helper Functions: Unnecessary mapping between handler and template types in Go
  4. Parallel Go Type Systems: Handler types + template types for same data (violates guidelines in Go)
  5. Type Mismatches: Handler types don't match TypeScript interfaces (field names, types, or count)
  6. pgtype Mapping Errors: Incorrect mapping from Go pgtype to TypeScript types
  7. Missing Indexes: Database queries slow due to missing indexes
  8. Breaking Changes: Schema changes break existing functionality
  9. OOP Patterns: Classes or this references in TypeScript
  10. Inline JavaScript: <script> blocks in templates
  11. Missing HTMX Fallbacks: Forms don't work without JavaScript
  12. Accessibility Issues: Missing ARIA attributes or keyboard support
  13. Performance Issues: Large bundle sizes or slow queries
  14. Timeline Errors: Underestimated effort for phases
  15. Contradictions: Plan conflicts with itself or other guidelines

IMPORTANT DISTINCTIONS:

  • Wrong: templates/types.go creating duplicate Go types
  • Correct: web/src/types/*.d.ts recreating types for TypeScript (necessary due to pgtype)
  • Wrong: TypeScript interfaces with partial fields (e.g., only 3 of 10 Go struct fields)
  • Correct: TypeScript interfaces with ALL fields from Go handler struct

IMPORTANT DISTINCTIONS:

  • Wrong: templates/types.go creating duplicate Go types
  • Correct: web/src/types/*.d.ts recreating types for TypeScript (necessary due to pgtype)
  • Wrong: TypeScript interfaces with partial fields (e.g., only 3 of 10 Go struct fields)
  • Correct: TypeScript interfaces with ALL fields from Go handler struct

Created: 2025-02-18 Purpose: Comprehensive verification of Carousel Dashboard plan Version: 1.0