8.2 KiB
Headquarter Architecture
Canonical architecture specification for the hosted workspace and tool-orchestration platform. Decisions in this document override ad-hoc choices in implementation tasks.
1. Overview & Goals
Headquarter is a hosted control plane where authenticated users create projects, connect Git repositories, and spawn containerized tools (RunFusion, code-server, and future tools). The platform is manifest-driven and provider-abstracted so new tools, Git providers, runtimes, and access providers can be added without rewriting core orchestration logic.
MVP scope: Single-user projects, Authentik OIDC auth, Docker runtime, Traefik subdomain routing, Portainer-managed Docker Compose deployment.
2. Domain Model
User ──< Project ──< Repository
└──< ToolInstance
Tool (manifest-driven, global registry)
- User: Authentik-managed identity. MVP assumes individual users; schema leaves room for teams/shared projects later.
- Project: Owned by a user. Contains repositories and spawned tool instances.
- Repository: Git-backed workspace. Clone, fetch, and push via provider-independent adapters.
- Tool: Manifest-driven definition (image, ports, mounts, env, health checks, routing rules). Defined in FN-003.
- ToolInstance: A running container spawned from a Tool manifest for a specific project. Receives workspace mounts, config mounts, secrets, and Traefik routing labels.
3. Provider Interfaces
The backend must define provider contracts before implementing any concrete adapter.
3.1 GitProvider
class GitProvider(Protocol):
def clone(self, repo_url: str, dest: Path, credentials: GitCredentials) -> None: ...
def fetch(self, repo_path: Path, credentials: GitCredentials) -> None: ...
def push(self, repo_path: Path, credentials: GitCredentials) -> None: ...
- Adapters: GitHub, GitLab, Gitea, Forgejo, etc.
- Credentials: generated SSH keys (per-repository) or access tokens.
- SSH keys must be scoped per repository connection for clean revocation.
3.2 RuntimeProvider
class RuntimeProvider(Protocol):
def spawn(self, manifest: ToolManifest, project: Project, config: SpawnConfig) -> ToolInstance: ...
def stop(self, instance: ToolInstance) -> None: ...
def health(self, instance: ToolInstance) -> HealthStatus: ...
- MVP adapter: Docker Compose service generation + Docker API.
- Future adapters: Kubernetes, Nomad, etc.
3.3 AccessProvider
class AccessProvider(Protocol):
def route(self, instance: ToolInstance, domain: str) -> RoutingConfig: ...
- MVP adapter: Traefik labels on Docker containers.
- Future adapter: Cloudflare Tunnel, etc.
4. Deployment Architecture
4.1 MVP Target
- Orchestration: Portainer-managed Docker Compose stack.
- Reverse Proxy: Existing Traefik instance (external to the app stack).
- Network: Shared Traefik Docker network; app stack attaches to it.
- Certificate Resolution: Let's Encrypt or internal CA via Traefik cert resolver.
4.2 Subdomain Routing
Path-based routing is avoided because many tools expect to run at /.
Pattern:
https://{tool}-{project}-{user}.{tool_domain}
Examples:
https://runfusion-myapp-alice.tools.example.com
https://code-myapp-alice.tools.example.com
4.3 Compose Skeleton
docker-compose.yml: local development (backend, frontend, PostgreSQL).docker-compose.traefik.yml: deployment overlay with Traefik labels and external network.- Environment-driven; no secrets committed to repository.
5. Security Boundaries
5.1 Authentication
- Authentik OIDC for user login.
- FastAPI backend validates JWT/id tokens at API boundaries.
- Frontend stores tokens securely (httpOnly cookie or secure storage pattern).
5.2 Secrets
- Never treat secrets as plaintext config.
- Support encrypted storage at rest and runtime injection as:
- Environment variables
- Mounted secret files
- Encryption key is an environment secret (
SECRET_ENCRYPTION_KEY).
5.3 SSH Keys
- Generated per repository connection.
- Stored encrypted.
- Injected into tool containers at runtime for Git operations.
5.4 Container Isolation
- Each tool instance runs in its own container.
- Resource limits declared in tool manifest.
- Workspace and config mounts are scoped to user/project.
6. Data & Storage
6.1 Database
- PostgreSQL for relational data (users, projects, repositories, tool instances, manifests).
- Schema migrations managed by backend (Alembic or equivalent).
6.2 Filesystem Layout (Conceptual)
/data/
users/{userId}/tool-configs/{toolId}/
projects/{projectId}/repo/
projects/{projectId}/tool-configs/{toolId}/
- Repository workspace storage: Docker volumes or local bind mounts.
- Tool config storage: persistent host mounts, separate from repository workspaces.
- Config scopes: global default → user-level → project-level → tool-instance override.
7. Tool Manifest & Orchestration
Tools are defined by manifests (FN-003) that declare:
- Runtime image / image tag
- Node/npm version expectations (for executable environments)
- Bootstrap / install commands
- Command execution needs
- Workspace mounts
- Config mounts
- Environment variables
- Secrets
- Ports
- Health checks
- Resource limits
- Traefik routing needs (subdomain pattern, middleware)
The platform reads manifests and generates:
- Docker Compose service definitions
- Traefik labels for routing
- Volume mounts for workspace and config
- Secret injection at runtime
8. MVP Phases
| Phase | Task | Deliverable |
|---|---|---|
| Foundation | FN-002 | Monorepo scaffold, build/test/lint pipelines |
| Registry | FN-003 | Manifest schema, RunFusion and code-server manifests |
| Backend | FN-004 | FastAPI app, domain models, API endpoints, DB migrations |
| Frontend | FN-005 | Auth-ready shell, navigation, placeholder screens |
| Deployment | FN-006 | Docker Compose overlays, Traefik labels, Portainer config |
| Git Model | FN-007 | Provider interface, SSH key generation, credential storage |
| RunFusion POC | FN-008 | Executable environment proof of concept |
| Secrets & Config | FN-009 | Encrypted secrets, persistent config mounts |
| code-server Spawn | FN-010 | code-server manifest, spawn script, runtime integration |
9. Extension Points
- New Git providers: Implement
GitProviderprotocol. - New tools: Add a manifest to the registry (no code changes required for standard containers).
- New runtimes: Implement
RuntimeProviderprotocol. - New access providers: Implement
AccessProviderprotocol. - Teams/organizations: Add
OrganizationandProjectMemberentities later.
10. Environment Assumptions
Required environment variables (no defaults in production):
APP_NAME=
ROOT_DOMAIN=
TOOL_DOMAIN=
API_URL=
TRAEFIK_NETWORK=
TRAEFIK_ENTRYPOINT=
TRAEFIK_CERT_RESOLVER=
AUTHENTIK_ISSUER_URL=
AUTHENTIK_CLIENT_ID=
AUTHENTIK_CLIENT_SECRET=
DATABASE_URL=
SECRET_ENCRYPTION_KEY=
Local development uses .env.example and safe defaults.
11. Technology Boundaries
| Layer | Choice | Migration Path |
|---|---|---|
| Frontend | React + Vite | Next.js, Vue, etc. if needed |
| Backend | FastAPI | Any ASGI framework |
| Database | PostgreSQL | Managed Postgres, CockroachDB |
| Runtime | Docker Compose | Kubernetes, Nomad |
| Access | Traefik | Cloudflare Tunnel, custom proxy |
| Auth | Authentik OIDC | Any OIDC provider |
12. Acceptance Criteria for Architecture Compliance
Any implementation task must:
- Respect provider interfaces (no hardcoded GitHub/Traefik logic in core orchestration).
- Keep secrets out of committed files and plaintext logs.
- Use environment variables for deployment-specific values.
- Leave schema room for multi-user teams without rewriting ownership models.
- Support adding a new tool via manifest + registry entry alone (no new backend code for standard containers).
13. Deferred Decisions
- Multi-tenancy: MVP is single-tenant deployment. Multi-tenant routing and isolation are future concerns.
- High availability: No replicas or load balancing in MVP.
- Backup strategy: Out of MVP scope; rely on host-level volume backups.
- Rate limiting: Not in MVP; add at Traefik or API gateway layer later.