8.5 KiB
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=Trueflag - 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:
# 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:
# 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:
# 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:
-
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
-
Status Validation
- ✅ All system statuses validated successfully
- ✅ Custom statuses validated for their project
- ✅ Invalid statuses correctly rejected
-
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
-
Bulk Status Update Validation
- ✅ Status validated for each task's project
- ✅ System statuses valid for all tasks
- ✅ Custom statuses only valid for their project
-
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
POST /tasks/
{
"project_id": 1,
"name": "New Task",
"task_type": "modeling",
// status not specified - will use project default
}
Task Status Update
PUT /tasks/123/status
{
"status": "custom_todo" // Must be valid for task's project
}
Bulk Status Update
PUT /tasks/bulk/status
{
"task_ids": [1, 2, 3],
"status": "custom_doing" // Validated for each task's project
}
Error Handling
Invalid Status Error
{
"detail": "Invalid status 'custom_nonexistent' for this project"
}
Bulk Update Errors
{
"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 statusestasks.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:
- Fetch custom statuses from
/projects/{id}/task-statusesendpoint - Display custom status colors in UI
- Use custom statuses in status dropdowns and filters
- Handle validation errors from backend
Related Files
backend/routers/tasks.py- Main implementationbackend/routers/projects.py- Custom status management endpointsbackend/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