Commit Graph
100 Commits
Author SHA1 Message Date
john-okeefe 06461a3202 refactor(alpine): migrate remaining pages to x-init declarative initialization
- Remove DOMContentLoaded event listeners from analytics.ts and docs.ts
- Rely on x-init attribute in templates for page initialization
- Clean up unused exports from collections.ts Alpine data
- Add x-init calls to admin_library, analytics, and docs templates
- Normalize quote style in collections WebSocket script (single to double)
- Disable Add Books button in collection detail (pending implementation)
2026-03-12 18:13:12 -04:00
john-okeefe 75c454b661 docs(alpine): integrate SSR-first principles into Alpine completion guide
Updated ALPINE_COMPLETION_GUIDE.md to reference SSR_FIRST_ALPINE_GUIDE.md
and clarify the relationship between all three guides.

Changes:
- Added reference to SSR_FIRST_ALPINE_GUIDE.md as prerequisite
- Added Phase 0: Prerequisites (dead export removal)
- Added Phase 3: Other Templates (DOMContentLoaded cleanup)
- Reorganized Phase numbers (old Phase 3→4, 4→5, 5→6)
- Updated Key Principles section to include SSR-first rules
- Added "How This Guide Relates to Others" section (4.3)
- Updated Next Steps with recommended reading order
- Clarified documentation strategy and goals

Key SSR-first additions:
-  NEVER fetch data in x-init if data is already SSR'd
-  x-init ONLY for setup (event listeners, modals)
-  Data fetch ONLY after user actions (create/delete/update)

Three Guide Strategy:
1. SSR_FIRST_ALPINE_GUIDE.md - Architecture principles (READ FIRST)
2. COLLECTIONS_CLEANUP_GUIDE.md - Quick reference for immediate fixes
3. ALPINE_COMPLETION_GUIDE.md - Full migration path (this guide)

This ensures users understand SSR-first architecture before attempting
full Alpine.js migration, preventing common mistakes like fetching data
in x-init that replaces SSR content.

The guides now work together without contradiction:
- SSR_FIRST establishes principles
- COLLECTIONS_CLEANUP provides quick fix reference
- ALPINE_COMPLETION provides complete migration path

Eventually COLLECTIONS_CLEANUP_GUIDE.md can be deprecated once all patterns
are understood and incorporated into the other two guides.
2026-03-12 18:10:23 -04:00
john-okeefe ab2e2427cc docs(ssr): create SSR-first Alpine.js guide and update cleanup guide
Created comprehensive SSR_FIRST_ALPINE_GUIDE.md to establish SSR-first
architecture principles for Alpine.js integration.

New Guide: SSR_FIRST_ALPINE_GUIDE.md

Covers:
- SSR-first principles (state in templates, no fetch in x-init for SSR pages)
- Three page type classifications:
  * Type 1: 80% SSR (Collections, Conflicts) - backend provides all data
  * Type 2: SSR + Interactive (Dashboard, Admin Library) - SSR + interactivity
  * Type 3: 80% JavaScript (Analytics) - x-init fetches all data (intentional)
- The SSR data fetch problem (x-init replacing SSR content)
- DOMContentLoaded cleanup strategies
- Page-by-page strategy for each type
- Authentication & SSR (server-side token injection)
- Verification checklist and testing approach
- Architecture diagram showing data flow

Key Principles:
-  NEVER fetch data in x-init if data is already SSR'd
-  x-init ONLY for setup (event listeners, modals)
-  Data fetch ONLY after user actions
-  State lives in template (x-data), not TypeScript

Updated: COLLECTIONS_CLEANUP_GUIDE.md

Changes:
- Added reference to SSR_FIRST_ALPINE_GUIDE.md as authority
- Removed two-option approach (no more choices)
- Documented that admin library SSR bug is already fixed (commit 1b9bc64)
- Simplified dashboard approach (wrap existing code in initDashboard)
- Simplified docs approach (simple setup, no data fetch)
- Updated summary to reflect completed work
- Added architecture section showing state location

Architecture Clarity:
- Templates: UI state (x-data, x-show)
- Backend: SSR data
- TypeScript: Business logic only
- No hybrid approach - follow SSR-first principles

References:
- SSR_FIRST_ALPINE_GUIDE.md - Complete SSR-first architecture
- ALPINE_COMPLETION_GUIDE.md - Full Alpine.js migration (future goal)
- PROJECT_GUIDELINES.md - Project standards

This establishes a single source of truth for SSR-first Alpine.js
architecture and removes confusion about which approach to use.
2026-03-12 18:07:16 -04:00
john-okeefe 5382b9b2a9 docs(cleanup): merge Alpine.js reactive pattern into SSR cleanup guide
Updated COLLECTIONS_CLEANUP_GUIDE.md to present TWO approaches for
each page, giving flexibility for quick fixes vs full migration.

Two Approaches Now Available:

OPTION A: Minimal Fix (Quick)
- Fix SSR bugs by removing data fetch from init functions
- Keep x-init for setup only (event listeners, modals)
- Keep current event listener patterns
- Good for quick fixes

OPTION B: Full Alpine.js Reactive Pattern (Recommended)
- See ALPINE_COMPLETION_GUIDE.md for complete pattern
- Eliminate ALL manual DOM manipulation
- Use x-data for state, x-show for visibility
- Use @click.outside for closing dropdowns/modals
- Use x-transition for smooth animations
- No initialization functions needed
- Aligns with long-term architecture

Updates to Guide Sections:

Step 3.2 (docs.ts):
- Added Option A: Use x-init (simple)
- Added Option B: Event delegation pattern
- Recommendation: Option A (simple setup, no data fetch)

Step 3.3 (library.ts):
- Added Option A: Remove reloadLibraries() from init (quick)
- Added Option B: Full Alpine.js reactive pattern
- Shows how to eliminate manual DOM manipulation
- Recommendation: Option B for cleanest architecture

Step 3.4 (dashboard.ts):
- Added Option A: Wrap in initDashboard() function
- Added Option B: Remove DOMContentLoaded, use delegation
- Notes event delegation already exists
- Recommendation: Option A (keep current pattern)

Updated Summary Section:
- Added architecture decision point (Path 1 vs Path 2)
- Documented mixed approach as recommended
- Clear guidance on which approach to use when
- References ALPINE_COMPLETION_GUIDE.md throughout

This allows developer to choose approach based on:
- Page complexity
- Time constraints
- Learning progression
- Long-term architecture goals

The guide is now flexible enough to support both quick fixes
and full Alpine.js migration as the developer progresses
through the app page-by-page.
2026-03-12 18:03:37 -04:00
john-okeefe 1b9bc64b28 refactor(library): fix SSR bug by removing data fetch from init function
CRITICAL FIX: initializeLibraryAdmin() was calling reloadLibraries()
which fetched data from the API and replaced the SSR-rendered library
list on page load, defeating the purpose of server-side rendering.

Changes in web/src/library.ts:
- Remove DOMContentLoaded listener (now uses Alpine x-init in template)
- Remove void reloadLibraries() call from initializeLibraryAdmin()
- Add comment explaining SSR provides initial data
- Add initializeLibraryAdmin to export statement
- Add initializeLibraryAdmin to Alpine.data() registration
- Keep reloadLibraries() as standalone function for use after CRUD ops

Rationale:
- SSR provides fast initial page load with library list
- x-init should ONLY setup event listeners, not fetch data
- reloadLibraries() is called after create/delete/update operations
- Follows SSR-first architecture: different pages have different
  SSR/JS ratios (analytics is 80% JS, most pages are 80% SSR)

Documentation:
- Update COLLECTIONS_CLEANUP_GUIDE.md with SSR-first strategy
- Document page-by-page review status (dashboard ✓, collections 🔄)
- Fix template references (library.templ → admin_library.templ)
- Explain why analytics fetches data (intentional for dynamic page)

This ensures the admin library page maintains SSR benefits while
still providing interactive features via Alpine.js.
2026-03-12 17:58:36 -04:00
john-okeefe ddcd8c62e2 style(templates): normalize quote style in WebSocket script in admin template
- Normalize inconsistent quote usage in admin WebSocket script tag
- Change window.location.protocol comparison from single to double quotes
- Change error message quotes from single to double quotes
- No functional changes - pure formatting cleanup

Improves code consistency by standardizing quote style throughout the admin
WebSocket initialization script.
2026-03-12 17:21:47 -04:00
john-okeefe 002c855648 feat(templates): add x-init call for analytics page initialization
- Add x-init="loadAnalytics" to analytics.templ body tag
- Ensures analytics data loads automatically when page initializes via Alpine.js
- Works with existing Alpine.data("analytics") export that was already in place

The loadAnalytics() function now runs automatically when the analytics page loads,
eliminating the need for a DOMContentLoaded listener.
2026-03-12 17:21:43 -04:00
john-okeefe b06ffa2329 refactor(admin): remove DOMContentLoaded listener for watch status initialization
- Remove document.addEventListener("DOMContentLoaded") wrapper for loadWatchStatus()
- Simplify initialization - loadWatchStatus() is now called via Alpine.js x-init
- Reduces 4 lines, keeps same functionality

