Files
headquarter/apps/api
Fusion f37813a317 revert: remove ResizeObserver and stty-on-every-resize to fix infinite loop
The ResizeObserver detected size changes caused by the stty command
output appearing in the terminal, creating an infinite resize loop:
1. Resize detected -> fit() -> send resize to backend
2. Backend sends stty command through PTY
3. stty text appears in terminal output
4. ResizeObserver detects content height change
5. fit() calculates new rows -> send resize
6. Loop continues forever

Reverted to:
- Window resize event instead of ResizeObserver
- stty command only sent once on first resize

This means the container shell stays at the initial size and won't
dynamically resize when the browser window changes, but prevents
the infinite loop.
2026-05-24 16:54:05 +02:00
..

Headquarter API

The backend API for Headquarter - a self-hosted platform for managing projects, git repositories, and development tools.

Overview

Built with FastAPI and SQLAlchemy (async), using PostgreSQL for data storage and Docker for tool instance management.

Tech Stack

  • Framework: FastAPI (Python 3.12+)
  • Database: PostgreSQL 15+ with asyncpg
  • ORM: SQLAlchemy 2.0 (async)
  • Auth: OAuth2 via Authentik with session cookies
  • Migrations: Alembic
  • Tools: Docker Compose for instance management

Quick Start

Prerequisites

  • Python 3.12+
  • PostgreSQL 15+ running locally
  • Docker (for tool instances)

Setup

cd apps/api

# Create virtual environment
python -m venv .venv
source .venv/bin/activate

# Install dependencies
pip install -e ".[dev]"

# Set up database
# Ensure PostgreSQL is running with a 'headquarter' database

# Run migrations
alembic upgrade head

# Start development server
uvicorn src.main:app --reload --port 8000

The API will be available at http://localhost:8000.

Interactive Documentation

Once running, visit:

Environment Variables

Variable Required Default Description
DATABASE_URL Yes - PostgreSQL connection string
API_BASE_URL Yes - Public API URL (e.g., https://api.example.com)
AUTHENTIK_DOMAIN Yes - Authentik server domain
AUTHENTIK_CLIENT_ID Yes - OAuth2 client ID
AUTHENTIK_CLIENT_SECRET Yes - OAuth2 client secret
AUTHENTIK_APPLICATION_SLUG Yes - Authentik application slug
WEB_BASE_URL Yes - Public frontend URL
SESSION_SECRET Yes - Secret for session cookie signing
COOKIE_DOMAIN No - Cookie domain (e.g., .example.com)
UPLOAD_DIR No ./uploads Directory for file uploads
REPO_BASE_PATH No ./repositories Base path for git repositories
INSTANCES_BASE_PATH No ./instances Base path for tool instances
LOG_LEVEL No INFO Logging level

Development

Running Tests

# Run all tests
pytest

# Run specific test category
pytest -m unit          # Unit tests (no DB)
pytest -m integration   # Integration tests (requires DB)

# Run with coverage
pytest --cov=src --cov-report=html

Code Quality

# Format code
ruff format src tests

# Lint
ruff check src tests

# Type check
mypy src

Database Migrations

# Create new migration
alembic revision --autogenerate -m "description"

# Apply migrations
alembic upgrade head

# Rollback one migration
alembic downgrade -1

# Show current revision
alembic current

Architecture

Directory Structure

src/
├── api/              # API endpoint routers
│   ├── auth.py       # OAuth2 authentication
│   ├── dashboard.py  # Dashboard summary
│   ├── git_repositories.py  # Git repo management
│   ├── health.py     # Health checks
│   ├── projects.py   # Project CRUD
│   ├── ssh_keys.py   # SSH key management
│   ├── terminal.py   # WebSocket terminal
│   ├── tool_instances.py  # Tool instance management
│   ├── tool_types.py # Tool type definitions
│   ├── user_config.py # User preferences
│   └── users.py      # User profile
├── auth/             # Authentication logic
│   ├── cookies.py    # Cookie utilities
│   ├── dependencies.py # Auth dependencies
│   ├── oidc.py       # OpenID Connect
│   └── session.py    # Session management
├── config.py         # Application settings
├── database.py       # Database setup
├── main.py           # FastAPI application
├── models/           # SQLAlchemy models
├── schemas/          # Pydantic schemas
├── services/         # Business logic
│   ├── docker.py     # Docker Compose management
│   ├── terminal_manager.py  # Terminal sessions
│   └── terminal_session.py  # Terminal I/O
└── utils/            # Utilities
    ├── git_control.py      # Git operations
    ├── git_files.py        # File operations
    ├── git_history.py      # History extraction
    └── git_url_parser.py   # URL parsing

Authentication Flow

  1. User clicks "Login" → redirects to Authentik OAuth
  2. Authentik redirects back with authorization code
  3. API exchanges code for tokens and fetches user info
  4. API creates session cookie (HMAC-signed, httpOnly)
  5. Frontend stores nothing - cookie sent automatically
  6. Subsequent requests include cookie for authentication

Data Flow

Client → FastAPI Router → Auth Dependency → Service Layer → Database
                ↓
         Pydantic Models (validation)
                ↓
         SQLAlchemy Models (ORM)
                ↓
         PostgreSQL (storage)

API Endpoints

Authentication

  • GET /auth/login - Initiate OAuth login
  • GET /auth/callback - OAuth callback
  • GET /auth/me - Get current user
  • POST /auth/logout - Logout

Projects

  • GET /projects - List projects
  • POST /projects - Create project
  • GET /projects/{id} - Get project
  • PUT /projects/{id} - Update project
  • DELETE /projects/{id} - Delete project

Git Repositories

  • GET /projects/{id}/repositories - List repositories
  • POST /projects/{id}/repositories - Create repository
  • GET /projects/{id}/repositories/{id} - Get repository
  • DELETE /projects/{id}/repositories/{id} - Delete repository
  • GET /projects/{id}/repositories/{id}/files - List files
  • 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
  • GET /projects/{id}/repositories/{id}/history - Commit history
  • GET /projects/{id}/repositories/{id}/commits/{hash} - Commit detail

Tool Types

  • GET /tool-types - List tool types
  • POST /tool-types - Create tool type
  • GET /tool-types/{id} - Get tool type
  • PUT /tool-types/{id} - Update tool type
  • DELETE /tool-types/{id} - Delete tool type

Tool Instances

  • GET /tool-instances - List instances
  • POST /tool-instances - Create instance
  • GET /tool-instances/{id} - Get instance
  • POST /tool-instances/{id}/start - Start instance
  • POST /tool-instances/{id}/stop - Stop instance
  • POST /tool-instances/{id}/restart - Restart instance
  • DELETE /tool-instances/{id} - Delete instance
  • GET /tool-instances/{id}/logs - Get logs

Terminal

  • WS /ws/tool-instances/{id}/terminal - WebSocket terminal

Users

  • GET /users/me - Get profile
  • PUT /users/me - Update profile
  • POST /users/me/avatar - Upload avatar
  • GET /users/me/config - Get config
  • PATCH /users/me/config - Update config

SSH Keys

  • GET /ssh-keys - List keys
  • POST /ssh-keys - Create key
  • DELETE /ssh-keys/{id} - Delete key

Health

  • GET /health - System health
  • GET /health/db - Database health

Deployment

See the deployment documentation for Docker and Traefik setup.

Contributing

  1. Follow PEP 8 style guide
  2. Add tests for new endpoints
  3. Update documentation
  4. Run quality gates before committing