feat: initialize project structure and configuration
- Create backend directory structure (app/models, app/schemas, app/services, app/api, app/tasks, tests) - Create frontend directory structure (src/router, src/views, src/components, src/api, src/stores) - Create data directories (ssh_keys, repos) - Add requirements.txt with FastAPI, SQLAlchemy, Pydantic, and testing dependencies - Add frontend package.json with Vue 3, Vue Router, Pinia, and Element Plus - Add .env.example with configuration template - Add .gitignore for Python, data directories, and frontend - Add pytest conftest.py with test fixtures for database and environment Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
12
.env.example
Normal file
12
.env.example
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# AES-256 加密密钥 (32字节 base64编码)
|
||||||
|
GM_ENCRYPT_KEY=change-this-to-a-32-byte-base64-key
|
||||||
|
|
||||||
|
# API 认证 Token
|
||||||
|
GM_API_TOKEN=change-this-api-token
|
||||||
|
|
||||||
|
# 数据目录
|
||||||
|
GM_DATA_DIR=./data
|
||||||
|
|
||||||
|
# 服务器配置
|
||||||
|
GM_HOST=0.0.0.0
|
||||||
|
GM_PORT=8000
|
||||||
30
.gitignore
vendored
Normal file
30
.gitignore
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# Python
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
*.so
|
||||||
|
.Python
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
.venv/
|
||||||
|
|
||||||
|
# 数据
|
||||||
|
data/
|
||||||
|
*.db
|
||||||
|
*.db-journal
|
||||||
|
|
||||||
|
# 环境变量
|
||||||
|
.env
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
*.swp
|
||||||
|
|
||||||
|
# 前端
|
||||||
|
frontend/node_modules/
|
||||||
|
frontend/dist/
|
||||||
|
frontend/.vite/
|
||||||
|
|
||||||
|
# 日志
|
||||||
|
*.log
|
||||||
0
backend/app/__init__.py
Normal file
0
backend/app/__init__.py
Normal file
0
backend/app/api/__init__.py
Normal file
0
backend/app/api/__init__.py
Normal file
0
backend/app/models/__init__.py
Normal file
0
backend/app/models/__init__.py
Normal file
0
backend/app/schemas/__init__.py
Normal file
0
backend/app/schemas/__init__.py
Normal file
0
backend/app/services/__init__.py
Normal file
0
backend/app/services/__init__.py
Normal file
0
backend/app/tasks/__init__.py
Normal file
0
backend/app/tasks/__init__.py
Normal file
14
backend/requirements.txt
Normal file
14
backend/requirements.txt
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
fastapi==0.109.0
|
||||||
|
uvicorn[standard]==0.27.0
|
||||||
|
sqlalchemy==2.0.25
|
||||||
|
pydantic==2.5.3
|
||||||
|
pydantic-settings==2.1.0
|
||||||
|
python-multipart==0.0.6
|
||||||
|
apscheduler==3.10.4
|
||||||
|
paramiko==3.4.0
|
||||||
|
gitpython==3.1.40
|
||||||
|
cryptography==41.0.7
|
||||||
|
requests==2.31.0
|
||||||
|
pytest==7.4.4
|
||||||
|
pytest-asyncio==0.23.3
|
||||||
|
httpx==0.26.0
|
||||||
0
backend/tests/__init__.py
Normal file
0
backend/tests/__init__.py
Normal file
55
backend/tests/conftest.py
Normal file
55
backend/tests/conftest.py
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
import pytest
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# Add backend to path
|
||||||
|
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||||
|
|
||||||
|
from sqlalchemy import create_engine
|
||||||
|
from sqlalchemy.orm import sessionmaker
|
||||||
|
from app.models import Base
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="function")
|
||||||
|
def db_path(tmp_path):
|
||||||
|
"""临时数据库路径."""
|
||||||
|
return tmp_path / "test.db"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="function")
|
||||||
|
def db_engine(db_path):
|
||||||
|
"""临时数据库引擎."""
|
||||||
|
engine = create_engine(f"sqlite:///{db_path}", connect_args={"check_same_thread": False})
|
||||||
|
Base.metadata.create_all(engine)
|
||||||
|
yield engine
|
||||||
|
engine.dispose()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="function")
|
||||||
|
def db_session(db_engine):
|
||||||
|
"""临时数据库会话."""
|
||||||
|
SessionLocal = sessionmaker(bind=db_engine, autocommit=False, autoflush=False)
|
||||||
|
session = SessionLocal()
|
||||||
|
yield session
|
||||||
|
session.close()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="function")
|
||||||
|
def test_encrypt_key():
|
||||||
|
"""测试加密密钥."""
|
||||||
|
import base64
|
||||||
|
return base64.b64encode(b'test-key-32-bytes-long-1234567890').decode()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="function")
|
||||||
|
def test_env_vars(db_path, test_encrypt_key, monkeypatch):
|
||||||
|
"""设置测试环境变量."""
|
||||||
|
monkeypatch.setenv("GM_ENCRYPT_KEY", test_encrypt_key)
|
||||||
|
monkeypatch.setenv("GM_API_TOKEN", "test-token")
|
||||||
|
monkeypatch.setenv("GM_DATA_DIR", str(db_path.parent))
|
||||||
|
return {
|
||||||
|
"GM_ENCRYPT_KEY": test_encrypt_key,
|
||||||
|
"GM_API_TOKEN": "test-token",
|
||||||
|
}
|
||||||
3799
docs/superpowers/plans/2026-03-30-git-repo-manager.md
Normal file
3799
docs/superpowers/plans/2026-03-30-git-repo-manager.md
Normal file
File diff suppressed because it is too large
Load Diff
378
docs/superpowers/specs/2026-03-30-git-repo-manager-design.md
Normal file
378
docs/superpowers/specs/2026-03-30-git-repo-manager-design.md
Normal file
@@ -0,0 +1,378 @@
|
|||||||
|
# Git Repo Manager - 设计文档
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
一个面向小团队(3-10人)的 Git 仓库本地同步管理工具。通过 Web 界面管理多个 Gitea 服务器,支持将远程仓库批量同步到本地,提供提交历史查看和定时自动同步功能。首版聚焦 Gitea 服务器支持。
|
||||||
|
|
||||||
|
## 技术选型
|
||||||
|
|
||||||
|
| 层 | 技术 | 理由 |
|
||||||
|
|----|------|------|
|
||||||
|
| 后端 | Python FastAPI | 开发快速,异步支持好 |
|
||||||
|
| 前端 | Vue 3 + Element Plus + Pinia | 中文生态完善,适合管理后台 |
|
||||||
|
| 数据库 | SQLite + SQLAlchemy ORM | 零部署,适合小团队 |
|
||||||
|
| 调度 | APScheduler | Python 生态成熟方案 |
|
||||||
|
| SSH | paramiko | 纯 Python SSH 实现 |
|
||||||
|
| HTTP 客户端 | Axios | 前端请求拦截器 |
|
||||||
|
| 部署 | 单进程 uvicorn | 一个命令启动全部功能 |
|
||||||
|
|
||||||
|
## 架构设计
|
||||||
|
|
||||||
|
### 整体架构
|
||||||
|
|
||||||
|
单体 FastAPI 应用,内嵌前端静态资源,单进程运行:
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────┐
|
||||||
|
│ FastAPI 单进程 │
|
||||||
|
│ │
|
||||||
|
│ ┌─────────┐ ┌──────────┐ ┌────────────┐ │
|
||||||
|
│ │ REST API │ │ Scheduler │ │ Git Engine │ │
|
||||||
|
│ │ /api/v1 │ │ APSched │ │ git+SSH │ │
|
||||||
|
│ └────┬─────┘ └─────┬────┘ └─────┬──────┘ │
|
||||||
|
│ │ │ │ │
|
||||||
|
│ ┌────┴──────────────┴──────────────┴──────┐ │
|
||||||
|
│ │ Service Layer │ │
|
||||||
|
│ │ ServerService / RepoService / SyncSvc │ │
|
||||||
|
│ └────────────────┬────────────────────────┘ │
|
||||||
|
│ │ │
|
||||||
|
│ ┌────────────────┴────────────────────────┐ │
|
||||||
|
│ │ SQLAlchemy + SQLite (data + keys) │ │
|
||||||
|
│ └─────────────────────────────────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ ┌─────────────────────────────────────────┐ │
|
||||||
|
│ │ Vue 3 SPA (打包后静态托管) │ │
|
||||||
|
│ └─────────────────────────────────────────┘ │
|
||||||
|
└─────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 项目目录结构
|
||||||
|
|
||||||
|
```
|
||||||
|
git-manager/
|
||||||
|
├── backend/
|
||||||
|
│ ├── app/
|
||||||
|
│ │ ├── main.py # FastAPI 入口,挂载路由和静态文件
|
||||||
|
│ │ ├── config.py # 配置管理,读取环境变量
|
||||||
|
│ │ ├── database.py # SQLite 连接,会话管理
|
||||||
|
│ │ ├── security.py # 加解密工具,API 认证
|
||||||
|
│ │ ├── models/ # SQLAlchemy 数据模型
|
||||||
|
│ │ │ ├── __init__.py
|
||||||
|
│ │ │ ├── server.py # Server 模型
|
||||||
|
│ │ │ ├── repo.py # Repo 模型
|
||||||
|
│ │ │ ├── ssh_key.py # SshKey 模型
|
||||||
|
│ │ │ └── sync_log.py # SyncLog 模型
|
||||||
|
│ │ ├── schemas/ # Pydantic 请求/响应模型
|
||||||
|
│ │ │ ├── __init__.py
|
||||||
|
│ │ │ ├── server.py
|
||||||
|
│ │ │ ├── repo.py
|
||||||
|
│ │ │ ├── ssh_key.py
|
||||||
|
│ │ │ ├── sync_log.py
|
||||||
|
│ │ │ └── common.py # 标准响应格式
|
||||||
|
│ │ ├── services/ # 业务逻辑层
|
||||||
|
│ │ │ ├── __init__.py
|
||||||
|
│ │ │ ├── server_service.py
|
||||||
|
│ │ │ ├── repo_service.py
|
||||||
|
│ │ │ ├── sync_service.py
|
||||||
|
│ │ │ └── ssh_key_service.py
|
||||||
|
│ │ ├── api/ # API 路由
|
||||||
|
│ │ │ ├── __init__.py
|
||||||
|
│ │ │ ├── deps.py # 依赖注入(DB 会话、认证)
|
||||||
|
│ │ │ ├── servers.py
|
||||||
|
│ │ │ ├── repos.py
|
||||||
|
│ │ │ ├── ssh_keys.py
|
||||||
|
│ │ │ ├── sync_logs.py
|
||||||
|
│ │ │ ├── schedules.py
|
||||||
|
│ │ │ └── status.py
|
||||||
|
│ │ └── tasks/ # 定时任务
|
||||||
|
│ │ ├── __init__.py
|
||||||
|
│ │ └── sync_task.py
|
||||||
|
│ ├── init_db.py # 数据库初始化脚本
|
||||||
|
│ └── requirements.txt
|
||||||
|
├── frontend/
|
||||||
|
│ ├── src/
|
||||||
|
│ │ ├── App.vue
|
||||||
|
│ │ ├── main.js
|
||||||
|
│ │ ├── router/
|
||||||
|
│ │ │ └── index.js
|
||||||
|
│ │ ├── views/ # 页面组件
|
||||||
|
│ │ │ ├── Dashboard.vue
|
||||||
|
│ │ │ ├── Servers.vue
|
||||||
|
│ │ │ ├── Repos.vue
|
||||||
|
│ │ │ ├── SyncLogs.vue
|
||||||
|
│ │ │ ├── SshKeys.vue
|
||||||
|
│ │ │ └── Settings.vue
|
||||||
|
│ │ ├── components/ # 通用组件
|
||||||
|
│ │ │ ├── ServerForm.vue
|
||||||
|
│ │ │ ├── RepoSyncStatus.vue
|
||||||
|
│ │ │ └── CommitHistory.vue
|
||||||
|
│ │ ├── api/ # API 调用封装
|
||||||
|
│ │ │ ├── index.js # Axios 实例,拦截器
|
||||||
|
│ │ │ ├── servers.js
|
||||||
|
│ │ │ ├── repos.js
|
||||||
|
│ │ │ ├── sshKeys.js
|
||||||
|
│ │ │ └── syncLogs.js
|
||||||
|
│ │ └── stores/ # Pinia 状态管理
|
||||||
|
│ │ ├── servers.js
|
||||||
|
│ │ ├── repos.js
|
||||||
|
│ │ └── app.js
|
||||||
|
│ ├── index.html
|
||||||
|
│ ├── vite.config.js
|
||||||
|
│ └── package.json
|
||||||
|
└── data/ # 运行时数据目录
|
||||||
|
├── git_manager.db # SQLite 数据库
|
||||||
|
├── ssh_keys/ # SSH 密钥文件(加密存储)
|
||||||
|
└── repos/ # 本地仓库镜像
|
||||||
|
└── {server_name}/
|
||||||
|
└── {repo_full_name}/
|
||||||
|
```
|
||||||
|
|
||||||
|
## API 设计
|
||||||
|
|
||||||
|
### 设计原则
|
||||||
|
|
||||||
|
- 统一 `/api/v1/` 前缀,版本化管理
|
||||||
|
- 标准 JSON 响应格式:`{"code": 0, "data": {}, "message": "success"}`
|
||||||
|
- Bearer Token 认证:`Authorization: Bearer <token>`
|
||||||
|
- Swagger 文档自动生成(`/docs`)
|
||||||
|
|
||||||
|
### 接口列表
|
||||||
|
|
||||||
|
#### 服务器管理
|
||||||
|
|
||||||
|
| 方法 | 路径 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| POST | `/api/v1/servers` | 添加 Gitea 服务器 |
|
||||||
|
| GET | `/api/v1/servers` | 服务器列表 |
|
||||||
|
| GET | `/api/v1/servers/{id}` | 服务器详情 |
|
||||||
|
| PUT | `/api/v1/servers/{id}` | 更新服务器配置 |
|
||||||
|
| DELETE | `/api/v1/servers/{id}` | 删除服务器 |
|
||||||
|
| POST | `/api/v1/servers/{id}/test` | 测试连接 + SSH 密钥有效性 |
|
||||||
|
| POST | `/api/v1/servers/{id}/sync` | 触发该服务器所有仓库同步 |
|
||||||
|
|
||||||
|
#### 仓库管理
|
||||||
|
|
||||||
|
| 方法 | 路径 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| GET | `/api/v1/servers/{id}/repos` | 获取服务器仓库列表(调 Gitea API) |
|
||||||
|
| GET | `/api/v1/repos` | 所有本地已同步的仓库 |
|
||||||
|
| GET | `/api/v1/repos/{id}` | 仓库详情 |
|
||||||
|
| POST | `/api/v1/repos/{id}/sync` | 手动同步单个仓库 |
|
||||||
|
| GET | `/api/v1/repos/{id}/commits` | 仓库提交历史 |
|
||||||
|
|
||||||
|
#### SSH 密钥管理
|
||||||
|
|
||||||
|
| 方法 | 路径 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| POST | `/api/v1/ssh-keys` | 上传私钥 |
|
||||||
|
| GET | `/api/v1/ssh-keys` | 密钥列表 |
|
||||||
|
| DELETE | `/api/v1/ssh-keys/{id}` | 删除密钥 |
|
||||||
|
| POST | `/api/v1/ssh-keys/{id}/test` | 测试密钥有效性 |
|
||||||
|
|
||||||
|
#### 同步记录
|
||||||
|
|
||||||
|
| 方法 | 路径 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| GET | `/api/v1/sync-logs` | 同步日志列表(支持分页和状态筛选) |
|
||||||
|
| GET | `/api/v1/sync-logs/{id}` | 同步详情 |
|
||||||
|
|
||||||
|
#### 调度配置
|
||||||
|
|
||||||
|
| 方法 | 路径 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| GET | `/api/v1/schedules` | 查看调度配置 |
|
||||||
|
| PUT | `/api/v1/schedules` | 修改调度配置 |
|
||||||
|
|
||||||
|
#### 系统状态
|
||||||
|
|
||||||
|
| 方法 | 路径 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| GET | `/api/v1/status` | 系统运行状态、磁盘空间、仓库统计 |
|
||||||
|
|
||||||
|
## 数据模型
|
||||||
|
|
||||||
|
### ER 关系
|
||||||
|
|
||||||
|
```
|
||||||
|
ssh_keys 1 ──── N servers
|
||||||
|
servers 1 ──── N repos
|
||||||
|
repos 1 ──── N sync_logs
|
||||||
|
```
|
||||||
|
|
||||||
|
### ssh_keys 表
|
||||||
|
|
||||||
|
| 字段 | 类型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| id | INTEGER PK | 自增主键 |
|
||||||
|
| name | VARCHAR(100) | 密钥名称 |
|
||||||
|
| private_key | TEXT | AES-256 加密后的私钥内容 |
|
||||||
|
| fingerprint | VARCHAR(64) | 密钥指纹(用于展示) |
|
||||||
|
| created_at | DATETIME | 创建时间 |
|
||||||
|
|
||||||
|
### servers 表
|
||||||
|
|
||||||
|
| 字段 | 类型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| id | INTEGER PK | 自增主键 |
|
||||||
|
| name | VARCHAR(100) | 服务器名称 |
|
||||||
|
| url | VARCHAR(500) | Gitea 服务器地址(如 https://gitea.example.com) |
|
||||||
|
| api_token | TEXT | Gitea API Token(AES-256 加密存储) |
|
||||||
|
| ssh_key_id | INTEGER FK | 关联 ssh_keys.id |
|
||||||
|
| sync_enabled | BOOLEAN | 是否启用自动同步 |
|
||||||
|
| schedule_cron | VARCHAR(50) | 定时表达式(如 `0 */2 * * *`) |
|
||||||
|
| local_path | VARCHAR(500) | 本地仓库存储路径 |
|
||||||
|
| status | VARCHAR(20) | 连接状态:connected / disconnected / untested |
|
||||||
|
| created_at | DATETIME | 创建时间 |
|
||||||
|
| updated_at | DATETIME | 更新时间 |
|
||||||
|
|
||||||
|
### repos 表
|
||||||
|
|
||||||
|
| 字段 | 类型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| id | INTEGER PK | 自增主键 |
|
||||||
|
| server_id | INTEGER FK | 关联 servers.id |
|
||||||
|
| name | VARCHAR(200) | 仓库名称 |
|
||||||
|
| full_name | VARCHAR(300) | 完整路径(owner/repo) |
|
||||||
|
| clone_url | VARCHAR(500) | SSH 克隆地址 |
|
||||||
|
| local_path | VARCHAR(500) | 本地镜像路径 |
|
||||||
|
| last_sync_at | DATETIME | 最后同步时间 |
|
||||||
|
| status | VARCHAR(20) | 状态:pending / syncing / synced / failed |
|
||||||
|
| created_at | DATETIME | 创建时间 |
|
||||||
|
|
||||||
|
### sync_logs 表
|
||||||
|
|
||||||
|
| 字段 | 类型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| id | INTEGER PK | 自增主键 |
|
||||||
|
| repo_id | INTEGER FK | 关联 repos.id |
|
||||||
|
| status | VARCHAR(20) | synced / failed |
|
||||||
|
| started_at | DATETIME | 开始时间 |
|
||||||
|
| finished_at | DATETIME | 结束时间 |
|
||||||
|
| commits_count | INTEGER | 本次同步新增提交数 |
|
||||||
|
| error_msg | TEXT | 失败时的错误信息 |
|
||||||
|
| created_at | DATETIME | 创建时间 |
|
||||||
|
|
||||||
|
## 同步流程
|
||||||
|
|
||||||
|
### 首次同步(clone)
|
||||||
|
|
||||||
|
```
|
||||||
|
用户添加服务器 → 调 Gitea API 获取仓库列表
|
||||||
|
→ 对每个仓库:
|
||||||
|
1. 生成 local_path: data/repos/{server_name}/{full_name}
|
||||||
|
2. 解密 SSH 私钥到内存
|
||||||
|
3. git clone --mirror <clone_url> <local_path>
|
||||||
|
4. 记录 sync_log(状态 synced,提交数)
|
||||||
|
5. 更新 repo.status = synced
|
||||||
|
```
|
||||||
|
|
||||||
|
### 增量同步(fetch)
|
||||||
|
|
||||||
|
```
|
||||||
|
定时任务触发 / 手动触发
|
||||||
|
→ 遍历该服务器下所有仓库:
|
||||||
|
1. repo.status = syncing
|
||||||
|
2. 解密 SSH 私钥到内存
|
||||||
|
3. git fetch --all
|
||||||
|
4. 对比 refs 变化,计算新增提交数
|
||||||
|
5. 记录 sync_log
|
||||||
|
6. repo.status = synced / failed
|
||||||
|
```
|
||||||
|
|
||||||
|
## 前端页面
|
||||||
|
|
||||||
|
### 页面布局
|
||||||
|
|
||||||
|
```
|
||||||
|
┌──────────────────────────────────────────────────┐
|
||||||
|
│ Git Manager [状态] [≡] │
|
||||||
|
├────────┬─────────────────────────────────────────┤
|
||||||
|
│ 仪表盘 │ │
|
||||||
|
│ 服务器 │ 主内容区 │
|
||||||
|
│ 仓库 │ │
|
||||||
|
│ 同步记录 │ │
|
||||||
|
│ SSH密钥 │ │
|
||||||
|
│ 系统设置 │ │
|
||||||
|
├────────┴─────────────────────────────────────────┤
|
||||||
|
│ 上次同步: 2026-03-30 14:00 | 下次: 16:00 | 共 42 仓库 │
|
||||||
|
└──────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 页面功能
|
||||||
|
|
||||||
|
**仪表盘:** 服务器数量、仓库总数、同步状态统计(synced/failed/syncing)、最近 5 条同步记录、磁盘占用。
|
||||||
|
|
||||||
|
**服务器管理:** 添加/编辑/删除 Gitea 服务器,配置 URL、API Token、关联 SSH 密钥、同步计划(Cron 表达式),"测试连接"按钮验证配置有效性。
|
||||||
|
|
||||||
|
**仓库列表:** 按服务器分组展示,显示同步状态(标签颜色区分)、最后同步时间。支持搜索过滤。每行有"手动同步"按钮。
|
||||||
|
|
||||||
|
**同步记录:** 时间线形式展示同步日志,支持按状态(成功/失败)筛选,展开查看新增提交数和错误详情。
|
||||||
|
|
||||||
|
**SSH 密钥:** 上传私钥文件或粘贴内容,显示密钥指纹和关联服务器数,删除时检查是否有关联服务器。
|
||||||
|
|
||||||
|
**系统设置:** API Token 管理、全局仓库存储根路径、调度全局开关(暂停/恢复所有定时任务)。
|
||||||
|
|
||||||
|
## 安全设计
|
||||||
|
|
||||||
|
| 项 | 方案 |
|
||||||
|
|----|------|
|
||||||
|
| 私钥存储 | AES-256 加密后存入 SQLite,加密密钥从环境变量 `GM_ENCRYPT_KEY` 读取 |
|
||||||
|
| Gitea Token | 同样 AES-256 加密存储 |
|
||||||
|
| API 认证 | Bearer Token,配置在环境变量 `GM_API_TOKEN` |
|
||||||
|
| SSH 连接 | paramiko 使用内存中的解密私钥,不写入磁盘临时文件 |
|
||||||
|
| 输入校验 | Pydantic 模型自动校验所有 API 入参 |
|
||||||
|
|
||||||
|
## 环境变量
|
||||||
|
|
||||||
|
| 变量 | 必填 | 默认值 | 说明 |
|
||||||
|
|------|------|--------|------|
|
||||||
|
| GM_ENCRYPT_KEY | 是 | - | AES-256 加密密钥(32字节) |
|
||||||
|
| GM_API_TOKEN | 是 | - | API 认证 Token |
|
||||||
|
| GM_DATA_DIR | 否 | ./data | 数据存储根目录 |
|
||||||
|
| GM_HOST | 否 | 0.0.0.0 | 监听地址 |
|
||||||
|
| GM_PORT | 否 | 8000 | 监听端口 |
|
||||||
|
|
||||||
|
## 部署方式
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 安装后端依赖
|
||||||
|
pip install -r backend/requirements.txt
|
||||||
|
|
||||||
|
# 构建前端
|
||||||
|
cd frontend && npm install && npm run build
|
||||||
|
# 构建产物自动输出到 backend/app/static/
|
||||||
|
|
||||||
|
# 配置环境变量
|
||||||
|
export GM_ENCRYPT_KEY=<your-encryption-key>
|
||||||
|
export GM_API_TOKEN=<your-api-token>
|
||||||
|
|
||||||
|
# 初始化数据库
|
||||||
|
python -m backend.init_db
|
||||||
|
|
||||||
|
# 启动服务
|
||||||
|
uvicorn backend.app.main:app --host 0.0.0.0 --port 8000
|
||||||
|
```
|
||||||
|
|
||||||
|
## MVP 交付范围
|
||||||
|
|
||||||
|
### 包含
|
||||||
|
|
||||||
|
- 多 Gitea 服务器管理(增删改查)
|
||||||
|
- SSH 密钥上传和管理
|
||||||
|
- 拉取服务器所有仓库列表
|
||||||
|
- 仓库 clone/fetch 同步
|
||||||
|
- 手动触发同步
|
||||||
|
- 定时自动同步(APScheduler + Cron)
|
||||||
|
- 同步历史记录查看
|
||||||
|
- 提交历史查看
|
||||||
|
- REST API(版本化,供外部集成)
|
||||||
|
- API Token 认证
|
||||||
|
- Vue 3 Web 管理界面
|
||||||
|
|
||||||
|
### 不包含(后续迭代)
|
||||||
|
|
||||||
|
- 多用户 / 权限系统
|
||||||
|
- Webhook 实时推送
|
||||||
|
- GitLab / GitHub 支持
|
||||||
|
- Docker 容器化部署
|
||||||
|
- 仓库内容浏览(文件树)
|
||||||
22
frontend/package.json
Normal file
22
frontend/package.json
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"name": "git-manager-frontend",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "vite build",
|
||||||
|
"preview": "vite preview"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"vue": "^3.4.15",
|
||||||
|
"vue-router": "^4.2.5",
|
||||||
|
"pinia": "^2.1.7",
|
||||||
|
"axios": "^1.6.5",
|
||||||
|
"element-plus": "^2.5.4",
|
||||||
|
"@element-plus/icons-vue": "^2.3.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@vitejs/plugin-vue": "^5.0.3",
|
||||||
|
"vite": "^5.0.11"
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user