16 KiB
Library Cluster Feature - Design Document
📋 Overview
The Library Cluster feature allows users to group multiple libraries that share similar content categories together, providing better organization and navigation for media collections spread across different mount points or locations.
🎯 Problem Statement
In the current system:
- Users can have many libraries mounted from different locations (NAS, external drives, network shares)
- Some libraries contain similar content (e.g., multiple anime libraries, multiple movie collections)
- There's no way to logically group these related libraries together
- Navigation becomes difficult when managing 10+ libraries with similar content
💡 Solution: Library Clusters
A Library Cluster is a logical grouping of multiple libraries that share similar content categories.
Key Benefits:
- Unified View: View media from multiple related libraries in a single interface
- Better Organization: Group libraries by category (Movies, TV Shows, Anime, Documentaries, etc.)
- Simplified Navigation: Filter and browse by cluster instead of individual libraries
- Flexible Management: Libraries can belong to multiple clusters
- Performance: Cluster-based queries can be optimized with proper indexing
🏗️ Architecture Design
Database Schema
New Table: clusters
CREATE TABLE clusters (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
description TEXT,
color TEXT DEFAULT '#6366f1', -- UI color for visual distinction
icon TEXT DEFAULT 'folder', -- Icon identifier for UI
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
New Table: library_cluster_mapping
CREATE TABLE library_cluster_mapping (
id INTEGER PRIMARY KEY AUTOINCREMENT,
library_id INTEGER NOT NULL,
cluster_id INTEGER NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (library_id) REFERENCES libraries(id) ON DELETE CASCADE,
FOREIGN KEY (cluster_id) REFERENCES clusters(id) ON DELETE CASCADE,
UNIQUE(library_id, cluster_id)
);
Indexes for Performance
CREATE INDEX idx_library_cluster_mapping_library ON library_cluster_mapping(library_id);
CREATE INDEX idx_library_cluster_mapping_cluster ON library_cluster_mapping(cluster_id);
CREATE INDEX idx_clusters_name ON clusters(name);
API Endpoints
Cluster Management
GET /api/clusters
- List all clusters with library counts
- Response:
{ clusters: Array<Cluster & { library_count: number }> }
POST /api/clusters
- Create a new cluster
- Body:
{ name: string, description?: string, color?: string, icon?: string } - Response:
{ id: number, name: string, ... }
GET /api/clusters/[id]
- Get cluster details with associated libraries
- Response:
{ cluster: Cluster, libraries: Library[] }
PUT /api/clusters/[id]
- Update cluster metadata (name, description, color, icon)
- Body:
{ name?: string, description?: string, color?: string, icon?: string }
DELETE /api/clusters/[id]
- Delete cluster (removes mappings, not libraries)
- Response:
{ message: string }
Cluster-Library Mapping
POST /api/clusters/[id]/libraries
- Add libraries to a cluster
- Body:
{ libraryIds: number[] } - Response:
{ added: number, cluster: Cluster }
DELETE /api/clusters/[id]/libraries/[libraryId]
- Remove a library from a cluster
- Response:
{ message: string }
Media Queries by Cluster
GET /api/clusters/[id]/videos
- Get all videos from libraries in this cluster
- Query params:
limit,offset,search,sort - Response: Paginated video list
GET /api/clusters/[id]/photos
- Get all photos from libraries in this cluster
- Query params:
limit,offset,search,sort - Response: Paginated photo list
GET /api/clusters/[id]/texts
- Get all text files from libraries in this cluster
- Query params:
limit,offset,search,sort - Response: Paginated text list
GET /api/clusters/[id]/stats
- Get statistics for a cluster
- Response:
{ video_count: number, photo_count: number, text_count: number, total_size: number, library_count: number }
Frontend Components
1. Cluster Management UI (Settings Page)
Location: /app/settings/page.tsx
Add new section after "Media Libraries":
┌─────────────────────────────────────────┐
│ 🗂️ Library Clusters │
│ │
│ [+ Create Cluster] │
│ │
│ ┌─────────────────────────────────────┐ │
│ │ 🎬 Movies (Blue) │ │
│ │ 3 libraries • 1,234 videos │ │
│ │ [Edit] [Delete] │ │
│ └─────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────┐ │
│ │ 📺 TV Shows (Green) │ │
│ │ 2 libraries • 567 videos │ │
│ │ [Edit] [Delete] │ │
│ └─────────────────────────────────────┘ │
└─────────────────────────────────────────┘
Features:
- Create/edit/delete clusters
- Assign libraries to clusters (multi-select interface)
- Visual color coding
- Icon selection
- Statistics display
2. Cluster Navigation (Sidebar)
Location: /components/sidebar.tsx
Add "Clusters" section in sidebar:
┌────────────────┐
│ 🗂️ Clusters │
│ │
│ 🎬 Movies │
│ 📺 TV Shows │
│ 🎌 Anime │
│ 📚 Docs │
└────────────────┘
Features:
- Expandable/collapsible section
- Color-coded indicators
- Click to filter content by cluster
3. Cluster View Page
New Route: /app/clusters/[id]/page.tsx
Display media from all libraries in the selected cluster:
┌─────────────────────────────────────────┐
│ 🎬 Movies Cluster │
│ 3 libraries • 1,234 videos │
│ │
│ Tabs: [Videos] [Photos] [Stats] │
│ │
│ [Grid of video cards from all libs] │
└─────────────────────────────────────────┘
Features:
- Tabbed interface for different media types
- Statistics overview
- Virtual scrolling for performance
- Library breakdown toggle
4. Enhanced Library Card
Location: /app/settings/page.tsx
Update library cards to show cluster assignments:
┌─────────────────────────────────────────┐
│ 📁 /mnt/nas/movies │
│ Clusters: [🎬 Movies] [🏆 Awards] │
│ [Scan] [Manage Clusters] [Delete] │
└─────────────────────────────────────────┘
Data Flow
Creating a Cluster
graph LR
A[User creates cluster] --> B[POST /api/clusters]
B --> C[Insert into clusters table]
C --> D[Return cluster ID]
D --> E[User assigns libraries]
E --> F[POST /api/clusters/id/libraries]
F --> G[Insert into library_cluster_mapping]
G --> H[Refresh UI]
Viewing Cluster Content
graph LR
A[User clicks cluster] --> B[Navigate to /clusters/id]
B --> C[GET /api/clusters/id/videos]
C --> D[Query media WHERE library_id IN cluster_libraries]
D --> E[Return paginated results]
E --> F[Render virtual grid]
🔧 Implementation Plan
Phase 1: Database & Backend (Priority: P0)
Estimated Time: 4 hours
-
Task 1.1: Update database schema
- Add
clusterstable - Add
library_cluster_mappingtable - Create indexes
- Add migration support
- Add
-
Task 1.2: Create cluster management APIs
GET /api/clustersPOST /api/clustersGET /api/clusters/[id]PUT /api/clusters/[id]DELETE /api/clusters/[id]
-
Task 1.3: Create cluster-library mapping APIs
POST /api/clusters/[id]/librariesDELETE /api/clusters/[id]/libraries/[libraryId]
-
Task 1.4: Create cluster media query APIs
GET /api/clusters/[id]/videosGET /api/clusters/[id]/photosGET /api/clusters/[id]/textsGET /api/clusters/[id]/stats
Phase 2: Settings UI (Priority: P0)
Estimated Time: 6 hours
-
Task 2.1: Create cluster management component
- Cluster list with create/edit/delete
- Color picker integration
- Icon selector component
-
Task 2.2: Create library-to-cluster assignment UI
- Multi-select library picker
- Drag-and-drop interface (optional)
- Bulk assignment support
-
Task 2.3: Update library cards
- Show cluster badges
- Quick cluster assignment
Phase 3: Navigation & Viewing (Priority: P1)
Estimated Time: 5 hours
-
Task 3.1: Update sidebar
- Add "Clusters" section
- Collapsible cluster list
- Color-coded indicators
-
Task 3.2: Create cluster view page
/app/clusters/[id]/page.tsx- Tabbed interface
- Reuse existing virtualized grid components
-
Task 3.3: Add cluster statistics
- Overview cards
- Library breakdown
- Media count by type
Phase 4: Enhancements (Priority: P2)
Estimated Time: 3 hours
-
Task 4.1: Search and filtering
- Search across cluster media
- Filter by library within cluster
- Sort options
-
Task 4.2: Cluster templates
- Pre-defined cluster types (Movies, TV, Music, etc.)
- Import/export cluster configurations
-
Task 4.3: Analytics
- Cluster usage statistics
- Library overlap analysis
- Storage breakdown by cluster
📊 UI/UX Considerations
Design Principles
- Non-intrusive: Clusters are optional, don't change existing workflows
- Visual Clarity: Use colors and icons for easy identification
- Performance: Virtual scrolling for cluster views with many items
- Flexibility: Libraries can belong to multiple clusters
Color Palette for Clusters
const CLUSTER_COLORS = [
{ name: 'Indigo', value: '#6366f1' },
{ name: 'Blue', value: '#3b82f6' },
{ name: 'Green', value: '#10b981' },
{ name: 'Red', value: '#ef4444' },
{ name: 'Purple', value: '#a855f7' },
{ name: 'Pink', value: '#ec4899' },
{ name: 'Orange', value: '#f97316' },
{ name: 'Yellow', value: '#eab308' },
];
Icon Options
const CLUSTER_ICONS = [
'folder', 'film', 'tv', 'music', 'image',
'book', 'archive', 'database', 'star', 'heart'
];
🔍 Example Use Cases
Use Case 1: Multiple Anime Libraries
User has:
- /mnt/nas1/anime
- /mnt/nas2/anime
- /mnt/external/anime-movies
Creates cluster: "Anime" (Pink, 🎌)
- Assigns all three libraries
- Views unified anime collection
Use Case 2: Content Type Organization
User has libraries across different drives:
- /mnt/drive1/content
- /mnt/drive2/content
- /mnt/drive3/content
Creates clusters:
- "Movies" → Contains movie folders from all drives
- "TV Shows" → Contains TV show folders from all drives
- "Documentaries" → Contains documentary folders
Use Case 3: Quality Tiers
User organizes by quality:
- "4K HDR" cluster → High-quality libraries
- "1080p" cluster → Standard quality libraries
- "Archive" cluster → Old/backup content
🚀 Performance Considerations
Database Query Optimization
-- Efficient cluster media query with proper indexes
SELECT m.*
FROM media m
INNER JOIN libraries l ON m.library_id = l.id
INNER JOIN library_cluster_mapping lcm ON l.id = lcm.library_id
WHERE lcm.cluster_id = ?
AND m.type = 'video'
ORDER BY m.created_at DESC
LIMIT ? OFFSET ?;
Caching Strategy
- Cache cluster configurations in memory
- Use Redis for cluster media counts
- Client-side caching of cluster metadata
🧪 Testing Strategy
Unit Tests
- Cluster CRUD operations
- Library-cluster mapping
- Media queries by cluster
- Cascade delete behavior
Integration Tests
- End-to-end cluster creation flow
- Multi-library media aggregation
- Permission and access control
Performance Tests
- Large cluster queries (1000+ items)
- Multiple concurrent cluster views
- Database index effectiveness
📈 Future Enhancements
Phase 5: Advanced Features (Future)
- Smart Clusters: Auto-categorization based on content analysis
- Cluster Sharing: Share cluster configurations between users
- Cluster Permissions: Fine-grained access control per cluster
- Cross-cluster Search: Search across all clusters simultaneously
- Cluster Analytics: Viewing patterns, popular content
- Cluster Backups: Export/import cluster configurations
- Cluster Scheduling: Automatic scanning schedules per cluster
🔐 Security Considerations
- Access Control: Ensure users can only access libraries they have permissions for
- Validation: Validate cluster names, prevent SQL injection
- Cascade Deletes: Properly handle library/cluster deletions
- API Rate Limiting: Prevent abuse of cluster creation/modification
📝 Migration Strategy
For Existing Users
- Database migration script runs automatically on app start
- All existing libraries remain functional (no cluster assignment)
- Users can gradually organize libraries into clusters
- No breaking changes to existing functionality
Migration Script
-- migrations/add_library_clusters.sql
BEGIN TRANSACTION;
-- Create clusters table
CREATE TABLE IF NOT EXISTS clusters (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
description TEXT,
color TEXT DEFAULT '#6366f1',
icon TEXT DEFAULT 'folder',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- Create mapping table
CREATE TABLE IF NOT EXISTS library_cluster_mapping (
id INTEGER PRIMARY KEY AUTOINCREMENT,
library_id INTEGER NOT NULL,
cluster_id INTEGER NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (library_id) REFERENCES libraries(id) ON DELETE CASCADE,
FOREIGN KEY (cluster_id) REFERENCES clusters(id) ON DELETE CASCADE,
UNIQUE(library_id, cluster_id)
);
-- Create indexes
CREATE INDEX IF NOT EXISTS idx_library_cluster_mapping_library ON library_cluster_mapping(library_id);
CREATE INDEX IF NOT EXISTS idx_library_cluster_mapping_cluster ON library_cluster_mapping(cluster_id);
CREATE INDEX IF NOT EXISTS idx_clusters_name ON clusters(name);
COMMIT;
📚 Documentation Updates
- Update README.md with cluster feature overview
- Create user guide for cluster management
- Add API documentation for cluster endpoints
- Update deployment guide for database migration
✅ Success Metrics
- Users can create and manage clusters
- Media from multiple libraries displays in unified cluster view
- Performance remains acceptable with 10+ libraries per cluster
- No regression in existing library functionality
- Positive user feedback on organization improvement
Document Version: 1.0
Last Updated: 2025-10-11
Status: Planning Phase
Estimated Total Implementation Time: 18-20 hours