LinkDesk/backend/docs/task-8-custom-status-suppor...

278 lines
8.5 KiB
Markdown

# 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