LinkDesk/backend/docs/shot-task-creation-endpoint.md

223 lines
6.0 KiB
Markdown

# Shot Task Creation Endpoint
## Overview
Added a new backend endpoint to create tasks for shots, enabling AJAX-based task status editing in the frontend shot table.
## Endpoint Details
### POST /shots/{shot_id}/tasks
**Purpose**: Create a new task for a specific shot
**Location**: `backend/routers/shots.py` (after `get_shot` endpoint)
**Authentication**: Requires coordinator or admin role
**Parameters**:
- `shot_id` (path): The ID of the shot
- `task_type` (query): The type of task to create (e.g., "layout", "animation")
**Request Example**:
```
POST /shots/1/tasks?task_type=layout
Authorization: Bearer {token}
```
**Response** (201 Created):
```json
{
"task_type": "layout",
"status": "not_started",
"task_id": 123,
"assigned_user_id": null
}
```
**Response** (200 OK - if task already exists):
```json
{
"task_type": "layout",
"status": "in_progress",
"task_id": 123,
"assigned_user_id": 5
}
```
## Implementation
```python
@router.post("/{shot_id}/tasks", response_model=TaskStatusInfo, status_code=status.HTTP_201_CREATED)
async def create_shot_task(
shot_id: int,
task_type: str,
db: Session = Depends(get_db),
current_user: User = Depends(require_coordinator_or_admin)
):
"""Create a new task for a shot"""
shot = db.query(Shot).filter(Shot.id == shot_id).first()
if not shot:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Shot not found"
)
# Check episode access
episode = check_episode_access(shot.episode_id, current_user, db)
# Check if task already exists
existing_task = db.query(Task).filter(
Task.shot_id == shot_id,
Task.task_type == task_type
).first()
if existing_task:
# Return existing task info instead of error (idempotent)
return TaskStatusInfo(
task_type=existing_task.task_type,
status=existing_task.status,
task_id=existing_task.id,
assigned_user_id=existing_task.assigned_user_id
)
# Create the task
task_name = f"{shot.name} - {task_type.title()}"
db_task = Task(
project_id=episode.project_id,
shot_id=shot.id,
task_type=task_type,
name=task_name,
description=f"{task_type.title()} task for {shot.name}",
status=TaskStatus.NOT_STARTED
)
db.add(db_task)
db.commit()
db.refresh(db_task)
return TaskStatusInfo(
task_type=db_task.task_type,
status=db_task.status,
task_id=db_task.id,
assigned_user_id=db_task.assigned_user_id
)
```
## Key Features
### 1. Idempotent Operation
- If task already exists, returns existing task info
- No error thrown for duplicate creation attempts
- Simplifies frontend logic (no need to check existence first)
### 2. Permission Validation
- Requires coordinator or admin role
- Uses `require_coordinator_or_admin` dependency
- Artists cannot create tasks directly
### 3. Access Control
- Validates shot exists
- Checks episode access via `check_episode_access`
- Ensures user has permission to access the project
### 4. Automatic Task Naming
- Format: `{shot_name} - {task_type}`
- Example: "SH010 - Layout"
- Consistent with asset task naming
### 5. Default Values
- Status: `NOT_STARTED`
- Description: Auto-generated
- Project ID: Inherited from episode
- No assignee initially
## Error Responses
### 404 Not Found
```json
{
"detail": "Shot not found"
}
```
### 403 Forbidden
```json
{
"detail": "Insufficient permissions"
}
```
Or:
```json
{
"detail": "Access denied to this project"
}
```
## Comparison with Asset Endpoint
The shot task creation endpoint mirrors the asset version:
| Feature | Asset Endpoint | Shot Endpoint |
|---------|---------------|---------------|
| Path | `/assets/{asset_id}/tasks` | `/shots/{shot_id}/tasks` |
| Permission | Coordinator/Admin | Coordinator/Admin |
| Idempotent | ✅ Yes | ✅ Yes |
| Access Check | `check_project_access` | `check_episode_access` |
| Task Naming | `{asset.name} - {type}` | `{shot.name} - {type}` |
| Project ID | From asset | From episode |
## Frontend Integration
This endpoint is called by:
- `frontend/src/services/task.ts` - `createShotTask()` method
- `frontend/src/components/shot/EditableTaskStatus.vue` - When changing status for non-existent task
**Usage Flow**:
1. User changes task status in shot table
2. Frontend checks if task exists (via `taskId` prop)
3. If no task exists, calls `createShotTask(shotId, taskType)`
4. Backend creates task and returns task ID
5. Frontend then calls `updateTaskStatus(taskId, newStatus)`
6. Status is updated and table refreshes
## Testing
Test file created: `backend/test_shot_task_creation.py`
**Manual Testing**:
1. Navigate to project shots tab
2. Switch to table view
3. Click on a task status cell for a shot without that task
4. Select a status
5. Verify:
- Task is created
- Status is set
- No errors in console
- Table updates correctly
## Related Files
- `backend/routers/shots.py` - Endpoint implementation
- `backend/routers/assets.py` - Reference implementation for assets
- `backend/schemas/shot.py` - TaskStatusInfo schema
- `backend/models/task.py` - Task model
- `frontend/src/services/task.ts` - Frontend service calling this endpoint
- `frontend/src/components/shot/EditableTaskStatus.vue` - Component using this endpoint
## Future Enhancements
Potential improvements:
1. **Bulk Task Creation**: Create multiple tasks at once
2. **Custom Defaults**: Allow project-specific default task settings
3. **Template Support**: Use task templates for consistent setup
4. **Validation**: Validate task_type against allowed types
5. **Webhooks**: Trigger notifications when tasks are created
6. **Audit Log**: Track who created which tasks and when
## Conclusion
The shot task creation endpoint successfully enables AJAX-based task status editing in the shot table, providing a seamless user experience without page refreshes. The implementation follows the same pattern as the asset endpoint, ensuring consistency across the application.