Files
pj0235-eai_agentplatform/docs/02_Architecture/AR01_Backend_Arch.md
T
eaiadminandClaude Code 16d63de4e1 chore: 工作台产品化进行中的改动
把工作区里其余在制品一并入库,主要是工作台产品化的推进:

  后端:新增 capability_definition / project / my_app_center / office_skill
        接口与 action_definition / skill_definition / project / user_app_center
        模型,config 加路由健康上报。
  前端:新增 frontend/src/skills(Office 技能与 workbuddy 复刻)、
        项目管理、应用中心、能力目录页,以及配套 api / store / config;
        聊天侧新增 SpecialistChip / SpecialistPanel / SkillStrip / AppChatRail
        等组件。
  清理:移除旧 views/tools 下的单页工具(已并入工作台)、_frozen 冻结组件、
        cmd/inspect_oa_debug 调试入口,以及两份调试笔记。
  其它:文档与启动脚本同步。

(这批改动与上一提交的 SY23 工作并行进行,此前已在同一工作区内交织。)

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-17 21:32:35 +08:00

7.1 KiB
Raw Blame History

AR01 — 后端架构设计

版本:V2.0 | 框架:Go + Gin + GORM + SQLite(modernc) 参考:eai_agentplatform/backend-go/internal/api/ + internal/model/ + internal/store/

当前实现:Go 单二进制 + systemd + Clonezilla 整盘克隆,backend-go/internal/ 为标准源码布局。


1. 架构分层

┌─────────────────────────────────────────────┐
│              API 路由层 (api/)                │
│  auth / company_train / product / course     │
│  exam / media / ai_chat / system             │
├─────────────────────────────────────────────┤
│            Gin Context + 请求/响应结构体      │
│  web.OK / web.Fail 统一响应                  │
├─────────────────────────────────────────────┤
│             业务逻辑 (api/ 内函数)             │
│  exam.go / media.go / ai_chat.go            │
├─────────────────────────────────────────────┤
│         GORM 模型层 (model/)                 │
│  User / Product / Course / MediaFile / ...    │
├─────────────────────────────────────────────┤
│         数据库层 (store/)                    │
│  db.go: SQLite Init + AutoMigrate           │
├─────────────────────────────────────────────┤
│           SQLite + data/media                │
└─────────────────────────────────────────────┘

2. 目录结构

backend-go/
├── cmd/
│   └── server.go              # 入口:gin.Engine + systemd 裸进程
├── internal/
│   ├── api/                   # 路由层(Gin handlers)
│   │   ├── auth.go            # /api/auth/* — 登录/注册/me
│   │   ├── company_train.go   # /api/company-train/*
│   │   ├── product.go         # /api/products/*
│   │   ├── exam.go            # /api/exam/* — 题库/组卷/考试/记录
│   │   ├── media.go           # /api/media/* — 上传/预览/审批
│   │   ├── ai_chat.go         # /api/ai-chat/* — PathCoach SSE
│   │   ├── system.go          # /api/system/* — 用户/成绩/配置
│   │   ├── router.go          # RegisterRoutes 总路由
│   │   └── (其余为功能模块)
│   ├── model/                 # GORM 模型
│   │   ├── user.go
│   │   ├── product.go
│   │   ├── course.go
│   │   ├── media_file.go
│   │   ├── knowledge_chunk.go
│   │   ├── question.go
│   │   ├── exam_paper.go
│   │   └── exam_record.go
│   ├── store/                 # 数据库层
│   │   └── db.go              # SQLite Init + AutoMigrate
│   ├── ai/                    # AI 客户端与检索
│   │   ├── llm.go             # OpenAI 兼容 LLM 调用
│   │   └── retrieve.go        # 知识检索
│   ├── config/                # 配置加载
│   └── middleware/            # 中间件(JWT 认证等)
├── knowledge_source/          # 知识源 Markdown(运行时)
├── data/                      # 运行时数据(db+media,git 忽略)
└── deploy/                    # systemd 单元 + DELIVERY.md

