feat: implement docker infrastructure (US-001)

- Add docker-compose.yml with postgres, redis, api, and web services
- Add multi-stage Dockerfile for API (Python 3.11)
- Add multi-stage Dockerfile for web (Node.js 20 + nginx)
- Add Makefile with common development commands
- Add .env.example with all required environment variables
- Add placeholder pyproject.toml and package.json for builds
- Configure health checks for all services
- Setup persistent volumes for postgres, redis, and repos
- Run services as non-root users
This commit is contained in:
2026-05-16 17:44:39 +00:00
parent 212d072417
commit e7819bfc82
246 changed files with 3625 additions and 17311 deletions
+94
View File
@@ -0,0 +1,94 @@
# API Documentation Specification
## Purpose
Provide comprehensive API documentation and health monitoring endpoints.
## Requirements
### Requirement: OpenAPI/Swagger Documentation
The system SHALL auto-generate API documentation.
#### Scenario: API docs access
- GIVEN the running API server
- WHEN visiting `/docs`
- THEN Swagger UI displays:
- All available endpoints
- Request/response schemas
- Authentication requirements
- Example requests and responses
### Requirement: Health Check Endpoints
The system SHALL provide health monitoring endpoints.
#### Scenario: General health check
- GIVEN the running API server
- WHEN visiting `/health`
- THEN it returns:
- Overall service status
- Database connectivity status
- Redis connectivity status
- Disk space status
- Uptime information
#### Scenario: Database health check
- GIVEN the running API server
- WHEN visiting `/health/db`
- THEN it returns:
- Database connection status
- Response time
- Connection pool status
### Requirement: API Setup Documentation
The system SHALL document API setup and configuration.
#### Scenario: Developer onboarding
- GIVEN a new developer
- WHEN they read `apps/api/README.md`
- THEN they find:
- Setup instructions
- Environment variables
- Running tests
- Common commands
- Architecture overview
### Requirement: Architecture Decision Records
The system SHALL document significant architectural decisions.
#### Scenario: Auth decision record
- GIVEN the codebase
- THEN an ADR SHALL exist documenting:
- Why httpOnly cookies were chosen
- Alternatives considered
- Trade-offs and risks
- Decision date and participants
### Requirement: Endpoint Documentation
The system SHALL document all API endpoints.
#### Scenario: Endpoint coverage
- GIVEN the API codebase
- THEN every endpoint SHALL have:
- Pydantic request/response models
- Docstrings with descriptions
- Response status codes
- Authentication requirements
## Dependencies
- FastAPI (auto-generates OpenAPI)
- Pydantic v2
## Quality Gates
- `/docs` endpoint loads successfully
- `/health` returns 200 with valid JSON
- `/health/db` returns database status
- `pytest` must pass
- `mypy .` must pass
- `ruff check .` must pass
+66
View File
@@ -0,0 +1,66 @@
# Authentication Specification
## Purpose
Manage user authentication via Authentik OAuth with secure session handling.
## Requirements
### Requirement: OAuth2/OIDC Flow
The system SHALL support OAuth2/OIDC authentication via Authentik.
#### Scenario: User login
- GIVEN a user clicks the login button
- WHEN the frontend redirects to Authentik authorization endpoint
- THEN the user authenticates with Authentik
- AND Authentik redirects back with authorization code
#### Scenario: Token exchange
- GIVEN Authentik has redirected with authorization code
- WHEN the callback endpoint receives the code
- THEN it exchanges the code for access and refresh tokens
- AND sets httpOnly, Secure, SameSite=strict cookies
### Requirement: Session Security
The system SHALL protect sessions using httpOnly cookies.
#### Scenario: Cookie attributes
- GIVEN successful authentication
- WHEN cookies are set
- THEN access_token cookie SHALL be httpOnly
- AND access_token cookie SHALL have Secure flag
- AND access_token cookie SHALL have SameSite=strict
- AND refresh_token cookie SHALL have same attributes
### Requirement: Token Refresh
The system SHALL support automatic token refresh.
#### Scenario: Access token expiration
- GIVEN a user has an expired access token
- WHEN the user makes an authenticated request
- THEN the system uses the refresh token to get a new access token
- AND rotates the refresh token
### Requirement: Session Termination
The system SHALL support explicit logout.
#### Scenario: User logout
- GIVEN an authenticated user
- WHEN the user clicks logout
- THEN all auth cookies are cleared
- AND the refresh token is invalidated
## Dependencies
- Authentik OIDC provider configured
- Database models: User
## Quality Gates
- `pytest` must pass
- `mypy .` must pass
- `ruff check .` must pass
+127
View File
@@ -0,0 +1,127 @@
# Database Models Specification
## Purpose
Define the database schema and models for the Headquarter platform using SQLAlchemy 2.0 async style.
## Requirements
### Requirement: User Model
The system SHALL store user information.
#### Scenario: User record
- GIVEN user authentication
- THEN the User model SHALL have:
- id: UUID primary key
- email: Unique email address
- name: Display name
- authentik_id: External Authentik identifier
- avatar_url: Local avatar path (optional)
- created_at: Timestamp
- updated_at: Timestamp
### Requirement: Project Model
The system SHALL organize work into projects.
#### Scenario: Project record
- GIVEN project creation
- THEN the Project model SHALL have:
- id: UUID primary key
- name: Project name
- description: Project description (optional)
- owner_id: Reference to User
- default_ssh_key_id: Reference to SSHKey (optional)
- created_at: Timestamp
- updated_at: Timestamp
### Requirement: GitRepository Model
The system SHALL track git repositories.
#### Scenario: Repository record
- GIVEN repository creation
- THEN the GitRepository model SHALL have:
- id: UUID primary key
- name: Repository name
- path: Filesystem path to bare repo
- project_id: Reference to Project
- owner_id: Reference to User
- is_mirror: Boolean (cloned vs created)
- remote_url: Source URL (for mirrors)
- last_push: Timestamp (optional)
- created_at: Timestamp
### Requirement: SSHKey Model
The system SHALL manage SSH keys.
#### Scenario: SSH key record
- GIVEN SSH key generation
- THEN the SSHKey model SHALL have:
- id: UUID primary key
- name: Key identifier
- public_key: OpenSSH format public key
- private_key_encrypted: Fernet-encrypted private key
- user_id: Reference to User
- project_id: Reference to Project (optional, for project-level keys)
- created_at: Timestamp
### Requirement: UserConfig Model
The system SHALL store user preferences.
#### Scenario: Configuration record
- GIVEN user preferences
- THEN the UserConfig model SHALL have:
- id: UUID primary key
- user_id: Reference to User
- config: JSONB key-value storage
- created_at: Timestamp
- updated_at: Timestamp
### Requirement: Alembic Migrations
The system SHALL version database schema changes.
#### Scenario: Migration setup
- GIVEN the database models
- THEN Alembic SHALL:
- Be initialized with `alembic init`
- Have an initial migration creating all tables
- Support async operations with `asyncpg`
- Be runnable via `make migrate`
### Requirement: Database Seeding
The system SHALL provide development data.
#### Scenario: Development setup
- GIVEN a fresh database
- WHEN running the seed script
- THEN a test user is created
- AND sample data is available for development
## Relationships
- User owns Projects (1:N)
- Project has GitRepositories (1:N)
- User has SSHKeys (1:N)
- User has UserConfig (1:1)
- Project optionally has default SSHKey (N:1)
## Dependencies
- PostgreSQL 15+
- SQLAlchemy 2.0+
- asyncpg
- Alembic
## Quality Gates
- `pytest` must pass
- `mypy .` must pass
- `ruff check .` must pass
- All migrations run successfully
- Models use SQLAlchemy 2.0 async style
@@ -0,0 +1,113 @@
# Docker Infrastructure Specification
## Purpose
Provide a complete Docker-based development environment with all required services.
## Requirements
### Requirement: Docker Compose Setup
The system SHALL provide a `docker-compose.yml` with all platform services.
#### Scenario: Service definitions
- GIVEN the development environment
- THEN `docker-compose.yml` SHALL define:
- PostgreSQL database with health checks
- Redis cache with health checks
- Traefik reverse proxy with dashboard
- Authentik authentication server
- API service (FastAPI)
- Web frontend (React/Vite)
### Requirement: Multi-Stage API Dockerfile
The system SHALL build the API using a multi-stage Docker build.
#### Scenario: API container build
- GIVEN the API source code
- WHEN building the Docker image
- THEN `apps/api/Dockerfile` SHALL:
- Use Python 3.11+ base image
- Install dependencies in a builder stage
- Copy only necessary files to production stage
- Run as non-root user
- Expose port 8000
### Requirement: Web Frontend Dockerfile
The system SHALL build the web frontend for production deployment.
#### Scenario: Web container build
- GIVEN the frontend source code
- WHEN building the Docker image
- THEN `apps/web/Dockerfile` SHALL:
- Use Node.js 20+ base image
- Install dependencies
- Build the production bundle with Vite
- Serve via nginx or similar
- Run as non-root user
### Requirement: Environment Configuration
The system SHALL document all required environment variables.
#### Scenario: Environment setup
- GIVEN a new developer
- WHEN they set up the project
- THEN `.env.example` SHALL document:
- Database connection strings
- Redis connection strings
- Authentik configuration
- JWT secrets
- Docker volume paths
- External service URLs
### Requirement: Service Health Checks
The system SHALL provide health checks for all services.
#### Scenario: Health verification
- GIVEN running services
- WHEN health checks are performed
- THEN each service reports healthy status
- AND unhealthy services are restarted automatically
### Requirement: Makefile Commands
The system SHALL provide common operational commands.
#### Scenario: Developer workflow
- GIVEN the project repository
- WHEN a developer runs make commands
- THEN these commands work:
- `make up` - Start all services
- `make down` - Stop all services
- `make logs` - View service logs
- `make migrate` - Run database migrations
- `make test` - Run test suites
- `make lint` - Run linting
### Requirement: Persistent Storage
The system SHALL persist git repositories across container restarts.
#### Scenario: Repository storage
- GIVEN the Docker setup
- THEN a dedicated volume SHALL mount at `/data/repos`
- AND repositories persist across container restarts
## Dependencies
- Docker 24.0+
- Docker Compose 2.20+
- Make
## Quality Gates
- `docker-compose config` validates without errors
- All services start successfully with `make up`
- Health checks pass for all services
- `pytest` must pass
- `mypy .` must pass
- `ruff check .` must pass
+134
View File
@@ -0,0 +1,134 @@
# Frontend Foundation Specification
## Purpose
Provide a modern React frontend with TypeScript, routing, and responsive layout.
## Requirements
### Requirement: React Application Setup
The system SHALL use React 18+ with TypeScript.
#### Scenario: Frontend build
- GIVEN the frontend codebase
- THEN it SHALL:
- Use React 18+ with TypeScript 5+
- Use Vite as the build tool
- Support Hot Module Replacement (HMR)
- Output optimized production builds
### Requirement: Client-Side Routing
The system SHALL implement client-side routing.
#### Scenario: Navigation
- GIVEN the frontend application
- THEN React Router SHALL:
- Define routes for all pages
- Support protected routes (require authentication)
- Handle 404 errors
- Support route parameters
#### Scenario: Protected routes
- GIVEN an unauthenticated user
- WHEN they access a protected route
- THEN they are redirected to login
### Requirement: Styling Framework
The system SHALL use Tailwind CSS for styling.
#### Scenario: UI components
- GIVEN the frontend codebase
- THEN Tailwind CSS SHALL:
- Provide utility-first styling
- Support custom theme configuration
- Include responsive design utilities
- Support dark mode
### Requirement: Layout Component
The system SHALL provide a consistent application layout.
#### Scenario: Application shell
- GIVEN the frontend application
- THEN a Layout component SHALL:
- Display a header with user info and logout
- Display a sidebar with navigation links
- Show main content area
- Collapse sidebar on mobile
#### Scenario: Navigation links
- GIVEN the sidebar navigation
- THEN it SHALL include links to:
- Dashboard
- Projects
- Repositories
- SSH Keys
- Settings
### Requirement: Responsive Design
The system SHALL support mobile devices.
#### Scenario: Mobile viewport
- GIVEN a mobile device
- WHEN the app loads
- THEN:
- A hamburger menu replaces the sidebar
- Content adapts to screen width
- Touch targets are appropriately sized
### Requirement: Loading States
The system SHALL handle asynchronous operations gracefully.
#### Scenario: Data fetching
- GIVEN a page loading data
- THEN:
- Loading spinners/skeletons are shown
- Error boundaries catch errors
- Retry options are available on failure
### Requirement: HTTP Client Configuration
The system SHALL configure HTTP requests properly.
#### Scenario: API communication
- GIVEN the frontend application
- THEN Axios/fetch SHALL:
- Send credentials (cookies) with requests
- Handle 401 responses by redirecting to login
- Set appropriate content-type headers
- Support request/response interceptors
### Requirement: Dashboard Page
The system SHALL provide a dashboard overview.
#### Scenario: Dashboard view
- GIVEN an authenticated user
- WHEN they visit the dashboard
- THEN they see:
- Total repository count
- Total project count
- Recent activity
- Quick action buttons
## Dependencies
- React 18+
- TypeScript 5+
- Vite
- React Router
- Tailwind CSS
- Axios
## Quality Gates
- `npm run typecheck` must pass
- `npm run lint` must pass
- `npm run build` must succeed
- Frontend handles 401 responses correctly
- Responsive design works on mobile
+68
View File
@@ -0,0 +1,68 @@
# Git Repository Management Specification
## Purpose
Manage git repositories as bare repos on disk with metadata in database.
## Requirements
### Requirement: Repository Creation
The system SHALL allow creating new bare git repositories.
#### Scenario: Create repository
- GIVEN an authenticated user with a project
- WHEN they create a new repository
- THEN a bare repo is initialized on disk at `/data/repos/{user_id}/{project_id}/{repo_name}.git`
- AND metadata is stored in the database
### Requirement: Repository Cloning
The system SHALL support cloning external repositories.
#### Scenario: Clone repository
- GIVEN an authenticated user with a project
- WHEN they provide a remote URL
- THEN the system clones as a bare mirror
- AND stores it in the structured path
### Requirement: Repository Listing
The system SHALL list all user repositories.
#### Scenario: List repositories
- GIVEN an authenticated user
- WHEN they view the repositories page
- THEN all their repos are listed with name, path, and last push date
### Requirement: Repository Deletion
The system SHALL support repository deletion.
#### Scenario: Delete repository
- GIVEN an authenticated user
- WHEN they delete a repository
- THEN it's removed from disk
- AND the database record is deleted
### Requirement: Duplicate Prevention
The system SHALL prevent duplicate repository names per project.
#### Scenario: Duplicate name
- GIVEN a project with a repo named "frontend"
- WHEN the user tries to create another "frontend" repo
- THEN the system rejects with a validation error
## Dependencies
- Database models: GitRepository, Project, User
- Docker volume for repo storage
## Quality Gates
- `pytest` must pass
- `mypy .` must pass
- `ruff check .` must pass
- `npm run typecheck` must pass
- `npm run lint` must pass
+69
View File
@@ -0,0 +1,69 @@
# Project Management Specification
## Purpose
Organize repositories into projects for grouping related work.
## Requirements
### Requirement: Project Creation
The system SHALL allow creating new projects.
#### Scenario: Create project
- GIVEN an authenticated user
- WHEN they create a project with name and description
- THEN a project record is created
- AND the user is set as owner
### Requirement: Project Listing
The system SHALL list all user projects.
#### Scenario: List projects
- GIVEN an authenticated user
- WHEN they view the projects page
- THEN all their projects are listed with associated repositories
### Requirement: Project Updates
The system SHALL support updating project details.
#### Scenario: Update project
- GIVEN a project owner
- WHEN they update the name or description
- THEN the changes are persisted
### Requirement: Project Deletion
The system SHALL support cascading project deletion.
#### Scenario: Delete project
- GIVEN a project owner
- WHEN they delete a project
- THEN all associated repositories are deleted
- AND all associated SSH keys are removed
- AND the project record is deleted
### Requirement: Default SSH Key
The system SHALL allow setting a default SSH key per project.
#### Scenario: Set default key
- GIVEN a project with SSH keys
- WHEN the owner selects a default key
- THEN it's used for git operations in that project
## Dependencies
- Database models: Project, User, GitRepository, SSHKey
- git-repo (for cascading delete)
- ssh-keys (for default key)
## Quality Gates
- `pytest` must pass
- `mypy .` must pass
- `ruff check .` must pass
- `npm run typecheck` must pass
- `npm run lint` must pass
-243
View File
@@ -1,243 +0,0 @@
# Headquarter Project Specsheet
> Canonical project state document. Updated after each completed FN task.
> Last updated: 2026-05-14
## Project Overview
Headquarter is a hosted workspace and tool-orchestration platform where authenticated users create Git-backed projects and spawn containerized development tools (OpenCode, code-server) via HTTPS subdomains.
## Tech Stack
| Layer | Technology |
|-------|-----------|
| Frontend | React 19 + Vite 6 + TypeScript 5 |
| Backend | FastAPI + SQLAlchemy 2.0 (async) + Pydantic v2 |
| Database | PostgreSQL 17 + Alembic migrations |
| Auth | Authentik OIDC (planned) |
| Runtime | Docker Compose (local dev + Portainer production) |
| Routing | Traefik reverse proxy with subdomain routing |
| Monorepo | pnpm workspace |
## Completed Features
### FN-002: Monorepo Scaffold ✅
- Root tooling (Makefile, package.json, pnpm-workspace.yaml)
- React frontend skeleton (apps/web/)
- FastAPI backend skeleton (apps/api/)
- Docker Compose local development stack
- Deployment skeleton for Portainer + Traefik
- CI/CD workflow (GitHub Actions)
### FN-019: Architecture & Specification ✅
- Enhanced docs/architecture.md (18 sections)
- docs/mvp-scope.md with milestones and dependency order
- docs/project-brief.md
- docs/development.md
- docs/deployment.md
- docs/tool-manifest-spec.md
### FN-003: Tool Registry ✅
- Manifest-driven tool registry (JSON schema)
- In-memory registry with built-in manifests
- FastAPI CRUD routes for tool definitions
- OpenCode and code-server built-in definitions
- Registry loaded at application startup
### FN-011: Git Provider Model ✅
- Git provider abstraction (GitHub, GitLab, Gitea, Forgejo, generic)
- SSH key pair generation (Ed25519)
- Encrypted private key storage
- Credential model and storage interface
- Repository connection model and manager
- Local Git operations interface
- Alembic migration for repository_connection table
- Full test coverage
### FN-004: Backend Foundation (Partial) ✅
- Domain models: User, Project, Repository, Workspace, ToolDefinition, ToolInstance, Config, Secret, AccessRoute, RepositoryConnection
- Alembic migrations
- API routers for all entities
- Database configuration with async SQLAlchemy
- Encryption utilities (Fernet)
- Auth dependencies structure
### FN-049: CI / Testing ✅
- GitHub Actions workflow
- Frontend: lint, typecheck, test (Vitest)
- Backend: lint (ruff), typecheck (mypy), test (pytest)
- PostgreSQL service container for backend tests
## OpenSpec Changes (Ready for Implementation)
### FN-005: Frontend Foundation 📋
**Location:** `openspec/changes/frontend-foundation/`
**Status:** All artifacts complete (proposal, design, specs, tasks)
**Dependencies:** FN-002, FN-019
**Tasks:** 46 total
**Key deliverables:**
- Authentik OIDC auth flow with PKCE
- Dashboard shell with responsive navigation
- Project CRUD UI
- Typed API client
- Auth-guarded routes
### FN-006: Deployment Config 📋
**Location:** `openspec/changes/deployment-config/`
**Status:** All artifacts complete (proposal, design, specs, tasks)
**Dependencies:** FN-002
**Tasks:** 27 total
**Key deliverables:**
- Traefik label generator service
- Production Docker Compose stack
- Portainer deployment guide
- Dynamic subdomain routing
### FN-009: Config & Secrets 📋
**Location:** `openspec/changes/config-secrets/`
**Status:** All artifacts complete (proposal, design, specs, tasks)
**Dependencies:** FN-004, FN-005
**Tasks:** 31 total
**Key deliverables:**
- Config management UI (global/user/project/instance scopes)
- Encrypted secret storage UI
- Runtime injection into tool containers
- Scope-based access control
### FN-010: code-server Spawn 📋
**Location:** `openspec/changes/codeserver-spawn/`
**Status:** All artifacts complete (proposal, design, specs, tasks)
**Dependencies:** FN-003, FN-006, FN-009
**Tasks:** 38 total
**Key deliverables:**
- Tool spawn API endpoint
- code-server manifest refinement
- Frontend spawn UI
- Container lifecycle management (start/stop/status)
- Traefik auth proxy integration
### FN-008: OpenCode POC 📋
**Location:** `openspec/changes/opencode-poc/`
**Status:** All artifacts complete (proposal, design, specs, tasks)
**Dependencies:** FN-003, FN-006, FN-009
**Tasks:** 25 total
**Key deliverables:**
- OpenCode manifest with web terminal config
- Containerized terminal environment
- Health reporting mechanism
- Web terminal interface
## Dependency Graph
```
FN-002 (Scaffold) ✅
├──> FN-019 (Architecture) ✅ ──> FN-004 (Backend) ✅
│ │
│ ├──> FN-003 (Tool Registry) ✅
│ │ │
│ │ ├──> FN-010 (code-server) 📋
│ │ └──> FN-008 (OpenCode) 📋
│ │
│ ├──> FN-011 (Git Provider) ✅
│ │
│ └──> FN-009 (Config/Secrets) 📋
│ │
│ └──> FN-010, FN-008 (runtime)
└──> FN-005 (Frontend) 📋 ───────> FN-009 (UI)
FN-006 (Deployment) 📋 runs in parallel with FN-004/FN-005
```
## Critical Path
FN-002 ✅ → FN-019 ✅ → FN-004 ✅ → FN-003 ✅ → FN-010/FN-008 📋
## Next Recommended Task
**FN-005: Frontend Foundation** - This unblocks user-facing features and enables parallel work on FN-009 (Config/Secrets UI).
## Database Schema
### Existing Tables
- `users` - User accounts (Authentik OIDC)
- `projects` - User projects with slug
- `repositories` - Git repository metadata
- `repository_connections` - Provider-specific connections with SSH keys
- `workspaces` - Project workspaces
- `tool_definitions` - Manifest-driven tool definitions
- `tool_instances` - Running/spawned tool instances
- `configs` - Key-value config storage (scoped)
- `secrets` - Encrypted secret storage (scoped)
- `access_routes` - Traefik routing rules
## API Endpoints
### Implemented Routers
- `/api/v1/users` - User management
- `/api/v1/projects` - Project CRUD
- `/api/v1/repositories` - Repository management
- `/api/v1/workspaces` - Workspace management
- `/api/v1/tool-definitions` - Tool registry CRUD
- `/api/v1/tool-instances` - Tool instance lifecycle
- `/api/v1/configs` - Config management
- `/api/v1/secrets` - Secret management
- `/api/v1/access-routes` - Routing rules
- `/api/v1/tools` - Tool registry (manifest-driven)
- `/health` - Health check
## Open Questions (from mvp-scope.md)
1. **Admin role in MVP:** Do we need a basic admin role for global config management?
2. **User slug derivation:** Display name, email local-part, or dedicated slug column?
3. **Provider adapter coverage:** Which Git providers get concrete adapters in MVP?
4. **Auto-deploy-key registration:** Automatic via provider APIs or manual copy-paste?
5. **Container image trust:** Allow-list or any image reference?
6. **Billing or resource quotas:** Usage limiting needed in MVP?
## File Structure
```
headquarter/
├── apps/
│ ├── web/ # React frontend (skeleton)
│ └── api/ # FastAPI backend (models + routers)
├── docs/ # Architecture, scope, development docs
├── deploy/ # Portainer/Traefik deployment examples
├── openspec/ # Spec-driven workflow
│ ├── config.yaml # Project context for AI
│ ├── changes/ # Active changes
│ │ ├── frontend-foundation/ # FN-005
│ │ ├── deployment-config/ # FN-006
│ │ ├── config-secrets/ # FN-009
│ │ ├── codeserver-spawn/ # FN-010
│ │ └── opencode-poc/ # FN-008
│ └── specs/ # Project specsheets
│ └── project-specsheet.md
├── docker-compose.yml # Local development stack
├── docker-compose.traefik.yml
├── Makefile # Common workflows
└── package.json # Root monorepo scripts
```
## Test Status
- **Frontend:** Vitest configured, basic App.test.tsx passing
- **Backend:** pytest configured, tests for git provider, credentials, operations
- **CI:** GitHub Actions runs on PR/push to main
## Definition of MVP Done
1. ✅ Monorepo scaffold complete
2. ✅ Architecture documented
3. ✅ Backend models and migrations
4. ✅ Tool registry with manifests
5. ✅ Git provider abstraction
6. 📋 Frontend auth and navigation (spec ready)
7. 📋 Config/secrets UI and runtime injection (spec ready)
8. 📋 code-server spawn flow (spec ready)
9. 📋 OpenCode terminal environment (spec ready)
10. 📋 Production deployment stack (spec ready)
11. ⏳ All tests passing
12. ⏳ Documentation consistent with implementation
+65
View File
@@ -0,0 +1,65 @@
# SSH Key Management Specification
## Purpose
Generate and manage SSH keys for git operations with external providers.
## Requirements
### Requirement: Key Generation
The system SHALL generate Ed25519 SSH key pairs.
#### Scenario: Generate key
- GIVEN an authenticated user
- WHEN they request a new SSH key
- THEN an Ed25519 key pair is generated
- AND the private key is encrypted with Fernet
- AND the public key is stored in OpenSSH format
### Requirement: Key Association
The system SHALL support user-level and project-level keys.
#### Scenario: User-level key
- GIVEN an authenticated user
- WHEN they generate a key without specifying a project
- THEN it's associated with their user account
#### Scenario: Project-level key
- GIVEN an authenticated user with a project
- WHEN they generate a key for that project
- THEN it's associated with the project
### Requirement: Key Display
The system SHALL display public keys for copying.
#### Scenario: Copy public key
- GIVEN an authenticated user
- WHEN they view their SSH keys
- THEN each public key is displayed in OpenSSH format
- AND a copy button is available
### Requirement: Key Deletion
The system SHALL support key removal.
#### Scenario: Delete key
- GIVEN an authenticated user
- WHEN they delete an SSH key
- THEN it's removed from the database
- AND the key files are deleted
## Dependencies
- Database models: SSHKey, User, Project
- cryptography library for key generation
## Quality Gates
- `pytest` must pass
- `mypy .` must pass
- `ruff check .` must pass
- `npm run typecheck` must pass
- `npm run lint` must pass
+90
View File
@@ -0,0 +1,90 @@
# Tool Instance Management Specification
## Purpose
Launch, monitor, and manage development tool instances in Docker containers.
## Requirements
### Requirement: Tool Instance Creation
The system SHALL create and launch tool instances from repositories.
#### Scenario: Launch tool
- GIVEN an authenticated user with a project and repository
- WHEN they create a tool instance
- THEN:
1. A unique subdomain is generated: `{tool-name}-{tool-id}.hq.local`
2. The Docker Compose template is rendered with project values
3. `docker compose up -d` is executed
4. Container ID and status are stored
### Requirement: Tool Lifecycle
The system SHALL manage tool lifecycle operations.
#### Scenario: Stop tool
- GIVEN a running tool instance
- WHEN the user stops it
- THEN `docker compose stop` is executed
- AND status is updated to "stopped"
#### Scenario: Start tool
- GIVEN a stopped tool instance
- WHEN the user starts it
- THEN `docker compose start` is executed
- AND status is updated to "running"
#### Scenario: Delete tool
- GIVEN a tool instance
- WHEN the user deletes it
- THEN the container and volumes are removed
- AND the database record is deleted
### Requirement: Traefik Integration
The system SHALL auto-generate Traefik labels for routing.
#### Scenario: Route generation
- GIVEN a running tool instance
- THEN these labels are set:
- `traefik.enable=true`
- `traefik.http.routers.{tool_id}.rule=Host(\`{subdomain}.hq.local\`)`
- `traefik.http.routers.{tool_id}.entrypoints=web`
- `traefik.http.services.{tool_id}.loadbalancer.server.port={port}`
### Requirement: Status Monitoring
The system SHALL track tool status.
#### Scenario: Status check
- GIVEN a tool instance
- WHEN status is queried
- THEN the real-time container status is returned:
- pending, building, running, stopped, error
### Requirement: Log Access
The system SHALL provide access to container logs.
#### Scenario: View logs
- GIVEN a tool instance
- WHEN logs are requested
- THEN the last 100 lines are returned
- AND live streaming is available via WebSocket
## Dependencies
- tool-types (tool definitions)
- git-repo (repository access)
- project-management (project context)
- Docker runtime
- Traefik reverse proxy
## Quality Gates
- `pytest` must pass
- `mypy .` must pass
- `ruff check .` must pass
- `npm run typecheck` must pass
- `npm run lint` must pass
+76
View File
@@ -0,0 +1,76 @@
# Web Terminal Specification
## Purpose
Provide browser-based terminal access to running tool containers.
## Requirements
### Requirement: WebSocket Terminal
The system SHALL provide terminal sessions via WebSocket.
#### Scenario: Open terminal
- GIVEN a running tool instance
- WHEN the user opens the terminal
- THEN a WebSocket connection is established
- AND a shell is spawned in the container via `docker exec`
### Requirement: Terminal I/O
The system SHALL stream terminal I/O via WebSocket.
#### Scenario: Command execution
- GIVEN an active terminal session
- WHEN the user types a command
- THEN stdin is forwarded to the container shell
- AND stdout/stderr is streamed back to the browser
### Requirement: Terminal Resize
The system SHALL support terminal resize events.
#### Scenario: Resize terminal
- GIVEN an active terminal session
- WHEN the browser window is resized
- THEN the terminal dimensions (COLS, ROWS) are updated
- AND the shell receives the new size
### Requirement: Session Management
The system SHALL manage terminal sessions.
#### Scenario: Multiple sessions
- GIVEN a running tool instance
- WHEN multiple terminals are opened
- THEN each has an independent session
#### Scenario: Cleanup
- GIVEN an active terminal session
- WHEN the user disconnects
- THEN the session is cleaned up
- AND the shell process is terminated
### Requirement: Access Control
The system SHALL restrict terminal access.
#### Scenario: Unauthorized access
- GIVEN a tool instance owned by user A
- WHEN user B tries to access the terminal
- THEN the connection is rejected with 403
## Dependencies
- tool-instances (running containers)
- auth-oauth (authentication)
- xterm.js frontend library
- ptyprocess for pseudo-TTY
## Quality Gates
- `pytest` must pass
- `mypy .` must pass
- `ruff check .` must pass
- `npm run typecheck` must pass
- `npm run lint` must pass
+67
View File
@@ -0,0 +1,67 @@
# Tool Type Definition Specification
## Purpose
Define and register tool types using Docker Compose templates for launching development tools.
## Requirements
### Requirement: Tool Type Model
The system SHALL store tool type definitions in the database.
#### Scenario: Create tool type
- GIVEN an admin user
- WHEN they define a new tool type
- THEN the following fields are stored:
- name: Tool identifier
- description: Human-readable description
- docker_compose_template: Compose file template
- icon: Visual identifier
- category: Tool category
- default_env_vars: Default environment variables
- default_ports: Exposed ports
### Requirement: Template Variables
The system SHALL support template variable substitution.
#### Scenario: Variable substitution
- GIVEN a Docker Compose template
- WHEN it's rendered for a tool instance
- THEN these variables are substituted:
- `{{REPO_PATH}}`: Path to the git repository
- `{{WORKSPACE_DIR}}`: Working directory inside container
- `{{USER_ID}}`: User identifier
- `{{PROJECT_ID}}`: Project identifier
- `{{TOOL_ID}}`: Tool instance identifier
### Requirement: Built-in Tools
The system SHALL include default tool types.
#### Scenario: Built-in tools
- GIVEN a fresh installation
- THEN these tool types are pre-configured:
- code-server: VS Code in browser
- jupyter-notebook: Jupyter notebooks
- opencode: OpenCode agent environment
### Requirement: Template Validation
The system SHALL validate Docker Compose templates.
#### Scenario: Invalid template
- GIVEN an invalid Docker Compose template
- WHEN a user tries to create/update a tool type
- THEN the system rejects with validation errors
## Dependencies
- Database models: ToolType
## Quality Gates
- `pytest` must pass
- `mypy .` must pass
- `ruff check .` must pass
+69
View File
@@ -0,0 +1,69 @@
# User Configuration Specification
## Purpose
Store and manage user preferences and settings.
## Requirements
### Requirement: Key-Value Storage
The system SHALL store user configuration as JSONB key-value pairs.
#### Scenario: Store preferences
- GIVEN an authenticated user
- WHEN they update their settings
- THEN the configuration is stored in the UserConfig model
### Requirement: Supported Config Keys
The system SHALL support specific configuration keys.
#### Scenario: Supported keys
- GIVEN the configuration system
- THEN these keys SHALL be supported:
- `default_editor`: Preferred code editor
- `theme`: UI theme preference
- `git_user_name`: Git commit author name
- `git_user_email`: Git commit author email
### Requirement: Config Retrieval
The system SHALL return user configuration.
#### Scenario: Get config
- GIVEN an authenticated user
- WHEN they access settings
- THEN their current configuration is returned
### Requirement: Config Updates
The system SHALL support partial configuration updates.
#### Scenario: Update single key
- GIVEN an authenticated user with existing config
- WHEN they update just the theme
- THEN only that key is modified
- AND other keys remain unchanged
### Requirement: Frontend Integration
The system SHALL apply configuration in the frontend.
#### Scenario: Apply theme
- GIVEN a user with theme preference set
- WHEN they load the application
- THEN the selected theme is applied
## Dependencies
- Database models: UserConfig, User
- auth-oauth (authenticated users)
## Quality Gates
- `pytest` must pass
- `mypy .` must pass
- `ruff check .` must pass
- `npm run typecheck` must pass
- `npm run lint` must pass
+50
View File
@@ -0,0 +1,50 @@
# User Profile Management Specification
## Purpose
Manage user profiles including personal information and avatar.
## Requirements
### Requirement: Profile Retrieval
The system SHALL allow users to view their profile.
#### Scenario: View profile
- GIVEN an authenticated user
- WHEN they access the profile page
- THEN their name, email, and avatar are displayed
### Requirement: Profile Updates
The system SHALL allow users to update their profile.
#### Scenario: Update name and email
- GIVEN an authenticated user
- WHEN they submit profile changes
- THEN the system validates the input
- AND updates the user record
### Requirement: Avatar Upload
The system SHALL support local avatar storage.
#### Scenario: Upload avatar
- GIVEN an authenticated user
- WHEN they upload an image file
- THEN the system validates the file type and size
- AND stores it locally
- AND updates the user's avatar URL
## Dependencies
- auth-oauth (authenticated users)
- Database models: User
## Quality Gates
- `pytest` must pass
- `mypy .` must pass
- `ruff check .` must pass
- `npm run typecheck` must pass
- `npm run lint` must pass