Files
bookhoard/CAROUSEL_DASHBOARD_VERIFICATION_CHECKLIST.md
T
john-okeefe da33e2c126 docs: update Carousel Dashboard plan and resolve verification checklist discrepancies
Updated Carousel Dashboard documentation to reflect finalized architecture decisions
and resolve discrepancies between plan and verification checklist.

## CAROUSEL_DASHBOARD_PLAN.md Changes

### Added Phase 4.5: Collections Preview Endpoint
- Documented why preview endpoint is required (web UI + mobile apps)
- Explained why client-side preview is a bad idea (download entire library,
  code duplication, maintenance nightmare)
- Added full PreviewCollection handler implementation
- Added Bruno test specification

### Enhanced Phase 7: Router Registration & Config Setup
- Renamed from "Router Registration" to "Router Registration & Config Setup"
- Added Step 1: Update router.go Config struct with line numbers
- Added Step 2: Update main.go initialization with line numbers
- Added Step 3: Update test_helpers.go with line numbers
- Added explanation: Why both DashboardService AND DashboardHandler?

### Updated Phase 10.5.4: Collections Preview Endpoint
- Referenced Phase 4.5 (endpoint already implemented earlier)
- Clarified needed for web UI AND mobile apps
- Noted no additional work needed

### Added Phase 10.6: Implementation Checklist
- 30+ checklist items with file paths and verification commands
- Organized by layer (Database, Service, Handler, Router, Templates, TypeScript, Tests, Docs)
- Added Build & Verification section
- Added Timeline Estimate (20-26 hours)
- Added Post-Implementation Tasks

## CAROUSEL_DASHBOARD_VERIFICATION_CHECKLIST.md Changes

### Added Clarification Section (at top)
- Explained all discrepancies between plan and checklist
- Preview endpoint IS in plan (Phase 4.5)
- Custom Section Builder IS in plan (Phase 10.5.2 and 10.5.3)
- Service method names - Plan is correct
- Config struct - Documented with exact line numbers
- DashboardService vs DashboardHandler - Explained why both needed

### Updated Service Method Names (Section 3.2)
Changed to match plan's actual implementation:
- GetDashboardSections (not GetSectionItems)
- filterHiddenCollections (not filterHiddenSections)
- reorderCollections (not reorderSections)
- sortByPriority (new method)
- getUserCollectionItems (not getCollectionSections)
- getCollectionItemsByQueryType (renamed)

### Enhanced Config Verification (Section 6.4)
Added exact line numbers for all 3 files:
- internal/router/router.go lines 58-59
- cmd/server/main.go lines 123-124, 172-173
- cmd/server/tests/test_helpers.go lines 419-420, 458-459

### Updated Preview Endpoint Section (Section 6.3)
Added clear explanation of why endpoint is REQUIRED and why NOT client-side.

### Clarified Custom Section Builder (Sections 8.5, 9.4)
Both now explicitly state "IS in the plan (Phase 10.5)"

## docs/developer/api/dashboard.md Changes

Updated API documentation to match new unified collections architecture:
- Terminology: "smart sections" → "system collections"
- Field: `type: string` → `is_system: boolean`
- Field: `id` → `media_item_id` for books
- Request: `hidden_sections` → `hidden_collections`
- Request: `section_order` → `collection_order`
- Removed: "in-progress" and "unread" smart sections
- Added: Update Dashboard Preferences endpoint
- Added: Restore System Collection endpoint
- Updated: Example responses with new field names and types
- Updated: Error responses table

## Impact

These changes clarify:
1. Preview endpoint is required for both web UI custom section builder and mobile apps
2. Custom Section Builder IS a major feature in the plan (not missing)
3. Service method names use "collections" terminology consistently
4. Config struct updates are clearly documented with exact line numbers (3 files only)
5. Why both DashboardService AND DashboardHandler are needed in Config

All documentation now accurately reflects the finalized Carousel Dashboard architecture.
2026-02-19 18:48:09 -05:00

108 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(items []services.SectionItems) []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 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.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.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