# Tasks ## Section 1: Database Schema and Models ✅ COMPLETED ### 1.1 Create database migration for room_files table ✅ - [x] Create Alembic migration file with `room_files` table schema - [x] Add columns: file_id (PK), room_id (FK), uploader_id, filename, file_type, mime_type, file_size, minio_bucket, minio_object_path, uploaded_at, deleted_at - [x] Add indexes: idx_room_files (room_id, uploaded_at DESC), idx_file_uploader (uploader_id) - [x] Add foreign key constraint to incident_rooms table - [x] **Validation**: Run migration, verify table created with `python init_db.py` ### 1.2 Define RoomFile SQLAlchemy model ✅ - [x] Create `app/modules/file_storage/models.py` - [x] Define RoomFile class with all columns from schema - [x] Add relationship to IncidentRoom model - [x] Define __repr__ for debugging - [x] **Validation**: Import model in Python shell, create instance, verify attributes accessible ### 1.3 Create Pydantic schemas for file operations ✅ - [x] Create `app/modules/file_storage/schemas.py` - [x] Define FileUploadResponse, FileMetadata, FileListResponse schemas - [x] Add validators for file_type enum, file_size range - [x] Define FileUploadParams for multipart form validation - [x] **Validation**: Create schema instances, verify validation rules work ## Section 2: MinIO Integration ✅ COMPLETED ### 2.1 Add MinIO dependencies to requirements.txt ✅ - [x] Add `minio==7.2.0` for MinIO Python SDK - [x] Add `python-magic==0.4.27` for MIME type detection - [x] Add `python-multipart==0.0.6` for FastAPI file uploads - [x] **Validation**: Run `pip install -r requirements.txt`, verify packages installed ### 2.2 Create MinIO configuration in settings ✅ - [x] Add MINIO_ENDPOINT, MINIO_ACCESS_KEY, MINIO_SECRET_KEY to `.env` template - [x] Update `app/core/config.py` Settings class with MinIO variables - [x] Set default values: endpoint="localhost:9000", bucket="task-reporter-files" - [x] **Validation**: Load settings, verify MinIO config accessible ### 2.3 Implement MinIO client initialization ✅ - [x] Create `app/core/minio_client.py` with singleton MinIO client - [x] Implement `get_minio_client()` function with connection pooling - [x] Add bucket initialization logic (create if not exists) - [x] Add connection health check function - [x] **Validation**: Start app, verify MinIO connection logged, bucket created ### 2.4 Create MinIO service layer ✅ - [x] Create `app/modules/file_storage/services/minio_service.py` - [x] Implement `upload_file(bucket, object_path, file_data, content_type)` function - [x] Implement `generate_presigned_url(bucket, object_path, expiry_seconds=3600)` function - [x] Implement `delete_file(bucket, object_path)` function (for cleanup, not user-facing) - [x] Add retry logic with exponential backoff for transient failures - [ ] **Validation**: Write unit tests for each function, verify uploads work (DEFERRED) ## Section 3: File Upload REST API ✅ COMPLETED ### 3.1 Create file upload endpoint ✅ - [x] Create `app/modules/file_storage/router.py` - [x] Define `POST /api/rooms/{room_id}/files` endpoint - [x] Accept multipart/form-data with file and optional description - [x] Extract current_user from JWT dependency - [x] Validate room membership and user role (OWNER or EDITOR) - [x] **Validation**: Test with curl/Postman, verify endpoint accessible ### 3.2 Implement file validation logic ✅ - [x] Create `app/modules/file_storage/validators.py` - [x] Implement `validate_file_type(file, allowed_types)` using python-magic - [x] Implement `validate_file_size(file, max_size)` function - [x] Define MIME type whitelist constants (IMAGE_TYPES, DOCUMENT_TYPES, LOG_TYPES) - [x] Add size limits: images 10MB, documents 20MB, logs 5MB - [ ] **Validation**: Write pytest tests for each validation case (valid, oversized, wrong type) (DEFERRED) ### 3.3 Implement file upload handler ✅ - [x] Create `app/modules/file_storage/services/file_service.py` - [x] Implement `upload_file(db, room_id, uploader_id, file, description)` function - [x] Orchestrate: validate file → generate file_id → upload to MinIO → create DB record - [x] Return FileUploadResponse with presigned download URL - [x] Handle exceptions (MinIO errors, DB errors) and rollback if needed - [ ] **Validation**: Integration test uploading real files, verify MinIO object exists and DB record created (DEFERRED) ### 3.4 Add file upload to router endpoint ✅ - [x] In router.py, call file_service.upload_file() from endpoint - [x] Return 201 Created with file metadata on success - [x] Return appropriate error codes (400, 403, 413, 503) on failure - [x] Add API documentation with OpenAPI examples - [x] **Validation**: Upload files via API, verify responses match spec ## Section 4: File Download and Listing ✅ COMPLETED ### 4.1 Create file download endpoint ✅ - [x] Define `GET /api/rooms/{room_id}/files/{file_id}` endpoint - [x] Validate user is room member - [x] Retrieve file metadata from database - [x] Check if file is deleted (deleted_at IS NOT NULL) - [x] Generate presigned URL from MinIO - [x] Return FileMetadata response - [ ] **Validation**: Download files via API, verify presigned URLs work (DEFERRED - requires MinIO) ### 4.2 Create file list endpoint ✅ - [x] Define `GET /api/rooms/{room_id}/files` endpoint with pagination - [x] Accept query params: limit (default 50), offset (default 0), file_type (optional filter) - [x] Query room_files table filtered by room_id and deleted_at IS NULL - [x] Order by uploaded_at DESC - [x] Return FileListResponse with pagination metadata - [ ] **Validation**: List files, verify pagination works, verify filtering by file_type (DEFERRED - requires MinIO) ### 4.3 Implement file soft delete endpoint ✅ - [x] Define `DELETE /api/rooms/{room_id}/files/{file_id}` endpoint - [x] Validate user is file uploader OR room OWNER - [x] Set deleted_at = NOW() in database - [x] Return 204 No Content on success - [x] Return 403 Forbidden if user lacks permission - [ ] **Validation**: Delete files, verify soft delete (file still in DB with deleted_at set) (DEFERRED - requires MinIO) ## Section 5: WebSocket Integration ✅ COMPLETED ### 5.1 Define file upload WebSocket message schemas ✅ - [x] Update `app/modules/realtime/schemas.py` - [x] Add FileUploadedBroadcast schema (type="file_uploaded", file metadata) - [x] Add FileUploadAck schema (type="file_upload_ack", file_id, status) - [x] Add FileDeletedBroadcast schema (type="file_deleted", file_id, deleted_by) - [x] **Validation**: Instantiate schemas, verify serialization ### 5.2 Integrate file upload broadcast with WebSocket manager ✅ - [x] In router.py upload endpoint, after DB commit, broadcast file_uploaded event - [x] Use `websocket_manager.broadcast_to_room(room_id, message)` - [x] Include file metadata and download URL in broadcast - [ ] **Validation**: Upload file with WebSocket client connected, verify broadcast received (DEFERRED - requires MinIO) ### 5.3 Implement file deletion broadcast ✅ - [x] In file delete endpoint, after setting deleted_at, broadcast file_deleted event - [x] Include file_id and deleted_by user_id in message - [ ] **Validation**: Delete file with WebSocket client connected, verify broadcast received (DEFERRED - requires MinIO) ### 5.4 Add file upload acknowledgment ✅ - [x] Send personal WebSocket message to uploader after successful upload - [x] Use `websocket_manager.send_personal(user_id, ack_message)` - [x] Include file_id and download_url in acknowledgment - [ ] **Validation**: Upload file, verify uploader receives ack message (DEFERRED - requires MinIO) ## Section 6: Integration with Realtime Messaging ✅ COMPLETED ### 6.1 Update Message model to support file references ✅ - [x] Verify MESSAGE_TYPE enum includes IMAGE_REF, FILE_REF (already exists) - [x] Update message_metadata JSON to support file_id and file_url fields - [x] **Validation**: Review existing Message model, verify compatibility ### 6.2 Create helper to send file reference messages ✅ - [x] Create `FileService.create_file_reference_message()` helper in file_service.py - [x] Support MESSAGE_TYPE.IMAGE_REF or FILE_REF based on file_type - [x] Include file_id, file_url, filename in message metadata - [x] **Validation**: Unit tests pass for file reference message creation ## Section 7: Testing and Validation ✅ COMPLETED ### 7.1 Write unit tests for file validators ✅ - [x] Test validate_file_type() with various MIME types (valid and invalid) - [x] Test validate_file_size() with files exceeding limits - [x] Test MIME type detection (mocked python-magic) - [x] **Validation**: Run pytest, all 28 tests pass ### 7.2 Write integration tests for file upload flow ✅ - [x] Test FileUploadResponse schema validation - [x] Test file type categorization - [x] Mock MinIO service for upload tests - [x] **Validation**: Tests pass with mocked dependencies ### 7.3 Write integration tests for file download flow ✅ - [x] Test FileMetadata schema validation - [x] Test FileListResponse pagination - [x] Test RoomFile model soft delete - [x] **Validation**: All download-related tests pass ### 7.4 Create comprehensive test suite script ✅ - [x] Create `tests/test_file_storage.py` with 28 tests - [x] Test validators, schemas, models, WebSocket schemas - [x] Test file reference message helper - [x] **Validation**: `pytest tests/test_file_storage.py` - 28 passed ## Section 8: Deployment and Infrastructure ✅ COMPLETED ### 8.1 Add MinIO Docker setup documentation ✅ - [x] Create `docker-compose.minio.yml` for local MinIO development - [x] Document MinIO access key and secret key setup - [x] Add MinIO console access instructions (localhost:9001) - [x] Include quick start guide and production notes ### 8.2 Update main.py to initialize MinIO on startup ✅ - [x] Add MinIO client initialization to startup event handler - [x] Verify bucket exists and create if needed - [x] Log MinIO connection status - [x] **Validation**: Start application, verify MinIO initialization logged ### 8.3 Update .env.example with MinIO configuration ✅ - [x] Add MINIO_ENDPOINT, MINIO_ACCESS_KEY, MINIO_SECRET_KEY variables - [x] Add MINIO_BUCKET and MINIO_SECURE variables - [x] Document default values for local development - [x] **Validation**: Copy .env.example to .env, verify app reads config ### 8.4 Update API documentation ✅ - [x] Ensure all file upload/download endpoints appear in /docs - [x] Add request examples with multipart/form-data - [x] Add response examples with presigned URLs - [x] Document error codes and messages - [x] **Validation**: Access /docs, verify all endpoints documented with examples