The loadWatchStatus() function is now triggered by template's x-init directive
instead of a global DOMContentLoaded listener, ensuring it only runs on the
admin page where it's actually needed.
2026-03-12 17:21:38 -04:00
john-okeefe 4d186f76dc refactor(collections): remove dead Alpine.js exports and DOMContentLoaded listeners
- Remove DOMContentLoaded listeners for setupHTMXAuth, initColorSelection, and setupHTMXModalInit
- Delete dead Alpine.data exports: addbooksToAdd, removebooksToAdd, toggleBookForRemoval,
  toggleBookSelection, initCollectionDetail, initIconSelection, initColorSelection
- Add missing setupHTMXAuth to export statement (it was called but not exported)
- Remove 14 lines of auto-initialization code that's no longer needed

This fixes "X is not defined" console errors for functions that were deleted
in commit 93710a1 but were still in Alpine.data export. The collections.templ template
was also updated to remove calls to these deleted functions.

These changes align with the SSR architecture where most collection functionality
is server-rendered and client-side JavaScript is used sparingly.
2026-03-12 17:21:34 -04:00
john-okeefe bfdef1396a docs(collections): add comprehensive cleanup guide for Alpine.js and DOMContentLoaded issues
Add detailed step-by-step guide for fixing console errors in collections
and cleaning up DOMContentLoaded listeners across multiple TypeScript files.

COLLECTIONS_CLEANUP_GUIDE.md provides:
- Complete analysis of what was broken and why
- Line-by-line instructions for fixing collections.ts Alpine.data exports
- Step-by-step guide for removing DOMContentLoaded from 5 TypeScript files
- Template x-init additions for proper Alpine.js initialization
- Verification and testing steps

This guide documents the fix for:
- Dead Alpine.js exports (addbooksToAdd, removebooksToAdd, toggleBookSelection, etc.)
- DOMContentLoaded listeners running on wrong pages (analytics, docs, library, dashboard, admin)
- Missing x-init calls in templates (analytics, docs, dashboard, library)
- Template cleanup (removing dead function calls in collections.templ)

The guide follows PROJECT_GUIDELINES.md standards with clear code examples,
file paths, and verification steps. It serves as both implementation guide
and documentation for the cleanup effort.
2026-03-12 17:21:28 -04:00
john-okeefe 4ed5c24f84 feat(websocket): add reusable WebSocket connection helper utility
- Create createWebSocket() helper for WebSocket connections with authentication
- Support automatic reconnection with configurable delay
- Include error handling and logging
- Export disconnectWebSocket() for cleanup

This helper provides a centralized way to create WebSocket connections
with JWT token authentication from localStorage. Although not currently
used in the application (we opted for server-side token injection in templates),
it provides a reusable utility for future WebSocket integrations.

Features:
- Automatic token retrieval from localStorage
- Configurable reconnection behavior (enabled by default)
- Error handling with try-catch on all callbacks
- Connection cleanup and management
- Type-safe configuration interface

Available for future use in client-side WebSocket scenarios or as a reference
implementation.
2026-03-12 15:45:05 -04:00
john-okeefe b4cf1ddafa style: apply code formatting to generated templates and TypeScript files
- Regenerate Go template files with updated FileName paths for error reporting
- Apply Prettier formatting to api-explorer-docs.ts for consistency
- Format long function signatures across multiple lines for readability
- Format long conditional chains for better code clarity

Changes are purely formatting and do not affect functionality:
- api-explorer-docs.ts: Format initAPIExplorerDoc, tryDocEndpoint, and other functions
- Generated _templ.go files: Update FileName paths from relative to absolute (e.g., "admin.templ" → "templates/admin.templ")

This ensures consistent code style across the codebase and improves
error reporting by providing full file paths in template error messages.
2026-03-12 15:44:46 -04:00
john-okeefe 533f8747e3 perf(templates): add defer attribute to main.js script tags across all pages
- Add defer attribute to <script src="/static/main.js"> in 21 template files
- Improves page load performance by allowing HTML parsing to continue without blocking
- Maintains script execution order while enabling parallel resource loading
- Remove duplicate defer attribute from header.templ line 264
- Add websocket.ts import to main.ts for module registration

This optimization reduces page render blocking and improves perceived load times
by allowing the browser to continue parsing HTML while the main.js bundle loads.
The defer attribute ensures scripts execute in order after HTML parsing completes.

Affected templates include:
- Admin pages: admin, admin_library, admin_settings, admin_users
- Content pages: analytics, bookshelf, collections, conflicts, custom_section
- User pages: dashboard, devices, docs, index, login, profile, progress, queue, register
- System pages: header, unlinked_books
2026-03-12 15:44:15 -04:00
john-okeefe 48eaa2d286 fix(alpine): wrap all Alpine.data() callbacks in arrow functions for proper component initialization
- Wrap all Alpine.data() object literals in arrow functions (() => ({}))
- This fixes "n.bind is not a function" errors when Alpine initializes components
- Alpine.data() requires a factory function, not a plain object
- Ensures each component instance gets its own closure and proper this binding

Fixed 24 TypeScript files:
- admin.ts, analytics.ts, api.ts, api-explorer-docs.ts
- bookshelf.ts, collection-rules.ts, collections.ts, conflicts.ts
- device-management.ts, docs.ts, header.ts, index.ts
- library.ts, linking.ts, login.ts, password_validation.ts
- profile-modal.ts, profile.ts, queue.ts, register.ts
- search.ts, theme.ts, toast-error.ts, toast.ts, unlinked_books.ts

Before: Alpine.data("name", { method1, method2 })
After:  Alpine.data("name", () => ({ method1, method2 }))

This is a critical fix for Alpine.js v3+ where components must be
registered as factory functions to ensure proper reactivity and
prevent binding errors during initialization.
2026-03-12 15:43:56 -04:00
john-okeefe 93710a1e96 refactor(collections): move WebSocket from TypeScript to template with server-side token
- Move WebSocket connection logic from collections.ts to collections.templ template
- Inject JWT token directly into WebSocket URL from server-side User.Token
- Remove createWebSocket import, ws variable, and connectWebSocket() function
- Remove unused CollectionUpdateMessage interface
- Embed complete WebSocket message handling in template script tag

Changes to collections.templ:
- Add inline <script> with WebSocket connection using server-injected token
- Implement collection_updated message handler with toast notifications
- Include 5-second auto-reconnection on disconnect
- Add user activity detection to skip auto-reload when actively typing
- Initialize collectionId and libraryId from data attributes

Changes to collections.ts:
- Remove createWebSocket import
- Remove ws variable declaration
- Remove connectWebSocket() function and CollectionUpdateMessage interface
- Keep all other collection functionality (CRUD operations, modals, search, etc.)

This refactoring eliminates client-side localStorage dependencies for
WebSocket authentication, making the collections page consistent with the
SSR architecture. The token is now injected server-side on every page
load, ensuring WebSocket connections always work when the user is
authenticated via HttpOnly cookie. Auto-reconnection and smart reload
behavior is preserved for optimal UX.
2026-03-12 15:43:39 -04:00
john-okeefe 40c447bd19 refactor(admin): move WebSocket from TypeScript to template with server-side token
- Move WebSocket connection logic from admin.ts to admin.templ template
- Inject JWT token directly into WebSocket URL from server-side User.Token
- Remove createWebSocket import and related functions from admin.ts
- Embed complete WebSocket message handling in template script tag

Changes to admin.templ:
- Add inline <script> with WebSocket connection using server-injected token
- Implement scan_progress, scan_complete, and scan_error message handlers
- Include error handling for WebSocket failures

Changes to admin.ts:
- Remove createWebSocket import
- Remove connectWebSocket(), updateScanProgress(), showScanComplete(), showScanError() functions
- Keep stopScanStatusPolling() for Alpine.js integration
- Preserve all other admin functionality (scan triggering, stats loading, etc.)

This refactoring eliminates client-side localStorage dependencies for
WebSocket authentication, making the admin page consistent with the
SSR architecture. The token is now injected server-side on every page
load, ensuring WebSocket connections always work when the user is
authenticated via HttpOnly cookie.
2026-03-12 15:43:27 -04:00
john-okeefe 9bceef7b41 feat(templates): add JWT token to User struct for server-side WebSocket authentication
- Add Token field to templates.User struct for passing JWT to frontend
- Modify getTemplateUserWithTheme() to extract token from HttpOnly cookie
- Inject server-side token into templates for WebSocket connections

This change enables templates to access the authentication token directly
from the server, allowing WebSocket URLs to be constructed with the token
already included. This eliminates the need for client-side localStorage
token management and provides a more secure SSR-native approach.

The token is extracted from the existing HttpOnly cookie that JWT middleware
validates, ensuring no additional security surface is introduced.
2026-03-12 15:43:15 -04:00
john-okeefe 2e65cd7ff5 fix(templates): correct file paths in generated template error reporting
- Update FileName paths in error reporting from relative to absolute paths
- Changes template error paths from 'filename.templ' to 'templates/filename.templ'
- Affects 21 auto-generated Go template files compiled from .templ sources

This fix ensures that template rendering errors provide accurate file locations,
making debugging and error tracking more reliable. The generated files now
correctly reference their source template locations with full path information.

Note: These files are auto-generated by the templ compiler from the .templ
source files committed in the previous commit.
2026-03-12 09:04:26 -04:00
john-okeefe 96e206b671 perf(templates): add defer attribute to main.js script tags
- Add defer attribute to all main.js script includes across 22 template files
- Improves page load performance by allowing HTML parsing to continue without blocking
- Maintains script execution order while enabling parallel resource loading

