Initial commit: KPI Management System Backend

Features:
- FastAPI backend with JWT authentication
- MySQL database with SQLAlchemy ORM
- KPI workflow: draft → pending → approved → evaluation → completed
- Ollama LLM API integration for AI features
- Gitea API integration for version control
- Complete API endpoints for KPI, dashboard, notifications

Tables: KPI_D_* prefix naming convention

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-11 16:20:57 +08:00
commit f810ddc2ea
48 changed files with 4950 additions and 0 deletions

166
app/api/gitea.py Normal file
View File

@@ -0,0 +1,166 @@
"""
Gitea API
"""
from typing import Optional
from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel
from app.api.deps import get_current_user, get_current_admin
from app.models.employee import Employee
from app.services.gitea_service import gitea_service, create_kpi_management_repo
router = APIRouter(prefix="/api/gitea", tags=["Gitea"])
class CreateRepoRequest(BaseModel):
"""建立 Repo 請求"""
name: str
description: Optional[str] = ""
private: bool = False
class CreateFileRequest(BaseModel):
"""建立檔案請求"""
repo_name: str
file_path: str
content: str
message: str = "Add file"
branch: str = "main"
@router.get("/user")
def get_user(current_user: Employee = Depends(get_current_admin)):
"""
取得 Gitea 使用者資訊
"""
return gitea_service.get_user()
@router.get("/repos")
def list_repos(current_user: Employee = Depends(get_current_admin)):
"""
列出所有 Repo
"""
repos = gitea_service.list_repos()
return {"repos": repos}
@router.get("/repos/{repo_name}")
def get_repo(
repo_name: str,
current_user: Employee = Depends(get_current_admin),
):
"""
取得 Repo 資訊
"""
return gitea_service.get_repo(repo_name)
@router.post("/repos")
def create_repo(
data: CreateRepoRequest,
current_user: Employee = Depends(get_current_admin),
):
"""
建立新的 Repo
"""
result = gitea_service.create_repo(
name=data.name,
description=data.description,
private=data.private,
)
if "error" in result:
raise HTTPException(status_code=400, detail=result["error"])
return result
@router.delete("/repos/{repo_name}")
def delete_repo(
repo_name: str,
current_user: Employee = Depends(get_current_admin),
):
"""
刪除 Repo
"""
result = gitea_service.delete_repo(repo_name)
if "error" in result:
raise HTTPException(status_code=400, detail=result["error"])
return {"message": f"Repo '{repo_name}' 已刪除"}
@router.post("/repos/kpi-management/init")
def init_kpi_repo(current_user: Employee = Depends(get_current_admin)):
"""
初始化 KPI Management Repo
"""
result = create_kpi_management_repo()
if "error" in result:
raise HTTPException(status_code=400, detail=result["error"])
return result
@router.get("/repos/{repo_name}/branches")
def list_branches(
repo_name: str,
current_user: Employee = Depends(get_current_admin),
):
"""
列出分支
"""
return gitea_service.list_branches(repo_name)
@router.get("/repos/{repo_name}/commits")
def list_commits(
repo_name: str,
branch: str = "main",
limit: int = 10,
current_user: Employee = Depends(get_current_admin),
):
"""
列出 Commits
"""
return gitea_service.list_commits(repo_name, branch, limit)
@router.post("/files")
def create_file(
data: CreateFileRequest,
current_user: Employee = Depends(get_current_admin),
):
"""
建立檔案
"""
result = gitea_service.create_file(
repo_name=data.repo_name,
file_path=data.file_path,
content=data.content,
message=data.message,
branch=data.branch,
)
if "error" in result:
raise HTTPException(status_code=400, detail=result["error"])
return result
@router.get("/repos/{repo_name}/files/{file_path:path}")
def get_file(
repo_name: str,
file_path: str,
current_user: Employee = Depends(get_current_admin),
):
"""
取得檔案內容
"""
return gitea_service.get_file(repo_name, file_path)