- 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>
15 KiB
15 KiB
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 | 监听端口 |
部署方式
# 安装后端依赖
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 容器化部署
- 仓库内容浏览(文件树)