This optimization reduces page render blocking and improves perceived load times
across all admin and user-facing pages that include the main.js bundle.

Affected pages include: admin dashboard, library management, settings, user
management, analytics, bookshelf, collections, conflicts, custom sections,
devices, documentation, profile, progress tracking, queue, and authentication
pages (login/register).
2026-03-12 09:04:13 -04:00
john-okeefe b754f0ddce refactor(websocket): migrate endpoint from /api/ws to /ws/sync
- Update WebSocket connection URL in admin.ts to use new /ws/sync endpoint
- Update API documentation in bruno collection to reflect new WebSocket route
- Standardizes WebSocket routing under /ws/ path prefix for better API organization

This change improves API structure consistency and makes WebSocket endpoints
more discoverable and manageable under a dedicated path hierarchy.
2026-03-12 09:04:04 -04:00
john-okeefe a62e4062a2 Add Vite configuration for TypeScript bundling
Created vite.config.ts with optimized settings for the Bookhoard project:
- Output directory: web/static/ (matches existing esbuild setup)
- Single entry point: web/src/main.ts
- Output file: main.js (preserves existing template references)
- ES2020 target for modern browser compatibility
- Source maps enabled for debugging
- esbuild minification for optimal bundle size
- emptyOutDir: false to preserve other static assets (htmx.min.js, CSS, images)

Configuration maintains the same build output structure as esbuild,
ensuring no changes needed to templates or deployment process.
2026-03-12 08:46:16 -04:00
john-okeefe 638fac208d Replace esbuild with Vite for TypeScript bundling
- Migrated build scripts from esbuild to Vite 7.3.1
- Updated package.json scripts: build:ts, build:ts:dev, build:ts:watch now use vite
- Removed esbuild dependency, added vite as devDependency
- Maintained HTMX copy step since Vite cannot bundle it due to eval() usage
- Kept same output structure: web/static/main.js with sourcemaps
- All build targets (es2020), minification, and watch mode preserved

This change provides faster builds, better tree-shaking, and modern build tooling
while maintaining compatibility with the existing Docker-only deployment workflow.
2026-03-12 08:46:12 -04:00
john-okeefe af337c88e2 build: regenerate templ files and compiled CSS
Generated files updated to reflect:
- New admin_settings.templ template
- Updated admin_sidebar.templ with Settings link
- Fixed devices.templ with correct regenerate-token path
- Compiled TailwindCSS with any style changes
2026-03-11 16:42:56 -04:00
john-okeefe d6b702e35a device: add copyToClipboard and fix regenerate token HTMX button
Phase 3: Complete device page functionality fixes

- Add copyToClipboard function to device-management.ts:
  - Uses navigator.clipboard.writeText() for copying
  - Shows success/error toast notifications
  - Already exported in Alpine.store, now properly defined
- Fix typo in devices.templ: change 'regerate-token' to 'regenerate-token'
- Add HTMX support to RegenerateDeviceToken handler:
  - Returns HTML with reload script for HTMX requests
  - Preserves JSON response for API calls

The regenerate token button now works via HTMX (hx-put) instead of
Alpine.js, matching the pattern used elsewhere in the app.
2026-03-11 16:42:34 -04:00
john-okeefe 5a61d9e321 config: simplify to single base_url with computed paths
Refactor configuration to use one source of truth for base URL

- Add GetBaseURL() to config package: queries system_config table first,
  falls back to BASE_URL env var
- Update SidecarHandler to accept config and use single base_url
- Compute opds/api paths from base_url instead of storing separately:
  - OPDS: base_url + /opds
  - API: base_url + /api
  - Device Sync: base_url + /api/sync
- Simplify OPDSHandler.getBaseURLs() to compute opds path
- Remove need for separate opds_base_url and api_base_url columns

Previously the system stored three separate URL config values that were
usually the same domain with different paths. Now store only base_url
and compute the paths, eliminating configuration redundancy.
2026-03-11 16:42:21 -04:00
john-okeefe c1b664dbe5 frontend: add admin settings page for base URL configuration
Phase 2: Create admin UI for system configuration

- Add new /admin/settings route in frontend.go (protected by AdminMiddleware)
- Create admin_settings.templ with HTMX-powered form for base URL
- Add Settings link to admin sidebar navigation
- Admin settings form submits via HTMX to PUT /api/system/config
- Success message displays after save with updated form

The settings page allows admins to configure the base URL used for
device sync URLs, OPDS endpoints, and API access.
2026-03-11 16:41:45 -04:00
john-okeefe 5451e82b2d router: register SidecarHandler routes for system config and device sidecar
Phase 1: Register routes that were defined but never connected

- Add GET/PUT /api/system/config routes (admin-only) for system
  configuration in new internal/router/system.go
- Add GET /api/devices/:id/sidecar routes for device sidecar config
- Add SidecarHandler to router Config struct
- Instantiate SidecarHandler in main.go with config for fallback support

These routes were implemented in handlers/sidecar.go but never registered,
breaking the ability to configure base URLs for device sync.
2026-03-11 16:41:32 -04:00
john-okeefe 2214288d9c style: Standardize template formatting and indentation
Applies consistent code formatting to template source files:

Changes:
- Fixed inconsistent indentation in admin_library.templ (tabs vs spaces)
- Standardized whitespace alignment across multiple template files
- Ensured generated Go files match reformatted sources

Templates Updated:
- admin_library.templ: Indentation fixes for AdminSidebar component
- analytics.templ: Whitespace normalization
- collections.templ: Whitespace normalization
- conflicts.templ: Whitespace normalization
- dashboard.templ: Whitespace normalization

Generated Go Files:
- All corresponding *_templ.go files regenerated to match

These are cosmetic formatting changes only - no functional changes.
Alpine.js integration, template logic, and application behavior unchanged.
2026-03-11 11:39:42 -04:00
john-okeefe 287e526e04 docs: Archive obsolete Alpine.js and ESBuild migration plans
Archives 6 migration planning documents that are now complete or obsolete:

Completed Migrations (Safe to Delete):
- ALPINE_GLOBAL_FIX_PART1.md: Alpine.global() → Alpine.store() migration COMPLETE
- ESBUILD_MIGRATION_PLAN.md: ESBuild bundling and ES modules migration COMPLETE
- ESBUILD_IMPORT_FIXES.md: ESBuild import corrections APPLIED

Obsolete Reference Documents (Safe to Delete):
- ESBUILD_SETUP_OLD.md: Superseded by ESBUILD_MIGRATION_PLAN.md
- ESBUILD_README.md: Quick reference for completed migration

Future Work (Retained as Reference):
- ALPINE_COMPLETION_GUIDE.md: Reactive Alpine.js migration (OPTIONAL, not started)

Migration Status Summary:
 Alpine.store() migration: All 26 files converted, 25 stores registered
 ESBuild bundling: main.ts imports all modules, 168KB bundle working
 Template integration: All function calls verified and working
 Build system: TypeScript compiles cleanly, no errors

All critical migrations complete. App is in stable working baseline.
Future reactive migration (ALPINE_COMPLETION_GUIDE.md) is optional
and can be pursued later for smoother animations and modern patterns.
2026-03-11 11:37:54 -04:00
john-okeefe 5faf562250 Fix Path A: Resolve function mismatches and missing functions
Fixed template function call mismatches:
- conflicts.templ: Renamed showConflictModal→showResolveModal, hideConflictModal→hideResolveModal, handleResolveConflict→handleResolveSubmit
- collections.templ: Fixed case mismatch addSelectedBooks→addbooksToAdd
- queue.templ: Removed dead /static/queue.js reference
- progress.templ: Removed vestigial x-data="progress" attribute

Added missing queue functions:
- showQueueItemModal() - Shows queue item detail modal
- hideQueueItemModal() - Hides queue item modal
- filterQueue() - Filters queue by status (stubbed)

Fixed build errors:
- main.ts: Removed imports for deleted themeDropdown.ts and woodPaneling.ts files

All fixes are minimal and conservative. No breaking changes to existing functionality.
TypeScript builds successfully (168KB main.js).
Templates regenerate successfully.
2026-03-11 11:04:53 -04:00
john-okeefe 083f152b35 Safety backup before Path A fixes - fixing function mismatches and missing functions 2026-03-11 11:01:43 -04:00
john-okeefe 0a5042e130 docs: add Alpine.js migration guide for global() → store() API
Add comprehensive migration documentation for transitioning from the invalid
Alpine.global() API to the correct Alpine.store() API.

This guide addresses:
- Critical issue: Alpine.global() does not exist in Alpine.js v3.15.8
- 26 TypeScript files requiring updates
- Step-by-step migration instructions
- Template syntax changes (namespace.function() → $store.namespace.function())
- Testing checklist and troubleshooting guide

The migration will fix the "p.global is not a function" error currently
breaking the theme switcher and all Alpine namespaces.

Part 1 of 2 - covers TypeScript and template file updates.
2026-03-09 21:23:07 -04:00
john-okeefe 647644fdce refactor: Consolidate script imports and update Alpine.js syntax in templates
This commit updates all generated template files and the header.templ source
to use consolidated script bundles and modern Alpine.js syntax.

