# Repository Workspace Specification

## Requirements

### Functional Requirements

1. **Default Project View**: Clicking a project opens the repository workspace
2. **File Browser**: Tree view of repository files and directories
3. **Branch Navigation**: Switch between branches to view different states
4. **File Viewer**: View file contents with syntax highlighting
5. **Quick Edit**: Make small changes and commit them
6. **Repository Switching**: Switch between repositories in a project
7. **Breadcrumb Navigation**: Show current file path with clickable segments

### Non-Functional Requirements

1. **Performance**: File tree loads in < 1 second
2. **Responsiveness**: UI remains responsive during git operations
3. **Usability**: Familiar interface similar to GitHub/GitLab
4. **Accessibility**: Keyboard navigation, screen reader support

## API Specification

### GET /projects/{project_id}/repositories/{repo_id}/files
List files in a directory.

**Query Parameters:**
- `branch` (optional): Branch name, defaults to repository default branch
- `path` (optional): Directory path, defaults to root

**Response 200:**
```json
{
  "path": "src",
  "branch": "main",
  "entries": [
    {
      "name": "components",
      "type": "directory",
      "path": "src/components",
      "mode": "040000"
    },
    {
      "name": "main.py",
      "type": "file",
      "path": "src/main.py",
      "size": 1234,
      "mode": "100644",
      "last_commit": {
        "hash": "abc123",
        "message": "Initial commit",
        "author": "John Doe",
        "date": "2024-01-01T00:00:00Z"
      }
    }
  ]
}
```

**Response 404:** Branch or path not found

### GET /projects/{project_id}/repositories/{repo_id}/files/content
Get file content.

**Query Parameters:**
- `branch` (required): Branch name
- `path` (required): File path

**Response 200:**
```json
{
  "path": "src/main.py",
  "branch": "main",
  "content": "function hello() {\n  return 'world';\n}",
  "size": 42,
  "encoding": "utf-8",
  "language": "python",
  "is_binary": false,
  "last_commit": {
    "hash": "abc123",
    "message": "Initial commit",
    "author": "John Doe",
    "date": "2024-01-01T00:00:00Z"
  }
}
```

**Response 404:** File not found

### GET /projects/{project_id}/repositories/{repo_id}/branches
List branches.

**Response 200:**
```json
{
  "branches": [
    {
      "name": "main",
      "is_default": true,
      "last_commit": {
        "hash": "abc123",
        "message": "Initial commit",
        "date": "2024-01-01T00:00:00Z"
      }
    }
  ],
  "default_branch": "main"
}
```

### POST /projects/{project_id}/repositories/{repo_id}/files/content
Update file content.

**Request Body:**
```json
{
  "path": "src/main.py",
  "branch": "main",
  "content": "new content",
  "commit_message": "Update file",
  "author_name": "User",
  "author_email": "user@example.com"
}
```

**Response 200:**
```json
{
  "commit_hash": "def789",
  "message": "Update file",
  "branch": "main"
}
```

## Data Model

### FileTreeEntry
```typescript
interface FileTreeEntry {
  name: string;
  type: 'file' | 'directory';
  path: string;
  size?: number;
  mode?: string;
  last_commit?: {
    hash: string;
    message: string;
    author: string;
    date: string;
  };
}
```

### Branch
```typescript
interface Branch {
  name: string;
  is_default: boolean;
  last_commit?: {
    hash: string;
    message: string;
    date: string;
  };
}
```

### FileContent
```typescript
interface FileContent {
  path: string;
  branch: string;
  content: string;
  size: number;
  encoding: string;
  language: string | null;
  is_binary: boolean;
  last_commit?: {
    hash: string;
    message: string;
    author: string;
    date: string;
  };
}
```

## Frontend Specification

### URL Structure
```
/projects/:projectId                    → Default view (first repo, default branch)
/projects/:projectId?repo=:repoId       → Specific repo
/projects/:projectId?repo=:repoId&branch=:branch&path=:path  → Specific file
```

### Components

**RepoWorkspace**
- Layout: Sidebar (250px) + Main Content (flex)
- State: manages repo, branch, path, file selections
- Effects: sync URL params, fetch data

**FileTree**
- Props: entries, activePath, onFileClick, onDirectoryToggle
- Recursive rendering for nested directories
- Expand/collapse state per directory

**FileViewer**
- Props: content, language, path, isEditing, onEdit
- View mode: preformatted text with syntax highlighting
- Edit mode: textarea with save/cancel

**RepoSelector**
- Props: repositories, selectedRepoId, onSelect
- Dropdown with repo names

**BranchSelector**
- Props: branches, selectedBranch, onSelect
- Dropdown with branch names, default branch marked

### State Management
Use React state with URL synchronization:
```typescript
const [searchParams, setSearchParams] = useSearchParams();
const repoId = searchParams.get('repo');
const branch = searchParams.get('branch');
const path = searchParams.get('path');
```

## Error Codes

| Error Code | Description | User Message |
|------------|-------------|--------------|
| REPO_NOT_FOUND | Repository doesn't exist | "Repository not found" |
| BRANCH_NOT_FOUND | Branch doesn't exist | "Branch not found, using default" |
| FILE_NOT_FOUND | File path doesn't exist | "File not found" |
| BINARY_FILE | File is binary | "Cannot display binary file" |
| PERMISSION_DENIED | No access to file | "Permission denied" |

## Testing Strategy

### Backend Tests
- Test file listing for various paths
- Test file content retrieval
- Test branch listing
- Test file update/commit
- Test error cases (missing files, invalid branches)

### Frontend Tests
- Test file tree rendering
- Test file viewer display
- Test branch switching
- Test repo switching
- Test edit mode
- Test URL state sync

### Integration Tests
- End-to-end: Click project → browse files → view content → switch branch
