docs: comprehensive documentation overhaul

Add complete documentation structure:
- Frontend architecture documentation
- Database schema documentation
- Deployment guides (Docker, Traefik, Authentik, Environment)
- Development guides (Setup, Testing, Contributing, Quality Gates)
- Deployment architecture documentation
- Updated docs README with complete navigation

All new features and APIs are now documented.
Quality gates: docs only, no code changes
This commit is contained in:
Fusion
2026-05-19 14:18:20 +02:00
parent 6807f449b7
commit 83f94b1f09
31 changed files with 5498 additions and 0 deletions
+72
View File
@@ -0,0 +1,72 @@
# Headquarter Documentation
Welcome to the Headquarter documentation. This is your central hub for understanding, using, and contributing to the platform.
## Quick Links
- [Features](features/) - Learn about available features
- [API Reference](api/) - API endpoint documentation
- [Architecture](architecture/) - System design and architecture
- [Deployment](deployment/) - Setup and deployment guides
- [Development](development/) - Development and contributing guides
## Getting Started
New to Headquarter? Start here:
1. [Quick Start](../README.md#quick-start) - Get up and running
2. [Features](features/) - Discover what you can do
3. [Architecture](architecture/) - Understand the system
## Documentation Structure
### [Features](features/)
User guides for each feature:
- [Projects](features/projects.md) - Project management
- [Repositories](features/repositories.md) - Git repository management
- [Workspace](features/workspace.md) - Repository workspace
- [Git History](features/git-history.md) - History visualization
- [Authentication](features/auth.md) - Login and user management
- [Settings](features/settings.md) - User preferences
- [Tool Types](features/tool-types.md) - Development tool management
- [SSH Keys](features/ssh-keys.md) - SSH key management
### [API Reference](api/)
Complete API documentation:
- [Auth](api/auth.md) - Authentication endpoints
- [Projects](api/projects.md) - Project endpoints
- [Repositories](api/repositories.md) - Repository endpoints
- [Users](api/users.md) - User endpoints
- [Tool Types](api/tool-types.md) - Tool type endpoints
- [SSH Keys](api/ssh-keys.md) - SSH key endpoints
### [Architecture](architecture/)
System architecture documentation:
- [Backend](architecture/backend.md) - Backend architecture
- [Frontend](architecture/frontend.md) - Frontend architecture
- [Database](architecture/database.md) - Database schema
- [Deployment](architecture/deployment.md) - Deployment architecture
### [Deployment](deployment/)
Guides for deploying Headquarter:
- [Docker](deployment/docker.md) - Docker setup
- [Traefik](deployment/traefik.md) - Traefik configuration
- [Authentik](deployment/authentik.md) - Authentik setup
- [Environment](deployment/environment.md) - Environment variables
### [Development](development/)
Guides for developers:
- [Setup](development/setup.md) - Development environment
- [Testing](development/testing.md) - Testing strategy
- [Contributing](development/contributing.md) - How to contribute
- [Quality Gates](development/quality-gates.md) - Code quality
## Contributing to Documentation
When adding new features, please document them following our [templates](templates/):
- [Feature Documentation Template](templates/feature-doc.md)
- [API Documentation Template](templates/api-endpoint.md)
- [Architecture Documentation Template](templates/architecture.md)
See the [Contributing Guide](development/contributing.md) for more details.
+51
View File
@@ -0,0 +1,51 @@
# API Documentation
## Overview
The Headquarter API is a RESTful API built with FastAPI. All endpoints (except auth) require authentication via session cookie.
## Base URL
- Development: `http://localhost:8000`
- Production: `https://api.yourdomain.com`
## Authentication
Most endpoints require authentication. Include the session cookie in requests:
```bash
curl http://api.example.com/endpoint \
-H "Cookie: session=your_session_cookie"
```
## Response Format
All responses are JSON. Error responses follow this format:
```json
{
"detail": "Error message"
}
```
## API Sections
- [Auth](auth.md) - Authentication endpoints
- [Projects](projects.md) - Project management
- [Repositories](repositories.md) - Git repositories and file operations
- [Users](users.md) - User management and settings
- [Tool Types](tool-types.md) - Tool type management
- [SSH Keys](ssh-keys.md) - SSH key management
## Testing
Interactive API documentation is available at `/docs` when running the backend:
```
http://localhost:8000/docs
```
This provides:
- Interactive endpoint testing
- Request/response schemas
- Authentication via "Authorize" button
+105
View File
@@ -0,0 +1,105 @@
# Auth API
Authentication endpoints for OAuth2 login via Authentik.
## Authentication
These endpoints handle the OAuth2 flow. No prior authentication is required for `/auth/login` and `/auth/callback`.
---
## GET /auth/login
**Description:** Initiate OAuth2 login flow. Redirects to Authentik.
### Request
#### Query Parameters
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `next` | `string` | No | URL to redirect to after login |
### Response
#### Success (307 Temporary Redirect)
Redirects to Authentik OAuth2 authorization URL.
---
## GET /auth/callback
**Description:** Handle OAuth2 callback from Authentik.
### Request
#### Query Parameters
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `code` | `string` | Yes | Authorization code from Authentik |
| `state` | `string` | Yes | State parameter for CSRF protection |
### Response
#### Success (307 Temporary Redirect)
Sets session cookie and redirects to frontend.
#### Error (400 Bad Request)
```json
{
"detail": "Invalid state parameter"
}
```
---
## GET /auth/me
**Description:** Get current authenticated user.
**Auth:** Required (session cookie)
### Response
#### Success (200 OK)
```json
{
"id": "uuid",
"email": "user@example.com",
"name": "User Name",
"avatar_url": "https://..."
}
```
#### Error (401 Unauthorized)
```json
{
"detail": "Not authenticated"
}
```
---
## POST /auth/logout
**Description:** Log out current user.
**Auth:** Required (session cookie)
### Response
#### Success (200 OK)
Clears session cookie.
```json
{
"message": "Logged out"
}
```
+163
View File
@@ -0,0 +1,163 @@
# Projects API
Project management endpoints.
## Authentication
All endpoints require authentication (session cookie).
---
## GET /projects
**Description:** List all projects for the current user.
### Response
#### Success (200 OK)
```json
[
{
"id": "uuid",
"name": "My Project",
"description": "Project description",
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-01T00:00:00Z"
}
]
```
---
## POST /projects
**Description:** Create a new project.
### Request
#### Request Body
```json
{
"name": "My Project",
"description": "Optional description"
}
```
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | `string` | Yes | Project name (max 255 chars) |
| `description` | `string` | No | Project description |
### Response
#### Success (201 Created)
```json
{
"id": "uuid",
"name": "My Project",
"description": "Optional description",
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-01T00:00:00Z"
}
```
#### Error (422 Validation Error)
```json
{
"detail": [
{
"loc": ["body", "name"],
"msg": "field required",
"type": "value_error.missing"
}
]
}
```
---
## GET /projects/{id}
**Description:** Get project details.
### Response
#### Success (200 OK)
```json
{
"id": "uuid",
"name": "My Project",
"description": "Project description",
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-01T00:00:00Z"
}
```
#### Error (404 Not Found)
```json
{
"detail": "Project not found"
}
```
---
## PUT /projects/{id}
**Description:** Update a project.
### Request
#### Request Body
```json
{
"name": "Updated Name",
"description": "Updated description"
}
```
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | `string` | No | New project name |
| `description` | `string` | No | New description |
### Response
#### Success (200 OK)
```json
{
"id": "uuid",
"name": "Updated Name",
"description": "Updated description",
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-02T00:00:00Z"
}
```
---
## DELETE /projects/{id}
**Description:** Delete a project and all associated repositories.
### Response
#### Success (204 No Content)
#### Error (404 Not Found)
```json
{
"detail": "Project not found"
}
```
**Warning:** This also deletes all repositories and their data. Cannot be undone.
+349
View File
@@ -0,0 +1,349 @@
# Repositories API
Git repository and file management endpoints.
## Authentication
All endpoints require authentication (session cookie).
---
## GET /projects/{project_id}/repositories
**Description:** List repositories in a project.
### Response
#### Success (200 OK)
```json
[
{
"id": "uuid",
"name": "my-repo",
"clone_url": "https://github.com/user/repo.git",
"is_mirror": true,
"project_id": "uuid",
"created_at": "2024-01-01T00:00:00Z"
}
]
```
---
## POST /projects/{project_id}/repositories
**Description:** Create a new repository.
### Request
#### Request Body
```json
{
"name": "my-repo",
"remote_url": "https://github.com/user/repo.git",
"is_mirror": false
}
```
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | `string` | Yes | Repository name |
| `remote_url` | `string` | No | Remote URL to clone from |
| `is_mirror` | `boolean` | No | Create mirror clone (default: false) |
### Response
#### Success (201 Created)
```json
{
"id": "uuid",
"name": "my-repo",
"clone_url": "https://github.com/user/repo.git",
"is_mirror": false,
"project_id": "uuid",
"created_at": "2024-01-01T00:00:00Z"
}
```
#### URL Parsing Suggestion (422 Unprocessable Entity)
If the URL appears to be a browser URL:
```json
{
"detail": "URL appears to be a browser URL, not a git clone URL",
"suggested_url": "https://github.com/user/repo.git",
"original_url": "https://github.com/user/repo/tree/main",
"error_code": "URL_NEEDS_PARSING"
}
```
---
## DELETE /projects/{project_id}/repositories/{id}
**Description:** Delete a repository.
### Response
#### Success (204 No Content)
**Warning:** Permanently deletes the repository from disk. Cannot be undone.
---
## POST /projects/{project_id}/repositories/parse-url
**Description:** Parse and validate a git URL.
### Request
#### Request Body
```json
{
"url": "https://github.com/user/repo/tree/main"
}
```
### Response
#### Success (200 OK)
```json
{
"original_url": "https://github.com/user/repo/tree/main",
"base_url": "https://github.com/user/repo.git",
"is_valid_clone_url": false,
"needs_parsing": true,
"host": "github.com",
"message": "This URL contains a branch path. The repository URL is: https://github.com/user/repo.git"
}
```
---
## GET /projects/{project_id}/repositories/{id}/files
**Description:** List files in a directory.
### Request
#### Query Parameters
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `branch` | `string` | No | Branch name (default: repository default) |
| `path` | `string` | No | Directory path (default: root) |
### Response
#### Success (200 OK)
```json
{
"path": "src",
"branch": "main",
"entries": [
{
"name": "components",
"type": "directory",
"path": "src/components"
},
{
"name": "main.py",
"type": "file",
"path": "src/main.py",
"size": 1234,
"last_commit": {
"hash": "abc123",
"message": "Initial commit",
"author": "John Doe",
"date": "2024-01-01T00:00:00Z"
}
}
]
}
```
---
## GET /projects/{project_id}/repositories/{id}/files/content
**Description:** Get file content.
### Request
#### Query Parameters
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `branch` | `string` | Yes | Branch name |
| `path` | `string` | Yes | File path |
### Response
#### Success (200 OK)
```json
{
"path": "src/main.py",
"branch": "main",
"content": "function hello() {\n return 'world';\n}",
"size": 42,
"encoding": "utf-8",
"language": "python",
"is_binary": false
}
```
#### Binary File (200 OK)
```json
{
"path": "image.png",
"branch": "main",
"content": null,
"size": 12345,
"encoding": null,
"language": null,
"is_binary": true
}
```
---
## POST /projects/{project_id}/repositories/{id}/files/content
**Description:** Update file content and commit.
### Request
#### Request Body
```json
{
"path": "src/main.py",
"branch": "main",
"content": "new content",
"commit_message": "Update file",
"author_name": "User",
"author_email": "user@example.com"
}
```
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `path` | `string` | Yes | File path |
| `branch` | `string` | Yes | Branch name |
| `content` | `string` | Yes | New file content |
| `commit_message` | `string` | Yes | Commit message |
| `author_name` | `string` | Yes | Author name |
| `author_email` | `string` | Yes | Author email |
### Response
#### Success (200 OK)
```json
{
"commit_hash": "def789",
"message": "Update file",
"branch": "main"
}
```
---
## GET /projects/{project_id}/repositories/{id}/branches
**Description:** List branches.
### Response
#### Success (200 OK)
```json
{
"branches": [
{
"name": "main",
"is_default": true,
"last_commit": {
"hash": "abc123",
"message": "Initial commit",
"date": "2024-01-01T00:00:00Z"
}
}
],
"default_branch": "main"
}
```
---
## GET /projects/{project_id}/repositories/{id}/history
**Description:** Get commit history.
### Request
#### Query Parameters
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `branch` | `string` | No | Branch name (default: all branches) |
| `max_count` | `integer` | No | Maximum commits to return (default: 1000) |
### Response
#### Success (200 OK)
```json
{
"commits": [
{
"hash": "abc123",
"author_name": "John Doe",
"author_email": "john@example.com",
"author_date": "2024-01-01T00:00:00Z",
"message": "Initial commit",
"refs": ["HEAD", "main"]
}
],
"branch": "main",
"total_count": 50
}
```
---
## GET /projects/{project_id}/repositories/{id}/commits/{hash}
**Description:** Get commit details.
### Response
#### Success (200 OK)
```json
{
"hash": "abc123",
"author_name": "John Doe",
"author_email": "john@example.com",
"author_date": "2024-01-01T00:00:00Z",
"committer_name": "John Doe",
"committer_email": "john@example.com",
"commit_date": "2024-01-01T00:00:00Z",
"message": "Initial commit",
"stats": {
"files_changed": 2,
"insertions": 10,
"deletions": 0
},
"diff": "diff --git a/file.txt b/file.txt\n..."
}
```
+77
View File
@@ -0,0 +1,77 @@
# SSH Keys API
SSH key management endpoints.
## Authentication
All endpoints require authentication (session cookie).
---
## GET /ssh-keys
**Description:** List all SSH keys for the current user.
### Response
#### Success (200 OK)
```json
[
{
"id": "uuid",
"name": "GitHub Work",
"public_key": "ssh-ed25519 AAAAC3NzaC... user@example.com",
"created_at": "2024-01-01T00:00:00Z"
}
]
```
**Note:** Private keys are never returned.
---
## POST /ssh-keys
**Description:** Generate a new SSH key pair.
### Request
#### Request Body
```json
{
"name": "GitHub Personal"
}
```
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | `string` | Yes | Key name/label |
### Response
#### Success (201 Created)
```json
{
"id": "uuid",
"name": "GitHub Personal",
"public_key": "ssh-ed25519 AAAAC3NzaC... user@example.com",
"created_at": "2024-01-01T00:00:00Z"
}
```
**Note:** The private key is generated and stored securely. It is not returned in the response.
---
## DELETE /ssh-keys/{id}
**Description:** Delete an SSH key.
### Response
#### Success (204 No Content)
**Note:** This permanently deletes both public and private keys.
+154
View File
@@ -0,0 +1,154 @@
# Tool Types API
Tool type management endpoints.
## Authentication
All endpoints require authentication (session cookie).
---
## GET /tool-types
**Description:** List all tool types.
### Response
#### Success (200 OK)
```json
[
{
"id": "uuid",
"name": "code-server",
"display_name": "VS Code Server",
"description": "VS Code in the browser",
"is_builtin": true,
"created_at": "2024-01-01T00:00:00Z"
}
]
```
---
## POST /tool-types
**Description:** Create a new tool type.
### Request
#### Request Body
```json
{
"name": "my-tool",
"display_name": "My Custom Tool",
"description": "A custom development tool",
"compose_template": "version: \"3.8\"\nservices:\n tool:\n image: my-image:latest\n container_name: {{TOOL_NAME}}\n volumes:\n - {{REPO_PATH}}:/workspace",
"required_variables": ["TOOL_NAME", "REPO_PATH"]
}
```
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | `string` | Yes | Unique identifier |
| `display_name` | `string` | Yes | Human-readable name |
| `description` | `string` | No | Description |
| `compose_template` | `string` | Yes | Docker Compose YAML |
| `required_variables` | `array` | Yes | Required template variables |
### Response
#### Success (201 Created)
```json
{
"id": "uuid",
"name": "my-tool",
"display_name": "My Custom Tool",
"description": "A custom development tool",
"compose_template": "...",
"required_variables": ["TOOL_NAME", "REPO_PATH"],
"is_builtin": false,
"created_at": "2024-01-01T00:00:00Z"
}
```
#### Error (400 Bad Request)
```json
{
"detail": "Invalid YAML in compose template"
}
```
---
## GET /tool-types/{id}
**Description:** Get tool type details.
### Response
#### Success (200 OK)
```json
{
"id": "uuid",
"name": "code-server",
"display_name": "VS Code Server",
"description": "VS Code in the browser",
"compose_template": "...",
"required_variables": ["TOOL_NAME", "REPO_PATH"],
"is_builtin": true,
"created_at": "2024-01-01T00:00:00Z"
}
```
---
## PUT /tool-types/{id}
**Description:** Update a tool type.
**Note:** Built-in tool types cannot be modified.
### Request
#### Request Body
Same as POST /tool-types.
### Response
#### Success (200 OK)
Returns updated tool type.
#### Error (403 Forbidden)
```json
{
"detail": "Cannot modify built-in tool types"
}
```
---
## DELETE /tool-types/{id}
**Description:** Delete a tool type.
**Note:** Built-in tool types cannot be deleted.
### Response
#### Success (204 No Content)
#### Error (403 Forbidden)
```json
{
"detail": "Cannot delete built-in tool types"
}
```
+168
View File
@@ -0,0 +1,168 @@
# Users API
User profile and settings management.
## Authentication
All endpoints require authentication (session cookie).
---
## GET /users/me
**Description:** Get current user profile.
### Response
#### Success (200 OK)
```json
{
"id": "uuid",
"email": "user@example.com",
"name": "User Name",
"avatar_url": "https://...",
"authentik_id": "authentik-uuid",
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-01T00:00:00Z"
}
```
---
## PUT /users/me
**Description:** Update user profile.
### Request
#### Request Body
```json
{
"name": "New Name",
"email": "newemail@example.com"
}
```
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | `string` | No | New display name |
| `email` | `string` | No | New email address |
### Response
#### Success (200 OK)
```json
{
"id": "uuid",
"email": "newemail@example.com",
"name": "New Name",
"avatar_url": "https://...",
"updated_at": "2024-01-02T00:00:00Z"
}
```
---
## POST /users/me/avatar
**Description:** Upload avatar image.
### Request
#### Request Body
Multipart form data with `file` field.
**Requirements:**
- Format: PNG or JPEG
- Max size: 2MB
### Response
#### Success (200 OK)
```json
{
"avatar_url": "/uploads/avatars/uuid.png"
}
```
#### Error (400 Bad Request)
```json
{
"detail": "Invalid file format. Only PNG and JPEG are allowed."
}
```
---
## GET /users/me/config
**Description:** Get user settings.
### Response
#### Success (200 OK)
```json
{
"id": "uuid",
"user_id": "uuid",
"config": {
"theme": "dark",
"git_identity": {
"name": "User Name",
"email": "user@example.com"
},
"default_editor": "code-server"
}
}
```
---
## PATCH /users/me/config
**Description:** Update user settings.
### Request
#### Request Body
```json
{
"theme": "light",
"git_identity": {
"name": "New Name",
"email": "new@example.com"
}
}
```
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `theme` | `string` | No | "system", "light", or "dark" |
| `git_identity` | `object` | No | `{name, email}` |
| `default_editor` | `string` | No | Preferred editor |
### Response
#### Success (200 OK)
```json
{
"id": "uuid",
"user_id": "uuid",
"config": {
"theme": "light",
"git_identity": {
"name": "New Name",
"email": "new@example.com"
}
}
}
```
+212
View File
@@ -0,0 +1,212 @@
# Backend Architecture
## Overview
The Headquarter backend is built with **FastAPI** and follows a layered architecture pattern.
## Architecture Diagram
```
┌─────────────────────────────────────────────────────────────┐
│ FastAPI App │
├─────────────────────────────────────────────────────────────┤
│ Middleware: CORS → Request Logging → Exception Logging │
├─────────────────────────────────────────────────────────────┤
│ API Layer (src/api/) │
│ ┌─────────┐ ┌──────────┐ ┌────────┐ ┌──────────┐ │
│ │ Auth │ │ Projects │ │ Users │ │ Git │ │
│ │ Routes │ │ Routes │ │ Routes │ │ Repos │ │
│ └────┬────┘ └────┬─────┘ └───┬────┘ └────┬─────┘ │
├───────┼───────────┼───────────┼───────────┼─────────────────┤
│ │ │ │ │ │
│ Auth │ Project │ User │ Git │ │
│ Layer │ Service │ Service │ Service │ │
│ │ │ │ │ │
├───────┴───────────┴───────────┴───────────┴─────────────────┤
│ Data Layer │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Models │ │ Database │ │ Config │ │
│ │(SQLAlch) │ │(AsyncPG) │ │(Pydantic)│ │
│ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────────┘
```
## Directory Structure
```
src/
├── api/ # API Routes
│ ├── auth.py # Authentication endpoints
│ ├── projects.py # Project endpoints
│ ├── git_repositories.py # Repository endpoints
│ ├── users.py # User endpoints
│ ├── tool_types.py # Tool type endpoints
│ ├── ssh_keys.py # SSH key endpoints
│ └── dashboard.py # Dashboard endpoints
├── auth/ # Authentication
│ ├── session.py # Session management
│ ├── oidc.py # OAuth2 client
│ ├── dependencies.py # Auth dependencies
│ └── cookies.py # Cookie utilities
├── models/ # Database Models
│ ├── user.py # User model
│ ├── project.py # Project model
│ ├── git_repository.py # Repository model
│ ├── tool_type.py # Tool type model
│ ├── ssh_key.py # SSH key model
│ └── user_config.py # User config model
├── utils/ # Utilities
│ ├── git_url_parser.py # URL parsing
│ ├── git_files.py # Git file operations
│ └── git_history.py # Git history operations
├── config.py # Configuration
├── database.py # Database setup
└── main.py # Application entry point
```
## Layers
### 1. API Layer (`src/api/`)
**Responsibilities:**
- Define HTTP endpoints
- Parse request parameters
- Return HTTP responses
- Use dependencies for auth and DB
**Pattern:**
```python
@router.get("/projects")
async def list_projects(
session: AsyncSession = Depends(get_db_session),
user_id: str = Depends(get_current_user_id),
):
# Call service layer
projects = await project_service.list(session, user_id)
return projects
```
### 2. Auth Layer (`src/auth/`)
**Responsibilities:**
- Session management (create, verify, expire)
- OAuth2 flow (login, callback)
- User authentication dependencies
**Key Components:**
- `session.py`: HMAC-SHA256 signed cookies
- `oidc.py`: OAuth2 token exchange
- `dependencies.py`: FastAPI dependencies for auth
### 3. Data Layer (`src/models/`, `src/database.py`)
**Responsibilities:**
- Database schema definition
- Async database sessions
- Connection management
**Technology:**
- SQLAlchemy 2.0 with async support
- asyncpg driver for PostgreSQL
- Alembic for migrations
### 4. Utility Layer (`src/utils/`)
**Responsibilities:**
- Git operations (file browsing, history)
- URL parsing
- Helper functions
## Data Flow
### Request Lifecycle
```
1. Request arrives at FastAPI
2. Middleware processes (CORS, logging)
3. Auth dependency verifies session
4. Route handler processes request
5. Database session executes queries
6. Response returned to client
```
### Authentication Flow
```
1. User clicks login
2. Backend redirects to Authentik
3. User authenticates
4. Authentik redirects with code
5. Backend exchanges code for token
6. Backend fetches user info
7. Backend creates session cookie
8. User is authenticated
```
## Dependencies
### Database Session
```python
async def get_db_session() -> AsyncGenerator[AsyncSession, None]:
async with SessionLocal() as session:
yield session
```
### Current User
```python
async def get_current_user_id(
request: Request,
settings: Settings = Depends(get_settings),
) -> str:
# Verify session cookie
# Return user_id
```
## Configuration
Configuration is managed via Pydantic Settings:
```python
class Settings(BaseSettings):
app_env: str = "development"
database_url: str = "..."
authentik_domain: str = "..."
# ...
```
Environment variables are automatically loaded from `.env` files.
## Error Handling
Errors are handled at multiple levels:
1. **Validation**: Pydantic validates request bodies
2. **HTTP Exceptions**: FastAPI HTTPException for client errors
3. **Middleware**: ExceptionLoggingMiddleware logs server errors
4. **Database**: SQLAlchemy errors converted to HTTP responses
## Testing
- **Unit tests**: SQLite in-memory database
- **Integration tests**: PostgreSQL with transaction rollback
- **Fixtures**: Shared in `conftest.py`
## Technology Stack
| Component | Technology | Version |
|-----------|-----------|---------|
| Web Framework | FastAPI | ^0.104 |
| ORM | SQLAlchemy | ^2.0 |
| Database Driver | asyncpg | ^0.29 |
| Validation | Pydantic | ^2.0 |
| Migrations | Alembic | ^1.12 |
| HTTP Client | httpx | ^0.25 |
| Testing | pytest | ^7.4 |
## Related Documentation
- [Database Schema](database.md)
- [Frontend Architecture](../frontend.md)
- [API Documentation](../api/)
+231
View File
@@ -0,0 +1,231 @@
# Database Schema
## Overview
Headquarter uses PostgreSQL with SQLAlchemy ORM and Alembic for migrations. All tables use UUID primary keys and include `created_at`/`updated_at` timestamps.
## Entity Relationship Diagram
```
┌──────────────┐ ┌─────────────────┐ ┌──────────────┐
│ users │ │ git_repository │ │ project │
├──────────────┤ ├─────────────────┤ ├──────────────┤
│ id (PK) │ │ id (PK) │ │ id (PK) │
│ email │ │ project_id (FK) │──┐ │ name │
│ name │ │ name │ │ │ description │
│ authentik_id │ │ remote_url │ │ │ created_by_id│──┐
│ avatar_url │ │ local_path │ │ │ │ │
│ created_at │ │ is_mirror │ │ │ │ │
│ updated_at │ │ created_by_id │──┤ │ │ │
└──────────────┘ │ created_at │ │ └──────────────┘ │
│ │ updated_at │ │ ▲ │
│ └─────────────────┘ │ │ │
│ │ │ │ │
│ ┌───────┘ │ │ │
│ │ │ │ │
┌───────▼──────┐ ┌▼────────────────┐ │ │ │
│ ssh_keys │ │ user_config │ │ │ │
├──────────────┤ ├─────────────────┤ │ │ │
│ id (PK) │ │ user_id (FK) │───┘ │ │
│ user_id (FK) │ │ theme │ │ │
│ name │ │ git_name │ │ │
│ public_key │ │ git_email │ │ │
│ private_key │ │ default_editor │ │ │
│ created_at │ │ created_at │ │ │
│ updated_at │ │ updated_at │ │ │
└──────────────┘ └─────────────────┘ │ │
│ │
┌───────────────────────┘ │
│ │
▼ │
┌─────────────────┐ │
│ tool_types │ │
├─────────────────┤ │
│ id (PK) │ │
│ name │ │
│ display_name │ │
│ description │ │
│ compose_template│ │
│ required_vars │ │
│ is_builtin │ │
│ created_by_id │─────────────────────────┘
│ created_at │
│ updated_at │
└─────────────────┘
```
## Table Definitions
### users
Stores user accounts synchronized from Authentik.
| Column | Type | Constraints | Description |
|--------|------|-------------|-------------|
| id | UUID | PK | Unique identifier |
| email | VARCHAR(255) | NOT NULL, UNIQUE | User email |
| name | VARCHAR(255) | | Display name |
| authentik_id | VARCHAR(255) | UNIQUE | Authentik user ID |
| avatar_url | VARCHAR(500) | | Profile avatar URL |
| created_at | TIMESTAMP | DEFAULT now() | Creation timestamp |
| updated_at | TIMESTAMP | DEFAULT now() | Last update timestamp |
**Relationships**:
- One-to-Many: `users``git_repository` (created_by_id)
- One-to-Many: `users``project` (created_by_id)
- One-to-Many: `users``ssh_keys` (user_id)
- One-to-One: `users``user_config` (user_id)
- One-to-Many: `users``tool_types` (created_by_id)
### project
Organizes repositories into logical groups.
| Column | Type | Constraints | Description |
|--------|------|-------------|-------------|
| id | UUID | PK | Unique identifier |
| name | VARCHAR(255) | NOT NULL | Project name |
| description | TEXT | | Project description |
| created_by_id | UUID | FK → users.id | Creator |
| created_at | TIMESTAMP | DEFAULT now() | Creation timestamp |
| updated_at | TIMESTAMP | DEFAULT now() | Last update timestamp |
**Relationships**:
- One-to-Many: `project``git_repository` (project_id)
### git_repository
Git repositories (bare/mirror clones).
| Column | Type | Constraints | Description |
|--------|------|-------------|-------------|
| id | UUID | PK | Unique identifier |
| project_id | UUID | FK → project.id, NOT NULL | Parent project |
| name | VARCHAR(255) | NOT NULL | Repository name |
| remote_url | VARCHAR(500) | NOT NULL | Remote git URL |
| local_path | VARCHAR(500) | | Local filesystem path |
| is_mirror | BOOLEAN | DEFAULT false | Is mirror clone |
| created_by_id | UUID | FK → users.id | Creator |
| created_at | TIMESTAMP | DEFAULT now() | Creation timestamp |
| updated_at | TIMESTAMP | DEFAULT now() | Last update timestamp |
**Indexes**:
- `idx_repo_project`: (project_id)
- `idx_repo_name`: (project_id, name) - UNIQUE
### ssh_keys
User SSH keys for git authentication.
| Column | Type | Constraints | Description |
|--------|------|-------------|-------------|
| id | UUID | PK | Unique identifier |
| user_id | UUID | FK → users.id, NOT NULL | Owner |
| name | VARCHAR(255) | NOT NULL | Key name |
| public_key | TEXT | NOT NULL | Public key |
| private_key | TEXT | NOT NULL, ENCRYPTED | Encrypted private key |
| created_at | TIMESTAMP | DEFAULT now() | Creation timestamp |
| updated_at | TIMESTAMP | DEFAULT now() | Last update timestamp |
**Indexes**:
- `idx_ssh_user`: (user_id)
### user_config
User preferences and settings.
| Column | Type | Constraints | Description |
|--------|------|-------------|-------------|
| id | UUID | PK | Unique identifier |
| user_id | UUID | FK → users.id, NOT NULL, UNIQUE | Owner |
| theme | VARCHAR(50) | DEFAULT 'system' | UI theme (system/light/dark) |
| git_name | VARCHAR(255) | | Git user name |
| git_email | VARCHAR(255) | | Git user email |
| default_editor | VARCHAR(50) | DEFAULT 'vscode' | Preferred editor |
| created_at | TIMESTAMP | DEFAULT now() | Creation timestamp |
| updated_at | TIMESTAMP | DEFAULT now() | Last update timestamp |
### tool_types
Types of development tools that can be spawned.
| Column | Type | Constraints | Description |
|--------|------|-------------|-------------|
| id | UUID | PK | Unique identifier |
| name | VARCHAR(255) | NOT NULL, UNIQUE | Machine name |
| display_name | VARCHAR(255) | NOT NULL | Human-readable name |
| description | TEXT | | Description |
| compose_template | TEXT | NOT NULL | Docker Compose template |
| required_variables | JSONB | NOT NULL | Template variables |
| is_builtin | BOOLEAN | DEFAULT false | Built-in type |
| created_by_id | UUID | FK → users.id | Creator (null for built-in) |
| created_at | TIMESTAMP | DEFAULT now() | Creation timestamp |
| updated_at | TIMESTAMP | DEFAULT now() | Last update timestamp |
**Indexes**:
- `idx_tool_builtin`: (is_builtin)
## Migration History
| Version | Date | Description |
|---------|------|-------------|
| 0001_initial_schema | 2024-01-XX | Initial tables: users, projects, git_repositories |
| 0002_refresh_tokens | 2024-01-XX | Added refresh_tokens table |
| 0003_user_configs | 2024-05-18 | Added user_config table |
| 0004_tool_types | 2024-05-18 | Added tool_types table |
## Data Types
### PostgreSQL Types
- **UUID**: `uuid` - All primary keys
- **Timestamps**: `TIMESTAMP WITH TIME ZONE`
- **JSONB**: `JSONB` - For flexible config (user_config, tool_types)
- **Strings**: `VARCHAR(n)` - With appropriate length limits
- **Text**: `TEXT` - For unbounded content
- **Boolean**: `BOOLEAN` - True/false flags
### SQLAlchemy Configuration
```python
# Base model features
class Base:
id: UUID = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
created_at: datetime = Column(DateTime(timezone=True), server_default=func.now())
updated_at: datetime = Column(DateTime(timezone=True), onupdate=func.now())
```
## Backup Strategy
### Automated Backups
- **Frequency**: Daily at 2 AM
- **Retention**: 7 daily, 4 weekly, 12 monthly
- **Method**: `pg_dump` to S3/object storage
- **Encryption**: AES-256 encrypted backups
### Manual Backup
```bash
# Full backup
pg_dump -Fc -f headquarter_backup.dump postgresql://user:pass@host/db
# Restore
pg_restore -d postgresql://user:pass@host/db headquarter_backup.dump
```
## Performance
### Query Optimization
- All foreign keys indexed
- Frequently queried columns indexed
- Composite indexes for multi-column queries
### Connection Pooling
- SQLAlchemy async pool: 5-20 connections
- PgBouncer for production: transaction mode
## Future Schema Changes
Planned additions:
- [ ] **teams** table - Group users into teams
- [ ] **team_memberships** table - Link users to teams
- [ ] **tool_instances** table - Running tool containers
- [ ] **audit_logs** table - Track important actions
- [ ] **notifications** table - User notifications
+357
View File
@@ -0,0 +1,357 @@
# Deployment Architecture
## Overview
Headquarter is designed for containerized deployment using Docker, with support for both development and production environments.
## System Architecture
```
┌─────────────────────────────────────────────────────────────┐
│ Internet │
└──────────────────────┬──────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ Traefik (Reverse Proxy) │
│ SSL/TLS termination, routing │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ app.domain │ │ api.domain │ │ auth.domain │ │
│ │ (Frontend) │ │ (Backend) │ │ (Authentik) │ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
└─────────┼─────────────────┼─────────────────┼──────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────────────────────────────────────────────────┐
│ Docker Host / Server │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Frontend │ │ API │ │ Authentik │ │
│ │ (nginx) │ │ (FastAPI) │ │ (OAuth2) │ │
│ │ Port 80 │ │ Port 8000 │ │ Port 9443 │ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │ │
│ └─────────────────┼─────────────────┘ │
│ │ │
│ ┌────────┴────────┐ │
│ │ │ │
│ ┌───────▼───────┐ ┌──────▼───────┐ │
│ │ PostgreSQL │ │ Redis │ │
│ │ Port 5432 │ │ Port 6379 │ │
│ └───────────────┘ └──────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Volumes │ │
│ │ postgres_data │ repo_data │ avatar_uploads │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
## Components
### Frontend (Web)
- **Technology**: React + Vite + nginx
- **Port**: 80 (internal)
- **Role**: User interface
- **Scaling**: Static files, easily scaled horizontally
### Backend (API)
- **Technology**: FastAPI + Python 3.11
- **Port**: 8000 (internal)
- **Role**: Business logic, API endpoints
- **Scaling**: Stateless, can scale horizontally
### Database (PostgreSQL)
- **Technology**: PostgreSQL 15
- **Port**: 5432 (internal)
- **Role**: Persistent data storage
- **Scaling**: Vertical or read replicas
### Cache (Redis)
- **Technology**: Redis 7
- **Port**: 6379 (internal)
- **Role**: Session storage, caching
- **Scaling**: Redis Cluster for high availability
### Identity Provider (Authentik)
- **Technology**: Authentik (self-hosted)
- **Port**: 9443 (external), 9000 (internal)
- **Role**: OAuth2/OIDC authentication
- **Note**: Can be external service
## Network Architecture
```
┌─────────────────────────────────────────────────────────────┐
│ Networks │
├─────────────────────────────────────────────────────────────┤
│ │
│ External Network (traefik) │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Traefik │ │ Frontend │ │ API │ │
│ │ (proxy) │ │ (web) │ │ (api) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
│ Internal Network (backend) │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ API │ │ PostgreSQL │ │ Redis │ │
│ │ (api) │ │ (postgres) │ │ (redis) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
```
**Network Security**:
- External network: Exposes services to Traefik
- Internal network: Database and cache only accessible by API
- No direct database access from external network
## Data Flow
### Authentication Flow
```
User → Frontend → API → Authentik
OAuth2
User ← Frontend ← API ← Authentik
Session Cookie
```
### API Request Flow
```
User → Frontend → Traefik → API → Database
Redis (cache)
```
### Git Operations Flow
```
User → Frontend → API → Git Repository (filesystem)
Git History/Files
```
## Deployment Patterns
### Single Server
All services on one host:
- Simple to manage
- Suitable for small teams
- Single point of failure
### Multi-Server (HA)
Separate services across hosts:
- Database server
- Application servers (API + Frontend)
- Load balancer (Traefik)
- Higher availability
### Kubernetes (Future)
Container orchestration:
- Auto-scaling
- Self-healing
- Rolling updates
- Resource management
## Scaling Strategy
### Horizontal Scaling
**Stateless Services** (easy to scale):
- Frontend: Multiple nginx instances
- API: Multiple FastAPI instances
**Stateful Services** (require care):
- Database: Read replicas, connection pooling
- Redis: Cluster mode
### Vertical Scaling
Increase resources for:
- Database server (CPU, RAM, I/O)
- API server (CPU for git operations)
## Backup Strategy
### Automated Backups
```
Daily at 2 AM
├── PostgreSQL dump
├── Repository filesystem
├── User uploads (avatars)
└── Configuration files
```
### Backup Retention
- Daily: 7 days
- Weekly: 4 weeks
- Monthly: 12 months
- Yearly: 3 years
### Disaster Recovery
1. Restore database from backup
2. Restore repositories from backup
3. Verify application functionality
4. Update DNS if needed
## Security Considerations
### Network Security
- Internal services not exposed externally
- Database only accessible from API
- Redis only accessible from API
- SSL/TLS for all external traffic
### Data Security
- Encrypted database connections
- Encrypted backups
- SSH keys encrypted at rest
- Session cookies httpOnly + Secure
### Access Control
- OAuth2 authentication
- Role-based access (future)
- API rate limiting
- Audit logging (future)
## Monitoring
### Health Checks
```
API: GET /health
Database: pg_isready
Redis: redis-cli ping
```
### Metrics
- Request rate and latency
- Error rate
- Database connections
- Disk usage
- Memory usage
### Logging
- Application logs (structured JSON)
- Access logs (Traefik)
- Error logs (centralized)
- Audit logs (future)
## Performance Optimization
### Database
- Connection pooling (PgBouncer)
- Query optimization
- Proper indexing
- Regular VACUUM
### API
- Async operations
- Caching (Redis)
- Git operation optimization
- File streaming
### Frontend
- Code splitting
- Lazy loading
- Asset optimization
- CDN (future)
## Troubleshooting
### Common Issues
**High Memory Usage**:
```bash
# Check container stats
docker stats
# Restart API if needed
docker compose restart api
```
**Database Connection Issues**:
```bash
# Check PostgreSQL logs
docker compose logs postgres
# Verify connection
docker compose exec api pg_isready -h postgres
```
**Git Operations Slow**:
```bash
# Check disk I/O
iostat -x 1
# Check repository size
du -sh /data/repos/*
```
## Migration Strategy
### Version Updates
1. Backup data
2. Update images
3. Run migrations
4. Verify functionality
5. Rollback if needed
### Database Migrations
```bash
# Check current version
alembic current
# Upgrade
alembic upgrade head
# Downgrade if needed
alembic downgrade -1
```
## Future Architecture
### Planned Improvements
- [ ] Kubernetes deployment
- [ ] Microservices split
- [ ] Event-driven architecture
- [ ] Real-time WebSocket updates
- [ ] Multi-region deployment
- [ ] CDN integration
- [ ] Advanced monitoring (Prometheus/Grafana)
### Scalability Roadmap
1. **Phase 1**: Single server (current)
2. **Phase 2**: Separate database server
3. **Phase 3**: Load balanced API servers
4. **Phase 4**: Kubernetes cluster
5. **Phase 5**: Multi-region
+297
View File
@@ -0,0 +1,297 @@
# Frontend Architecture
## Overview
The Headquarter frontend is a React-based single-page application (SPA) built with modern tooling and designed for modularity and maintainability.
## Tech Stack
| Layer | Technology | Version |
|-------|-----------|---------|
| Framework | React | ^18.2.0 |
| Router | React Router | ^6.20.0 |
| Bundler | Vite | ^5.0.0 |
| Language | TypeScript | ^5.3.0 |
| Styling | CSS3 with CSS Variables | - |
| Testing | Vitest + React Testing Library | ^4.1.6 |
## Directory Structure
```
apps/web/src/
├── api/ # API clients
│ ├── auth.ts # Authentication API
│ ├── projects.ts # Project API
│ ├── git_repositories.ts # Repository API
│ ├── ssh_keys.ts # SSH key API
│ ├── tool_types.ts # Tool type API
│ ├── users.ts # User API
│ └── settings.ts # Settings API
├── components/ # Reusable components
│ ├── app-shell.tsx # Main app layout
│ ├── protected-route.tsx # Auth guard
│ └── [more...]
├── context/ # React contexts
│ └── auth.tsx # Auth state management
├── hooks/ # Custom hooks
│ ├── use-auth.ts # Auth hook
│ └── use-theme.ts # Theme hook
├── pages/ # Page components (routes)
│ ├── dashboard.tsx # Dashboard
│ ├── projects.tsx # Project list
│ ├── repo-workspace.tsx # Repository workspace
│ ├── git-history.tsx # Git history
│ ├── git-repositories.tsx # Repository management
│ ├── profile.tsx # User profile
│ ├── settings.tsx # User settings
│ ├── tool-types.tsx # Tool types
│ ├── ssh-keys.tsx # SSH keys
│ └── [more...]
├── styles/ # Global styles
│ ├── index.css # Main stylesheet
│ └── [more...]
├── types.ts # Shared TypeScript types
├── router.tsx # Route definitions
└── main.tsx # Entry point
```
## Architecture Patterns
### 1. Component Architecture
**Page Components**: Top-level components mapped to routes
- Own data fetching
- Manage page-level state
- Compose reusable components
**Reusable Components**: Shared UI elements
- No data fetching
- Receive data via props
- Emit events via callbacks
**Example**:
```typescript
// Page component
const RepoWorkspace = () => {
const [files, setFiles] = useState([]);
// ... fetch data, manage state
return (
<div className="workspace">
<FileTree files={files} onFileClick={handleFileClick} />
<FileViewer content={content} />
</div>
);
};
// Reusable component
const FileTree = ({ files, onFileClick }: FileTreeProps) => {
return (
<ul>
{files.map(file => (
<li onClick={() => onFileClick(file)}>{file.name}</li>
))}
</ul>
);
};
```
### 2. State Management
**URL State**: Shareable, bookmarkable state
```typescript
// Sync selections to URL
const [searchParams, setSearchParams] = useSearchParams();
// ?repo=123&branch=main&path=src/main.py
```
**React Context**: Global auth state
```typescript
// Auth context provides user, login, logout
const { user, isAuthenticated } = useAuth();
```
**Local State**: Component-specific state
```typescript
const [isEditing, setIsEditing] = useState(false);
```
### 3. API Client Pattern
Centralized API clients with type safety:
```typescript
// api/git_repositories.ts
export const getRepositories = async (projectId: string) => {
const response = await fetch(`${API_BASE_URL}/projects/${projectId}/repositories`, {
credentials: 'include',
});
return response.json();
};
// Usage in component
const repos = await getRepositories(projectId);
```
### 4. Authentication Flow
```
User clicks Login
→ Redirect to /auth/login (backend)
→ Backend redirects to Authentik OAuth
→ User authenticates with Authentik
→ Authentik redirects to /auth/callback
→ Backend creates session cookie
→ Backend redirects to frontend
→ Frontend checks /auth/me
→ User is authenticated!
```
**Auth State**:
```typescript
interface AuthState {
user: User | null;
isAuthenticated: boolean;
isLoading: boolean;
}
```
### 5. Routing Structure
```typescript
// router.tsx
<Route path="/" element={<Dashboard />} />
<Route path="/projects" element={<ProjectsPage />} />
<Route path="/projects/:projectId" element={<RepoWorkspace />} />
<Route path="/projects/:projectId/repositories" element={<GitRepositories />} />
<Route path="/projects/:projectId/repositories/:repoId/history" element={<GitHistory />} />
<Route path="/profile" element={<ProfilePage />} />
<Route path="/settings" element={<SettingsPage />} />
<Route path="/ssh-keys" element={<SSHKeysPage />} />
<Route path="/tool-types" element={<ToolTypesPage />} />
```
## Data Flow
### Repository Workspace Example
```
1. User clicks project
→ Navigate to /projects/:id
2. RepoWorkspace mounts
→ Fetch project repositories
→ Select first repo (or from URL)
3. Repo selected
→ Fetch branches
→ Fetch file tree (default branch)
4. User clicks file
→ Fetch file content
→ Display in viewer
→ Update URL: ?path=src/main.py
5. User switches branch
→ Fetch file tree for branch
→ Re-fetch current file if viewing
→ Update URL: ?branch=develop
```
## Component Communication
```
┌─────────────────────────────────────┐
│ RepoWorkspace │
│ ┌──────────┐ ┌──────────────┐ │
│ │ FileTree │───▶│ FileViewer │ │
│ │ │ │ │ │
│ │ onFileClick │ content │ │
│ │ │ │ onEdit │ │
│ └──────────┘ └──────────────┘ │
│ ▲ │
│ │ │
│ ┌──────────┐ │
│ │ Branch │───▶ fetch tree │
│ │ Selector │ │
│ └──────────┘ │
└─────────────────────────────────────┘
```
## Styling Strategy
### CSS Variables (Design Tokens)
```css
:root {
--color-primary: #007bff;
--color-bg: #ffffff;
--color-text: #333333;
--sidebar-width: 250px;
--border-radius: 4px;
}
[data-theme="dark"] {
--color-bg: #1a1a1a;
--color-text: #e0e0e0;
}
```
### Component Styles
- Each page/component has scoped CSS
- Global utilities in `styles/index.css`
- No CSS-in-JS library (keep it simple)
## Testing Strategy
### Unit Tests (Vitest)
```typescript
// Component test
import { render, screen } from '@testing-library/react';
import { FileTree } from './file-tree';
test('renders file list', () => {
const files = [{ name: 'test.py', type: 'file' }];
render(<FileTree files={files} onFileClick={() => {}} />);
expect(screen.getByText('test.py')).toBeInTheDocument();
});
```
### Test Coverage
- Component rendering
- User interactions
- Auth state changes
- API mocking
## Performance Considerations
1. **Code Splitting**: Vite handles automatic chunking
2. **Lazy Loading**: React.lazy() for heavy pages
3. **Debouncing**: URL updates debounced (300ms)
4. **Caching**: Browser caches API responses (ETags)
5. **Optimistic UI**: Immediate feedback before API response
## Future Improvements
- [ ] Add React Query for server state management
- [ ] Implement virtual scrolling for large file trees
- [ ] Add service worker for offline support
- [ ] Implement real-time updates (WebSocket)
- [ ] Add error boundary components
## Development Workflow
```bash
# Start dev server
cd apps/web && npm run dev
# Run tests
npm run test
# Type check
npm run typecheck
# Lint
npm run lint
# Build for production
npm run build
```
+201
View File
@@ -0,0 +1,201 @@
# Authentik OAuth Configuration
## Overview
Headquarter uses Authentik as its OAuth2 provider for authentication. This guide covers setting up Authentik and configuring Headquarter to work with it.
## Prerequisites
- Running Authentik instance
- Admin access to Authentik
- Headquarter deployed and accessible
## Authentik Setup
### Step 1: Create Application
1. Log in to Authentik Admin interface
2. Navigate to **Applications****Applications**
3. Click **Create**
4. Fill in:
- **Name**: Headquarter
- **Slug**: `headquarter-web` (or your preferred slug)
- **Provider**: Create new
### Step 2: Create OAuth Provider
1. In the provider creation form:
- **Name**: Headquarter OAuth
- **Authentication flow**: `default-authentication-flow`
- **Authorization flow**: `default-provider-authorization-explicit-consent`
- **Client type**: Confidential
- **Client ID**: Generate or use your own UUID
- **Client Secret**: Generate strong secret
- **Redirect URIs**: `https://api.yourdomain.com/auth/callback`
2. **Advanced protocol settings**:
- **Signing Key**: Select a signing key (required)
- **Access Token validity**: Minutes (default: 5)
- **Refresh Token validity**: Days (default: 30)
3. Save provider
### Step 3: Configure Application
1. Return to Application configuration
2. Select the created provider
3. Save application
### Step 4: Verify URLs
Note these URLs from your Authentik instance:
- **Authorize URL**: `https://auth.yourdomain.com/application/o/authorize/`
- **Token URL**: `https://auth.yourdomain.com/application/o/token/`
- **UserInfo URL**: `https://auth.yourdomain.com/application/o/userinfo/`
- **JWKS URL**: `https://auth.yourdomain.com/application/o/headquarter-web/jwks/`
## Headquarter Configuration
### Environment Variables
Add to your `.env` file:
```bash
# Authentik Configuration
AUTHENTIK_DOMAIN=auth.yourdomain.com
AUTHENTIK_CLIENT_ID=your-client-id-uuid
AUTHENTIK_CLIENT_SECRET=your-generated-secret
AUTHENTIK_APPLICATION_SLUG=headquarter-web
AUTHENTIK_AUDIENCE=your-client-id-uuid
# Optional: Override default URLs if needed
# AUTHENTIK_AUTHORIZE_URL=https://auth.yourdomain.com/application/o/authorize/
# AUTHENTIK_TOKEN_URL=https://auth.yourdomain.com/application/o/token/
# AUTHENTIK_JWKS_URL=https://auth.yourdomain.com/application/o/headquarter-web/jwks/
# AUTHENTIK_ISSUER=https://auth.yourdomain.com/application/o/headquarter-web/
```
### Important Notes
- **AUTHENTIK_CLIENT_ID**: The UUID from Authentik (used for OAuth)
- **AUTHENTIK_APPLICATION_SLUG**: The URL-friendly name (e.g., `headquarter-web`)
- **AUTHENTIK_AUDIENCE**: Usually same as Client ID
## User Synchronization
On first login, Headquarter creates a local user record:
```python
user = User(
email="user@example.com",
name="User Name",
authentik_id="authentik-user-id",
)
```
### Synced Fields
| Authentik Field | Headquarter Field |
|----------------|-------------------|
| email | email |
| name | name |
| sub (user ID) | authentik_id |
| groups | (future: team membership) |
## Troubleshooting
### Redirect URI Error
**Problem**: "Redirect URI Error" from Authentik
**Solution**:
1. Check redirect URI in Authentik matches exactly
2. Must include protocol: `https://api.yourdomain.com/auth/callback`
3. No trailing slash difference
### Invalid Client
**Problem**: "invalid_client" error
**Solution**:
1. Verify Client ID matches
2. Verify Client Secret is correct
3. Check application slug in URLs
### Missing Refresh Token
**Problem**: Authentik doesn't return refresh token
**Solution**:
This is normal. Headquarter creates its own session cookies and doesn't need refresh tokens from Authentik.
### CORS Errors
**Problem**: CORS errors in browser
**Solution**:
1. Ensure API domain is in CORS origins
2. Check `WEB_BASE_URL` environment variable
3. Verify cookies have correct domain
## Security Best Practices
1. **Use HTTPS** - Never use HTTP in production
2. **Strong Client Secret** - Use generated secret, don't reuse
3. **Short Token Lifetime** - Keep access tokens short-lived
4. **Validate State** - Always verify state parameter
5. **Secure Cookies** - Use httpOnly, Secure, SameSite
## Advanced Configuration
### Custom Claims
To add custom claims to the token:
1. In Authentik, go to **Customization****Property Mappings**
2. Create new **Scope Mapping**
3. Add custom attributes
4. Assign to provider
### Group Mapping
For team/organization support:
1. Configure group property mapping in Authentik
2. Headquarter will sync groups on login
3. Use groups for authorization
### Multiple Applications
If running multiple environments:
1. Create separate applications in Authentik
2. Use different client IDs
3. Configure environment-specific redirect URIs
## Testing
### Manual Test
1. Visit `https://app.yourdomain.com`
2. Click "Login"
3. Should redirect to Authentik
4. Login with Authentik credentials
5. Should redirect back to app, logged in
### API Test
```bash
# Check auth endpoint
curl https://api.yourdomain.com/auth/me
# Should return 401 (not authenticated)
# After login, should return user data
curl https://api.yourdomain.com/auth/me --cookie "session=..."
```
## Resources
- [Authentik Documentation](https://goauthentik.io/docs/)
- [OAuth2 Provider Setup](https://goauthentik.io/docs/providers/oauth2/)
- [Headquarter Auth Documentation](../features/auth.md)
+266
View File
@@ -0,0 +1,266 @@
# Docker Deployment Guide
## Overview
Headquarter is deployed as a multi-container Docker application using Docker Compose. The stack includes:
- **API** (FastAPI/Python)
- **Web** (React/Vite)
- **PostgreSQL** (Database)
- **Redis** (Cache)
## Quick Start
### Prerequisites
- Docker Engine 20.10+
- Docker Compose 2.0+
- 2GB RAM minimum
- 10GB disk space
### Development Deployment
```bash
# Clone repository
git clone https://github.com/your-org/headquarter.git
cd headquarter
# Copy environment file
cp .env.example .env
# Edit .env with your settings
# Start all services
docker compose up -d
# Run database migrations
docker compose exec api alembic upgrade head
# Access the app
# Frontend: http://localhost:5173
# API: http://localhost:8000
```
### Production Deployment
```bash
# Use production compose file
cp .env.example .env
# Configure production values in .env
docker compose -f docker-compose.traefik.yml up -d
# Run migrations
docker compose -f docker-compose.traefik.yml exec api alembic upgrade head
```
## Configuration
### Environment Variables
Required variables:
```bash
# Domains
API_DOMAIN=api.yourdomain.com
WEB_DOMAIN=app.yourdomain.com
# Database
POSTGRES_USER=headquarter
POSTGRES_PASSWORD=secure-password
POSTGRES_DB=headquarter
# Authentik OAuth
AUTHENTIK_DOMAIN=auth.yourdomain.com
AUTHENTIK_CLIENT_ID=your-client-id
AUTHENTIK_CLIENT_SECRET=your-client-secret
AUTHENTIK_APPLICATION_SLUG=headquarter
# Session
SESSION_SECRET=your-session-secret-min-32-chars
# Storage
REPO_BASE_PATH=/data/repos
```
### Volume Mounts
| Volume | Container Path | Purpose |
|--------|---------------|---------|
| postgres_data | /var/lib/postgresql/data | Database persistence |
| repo_data | /data/repos | Git repositories |
| avatar_uploads | /app/uploads | User avatars |
## Docker Compose Files
### docker-compose.yml (Development)
Standard development setup with:
- Hot reload for API
- Vite dev server for frontend
- Direct port access
- Local PostgreSQL
### docker-compose.traefik.yml (Production)
Production setup with:
- Traefik reverse proxy
- Let's Encrypt SSL
- External Traefik network
- Optimized builds
## SSL/TLS
### Development
Self-signed certificates or HTTP only.
### Production
Automatic Let's Encrypt certificates via Traefik.
```bash
# Traefik labels for SSL
traefik.http.routers.api.tls=true
traefik.http.routers.api.tls.certresolver=letsencrypt
```
## Health Checks
All services include health checks:
```yaml
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 3
```
## Backup and Restore
### Database Backup
```bash
# Automated daily backup
docker compose exec postgres pg_dump -U headquarter headquarter > backup.sql
# Restore
docker compose exec -T postgres psql -U headquarter < backup.sql
```
### Repository Backup
```bash
# Backup repos volume
docker run --rm -v headquarter_repo_data:/data -v $(pwd):/backup alpine tar czf /backup/repos.tar.gz /data
# Restore
docker run --rm -v headquarter_repo_data:/data -v $(pwd):/backup alpine tar xzf /backup/repos.tar.gz -C /
```
## Monitoring
### Logs
```bash
# All services
docker compose logs -f
# Specific service
docker compose logs -f api
# Last 100 lines
docker compose logs --tail=100 api
```
### Resource Usage
```bash
# Container stats
docker stats
# Disk usage
docker system df -v
```
## Troubleshooting
### Common Issues
**Database connection failed**
```bash
# Check PostgreSQL is running
docker compose ps
# Check logs
docker compose logs postgres
# Verify credentials in .env match
```
**Migrations failing**
```bash
# Check current migration version
docker compose exec api alembic current
# Manual upgrade
docker compose exec api alembic upgrade head
```
**Permission denied on repos**
```bash
# Fix permissions
docker compose exec api chown -R appuser:appuser /data/repos
```
## Updates
### Rolling Update
```bash
# Pull latest images
docker compose pull
# Restart with new images
docker compose up -d
# Run migrations if needed
docker compose exec api alembic upgrade head
```
### Zero-Downtime Update
```bash
# Scale API to 2 instances
docker compose up -d --scale api=2
# Update one instance at a time
# (Requires load balancer configuration)
```
## Security Best Practices
1. **Use strong passwords** for database and session secret
2. **Enable HTTPS** in production
3. **Keep images updated** with security patches
4. **Use read-only volumes** where possible
5. **Limit container capabilities**
6. **Use secrets management** for sensitive data
```yaml
# Example security hardening
api:
read_only: true
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
cap_add:
- CHOWN
- SETGID
- SETUID
```
## Resources
- [Docker Documentation](https://docs.docker.com/)
- [Docker Compose Reference](https://docs.docker.com/compose/)
- [Traefik Documentation](https://doc.traefik.io/traefik/)
+268
View File
@@ -0,0 +1,268 @@
# Environment Variables Reference
## Overview
This document describes all environment variables used by Headquarter. Variables are categorized by component and purpose.
## Required Variables
These variables must be set for the application to function:
### Domains
| Variable | Default | Description |
|----------|---------|-------------|
| `API_DOMAIN` | `localhost` | API server domain (e.g., `api.example.com`) |
| `WEB_DOMAIN` | `localhost` | Web frontend domain (e.g., `app.example.com`) |
### Database
| Variable | Default | Description |
|----------|---------|-------------|
| `POSTGRES_USER` | `headquarter` | PostgreSQL username |
| `POSTGRES_PASSWORD` | `headquarter` | PostgreSQL password (change in production!) |
| `POSTGRES_DB` | `headquarter` | PostgreSQL database name |
### Authentication
| Variable | Default | Description |
|----------|---------|-------------|
| `AUTHENTIK_DOMAIN` | `authentik.local` | Authentik server domain |
| `AUTHENTIK_CLIENT_ID` | `headquarter-web` | OAuth client ID from Authentik |
| `AUTHENTIK_CLIENT_SECRET` | `change-me` | OAuth client secret (change immediately!) |
| `AUTHENTIK_APPLICATION_SLUG` | `headquarter-web` | Authentik application slug |
| `SESSION_SECRET` | `change-me-session-secret` | Secret for signing session cookies (min 32 chars) |
## Optional Variables
### Application
| Variable | Default | Description |
|----------|---------|-------------|
| `APP_ENV` | `development` | Environment: `development`, `staging`, `production` |
| `LOG_LEVEL` | `INFO` | Logging level: `DEBUG`, `INFO`, `WARNING`, `ERROR` |
### Database
| Variable | Default | Description |
|----------|---------|-------------|
| `DATABASE_URL` | (constructed) | Full PostgreSQL connection URL |
| `POSTGRES_HOST` | `postgres` | PostgreSQL hostname |
| `POSTGRES_PORT` | `5432` | PostgreSQL port |
When `DATABASE_URL` is not set, it's constructed from:
```
postgresql+asyncpg://POSTGRES_USER:POSTGRES_PASSWORD@POSTGRES_HOST:POSTGRES_PORT/POSTGRES_DB
```
### URLs
| Variable | Default | Description |
|----------|---------|-------------|
| `API_PUBLIC_URL` | (constructed) | Public API URL (e.g., `https://api.example.com`) |
| `WEB_PUBLIC_URL` | (constructed) | Public web URL (e.g., `https://app.example.com`) |
Constructed from domains when not set:
```
API: https://API_DOMAIN (production) or http://API_DOMAIN:8000 (development)
WEB: https://WEB_DOMAIN (production) or http://WEB_DOMAIN:5173 (development)
```
### Authentik Overrides
| Variable | Default | Description |
|----------|---------|-------------|
| `AUTHENTIK_AUTHORIZE_URL` | (constructed) | OAuth authorization endpoint |
| `AUTHENTIK_TOKEN_URL` | (constructed) | OAuth token endpoint |
| `AUTHENTIK_JWKS_URL` | (constructed) | JWKS endpoint |
| `AUTHENTIK_ISSUER` | (constructed) | OAuth issuer URL |
| `AUTHENTIK_AUDIENCE` | `headquarter-web` | Token audience |
Constructed URLs:
```
https://AUTHENTIK_DOMAIN/application/o/authorize/
https://AUTHENTIK_DOMAIN/application/o/token/
https://AUTHENTIK_DOMAIN/application/o/AUTHENTIK_APPLICATION_SLUG/jwks/
https://AUTHENTIK_DOMAIN/application/o/AUTHENTIK_APPLICATION_SLUG/
```
### Session
| Variable | Default | Description |
|----------|---------|-------------|
| `SESSION_TTL_HOURS` | `24` | Session cookie lifetime in hours |
| `COOKIE_DOMAIN` | (none) | Cookie domain (set for cross-subdomain) |
| `COOKIE_SECURE` | `true` (prod) | Secure cookie flag |
| `COOKIE_SAMESITE` | `lax` | SameSite cookie attribute |
### Storage
| Variable | Default | Description |
|----------|---------|-------------|
| `REPO_BASE_PATH` | `/data/repos` | Base path for git repositories |
| `UPLOAD_DIR` | `uploads` | Directory for file uploads |
### Development
| Variable | Default | Description |
|----------|---------|-------------|
| `VITE_API_BASE_URL` | `http://localhost:8000` | Frontend API URL |
## Docker Compose Variables
### Traefik
| Variable | Default | Description |
|----------|---------|-------------|
| `TRAEFIK_NETWORK` | `traefik` | Docker network name for Traefik |
| `TRAEFIK_CERT_RESOLVER` | `letsencrypt` | Certificate resolver name |
### Docker Specific
| Variable | Default | Description |
|----------|---------|-------------|
| `COMPOSE_PROJECT_NAME` | `headquarter` | Docker Compose project name |
## Configuration Examples
### Development
```bash
APP_ENV=development
API_DOMAIN=localhost
WEB_DOMAIN=localhost
DATABASE_URL=postgresql+asyncpg://headquarter:headquarter@localhost:5432/headquarter
AUTHENTIK_DOMAIN=authentik.local
AUTHENTIK_CLIENT_ID=headquarter-web
AUTHENTIK_CLIENT_SECRET=dev-secret
SESSION_SECRET=dev-session-secret-change-in-production
VITE_API_BASE_URL=http://localhost:8000
```
### Production
```bash
APP_ENV=production
API_DOMAIN=api.headquarter.example.com
WEB_DOMAIN=app.headquarter.example.com
POSTGRES_PASSWORD=very-secure-password-here
AUTHENTIK_DOMAIN=auth.example.com
AUTHENTIK_CLIENT_ID=your-uuid-from-authentik
AUTHENTIK_CLIENT_SECRET=your-secret-from-authentik
AUTHENTIK_APPLICATION_SLUG=headquarter-web
SESSION_SECRET=minimum-32-characters-long-secret-key
SESSION_TTL_HOURS=24
COOKIE_DOMAIN=.headquarter.example.com
TRAEFIK_NETWORK=web
TRAEFIK_CERT_RESOLVER=letsencrypt
REPO_BASE_PATH=/data/repos
```
### Testing
```bash
APP_ENV=testing
DATABASE_URL=postgresql+asyncpg://headquarter:headquarter@localhost:5432/headquarter_test
SESSION_SECRET=test-secret
AUTHENTIK_CLIENT_ID=test-client
AUTHENTIK_CLIENT_SECRET=test-secret
```
## Security Checklist
Before deploying to production, verify:
- [ ] `POSTGRES_PASSWORD` is strong and unique
- [ ] `AUTHENTIK_CLIENT_SECRET` is kept secret
- [ ] `SESSION_SECRET` is at least 32 characters
- [ ] `APP_ENV` is set to `production`
- [ ] `COOKIE_SECURE` is enabled
- [ ] `COOKIE_DOMAIN` is set for your domain
- [ ] No default secrets in production
- [ ] `.env` file is not committed to git
- [ ] `.env` file has restricted permissions (600)
## Troubleshooting
### Variable Not Set
```bash
# Error: "Environment variable not set"
# Solution: Export the variable or add to .env file
export SESSION_SECRET="your-secret-here"
```
### Invalid URL
```bash
# Error: "Invalid URL"
# Solution: Check domain variables don't include protocol
# Bad: API_DOMAIN=https://api.example.com
# Good: API_DOMAIN=api.example.com
```
### Database Connection Failed
```bash
# Check DATABASE_URL or individual components
# Verify PostgreSQL is running
# Check credentials match
```
## Migration from Old Config
If upgrading from older versions:
1. `JWT_SECRET` → Removed (not needed with session auth)
2. `ACCESS_TOKEN_TTL_MINUTES` → Removed
3. `REFRESH_TOKEN_TTL_DAYS` → Removed
4. `AUTHENTIK_AUDIENCE` → Now defaults to `AUTHENTIK_CLIENT_ID`
5. `AUTHENTIK_APPLICATION_SLUG` → New variable for URL construction
## Environment Files
### Files Structure
```
headquarter/
├── .env # Main environment (not committed)
├── .env.example # Example/template
├── apps/
│ ├── api/
│ │ └── .env # API-specific overrides
│ └── web/
│ └── .env # Frontend-specific overrides
└── docker-compose.traefik.yml # References .env
```
### Loading Order
1. System environment variables
2. `.env` file in project root
3. Component-specific `.env` files
4. Default values in code
Later values override earlier ones.
## Validation
The application validates required variables on startup:
```python
# Missing critical variable
if not settings.session_secret or settings.session_secret == "change-me":
logger.warning("SESSION_SECRET not configured properly!")
# Invalid configuration
if settings.app_env == "production" and "localhost" in settings.api_domain:
logger.warning("Using localhost in production!")
```
## Best Practices
1. **Never commit `.env` files**
2. **Use strong passwords** for database and secrets
3. **Rotate secrets** regularly
4. **Use different secrets** per environment
5. **Document custom variables** in this file
6. **Validate configuration** before deployment
+305
View File
@@ -0,0 +1,305 @@
# Traefik Reverse Proxy Setup
## Overview
Traefik serves as the reverse proxy and load balancer for Headquarter in production, handling:
- SSL/TLS termination
- Automatic HTTPS via Let's Encrypt
- Route-based traffic distribution
- WebSocket support
## Architecture
```
Internet
Traefik (443)
├───▶ api.yourdomain.com → Headquarter API (8000)
└───▶ app.yourdomain.com → Headquarter Web (80)
```
## Prerequisites
- Docker Compose installed
- DNS records pointing to your server:
- `api.yourdomain.com` → Server IP
- `app.yourdomain.com` → Server IP
- Ports 80 and 443 open in firewall
## Configuration
### 1. Environment Variables
```bash
# .env file
API_DOMAIN=api.headquarter.example.com
WEB_DOMAIN=app.headquarter.example.com
# Traefik network (shared with other Traefik instances)
TRAEFIK_NETWORK=web
# SSL Certificate resolver
TRAEFIK_CERT_RESOLVER=letsencrypt
```
### 2. Traefik Labels
Services are configured via Docker labels:
```yaml
# API Service labels
labels:
- "traefik.enable=true"
- "traefik.http.routers.headquarter-api.rule=Host(`api.headquarter.example.com`)"
- "traefik.http.routers.headquarter-api.entrypoints=websecure"
- "traefik.http.routers.headquarter-api.tls=true"
- "traefik.http.routers.headquarter-api.tls.certresolver=${TRAEFIK_CERT_RESOLVER:-letsencrypt}"
- "traefik.http.services.headquarter-api.loadbalancer.server.port=8000"
# Web Service labels
labels:
- "traefik.enable=true"
- "traefik.http.routers.headquarter-frontend.rule=Host(`app.headquarter.example.com`)"
- "traefik.http.routers.headquarter-frontend.entrypoints=websecure"
- "traefik.http.routers.headquarter-frontend.tls=true"
- "traefik.http.routers.headquarter-frontend.tls.certresolver=${TRAEFIK_CERT_RESOLVER:-letsencrypt}"
- "traefik.http.services.headquarter-frontend.loadbalancer.server.port=80"
```
### 3. External Network
Connect to existing Traefik instance:
```yaml
networks:
traefik:
external: true
name: ${TRAEFIK_NETWORK:-traefik}
```
## Deployment Steps
### Step 1: Verify DNS
Ensure DNS records resolve to your server:
```bash
nslookup api.headquarter.example.com
nslookup app.headquarter.example.com
```
### Step 2: Start Services
```bash
# Start with Traefik compose file
docker compose -f docker-compose.traefik.yml up -d
# Verify containers are running
docker compose -f docker-compose.traefik.yml ps
```
### Step 3: Check SSL Certificates
```bash
# View Traefik logs
docker compose -f docker-compose.traefik.yml logs -f
# Check certificate status
curl -v https://api.headquarter.example.com/health
```
### Step 4: Run Migrations
```bash
docker compose -f docker-compose.traefik.yml exec api alembic upgrade head
```
## SSL Configuration
### Let's Encrypt (Default)
Automatic certificate generation and renewal:
```yaml
labels:
- "traefik.http.routers.headquarter-api.tls.certresolver=letsencrypt"
```
### Custom Certificates
For custom or wildcard certificates:
```yaml
labels:
- "traefik.http.routers.headquarter-api.tls=true"
- "traefik.http.routers.headquarter-api.tls.certresolver=myresolver"
```
### Self-Signed (Development)
```yaml
labels:
- "traefik.http.routers.headquarter-api.tls=true"
- "traefik.http.routers.headquarter-api.tls.certresolver=selfsigned"
```
## Advanced Configuration
### Rate Limiting
```yaml
labels:
- "traefik.http.middlewares.ratelimit.ratelimit.average=100"
- "traefik.http.routers.headquarter-api.middlewares=ratelimit"
```
### Basic Auth (for staging)
```yaml
labels:
- "traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/"
- "traefik.http.routers.headquarter-api.middlewares=auth"
```
### CORS Headers
```yaml
labels:
- "traefik.http.middlewares.cors.headers.accesscontrolalloworiginlist=*"
- "traefik.http.routers.headquarter-api.middlewares=cors"
```
## Troubleshooting
### Certificate Issues
**Problem**: Certificate not generated
```bash
# Check Traefik logs
docker compose logs traefik
# Verify DNS resolution
nslookup your-domain.com
# Check port 80 is accessible (required for HTTP challenge)
curl -I http://your-domain.com
```
**Problem**: Certificate expired
```bash
# Force renewal
docker compose restart traefik
# Or delete acme.json and restart
rm acme.json
docker compose restart traefik
```
### Routing Issues
**Problem**: 404 errors
```bash
# Check Traefik dashboard (if enabled)
# http://traefik.yourdomain.com
# Verify labels are correct
docker compose -f docker-compose.traefik.yml config
# Check container is on correct network
docker network inspect ${TRAEFIK_NETWORK:-traefik}
```
**Problem**: Services not detected
```bash
# Verify traefik.enable label
docker compose -f docker-compose.traefik.yml exec api labels
# Check Docker provider in Traefik
docker compose logs traefik | grep "Provider connection established"
```
## Maintenance
### Update Traefik
```bash
# Pull latest Traefik image
docker compose -f docker-compose.traefik.yml pull traefik
# Restart
docker compose -f docker-compose.traefik.yml up -d traefik
```
### View Dashboard
Enable Traefik dashboard (secure it in production):
```yaml
# traefik.yml
dashboard:
enabled: true
# Add to docker-compose.traefik.yml
labels:
- "traefik.http.routers.dashboard.rule=Host(`traefik.yourdomain.com`)"
- "traefik.http.routers.dashboard.tls=true"
- "traefik.http.routers.dashboard.tls.certresolver=letsencrypt"
```
## Security Considerations
1. **Always use HTTPS** in production (redirect HTTP to HTTPS)
2. **Secure Traefik dashboard** with authentication
3. **Use strong certificate resolver** (Let's Encrypt production)
4. **Keep Traefik updated** for security patches
5. **Restrict Docker socket access** if using Docker provider
## Example Complete Configuration
```yaml
# docker-compose.traefik.yml
services:
api:
build:
context: ./apps/api
environment:
API_DOMAIN: ${API_DOMAIN}
WEB_DOMAIN: ${WEB_DOMAIN}
# ... other env vars
labels:
- "traefik.enable=true"
- "traefik.http.routers.headquarter-api.rule=Host(`${API_DOMAIN}`)"
- "traefik.http.routers.headquarter-api.entrypoints=websecure"
- "traefik.http.routers.headquarter-api.tls=true"
- "traefik.http.routers.headquarter-api.tls.certresolver=${TRAEFIK_CERT_RESOLVER:-letsencrypt}"
- "traefik.http.services.headquarter-api.loadbalancer.server.port=8000"
networks:
- backend
- traefik
web:
build:
context: ./apps/web
labels:
- "traefik.enable=true"
- "traefik.http.routers.headquarter-frontend.rule=Host(`${WEB_DOMAIN}`)"
- "traefik.http.routers.headquarter-frontend.entrypoints=websecure"
- "traefik.http.routers.headquarter-frontend.tls=true"
- "traefik.http.routers.headquarter-frontend.tls.certresolver=${TRAEFIK_CERT_RESOLVER:-letsencrypt}"
- "traefik.http.services.headquarter-frontend.loadbalancer.server.port=80"
networks:
- traefik
networks:
traefik:
external: true
name: ${TRAEFIK_NETWORK:-traefik}
backend:
internal: true
```
## Resources
- [Traefik Documentation](https://doc.traefik.io/traefik/)
- [Docker Compose Integration](https://doc.traefik.io/traefik/providers/docker/)
- [Let's Encrypt Configuration](https://doc.traefik.io/traefik/https/acme/)
+261
View File
@@ -0,0 +1,261 @@
# Contributing Guide
## Welcome
Thank you for your interest in contributing to Headquarter! This document provides guidelines and workflows for contributing.
## Getting Started
1. Fork the repository
2. Clone your fork: `git clone https://github.com/your-username/headquarter.git`
3. Set up development environment (see [Setup Guide](./setup.md))
4. Create a branch: `git checkout -b feature/your-feature`
## Development Workflow
### 1. Find or Create an Issue
- Check existing issues for something to work on
- Create an issue to discuss new features before implementing
- Comment on issues to claim them
### 2. Create a Branch
```bash
# Feature branch
git checkout -b feature/description
# Bug fix branch
git checkout -b fix/description
# Documentation branch
git checkout -b docs/description
```
### 3. Make Changes
- Write clear, concise code
- Follow existing patterns and conventions
- Add tests for new functionality
- Update documentation as needed
### 4. Run Quality Gates
```bash
# Backend
cd apps/api
ruff check src/ tests/
mypy src/
pytest
# Frontend
cd apps/web
npm run lint
npm run typecheck
npm run test
npm run build
```
### 5. Commit Changes
We use conventional commits:
```bash
# Format: type(scope): description
# Examples:
git commit -m "feat(auth): add OAuth2 login"
git commit -m "fix(api): handle missing user gracefully"
git commit -m "docs(readme): update installation instructions"
git commit -m "test(git): add URL parsing tests"
git commit -m "refactor(models): extract base repository"
```
**Types**:
- `feat`: New feature
- `fix`: Bug fix
- `docs`: Documentation
- `style`: Formatting (no code change)
- `refactor`: Code restructuring
- `test`: Adding tests
- `chore`: Maintenance tasks
### 6. Push and Create Pull Request
```bash
git push origin feature/description
```
**PR Description should include**:
- What changed and why
- How to test
- Screenshots (for UI changes)
- Link to related issue
## Code Standards
### Python (Backend)
**Style**: Follow PEP 8 and project conventions
```python
# Function naming: snake_case
def get_user_by_id(user_id: str) -> User | None:
pass
# Class naming: PascalCase
class GitRepositoryService:
pass
# Constants: UPPER_SNAKE_CASE
MAX_FILE_SIZE = 1024 * 1024 # 1MB
# Type hints required
def process_data(data: dict[str, Any]) -> ProcessedResult:
pass
```
**Docstrings**: Google style
```python
def extract_base_repo_url(url: str) -> str | None:
"""Extract base repository URL from a browser URL.
Args:
url: The URL to parse, may be a browser URL or git URL.
Returns:
The base repository URL with .git suffix, or None if parsing fails.
Examples:
>>> extract_base_repo_url("https://github.com/user/repo/tree/main")
'https://github.com/user/repo.git'
>>> extract_base_repo_url("https://github.com/user/repo.git")
'https://github.com/user/repo.git'
"""
pass
```
### TypeScript (Frontend)
**Style**: Follow existing patterns
```typescript
// Interface naming: PascalCase
interface User {
id: string;
email: string;
name: string;
}
// Function naming: camelCase
function getUserById(userId: string): Promise<User> {
return api.get(`/users/${userId}`);
}
// Component naming: PascalCase
const UserProfile: React.FC<UserProfileProps> = ({ user }) => {
return <div>{user.name}</div>;
};
```
## Testing Requirements
### New Features
- Unit tests for business logic
- Integration tests for API endpoints
- Component tests for UI components
### Bug Fixes
- Regression test that would catch the bug
- Verify fix with the test
### Example
```python
# Backend test
def test_extract_github_browser_url():
url = "https://github.com/user/repo/tree/main"
result = extract_base_repo_url(url)
assert result == "https://github.com/user/repo.git"
# Frontend test
test('shows file tree', () => {
render(<FileTree files={mockFiles} onFileClick={() => {}} />);
expect(screen.getByText('src')).toBeInTheDocument();
});
```
## Documentation
Update documentation when:
- Adding new features
- Changing API endpoints
- Modifying configuration
- Adding environment variables
**Documentation locations**:
- `README.md` - Project overview
- `docs/features/` - Feature documentation
- `docs/api/` - API documentation
- `docs/deployment/` - Deployment guides
## Review Process
1. **Automated checks** must pass (CI/CD)
2. **Code review** by at least one maintainer
3. **Approval** required before merge
4. **Squash merge** to keep history clean
### Review Checklist
**For Authors**:
- [ ] Tests pass locally
- [ ] Quality gates pass
- [ ] Documentation updated
- [ ] PR description is clear
**For Reviewers**:
- [ ] Code makes sense
- [ ] Tests cover changes
- [ ] No security issues
- [ ] Follows conventions
## Release Process
1. Update version in `pyproject.toml` and `package.json`
2. Update `CHANGELOG.md`
3. Create git tag: `git tag v1.2.3`
4. Push tag: `git push origin v1.2.3`
5. Create GitHub release with notes
## Community
### Communication Channels
- GitHub Issues: Bug reports and feature requests
- GitHub Discussions: Questions and ideas
- Pull Requests: Code contributions
### Code of Conduct
- Be respectful and inclusive
- Welcome newcomers
- Focus on constructive feedback
- Respect different viewpoints
## Questions?
- Check existing documentation
- Search closed issues
- Ask in GitHub Discussions
- Join community chat (if available)
## Resources
- [Development Setup](./setup.md)
- [Testing Guide](./testing.md)
- [Quality Gates](./quality-gates.md)
- [Project README](../../README.md)
+365
View File
@@ -0,0 +1,365 @@
# Quality Gates
## Overview
All code changes must pass quality gates before being merged. These gates ensure code consistency, type safety, and prevent common issues.
## Backend Quality Gates
### 1. Code Formatting (ruff)
**Purpose**: Enforce consistent code style
```bash
cd apps/api
ruff check src/ tests/
ruff format src/ tests/
```
**Configuration** (`pyproject.toml`):
```toml
[tool.ruff]
line-length = 100
target-version = "py311"
select = ["E", "F", "I", "W", "UP"]
ignore = ["E501"]
[tool.ruff.lint.pydocstyle]
convention = "google"
```
**Pre-commit hook**:
```bash
# Install pre-commit
pip install pre-commit
pre-commit install
# Run manually
pre-commit run --all-files
```
### 2. Type Checking (mypy)
**Purpose**: Catch type errors before runtime
```bash
cd apps/api
mypy src/
```
**Configuration** (`pyproject.toml`):
```toml
[tool.mypy]
python_version = "3.11"
warn_return_any = true
warn_unused_ignores = true
disallow_untyped_defs = true
disallow_incomplete_defs = true
check_untyped_defs = true
```
**Common issues**:
- Missing type hints on function parameters
- Returning wrong type
- None checks needed
### 3. Unit Tests (pytest)
**Purpose**: Verify functionality works as expected
```bash
cd apps/api
pytest -v
```
**Requirements**:
- All tests must pass
- New code should have tests
- Coverage should not decrease
### 4. Security Checks
**Bandit** (security linter):
```bash
bandit -r src/
```
**Safety** (dependency vulnerabilities):
```bash
safety check
```
## Frontend Quality Gates
### 1. Type Checking (TypeScript)
**Purpose**: Catch type errors at build time
```bash
cd apps/web
npm run typecheck
```
**Configuration** (`tsconfig.json`):
```json
{
"compilerOptions": {
"target": "ES2020",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
}
}
```
### 2. Linting (ESLint)
**Purpose**: Enforce code style and catch issues
```bash
cd apps/web
npm run lint
npm run lint:fix
```
**Configuration** (`.eslintrc.cjs`):
```javascript
module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:react-hooks/recommended',
],
parser: '@typescript-eslint/parser',
plugins: ['react-refresh'],
rules: {
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
}
```
### 3. Build Check
**Purpose**: Ensure production build succeeds
```bash
cd apps/web
npm run build
```
**Requirements**:
- No TypeScript errors
- No build warnings
- Bundle size reasonable
### 4. Unit Tests (Vitest)
```bash
cd apps/web
npm run test
```
**Requirements**:
- All tests pass
- No test failures
- Coverage maintained
## Running All Gates
### Backend
```bash
cd apps/api
# Run all gates
ruff check src/ tests/ && \
mypy src/ && \
pytest
# Or use Makefile
make lint # ruff + mypy
make test # pytest
make check # All backend gates
```
### Frontend
```bash
cd apps/web
# Run all gates
npm run lint && \
npm run typecheck && \
npm run test && \
npm run build
# Or use package.json scripts
npm run check # All frontend gates
```
### Full Project
```bash
# From root
make check-all # Run all backend and frontend gates
```
## Continuous Integration
All quality gates run automatically on:
- Every Pull Request
- Every push to main branch
**CI Pipeline**:
```yaml
stages:
- lint
- test
- build
backend-lint:
stage: lint
script:
- cd apps/api && ruff check src/ tests/
- cd apps/api && mypy src/
backend-test:
stage: test
script:
- cd apps/api && pytest -v
frontend-lint:
stage: lint
script:
- cd apps/web && npm run lint
- cd apps/web && npm run typecheck
frontend-test:
stage: test
script:
- cd apps/web && npm run test
frontend-build:
stage: build
script:
- cd apps/web && npm run build
```
## Fixing Common Issues
### Backend
**ruff: Line too long**
```python
# Bad
result = some_very_long_function_name(with_many_parameters, that_make_the_line_too_long)
# Good
result = some_very_long_function_name(
with_many_parameters,
that_make_the_line_too_long,
)
```
**mypy: Missing return type**
```python
# Bad
def get_user(user_id):
return User.query.get(user_id)
# Good
def get_user(user_id: str) -> User | None:
return User.query.get(user_id)
```
### Frontend
**TypeScript: Implicit any**
```typescript
// Bad
function processData(data) {
return data.map(item => item.name);
}
// Good
function processData(data: DataItem[]) {
return data.map(item => item.name);
}
```
**ESLint: Unused variable**
```typescript
// Bad
const [count, setCount] = useState(0);
// count is never used
// Good
const [count] = useState(0);
// Or remove if not needed
```
## IDE Integration
### VS Code
**Settings** (`.vscode/settings.json`):
```json
{
"python.linting.enabled": true,
"python.linting.mypyEnabled": true,
"python.formatting.provider": "ruff",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
}
}
```
### PyCharm
1. **File****Settings****Tools****External Tools**
2. Add ruff and mypy as external tools
3. Set up pre-commit hooks
## Pre-commit Hooks
`.pre-commit-config.yaml`:
```yaml
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.1.0
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
- id: ruff-format
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.7.0
hooks:
- id: mypy
additional_dependencies: [types-all]
- repo: local
hooks:
- id: frontend-lint
name: Frontend Lint
entry: bash -c 'cd apps/web && npm run lint'
language: system
files: ^apps/web/
```
## Resources
- [ruff Documentation](https://docs.astral.sh/ruff/)
- [mypy Documentation](https://mypy.readthedocs.io/)
- [ESLint Documentation](https://eslint.org/)
- [TypeScript Handbook](https://www.typescriptlang.org/docs/)
+299
View File
@@ -0,0 +1,299 @@
# Development Setup Guide
## Prerequisites
- Python 3.11+
- Node.js 18+
- PostgreSQL 15+
- Redis 7+
- Git
## Quick Setup
### 1. Clone Repository
```bash
git clone https://github.com/your-org/headquarter.git
cd headquarter
```
### 2. Backend Setup
```bash
cd apps/api
# Create virtual environment
python -m venv .venv
source .venv/bin/activate # Linux/Mac
# .venv\Scripts\activate # Windows
# Install dependencies
pip install -e ".[dev]"
# Copy environment file
cp .env.example .env
# Edit .env with your settings
```
### 3. Frontend Setup
```bash
cd apps/web
# Install dependencies
npm install
# Copy environment file
cp .env.example .env
# Edit .env with your settings
```
### 4. Database Setup
```bash
# Start PostgreSQL and Redis
# (Using Docker or local installation)
docker run -d -p 5432:5432 -e POSTGRES_PASSWORD=headquarter postgres:15
docker run -d -p 6379:6379 redis:7
# Create database
createdb headquarter
# Run migrations
cd apps/api
alembic upgrade head
# (Optional) Seed data
python -m src.scripts.seed
```
### 5. Start Development Servers
Terminal 1 - Backend:
```bash
cd apps/api
source .venv/bin/activate
python -m uvicorn src.main:app --reload --port 8000
```
Terminal 2 - Frontend:
```bash
cd apps/web
npm run dev
```
Terminal 3 - (Optional) Authentik:
```bash
# If using local Authentik
docker compose -f docker-compose.authentik.yml up -d
```
## Development Environment Variables
Create `apps/api/.env`:
```bash
APP_ENV=development
DATABASE_URL=postgresql+asyncpg://headquarter:headquarter@localhost:5432/headquarter
REDIS_URL=redis://localhost:6379/0
SESSION_SECRET=dev-session-secret-change-me
API_DOMAIN=localhost
WEB_DOMAIN=localhost
# Authentik (optional for local dev)
AUTHENTIK_DOMAIN=authentik.local
AUTHENTIK_CLIENT_ID=headquarter-web
AUTHENTIK_CLIENT_SECRET=change-me
AUTHENTIK_APPLICATION_SLUG=headquarter-web
```
Create `apps/web/.env`:
```bash
VITE_API_BASE_URL=http://localhost:8000
```
## IDE Setup
### VS Code Extensions
Recommended extensions:
- Python (ms-python.python)
- Pylance (ms-python.vscode-pylance)
- ESLint (dbaeumer.vscode-eslint)
- Prettier (esbenp.prettier-vscode)
- TypeScript Importer (pmneo.tsimporter)
### PyCharm/IntelliJ
1. Open `apps/api` as project
2. Set Python interpreter to `.venv`
3. Enable Django/Flask support for FastAPI
## Debugging
### Backend Debugging
**VS Code launch.json**:
```json
{
"version": "0.2.0",
"configurations": [
{
"name": "Python: FastAPI",
"type": "python",
"request": "launch",
"module": "uvicorn",
"args": ["src.main:app", "--reload", "--port", "8000"],
"jinja": true,
"justMyCode": true
}
]
}
```
**PyCharm**:
1. Run → Edit Configurations
2. Add Python configuration
3. Module name: `uvicorn`
4. Parameters: `src.main:app --reload --port 8000`
### Frontend Debugging
**VS Code launch.json**:
```json
{
"type": "chrome",
"request": "launch",
"name": "Launch Chrome against localhost",
"url": "http://localhost:5173",
"webRoot": "${workspaceFolder}/apps/web/src"
}
```
## Common Tasks
### Database Migrations
```bash
cd apps/api
# Create new migration
alembic revision --autogenerate -m "description"
# Run migrations
alembic upgrade head
# Downgrade
alembic downgrade -1
# Current version
alembic current
# History
alembic history
```
### Adding Dependencies
**Backend**:
```bash
cd apps/api
# Add production dependency
pip install package-name
# Add to pyproject.toml [project.dependencies]
# Add dev dependency
pip install -e ".[dev]"
# Add to pyproject.toml [project.optional-dependencies.dev]
```
**Frontend**:
```bash
cd apps/web
npm install package-name
npm install -D package-name # dev dependency
```
### Git Workflow
1. Create feature branch: `git checkout -b feature/name`
2. Make changes
3. Run quality gates (see below)
4. Commit: `git commit -m "feat: description"`
5. Push: `git push origin feature/name`
6. Create Pull Request
## Project Structure
```
headquarter/
├── apps/
│ ├── api/ # Backend (FastAPI)
│ │ ├── src/
│ │ │ ├── api/ # API routes
│ │ │ ├── auth/ # Authentication
│ │ │ ├── models/ # Database models
│ │ │ ├── utils/ # Utilities
│ │ │ └── main.py # Entry point
│ │ ├── tests/ # Test suites
│ │ ├── alembic/ # Migrations
│ │ └── pyproject.toml # Dependencies
│ └── web/ # Frontend (React)
│ ├── src/
│ │ ├── api/ # API clients
│ │ ├── components/ # React components
│ │ ├── pages/ # Page components
│ │ └── styles/ # CSS
│ └── package.json # Dependencies
├── docs/ # Documentation
├── docker-compose.yml # Dev setup
└── Makefile # Common commands
```
## Troubleshooting
### Database Connection Errors
```bash
# Check PostgreSQL is running
pg_isready -h localhost -p 5432
# Check credentials
psql postgresql://headquarter:headquarter@localhost:5432/headquarter -c "SELECT 1"
```
### Port Conflicts
```bash
# Find process using port 8000
lsof -i :8000
# Kill process
kill -9 <PID>
```
### Node Modules Issues
```bash
cd apps/web
rm -rf node_modules package-lock.json
npm install
```
### Python Environment Issues
```bash
cd apps/api
rm -rf .venv
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
```
## Resources
- [FastAPI Documentation](https://fastapi.tiangolo.com/)
- [React Documentation](https://react.dev/)
- [SQLAlchemy Documentation](https://docs.sqlalchemy.org/)
- [Alembic Documentation](https://alembic.sqlalchemy.org/)
+365
View File
@@ -0,0 +1,365 @@
# Testing Guide
## Overview
Headquarter has comprehensive testing for both backend and frontend to ensure reliability and catch regressions.
## Backend Testing
### Test Framework
- **pytest**: Test runner
- **pytest-asyncio**: Async test support
- **httpx**: HTTP client for API tests
- **factory-boy**: Test data generation (recommended)
### Test Structure
```
apps/api/tests/
├── conftest.py # Shared fixtures
├── test_auth_api.py # Auth endpoint tests
├── test_auth_services.py # Auth service tests
├── test_models.py # Database model tests
├── test_projects_api.py # Project endpoint tests
├── test_git_repositories.py # Repository tests
└── ...
```
### Running Tests
```bash
cd apps/api
# Run all tests
pytest
# Run with coverage
pytest --cov=src --cov-report=html
# Run specific test file
pytest tests/test_auth_api.py
# Run specific test
pytest tests/test_auth_api.py::test_login_redirect
# Run with verbose output
pytest -v
# Run async tests
pytest --asyncio-mode=auto
```
### Writing Tests
**Unit Test Example**:
```python
import pytest
from src.utils.git_url_parser import extract_base_repo_url
def test_extract_github_url():
url = "https://github.com/user/repo/tree/main"
result = extract_base_repo_url(url)
assert result == "https://github.com/user/repo.git"
def test_valid_git_url_unchanged():
url = "https://github.com/user/repo.git"
result = extract_base_repo_url(url)
assert result == url
```
**Async Test Example**:
```python
import pytest
from httpx import AsyncClient
@pytest.mark.asyncio
async def test_get_projects(client: AsyncClient):
response = await client.get("/projects")
assert response.status_code == 200
assert isinstance(response.json(), list)
```
**API Integration Test**:
```python
@pytest.mark.asyncio
async def test_create_project(client: AsyncClient, auth_headers):
response = await client.post(
"/projects",
json={"name": "Test Project"},
headers=auth_headers
)
assert response.status_code == 201
data = response.json()
assert data["name"] == "Test Project"
assert "id" in data
```
### Test Fixtures
**conftest.py** provides:
```python
import pytest
from httpx import AsyncClient
@pytest.fixture
async def client():
from src.main import app
async with AsyncClient(app=app, base_url="http://test") as client:
yield client
@pytest.fixture
async def auth_headers(client):
# Login and return auth headers
response = await client.post("/auth/login")
# ... setup session
return {"Cookie": "session=..."}
```
### Test Database
Tests use a separate database:
```bash
# Test database URL (from .env)
TEST_DATABASE_URL=postgresql+asyncpg://headquarter:headquarter@localhost:5432/headquarter_test
# Run tests with test DB
TEST_DATABASE_URL=... pytest
```
## Frontend Testing
### Test Framework
- **Vitest**: Test runner
- **React Testing Library**: Component testing
- **jsdom**: DOM environment
### Test Structure
```
apps/web/src/
├── components/
│ └── protected-route.test.tsx
├── pages/
│ ├── dashboard.test.tsx
│ └── projects.test.tsx
└── test/
└── setup.ts # Test setup
```
### Running Tests
```bash
cd apps/web
# Run all tests
npm run test
# Run in watch mode
npm run test -- --watch
# Run with coverage
npm run test -- --coverage
# Run specific file
npm run test -- protected-route
```
### Writing Tests
**Component Test Example**:
```typescript
import { render, screen, fireEvent } from '@testing-library/react';
import { FileTree } from '../components/file-tree';
describe('FileTree', () => {
const mockFiles = [
{ name: 'src', type: 'directory', path: 'src' },
{ name: 'main.py', type: 'file', path: 'src/main.py' },
];
it('renders file list', () => {
render(<FileTree files={mockFiles} onFileClick={() => {}} />);
expect(screen.getByText('src')).toBeInTheDocument();
expect(screen.getByText('main.py')).toBeInTheDocument();
});
it('calls onFileClick when file clicked', () => {
const handleClick = vi.fn();
render(<FileTree files={mockFiles} onFileClick={handleClick} />);
fireEvent.click(screen.getByText('main.py'));
expect(handleClick).toHaveBeenCalledWith(mockFiles[1]);
});
});
```
**Async Test Example**:
```typescript
import { render, screen, waitFor } from '@testing-library/react';
import { ProjectsPage } from '../pages/projects';
describe('ProjectsPage', () => {
it('loads and displays projects', async () => {
render(<ProjectsPage />);
await waitFor(() => {
expect(screen.getByText('My Projects')).toBeInTheDocument();
});
});
});
```
## E2E Testing (Future)
### Playwright Setup
```bash
cd apps/web
npm install -D @playwright/test
npx playwright install
```
**Example E2E Test**:
```typescript
import { test, expect } from '@playwright/test';
test('user can login', async ({ page }) => {
await page.goto('http://localhost:5173');
await page.click('text=Login');
// Authentik login
await page.fill('[name="username"]', 'test@example.com');
await page.fill('[name="password"]', 'password');
await page.click('text=Sign In');
// Should redirect back to app
await expect(page).toHaveURL('http://localhost:5173/dashboard');
});
```
## Test Data
### Factories (Recommended)
Use factory-boy for test data:
```python
# tests/factories.py
import factory
from src.models.user import User
class UserFactory(factory.Factory):
class Meta:
model = User
email = factory.Faker('email')
name = factory.Faker('name')
authentik_id = factory.Faker('uuid4')
```
### Fixtures
```python
@pytest.fixture
async def test_user(db_session):
user = UserFactory()
db_session.add(user)
await db_session.commit()
return user
```
## Coverage Goals
| Component | Target Coverage |
|-----------|----------------|
| Backend API | 80%+ |
| Backend Services | 90%+ |
| Backend Models | 90%+ |
| Frontend Components | 70%+ |
| Frontend Pages | 60%+ |
## Continuous Integration
### GitHub Actions (Example)
```yaml
name: Tests
on: [push, pull_request]
jobs:
backend:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:15
env:
POSTGRES_PASSWORD: headquarter
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.11'
- run: pip install -e ".[dev]"
- run: pytest --cov=src --cov-report=xml
frontend:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '18'
- run: cd apps/web && npm ci
- run: cd apps/web && npm run test
```
## Best Practices
### Backend
1. **Test isolation**: Each test should be independent
2. **Use fixtures**: Don't repeat setup code
3. **Mock external services**: Authentik, git operations
4. **Test edge cases**: Empty lists, invalid inputs, errors
5. **Async properly**: Use `pytest.mark.asyncio` and async fixtures
### Frontend
1. **Test behavior, not implementation**: Check what user sees
2. **Use data-testid**: For stable selectors
3. **Mock API calls**: Don't hit real backend
4. **Test accessibility**: Use `screen.getByRole`
5. **Snapshot sparingly**: Only for complex UIs
## Debugging Tests
### Backend
```bash
# Run with debugger
pytest --pdb
# Run specific test with verbose
pytest -v -s test_file.py::test_name
# Show print statements
pytest -s
```
### Frontend
```bash
# Debug mode
npm run test -- --reporter=verbose
# Show browser (for E2E)
npx playwright test --headed
```
## Resources
- [pytest Documentation](https://docs.pytest.org/)
- [React Testing Library](https://testing-library.com/docs/react-testing-library/intro/)
- [Vitest Documentation](https://vitest.dev/)
- [Playwright Documentation](https://playwright.dev/)
+100
View File
@@ -0,0 +1,100 @@
# Authentication
## Overview
Headquarter uses OAuth2 authentication via Authentik. Users log in through their Authentik identity provider and receive a session cookie for authenticated access.
## How to Use
### Logging In
1. Navigate to the application
2. Click the **"Login"** button in the header
3. You will be redirected to **Authentik**
4. Enter your Authentik credentials
5. You will be redirected back to Headquarter, now logged in
### User Profile
After logging in, you can view your profile:
1. Click your **name** in the header
2. Select **"Profile"** from the dropdown
3. View and edit:
- Display name
- Email
- Avatar (upload or change)
### Logging Out
1. Click your **name** in the header
2. Select **"Logout"**
3. Your session will be cleared
4. You will be redirected to the login page
## Authentication Flow
```
User → Click Login → Authentik Login → OAuth2 Callback → Session Cookie → Authenticated
```
### Technical Details
**Session Management:**
- Uses signed session cookies
- Cookie is `HttpOnly` and `Secure` (in production)
- Session expires after configurable TTL (default: 24 hours)
**OAuth2 Flow:**
1. User clicks login
2. Backend redirects to Authentik authorize URL
3. User authenticates with Authentik
4. Authentik redirects back with authorization code
5. Backend exchanges code for access token
6. Backend fetches user info from Authentik
7. Backend creates/updates local user record
8. Backend sets session cookie
9. User is authenticated
## API Reference
### Endpoints
- `GET /auth/login` - Initiate login (redirects to Authentik)
- `GET /auth/callback` - OAuth2 callback
- `GET /auth/me` - Get current user
- `POST /auth/logout` - Logout (clears session)
See [Auth API](../api/auth.md) for detailed endpoint documentation.
## Configuration
| Variable | Description | Default |
|----------|-------------|---------|
| `AUTHENTIK_DOMAIN` | Authentik server domain | - |
| `AUTHENTIK_CLIENT_ID` | OAuth client ID | - |
| `AUTHENTIK_CLIENT_SECRET` | OAuth client secret | - |
| `AUTHENTIK_APPLICATION_SLUG` | Application slug for URLs | `headquarter-web` |
| `SESSION_SECRET` | Session cookie signing secret | `change-me` |
| `SESSION_TTL_HOURS` | Session duration | `24` |
## Troubleshooting
### Login Loop
**Issue:** After logging in, you're redirected back to login
**Solution:** Check that cookie domain matches your domain configuration
### "Invalid State" Error
**Issue:** Error about invalid state parameter
**Solution:** Clear cookies and try again. If persistent, check Authentik configuration.
### Session Expired
**Issue:** "Session expired" message
**Solution:** Log in again. Session duration is configurable via `SESSION_TTL_HOURS`.
## Related Features
- [User Settings](settings.md) - Configure user preferences
+106
View File
@@ -0,0 +1,106 @@
# Git History Visualization
## Overview
The Git History page provides a visual representation of a repository's commit history, including a branch graph and detailed commit information.
## How to Use
### Accessing History
1. Navigate to a **project workspace**
2. Select a **repository** from the dropdown
3. Click the **"History"** button on the repository card
Or:
1. Go to the **Repositories** page
2. Click **"History"** on any repository card
### History View Layout
```
┌─────────────────────────────────────────────┐
│ [Branch Selector ▼] [Repository Name] │
├─────────────────┬───────────────────────────┤
│ Commit List │ Commit Details │
│ │ │
│ ●─●─○─● │ Commit: abc1234 │
│ │ └─○ │ Author: John Doe │
│ │ │ Date: 2024-01-01 │
│ ● │ │
│ │ │ Message: │
│ ○ │ Fix bug in parser │
│ │ │
│ │ Stats: │
│ │ +15 -3 lines │
│ │ │
│ │ Diff: │
│ │ ```diff │
│ │ + new line │
│ │ - old line │
│ │ ``` │
└─────────────────┴───────────────────────────┘
```
### Commit Graph
The left panel shows:
- **Commit hashes** (abbreviated)
- **Branch/merge indicators** (lines connecting commits)
- **Commit messages** (first line)
- **Author** and **date**
- **Branch tags** (colored labels)
**Graph symbols:**
- `●` - Regular commit
- Branch lines show merge history
- Different colors indicate different branches
### Commit Details
Click any commit to see details:
**Metadata:**
- Full commit hash
- Author name and email
- Commit date and time
- Complete commit message
**Statistics:**
- Files changed
- Lines added (+)
- Lines removed (-)
**Diff:**
- Syntax-highlighted diff
- Added lines in green
- Removed lines in red
- Context lines for reference
### Branch Filtering
Use the **Branch Selector** to filter commits:
- Select **"All"** to see all branches
- Select a specific branch to see only that branch's history
- The graph updates to show only relevant commits
### Navigation
- **Click** a commit to view details
- **Scroll** the commit list to see older commits
- The view shows up to 10,000 commits (loads all at once)
## API Reference
### Endpoints
- `GET /projects/{id}/repositories/{id}/history` - Get commit history
- `GET /projects/{id}/repositories/{id}/commits/{hash}` - Get commit details
See [Repositories API](../api/repositories.md) for detailed endpoint documentation.
## Related Features
- [Git Repositories](repositories.md) - Manage repositories
- [Repository Workspace](workspace.md) - Browse files
+73
View File
@@ -0,0 +1,73 @@
# Project Management
## Overview
Projects are the top-level organizational unit in Headquarter. Each project can contain multiple git repositories and serves as a workspace for related development work.
## How to Use
### Creating a Project
1. Navigate to the **Projects** page from the sidebar
2. Click the **"New Project"** button
3. Enter a **name** for your project (required)
4. Optionally add a **description**
5. Click **"Create Project"**
### Viewing Projects
The Projects page displays all your projects in a card layout showing:
- Project name
- Description (if set)
- Creation date
- Associated repositories count
### Opening a Project Workspace
Click on any project card to open its **workspace**. The workspace is the default view for a project and shows:
- Repository file browser
- Branch selector
- File viewer
### Editing a Project
1. From the Projects page, click the **menu icon** (⋮) on a project card
2. Select **"Edit"**
3. Update the name or description
4. Click **"Save"**
### Deleting a Project
1. From the Projects page, click the **menu icon** (⋮) on a project card
2. Select **"Delete"**
3. Confirm the deletion
**Note:** Deleting a project also deletes all associated repositories and their data. This action cannot be undone.
## Project Workspace
The project workspace is the default view when you click on a project. It provides:
- **Repository Browser**: Navigate files and directories
- **File Viewer**: View file contents with syntax highlighting
- **Branch Management**: Switch between branches
- **Repository Switcher**: Switch between project repositories
See [Repository Workspace](workspace.md) for detailed documentation.
## API Reference
### Endpoints
- `GET /projects` - List all projects
- `POST /projects` - Create a new project
- `GET /projects/{id}` - Get project details
- `PUT /projects/{id}` - Update a project
- `DELETE /projects/{id}` - Delete a project
See [Projects API](../api/projects.md) for detailed endpoint documentation.
## Related Features
- [Repository Workspace](workspace.md) - Browse and edit repository files
- [Git Repositories](repositories.md) - Manage project repositories
+91
View File
@@ -0,0 +1,91 @@
# Git Repositories
## Overview
Git repositories are managed within projects. You can create bare repositories for new projects or clone existing repositories from remote sources.
## How to Use
### Creating a Repository
1. Navigate to a **project workspace** or the **Repositories** page
2. Click the **"New Repository"** button
3. Fill in the form:
- **Name**: Repository name (required)
- **Remote URL**: For cloning (optional)
- **Mirror Clone**: Toggle for mirror clones
4. Click **"Create Repository"**
#### Bare Repository (No Remote URL)
Creates a new bare git repository. Use this for:
- New projects
- Local-only repositories
- Repositories that will be pushed to later
#### Clone from Remote
Enter a git URL to clone from:
- `https://github.com/user/repo.git`
- `git@github.com:user/repo.git`
- `https://gitlab.com/user/repo.git`
**Smart URL Parsing:** If you paste a browser URL (like `https://github.com/user/repo/tree/main`), the system will automatically suggest the correct git URL.
#### Mirror Clone
Enable **"Mirror Clone"** to create a full mirror of a remote repository:
- Clones all branches and tags
- Sets up remote tracking
- Updates can be fetched later
### Smart URL Parsing
When pasting URLs, the system automatically detects browser URLs and suggests the correct git clone URL:
**Examples:**
- `https://github.com/user/repo/tree/main``https://github.com/user/repo.git`
- `https://github.com/user/repo/blob/main/README.md``https://github.com/user/repo.git`
- `https://gitlab.com/user/repo/-/tree/develop``https://gitlab.com/user/repo.git`
You can accept the suggestion or proceed with the original URL.
### Viewing Repositories
The Repositories page shows all repositories in a project:
- Repository name
- Clone URL
- Mirror status
- Creation date
### Repository Actions
Each repository card provides:
- **History**: View commit history and branch graph
- **Browse**: Open in workspace file browser
- **Delete**: Remove the repository
### Deleting a Repository
1. Click the **menu icon** (⋮) on a repository card
2. Select **"Delete"**
3. Confirm the deletion
**Note:** This permanently deletes the repository from disk. This action cannot be undone.
## API Reference
### Endpoints
- `GET /projects/{id}/repositories` - List repositories
- `POST /projects/{id}/repositories` - Create repository
- `DELETE /projects/{id}/repositories/{id}` - Delete repository
- `POST /projects/{id}/repositories/parse-url` - Parse and validate URL
See [Repositories API](../api/repositories.md) for detailed endpoint documentation.
## Related Features
- [Repository Workspace](workspace.md) - Browse repository files
- [Git History](git-history.md) - View commit history
- [Smart Git URL Parsing](repositories.md#smart-url-parsing) - Automatic URL correction
+56
View File
@@ -0,0 +1,56 @@
# User Settings
## Overview
User settings allow you to customize your Headquarter experience, including theme preferences and git identity.
## How to Use
### Accessing Settings
1. Click your **name** in the header
2. Select **"Settings"** from the dropdown
### Theme Selection
Choose your preferred theme:
- **System** - Follows your operating system preference
- **Light** - Light color scheme
- **Dark** - Dark color scheme
Changes are applied immediately and persist across sessions.
### Git Identity
Configure your git identity for commits made through the workspace:
- **Name**: Your display name for git commits
- **Email**: Your email for git commits
This information is used when you make quick edits in the repository workspace.
### Default Editor
Choose your preferred editor for quick edits:
- Options depend on available tool types
- Used when opening files for editing
## Configuration
Settings are stored per-user in the database and persist across sessions.
## API Reference
### Endpoints
- `GET /users/me/config` - Get user settings
- `PATCH /users/me/config` - Update user settings
See [Users API](../api/users.md) for detailed endpoint documentation.
## Related Features
- [Authentication](auth.md) - User authentication
- [Repository Workspace](workspace.md) - Edit files with git identity
+70
View File
@@ -0,0 +1,70 @@
# SSH Key Management
## Overview
Manage SSH key pairs for authenticating with git remotes. Keys are generated and stored securely, with the private key encrypted.
## How to Use
### Generating a Key Pair
1. Navigate to **Settings****SSH Keys**
2. Click **"Generate New Key"**
3. Enter a **name** for the key (e.g., "GitHub Work Account")
4. Click **"Generate"**
The system will:
- Generate an Ed25519 key pair
- Encrypt the private key
- Store both keys securely
- Display the public key
### Copying Public Key
1. Find the key in the list
2. Click the **"Copy"** button next to the public key
3. Paste into your git host (GitHub, GitLab, etc.)
### Adding to Git Hosts
#### GitHub
1. Go to Settings → SSH and GPG keys
2. Click "New SSH key"
3. Paste the public key
4. Give it a title
5. Click "Add SSH key"
#### GitLab
1. Go to Preferences → SSH Keys
2. Paste the public key
3. Set expiration (optional)
4. Click "Add key"
### Deleting Keys
1. Find the key in the list
2. Click the **"Delete"** button
3. Confirm deletion
**Note:** Deleting a key removes both public and private keys. This cannot be undone.
## Security
- **Ed25519 algorithm**: Modern, secure key type
- **Encrypted storage**: Private keys are encrypted at rest
- **No export**: Private keys cannot be exported
- **One-way generation**: Keys are generated server-side, never transmitted
## API Reference
### Endpoints
- `GET /ssh-keys` - List SSH keys
- `POST /ssh-keys` - Generate new key
- `DELETE /ssh-keys/{id}` - Delete key
See [SSH Keys API](../api/ssh-keys.md) for detailed endpoint documentation.
## Related Features
- [Git Repositories](repositories.md) - Use SSH keys for repository access
+104
View File
@@ -0,0 +1,104 @@
# Tool Types
## Overview
Tool types define development tools that can be spawned for projects. Headquarter includes built-in types and supports creating custom tool types with Docker Compose templates.
## How to Use
### Built-in Tool Types
Headquarter includes these built-in tool types:
#### VS Code Server
- **Image**: `lscr.io/linuxserver/code-server:latest`
- **Purpose**: Full VS Code in the browser
- **Features**: Extensions, terminal, debugging
- **Access**: Port 8443
#### Jupyter Notebook
- **Image**: `jupyter/scipy-notebook:latest`
- **Purpose**: Interactive Python development
- **Features**: Notebooks, data visualization
- **Access**: Port 8888
### Managing Tool Types
#### Viewing Tool Types
1. Navigate to **Settings****Tool Types**
2. See a list of all tool types
3. Built-in types are marked with a badge
#### Creating Custom Tool Types
1. Click **"New Tool Type"**
2. Fill in the form:
- **Name**: Unique identifier (e.g., `my-custom-tool`)
- **Display Name**: Human-readable name
- **Description**: What this tool does
- **Compose Template**: Docker Compose YAML
3. Click **"Create"**
#### Compose Template Format
The compose template uses Docker Compose syntax with template variables:
```yaml
version: "3.8"
services:
my-tool:
image: my-image:latest
container_name: {{TOOL_NAME}}
environment:
- VARIABLE=value
volumes:
- {{REPO_PATH}}:/workspace
ports:
- "8080:8080"
```
**Required Variables:**
- `{{TOOL_NAME}}` - Unique name for the container
- `{{REPO_PATH}}` - Path to the repository
#### Validating Templates
The system validates templates:
- Must be valid YAML
- Must contain a `services` section
- Must use all required variables
- Invalid templates will be rejected
#### Editing Tool Types
1. Find the tool type in the list
2. Click **"Edit"**
3. Update fields
4. Click **"Save"**
**Note:** Built-in tool types cannot be modified or deleted.
#### Deleting Tool Types
1. Find the tool type in the list
2. Click **"Delete"**
3. Confirm deletion
**Note:** Built-in tool types cannot be deleted.
## API Reference
### Endpoints
- `GET /tool-types` - List tool types
- `POST /tool-types` - Create tool type
- `GET /tool-types/{id}` - Get tool type details
- `PUT /tool-types/{id}` - Update tool type
- `DELETE /tool-types/{id}` - Delete tool type
See [Tool Types API](../api/tool-types.md) for detailed endpoint documentation.
## Related Features
- [Tool Instances](tool-instances.md) - Spawn and manage tool instances
+101
View File
@@ -0,0 +1,101 @@
# Repository Workspace
## Overview
The Repository Workspace is the default view when you open a project. It provides a file browser and viewer for exploring repository contents, similar to GitHub or GitLab's file browser.
## How to Use
### Workspace Layout
```
┌─────────────────────────────────────────────┐
│ [Repo Selector ▼] [Branch Selector ▼] │
├─────────────────┬───────────────────────────┤
│ File Tree │ Main Content │
│ │ │
│ 📁 src/ │ Breadcrumbs: src > main │
│ 📁 tests/ │ │
│ 📄 README.md │ [Edit] [History] │
│ 📄 .gitignore │ │
│ │ File content here... │
│ │ │
└─────────────────┴───────────────────────────┘
```
### Repository Selection
If a project has multiple repositories:
1. Use the **Repository Selector** dropdown at the top
2. Choose the repository you want to browse
3. The file tree updates automatically
### Branch Selection
1. Use the **Branch Selector** dropdown
2. Select a branch from the list
3. The file tree refreshes to show that branch's contents
### Browsing Files
**Navigate directories:**
- Click on a folder (📁) to expand it
- Click again to collapse
- The file tree shows the full directory structure
**View file contents:**
- Click on a file (📄) to open it
- The file viewer shows:
- File path breadcrumbs
- File content with syntax highlighting
- File metadata (size, last commit)
### File Viewer
The file viewer supports:
- **Syntax highlighting** for common languages
- **Line numbers**
- **Breadcrumb navigation** (click any path segment)
### Quick Editing
For small changes:
1. Open a file in the viewer
2. Click the **"Edit"** button
3. Make your changes in the text area
4. Enter a **commit message**
5. Click **"Save"**
The system will:
- Commit the changes to the current branch
- Show the new commit hash
- Refresh the file view
**Note:** This creates a real git commit. Make sure your commit message describes the change.
### Binary Files
Binary files (images, compiled code, etc.) cannot be viewed or edited in the workspace. The viewer will show "Binary file - cannot display."
## Keyboard Navigation
- **Click** folder to expand/collapse
- **Click** file to view
- **Click** breadcrumb to navigate up
## API Reference
### Endpoints
- `GET /projects/{id}/repositories/{id}/files` - List files in directory
- `GET /projects/{id}/repositories/{id}/files/content` - Get file content
- `POST /projects/{id}/repositories/{id}/files/content` - Update file
- `GET /projects/{id}/repositories/{id}/branches` - List branches
See [Repositories API](../api/repositories.md) for detailed endpoint documentation.
## Related Features
- [Git Repositories](repositories.md) - Manage repositories
- [Git History](git-history.md) - View commit history
+97
View File
@@ -0,0 +1,97 @@
# API Endpoint Documentation Template
Use this template when documenting API endpoints.
## Endpoint Group Name
Brief description of what this group of endpoints does.
### Authentication
Describe authentication requirements (e.g., "Requires valid session cookie").
---
## METHOD /path/to/endpoint
**Description:** What this endpoint does.
### Request
#### Headers
| Header | Required | Description |
|--------|----------|-------------|
| `Authorization` | Yes/No | Description |
| `Content-Type` | Yes/No | Description |
#### Query Parameters
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `param_name` | `string` | Yes/No | Description |
#### Request Body
```json
{
"field_name": "string",
"field_name": "number"
}
```
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `field_name` | `string` | Yes/No | Description |
### Response
#### Success (200 OK)
```json
{
"field_name": "value",
"field_name": "value"
}
```
#### Error Responses
**400 Bad Request**
```json
{
"detail": "Error message"
}
```
**401 Unauthorized**
```json
{
"detail": "Authentication required"
}
```
### Example
#### Request
```bash
curl -X METHOD http://api.example.com/path/to/endpoint \
-H "Content-Type: application/json" \
-H "Cookie: session=your_session_cookie" \
-d '{
"field_name": "value"
}'
```
#### Response
```json
{
"field_name": "value"
}
```
---
## METHOD /path/to/another/endpoint
[Repeat the same structure for each endpoint]
+69
View File
@@ -0,0 +1,69 @@
# Architecture Documentation Template
Use this template when documenting system architecture.
## System/Component Name
## Overview
Provide a high-level description of this system or component.
## Architecture Diagram
```
[ASCII or Mermaid diagram showing components and relationships]
```
## Components
### Component 1
**Purpose:** What this component does
**Responsibilities:**
- Responsibility 1
- Responsibility 2
**Dependencies:**
- Dependency 1
- Dependency 2
**Key Files:**
- `path/to/file1.py`
- `path/to/file2.py`
### Component 2
[Repeat for each component]
## Data Flow
Describe how data flows through the system.
```
[Step 1] → [Step 2] → [Step 3]
```
## Technology Stack
| Component | Technology | Purpose |
|-----------|-----------|---------|
| Component 1 | Technology 1 | Purpose |
| Component 2 | Technology 2 | Purpose |
## Configuration
Describe relevant configuration options.
## Security Considerations
List security considerations for this architecture.
## Scaling Considerations
Describe how this scales (or doesn't).
## Related Documentation
- [Link to related doc 1](link.md)
- [Link to related doc 2](link.md)
+65
View File
@@ -0,0 +1,65 @@
# Feature Documentation Template
Use this template when documenting a new feature.
## Feature Name
## Overview
Provide a 1-2 sentence description of what this feature does and why it exists.
## How to Use
### Prerequisites
List any prerequisites (e.g., must be logged in, must have project created).
### Step-by-Step Guide
1. **Step 1**: Description of first step
- Details
- Screenshots if applicable
2. **Step 2**: Description of second step
- Details
3. **Step 3**: Description of third step
- Details
## Screenshots
Include screenshots or diagrams if they help understanding.
## API Reference
List related API endpoints with links to API docs.
### Endpoints
- `METHOD /endpoint/path` - Brief description
- `METHOD /endpoint/path` - Brief description
## Configuration
List any relevant configuration options (environment variables, settings).
| Option | Description | Default |
|--------|-------------|---------|
| `VAR_NAME` | What this controls | `default_value` |
## Troubleshooting
### Common Issues
**Issue**: Description of problem
**Solution**: How to fix it
## Related Features
- [Feature Name](link.md) - How this relates
- [Feature Name](link.md) - How this relates
## See Also
- [API Documentation](../api/feature.md)
- [Architecture Documentation](../architecture/feature.md)