23 lines
20 KiB
JSON
23 lines
20 KiB
JSON
{"id":"phase1-epic","type":"epic","title":"Phase 1: Foundation (Auth, Git Repos, Project Structure)","description":"Rebuild Headquarter platform from scratch starting with foundational layer: Authentik OAuth auth, git repository management with bare repos on disk, SSH key management, user profiles, and basic project structure. Provides core infrastructure for Phase 2 (tool spawning) and Phase 3 (collaboration).","status":"open","priority":0,"parent":null,"external_ref":"prd:./tasks/prd-phase1-foundation.md","dependencies":[]}
|
|
{"id":"phase1-001","type":"story","title":"US-001: Docker Infrastructure & Project Bootstrap","description":"As a developer, I want a Docker Compose setup with all required services so that I can run the platform locally.\n\n## Acceptance Criteria\n- [ ] `docker-compose.yml` with PostgreSQL, Redis, Traefik, and Authentik services\n- [ ] `apps/api/Dockerfile` with multi-stage build for FastAPI\n- [ ] `apps/web/Dockerfile` for React SPA with Vite\n- [ ] `.env.example` documenting all required environment variables\n- [ ] Health checks for all services\n- [ ] `Makefile` with common commands (`make up`, `make down`, `make logs`, `make migrate`)\n- [ ] Git repo storage directory mounted as Docker volume\n\n## Quality Gates\n- `pytest` must pass\n- `mypy .` must pass\n- `ruff check .` must pass","status":"open","priority":1,"parent":"phase1-epic","external_ref":null,"dependencies":[]}
|
|
{"id":"phase1-002","type":"story","title":"US-002: Database Models & Alembic Migrations","description":"As a developer, I want database models for users, projects, and git repos so that the data layer is consistent and versioned.\n\n## Acceptance Criteria\n- [ ] SQLAlchemy models: User, Project, GitRepository, SSHKey, UserConfig\n- [ ] Relationships: User owns Projects, Project has GitRepositories, User has SSHKeys\n- [ ] Alembic initialized with initial migration script\n- [ ] Migration command documented in Makefile\n- [ ] Database seed script for development (creates test user)\n- [ ] All models use SQLAlchemy 2.0 async style\n\n## Quality Gates\n- `pytest` must pass\n- `mypy .` must pass\n- `ruff check .` must pass","status":"open","priority":1,"parent":"phase1-epic","external_ref":null,"dependencies":[]}
|
|
{"id":"phase1-003","type":"story","title":"US-003: Authentik OAuth Authentication with httpOnly Cookies","description":"As a user, I want to log in via Authentik OAuth with secure httpOnly cookies so that my session is protected from XSS attacks.\n\n## Acceptance Criteria\n- [ ] OAuth2/OIDC flow implemented with Authentik as provider\n- [ ] Callback endpoint exchanges code for tokens and sets httpOnly, Secure, SameSite=strict cookies\n- [ ] Token refresh mechanism with refresh token rotation\n- [ ] `/auth/me` endpoint returning current authenticated user\n- [ ] `/auth/logout` endpoint clearing all auth cookies\n- [ ] JWT validation middleware protecting all API routes (except public)\n- [ ] Frontend login button redirecting to Authentik\n- [ ] Frontend handles OAuth callback and refreshes user state\n- [ ] Tests mocking Authentik OIDC endpoints\n\n## Quality Gates\n- `pytest` must pass\n- `mypy .` must pass\n- `ruff check .` must pass","status":"open","priority":1,"parent":"phase1-epic","external_ref":null,"dependencies":["phase1-002"]}
|
|
{"id":"phase1-004","type":"story","title":"US-004: User Profile Management","description":"As a user, I want to view and edit my profile so that my information is up to date.\n\n## Acceptance Criteria\n- [ ] `GET /users/me` endpoint returning current user profile\n- [ ] `PATCH /users/me` endpoint for updating profile fields (name, email)\n- [ ] Frontend profile page displaying user info\n- [ ] Frontend profile edit form with validation\n- [ ] Avatar upload support (stored locally, not external service)\n- [ ] Tests for profile CRUD operations\n\n## Quality Gates\n- `pytest` must pass\n- `mypy .` must pass\n- `ruff check .` must pass\n- `npm run typecheck` must pass\n- `npm run lint` must pass","status":"open","priority":2,"parent":"phase1-epic","external_ref":null,"dependencies":["phase1-003"]}
|
|
{"id":"phase1-005","type":"story","title":"US-005: Git Repository Creation & Cloning","description":"As a user, I want to create new git repositories or clone existing ones so that I can start working on projects.\n\n## Acceptance Criteria\n- [ ] `POST /repos` endpoint to create a new bare git repository\n- [ ] `POST /repos/clone` endpoint to clone an existing repo (bare mirror)\n- [ ] Repositories stored as bare repos on disk in structured path (`/data/repos/{user_id}/{project_id}/{repo_name}.git`)\n- [ ] `GET /repos` listing all user repositories\n- [ ] `GET /repos/{id}` returning repo details (name, path, created_at, last_push)\n- [ ] `DELETE /repos/{id}` removing repo from disk and database\n- [ ] Validation preventing duplicate repo names per project\n- [ ] Frontend repo list page\n- [ ] Frontend forms for create and clone operations\n- [ ] Tests for repo lifecycle (create, clone, delete)\n\n## Quality Gates\n- `pytest` must pass\n- `mypy .` must pass\n- `ruff check .` must pass\n- `npm run typecheck` must pass\n- `npm run lint` must pass","status":"open","priority":2,"parent":"phase1-epic","external_ref":null,"dependencies":["phase1-002"]}
|
|
{"id":"phase1-006","type":"story","title":"US-006: SSH Key Management","description":"As a user, I want to generate and manage SSH keys for git operations so that I can authenticate with external git providers.\n\n## Acceptance Criteria\n- [ ] `POST /ssh-keys` endpoint generating Ed25519 key pair\n- [ ] `GET /ssh-keys` listing user's SSH keys\n- [ ] `DELETE /ssh-keys/{id}` removing a key\n- [ ] Public key displayed in OpenSSH format\n- [ ] Private key encrypted at rest (using Fernet with app secret)\n- [ ] SSH keys associated with User (global) or Project (project-specific)\n- [ ] Frontend SSH key management page\n- [ ] Frontend key generation with one-click copy of public key\n- [ ] Tests for key generation and encryption\n\n## Quality Gates\n- `pytest` must pass\n- `mypy .` must pass\n- `ruff check .` must pass\n- `npm run typecheck` must pass\n- `npm run lint` must pass","status":"open","priority":2,"parent":"phase1-epic","external_ref":null,"dependencies":["phase1-002"]}
|
|
{"id":"phase1-007","type":"story","title":"US-007: Project Structure & Organization","description":"As a user, I want to organize repositories into projects so that I can group related work.\n\n## Acceptance Criteria\n- [ ] `POST /projects` endpoint creating a new project\n- [ ] `GET /projects` listing user's projects\n- [ ] `GET /projects/{id}` returning project with associated repos\n- [ ] `PATCH /projects/{id}` updating project name/description\n- [ ] `DELETE /projects/{id}` deleting project and all associated repos\n- [ ] Project settings page for default SSH key selection\n- [ ] Frontend project list and detail pages\n- [ ] Frontend project creation form\n- [ ] Tests for project CRUD and cascading delete\n\n## Quality Gates\n- `pytest` must pass\n- `mypy .` must pass\n- `ruff check .` must pass\n- `npm run typecheck` must pass\n- `npm run lint` must pass","status":"open","priority":2,"parent":"phase1-epic","external_ref":null,"dependencies":["phase1-002","phase1-005"]}
|
|
{"id":"phase1-008","type":"story","title":"US-008: User Configuration System","description":"As a user, I want to set global preferences so that the platform behaves according to my preferences.\n\n## Acceptance Criteria\n- [ ] `UserConfig` model with key-value storage (JSONB)\n- [ ] `GET /config` endpoint returning user configuration\n- [ ] `PATCH /config` endpoint updating configuration\n- [ ] Supported config keys: default_editor, theme, git_user_name, git_user_email\n- [ ] Frontend settings page with config form\n- [ ] Config applied on frontend (theme, default values)\n- [ ] Tests for config CRUD\n\n## Quality Gates\n- `pytest` must pass\n- `mypy .` must pass\n- `ruff check .` must pass\n- `npm run typecheck` must pass\n- `npm run lint` must pass","status":"open","priority":2,"parent":"phase1-epic","external_ref":null,"dependencies":["phase1-003"]}
|
|
{"id":"phase1-009","type":"story","title":"US-009: Frontend Foundation & Layout","description":"As a user, I want a modern React frontend with navigation so that I can access all features.\n\n## Acceptance Criteria\n- [ ] React 18+ with TypeScript and Vite\n- [ ] React Router setup with protected routes\n- [ ] Tailwind CSS for styling\n- [ ] Layout component with header, sidebar navigation, and main content area\n- [ ] Navigation links: Dashboard, Projects, Repositories, SSH Keys, Settings\n- [ ] Responsive design (mobile hamburger menu)\n- [ ] Loading states and error boundaries\n- [ ] Axios/fetch configured with credentials (cookies)\n- [ ] Basic dashboard page showing user stats (repo count, project count)\n\n## Quality Gates\n- `pytest` must pass\n- `mypy .` must pass\n- `ruff check .` must pass\n- `npm run typecheck` must pass\n- `npm run lint` must pass","status":"open","priority":2,"parent":"phase1-epic","external_ref":null,"dependencies":["phase1-003","phase1-004"]}
|
|
{"id":"phase1-010","type":"story","title":"US-010: API Documentation & Health Checks","description":"As a developer, I want API documentation and health endpoints so that I can monitor and integrate with the platform.\n\n## Acceptance Criteria\n- [ ] OpenAPI/Swagger UI at `/docs` with all endpoints documented\n- [ ] `/health` endpoint returning database and service status\n- [ ] `/health/db` endpoint for database connectivity check\n- [ ] README in `apps/api/` with setup instructions\n- [ ] Architecture Decision Record (ADR) for httpOnly cookie auth choice\n- [ ] All quality gates passing\n\n## Quality Gates\n- `pytest` must pass\n- `mypy .` must pass\n- `ruff check .` must pass","status":"open","priority":3,"parent":"phase1-epic","external_ref":null,"dependencies":["phase1-003"]}
|
|
{"id":"phase2-epic","type":"epic","title":"Phase 2: Tool Runtime (Docker Tools, Web Access, Terminal)","description":"Extend Headquarter platform with Docker-based tool runtime system. Enables launching development tools (code-server, Jupyter, opencode) from git repositories, accessing their web UIs via Traefik routes, and interacting through web-based terminals. Tools are defined via Docker Compose templates and spawned into isolated containers.","status":"open","priority":0,"parent":null,"external_ref":"prd:./tasks/prd-phase2-tool-runtime.md","dependencies":[]}
|
|
{"id":"phase2-011","type":"story","title":"US-011: Tool Type Definition System","description":"As an admin, I want to define tool types using Docker Compose templates so that new tools can be added without code changes.\n\n## Acceptance Criteria\n- [ ] Create ToolType model with fields: name, description, docker_compose_template, icon, category, default_env_vars, default_ports\n- [ ] Support template variables: {{REPO_PATH}}, {{WORKSPACE_DIR}}, {{USER_ID}}, {{PROJECT_ID}}, {{TOOL_ID}}\n- [ ] Seed database with 3 built-in tool types: code-server, jupyter-notebook, opencode\n- [ ] GET /tool-types endpoint listing all available tool types\n- [ ] GET /tool-types/{id} returning tool type details\n- [ ] Docker Compose templates validated on create/update\n- [ ] Tests for template validation and variable substitution\n\n## Quality Gates\n- pytest must pass\n- mypy . must pass\n- ruff check . must pass","status":"open","priority":1,"parent":"phase2-epic","external_ref":null,"dependencies":[]}
|
|
{"id":"phase2-012","type":"story","title":"US-012: Tool Instance Model & Database Schema","description":"As a developer, I want a database model for tool instances so that I can track running tools and their state.\n\n## Acceptance Criteria\n- [ ] Create ToolInstance model with fields: id, name, project_id, repo_id, tool_type_id, status, container_id, subdomain, ports, env_vars, created_at, started_at, stopped_at\n- [ ] Status enum: pending, building, running, stopped, error\n- [ ] Relationship: ToolInstance belongs to Project and GitRepository\n- [ ] Alembic migration for tool instance tables\n- [ ] ToolInstanceConfig model for per-instance config overrides\n- [ ] Tests for model relationships and status transitions\n\n## Quality Gates\n- pytest must pass\n- mypy . must pass\n- ruff check . must pass","status":"open","priority":1,"parent":"phase2-epic","external_ref":null,"dependencies":["phase2-011"]}
|
|
{"id":"phase2-013","type":"story","title":"US-013: Docker Compose Template Engine","description":"As a developer, I want a template engine that renders Docker Compose files with project-specific values so that tools launch with correct configuration.\n\n## Acceptance Criteria\n- [ ] Implement template rendering engine (Jinja2 or string replacement)\n- [ ] Variable substitution: {{REPO_PATH}}, {{WORKSPACE_DIR}}, {{USER_ID}}, {{PROJECT_ID}}, {{TOOL_ID}}, {{SUBDOMAIN}}\n- [ ] Support environment variable injection from project/user config\n- [ ] Support port mapping configuration (host port allocation)\n- [ ] Support volume mounts (repo code, config files, persistent data)\n- [ ] Support network attachment (Traefik network)\n- [ ] Tests for template rendering with various inputs\n\n## Quality Gates\n- pytest must pass\n- mypy . must pass\n- ruff check . must pass","status":"open","priority":1,"parent":"phase2-epic","external_ref":null,"dependencies":["phase2-011"]}
|
|
{"id":"phase2-014","type":"story","title":"US-014: Tool Spawning & Docker Integration","description":"As a user, I want to launch tools from my repositories so that I can start working immediately.\n\n## Acceptance Criteria\n- [ ] POST /tools endpoint to create and launch a tool instance\n- [ ] Accept parameters: name, project_id, repo_id, tool_type_id, env_vars (optional), config_overrides (optional)\n- [ ] Generate unique subdomain: {tool-name}-{tool-id}.hq.local\n- [ ] Render Docker Compose template with project values\n- [ ] Execute docker compose up -d to launch container\n- [ ] Store container_id and update status to running\n- [ ] Handle build errors and set status to error with logs\n- [ ] POST /tools/{id}/stop to stop container (docker compose stop)\n- [ ] POST /tools/{id}/start to start stopped container\n- [ ] DELETE /tools/{id} to stop and remove container + data\n- [ ] Tests mocking Docker compose commands\n\n## Quality Gates\n- pytest must pass\n- mypy . must pass\n- ruff check . must pass","status":"open","priority":2,"parent":"phase2-epic","external_ref":null,"dependencies":["phase2-012","phase2-013"]}
|
|
{"id":"phase2-015","type":"story","title":"US-015: Traefik Route Generation","description":"As a user, I want tools accessible via clean URLs so that I can access them without remembering ports.\n\n## Acceptance Criteria\n- [ ] Auto-generate Traefik labels on tool containers:\n - traefik.enable=true\n - traefik.http.routers.{tool_id}.rule=Host({subdomain}.hq.local)\n - traefik.http.routers.{tool_id}.entrypoints=web\n - traefik.http.services.{tool_id}.loadbalancer.server.port={port}\n- [ ] Tools join Traefik Docker network for routing\n- [ ] GET /tools/{id}/url returning accessible URL\n- [ ] Handle subdomain collisions (append random suffix if needed)\n- [ ] Support HTTPS in production (websecure entrypoint)\n- [ ] Tests for label generation and URL construction\n\n## Quality Gates\n- pytest must pass\n- mypy . must pass\n- ruff check . must pass","status":"open","priority":2,"parent":"phase2-epic","external_ref":null,"dependencies":["phase2-014"]}
|
|
{"id":"phase2-016","type":"story","title":"US-016: Web-Based Terminal (xterm.js)","description":"As a user, I want a terminal in my browser to interact with running tools so that I don't need SSH access.\n\n## Acceptance Criteria\n- [ ] WebSocket endpoint /ws/terminal/{tool_id} for terminal sessions\n- [ ] Use docker exec to spawn shell in running container\n- [ ] Stream stdin/stdout/stderr via WebSocket\n- [ ] Terminal resize support (COLS, ROWS)\n- [ ] Session cleanup on disconnect\n- [ ] Authentication: only tool owner can access terminal\n- [ ] Frontend terminal component using xterm.js\n- [ ] Terminal connects to WebSocket with auth token\n- [ ] Support multiple terminal sessions per tool\n- [ ] Tests for WebSocket terminal lifecycle\n\n## Quality Gates\n- pytest must pass\n- mypy . must pass\n- ruff check . must pass\n- npm run typecheck must pass\n- npm run lint must pass","status":"open","priority":2,"parent":"phase2-epic","external_ref":null,"dependencies":["phase2-014"]}
|
|
{"id":"phase2-017","type":"story","title":"US-017: Tool Status Monitoring & Logs","description":"As a user, I want to see if my tools are running and view their logs so that I can debug issues.\n\n## Acceptance Criteria\n- [ ] GET /tools/{id}/status returning real-time container status\n- [ ] GET /tools/{id}/logs returning recent container logs (tail 100)\n- [ ] GET /tools/{id}/logs/stream WebSocket for live log streaming\n- [ ] Frontend tool dashboard showing:\n - Status indicator (running/stopped/error)\n - Uptime counter\n - Quick actions (start/stop/restart)\n - Log viewer with auto-scroll\n- [ ] Auto-refresh status every 5 seconds\n- [ ] Tests for status checking and log retrieval\n\n## Quality Gates\n- pytest must pass\n- mypy . must pass\n- ruff check . must pass\n- npm run typecheck must pass\n- npm run lint must pass","status":"open","priority":2,"parent":"phase2-epic","external_ref":null,"dependencies":["phase2-014"]}
|
|
{"id":"phase2-018","type":"story","title":"US-018: Frontend Tool Management UI","description":"As a user, I want a web interface to manage my tools so that I can launch, monitor, and access them easily.\n\n## Acceptance Criteria\n- [ ] Tools page listing all user's tool instances\n- [ ] Launch Tool button opening creation form\n- [ ] Form fields: name, project (dropdown), repository (dropdown), tool type (dropdown), environment variables (key-value), config overrides\n- [ ] Tool detail page showing:\n - Status and info\n - Open button (links to tool URL)\n - Terminal button (opens web terminal)\n - Logs panel\n - Settings (env vars, restart, delete)\n- [ ] Tool cards on dashboard showing quick stats\n- [ ] Empty state when no tools exist\n- [ ] Tests for tool CRUD operations in frontend\n\n## Quality Gates\n- pytest must pass\n- mypy . must pass\n- ruff check . must pass\n- npm run typecheck must pass\n- npm run lint must pass","status":"open","priority":2,"parent":"phase2-epic","external_ref":null,"dependencies":["phase2-015","phase2-016","phase2-017"]}
|
|
{"id":"phase2-019","type":"story","title":"US-019: Tool Configuration & Environment Variables","description":"As a user, I want to configure tools with custom environment variables and settings so that they work for my specific needs.\n\n## Acceptance Criteria\n- [ ] Global tool config at user level (default env vars for all tools)\n- [ ] Project-level tool config (overrides global defaults)\n- [ ] Tool instance-level config (overrides project defaults)\n- [ ] PATCH /tools/{id}/config endpoint for updating config\n- [ ] Config inheritance: user defaults -> project overrides -> instance overrides\n- [ ] Frontend config editor with key-value pairs\n- [ ] Support for secret values (masked in UI, encrypted at rest)\n- [ ] Tests for config inheritance and override logic\n\n## Quality Gates\n- pytest must pass\n- mypy . must pass\n- ruff check . must pass\n- npm run typecheck must pass\n- npm run lint must pass","status":"open","priority":3,"parent":"phase2-epic","external_ref":null,"dependencies":["phase2-014"]}
|
|
{"id":"phase2-020","type":"story","title":"US-020: Phase 2 Integration & Documentation","description":"As a developer, I want Phase 2 fully integrated with Phase 1 and documented so that the platform is cohesive.\n\n## Acceptance Criteria\n- [ ] Tool instances linked to projects and repositories (Phase 1 models)\n- [ ] SSH keys from Phase 1 available inside tool containers (mount ~/.ssh)\n- [ ] Git user config from Phase 1 applied to tool containers\n- [ ] Update API docs with all new endpoints\n- [ ] README section for tool configuration\n- [ ] Architecture Decision Record (ADR) for Docker Compose template approach\n- [ ] All quality gates passing\n- [ ] End-to-end test: create repo -> launch code-server -> access via URL -> open terminal\n\n## Quality Gates\n- pytest must pass\n- mypy . must pass\n- ruff check . must pass\n- npm run typecheck must pass\n- npm run lint must pass","status":"open","priority":3,"parent":"phase2-epic","external_ref":null,"dependencies":["phase2-015","phase2-016","phase2-017","phase2-018","phase2-019"]}
|