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:
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user