Files
headquarter/apps/api
alex 2e156fc534 fix: inject backend network into compose file instead of docker network connect
The post-creation 'docker network connect' was failing silently for
unknown reasons (race condition, container state, or Docker internals).

Instead of fighting with this, we now inject the backend network directly
into the compose file before 'docker compose up'. Docker Compose then
attaches the container to the network atomically during creation.

- apps/api/src/api/tool_instances.py: new _ensure_backend_network_in_compose()
  adds 'networks: [backend_name]' to the service and declares the network
  as external at the top level
- apps/api/src/api/tool_instances.py: call _ensure_backend_network_in_compose()
  in both start_instance and restart_instance, right after
  _ensure_container_name_in_compose()
- apps/api/src/api/tool_instances.py: removed connect_container_to_network
  import and call entirely
- apps/api/src/api/tool_instances.py: import get_backend_network_name from
  docker module for use in the new helper

Quality gates: ruff clean
2026-05-30 14:12:22 +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