Update the verification checklist to cover all aspects of Phase 4.6 (CreateCollection manual books support). New verification sections: - Section 6.4: Verify CreateCollection Endpoint Manual Books Support - Struct field verification (ManualBookIDs) - Validation tag verification (validate:"max=50") - Handler implementation verification - Error handling and logging verification - Graceful degradation verification - Section 19.1b: Verify Collections Bruno Tests Created - New bruno/collections/ directory structure - All 5 required test files - Test coverage verification - Section 19.1b: Verify Collections API Documentation - manual_book_ids field documentation - Validation limits (max 50) - Example requests - Error handling explanation - Backward compatibility notes Bug fix: - Fixed BuildSections function signature to match actual service (services.DashboardSection instead of services.SectionItems) All verification includes: - Step-by-step verification commands - Common pitfalls to avoid - Success criteria for each section
3490 lines
113 KiB
Markdown
3490 lines
113 KiB
Markdown
# 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
|
|
```go
|
|
// 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)
|
|
```typescript
|
|
// 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
|
|
```typescript
|
|
// 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```go
|
|
// 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# Check endpoint implementation
|
|
rg "func.*GetSections" internal/handlers/dashboard.go -A 50
|
|
|
|
# Verify response structure
|
|
rg "buildJSONSections" internal/handlers/dashboard.go -A 30
|
|
|
|
# Test with Bruno
|
|
cd bruno/dashboard/
|
|
# Run: GET /api/dashboard/sections?library_id=...
|
|
```
|
|
|
|
### 5.3 Verify BuildSections Function
|
|
|
|
**Required function:**
|
|
|
|
- [ ] `BuildSections(sections []services.DashboardSection) []SectionData` in dashboard.go
|
|
|
|
**Key requirements:**
|
|
|
|
- [ ] Converts service `SectionItems` to handler `SectionData` (from collections.go)
|
|
- [ ] Maps `database.MediaItems` to `handlers.BookInfo` (from collections.go)
|
|
- [ ] Uses `MediaItemID` field (not `ID`) when creating BookInfo
|
|
- [ ] Uses `IsSystem` boolean directly from database (no string conversion)
|
|
- [ ] No helper functions needed for type/title/icon (use database values directly)
|
|
- [ ] `getViewAllURL()` helper for system collection URLs only
|
|
|
|
**System collections data (from database):**
|
|
|
|
- [ ] `continue-reading` → is_system: true, title from DB, icon from DB
|
|
- [ ] `recently-added` → is_system: true, title from DB, icon from DB
|
|
- [ ] `recently-read` → is_system: true, title from DB, icon from DB
|
|
- [ ] `not-started` → is_system: true, title from DB, icon from DB
|
|
|
|
**User collections:**
|
|
|
|
- [ ] is_system: false (from database `is_system_collection` field)
|
|
- [ ] Title uses collection name from database
|
|
- [ ] Icon uses collection icon from database
|
|
- [ ] view_all_url is empty string
|
|
|
|
**Verification:**
|
|
```bash
|
|
# 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/sections` → `GetSections`
|
|
- [ ] Handler injected via Config struct
|
|
- [ ] Route registration called from main router
|
|
|
|
**Verification:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```json
|
|
{
|
|
"library_id": "uuid",
|
|
"rules": [
|
|
{
|
|
"id": "rule1",
|
|
"field": "genre",
|
|
"operator": "equals",
|
|
"value": "Sci-Fi",
|
|
"priority": 5
|
|
}
|
|
],
|
|
"manual_book_ids": ["uuid1", "uuid2"],
|
|
"limit": 20
|
|
}
|
|
```
|
|
|
|
**Response format:**
|
|
```json
|
|
{
|
|
"items": [
|
|
{
|
|
"media_item_id": "uuid",
|
|
"title": "Dune",
|
|
"author": "Frank Herbert",
|
|
"cover_image_path": "/path/to/cover.jpg"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
**Verification:**
|
|
```bash
|
|
# Check handler method exists (Phase 4.5 of plan)
|
|
rg "func.*PreviewCollection" internal/handlers/collections.go -A 30
|
|
|
|
# Check route registration (Phase 4.5 of plan)
|
|
rg 'POST.*"/preview"' internal/router/collections.go
|
|
|
|
# Verify EvaluateRules usage
|
|
rg "collectionService.EvaluateRules" internal/handlers/collections.go
|
|
|
|
# Check BookInfo conversion with MediaItemID
|
|
rg "MediaItemID.*String\(\)" internal/handlers/collections.go
|
|
|
|
# Verify manual book ID handling
|
|
rg "manual_book_ids" internal/handlers/collections.go
|
|
|
|
# Check Bruno test exists
|
|
ls -la bruno/dashboard/preview-collection.bru
|
|
```
|
|
|
|
### 6.4 Verify CreateCollection Endpoint Manual Books Support
|
|
|
|
**IMPORTANT: Custom Section Builder requires this feature**
|
|
|
|
**Why this endpoint update is necessary:**
|
|
- Custom Section Builder allows users to select books manually + use filter rules
|
|
- Single API call creates collection + adds books (cleaner than separate calls)
|
|
- Reuses existing `AddBookToCollection` service method
|
|
|
|
**For `internal/handlers/collections.go`:**
|
|
|
|
**Struct updates:**
|
|
- [ ] `ManualBookIDs []string` field added to `CreateCollectionRequest` struct (after line 40)
|
|
- [ ] Field has JSON tag: `json:"manual_book_ids"`
|
|
- [ ] Field has validation tag: `validate:"max=50"`
|
|
|
|
**Handler updates:**
|
|
- [ ] `CreateCollection` function updated (after line 97)
|
|
- [ ] Parses and validates `req.ManualBookIDs`
|
|
- [ ] Loops through manual book IDs
|
|
- [ ] Calls `h.collectionService.AddBookToCollection` for each valid book ID
|
|
- [ ] Logs errors for invalid book IDs but continues processing
|
|
- [ ] Logs summary of added books
|
|
|
|
**Error handling:**
|
|
- [ ] Invalid book IDs are skipped (not added to collection)
|
|
- [ ] Errors are logged using `c.Logger().Errorf`
|
|
- [ ] Collection is still created even if some books fail to add
|
|
- [ ] Returns 201 on success (even if some books failed)
|
|
|
|
**Validation:**
|
|
- [ ] Request validation checks manual_book_ids array length ≤ 50
|
|
- [ ] Returns 400 if more than 50 book IDs provided
|
|
- [ ] Validation tag enforces max limit: `validate:"max=50"`
|
|
|
|
**Verification commands:**
|
|
```bash
|
|
# Check ManualBookIDs field exists in struct
|
|
rg "ManualBookIDs.*\[\]string" internal/handlers/collections.go
|
|
|
|
# Check validation tag is present
|
|
rg 'validate:"max=50"' internal/handlers/collections.go
|
|
|
|
# Check CreateCollection handler processes manual books
|
|
rg "ManualBookIDs" internal/handlers/collections.go -A 30
|
|
|
|
# Verify AddBookToCollection is called
|
|
rg "AddBookToCollection.*ManualBookIDs" internal/handlers/collections.go -A 5
|
|
|
|
# Check error logging for invalid book IDs
|
|
rg "Logger.*Errorf.*Invalid book ID" internal/handlers/collections.go
|
|
```
|
|
|
|
**Common pitfalls:**
|
|
- Forgetting to validate array length (DoS vulnerability)
|
|
- Returning error on first invalid book ID (should continue processing)
|
|
- Not logging errors (makes debugging difficult)
|
|
- Creating separate service method (unnecessary - reuse existing)
|
|
|
|
### 6.5 Verify Config Setup
|
|
|
|
**CRITICAL: Config struct must be updated in 3 files**
|
|
|
|
**For `internal/router/router.go`:**
|
|
|
|
- [ ] `DashboardService *services.DashboardService` added to Config struct (after line 56)
|
|
- [ ] `DashboardHandler *handlers.DashboardHandler` added to Config struct (after line 57)
|
|
- [ ] Field order matches other service/handler fields
|
|
|
|
**For `cmd/server/main.go`:**
|
|
|
|
- [ ] `dashboardService := services.NewDashboardService(queries)` initialized (after line 123)
|
|
- [ ] `dashboardHandler := handlers.NewDashboardHandler(queries)` initialized (after line 124)
|
|
- [ ] `DashboardService: dashboardService,` added to routerConfig (after line 172)
|
|
- [ ] `DashboardHandler: dashboardHandler,` added to routerConfig (after line 173)
|
|
- [ ] Both initialized before router.RegisterRoutes() call
|
|
|
|
**For `cmd/server/tests/test_helpers.go`:**
|
|
|
|
- [ ] `dashboardService := services.NewDashboardService(queries)` initialized (after line 419)
|
|
- [ ] `dashboardHandler := handlers.NewDashboardHandler(queries)` initialized (after line 420)
|
|
- [ ] `DashboardService: dashboardService,` added to routerConfig (after line 458)
|
|
- [ ] `DashboardHandler: dashboardHandler,` added to routerConfig (after line 459)
|
|
|
|
**Why both DashboardService AND DashboardHandler?**
|
|
- **DashboardService**: Used by SSR routes in frontend.go for data fetching
|
|
- **DashboardHandler**: Used by API routes for JSON endpoints
|
|
- **Mobile apps**: Will use DashboardHandler API endpoints
|
|
- **Web UI**: Uses DashboardService for SSR + DashboardHandler for interactions
|
|
|
|
**Verification:**
|
|
```bash
|
|
# 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):**
|
|
```go
|
|
// Handler type defined once in handlers package
|
|
// Reused directly in template
|
|
templ Dashboard(sections []handlers.SectionData, books []handlers.BookInfo)
|
|
```
|
|
|
|
**❌ WRONG (Go):**
|
|
```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:**
|
|
```go
|
|
// ✅ 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):**
|
|
```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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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.Text` → `string`
|
|
- `pgtype.UUID` → `string`
|
|
- `pgtype.Timestamp` → `string` (ISO datetime)
|
|
- `pgtype.Int4` → `number`
|
|
- `pgtype.Bool` → `boolean`
|
|
- `pgtype.TextArray` → `string[]`
|
|
- [ ] 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:**
|
|
```bash
|
|
# 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
|
|
// 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
|
|
// 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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
|
|
// 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
|
|
// 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# Check Bruno test directory exists
|
|
ls -la bruno/dashboard/ || echo "Directory does not exist yet"
|
|
|
|
# Verify test files exist (after Phase 12 of plan)
|
|
ls -la bruno/dashboard/*.bru 2>/dev/null | wc -l
|
|
# Should return at least 9 after Phase 12
|
|
|
|
# Run Bruno tests
|
|
cd bruno/dashboard && bru run --env local
|
|
```
|
|
|
|
### 19.1b Verify Collections Bruno Tests Created
|
|
|
|
**Required files in `bruno/collections/` (NEW directory):**
|
|
|
|
- [ ] `create-collection-with-manual-books.bru` - Create collection with manual books
|
|
- [ ] `create-collection-too-many-books.bru` - Validation test (max 50 books)
|
|
- [ ] `create-collection-invalid-book-id.bru` - Invalid UUID handling
|
|
- [ ] `create-collection-rules-only.bru` - Auto-assign rules only
|
|
- [ ] `create-collection-unauthorized.bru` - No authentication
|
|
|
|
**Verification:**
|
|
```bash
|
|
# Check Bruno collections directory exists
|
|
ls -la bruno/collections/ || echo "Directory does not exist yet"
|
|
|
|
# Verify test files exist (after Phase 12.5 of plan)
|
|
ls -la bruno/collections/*.bru 2>/dev/null | wc -l
|
|
# Should return at least 5 after Phase 12.5
|
|
|
|
# Run Bruno tests for collections
|
|
cd bruno/collections && bru run --env local
|
|
```
|
|
|
|
**Test coverage verification:**
|
|
- [ ] `manual_book_ids` field included in request body
|
|
- [ ] Validation test sends 51+ book IDs, expects 400
|
|
- [ ] Invalid UUID test verifies graceful handling
|
|
- [ ] All tests verify 201 status on success
|
|
- [ ] Unauthorized tests verify 401 status
|
|
|
|
### 19.2 Verify Bruno Test Response Structure
|
|
|
|
**For `get-sections-success.bru`:**
|
|
|
|
- [ ] Response includes `is_system` field (boolean)
|
|
- [ ] Response does NOT include `type` field (old field name)
|
|
- [ ] Books have `media_item_id` field (not `id`)
|
|
- [ ] Response structure matches Go handler JSON tags
|
|
- [ ] Assertions verify correct field types
|
|
|
|
**For `restore-system-collection-success.bru`:**
|
|
|
|
- [ ] Request body uses `collection_name` parameter
|
|
- [ ] Valid collection names: continue-reading, recently-added, recently-read, not-started
|
|
- [ ] Invalid names return 400 status
|
|
- [ ] Success returns 200 status with message
|
|
|
|
**Verification:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# Check API documentation has correct field names
|
|
rg "is_system.*boolean" docs/developer/api/dashboard.md
|
|
rg "media_item_id" docs/developer/api/dashboard.md
|
|
rg "hidden_collections|collection_order" docs/developer/api/dashboard.md
|
|
|
|
# Verify no old field names
|
|
rg "\"type\":\s*\"smart\"" docs/developer/api/dashboard.md
|
|
# Should return nothing
|
|
|
|
# Verify only 4 system collections (no "In Progress")
|
|
rg "In Progress" docs/developer/api/dashboard.md
|
|
# Should return nothing
|
|
|
|
# Count system collections mentioned
|
|
rg "continue-reading|recently-added|recently-read|not-started" docs/developer/api/dashboard.md | wc -l
|
|
# Should return at least 4
|
|
```
|
|
|
|
### 19.1b Verify Collections API Documentation
|
|
|
|
**File: `docs/developer/api/collections/create_collection.md` (UPDATE existing):**
|
|
|
|
- [ ] `manual_book_ids` field added to request body documentation
|
|
- [ ] Field type documented as array of strings (book UUIDs)
|
|
- [ ] Field marked as optional
|
|
- [ ] Validation limit documented (max 50 items)
|
|
- [ ] Error case documented (400 if > 50 items)
|
|
- [ ] Example request shows `manual_book_ids` usage
|
|
- [ ] Notes explain combining with `auto_assign_rules`
|
|
- [ ] Notes explain invalid book IDs are skipped gracefully
|
|
|
|
**Documentation requirements:**
|
|
- [ ] Example shows both `auto_assign_rules` AND `manual_book_ids`
|
|
- [ ] Error handling explained for invalid book IDs
|
|
- [ ] Validation rule clearly stated (max 50)
|
|
- [ ] Backward compatibility noted (field is optional)
|
|
|
|
**Verification:**
|
|
```bash
|
|
# Check manual_book_ids in documentation
|
|
rg "manual_book_ids" docs/developer/api/collections/create_collection.md
|
|
|
|
# Verify validation is documented
|
|
rg "max.*50|50.*items" docs/developer/api/collections/create_collection.md -i
|
|
|
|
# Check example request
|
|
rg "manual_book_ids.*\[" docs/developer/api/collections/create_collection.md -A 5
|
|
|
|
# Verify error cases documented
|
|
rg "400.*invalid|validation" docs/developer/api/collections/create_collection.md -i
|
|
```
|
|
|
|
### 19.2 Verify User Documentation
|
|
|
|
**File: `docs/user/dashboard.md`:**
|
|
|
|
- [ ] Lists only 4 smart sections (no "In Progress")
|
|
- [ ] Explains system collections can be restored to defaults
|
|
- [ ] Customization instructions mention "System" badge
|
|
- [ ] Uses "collection" terminology consistently
|
|
- [ ] No references to "smart sections" concept
|
|
- [ ] Keyboard navigation documented
|
|
- [ ] Touch gestures documented
|
|
|
|
**Verification:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```typescript
|
|
// 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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*
|