3. 应用装配模式(RegisterRoutes)

入口 cmd/server.go 创建 gin.Engine,调用 api.RegisterRoutes 注册全部路由:

// backend-go/cmd/server.go
package main

import (
    "github.com/gin-gonic/gin"
    "eai_agentplatform/backend/internal/api"
    "eai_agentplatform/backend/internal/config"
)

func main() {
    cfg := config.Load()
    r := gin.Default()

    // 公开静态文件(已审批素材)
    r.Static("/media", cfg.KBDataDir+"/approved")

    // 注册全部路由
    api.RegisterRoutes(r, cfg)

    r.Run(":8080")
}

路由注册(api/router.go):

// api/router.go
func RegisterRoutes(r *gin.Engine, cfg *config.Config) {
    // 健康检查
    r.GET("/api/health", HealthCheck)

    // 公开 + 员工
    r.GET("/api/company-train", middleware.Auth(cfg), GetCompanyTrain)
    r.GET("/api/specialists", middleware.Auth(cfg), ListSpecialists)

    // 员工端考试
    r.GET("/api/exam/list", middleware.Auth(cfg), ExamList)
    r.GET("/api/exam/cover", middleware.Auth(cfg), ExamCover)
    r.POST("/api/exam/start", middleware.Auth(cfg), ExamStart)
    r.POST("/api/exam/submit", middleware.Auth(cfg), ExamSubmit)

    // 管理员
    admin := r.Group("/api").Use(middleware.Auth(cfg), middleware.RequireAdmin())
    {
        admin.POST("/products", CreateProduct)
        admin.POST("/courses", CreateCourse)
        admin.POST("/media/audit/:mediaId", AuditMedia)
        admin.POST("/knowledge/scan", KnowledgeScan)
        admin.GET("/system/users", ListUsers)
        admin.GET("/system/config", GetConfig)
        admin.GET("/system/exam-records", ListExamRecords)
    }

    // AI 对话
    r.POST("/api/ai-chat/message", middleware.Auth(cfg), ChatMessage)
    r.GET("/api/ai-chat/quick-actions", middleware.Auth(cfg), QuickActions)
}

4. 中间件模式

// internal/middleware/auth.go
func Auth(cfg *config.Config) gin.HandlerFunc {
    return func(c *gin.Context) {
        claims, err := auth.ParseToken(
            c.GetHeader("Authorization"), cfg.JWTSecret,
        )
        if err != nil {
            c.JSON(401, gin.H{"error": "unauthorized"})
            c.Abort()
            return
        }
        c.Set("user", claims)
        c.Next()
    }
}

func RequireAdmin() gin.HandlerFunc {
    return func(c *gin.Context) {
        user := c.MustGet("user").(jwt.MapClaims)
        if role, ok := user["role"].(string); !ok || role != "admin" {
            c.JSON(403, gin.H{"error": "forbidden"})
            c.Abort()
            return
        }
        c.Next()
    }
}

5. API 路由前缀

路由前缀 模块 说明
/api/auth/* auth.go 登录/注册/当前用户
/api/company-train/* company_train.go 公司介绍内容
/api/products/* product.go 产品 CRUD + 导入
/api/courses/* courses.go 课程 CRUD + 绑定产品
/api/exam/* exam.go 题库/组卷/考试/记录
/api/media/* media.go 上传/预览/审批/状态
/api/ai-chat/* ai_chat.go PathCoach 流式对话
/api/system/* system.go 用户/成绩/配置
/api/health — 健康检查

6. 单二进制交付

CGO_ENABLED=0 go build -o bin/eai_agentplatform-server ./cmd/server
# 输出:statically linked,无运行时依赖

部署:systemd 直接拉起单二进制,data/ 目录下 SQLite 数据库自动建表。