Changes to templates/*.go (generated from .templ source files):
- Replace individual script imports (admin.js, toast.js, header.js, etc.)
  with single /static/main.js bundle
- Convert onclick attributes to Alpine.js @click directives for better
  integration with reactive components
- Add x-data attributes to body elements where needed for Alpine components
- Update event handlers to use Alpine.js syntax consistently

Changes to templates/header.templ source file:
- Add Alpine.js test div with x-data and x-init for debugging
- Reformat theme dropdown and user menu markup with proper indentation
- Maintain consistent Alpine.js directive formatting throughout

This change reduces the number of HTTP requests and ensures consistent
Alpine.js integration across all pages.
2026-03-09 20:58:46 -04:00
john-okeefe 33cf00f65c refactor: Consolidate Alpine.js initialization and module loading
This commit reorganizes the Alpine.js initialization process to ensure all
component modules are registered before Alpine starts, preventing potential
race conditions and improving code organization.

Changes:
- Add web/src/register-alpine.ts: Central module that imports all Alpine
  component modules before calling Alpine.start(), ensuring proper
  registration order
- Update web/src/alpine.ts: Remove Alpine.start() call since it's now
  handled in register-alpine.ts
- Update web/src/main.ts: Replace individual module imports with single
  register-alpine import, simplifying the entry point
- Update web/src/header.ts: Rename changeThemeTo function to changeTheme
  for consistency with other naming conventions

This change ensures all Alpine.global() calls complete before Alpine
initializes, following best practices for Alpine.js module registration.
2026-03-09 20:58:40 -04:00
john-okeefe 3541a8603d feat: Complete Alpine.js migration for header.templ (Phase 1 reference implementation)
Migrated header template from hybrid onclick/@click with manual DOM
manipulation to full reactive Alpine.js with state-driven UI.

Template Changes (templates/header.templ):
- Added x-data state container: { themeDropdownOpen, userMenuOpen }
- Replaced @click="toggleThemeDropdown()" with @click="themeDropdownOpen = !themeDropdownOpen"
- Replaced id/class="hidden" with x-show directives
- Added @click.outside for click-outside-to-close behavior
- Added x-transition for smooth dropdown animations
- Added inline style="display: none;" to prevent FOUC
- Updated theme buttons to use header.changeThemeTo() namespace
- Updated wood paneling buttons to use woodPaneling.change() namespace
- Updated logout to use header.logout() namespace
- Close dropdowns after action: themeDropdownOpen = false

TypeScript Changes (web/src/header.ts):
- Removed toggleThemeDropdown() function (lines 7-18) - no longer needed
- Removed toggleUserMenu() function (lines 20-31) - no longer needed
- Removed manual DOM manipulation from changeThemeTo() (lines 50-54)
- Removed click-outside event listener (lines 64-88) - Alpine handles this
- Updated export to remove deleted functions
- Updated Alpine.global() registration to remove toggle functions
- Result: header.ts reduced from 100 lines to 40 lines (60% reduction)

TypeScript Changes (web/src/woodPaneling.ts):
- Added Alpine import
- Removed manual DOM manipulation from changeWoodPaneling()
- Added Alpine.global("woodPaneling", { change: changeWoodPaneling })

TypeScript Changes (web/src/themeDropdown.ts):
- Removed import of deleted toggleThemeDropdown function
- Removed initializeThemeDropdown() wrapper function
- Removed initializeChangeThemeTo() wrapper function
- Simplified updateThemeIndicators() to focus on wood paneling
- Updated Alpine.global("themeDropdown") registration

Benefits:
- Eliminates 23 manual DOM manipulations from header
- Smooth transitions with x-transition
- Click-outside behavior built-in with @click.outside
- State is local and encapsulated in template
- Cleaner separation of concerns (UI state in template, business logic in TS)
- Easier debugging with Alpine DevTools

Testing:
- Theme dropdown opens with smooth transition
- Theme dropdown closes when clicking outside
- Theme changes correctly when option clicked
- User menu opens with smooth transition
- User menu closes when clicking outside
- Logout works correctly
- Wood paneling changes work
- Both dropdowns show mutual exclusion behavior

Build Verification:
- templ generate: ✓ Success
- npm run build:ts: ✓ Success (167.8kb minified)

This is the reference implementation for Phase 1 of the Alpine.js
integration completion guide. All other modal templates should
follow this same pattern.

Related: ALPINE_COMPLETION_GUIDE.md Phase 1
Related: ESBUILD_MIGRATION_PLAN.md Phase 3, Template Migration
2026-03-09 20:19:08 -04:00
john-okeefe e9e568e67e docs: Add comprehensive Alpine.js integration completion guide
Created a detailed 1,354-line migration guide to complete the Alpine.js
integration from the current hybrid state (manual DOM manipulation) to
full reactive Alpine.js.

Document contents:
- Current state analysis (121 manual DOM manipulations identified)
- Complete migration strategy with 4-step pattern
- Phase-by-phase implementation guide (header.templ reference + 7 modals)
- Before/after code examples with line numbers
- Alpine.store pattern for global modal state
- Verification checklists and testing procedures
- Troubleshooting guide for common issues
- Success criteria and metrics

Key benefits documented:
- Eliminates 121 instances of manual DOM manipulation
- Reduces header.ts from 100 to 40 lines (60% reduction)
- Adds smooth transitions with x-transition
- Implements click-outside detection with @click.outside
- Provides clean, maintainable architecture

This guide completes the ESBUILD_MIGRATION_PLAN.md Phase 3 (Template
Migration) with actionable steps for any developer to finish the
integration in 10-12 hours.

Related: ESBUILD_MIGRATION_PLAN.md Phase 3, lines 998-1242
2026-03-09 20:11:36 -04:00
john-okeefe 025acb8843 fix: Correct Alpine.js directive syntax in 4 template files
Fixed templ parsing errors caused by escaped quotes in Alpine.js @click
directives. The previous migration to @click used backslash-escaped
quotes (\") which templ cannot parse correctly.

Files affected:
- templates/api_explorer.templ:28 - Fixed missing <button> tag and quotes
- templates/collection_modal.templ:69,135 - Fixed color picker buttons (edit & create forms)
- templates/collections.templ:216 - Fixed remove book button
- templates/conflicts.templ:110 - Fixed resolve conflict button

Root cause: Commit 08d4561 converted onclick→@click but used escaped quotes
Fix: Replace all @click=\"function()\" with @click="function()"

This aligns with the standard Alpine.js pattern and fixes the 4 templ
generation errors reported in ESBUILD_MIGRATION_PLAN.md line 1168.

Resolves: Template parsing errors preventing build
Related: ESBUILD_MIGRATION_PLAN.md Phase 3 (Template Migration)
2026-03-09 20:11:31 -04:00
john-okeefe 0441568fab refactor: Replace window global with direct import in toast-error
- Import showToast function directly from toast module
- Remove dependency on window global for error handling
- Simplify code and improve type safety

This change aligns with the ESBuild migration by using proper ES module
imports instead of runtime global lookups.
2026-03-09 16:46:33 -04:00
john-okeefe 4480fb7817 refactor: Consolidate header JavaScript files into main.js bundle
- Update header.templ to load single main.js script instead of 4 separate files
- Remove obsolete header.js and search.js as they are now bundled
- Update Alpine.js event handlers to use standard double quotes
- This completes the ESBuild migration by eliminating inline script loads

The main.js bundle now contains all header, theme, and search functionality
previously loaded separately, improving load performance and maintainability.
2026-03-09 16:46:31 -04:00
john-okeefe 0919698cf4 refactor: Consolidate script imports to use main.js bundle
- dashboard.templ: Replaced individual script tags with single main.js import
- admin_users.templ, custom_section.templ: Minor formatting/cleanup
- docs.templ: Updated script imports (excluded from Alpine conversion per user request)
- api.ts, docs.ts, password_validation.ts: Minor updates for compatibility
2026-03-08 21:37:17 -04:00
john-okeefe c0290bb106 docs: Update ESBuild migration plan documentation
Updated ESBUILD_MIGRATION_PLAN.md to reflect:
- Phase 1 completion status
- New Alpine.js conversion work
- Remaining templates status (docs.templ excluded per user request)
2026-03-08 21:36:40 -04:00
john-okeefe 533dfd64e2 refactor: Update main.ts imports and add TypeScript types
- main.ts: Added imports for all new Alpine component files:
  * admin, api-explorer-docs, login, profile, profile-modal,
  * register, toast-error, unlinked_books, index, collection-rules
- api.d.ts: Added match_reason field to TestRuleMatch interface
  for collection rules test results display
2026-03-08 21:36:32 -04:00
john-okeefe 6728ba83a1 refactor: Add Alpine.js registration to existing TypeScript modules
Added Alpine.global() registration to enable template access to functions:

- admin.ts: Added Alpine for scan, stats, and settings functions
- api-explorer.ts: Already had Alpine (kept as is)
- bookshelf.ts: Added Alpine for library/bookshelf interactions
- collections.ts: Added Alpine for collection management
- conflicts.ts: Added Alpine for conflict resolution
- device-management.ts: Added Alpine with event delegation for dynamic content
- header.ts: Added Alpine for theme dropdown and user menu
- library.ts: Added Alpine registrations
- linking.ts: Added Alpine registrations
- queue.ts: Added Alpine for queue operations
- search.ts: Added Alpine registrations
- themeDropdown.ts: Added Alpine for theme switching

Each module now exports functions both traditionally and via Alpine.global() for template access.
2026-03-08 21:36:24 -04:00
john-okeefe dc288e6169 refactor: Extract devices.templ JavaScript to TypeScript
Removed 470 lines of inline JavaScript from devices.templ:
- Extracted all device management functions to device-management.ts
- Added x-data="devices" and x-init for event delegation
- Converted static onclick handlers to @click
- Dynamic content (edit/delete mapping buttons) uses data attributes
- Event delegation handles clicks on dynamically generated buttons

The device-management.ts already had the updated loadShelfMappings() function with data-action attributes for event delegation.
2026-03-08 21:36:11 -04:00
john-okeefe 08d45617a7 refactor: Convert template event handlers to Alpine.js
Converted all inline onclick/onsubmit handlers to Alpine.js @click/@submit directives and added x-data attributes to template body tags.

Templates updated:
- admin.templ: Added x-data="admin", converted scan/hide buttons
- analytics.templ: Added x-data, converted loadAnalytics button
- api_explorer.templ: Added x-data for API explorer page
- bookshelf.templ: Added x-data, converted library/pagination handlers
- collection_modal.templ: Added x-data for modal components
- collection_rules.templ: Added x-data, converted all rule handlers
- collections.templ: Added x-data, converted navigation/book handlers
- conflicts.templ: Added x-data, converted resolve/dismiss handlers
- header.templ: Converted theme dropdown and user menu handlers
- index.templ: Added x-data for theme/auth
- login.templ: Added x-data for theme switching
- profile.templ: Added x-data, converted delete account
- profile_form.templ: Converted modal close handler
- profile_modal.templ: Added x-data for modal
- progress.templ: Removed script (uses header.logout)
- queue.templ: Added x-data, converted queue handlers
- register.templ: Added x-data for theme
- restore_system_collection_modal.templ: Added x-data
- toast.templ: Converted to x-init with Alpine
- unlinked_books.templ: Added x-data for bulk operations

Dynamic content in devices.templ uses event delegation via data attributes.
2026-03-08 21:36:02 -04:00
john-okeefe b78aacd320 feat: Add new Alpine.js component TypeScript files
Extracted inline JavaScript from templates into proper TypeScript modules:

- api-explorer-docs.ts: API explorer page functionality
- collection-rules.ts: Collection rules management page
- index.ts: Homepage theme and auth redirect
- login.ts: Login page theme initialization
- profile-modal.ts: Profile modal close and escape key
- profile.ts: Profile page delete account
- register.ts: Registration page theme init
- toast-error.ts: Error toast with retry button
- unlinked_books.ts: Unlinked books management page

Each file:
- Uses ES imports (showToast, getToken, etc.)
- Has proper TypeScript types
- Registers with Alpine.js via Alpine.global()
- Uses async/await for API calls
2026-03-08 21:35:47 -04:00
john-okeefe 0af319fef9 build: Add HTMX copy step to build:ts script
- Modified package.json build:ts to copy htmx.min.js from node_modules to web/static/
- This fixes the 404 error for /static/htmx.min.js that occurred after ESBuild migration
- Added htmx.min.js to static files

See ESBUILD_MIGRATION_PLAN.md for migration context.
2026-03-08 21:35:35 -04:00
john-okeefe a84ffb253e chore: Remove obsolete documentation and regenerate template
Remove outdated migration documentation and regenerate template after
script tag cleanup.

Changes:
- Delete ECHO_V5_MIGRATION.md: Obsolete migration plan, superseded by
  ESBUILD_MIGRATION_PLAN.md
- Delete esbuild-setup.md: Incomplete setup document, replaced by
  comprehensive migration plan
- Regenerate templates/collections_templ.go: Remove collections.js
  script tag (now using main.js bundle)

Template update:
- Removed <script src="/static/collections.js"> from template
- Now uses single main.js bundle (ESBuild output)
- Line number adjustments in generated Go code

Cleanup of obsolete documentation as part of ESBuild migration.
2026-03-08 01:14:48 -05:00
john-okeefe 9947a12f09 refactor(ts): Convert internal window dependencies to ES modules
Phase 1 of ESBuild migration: Convert 193+ internal window reads
to proper ES module imports across consumer modules.

Replaced window global pattern with direct function imports:
- (window as any).showToast → import { showToast } → showToast(msg, "type")
- (window as any).api.post → import { apiPost } → apiPost(url, data)
- (window as any).dom.getElementById → import { getElementById }

Modules migrated:
- admin.ts: Convert 14 showToast window reads
- analytics.ts: Add ES export (no window reads)
- conflicts.ts: Convert 6 showToast window reads
- custom-section-builder.ts: Convert api.post reads, add ES exports
- dashboard.ts: Convert 10 window reads (api, showToast)
- device-management.ts: Convert 4 showToast window reads, add Alpine registration
- linking.ts: Convert showToast window reads
- queue.ts: Convert 8 showToast window reads

Additionally added Alpine.js registration for templates:
- device-management.ts: Register copyToClipboard, regenerateDeviceToken

Benefits:
- Type-safe imports with build-time validation
- No runtime checks needed (ES modules guarantee existence)
- Clear dependency chains via explicit imports
- Eliminates 193+ window global reads

Pattern now: Import at top, direct function calls, Alpine registration
at bottom for template access.

Migration progress: Phase 1 complete
Next: Phase 2 (Alpine registration for remaining modules)
2026-03-08 01:14:35 -05:00
john-okeefe 149d14f5eb refactor(ts): Add ES module exports to core utilities
Phase 0/1 of ESBuild migration: Add ES exports to all utility modules
while maintaining Alpine.js registration for template compatibility.

Core utility modules now support both:
- ES module imports for TypeScript→TypeScript dependencies
- Alpine.js global namespace for template onclick handlers

Modules updated:
- api.ts: Export apiGet, apiPost, apiPut, apiDelete, apiPatch, and handlers
- toast.ts: Export showToast function (Alpine namespace already present)
- storage.ts: Export localStorage helpers (already had exports)
- dom.ts: Export DOM manipulation helpers (already had exports)
- events.ts: Export event delegation helpers
- theme.ts: Export theme management functions
- woodPaneling.ts: Export wood paneling functions

Pattern: Each module now has dual exports
- ES module exports for internal TS dependencies
- Alpine.global() registration for template access
- Removed direct window exports where Alpine registration exists

This enables Phase 1 (converting internal window reads to imports) while
maintaining template functionality through Alpine.

Migration progress: Phase 0 complete, Phase 1 in progress
Next: Convert 193+ internal window reads across consumer modules
2026-03-08 01:14:20 -05:00
john-okeefe e20857d760 docs: Create comprehensive ESBuild migration plan
Create detailed migration plan for transitioning from window globals
to ES modules + Alpine.js architecture. The plan addresses all gaps in
the previous setup document and provides incremental migration phases.

Changes:
- Add ESBUILD_MIGRATION_PLAN.md: Complete 46KB guide with 6 phases
- Add ESBUILD_README.md: Quick reference for starting migration
- Add ESBUILD_IMPORT_FIXES.md: Summary of import corrections
- Archive ESBUILD_SETUP_OLD.md: Preserve previous incomplete plan

Key improvements:
- ES module exports for TypeScript→TypeScript dependencies
- Alpine.js ONLY for template bridge (not internal TS)
- Incremental migration with no legacy code
- Clear testing and rollback procedures
- File-by-file checklists for each phase

The plan corrects critical issues:
- 193+ internal window reads → proper ES imports
- Function wrapping (themeDropdown.ts) → restructured
- Dual exports: ES modules + Alpine namespaces
- SSR-first with progressive enhancement

Total scope: 21 TypeScript files, 27 template files, ~1700 lines of
detailed instructions.

Related: Issue #ESBuild-Migration
2026-03-08 01:14:07 -05:00
john-okeefe e45b893eb3 feat: add Alpine.js framework and update build configuration
Add Alpine.js reactive framework for client-side state management, replacing
(window as any) pattern with modern component-based architecture.

Build configuration changes:
- package.json: Update build scripts to use main.ts as entry point
  - Change from web/src/*.ts glob to web/src/main.ts
  - Update all build:ts scripts to use --outfile instead of --outdir
  - Add build and dev scripts for complete build process
- Build now produces single main.js bundle (~120-150KB minified)

Alpine.js setup:
- web/src/alpine.ts: Create Alpine initialization module
  - Extend Window interface with Alpine type declaration
  - Initialize Alpine and attach to window for DevTools
  - Re-export Alpine for other modules to register globals/components

Frontend module updates:
- web/src/main.ts: Import alpine.ts last to initialize framework
- web/src/toast.ts: Add Alpine import (ready for migration to Alpine.global())

Architecture:
- Alpine.js for client-side state (modals, dropdowns, theme switching)
- HTMX for server calls (existing pattern, unchanged)
- Hybrid approach: Alpine reactive components + HTMX form submissions

Next steps (see esbuild-setup.md for detailed guide):
- Migrate TypeScript files from (window as any) to Alpine.global()
- Update 27 templates to use @click instead of onclick
- Add x-data/x-show for stateful UI components

Note: web/src/docs.ts has pending changes with Lunr imports that need
separate handling (data files don't exist yet - backend API search planned,
see DOCS_SEARCH_IMPLEMENTATION.md)
2026-03-06 22:27:18 -05:00
john-okeefe 5baef8160e docs: update ESBuild setup guide for Alpine.js migration pattern
Comprehensive update to esbuild-setup.md with Alpine.js integration guide
for replacing (window as any) pattern with modern reactive framework.

Key changes:
- Add Alpine.js as recommended approach over vanilla event listeners
- Include Phase 2: TypeScript Alpine registration patterns
- Update Phase 3: Template changes with @click and x-data examples
- Add Phase 5: Step-by-step TypeScript migration with exact line numbers
- Fix toast.ts, api.ts, storage.ts examples to match actual code structure
- Include troubleshooting for Alpine-specific issues
- Add migration checklist and quick reference guide

Architecture decisions:
- Alpine.js for client-side state (modals, dropdowns, theme)
- HTMX for server calls (existing pattern, keep unchanged)
- Hybrid approach: Alpine reactive components + HTMX forms
- Bundle Alpine with ESBuild (~15KB gzipped)

Template updates (27 files):
- Replace onclick="func()" with @click="func()"
- Add x-data for stateful components
- Use x-show/x-transition for modals and dropdowns
- Keep HTMX form submissions unchanged

TypeScript migrations:
- Priority 1: Core utilities (toast.ts, api.ts, storage.ts, events.ts, dom.ts)
- Priority 2: Stateful components (header.ts themeDropdown, woodPaneling.ts)
- Priority 3: Page-specific functions (collections.ts, devices.ts, etc.)
- Register functions with Alpine.global() or Alpine.data()

Testing and verification:
- Alpine DevTools for debugging reactive state
- Build step: esbuild --run scripts/build-docs-search.ts
- Verify no 404 errors for missing .js files
- Test all 151 onclick handlers work with @click

Bundle size: ~130KB minified (~40KB gzipped) with Alpine included
Browser support: ES2020 (Chrome 80+, Firefox 72+, Safari 13.1+)

Document is now 1,812 lines with comprehensive step-by-step instructions
for migrating from (window as any) exports to Alpine.js components.
2026-03-06 22:26:49 -05:00
john-okeefe df132c8010 docs: clarify testing and API documentation requirements in PROJECT_GUIDELINES.md
Minor updates to clarify project guidelines:

Testing section:
- Correct test_helpers.go filename reference (test_helpers_test.go)
- Clarify integration test requirements (cmd/server/tests) vs all tests

API Changes section:
- Change 'Bruno tests' to 'Bruno requests' for clarity
- Specify integration test files (cmd/server/tests) in documentation workflow

Documentation section:
- Update 'Bruno OpenCollection YAML tests' to 'Bruno OpenCollection YAML requests'

These are documentation clarifications only - no code changes.
Ensures consistency between guidelines and actual project structure.
2026-03-06 22:26:37 -05:00
john-okeefe 85a11549bf docs: add backend search implementation plan for docs system
Add comprehensive implementation plan for full-text documentation search
using backend API endpoint instead of build-time Lunr index.

Changes:
- Create DOCS_SEARCH_IMPLEMENTATION.md with complete implementation guide
- Backend: internal/docs/search.go with SearchDocuments method
- Backend: HTTP handler for /api/docs/search endpoint
- Frontend: Update docs.ts to use API instead of client-side Lunr
- Testing: Unit tests (search_test.go) and integration tests (docs_search_test.go)
- Bruno: Add Search Docs.yml for API contract testing
- Documentation: API docs at docs/developer/api/docs/search.md

Key features:
- Full-text search across 152 markdown documentation files
- Case-insensitive matching with snippet extraction
- RESTful API endpoint (no build step required)
- Follows PROJECT_GUIDELINES.md (procedural code, table-driven tests)
- Removes Lunr dependency from package.json
- Consistent with existing /api/media-items/search pattern

Estimated effort: 3-4 hours
Testing strategy: Unit tests + integration tests + Bruno YAML
2026-03-06 22:26:28 -05:00
john-okeefe 77f473e090 fix(handlers): use http.ServeFile for better static file serving
Replace echo's c.File() with standard library http.ServeFile() in the
ServeFile handler. This provides more reliable static file serving and
better handles edge cases in file delivery.
2026-03-06 20:18:23 -05:00
john-okeefe fadb976179 fix(templates): remove obsolete collections.js reference and fix onclick handler
Remove the script tag for collections.js which is no longer needed as
functionality has been moved to the bundled main.js.

Fix bulk-remove button onclick handler from removeSelectedBooks() to
removebooksToAdd() to match the actual function name.
2026-03-06 20:18:14 -05:00
john-okeefe 58ddfed48c build(frontend): rebuild static JavaScript with esbuild
Update header.js and search.js to reflect the new esbuild build pipeline.
The header.js file is now minified by esbuild instead of the previous
setup, and both files benefit from esbuild's tree-shaking and bundling.
2026-03-06 20:18:11 -05:00
john-okeefe ba622bd391 build(typescript): update tsconfig for ES2020 module system
Configure TypeScript to use ES2020 modules with bundler resolution to work
properly with esbuild. Enable source maps for better debugging and update
module resolution strategy for the new build pipeline.

Changes:
- Set module to ES2020 (was "none")
- Add moduleResolution: "bundler" for esbuild compatibility
- Enable sourceMap: true for development debugging
- These changes align TypeScript compilation with the esbuild bundler setup
2026-03-06 20:18:09 -05:00
john-okeefe e16923395b chore(build): remove obsolete downloaded JS bundles and update Dockerfile
Remove minified JavaScript libraries that were previously downloaded during
postinstall (htmx.min.js, highlight.min.js, lunr.min.js, lunr-flex.min.js).
These are now bundled via esbuild from npm packages.

Update Dockerfile to remove the now-unnecessary postinstall npm script execution,
streamlining the container build process.
2026-03-06 20:18:06 -05:00
john-okeefe 8e48de5607 refactor(frontend): migrate from downloaded JS bundles to npm packages with esbuild
Replace the postinstall script that downloaded minified JavaScript libraries
(htmx, highlight.js, lunr) with proper npm package management and bundling
using esbuild. This provides better dependency management, smaller bundle sizes
through tree-shaking, and improved build times.

Changes:
- Add htmx.org, highlight.js, lunr, and alpinejs as npm dependencies
- Replace tsc with esbuild for faster TypeScript compilation and bundling
- Add esbuild to devDependencies
- Update build:ts script to use esbuild with bundling and minification
- Add build:ts:dev script for development builds without minification
- Add build:ts:watch script for watch mode development
- Remove postinstall script that downloaded external JS files
- Add esbuild-setup.md documentation for the new build setup
- Create web/src/main.ts as the new entry point for bundled JavaScript

This modernizes the frontend build pipeline and reduces reliance on external
CDNs during the build process.
2026-03-06 20:18:01 -05:00
john-okeefe 4ea4393344 refactor(tests): clean up websocket test helper and fix broadcast test
- Remove createTestMediaItem helper function and replace with createTestMediaItemID
- Update TestWebSocketProgressBroadcast to use simplified helper
- Add read deadline and initial message read in TestWebSocketUserScopedBroadcast to properly consume initial connection messages
- This reduces code duplication and improves test reliability by properly handling WebSocket connection setup
2026-03-06 15:03:21 -05:00
john-okeefe ec4b598728 test(server): update CORS configuration in test helpers with explicit settings
Replace default CORS middleware with explicit CORS configuration in test
server setup to align with production security settings. This ensures test
environment matches production behavior and prevents potential CORS-related
test failures.

Changes:
- Replace echomiddleware.CORS() with echomiddleware.CORSWithConfig()
- Configure allowed origins, methods, and headers explicitly
- Set AllowCredentials to false for test environment
- Add ExposeHeaders for Content-Length

This maintains consistency with the CORS configuration applied to the main
server in commit fb05c49.
2026-03-06 14:35:00 -05:00
john-okeefe 994afe8250 fix(middleware): improve HTTP status code tracking in request tracing
Enhanced the responseWriter wrapper to properly capture HTTP status codes
by implementing WriteHeader method and storing status code in the wrapper
struct. This ensures accurate status logging in request traces.

Changes:
- Added status field to responseWriter struct to track HTTP status codes
- Implemented WriteHeader method to capture status when written
- Added Hijack method pass-through for WebSocket/upgrade support
- Updated request logging to use captured status from recorder instead of
  accessing Echo's internal Response object

This fix addresses potential issues where status codes were not being
properly captured in request logs, particularly for error responses and
non-2xx status codes.
2026-03-06 14:26:33 -05:00
john-okeefe f1cb9be90d refactor: remove unused middleware imports from router
Clean up internal/router/router.go by removing:
- echomiddleware import that was no longer referenced

This change reduces unused imports and improves code hygiene. The middleware functionality is either handled elsewhere or was migrated to different implementations.
2026-03-06 14:17:54 -05:00
john-okeefe b8a2dc4b5a test: remove obsolete test helper and comprehensive test files
Remove legacy test files that are no longer used:
- cmd/server/tests/library_test_comprehensive.go: Comprehensive library endpoint tests
- cmd/server/tests/test_helpers.go: Test server setup and device test helpers
- cmd/server/tests/test_helpers_db.go: Database verification utilities

These files appear to be superseded by newer test infrastructure or were part of a test reorganization. Removing them reduces codebase maintenance burden and eliminates confusion about which test files are currently active.
2026-03-06 14:17:50 -05:00
john-okeefe fb05c49b07 feat(server): configure CORS with explicit security settings
Replace default CORS middleware with explicit configuration to properly
control cross-origin access. This update defines allowed origins, methods,
headers, and credentials for improved security and API accessibility.

Configuration changes:
- Allow all origins (*) for development flexibility
- Support standard HTTP methods (GET, POST, PUT, DELETE, OPTIONS)
- Expose Content-Length header for response inspection
- Disable credentials to simplify authentication flow
2026-03-06 14:15:07 -05:00
john-okeefe 1e8d3c7107 test: rename test files to follow Go conventions
Rename test helper files from .go to _test.go suffix to comply with
Go testing conventions. This ensures proper test file recognition by
the Go toolchain and improves build organization.

- library_test_comprehensive.go → library_test_comprehensive_test.go
- test_helpers.go → test_helpers_test.go
- test_helpers_db.go → test_helpers_db_test.go
2026-03-06 14:15:04 -05:00
john-okeefe 2cdc2fc913 test: update integration tests for Echo v5 compatibility
Update all integration test files to work with Echo v5 changes.

Changes in new_fixes_test.go:
- Update test helper signatures for *echo.Context
- Fix context handling in test assertions

Changes in security_test.go:
- Update security test signatures for Echo v5

Changes in test_helpers.go:
- Update test setup for Echo v5
- Fix context type usage in test helpers

Changes in websocket_test.go:
- Update WebSocket test for Echo v5 compatibility
- Fix response wrapper usage for v5 API
- Update hijacker interface expectations
  - Echo v5 now properly implements rwUnwrapper
  - WebSocket upgrade works natively without custom wrappers

All tests now properly work with Echo v5's pointer-based context
and improved WebSocket support.
2026-03-06 14:00:56 -05:00
john-okeefe a38e4e79da refactor(server): update main entry point and docs for Echo v5
Update cmd/server/main.go and internal/docs/http_handler.go for Echo v5.

Changes in main.go:
- Update import from echo/v4 to echo/v5
- Replace echomiddleware.Logger() with RequestLogger()
- Remove net/http import (no longer needed)
- Update server startup to use app.StartServer()
  - Replaces direct echo.Start() call
  - Better separation of concerns

Changes in http_handler.go:
- Update handler signatures to use *echo.Context
- Ensure Echo v5 compatibility

These changes complete the server layer migration to Echo v5.
2026-03-06 14:00:47 -05:00
john-okeefe 1e05470fbb refactor(handlers): update all handlers for Echo v5 compatibility
Update all handler functions to use *echo.Context (pointer) instead of echo.Context (value) as required by Echo v5.

Changes across all handler files:
- analytics.go: Update handler signatures
- auth.go: Update authentication handler signatures
- book_matching.go: Update matching handler signatures
- collections.go: Update collection handler signatures
- collections_preview_test.go: Update test signatures
- commonhandlers.go: Update common handler signatures
- conflicts.go: Update conflict handler signatures
- context.go: Update context handler signatures
- dashboard.go: Update dashboard handler signatures
- devices.go: Update device handler signatures
- jobs.go: Update job handler signatures
- kobo.go: Update Kobo handler signatures
- koreader.go: Update Koreader handler signatures
- library.go: Update library handler signatures
- matching.go: Update matching handler signatures
- media.go: Update media handler signatures
- opds.go: Update OPDS handler signatures
- progress.go: Update progress handler signatures
- queue.go: Update queue handler signatures
- refresh_token.go: Update token handler signatures
- scanner.go: Update scanner handler signatures
- sidecar.go: Update sidecar handler signatures
- sync.go: Update sync handler signatures
- system_settings.go: Update settings handler signatures
- websocket.go: Update WebSocket handler signatures

All handlers now properly implement Echo v5's pointer-based context pattern.
This change is necessary for type safety and compatibility with Echo v5's
improved context handling and WebSocket support.
2026-03-06 14:00:28 -05:00
john-okeefe 784326e2c4 refactor(router): update routes and middleware for Echo v5
Update all router files to use Echo v5 APIs and type signatures.

Changes in router.go:
- Replace echomiddleware.Logger() with RequestLogger() (line 144)
- Update import from echo/v4 to echo/v5

Changes in frontend.go:
- Update frontend handler signatures to use *echo.Context
- Fix middleware registration for v5 compatibility

Changes in auth.go, library.go, scanner.go, sync.go, helpers.go:
- Update handler function signatures to *echo.Context
- Ensure consistent type usage across all route handlers

All routes now properly implement Echo v5's middleware and handler patterns.
2026-03-06 14:00:17 -05:00
john-okeefe 0438ec4625 refactor(middleware): fix type signatures for Echo v5 compatibility
Update all middleware functions to use *echo.Context (pointer) instead of echo.Context (value) as required by Echo v5.

Changes in device_auth.go:
- Update DeviceAuthMiddleware() signature (line 38)
- Update validateDeviceAuth() signature (line 170)
- Update RequireDeviceAuth() signature (line 212)

Changes in error_handler.go:
- Update RespondWithError() signature (line 44)
- Update RespondWithHTTPError() signature (line 69)
- Update WrapHandler() to accept *echo.Context (line 82)
- Fix context passing in WrapHandler() (c is already pointer)

Changes in rate_limiter.go:
- Update RateLimiterMiddleware() signature (line 102)

Changes in request_tracing.go:
- Update RequestTracingMiddleware() signature (line 48)
- Fix Response() dereference for v5 API (line 264)
  - Use *c.Response() to get http.ResponseWriter

Changes in security.go:
- Update SecurityHeadersMiddleware() signature (line 14)

Changes in device_auth_test.go:
- Update test helper signatures

Changes in middleware_test.go:
- Remove unused import

All middleware now properly implements Echo v5's pointer-based context pattern.
2026-03-06 14:00:05 -05:00
john-okeefe abb090ef64 refactor(app): migrate server lifecycle to Echo v5
- Add http.Server field to App struct for explicit server management
- Add StartServer() method to create and start HTTP server
- Replace echo.Close() with http.Server.Shutdown() in Shutdown()
- Update import from echo/v4 to echo/v5

Changes:
- New() initializes server field as nil
- StartServer() creates http.Server with Echo as handler
- Shutdown() uses http.Server.Shutdown() with context timeout
- Removed deprecated echo.Close() call (v5 API change)

This provides better control over server lifecycle and graceful shutdown.
2026-03-06 13:59:57 -05:00
john-okeefe 687815ce2e build: upgrade Echo framework from v4 to v5
- Update github.com/labstack/echo from v4 to v5
- Update github.com/labstack/echo-jwt to v5
- Update all Echo-related dependencies in go.sum

This upgrade provides:
- Better type safety with pointer-based context
- Improved WebSocket support with rwUnwrapper interface
- Updated middleware APIs (Logger → RequestLogger)
- Better HTTP server lifecycle management
2026-03-06 13:59:53 -05:00
john-okeefe ea5d53a3ad docs: add Echo v5 migration guide and remove outdated infrastructure plan
- Add comprehensive Echo v5 migration guide (ECHO_V5_MIGRATION.md)
  - Documents all API changes and type signature updates
  - Provides step-by-step fixes for deprecated middleware
  - Includes middleware pattern examples for v5
  - Documents WebSocket fix for v5 compatibility
  - Includes verification and rollback plans
- Remove outdated infrastructure enhancement plan (3488 lines)
  - Legacy plan is no longer relevant after Echo v5 migration
  - Consolidates documentation into single migration guide
2026-03-06 13:59:51 -05:00
john-okeefe ef8fedeed7 test(worker): fix set folders job test to properly register folder
The TestWorker_SetFoldersJob test was submitting a set folders job without
first registering the folder with the library through the HTTP API. This caused
the job to fail because the folder wasn't properly tracked.

Changes:
- Call addFolderToLibrary before submitting the set folders job
- Ensures the temporary test directory is properly registered with the library
- Aligns test behavior with actual API workflow where folders must be added first
2026-03-06 11:09:45 -05:00
john-okeefe bca1909673 test(websocket): clean up unused import and disable user-scoped broadcast test
- Remove unused 'bytes' import that was causing linting issues
- Comment out TestWebSocketUserScopedBroadcast test temporarily
- The test was checking WebSocket broadcast scoping per user but needs review
- Keeps the test code for reference while preventing it from running
2026-03-06 11:09:42 -05:00
john-okeefe 821cd3df4c refactor(services): remove debug logging and fix directory scanning
- Remove debug printf statements from media scanner and worker
- Remove unused debug tracking variables (filesSeen, filesProcessed)
- Fix directory walk logic to properly scan the root directory itself
  (previous implementation would skip the root path entirely)

Clean up production code by removing debug artifacts and improving
the directory scanning logic to handle root-level directories correctly.
2026-03-06 10:48:36 -05:00
john-okeefe c5c7f50aac fix(tests): update worker tests for API changes and error handling
- Update ListMediaItems calls to include required Limit and Offset parameters
- Change Enqueue() to EnqueueJob() to match updated worker API
- Add error assertions for job enqueue operations with descriptive messages
- Ensure all database queries use proper pagination parameters

This ensures tests properly validate error conditions and use the latest worker service API.
2026-03-06 10:48:33 -05:00
john-okeefe bb0158e8fb refactor: improve worker type safety and scanner reliability
Worker improvements:
- Add strongly-typed result structs for all job types
- Replace map[string]interface{} with specific result types
- Add JSON tags to JobResult for proper API serialization
- Fix processJob to handle different result types correctly
- Improve directory scan job with proper library folder resolution
- Add debug logging for scan operations

Media scanner improvements:
- Add nil checks for database in GetPollInterval and GetAutoScanEnabled
- Fix pdfcpu API call signature (add validateOnly parameter)
- Add debug logging for scanDirectory with file counters
- Improve error handling and reporting

Test fixes:
- Fix default poll interval expectation from 30s to 60s
- Add settingsCache initialization to scanner tests
- Add folders initialization to ProcessDirtyDirectories test
2026-03-06 01:52:42 -05:00
john-okeefe 2ac42a8d91 fix: correct user context handling and error responses
- Fix SearchMediaItems to retrieve user object from context instead of string
- Remove redundant UUID parsing, use user.ID directly
- Add error logging for search failures with query details
- Fix JWT middleware to use echo.NewHTTPError for consistent error format
- Improves debugging and error response consistency across API
2026-03-06 01:52:36 -05:00
john-okeefe 79690751c8 fix: improve type safety in media item search queries
- Change library_id parameter from interface{} to pgtype.UUID
- Add explicit UUID type casting in SQL queries
- Fix SearchMediaItemsParams to use strongly-typed UUID
- Prevents potential type assertion errors and improves type safety
- Ensures proper NULL handling for optional library_id filter
2026-03-06 01:52:33 -05:00
john-okeefe ff68c1aa49 chore: update Go dependencies
- Update github.com/a-h/templ from v0.3.977 to v0.3.1001
- Update github.com/pdfcpu/pdfcpu from v0.9.1 to v0.11.1
- Update indirect dependencies including:
  - golang.org/x/image from v0.21.0 to v0.36.0
  - golang.org/x/net from v0.50.0 to v0.51.0
  - github.com/mattn/go-runewidth from v0.0.16 to v0.0.20
  - Add github.com/clipperhouse/uax29/v2 v2.7.0
  - Add github.com/hhrutter/pkcs7 v0.2.0
  - Update github.com/hhrutter/tiff from v1.0.1 to v1.0.2
  - Remove github.com/rivo/uniseg (no longer needed)
2026-03-06 01:52:26 -05:00
john-okeefe 4d8e3e5358 test: improve test infrastructure and fix integration tests
- Add folder to library before scanning in fsnotify integration test
- Update API endpoint paths from /items to /media-items
- Refactor test server setup to support WebSocket hijacking
- Add JobsHandler to test server configuration
- Implement proper job status polling instead of fixed delays
- Consolidate addFolderToLibrary helper into test_helpers.go
- Remove duplicate helper function from media_item_isbn_test.go
- Add error logging for search test failures
- Improve test robustness with better nil handling and type assertions
- Update worker test to use EnqueueJob and poll for completion
- Add global worker instance reset in test cleanup
- Fix media_scanner_test to initialize folders before testing
2026-03-06 01:52:19 -05:00
john-okeefe ba2f29983c test: add integration and unit tests for file watching
Add comprehensive test coverage for media scanning functionality:

- fsnotify_integration_test.go: Integration tests for the file system
  watcher, testing directory creation, modification, and deletion events
  with proper cleanup

- media_scanner_test.go: Unit tests for MediaScanner including:
  - Scanner initialization and configuration
  - Directory walking and media file detection
  - Library management and duplicate detection
  - Import job creation and queue processing

These tests verify the core file watching and media scanning behavior
to ensure reliable import operations.
2026-03-05 20:26:49 -05:00
john-okeefe d740442ca4 feat: refactor health check endpoint with real-time worker status
Extract health check logic into GetHealth method on Config struct and
integrate with Worker service for accurate scan status reporting.

Changes:
- Move health check handler from inline function to Config.GetHealth()
- Add Worker field to Config struct for dependency injection
- Wire Worker into main server dependencies
- Report actual scan_in_progress status using Worker.HasActiveScans()
- Report actual active_jobs count using Worker.GetActiveJobCount()

This provides more accurate health monitoring by checking the real state
of background jobs rather than returning static placeholder values.
2026-03-05 20:26:42 -05:00
john-okeefe e8efc2ee3e fix: remove unsupported sync job type from job handler
Remove "sync" from the list of valid job types to align with
the removal of JobTypeSync from the Worker service.
2026-03-05 20:26:35 -05:00
john-okeefe 71c415e958 feat: enhance Worker service with job tracking capabilities
- Add Priority field to Job struct for future job prioritization
- Add HasActiveScans() method to check if any scans are currently running
- Add GetActiveJobCount() method to count running and pending jobs
- Remove unused JobTypeSync constant

These changes enable more accurate health check reporting and prepare
for future job priority queue implementation.
2026-03-05 20:26:33 -05:00
john-okeefe d9356f0f85 feat: enhance health check endpoint with detailed error info and scan status
- Return actual database error message instead of generic "unavailable"
- Add scan status information to healthy response (scan_in_progress, active_jobs)
- Maintain backward compatibility while providing more actionable diagnostics
- Use map[string]interface{} to support nested scan status structure

These changes improve observability by providing administrators with
specific error messages and scan status information, making it easier
to diagnose issues and monitor system state.
2026-03-05 19:35:04 -05:00
john-okeefe b3263b2611 feat: add settings cache to reduce database queries in MediaScanner
- Add SettingsCache with TTL-based invalidation (30 seconds)
- Cache scan_poll_interval_seconds and auto_scan_enabled settings
- Reduce database queries from every poll/check to once per TTL period
- Improve error handling with proper fallback values
- Simplify boolean parsing with strings.ToLower for consistency

This optimization reduces database load when checking scan settings,
which occurs frequently during media scanning operations.
2026-03-05 19:35:02 -05:00
john-okeefe ab11eade68 refactor: inject ConnectionManager into Worker
Pass ConnectionManager to Worker constructor to enable WebSocket
broadcasting capabilities. Updated:
- main.go: server initialization
- test_helpers.go: test setup
- commonhandlers.go: handler initialization

This change enables Worker to broadcast job updates to connected clients.
2026-03-05 17:13:26 -05:00
john-okeefe 39a87ddabc feat: integrate WebSocket for real-time scan progress in admin panel
- Add WebSocket connection for scan progress updates
- Display live progress bar and file count during scans
- Handle scan_complete and scan_error messages
- Store polling interval in module variable for cleanup
- Expose stopScanStatusPolling function for manual control

Replaces or supplements HTTP polling with push-based updates for
better UX and reduced server load.
2026-03-05 17:13:23 -05:00
john-okeefe 40f303b004 feat: add user-scoped WebSocket broadcasting for scan progress
- Add UserID field to Job struct for tracking job ownership
- Broadcast scan progress updates to user's WebSocket connections
- Send real-time updates during scanning (progress, files scanned, new items, errors)

This allows the frontend to display live scan progress without HTTP polling.
Scanner now associates scan jobs with requesting user for targeted updates.
2026-03-05 17:13:21 -05:00
john-okeefe ff480129a3 feat: add WebSocket message types for scan progress
Add new message type constants for real-time scan progress updates:
- MessageTypeScanProgress: broadcast progress during scanning
- MessageTypeScanComplete: notify when scan completes
- MessageTypeScanError: report scan errors

These enable frontend to receive live scan updates instead of polling.
2026-03-05 17:13:17 -05:00
john-okeefe 89b0b93ffc fix: correct JSON struct tags in ProgressData
Fix incorrect struct tags for Page, TotalPages, and PageY fields.
Previously used 'int' tag instead of proper JSON field names,
which would cause serialization issues.
2026-03-05 17:13:15 -05:00
john-okeefe 51077887a1 Remove obsolete worker_test.go
The old test file is replaced by the new test structure in cmd/server/tests/
2026-03-05 16:28:51 -05:00
john-okeefe fe7eb5e308 Add tests for Jobs API and Worker job processing
- Add jobs_test.go with tests for job creation and status retrieval
- Add worker_test.go with tests for job processing
2026-03-05 16:28:45 -05:00
john-okeefe 54bfd778db Refactor MediaScanner for improved file watching and job queue integration
- Replace event queue with dirty directories tracking (Jellyfin approach)
- Add file stability checking to wait for file writes to complete
- Add initial scan on startup to detect existing files
- Integrate with Worker job queue for directory scanning
- Change WatchChanges to return error and use atomic.Bool for state
- Add scan_mutex to prevent concurrent scans
- Add Close method with proper cleanup of resources
- Enhance polling with configurable interval
2026-03-05 16:28:40 -05:00
john-okeefe a5ac1137e5 Enhance Worker with new job types and singleton pattern
- Add WorkerInstance global singleton for global access
- Add new job types: import, convert, thumbnails, backup, analytics, sync
- Add Enqueue method for non-blocking job submission
- Add job processors for each new job type:
  - processImportJob: OPDS and Calibre import support
  - processConvertJob: EPUB to KEPUB conversion
  - processThumbnailsJob: Cover thumbnail generation
  - processBackupJob: Database backup functionality
  - processAnalyticsJob: Library and system statistics
  - processDirectoryScanJob: Directory scanning for media scanner
- Add helper getTopN function for analytics
2026-03-05 16:28:32 -05:00