# Task 8: Backend Task Endpoints Custom Status Support ## Overview This implementation adds support for custom task statuses to all task-related endpoints in the backend. The system now validates statuses against both system statuses and project-specific custom statuses, ensuring proper status resolution across project boundaries. ## Changes Made ### 1. Added Helper Functions (`backend/routers/tasks.py`) #### `get_project_default_status(db: Session, project_id: int) -> str` - Retrieves the default status for a project - Checks for custom statuses with `is_default=True` flag - Falls back to system default "not_started" if no custom default is set - Handles JSON parsing for custom_task_statuses field #### `validate_task_status(db: Session, project_id: int, status_value: str) -> bool` - Validates that a status exists for a specific project - Checks system statuses first (not_started, in_progress, submitted, approved, retake) - Then checks project-specific custom statuses - Returns True if valid, False otherwise - Ensures status isolation between projects ### 2. Updated Task Creation Endpoint **Endpoint**: `POST /tasks/` **Changes**: - Uses `get_project_default_status()` when no status is specified - Validates provided status using `validate_task_status()` - Returns 400 error if invalid status is provided - Maintains backward compatibility with system statuses **Example**: ```python # Use default status if not specified task_data = task.model_dump() if not task_data.get('status') or task_data['status'] == 'not_started': task_data['status'] = get_project_default_status(db, task.project_id) else: # Validate the provided status if not validate_task_status(db, task.project_id, task_data['status']): raise HTTPException( status_code=400, detail=f"Invalid status '{task_data['status']}' for this project" ) ``` ### 3. Updated Task Status Update Endpoint **Endpoint**: `PUT /tasks/{task_id}/status` **Changes**: - Validates new status against project's available statuses - Returns 400 error if status is invalid for the task's project - Supports both system and custom statuses **Example**: ```python # Validate the status for the task's project if not validate_task_status(db, task.project_id, status_update.status): raise HTTPException( status_code=400, detail=f"Invalid status '{status_update.status}' for this project" ) ``` ### 4. Updated Task Update Endpoint **Endpoint**: `PUT /tasks/{task_id}` **Changes**: - Validates status field if it's being updated - Checks status validity before applying update - Maintains existing permission checks ### 5. Updated Bulk Status Update Endpoint **Endpoint**: `PUT /tasks/bulk/status` **Changes**: - Validates status for each task's project before updating - Ensures atomic updates - all tasks succeed or all fail - Provides detailed error messages for invalid statuses - Handles tasks from different projects correctly **Example**: ```python # Validate status for the task's project if not validate_task_status(db, task.project_id, bulk_update.status): errors.append({ "task_id": task_id, "error": f"Invalid status '{bulk_update.status}' for task's project" }) failed_count += 1 continue ``` ## Requirements Addressed ### Requirement 5.3: Default Status for New Tasks ✅ Task creation uses project's default status when not specified ✅ Falls back to system default "not_started" for projects without custom statuses ### Requirement 6.4: Backward Compatibility ✅ System statuses (not_started, in_progress, submitted, approved, retake) remain valid for all projects ✅ Existing tasks with system statuses continue to work ### Requirement 6.5: Status Resolution ✅ Status validation checks both system and custom statuses ✅ Custom statuses are project-specific and don't leak between projects ### Requirement 10.1: Bulk Status Update Validation ✅ Bulk updates validate status for each task's project ✅ Atomic updates ensure consistency ### Requirement 10.2: Cross-Project Handling ✅ Tasks from different projects can be updated in bulk ✅ Each task's status is validated against its own project's statuses ## Testing ### Test Coverage Created comprehensive test suite (`backend/test_task_custom_status_support.py`) covering: 1. **Task Creation with Default Status** - ✅ Default status correctly identified from custom statuses - ✅ Tasks created without explicit status use project default - ✅ Tasks can be created with explicit custom status 2. **Status Validation** - ✅ All system statuses validated successfully - ✅ Custom statuses validated for their project - ✅ Invalid statuses correctly rejected 3. **Status Resolution Across Projects** - ✅ Project 1 custom statuses rejected for Project 2 - ✅ Project 2 custom statuses rejected for Project 1 - ✅ System statuses valid for all projects - ✅ Each project has its own default status 4. **Bulk Status Update Validation** - ✅ Status validated for each task's project - ✅ System statuses valid for all tasks - ✅ Custom statuses only valid for their project 5. **Projects Without Custom Statuses** - ✅ Use system default "not_started" - ✅ System statuses remain valid - ✅ Custom statuses from other projects rejected ### Test Results ``` ============================================================ Testing Task Endpoints Custom Status Support ============================================================ === Test 1: Task Creation with Default Status === ✓ Default status correctly identified: custom_todo ✓ Task created with default status: custom_todo ✓ Task created with explicit custom status: custom_doing ✓ Test 1 PASSED === Test 2: Status Validation === ✓ All system statuses validated successfully ✓ All custom statuses validated successfully ✓ Invalid statuses correctly rejected ✓ Test 2 PASSED === Test 3: Status Resolution Across Projects === ✓ Project 1 custom status correctly rejected for Project 2 ✓ Project 2 custom status correctly rejected for Project 1 ✓ System statuses valid for both projects ✓ Project 1 default: custom_todo, Project 2 default: project2_status ✓ Test 3 PASSED === Test 4: Bulk Status Update Validation === ✓ Validated 2 tasks from Project 1 ✓ Validated 0 tasks from Project 2 ✓ System statuses valid for all 2 tasks ✓ Test 4 PASSED === Test 5: Project Without Custom Statuses === ✓ Project without custom statuses uses system default: not_started ✓ System statuses valid for project without custom statuses ✓ Custom statuses from other projects correctly rejected ✓ Test 5 PASSED ============================================================ ✓ ALL TESTS PASSED ============================================================ ``` ## API Behavior ### Task Creation ```json POST /tasks/ { "project_id": 1, "name": "New Task", "task_type": "modeling", // status not specified - will use project default } ``` ### Task Status Update ```json PUT /tasks/123/status { "status": "custom_todo" // Must be valid for task's project } ``` ### Bulk Status Update ```json PUT /tasks/bulk/status { "task_ids": [1, 2, 3], "status": "custom_doing" // Validated for each task's project } ``` ## Error Handling ### Invalid Status Error ```json { "detail": "Invalid status 'custom_nonexistent' for this project" } ``` ### Bulk Update Errors ```json { "success_count": 2, "failed_count": 1, "errors": [ { "task_id": 3, "error": "Invalid status 'custom_todo' for task's project" } ] } ``` ## Database Schema No database changes required. The implementation uses existing fields: - `projects.custom_task_statuses` (JSON) - stores custom statuses - `tasks.status` (String) - stores status value ## Backward Compatibility ✅ **Fully backward compatible** - Existing tasks with system statuses continue to work - Projects without custom statuses use system defaults - System statuses remain valid for all projects - No migration required ## Next Steps The frontend components should be updated to: 1. Fetch custom statuses from `/projects/{id}/task-statuses` endpoint 2. Display custom status colors in UI 3. Use custom statuses in status dropdowns and filters 4. Handle validation errors from backend ## Related Files - `backend/routers/tasks.py` - Main implementation - `backend/routers/projects.py` - Custom status management endpoints - `backend/models/task.py` - Task model (status field is String) - `backend/models/project.py` - Project model (custom_task_statuses field) - `backend/test_task_custom_status_support.py` - Test suite