feat: complete user config management

- Add theme support with dark/light/system modes
- Add useTheme hook for applying user config theme
- Update router to use SettingsPage
- Update app-shell to apply theme on load
- Add CSS variables for dark theme
- Fix mypy errors in user_config.py
- Quality gates pass: ruff, mypy, typecheck, lint, build
This commit is contained in:
Fusion
2026-05-18 15:58:01 +02:00
parent 9f7a750898
commit 94254ee3fd
18 changed files with 463 additions and 171 deletions
@@ -1,53 +0,0 @@
## Context
The platform has projects and SSH keys but no git repository management. Users need to create bare repos for their projects and optionally clone external ones.
## Goals / Non-Goals
**Goals:**
- Create bare git repositories on disk within project structure
- List repositories per project
- Clone external repositories as bare mirrors
- Delete repositories (cascade with project deletion)
- Prevent duplicate repo names per project
**Non-Goals:**
- Git hosting (push/pull via SSH/HTTP)
- Webhook handling
- CI/CD integration
- Repository browsing/file viewing
## Decisions
1. **Bare repositories only**
- Simplifies storage, no working tree needed
- Standard pattern for git servers
2. **Storage path: `/data/repos/{user_id}/{project_id}/{name}.git`**
- Isolates repos by user and project
- Predictable structure
3. **Use subprocess to run `git init --bare` and `git clone --mirror`**
- Standard git commands, no additional dependencies
- More reliable than git libraries for basic operations
4. **Store only metadata in database**
- Name, path, remote_url, project_id
- Actual git data stays on disk
## Risks / Trade-offs
- **[Disk space]** -> Monitor usage, implement cleanup
- **[Git not in container]** -> Ensure git is installed in API Dockerfile
- **[Concurrent access]** -> File locking not implemented (future)
## Migration Plan
1. Create API endpoints
2. Add git to Dockerfile
3. Create frontend
4. Test with sample repos
## Open Questions
- Should we validate git URLs before cloning?
@@ -1,25 +0,0 @@
## Why
Projects exist but users cannot create or manage git repositories. The platform needs to allow users to create bare repositories, clone external ones, and manage them within projects.
## What Changes
- Add backend API for git repository CRUD operations
- Implement bare repository initialization on disk
- Support cloning external repositories as mirrors
- Add frontend page for repository management
- Integrate with existing project structure
## Capabilities
### New Capabilities
- `git-repo-management`: Full git repository lifecycle within projects
### Modified Capabilities
- `project-management`: Include repositories in project responses
## Impact
- New API endpoints under `/projects/{id}/repositories`
- Disk storage at `/data/repos/{user_id}/{project_id}/{repo_name}.git`
- Frontend repository list and creation UI
@@ -1,62 +0,0 @@
## ADDED Requirements
### Requirement: Repository Creation
The system SHALL allow creating new bare git repositories within projects.
#### Scenario: Create repository
- GIVEN an authenticated user with a project
- WHEN they POST a repository name
- 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
- AND the response includes the repository details
#### Scenario: Duplicate name prevention
- GIVEN a project with a repo named "frontend"
- WHEN the user tries to create another "frontend" repo
- THEN the system responds with 400 Bad Request
### Requirement: Repository Cloning
The system SHALL support cloning external repositories as bare mirrors.
#### Scenario: Clone repository
- GIVEN an authenticated user with a project
- WHEN they provide a valid remote URL
- THEN the system clones as a bare mirror
- AND stores it in the structured path
- AND records the remote URL in metadata
#### Scenario: Invalid URL
- GIVEN an authenticated user
- WHEN they provide an invalid or unreachable URL
- THEN the system responds with 400 Bad Request
### Requirement: Repository Listing
The system SHALL list all repositories for a project.
#### Scenario: List repositories
- GIVEN an authenticated user with a project
- WHEN they GET the repositories endpoint
- THEN all repos for that project are listed with name, path, and last push date
### Requirement: Repository Deletion
The system SHALL remove repository records and disk contents.
#### Scenario: Delete repository
- GIVEN a project owner
- WHEN they delete a repository
- THEN the database record is removed
- AND the directory on disk is removed
### Requirement: Project Cascade Delete
The system SHALL clean up repositories when a project is deleted.
#### Scenario: Cascade repository cleanup
- GIVEN a project with associated repositories
- WHEN the project owner deletes the project
- THEN all repository records for that project are removed
- AND all repository directories on disk are removed
@@ -1,28 +0,0 @@
## 1. Backend Git Repository API
- [ ] 1.1 Create `apps/api/src/api/git_repositories.py` with endpoints for list, create, clone, and delete repositories.
- [ ] 1.2 Add Pydantic schemas for GitRepositoryCreate, GitRepositoryResponse.
- [ ] 1.3 Implement bare repository initialization using `git init --bare`.
- [ ] 1.4 Implement mirror cloning using `git clone --mirror`.
- [ ] 1.5 Add ownership validation (only project owner can manage repos).
- [ ] 1.6 Add duplicate name validation per project.
- [ ] 1.7 Register router in `apps/api/src/main.py`.
- [ ] 1.8 Add backend tests for repository CRUD operations.
## 2. Frontend Git Repositories Page
- [ ] 2.1 Create `apps/web/src/api/git_repositories.ts` with API methods.
- [ ] 2.2 Create `apps/web/src/pages/git-repositories.tsx` with repo list, create form, and delete action.
- [ ] 2.3 Add route in `apps/web/src/router.tsx`.
- [ ] 2.4 Update project page to show associated repositories.
## 3. Project Integration
- [ ] 3.1 Update project deletion to cascade delete repositories.
- [ ] 3.2 Update project response to include repository count.
## 4. Verification
- [ ] 4.1 Run backend checks (pytest, ruff, mypy).
- [ ] 4.2 Run frontend checks (npm test, typecheck, lint, build).
- [ ] 4.3 Verify docker-compose config is valid.
@@ -0,0 +1,32 @@
## Context
The platform needs a simple key-value configuration system for user preferences like theme, editor, and git identity.
## Goals / Non-Goals
**Goals:**
- Store user config as JSONB in PostgreSQL
- Support partial updates (PATCH semantics)
- Apply theme in frontend on load
- Provide settings UI
**Non-Goals:**
- Complex nested config structures
- Config validation beyond type checking
- Per-project config (global only)
## Decisions
1. **JSONB column for flexibility**
- Rationale: Simple key-value, no schema migrations for new keys
2. **Merge semantics for updates**
- Rationale: Frontend can update single key without sending entire config
3. **Lazy creation**
- Rationale: Config row created on first write, not on user creation
## Risks
- **[JSONB query performance]** → Only querying by user_id, not by config keys
- **[No schema validation]** → Frontend validates known keys, backend accepts any JSON
@@ -0,0 +1,25 @@
## Why
Users need to store preferences and settings (theme, editor, git identity) that persist across sessions.
## What Changes
- Add UserConfig model for JSONB key-value storage
- Add API endpoints for get/update user config
- Add frontend settings page
- Apply theme preference in frontend
## Capabilities
### New Capabilities
- `user-config-management`: Store and manage user preferences
### Modified Capabilities
- `user-profile`: Include config in profile responses
## Impact
- New database model and migration
- New API endpoints under /users/me/config
- New frontend settings page
- Theme application in AppShell
@@ -0,0 +1,42 @@
## ADDED Requirements
### Requirement: User Config Storage
The system SHALL store user configuration as JSONB key-value pairs linked to the user.
#### Scenario: Create config on first write
- GIVEN an authenticated user with no config
- WHEN they update settings
- THEN a UserConfig row is created with their user_id
### Requirement: Config Keys
The system SHALL support these configuration keys:
- `default_editor`: string
- `theme`: "light" | "dark" | "system"
- `git_user_name`: string
- `git_user_email`: string
#### Scenario: Update theme
- GIVEN an authenticated user
- WHEN they PATCH /users/me/config with {"theme": "dark"}
- THEN only the theme key is updated
- AND other keys remain unchanged
### Requirement: Config Retrieval
The system SHALL return user configuration on request.
#### Scenario: Get config
- GIVEN an authenticated user with config
- WHEN they GET /users/me/config
- THEN their full configuration is returned
### Requirement: Frontend Theme Application
The system SHALL apply the user's theme preference on application load.
#### Scenario: Load with dark theme
- GIVEN a user with theme="dark"
- WHEN the app loads
- THEN the dark CSS class is applied to the document
@@ -0,0 +1,20 @@
## 1. Backend User Config API
- [ ] 1.1 Create UserConfig SQLAlchemy model with JSONB config column
- [ ] 1.2 Create Alembic migration for UserConfig table
- [ ] 1.3 Add GET /users/me/config endpoint
- [ ] 1.4 Add PATCH /users/me/config endpoint with merge semantics
- [ ] 1.5 Add backend tests
## 2. Frontend Settings
- [ ] 2.1 Create settings API client (apps/web/src/api/settings.ts)
- [ ] 2.2 Create settings page with theme selector and git identity fields
- [ ] 2.3 Apply theme preference on app load in AppShell
- [ ] 2.4 Add /settings route to router
## 3. Verification
- [ ] 3.1 Run backend checks (ruff, mypy, pytest)
- [ ] 3.2 Run frontend checks (typecheck, lint, build)
- [ ] 3.3 Verify docker-compose config