LinkDesk/frontend/docs/shot-detail-403-fix.md

4.1 KiB

Shot Detail Panel 403 Error - Troubleshooting Guide

Problem

When clicking on a shot to view its details, you receive a 403 Forbidden error.

Root Cause

The backend GET /shots/{shot_id} endpoint checks project access permissions:

  • Artists: Must be members of the project containing the shot
  • Coordinators & Admins: Have access to all shots

Diagnosis Steps

1. Check Your User Role

// In browser console
console.log(localStorage.getItem('user'))

Look for the role field. If it's "artist", you need to be a project member.

2. Check Project Membership

If you're an artist:

  1. Navigate to the project that contains the shot
  2. Check if you're listed as a project member
  3. If not, ask a coordinator or admin to add you to the project

3. Check Browser Console

Open browser DevTools (F12) and look for the error:

GET http://localhost:8000/shots/{shot_id} 403 (Forbidden)

The response will show:

{
  "detail": "Access denied to this project"
}

Solutions

For Coordinators/Admins:

  1. Go to the project page
  2. Click "Manage Members" or similar
  3. Add the artist to the project with appropriate department role

Solution 2: Change User Role (If Appropriate)

For Admins:

  1. Go to User Management
  2. Find the user
  3. Change role to coordinator if they need broader access
  4. Or grant admin permission

Solution 3: Modify Backend (Development Only)

If you want to allow all users to view all shots (not recommended for production):

File: backend/routers/shots.py

Modify the check_episode_access function:

def check_episode_access(episode_id: int, current_user: User, db: Session):
    """Check if user has access to the episode and its project."""
    # Check if episode exists
    episode = db.query(Episode).filter(Episode.id == episode_id).first()
    if not episode:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Episode not found"
        )
    
    # OPTION A: Remove access check entirely (allow all authenticated users)
    return episode
    
    # OPTION B: Keep original logic (recommended)
    # Check project access for artists
    if current_user.role == UserRole.ARTIST:
        member = db.query(ProjectMember).filter(
            ProjectMember.project_id == episode.project_id,
            ProjectMember.user_id == current_user.id
        ).first()
        if not member:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="Access denied to this project"
            )
    
    return episode

Testing

Test Script

Run this to verify access:

cd backend
python test_shot_detail_403.py

Manual Test

  1. Login as an admin or coordinator
  2. Navigate to a project
  3. Click on any shot
  4. Shot detail panel should open without errors

Prevention

For New Projects

When creating a project, immediately add all relevant artists as members.

For Existing Projects

Regularly audit project membership to ensure artists have access to their assigned work.

  • Backend: backend/routers/shots.py (line 52-72, 428-445)
  • Frontend: frontend/src/components/shot/ShotDetailPanel.vue
  • Service: frontend/src/services/shot.ts

API Endpoint Details

GET /shots/{shot_id}

Authentication: Required (Bearer token)

Authorization:

  • Coordinators: Access to all shots
  • Admins: Access to all shots
  • Artists: Access only to shots in projects where they are members

Response Codes:

  • 200: Success
  • 401: Unauthorized (not logged in)
  • 403: Forbidden (not a project member)
  • 404: Shot not found

Quick Fix for Development

If you're testing and just need to see the shot detail panel work:

  1. Login as admin (admins can see all shots)
  2. Or add yourself to the project:
    • Go to project settings
    • Add your user as a project member
    • Assign a department role

Notes

  • This is working as designed for security
  • Project-based access control is a core feature
  • Artists should only see shots from their assigned projects
  • Coordinators and admins have global access