Updated Carousel Dashboard documentation to reflect finalized architecture decisions and resolve discrepancies between plan and verification checklist. ## CAROUSEL_DASHBOARD_PLAN.md Changes ### Added Phase 4.5: Collections Preview Endpoint - Documented why preview endpoint is required (web UI + mobile apps) - Explained why client-side preview is a bad idea (download entire library, code duplication, maintenance nightmare) - Added full PreviewCollection handler implementation - Added Bruno test specification ### Enhanced Phase 7: Router Registration & Config Setup - Renamed from "Router Registration" to "Router Registration & Config Setup" - Added Step 1: Update router.go Config struct with line numbers - Added Step 2: Update main.go initialization with line numbers - Added Step 3: Update test_helpers.go with line numbers - Added explanation: Why both DashboardService AND DashboardHandler? ### Updated Phase 10.5.4: Collections Preview Endpoint - Referenced Phase 4.5 (endpoint already implemented earlier) - Clarified needed for web UI AND mobile apps - Noted no additional work needed ### Added Phase 10.6: Implementation Checklist - 30+ checklist items with file paths and verification commands - Organized by layer (Database, Service, Handler, Router, Templates, TypeScript, Tests, Docs) - Added Build & Verification section - Added Timeline Estimate (20-26 hours) - Added Post-Implementation Tasks ## CAROUSEL_DASHBOARD_VERIFICATION_CHECKLIST.md Changes ### Added Clarification Section (at top) - Explained all discrepancies between plan and checklist - Preview endpoint IS in plan (Phase 4.5) - Custom Section Builder IS in plan (Phase 10.5.2 and 10.5.3) - Service method names - Plan is correct - Config struct - Documented with exact line numbers - DashboardService vs DashboardHandler - Explained why both needed ### Updated Service Method Names (Section 3.2) Changed to match plan's actual implementation: - GetDashboardSections (not GetSectionItems) - filterHiddenCollections (not filterHiddenSections) - reorderCollections (not reorderSections) - sortByPriority (new method) - getUserCollectionItems (not getCollectionSections) - getCollectionItemsByQueryType (renamed) ### Enhanced Config Verification (Section 6.4) Added exact line numbers for all 3 files: - internal/router/router.go lines 58-59 - cmd/server/main.go lines 123-124, 172-173 - cmd/server/tests/test_helpers.go lines 419-420, 458-459 ### Updated Preview Endpoint Section (Section 6.3) Added clear explanation of why endpoint is REQUIRED and why NOT client-side. ### Clarified Custom Section Builder (Sections 8.5, 9.4) Both now explicitly state "IS in the plan (Phase 10.5)" ## docs/developer/api/dashboard.md Changes Updated API documentation to match new unified collections architecture: - Terminology: "smart sections" → "system collections" - Field: `type: string` → `is_system: boolean` - Field: `id` → `media_item_id` for books - Request: `hidden_sections` → `hidden_collections` - Request: `section_order` → `collection_order` - Removed: "in-progress" and "unread" smart sections - Added: Update Dashboard Preferences endpoint - Added: Restore System Collection endpoint - Updated: Example responses with new field names and types - Updated: Error responses table ## Impact These changes clarify: 1. Preview endpoint is required for both web UI custom section builder and mobile apps 2. Custom Section Builder IS a major feature in the plan (not missing) 3. Service method names use "collections" terminology consistently 4. Config struct updates are clearly documented with exact line numbers (3 files only) 5. Why both DashboardService AND DashboardHandler are needed in Config All documentation now accurately reflects the finalized Carousel Dashboard architecture.
3367 lines
108 KiB
Markdown
3367 lines
108 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(items []services.SectionItems) []SectionData` in dashboard.go
|
|
|
|
**Key requirements:**
|
|
|
|
- [ ] Converts service `SectionItems` to handler `SectionData` (from collections.go)
|
|
- [ ] Maps `database.MediaItems` to `handlers.BookInfo` (from collections.go)
|
|
- [ ] Uses `MediaItemID` field (not `ID`) when creating BookInfo
|
|
- [ ] Uses `IsSystem` boolean directly from database (no string conversion)
|
|
- [ ] No helper functions needed for type/title/icon (use database values directly)
|
|
- [ ] `getViewAllURL()` helper for system collection URLs only
|
|
|
|
**System collections data (from database):**
|
|
|
|
- [ ] `continue-reading` → is_system: true, title from DB, icon from DB
|
|
- [ ] `recently-added` → is_system: true, title from DB, icon from DB
|
|
- [ ] `recently-read` → is_system: true, title from DB, icon from DB
|
|
- [ ] `not-started` → is_system: true, title from DB, icon from DB
|
|
|
|
**User collections:**
|
|
|
|
- [ ] is_system: false (from database `is_system_collection` field)
|
|
- [ ] Title uses collection name from database
|
|
- [ ] Icon uses collection icon from database
|
|
- [ ] view_all_url is empty string
|
|
|
|
**Verification:**
|
|
```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 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.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.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*
|