Files
headquarter/docs/development.md
T
Fusion 2c52b1634f docs(FN-011): complete Step 8 — update architecture and development docs
Fusion-Task-Id: FN-011
Fusion-Task-Lineage: 4a9aca6f-9d91-43aa-8d2a-d59657c1541a
2026-05-14 08:37:11 +02:00

4.5 KiB

Development Guide

Prerequisites

  • Node.js ≥ 20 and pnpm ≥ 9
  • Python ≥ 3.11 with venv support
  • Docker and Docker Compose (for local services)

Installation

# Install Node dependencies and Python virtualenv + packages
make install

# Or manually:
pnpm install
cd apps/api && python3 -m venv .venv && .venv/bin/pip install -e ".[dev]"

Environment Setup

Copy the root environment example and fill in local values:

cp .env.example .env

Copy the frontend environment example:

cp apps/web/.env.example apps/web/.env

Running Locally

Frontend only

cd apps/web
pnpm dev        # Vite dev server on http://localhost:5173

Backend only

cd apps/api
.venv/bin/uvicorn app.main:app --reload --port 8000

Both (via root script)

pnpm dev        # Runs frontend and backend in parallel

With Docker Compose

docker compose up --build -d

Alembic Migrations

Generate a new migration after modifying models:

cd apps/api
.venv/bin/alembic revision --autogenerate -m "description"

Apply migrations:

cd apps/api
.venv/bin/alembic upgrade head

Downgrade one revision:

cd apps/api
.venv/bin/alembic downgrade -1

Or use the Makefile targets:

cd apps/api
make revision msg="description"
make upgrade
make downgrade

Testing

Frontend

pnpm --filter @headquarter/web test

Uses Vitest + Testing Library + jsdom.

Backend

pnpm --filter @headquarter/api test

Or directly with pytest:

cd apps/api && .venv/bin/pytest

All tests

make test
# or
pnpm test

CI / Testing

A GitHub Actions workflow (.github/workflows/ci.yml) runs on every push and pull request to main. It executes two jobs in parallel:

  • web-ci — checks out the repo, installs Node.js ≥ 20 and pnpm, then runs lint, typecheck, and test for @headquarter/web.
  • api-ci — checks out the repo, sets up Python 3.11, installs API dev dependencies (pytest, ruff, mypy, httpx), starts a PostgreSQL service container, then runs ruff check, mypy, and pytest for the API.

The workflow reports pass/fail status directly on pull requests as required status checks. All commands must pass before a PR can be merged.

Linting and Type Checking

Frontend

pnpm --filter @headquarter/web lint
pnpm --filter @headquarter/web typecheck

Backend

pnpm --filter @headquarter/api lint
pnpm --filter @headquarter/api typecheck

All

make lint
make typecheck

Building

make build
# or
pnpm build

Project Layout

├── apps/
│   ├── web/          # Vite React TypeScript frontend
│   └── api/          # FastAPI Python backend
├── packages/         # Shared packages (future)
├── docs/             # Documentation
├── deploy/           # Deployment skeleton files
├── docker-compose.yml
└── package.json      # Root monorepo scripts

Conventions

  • Frontend: React functional components, TypeScript strict mode, ESLint + Ruff-like rules.
  • Backend: FastAPI, Pydantic settings, pytest, ruff, mypy.
  • Commits: Conventional commits with task ID prefix, e.g. feat(FN-002): description.

Git Abstraction

The app/git/ package in the backend provides provider-independent Git orchestration. It is split into two layers so that remote provider API logic and local CLI operations evolve independently:

Module Responsibility
types Enumerations (ProviderKind, CredentialKind, ConnectionStatus, SshKeyStatus)
provider Abstract GitProvider — remote operations (validate_connection, list_repositories, create_deploy_key, …)
credentials GitCredential / AccessTokenCredential models and CredentialStorage ABC
ssh_key SshKeyPair model and SshKeyLifecycle (Ed25519 generation via cryptography)
connection RepositoryConnection ORM mapping and ConnectionManager orchestration
operations Abstract GitOperations and concrete LocalGitOperations (subprocess-based get_status)

Security rules for the package:

  • Credential models store only encrypted_payload — no plaintext token or private_key fields.
  • SSH private keys are encrypted before storage; the field uses repr=False.
  • Real encryption of the payload is deferred to FN-009; the current placeholder is base64-only.