* Implement optimized batch rule application
- Add apply_all_album_rules/1 to batch apply all album rules in single query
- Add apply_all_artist_rules/1 to batch apply all artist rules in single query
- Update apply_all_rules/0 to use new batch functions
- Add comprehensive tests for batch application
- Use CASE statement in SQL to apply multiple rules efficiently
Co-authored-by: cloud8421 <537608+cloud8421@users.noreply.github.com>
* Add batch application support for track-filtered rules
- Extend apply_all_album_rules/2 to support filtering by tracks
- Extend apply_all_artist_rules/2 to support filtering by tracks
- Update apply_all_rules/1 to use batch functions for track-filtered application
- Remove duplicate function definitions
- Ensures both main use cases (all tracks and specific tracks) are optimized
Co-authored-by: cloud8421 <537608+cloud8421@users.noreply.github.com>
* Add comprehensive documentation for optimization
- Document the problem and solution approach
- Explain SQL generation and performance impact
- Detail trade-offs and backward compatibility
- Include future considerations and scalability notes
Co-authored-by: cloud8421 <537608+cloud8421@users.noreply.github.com>
* Apply credo suggestions and format
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: cloud8421 <537608+cloud8421@users.noreply.github.com>
Co-authored-by: Claudio Ortolina <cloud8421@gmail.com>
╭─────────────────────────────────────────────────────────╮
│ ✻ Welcome to Claude Code! │
│ │
│ /help for help, /status for your current setup │
│ │
│ cwd: /Users/cloud/github.com/cloud8421/music_library │
╰─────────────────────────────────────────────────────────╯
> Look at @lib/music_library_web/components/ and you fill find
components there. I would like you to rename the component modules so
that instead
of being called MusicLibraryWeb.<something>Component, they're called
MusicLibraryWeb.Components.<something>. For example
MusicLibraryWeb.AddRecordComponent would be called
MusicLibraryWeb.Components.AddRecord. Make sure you also update
references where these
components are used.
⎿ Listed directory lib/music_library_web/components/
⏺ I'll help you rename the component modules and update their
references. Let me first examine the components directory structure and
then create
a plan.
⏺ Bash(find
/Users/cloud/github.com/cloud8421/music_library/lib/music_library_web/components
-name "*.ex" | head -20)
⎿
/Users/cloud/github.com/cloud8421/music_library/lib/music_library_web/components/pagination_component.ex
/Users/cloud/github.com/cloud8421/music_library/lib/music_library_web/components/add_record_component.ex
/Users/cloud/github.com/cloud8421/music_library/lib/music_library_web/components/release_component.ex
… +10 lines (ctrl+o to expand)
⏺ Now let me examine a few of these files to understand the current
naming pattern:
⏺ Read(lib/music_library_web/components/add_record_component.ex)
⎿ Read 10 lines (ctrl+o to expand)
⏺ Read(lib/music_library_web/components/pagination_component.ex)
⎿ Read 10 lines (ctrl+o to expand)
⏺ Read(lib/music_library_web/components/barcode_scanner_component.ex)
⎿ Read 10 lines (ctrl+o to expand)
⏺ Now let me search for references to these components across the
codebase:
⏺ Search(pattern:
"MusicLibraryWeb\.(AddRecord|Pagination|BarcodeScanner|Notes|Release)Component")
⎿ Found 13 files (ctrl+o to expand)
⏺ Let me also check for other component patterns:
⏺ Search(pattern: "MusicLibraryWeb\.[A-Z][a-zA-Z]*Components?")
⎿ Found 34 files (ctrl+o to expand)
⏺ Now let me create a plan for this refactoring task:
⏺ Let me examine all component files to understand the current naming
pattern:
⏺ Bash(find
/Users/cloud/github.com/cloud8421/music_library/lib/music_library_web/components
-name "*.ex" -exec grep -l "defmodule MusicLibraryWeb\."
{} \;)
⎿ Interrupted · What should Claude do instead?
> Retry the find command
⏺ Bash(find
/Users/cloud/github.com/cloud8421/music_library/lib/music_library_web/components
-name "*.ex" -exec grep -l "defmodule MusicLibraryWeb\."
{} \;)
⎿
/Users/cloud/github.com/cloud8421/music_library/lib/music_library_web/components/pagination_component.ex
/Users/cloud/github.com/cloud8421/music_library/lib/music_library_web/components/add_record_component.ex
/Users/cloud/github.com/cloud8421/music_library/lib/music_library_web/components/release_component.ex
… +10 lines (ctrl+o to expand)
⏺ Now let me examine the module names in each file to identify which
ones need renaming:
⏺ Bash(grep "defmodule MusicLibraryWeb\."
/Users/cloud/github.com/cloud8421/music_library/lib/music_library_web/components/*.ex)
⎿
/Users/cloud/github.com/cloud8421/music_library/lib/music_library_web/components/add_record_component.ex:defmodule
MusicLibraryWeb.AddRecord
Component do
/Users/cloud/github.com/cloud8421/music_library/lib/music_library_web/components/artist_components.ex:defmodule
MusicLibraryWeb.ArtistCompon
… +21 lines (ctrl+o to expand)
⏺ Perfect! Now I can see which components need renaming. Based on the
current naming pattern, I need to rename the ones ending with
"Component"
to be under the "Components" namespace. Let me update my todo list and
complete the identification:
⏺ Now let me start renaming the components. I'll begin with
AddRecordComponent:
⏺ Update(lib/music_library_web/components/add_record_component.ex)
⎿ Updated lib/music_library_web/components/add_record_component.ex
with 1 addition and 1 removal
1 - defmodule MusicLibraryWeb.AddRecordComponent do
1 + defmodule MusicLibraryWeb.Components.AddRecord do
2 use MusicLibraryWeb, :live_component
3
4 import MusicLibraryWeb.RecordComponents, only:
[format_label: 1, type_label: 1]
⏺ Update(lib/music_library_web/components/barcode_scanner_component.ex)
⎿ Updated
lib/music_library_web/components/barcode_scanner_component.ex with 1
addition and 1 removal
1 - defmodule MusicLibraryWeb.BarcodeScannerComponent do
1 + defmodule MusicLibraryWeb.Components.BarcodeScanner do
2 use MusicLibraryWeb, :live_component
3
4 alias MusicBrainz.ReleaseGroupSearchResult
⏺ Update(lib/music_library_web/components/notes_component.ex)
⎿ Updated lib/music_library_web/components/notes_component.ex with 1
addition and 1 removal
1 - defmodule MusicLibraryWeb.NotesComponent do
1 + defmodule MusicLibraryWeb.Components.Notes do
2 use MusicLibraryWeb, :live_component
3
4 alias MusicLibrary.Notes
⏺ Update(lib/music_library_web/components/pagination_component.ex)
⎿ Updated lib/music_library_web/components/pagination_component.ex
with 1 addition and 1 removal
1 - defmodule MusicLibraryWeb.PaginationComponent do
1 + defmodule MusicLibraryWeb.Components.Pagination do
2 use MusicLibraryWeb, :html
3
4 attr :pagination_params, :map, required: true
⏺ Update(lib/music_library_web/components/release_component.ex)
⎿ Updated lib/music_library_web/components/release_component.ex with 1
addition and 1 removal
1 - defmodule MusicLibraryWeb.ReleaseComponent do
1 + defmodule MusicLibraryWeb.Components.Release do
2 use MusicLibraryWeb, :live_component
3 use Gettext, backend: MusicLibraryWeb.Gettext
4
⏺ Update(lib/music_library_web/components/record_form.ex)
⎿ Updated lib/music_library_web/components/record_form.ex with 1
addition and 1 removal
1 - defmodule MusicLibraryWeb.RecordForm do
1 + defmodule MusicLibraryWeb.Components.RecordForm do
2 use MusicLibraryWeb, :live_component
3
4 import MusicLibraryWeb.RecordComponents,
⏺ Now I need to update all the references across the codebase. Let me
start this process:
⏺ Now let me search for and update all references to these components.
Let me start with AddRecordComponent:
⏺ Search(pattern: "AddRecordComponent", output_mode: "content")
⎿ Found 3 lines (ctrl+o to expand)
⏺ Update(lib/music_library_web/live/artist_live/show.html.heex)
⎿ File must be read first
⏺ Read(lib/music_library_web/live/artist_live/show.html.heex)
⎿ Read 10 lines (ctrl+o to expand)
⏺ Update(lib/music_library_web/live/artist_live/show.html.heex)
⎿ Updated lib/music_library_web/live/artist_live/show.html.heex with 1
addition and 1 removal
237
on_close={JS.patch(~p"/artists/#{@artist.musicbrainz_id}")}
238 >
239 <.live_component
240 - module={MusicLibraryWeb.AddRecordComponent}
240 + module={MusicLibraryWeb.Components.AddRecord}
241 id={:search}
242 title={@page_title}
243 action={@live_action}
⏺ Read(lib/music_library_web/live/wishlist_live/index.html.heex)
⎿ Read 10 lines (ctrl+o to expand)
⏺ Update(lib/music_library_web/live/wishlist_live/index.html.heex)
⎿ Updated lib/music_library_web/live/wishlist_live/index.html.heex
with 1 addition and 1 removal
70 on_close={JS.patch(back_path(@record_list_params))}
71 >
72 <.live_component
73 - module={MusicLibraryWeb.AddRecordComponent}
73 + module={MusicLibraryWeb.Components.AddRecord}
74 id={:search}
75 title={@page_title}
76 action={@live_action}
⏺ Read(lib/music_library_web/live/collection_live/index.html.heex)
⎿ Read 10 lines (ctrl+o to expand)
⏺ Update(lib/music_library_web/live/collection_live/index.html.heex)
⎿ Updated lib/music_library_web/live/collection_live/index.html.heex
with 1 addition and 1 removal
82 on_close={JS.patch(back_path(@record_list_params))}
83 >
84 <.live_component
85 - module={MusicLibraryWeb.AddRecordComponent}
85 + module={MusicLibraryWeb.Components.AddRecord}
86 id={:search}
87 title={@page_title}
88 action={@live_action}
⏺ Now let me search for BarcodeScannerComponent references:
⏺ Search(pattern: "BarcodeScannerComponent", output_mode: "content")
⎿ Found 2 lines (ctrl+o to expand)
⏺ Read(lib/music_library_web/live/collection_live/index.ex)
⎿ Read 10 lines (ctrl+o to expand)
⏺ I notice there are also imports of PaginationComponent in the same
file. Let me update multiple references in this file:
⏺ Update(lib/music_library_web/live/collection_live/index.ex)
⎿ Updated lib/music_library_web/live/collection_live/index.ex with 2
additions and 2 removals
1 defmodule MusicLibraryWeb.CollectionLive.Index do
2 use MusicLibraryWeb, :live_view
3
4 - import MusicLibraryWeb.BarcodeScannerComponent, only:
[barcode_icon: 1]
5 - import MusicLibraryWeb.PaginationComponent
4 + import MusicLibraryWeb.Components.BarcodeScanner, only:
[barcode_icon: 1]
5 + import MusicLibraryWeb.Components.Pagination
6 import MusicLibraryWeb.RecordComponents
7
8 alias MusicLibrary.Collection
⏺ Read(lib/music_library_web/live/collection_live/index.html.heex)
⎿ Read 10 lines (ctrl+o to expand)
⏺ Update(lib/music_library_web/live/collection_live/index.html.heex)
⎿ Updated lib/music_library_web/live/collection_live/index.html.heex
with 1 addition and 1 removal
99 on_close={JS.patch(back_path(@record_list_params))}
100 >
101 <.live_component
102 - module={MusicLibraryWeb.BarcodeScannerComponent}
102 + module={MusicLibraryWeb.Components.BarcodeScanner}
103 id={:barcode_scanner}
104 title={@page_title}
105 action={@live_action}
⏺ Let me continue searching for other component references. Let me
search for all the components I renamed:
⏺ Search(pattern:
"MusicLibraryWeb\.(NotesComponent|PaginationComponent|ReleaseComponent|RecordForm)",
output_mode: "content")
⎿ Found 18 lines (ctrl+o to expand)
⏺ Let me use a more efficient approach and update all the references at
once. First, let me read the files that need updating and then apply the
changes:
⏺ Read(lib/music_library_web/live/wishlist_live/index.ex)
⎿ Read 80 lines (ctrl+o to expand)
⏺ Update(lib/music_library_web/live/wishlist_live/index.ex)
⎿ Updated lib/music_library_web/live/wishlist_live/index.ex with 2
additions and 2 removals
1 defmodule MusicLibraryWeb.WishlistLive.Index do
2 use MusicLibraryWeb, :live_view
3
4 - import MusicLibraryWeb.PaginationComponent
4 + import MusicLibraryWeb.Components.Pagination
5 import MusicLibraryWeb.RecordComponents
6
7 alias MusicLibrary.Records
...
70 end
71
72 @impl true
73 - def handle_info({MusicLibraryWeb.RecordForm, {:saved,
_record}}, socket) do
73 + def handle_info({MusicLibraryWeb.Components.RecordForm,
{:saved, _record}}, socket) do
74 {:noreply, load_and_assign_records(socket,
socket.assigns.record_list_params)}
75 end
76
⏺ Let me continue with the other files. I'll use grep and replace to do
this more efficiently:
⏺ Bash(grep -r "MusicLibraryWeb\.RecordForm"
/Users/cloud/github.com/cloud8421/music_library/lib/music_library_web/
--exclude-dir=.git)
⎿
/Users/cloud/github.com/cloud8421/music_library/lib/music_library_web/live/wishlist_live/index.html.heex:
module={MusicLibraryWeb.Recor
dForm}
/Users/cloud/github.com/cloud8421/music_library/lib/music_library_web/live/wishlist_live/show.ex:
def handle_info({MusicLibraryWeb.RecordFo
… +11 lines (ctrl+o to expand)
⏺ Let me update these files with the correct module references:
⏺ Read(lib/music_library_web/live/wishlist_live/index.html.heex)
⎿ Read 10 lines (ctrl+o to expand)
⏺ Let me use a more efficient approach by using sed to replace all
occurrences in all files at once:
⏺ Bash(find
/Users/cloud/github.com/cloud8421/music_library/lib/music_library_web
-name "*.ex" -o -name "*.heex" | xargs sed -i ''
's/MusicLibraryWeb\.RecordForm/Music…)
⎿ (No content)
⏺ Perfect! Now let me continue with the other components. Let me update
NotesComponent references:
⏺ Bash(find
/Users/cloud/github.com/cloud8421/music_library/lib/music_library_web
-name "*.ex" -o -name "*.heex" | xargs sed -i ''
's/MusicLibraryWeb\.NotesComponent/M…)
⎿ (No content)
⏺ Now let me update ReleaseComponent references:
⏺ Bash(find
/Users/cloud/github.com/cloud8421/music_library/lib/music_library_web
-name "*.ex" -o -name "*.heex" | xargs sed -i ''
's/MusicLibraryWeb\.ReleaseComponent…)
⎿ (No content)
⏺ Finally, let me update PaginationComponent references:
⏺ Bash(find
/Users/cloud/github.com/cloud8421/music_library/lib/music_library_web
-name "*.ex" -o -name "*.heex" | xargs sed -i ''
's/MusicLibraryWeb\.PaginationCompon…)
⎿ (No content)
⏺ Read(lib/music_library_web/live/scrobbled_tracks_live/index.ex)
⎿ Read 10 lines (ctrl+o to expand)
⏺ Great! Now let me verify that all the references have been updated.
Let me search for any remaining old component references:
⏺ Search(pattern:
"MusicLibraryWeb\.(AddRecordComponent|BarcodeScannerComponent|NotesComponent|PaginationComponent|ReleaseComponent|RecordForm)(?!\.C
omponents)", output_mode: "content")
⎿ Found 0 lines
⏺ Excellent! Let me also check if there are any references in the
documentation that I should update:
⏺ Search(pattern: "MusicLibraryWeb\.PaginationComponent", path: "docs",
output_mode: "content")
⎿ Found 2 lines (ctrl+o to expand)
⏺ Let me update the documentation references as well:
⏺ Read(docs/plans/scrobbled-tracks-crud.md)
⎿ Read 10 lines (ctrl+o to expand)
⏺ Update(docs/plans/scrobbled-tracks-crud.md)
⎿ Updated docs/plans/scrobbled-tracks-crud.md with 2 additions and 2
removals
84 - Album title
85 - Scrobbled date/time
86 - Edit/Delete action buttons
87 - - Pagination component at bottom using
`MusicLibraryWeb.PaginationComponent`
87 + - Pagination component at bottom using
`MusicLibraryWeb.Components.Pagination`
88 - Empty state message when no tracks found
89
90 ### Form Component Template
...
127 ### Pagination Integration
128
129 - **Pattern**: Follow `CollectionLive.Index` pagination
approach
130 - - **Component**: Reuse
`MusicLibraryWeb.PaginationComponent`
130 + - **Component**: Reuse
`MusicLibraryWeb.Components.Pagination`
131 - **Parameters**: Support `query`, `page`, `page_size`,
and `order`
132 - **URL Structure**:
`/scrobbled-tracks?page=2&query=artist&page_size=50`
133
⏺ Now let me mark the reference update task as completed and run tests
to verify everything works:
⏺ Bash(mix test --max-failures=5)
⎿ Compiling 13 files (.ex)
Generated music_library app
Running ExUnit with seed: 515502, max_cases: 20
… +5 lines (ctrl+o to expand)
⏺ Perfect! All tests pass. Let me also run the format and static checks
to make sure everything is properly formatted:
⏺ Bash(mix do format --check-formatted, credo --strict)
⎿ Checking 193 source files (this might take a while) ...
Please report incorrect results:
https://github.com/rrrene/credo/issues
… +5 lines (ctrl+o to expand)
⏺ Excellent! All static checks pass as well. Let me complete the final
todo:
⏺ Perfect! I have successfully completed the component renaming task.
Here's a summary of what was accomplished:
Component Renaming Summary
Renamed Components:
- MusicLibraryWeb.AddRecordComponent →
MusicLibraryWeb.Components.AddRecord
- MusicLibraryWeb.BarcodeScannerComponent →
MusicLibraryWeb.Components.BarcodeScanner
- MusicLibraryWeb.NotesComponent → MusicLibraryWeb.Components.Notes
- MusicLibraryWeb.PaginationComponent →
MusicLibraryWeb.Components.Pagination
- MusicLibraryWeb.ReleaseComponent →
MusicLibraryWeb.Components.Release
- MusicLibraryWeb.RecordForm → MusicLibraryWeb.Components.RecordForm
Files Updated:
- Updated module definitions in all component files
- Updated imports in LiveView modules
- Updated module={...} references in templates
- Updated handle_info callback references
- Updated function calls in templates
- Updated documentation references
Verification:
- All tests pass (198 tests, 0 failures)
- Static checks pass (format and credo)
- No remaining old component references found
The component modules are now properly organized under the
MusicLibraryWeb.Components namespace as requested.
> Note that the file names of the renamed components need to be updated
as well
⏺ You're absolutely right! I need to rename the actual files to match
the new module structure. Let me update the filenames as well.
⏺ Bash(mv
/Users/cloud/github.com/cloud8421/music_library/lib/music_library_web/components/add_record_component.ex
/Users/cloud/github.com/cloud8421/music_library/lib/…)
⎿ (No content)
⏺ Bash(mv
/Users/cloud/github.com/cloud8421/music_library/lib/music_library_web/components/barcode_scanner_component.ex
/Users/cloud/github.com/cloud8421/music_library…)
⎿ (No content)
⏺ Bash(mv
/Users/cloud/github.com/cloud8421/music_library/lib/music_library_web/components/notes_component.ex
/Users/cloud/github.com/cloud8421/music_library/lib/music…)
⎿ (No content)
⏺ Bash(mv
/Users/cloud/github.com/cloud8421/music_library/lib/music_library_web/components/pagination_component.ex
/Users/cloud/github.com/cloud8421/music_library/lib/…)
⎿ (No content)
⏺ Bash(mv
/Users/cloud/github.com/cloud8421/music_library/lib/music_library_web/components/release_component.ex
/Users/cloud/github.com/cloud8421/music_library/lib/mus…)
⎿ (No content)
⏺ Now let me verify that all files have been renamed correctly:
⏺ Bash(ls -la
/Users/cloud/github.com/cloud8421/music_library/lib/music_library_web/components/)
⎿ .rw-r--r--@ 6.4k cloud 23 Sep 09:51 add_record.ex
.rw-r--r--@ 682 cloud 23 Sep 09:51 artist_components.ex
.rw-r--r--@ 15k cloud 23 Sep 09:51 barcode_scanner.ex
… +11 lines (ctrl+o to expand)
⏺ Perfect! Now let me run tests to verify everything still works after
the file renames:
⏺ Bash(mix test --max-failures=5)
⎿ Compiling 8 files (.ex)
Generated music_library app
Running ExUnit with seed: 143097, max_cases: 20
… +5 lines (ctrl+o to expand)
⏺ Excellent! All tests still pass. Let me also run the static checks:
⏺ Bash(mix do format --check-formatted, credo --strict)
⎿ Checking 193 source files (this might take a while) ...
Please report incorrect results:
https://github.com/rrrene/credo/issues
… +5 lines (ctrl+o to expand)
⏺ Perfect! Let me complete the final todo:
⏺ Complete Component Renaming Summary
I have successfully completed the component renaming task, including
updating both the module names and the file names:
Module and File Renames:
- add_record_component.ex → add_record.ex
(MusicLibraryWeb.AddRecordComponent →
MusicLibraryWeb.Components.AddRecord)
- barcode_scanner_component.ex → barcode_scanner.ex
(MusicLibraryWeb.BarcodeScannerComponent →
MusicLibraryWeb.Components.BarcodeScanner)
- notes_component.ex → notes.ex (MusicLibraryWeb.NotesComponent →
MusicLibraryWeb.Components.Notes)
- pagination_component.ex → pagination.ex
(MusicLibraryWeb.PaginationComponent →
MusicLibraryWeb.Components.Pagination)
- release_component.ex → release.ex (MusicLibraryWeb.ReleaseComponent
→ MusicLibraryWeb.Components.Release)
- record_form.ex → kept same filename (MusicLibraryWeb.RecordForm →
MusicLibraryWeb.Components.RecordForm)
What was updated:
- Module definitions in component files
- All import statements across the codebase
- LiveView template references (module={...})
- Function calls in templates
- handle_info callback references in LiveViews
- Documentation references
Verification:
- All tests pass (198 tests, 0 failures)
- Static checks pass (format and credo)
- Application compiles successfully
All component modules are now properly organized under the
MusicLibraryWeb.Components namespace with matching file names.
# Universal Search Modal Implementation Plan
## Overview
This plan outlines the implementation of a universal search modal that
provides unified search across Records (Collection), Records (Wishlist),
and Artists. The modal will be accessible via a search icon in the top
navigation bar and a keyboard shortcut.
## Requirements
### Core Features
- Modal accessible via:
- Search icon in top navigation bar
- Keyboard shortcut (Ctrl/Cmd + K)
- Search across three entity types:
1. Records in Collection
2. Records in Wishlist
3. Artists
- Real-time search as user types
- Keyboard navigation support
- Mobile-responsive design
### Search Functionality
- Leverage existing FTS5 search infrastructure
- Support existing search syntax (artist:, album:, genre:, etc.)
- Show search results grouped by entity type
- Limit results per category (e.g., 5 per type)
- Click-to-navigate to full results or individual records
## Technical Architecture
### 1. Modal Component Structure
**New Components:**
- `UniversalSearchModal` - Main modal component
- `SearchResultGroup` - Groups results by type (Collection, Wishlist,
Artists)
- `SearchResultItem` - Individual result display
- `SearchInput` - Enhanced search input with keyboard shortcuts
**Component Location:**
```
lib/music_library_web/components/
├── search_components.ex # New universal search components
└── layouts/app.html.heex # Add search icon to navigation
```
### 2. LiveView Integration
**New LiveView Module:**
```
lib/music_library_web/live/universal_search_live/
├── index.ex # Main search LiveView
└── index.html.heex # Search modal template
```
**Integration Points:**
- Mount as child LiveView in main layout
- Handle modal open/close state
- Manage search query and results
- Handle keyboard navigation
### 3. Backend Search Implementation
**New Context Functions:**
```elixir
# In lib/music_library/search.ex (new module)
def universal_search(query, opts \\ [])
def search_collection(query, limit \\ 5)
def search_wishlist(query, limit \\ 5)
def search_artists(query, limit \\ 5)
```
**Search Strategy:**
- Reuse existing `Records.search_collection/2` and
`Records.search_wishlist/2`
- Extend `Artists.search/2` or create new artist search function
- Combine results with type metadata
- Implement result limiting and pagination
### 4. Database Considerations
**Leverage Existing Infrastructure:**
- Use existing `records_search_index` FTS5 table
- Utilize existing search parser for tagged queries
- Consider artist search optimization (may need artist search index)
**Artist Search Enhancement:**
- Current artist search may need optimization
- Consider adding FTS5 index for artist_infos table if performance
issues
- Leverage existing artist_records view for artist-record relationships
## Implementation Details
### 1. Modal Behavior
**Desktop:**
- Modal opens centered on screen
- Size: `max-w-2xl` (responsive)
- Overlay with backdrop blur
- Esc key to close, click outside to close
**Mobile:**
- Full-screen modal on mobile (`sm:max-w-2xl max-w-full`)
- Touch-friendly result items
- Swipe down to close (if feasible)
- Virtual keyboard considerations
### 2. Search Interface
**Search Input:**
- Placeholder: "Search records and artists..."
- Auto-focus when modal opens
- Debounced search (300ms delay)
- Clear button when text present
- Loading indicator during search
**Search Results:**
```
┌─────────────────────────────────────┐
│ Search: "radiohead ok computer" │
├─────────────────────────────────────┤
│ COLLECTION (3 results) │
│ • OK Computer - Radiohead │
│ • Kid A - Radiohead │
│ • In Rainbows - Radiohead │
│ View all 12 collection results → │
├─────────────────────────────────────┤
│ WISHLIST (1 result) │
│ • Hail to the Thief - Radiohead │
│ View all 1 wishlist results → │
├─────────────────────────────────────┤
│ ARTISTS (1 result) │
│ • Radiohead │
│ View artist page → │
└─────────────────────────────────────┘
```
### 3. Keyboard Navigation
**Keyboard Shortcuts:**
- `Ctrl/Cmd + K` - Open modal
- `Esc` - Close modal
- `↑/↓` - Navigate results
- `Enter` - Select highlighted result
- `Tab` - Move between sections
**Implementation:**
- Use Phoenix LiveView's `phx-window-keydown` for global shortcuts
- Implement focus management with JavaScript hooks
- Maintain accessibility standards (ARIA labels, focus indicators)
### 4. Result Navigation
**Click Actions:**
- Record results → Navigate to record show page
- Artist results → Navigate to artist page
- "View all X results" → Navigate to respective list page with search
applied
**URL Strategy:**
- Don't change URL for modal open/close
- When navigating to results, apply search query to destination page
- Use existing search parameter patterns
## Database Schema Impact
**No Schema Changes Required:**
- Leverage existing tables and search infrastructure
- May add database indexes for performance if needed
**Performance Considerations:**
- Monitor query performance with combined searches
- Consider query result caching for common searches
- Implement search result limits to prevent slow queries
## Testing Strategy
### 1. Unit Tests
**Search Logic Tests:**
```elixir
# test/music_library/search_test.exs
describe "universal_search/2" do
test "searches across all entity types"
test "limits results per category"
test "handles empty queries"
test "handles special characters"
test "respects search syntax (artist:, album:, etc.)"
end
```
### 2. Integration Tests
**LiveView Tests:**
```elixir
# test/music_library_web/live/universal_search_live_test.exs
describe "UniversalSearchLive" do
test "opens modal on keyboard shortcut"
test "searches as user types"
test "displays results grouped by type"
test "navigates to selected results"
test "handles keyboard navigation"
test "closes modal on escape"
end
```
### 3. Component Tests
**Search Components:**
```elixir
# test/music_library_web/components/search_components_test.exs
describe "SearchResultGroup" do
test "renders results with proper grouping"
test "shows 'view all' link when more results available"
test "handles empty result sets"
end
```
### 4. JavaScript/Hook Tests
**Browser Tests:**
- Test keyboard shortcuts work globally
- Test focus management
- Test modal open/close behavior
- Test mobile touch interactions
## Mobile Considerations
### 1. Layout Adaptations
**Mobile Modal:**
- Full-screen on small devices
- Reduced padding and margins
- Larger touch targets for results
- Simplified result display (fewer details)
**Touch Interactions:**
- Swipe down to close modal
- Tap to select results
- Pull-to-refresh for search results
### 2. Performance
**Mobile Optimization:**
- Shorter debounce delays on mobile
- Reduced result limits on mobile
- Lazy loading for large result sets
- Optimize image loading for album covers
### 3. Virtual Keyboard
**iOS/Android Considerations:**
- Modal positioning with virtual keyboard
- Proper input focus management
- Prevent zoom on input focus
## Implementation Phases
### Phase 1: Core Modal Infrastructure
1. Create basic modal component
2. Add search icon to navigation
3. Implement modal open/close
4. Add keyboard shortcut support
### Phase 2: Search Backend
1. Create universal search context
2. Implement combined search functions
3. Add result limiting and grouping
4. Optimize query performance
### Phase 3: Search Interface
1. Implement search input with debouncing
2. Add search result display
3. Implement keyboard navigation
4. Add result selection and navigation
### Phase 4: Mobile & Polish
1. Mobile layout optimizations
2. Touch interaction improvements
3. Performance optimizations
4. Accessibility enhancements
### Phase 5: Testing & Documentation
1. Comprehensive test coverage
2. Performance testing
3. Mobile device testing
4. Documentation updates
## Success Metrics
**Functionality:**
- Modal opens/closes reliably
- Search results are accurate and fast
- Keyboard navigation works smoothly
- Mobile experience is touch-friendly
**Performance:**
- Search queries complete in <500ms
- Modal opens in <100ms
- No janky animations or interactions
- Efficient database queries
**Usability:**
- Easy to discover and use
- Intuitive keyboard shortcuts
- Clear result presentation
- Seamless navigation to results
## Risks and Mitigation
**Performance Risks:**
- Complex queries may be slow
- **Mitigation:** Implement query limits, caching, and monitoring
**Mobile Experience:**
- Small screen constraints
- **Mitigation:** Responsive design, touch-friendly interfaces
**Accessibility:**
- Keyboard navigation complexity
- **Mitigation:** Follow ARIA guidelines, comprehensive testing
**Search Accuracy:**
- Users may expect Google-like search
- **Mitigation:** Clear documentation of search syntax, good defaults
## Future Enhancements
**Advanced Features:**
- Search history and suggestions
- Saved searches
- Search filters and facets
- Search result previews
**Integration:**
- Integration with barcode scanning
- Voice search capabilities
- External search (MusicBrainz, Last.fm)
**Analytics:**
- Search usage analytics
- Popular search terms
- Search success rates
## Conclusion
This universal search modal will significantly improve the user
experience by providing quick access to all content types from any page.
The implementation leverages existing infrastructure while adding a
modern, accessible search interface that works well on both desktop and
mobile devices.
The phased approach ensures a solid foundation while allowing for
iterative improvements based on user feedback and usage patterns.