# Project Thumbnail Implementation ## Overview This document describes the implementation of project thumbnail upload functionality for the VFX Project Management System. ## Requirements Based on Requirement 2.1, the system allows coordinators and administrators to: - Upload thumbnail images for projects - Replace existing thumbnails - Delete thumbnails - View thumbnails on project cards ## Implementation Details ### 1. Database Changes **Migration Script**: `backend/migrate_project_thumbnail.py` Added `thumbnail_path` column to the `projects` table: ```sql ALTER TABLE projects ADD COLUMN thumbnail_path VARCHAR ``` **Model Update**: `backend/models/project.py` ```python thumbnail_path = Column(String, nullable=True) # Path to project thumbnail image ``` ### 2. API Endpoints #### Upload Thumbnail **Endpoint**: `POST /api/projects/{project_id}/thumbnail` **Access**: Coordinators and Admins only **Request**: Multipart form data with image file **Response**: ```json { "message": "Thumbnail uploaded successfully", "thumbnail_url": "/api/files/projects/{project_id}/thumbnail" } ``` **Features**: - Validates file format (jpg, jpeg, png, gif, webp) - Validates file size (max 10MB) - Processes and resizes images to max 800x600 while maintaining aspect ratio - Converts images with transparency to RGB with white background - Generates unique filenames with timestamp and hash - Automatically deletes old thumbnail when uploading new one - Stores processed images in `uploads/project_thumbnails/` #### Delete Thumbnail **Endpoint**: `DELETE /api/projects/{project_id}/thumbnail` **Access**: Coordinators and Admins only **Response**: 204 No Content **Features**: - Removes thumbnail file from filesystem - Clears `thumbnail_path` in database - Returns 404 if project has no thumbnail #### Serve Thumbnail **Endpoint**: `GET /api/files/projects/{project_id}/thumbnail` **Access**: All authenticated users (with project access) **Response**: Image file with appropriate content-type **Features**: - Checks user has access to the project - Artists can only access thumbnails for projects they're members of - Returns 404 if thumbnail doesn't exist - Serves image with proper MIME type ### 3. Schema Updates **File**: `backend/schemas/project.py` Added `thumbnail_url` field to response schemas: ```python class ProjectResponse(ProjectBase): # ... existing fields ... thumbnail_url: Optional[str] = None class ProjectListResponse(BaseModel): # ... existing fields ... thumbnail_url: Optional[str] = None ``` ### 4. Router Updates **File**: `backend/routers/projects.py` Updated project endpoints to include thumbnail URL: ```python # In list_projects if project.thumbnail_path: project_data.thumbnail_url = f"/api/files/projects/{project.id}/thumbnail" # In get_project if project.thumbnail_path: project_data.thumbnail_url = f"/api/files/projects/{project.id}/thumbnail" # In update_project 'thumbnail_url': f"/api/files/projects/{db_project.id}/thumbnail" if db_project.thumbnail_path else None ``` ## File Storage Structure ``` backend/ └── uploads/ └── project_thumbnails/ ├── project_1_20241119_123456_a1b2c3d4.jpg ├── project_2_20241119_123457_e5f6g7h8.jpg └── ... ``` ## Image Processing The system processes uploaded thumbnails as follows: 1. **Format Validation**: Only accepts jpg, jpeg, png, gif, webp 2. **Size Validation**: Maximum 10MB file size 3. **Color Conversion**: Converts RGBA/LA/P modes to RGB with white background 4. **Resizing**: Maintains aspect ratio while fitting within 800x600 pixels 5. **Optimization**: Saves as JPEG with 90% quality and optimization enabled ## Access Control | Role | Upload | Delete | View | |------|--------|--------|------| | Admin | ✓ | ✓ | ✓ | | Coordinator | ✓ | ✓ | ✓ | | Director | ✗ | ✗ | ✓ | | Artist | ✗ | ✗ | ✓ (own projects only) | | Developer | ✗ | ✗ | ✓ | ## Testing A test script is provided at `backend/test_project_thumbnail.py` that verifies: 1. Thumbnail upload 2. Thumbnail URL in project responses 3. Thumbnail download 4. Thumbnail deletion 5. Thumbnail removal verification To run the test: ```bash cd backend python test_project_thumbnail.py ``` **Note**: The backend server must be running on `http://localhost:8000` ## Error Handling | Error | Status Code | Description | |-------|-------------|-------------| | Invalid file format | 400 | File extension not in allowed list | | File too large | 413 | File exceeds 10MB limit | | Image processing failed | 400 | PIL failed to process image | | Project not found | 404 | Invalid project_id | | No thumbnail | 404 | Project has no thumbnail | | Access denied | 403 | User lacks permission | ## Frontend Integration The frontend can now: 1. Display thumbnails on project cards using `project.thumbnail_url` 2. Upload thumbnails in project settings 3. Replace existing thumbnails 4. Remove thumbnails 5. Show placeholder when no thumbnail exists Example usage: ```typescript // Display thumbnail // Upload thumbnail const formData = new FormData() formData.append('file', file) await apiClient.post(`/projects/${projectId}/thumbnail`, formData) // Delete thumbnail await apiClient.delete(`/projects/${projectId}/thumbnail`) ``` ## Next Steps The following frontend tasks remain to be implemented: - Task 22: Implement frontend project thumbnail upload component - Task 22.1: Add thumbnail preview and management - Task 22.2: Integrate thumbnail upload in project settings - Task 22.3: Update project card to display thumbnails - Task 22.4: Update project type definitions ## Related Files - `backend/models/project.py` - Project model with thumbnail_path - `backend/routers/projects.py` - Thumbnail upload/delete endpoints - `backend/routers/files.py` - Thumbnail serving endpoint - `backend/schemas/project.py` - Response schemas with thumbnail_url - `backend/migrate_project_thumbnail.py` - Database migration script - `backend/test_project_thumbnail.py` - Test script