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

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=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:

# 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:

  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

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 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
  • 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