32 KiB
Cluster Folder View Tab - Design Document
📋 Executive Summary
Feature: Add a "Folders" tab to cluster pages that displays hierarchical folder structure instead of flat media lists.
Problem: Currently, the Videos/Photos/Texts tabs in cluster pages show a flat list of all media items without preserving the folder hierarchy. This makes it difficult to:
- Navigate media by folder structure
- Understand where files are physically located
- Browse content in the same hierarchical way as the Folder Viewer
Solution: Add a "Folders" tab that provides hierarchical navigation across all libraries in a cluster, with breadcrumb trails and library-level organization.
🎯 Requirements Analysis
Current State
The cluster page at /clusters/[id]/page.tsx currently has 4 tabs:
- Videos Tab: Flat grid of all videos using
InfiniteVirtualGrid+/api/clusters/[id]/videos - Photos Tab: Flat grid of all photos using
InfiniteVirtualGrid+/api/clusters/[id]/photos - Texts Tab: Flat grid of all texts using
InfiniteVirtualGrid+/api/clusters/[id]/texts - Stats Tab: Statistics and library list
User Requirement Clarification
Question Answered: Yes, the current tabs flatten all media without folder structure.
Proposed Enhancement: Add a 5th tab called "Folders" that:
- Shows folder hierarchy similar to the Folder Viewer (
/folder-viewer) - Displays libraries in the cluster as top-level "virtual folders"
- Allows users to drill down into each library's folder structure
- Maintains breadcrumb navigation (Cluster → Library → Folder1 → Folder2)
- Supports all media types (videos, photos, texts) within the folder view
🏗️ Design Approach: Virtual Root with Library Folders ✅ APPROVED
Selected Design
Decision: Option 1 - Virtual Root with Library Folders (User Approved)
Concept: The Folders tab starts at a "virtual root" showing all cluster libraries as top-level folders.
Navigation Flow:
Cluster: "My Movies" (Virtual Root)
├── 📁 Library: /mnt/movies/action
├── 📁 Library: /mnt/movies/comedy
└── 📁 Library: /nas/classics
Click on "/mnt/movies/action" →
/mnt/movies/action (Library Root)
├── 📁 2023
├── 📁 2024
└── 🎬 standalone-movie.mp4
Click on "2023" →
/mnt/movies/action/2023
├── 📁 January
├── 📁 February
└── 🎬 new-years-movie.mp4
Breadcrumb Example:
My Movies > /mnt/movies/action > 2023 > January
Why This Approach:
- ✅ Clear entry point (virtual root shows all libraries)
- ✅ Consistent with existing Stats tab (which lists libraries)
- ✅ Easy to switch between different libraries in the cluster
- ✅ Natural hierarchy: Cluster → Library → Folders
- ✅ Can reuse existing
VirtualizedFolderGridcomponent logic - ✅ Preserves physical path information
- ✅ No folder name conflicts between libraries
- ✅ Straightforward implementation with proven patterns
Trade-offs Accepted:
- Extra click needed to enter a library (acceptable for clarity)
- Separate library view rather than merged (preferred for transparency)
🎨 Detailed Design Implementation
UI Components
1. Virtual Root View (Initial State)
┌─────────────────────────────────────────────────────────────┐
│ [←] Folders (3 libraries) │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ 📁 │ │ 📁 │ │ 📁 │ │
│ │ │ │ │ │ │ │
│ │ /mnt/movies/ │ │ /nas/media/ │ │ /storage/ │ │
│ │ action │ │ classics │ │ anime │ │
│ │ │ │ │ │ │ │
│ │ 245 videos │ │ 89 videos │ │ 1,234 videos │ │
│ │ 15.3 GB │ │ 8.2 GB │ │ 156.7 GB │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
Features:
- Shows all cluster libraries as folder cards
- Displays library statistics (item count, size)
- Clickable to navigate into each library
- Uses same visual style as
VirtualizedFolderGridfolder cards
2. Drilled-Down Folder View
Once user clicks a library, show normal folder hierarchy:
┌─────────────────────────────────────────────────────────────┐
│ [←] My Movies > /mnt/movies/action > 2023 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ 📁 │ │ 🎬 │ │ 🎬 │ │
│ │ │ │ [thumbnail] │ │ [thumbnail] │ │
│ │ January │ │ │ │ │ │
│ │ │ │ movie1.mp4 │ │ movie2.mkv │ │
│ │ 15 items │ │ 1.2 GB │ │ 850 MB │ │
│ │ │ │ ⭐⭐⭐⭐☆ │ │ ⭐⭐⭐☆☆ │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
Features:
- Breadcrumb navigation showing: Cluster > Library > Folders
- Mixed display of folders and media files
- Same interaction model as Folder Viewer
- Support for ratings, bookmarks on individual files
- Click folders to drill down, click media to open viewers
Navigation Logic
Breadcrumb Structure
Format: ClusterName > LibraryPath > Subfolder1 > Subfolder2
States:
- Virtual Root:
My Movies(no breadcrumb path) - Library Root:
My Movies > /mnt/movies/action - Subfolder:
My Movies > /mnt/movies/action > 2023 > January
Back Button Behavior:
- From subfolder → parent folder
- From library root → virtual root
- From virtual root → disabled (already at top)
API Requirements
New API Endpoint: /api/clusters/[id]/folders
Purpose: Fetch folder contents for a specific path within a cluster.
Query Parameters:
path(optional): Folder path to list. If empty/null, return library list (virtual root)limit,offset: Pagination
Response Format:
Virtual Root (no path provided):
{
"isVirtualRoot": true,
"libraries": [
{
"id": 1,
"path": "/mnt/movies/action",
"itemCount": 245,
"totalSize": 16434124800,
"videoCount": 245,
"photoCount": 0,
"textCount": 0
}
]
}
Folder Contents (path provided):
{
"isVirtualRoot": false,
"currentPath": "/mnt/movies/action/2023",
"libraryRoot": "/mnt/movies/action",
"items": [
{
"name": "January",
"path": "/mnt/movies/action/2023/January",
"isDirectory": true,
"size": 0,
"itemCount": 15
},
{
"name": "movie1.mp4",
"path": "/mnt/movies/action/2023/movie1.mp4",
"isDirectory": false,
"id": 12345,
"type": "video",
"size": 1258291200,
"thumbnail": "/api/videos/12345/thumbnail",
"avg_rating": 4.5,
"star_count": 8,
"bookmark_count": 2
}
],
"total": 16,
"limit": 50,
"offset": 0
}
Path Validation:
- Verify requested path belongs to one of the cluster's libraries
- Return 403 if path is outside cluster libraries
- Handle both absolute and relative paths
Component Architecture
New Component: ClusterFolderView.tsx
Location: /src/components/cluster-folder-view.tsx
Props:
interface ClusterFolderViewProps {
clusterId: number;
libraries: Library[];
onVideoClick: (video: FileSystemItem) => void;
onPhotoClick: (photo: FileSystemItem, index: number) => void;
onTextClick: (text: FileSystemItem) => void;
}
State Management:
const [currentPath, setCurrentPath] = useState<string | null>(null); // null = virtual root
const [items, setItems] = useState<FileSystemItem[]>([]);
const [isVirtualRoot, setIsVirtualRoot] = useState(true);
const [breadcrumbs, setBreadcrumbs] = useState<BreadcrumbItem[]>([]);
Key Methods:
fetchFolderContents(path?: string): Fetch items from APIhandleItemClick(item): Navigate folders or open media viewershandleBreadcrumbClick(path): Navigate to breadcrumb locationhandleBackClick(): Navigate to parentgetBreadcrumbs(path): Generate breadcrumb array
Reusable Components
Reuse from existing codebase:
-
✅
VirtualizedFolderGrid- for rendering folders/media- Already supports breadcrumbs, back button
- Already handles folder/media mixed display
- Need minor props extension for cluster context
-
✅
UnifiedVideoPlayer- video playback modal -
✅
PhotoViewer- photo viewing modal -
✅
TextViewer- text viewing modal
Why reuse VirtualizedFolderGrid?
- Proven component with all necessary features
- Consistent UX with Folder Viewer page
- Saves development time
- Maintains design consistency
Integration Points
Modify: /src/app/clusters/[id]/page.tsx
Add "Folders" Tab:
<button
onClick={() => setActiveTab('folders')}
className={/* tab styles */}
>
<Folder className="h-4 w-4 inline mr-2" />
Folders
</button>
Add Tab Content:
{activeTab === 'folders' && (
<ClusterFolderView
clusterId={clusterId}
libraries={libraries}
onVideoClick={handleVideoClick}
onPhotoClick={handlePhotoClick}
onTextClick={handleTextClick}
/>
)}
🔄 User Experience Flow
Scenario 1: Browse Cluster Folders from Scratch
- User navigates to cluster page
/clusters/3 - User clicks "Folders" tab
- Virtual Root displays showing 3 library cards:
/mnt/movies/action(245 videos)/nas/media/classics(89 videos)/storage/anime(1,234 videos)
- User clicks
/mnt/movies/actionlibrary card - Library root displays showing folders:
- Breadcrumb:
My Movies > /mnt/movies/action - Folders:
2023/,2024/,standalone-movie.mp4
- Breadcrumb:
- User clicks
2023/folder - Subfolder displays:
- Breadcrumb:
My Movies > /mnt/movies/action > 2023 - Folders/Files:
January/,February/,new-years-movie.mp4
- Breadcrumb:
- User clicks video file → Video player modal opens
- User closes modal → returns to same folder view
- User clicks breadcrumb "My Movies" → returns to virtual root
Scenario 2: Quick Switch Between Libraries
- User is browsing
/mnt/movies/action/2023/January - User clicks "My Movies" in breadcrumb → returns to virtual root
- User clicks
/nas/media/classicslibrary card - Now browsing different library in same cluster
🛠️ Technical Implementation Plan
Phase 1: Backend API (Estimated: 2-3 hours)
File: /src/app/api/clusters/[id]/folders/route.ts
Tasks:
- ✅ Create new API route
- ✅ Handle virtual root (no path) → return library list with stats
- ✅ Handle path parameter → return folder contents
- ✅ Validate path belongs to cluster libraries
- ✅ Reuse existing file system scanning logic from
/api/folder-viewer - ✅ Add pagination support
- ✅ Add error handling (404, 403, 500)
Database Queries:
-- Get cluster libraries
SELECT l.* FROM libraries l
INNER JOIN library_cluster_mapping lcm ON l.id = lcm.library_id
WHERE lcm.cluster_id = ?
-- Get media stats for library (for virtual root cards)
SELECT
COUNT(*) as total_count,
SUM(size) as total_size,
SUM(CASE WHEN type = 'video' THEN 1 ELSE 0 END) as video_count,
SUM(CASE WHEN type = 'photo' THEN 1 ELSE 0 END) as photo_count,
SUM(CASE WHEN type = 'text' THEN 1 ELSE 0 END) as text_count
FROM media
WHERE library_id = ?
-- Get media items in folder (for drill-down)
SELECT * FROM media
WHERE library_id = ? AND path LIKE ?
Phase 2: ClusterFolderView Component (Estimated: 3-4 hours)
File: /src/components/cluster-folder-view.tsx
Tasks:
- ✅ Create base component structure
- ✅ Implement virtual root library card rendering
- ✅ Implement folder navigation state management
- ✅ Integrate with
VirtualizedFolderGridfor folder display - ✅ Build breadcrumb system (Cluster → Library → Folders)
- ✅ Handle back navigation logic
- ✅ Connect to folder API endpoint
- ✅ Handle loading states and errors
- ✅ Add folder/media click handlers
- ✅ Style library cards (match cluster theme colors)
Virtual Root Implementation:
// Render library cards
{isVirtualRoot && (
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
{libraries.map(lib => (
<LibraryCard
key={lib.id}
library={lib}
onClick={() => navigateToLibrary(lib.path)}
clusterColor={cluster.color}
/>
))}
</div>
)}
Folder View Implementation:
// Reuse VirtualizedFolderGrid
{!isVirtualRoot && (
<VirtualizedFolderGrid
currentPath={currentPath}
onVideoClick={onVideoClick}
onPhotoClick={onPhotoClick}
onTextClick={onTextClick}
onBackClick={handleBackClick}
onBreadcrumbClick={handleBreadcrumbClick}
breadcrumbs={breadcrumbs}
libraries={libraries}
isClusterView={true} // New prop to adjust breadcrumb display
/>
)}
Phase 3: Cluster Page Integration (Estimated: 1 hour)
File: /src/app/clusters/[id]/page.tsx
Tasks:
- ✅ Import
ClusterFolderViewcomponent - ✅ Add
'folders'toMediaTypeunion type - ✅ Add "Folders" tab button in navigation
- ✅ Add tab content section for folders
- ✅ Pass necessary props (clusterId, libraries, handlers)
- ✅ Test tab switching
Phase 4: VirtualizedFolderGrid Enhancement (Estimated: 1-2 hours)
File: /src/components/virtualized-media-grid.tsx
Tasks:
- ✅ Add optional
isClusterViewprop - ✅ Modify breadcrumb rendering to show cluster name when in cluster view
- ✅ Adjust "Home" breadcrumb behavior (return to virtual root vs library list)
- ✅ Add cluster color theming support (optional enhancement)
- ✅ Test with existing Folder Viewer to ensure no regression
Breadcrumb Modification:
// Current: Libraries > Library Name > Folder
// Cluster: Cluster Name > Library Path > Folder
const breadcrumbs = isClusterView
? [
{ name: clusterName, path: '' }, // Virtual root
...pathBreadcrumbs
]
: pathBreadcrumbs;
Phase 5: Testing & Polish (Estimated: 2 hours)
Test Cases:
- ✅ Virtual root displays all cluster libraries correctly
- ✅ Library statistics are accurate
- ✅ Navigating into library shows correct folder structure
- ✅ Breadcrumbs update correctly at each level
- ✅ Back button works from all levels
- ✅ Clicking breadcrumbs navigates correctly
- ✅ Video/photo/text viewers open from folder view
- ✅ Path validation prevents access outside cluster
- ✅ Pagination works for large folders
- ✅ Empty folders display appropriately
- ✅ Error states (403, 404) display user-friendly messages
- ✅ Tab switching preserves state vs resets (decide behavior)
Edge Cases:
- Empty cluster (no libraries)
- Library with no media files
- Deep folder nesting (20+ levels)
- Very large folders (1000+ items)
- Special characters in folder names
- Symbolic links (how to handle?)
📊 Data Flow Diagram
┌─────────────────────────────────────────────────────────────┐
│ Cluster Page │
│ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌───────┐│
│ │ Videos │ │ Photos │ │ Texts │ │ Folders│ │ Stats ││
│ └────────┘ └────────┘ └────────┘ └───▲────┘ └───────┘│
│ │ │
└──────────────────────────────────────────┼──────────────────┘
│
┌────────────────▼────────────────┐
│ ClusterFolderView Component │
│ - State: currentPath │
│ - State: isVirtualRoot │
│ - State: items │
└────────┬──────────────┬─────────┘
│ │
┌──────────────▼──┐ ┌──────▼──────────────┐
│ Virtual Root │ │ Folder View │
│ (Library Cards) │ │ (VirtualizedGrid) │
└──────────┬──────┘ └──────┬──────────────┘
│ │
│ │
┌──────────▼──────────────────▼──────────┐
│ /api/clusters/[id]/folders │
│ - GET ?path=null → libraries │
│ - GET ?path=/foo → folder contents │
└──────────┬─────────────────────────────┘
│
┌──────────▼──────────┐
│ Database │
│ - libraries table │
│ - media table │
│ - cluster mapping │
└─────────────────────┘
🎨 UI Mockups
Virtual Root State
╔═══════════════════════════════════════════════════════════╗
║ My Movies Cluster [← Back]║
╠═══════════════════════════════════════════════════════════╣
║ [Videos] [Photos] [Texts] [Folders*] [Stats] ║
╠═══════════════════════════════════════════════════════════╣
║ ║
║ Libraries in this cluster: ║
║ ║
║ ╔═══════════╗ ╔═══════════╗ ╔═══════════╗ ║
║ ║ 📁 ║ ║ 📁 ║ ║ 📁 ║ ║
║ ║ ║ ║ ║ ║ ║ ║
║ ║ /mnt/ ║ ║ /nas/ ║ ║ /storage/ ║ ║
║ ║ movies/ ║ ║ media/ ║ ║ anime ║ ║
║ ║ action ║ ║ classics ║ ║ ║ ║
║ ║ ║ ║ ║ ║ ║ ║
║ ║ 245 videos║ ║ 89 videos ║ ║ 1.2K vids ║ ║
║ ║ 15.3 GB ║ ║ 8.2 GB ║ ║ 156.7 GB ║ ║
║ ╚═══════════╝ ╚═══════════╝ ╚═══════════╝ ║
║ ║
╚════════════════════════════════════════════════════════════╝
Library Folder View State
╔═══════════════════════════════════════════════════════════╗
║ My Movies > /mnt/movies/action [← Back]║
╠═══════════════════════════════════════════════════════════╣
║ ║
║ ╔═══════════╗ ╔═══════════╗ ╔═══════════╗ ║
║ ║ 📁 ║ ║ 🎬 ║ ║ 🎬 ║ ║
║ ║ ║ ║ [thumb] ║ ║ [thumb] ║ ║
║ ║ 2023 ║ ║ ║ ║ ║ ║
║ ║ ║ ║ movie1.mp4║ ║ movie2.mkv║ ║
║ ║ 128 items ║ ║ 1.2 GB ║ ║ 850 MB ║ ║
║ ║ ║ ║ ⭐⭐⭐⭐☆ ║ ║ ⭐⭐⭐☆☆ ║ ║
║ ╚═══════════╝ ╚═══════════╝ ╚═══════════╝ ║
║ ║
║ ╔═══════════╗ ╔═══════════╗ ║
║ ║ 📁 ║ ║ 🎬 ║ ║
║ ║ ║ ║ [thumb] ║ ║
║ ║ 2024 ║ ║ ║ ║
║ ║ ║ ║ movie3.mp4║ ║
║ ║ 45 items ║ ║ 2.1 GB ║ ║
║ ║ ║ ║ ⭐⭐⭐⭐⭐ ║ ║
║ ╚═══════════╝ ╚═══════════╝ ║
║ ║
╚════════════════════════════════════════════════════════════╝
Deep Folder Navigation
╔═══════════════════════════════════════════════════════════╗
║ My Movies > /mnt/movies/action > 2023 > Jan [← Back]║
╠═══════════════════════════════════════════════════════════╣
║ ║
║ 15 items ║
║ ║
║ ╔═══════════╗ ╔═══════════╗ ╔═══════════╗ ║
║ ║ 🎬 ║ ║ 🎬 ║ ║ 🎬 ║ ║
║ ║ [thumb] ║ ║ [thumb] ║ ║ [thumb] ║ ║
║ ║ ║ ║ ║ ║ ║ ║
║ ║ movie-a ║ ║ movie-b ║ ║ movie-c ║ ║
║ ║ 1.5 GB ║ ║ 920 MB ║ ║ 2.3 GB ║ ║
║ ║ ⭐⭐⭐⭐☆ ║ ║ ⭐⭐⭐☆☆ ║ ║ ⭐⭐⭐⭐⭐ ║ ║
║ ╚═══════════╝ ╚═══════════╝ ╚═══════════╝ ║
║ ║
╚════════════════════════════════════════════════════════════╝
🚀 Benefits
For Users
- Familiar Navigation: Same folder browsing experience as Folder Viewer
- Context Preservation: Understand where files physically reside
- Flexible Access: Choose between flat view (Videos/Photos/Texts tabs) or hierarchical view (Folders tab)
- Multi-Library Navigation: Easily switch between different libraries in a cluster
- Breadcrumb Clarity: Always know current location in cluster hierarchy
For System
- Code Reuse: Leverages existing
VirtualizedFolderGridcomponent - Consistent UX: Maintains design language across Folder Viewer and Cluster views
- Scalability: Pagination handles large folder structures
- Security: Path validation prevents unauthorized access
- Performance: Virtual root caches library stats
⚠️ Potential Challenges & Solutions
Challenge 1: Breadcrumb Confusion
Problem: Users might confuse cluster breadcrumbs with library breadcrumbs.
Solution:
- Use cluster color theming in breadcrumbs
- First breadcrumb always shows cluster name + icon
- Clear visual separator between cluster and library levels
Challenge 2: Deep Folder Performance
Problem: Very deep folder hierarchies (20+ levels) slow down navigation.
Solution:
- Implement breadcrumb truncation (show first 2 + last 2 levels)
- Add "Show full path" tooltip on hover
- Use pagination for large folder listings
Challenge 3: Cross-Library Search
Problem: User wants to search across all libraries in folder view.
Solution (Future Enhancement):
- Add search bar to Folders tab
- Search results show items with full paths
- Clicking result navigates to that folder
Challenge 4: Virtual Root Empty State
Problem: Cluster has no libraries assigned.
Solution:
- Show empty state: "No libraries in this cluster"
- Provide link to Settings to add libraries
- Suggest using other tabs for cluster-wide media view
📈 Success Metrics
- Adoption Rate: % of cluster page visits that use Folders tab
- Navigation Depth: Average folder depth users navigate to
- Time to Content: Time from cluster page load to media playback
- Bounce Rate: % of users who switch back to flat tabs
- Error Rate: 404/403 errors from invalid path navigation
Target: 30% of users use Folders tab for at least 1 navigation per visit
🔮 Future Enhancements
- Folder Statistics: Show video count, total size for each folder in virtual root
- Folder Bookmarking: Bookmark specific folders within cluster
- Cross-Library Search: Search across all cluster libraries from Folders tab
- Quick Actions: Bulk operations (rate all, bookmark all) from folder view
- Sorting Options: Sort folders by name, size, item count, date
- View Modes: Toggle between grid view and list view
- Folder Thumbnails: Show preview thumbnails from folder contents
- Drag & Drop: Move files between folders (advanced feature)
📝 Implementation Checklist
Backend
- Create
/api/clusters/[id]/folders/route.ts - Implement virtual root handler (no path)
- Implement folder contents handler (with path)
- Add path validation for cluster libraries
- Add pagination support
- Add library statistics calculation
- Add error handling (403, 404, 500)
- Test with various folder structures
Frontend - Component
- Create
/src/components/cluster-folder-view.tsx - Implement virtual root library cards
- Integrate
VirtualizedFolderGridfor folder view - Build breadcrumb system (Cluster → Library → Folders)
- Implement navigation state management
- Add loading/error states
- Style library cards with cluster colors
- Test folder navigation flow
Frontend - Integration
- Update
/src/app/clusters/[id]/page.tsx - Add "Folders" tab to navigation
- Add tab content section
- Connect to
ClusterFolderViewcomponent - Pass props (clusterId, libraries, handlers)
- Test tab switching
Enhancement
- Update
VirtualizedFolderGridfor cluster context - Add
isClusterViewprop - Modify breadcrumb rendering
- Add cluster color theming (optional)
- Test backward compatibility with Folder Viewer
Testing
- Unit tests for API endpoint
- Integration tests for navigation flow
- Test virtual root → library → folder → file
- Test breadcrumb navigation
- Test back button behavior
- Test path validation (403 errors)
- Test pagination in large folders
- Test empty states
- Test error states
- Manual testing with real media libraries
Documentation
- Update progress tracker
- Document API endpoint
- Update component documentation
- Add usage examples
- Create user guide section
🎯 Conclusion
The Folders Tab with Virtual Root approach provides a natural, intuitive way to browse cluster content hierarchically while maintaining consistency with the existing Folder Viewer. By reusing proven components and following established patterns, this feature can be delivered efficiently with minimal risk.
Implementation Status: ✅ APPROVED - Ready for Development
Next Steps:
- ✅ Design reviewed and approved by user
- 🔄 Begin Phase 1: Backend API implementation
- 🔄 Implement frontend components
- 🔄 Test thoroughly with real media libraries
- 🔄 Gather user feedback and refine
Estimated Total Development Time: 8-12 hours
Risk Level: Low (reuses existing patterns and components)
User Impact: High (significantly improves cluster navigation experience)
Document Version: 2.0
Last Updated: 2025-10-12
_Status: ✅ APPROVED - Implementation Ready
Approved By: User
Decision: Option 1 - Virtual Root with Library Folders