- Update architecture.md with spawn service and auth proxy sections - Update deployment.md with production stack details - Update development.md with spawn workflow documentation - Update mvp-scope.md, project-brief.md, tool-manifest-spec.md - Update conversation-handoff.md with current status - Replace all RunFusion references with OpenCode
7.1 KiB
Development Guide
Prerequisites
- Node.js ≥ 20 and pnpm ≥ 9
- Python ≥ 3.11 with
venvsupport - 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
Frontend Authentication (OIDC)
The frontend uses OpenID Connect (OIDC) with PKCE for authentication. Configure the following environment variables in apps/web/.env:
| Variable | Description | Example |
|---|---|---|
VITE_API_URL |
Backend API base URL | http://localhost:8000 |
VITE_OIDC_ISSUER |
OIDC provider issuer URL | https://authentik.example.com/application/o/headquarter |
VITE_OIDC_CLIENT_ID |
OIDC client ID | headquarter-web |
VITE_OIDC_REDIRECT_URI |
Post-login redirect URL | http://localhost:5173/callback |
Authentication Flow:
- User clicks login → redirected to OIDC provider authorize endpoint
- User authenticates with provider
- Provider redirects to
/callbackwith authorization code - Frontend exchanges code for access token (PKCE)
- Token stored in
localStorage, user info fetched from/api/v1/users/me
Logout:
- Clears local token
- Redirects to login page
- User can re-authenticate via OIDC flow
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, andtestfor@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 runsruff check,mypy, andpytestfor 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 plaintexttokenorprivate_keyfields. - 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.
Tool Spawn Workflow
The platform supports spawning development tools (e.g., code-server) as Docker containers via Docker Compose.
Architecture
-
Tool Manifest (
apps/api/app/tools/manifests/*.yml):- Defines Docker image, ports, volumes, environment variables, health checks
- Loaded into in-memory registry at application startup
-
Spawn Service (
apps/api/app/services/spawn.py):- Generates Docker Compose service definitions from manifests
- Handles container lifecycle: spawn, stop, status polling
- Integrates Traefik label generation for subdomain routing
-
API Endpoints (
apps/api/app/routers/tool_instances.py):POST /projects/{id}/tool-instances— Spawn a new tool instancePOST /projects/{id}/tool-instances/{id}/stop— Stop a running instancePOST /projects/{id}/tool-instances/{id}/start— Restart a stopped instanceGET /projects/{id}/tool-instances/{id}/status— Get container status
-
Frontend UI:
/tools/spawn— Form to select tool, project, and spawn/projects/{id}/instances/{id}— Instance detail with status, controls, and "Open Tool" link
Auth Proxy
Spawned tools are protected behind Traefik forwardAuth middleware:
- Traefik forwards requests to
/api/v1/auth/validatefor session validation - code-server built-in auth is disabled (
PASSWORD: "") - Only authenticated platform users can access spawned tools
Local Development
Ensure Docker socket is accessible and the tools network exists:
docker network create tools # One-time setup
Spawned containers use the tools network for Traefik routing.