499 lines
16 KiB
Markdown
499 lines
16 KiB
Markdown
# 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:
|
|
1. **Unified View**: View media from multiple related libraries in a single interface
|
|
2. **Better Organization**: Group libraries by category (Movies, TV Shows, Anime, Documentaries, etc.)
|
|
3. **Simplified Navigation**: Filter and browse by cluster instead of individual libraries
|
|
4. **Flexible Management**: Libraries can belong to multiple clusters
|
|
5. **Performance**: Cluster-based queries can be optimized with proper indexing
|
|
|
|
## 🏗️ Architecture Design
|
|
|
|
### Database Schema
|
|
|
|
#### New Table: `clusters`
|
|
```sql
|
|
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`
|
|
```sql
|
|
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
|
|
```sql
|
|
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
|
|
```mermaid
|
|
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
|
|
```mermaid
|
|
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 `clusters` table
|
|
- Add `library_cluster_mapping` table
|
|
- Create indexes
|
|
- Add migration support
|
|
|
|
- [ ] **Task 1.2**: Create cluster management APIs
|
|
- `GET /api/clusters`
|
|
- `POST /api/clusters`
|
|
- `GET /api/clusters/[id]`
|
|
- `PUT /api/clusters/[id]`
|
|
- `DELETE /api/clusters/[id]`
|
|
|
|
- [ ] **Task 1.3**: Create cluster-library mapping APIs
|
|
- `POST /api/clusters/[id]/libraries`
|
|
- `DELETE /api/clusters/[id]/libraries/[libraryId]`
|
|
|
|
- [ ] **Task 1.4**: Create cluster media query APIs
|
|
- `GET /api/clusters/[id]/videos`
|
|
- `GET /api/clusters/[id]/photos`
|
|
- `GET /api/clusters/[id]/texts`
|
|
- `GET /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
|
|
1. **Non-intrusive**: Clusters are optional, don't change existing workflows
|
|
2. **Visual Clarity**: Use colors and icons for easy identification
|
|
3. **Performance**: Virtual scrolling for cluster views with many items
|
|
4. **Flexibility**: Libraries can belong to multiple clusters
|
|
|
|
### Color Palette for Clusters
|
|
```javascript
|
|
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
|
|
```javascript
|
|
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
|
|
```sql
|
|
-- 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
|
|
|
|
1. **Access Control**: Ensure users can only access libraries they have permissions for
|
|
2. **Validation**: Validate cluster names, prevent SQL injection
|
|
3. **Cascade Deletes**: Properly handle library/cluster deletions
|
|
4. **API Rate Limiting**: Prevent abuse of cluster creation/modification
|
|
|
|
## 📝 Migration Strategy
|
|
|
|
### For Existing Users
|
|
1. Database migration script runs automatically on app start
|
|
2. All existing libraries remain functional (no cluster assignment)
|
|
3. Users can gradually organize libraries into clusters
|
|
4. No breaking changes to existing functionality
|
|
|
|
### Migration Script
|
|
```sql
|
|
-- 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
|