feat: v0.3.1 — Go/Gin 后端重写 + gh-ost 集成

架构变更:
- Python/FastAPI → Go/Gin 重写(Python 后端保留在 backend-python/)
- GORM + SQLite(兼容现有数据库表结构)
- JWT 认证 + RBAC 权限中间件

Go 后端结构:
- cmd/server/main.go — 入口,端口 9000
- config/config.go — 环境变量配置
- internal/model/ — GORM 模型(30张表,完全兼容 SQLite)
- internal/handler/ — auth/instance/ticket/dashboard/ghost handler
- internal/middleware/ — JWT 认证 + CORS
- internal/ghost/ — gh-ost 集成模块(同步/异步执行,任务管理)
- router/router.go — API 路由注册(/api/v1/...)

gh-ost 集成:
- RunGhOst() 同步执行
- RunGhOstAsync() 异步执行 + 进度追踪
- TaskManager 管理多个并发任务
- API: POST /ghost/dry-run, /ghost/execute, GET /ghost/status/:taskId

核心 API 已对齐:
- POST /auth/login (JWT)
- GET /dashboard/stats, /dashboard/my-tickets
- GET /tickets/statistics, CRUD + approve/execute
- GET/POST/PUT/DELETE /instances
- GET /users, /audit-rules, /announcements, /settings

已验证:
- 登录 admin/admin123 ✅
- Dashboard 99工单/110查询/4实例 ✅
- 工单统计按角色过滤 ✅
This commit is contained in:
logan committed 2026-05-25 21:40:54 +08:00
1 parent 43d1f3a234
commit ca308e277d
202 files changed
+2265 -51181

No files matched your search

+68
View File
@@ -0,0 +1,68 @@
package handler
import (
"net/http"
"sql-platform/internal/middleware"
"sql-platform/internal/model"
"github.com/gin-gonic/gin"
)
// GET /api/v1/dashboard/stats
func DashboardStats(c *gin.Context) {
var ticketCount, queryCount, instanceCount int64
model.DB.Model(&model.Ticket{}).Count(&ticketCount)
model.DB.Model(&model.QueryHistory{}).Count(&queryCount)
model.DB.Model(&model.Instance{}).Count(&instanceCount)
c.JSON(http.StatusOK, gin.H{
"ticket_count": ticketCount,
"query_count": queryCount,
"instance_count": instanceCount,
})
}
// GET /api/v1/dashboard/my-tickets
func MyTickets(c *gin.Context) {
userID, _, role := middleware.GetCurrentUser(c)
var tickets []model.Ticket
query := model.DB.Order("id DESC").Limit(10)
switch role {
case "admin":
// Admin sees all pending/executing tickets
query = query.Where("status IN ?", []string{"pending", "reviewing", "executing"})
case "dba", "auditor":
// DBA sees their own + pending approval
query = query.Where(
"(applicant_id = ? AND status IN ?) OR (id IN (SELECT ticket_id FROM ticket_approvals WHERE approver_id = ?) AND status IN ?)",
userID, []string{"pending", "executing"},
userID, []string{"pending", "reviewing", "executing"},
)
default: // developer
query = query.Where("applicant_id = ?", userID)
}
query.Find(&tickets)
type ticketWithRelation struct {
model.Ticket
Relation string `json:"relation"` // "submitted" or "pending_approval"
}
var result []ticketWithRelation
for _, t := range tickets {
rel := "submitted"
if t.ApplicantID != userID {
rel = "pending_approval"
}
result = append(result, ticketWithRelation{Ticket: t, Relation: rel})
}
if result == nil {
result = []ticketWithRelation{}
}
c.JSON(http.StatusOK, result)
}