Skip to content

Latest commit

 

History

History
992 lines (824 loc) · 31.8 KB

File metadata and controls

992 lines (824 loc) · 31.8 KB

GraphNote - 代码架构设计文档

本文档基于当前实现代码(2026-01-18)描述 GraphNote 应用的完整架构设计。

目录

  1. 系统概述
  2. 技术栈
  3. 系统架构
  4. 数据模型
  5. 前端架构
  6. 后端架构
  7. 关键数据流
  8. API 端点
  9. 安全性设计

系统概述

GraphNote 是一个 AI 驱动的知识管理工具,通过关系图可视化帮助用户管理笔记和知识。

核心特性

  • 关系图可视化:使用 G6 库实现节点和边的交互式编辑
  • AI 文本分析:通过 OpenAI 兼容接口(可配置自定义 URL)自动从文本提取实体和关系
  • 笔记管理:富文本编辑、笔记 CRUD、版本控制
  • 用户认证:JWT 令牌认证,支持注册/登录
  • 数据导出:支持 JSON 和 CSV 格式的数据导出
  • 共享功能:每个笔记生成唯一 8 字符 ID 用于共享

系统架构图

┌─────────────────────────────────────────────────────────────┐
│                        客户端浏览器                              │
│                    (Vue 3 + TypeScript)                     │
│                                                             │
│  ┌──────────────────────────────────────────────────────┐  │
│  │              GraphNote Web 前端应用                   │  │
│  │  ┌────────────┐  ┌───────────┐  ┌──────────────┐   │  │
│  │  │   Views    │  │ Components│  │    Stores    │   │  │
│  │  │ (Pages)    │  │(UI/Graph) │  │  (Pinia)    │   │  │
│  │  └────────────┘  └───────────┘  └──────────────┘   │  │
│  │        ↓                 ↓              ↓            │  │
│  │  ┌──────────────────────────────────────────────┐   │  │
│  │  │         Services Layer (Axios)              │   │  │
│  │  │  - auth.ts                                   │   │  │
│  │  │  - notebook.ts                               │   │  │
│  │  │  - api.ts (拦截器、token 管理)               │   │  │
│  │  └──────────────────────────────────────────────┘   │  │
│  └──────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────┘
         │
         │ HTTP/JSON (REST API)
         │
┌─────────────────────────────────────────────────────────────┐
│                     后端 API 服务器                           │
│                  (Express + TypeScript)                    │
│                                                             │
│  ┌──────────────────────────────────────────────────────┐  │
│  │            Middleware Stack                          │  │
│  │  - helmet (安全头)                                   │  │
│  │  - cors (跨域)                                       │  │
│  │  - rate-limit (速率限制)                             │  │
│  │  - auth (JWT 验证)                                   │  │
│  │  - validation (Zod 数据验证)                         │  │
│  │  - errorHandler (统一错误处理)                       │  │
│  └──────────────────────────────────────────────────────┘  │
│         ↓                                                    │
│  ┌──────────────────────────────────────────────────────┐  │
│  │              Routes + Controllers                    │  │
│  │  ┌──────────────┐  ┌──────────────┐  ┌──────────┐   │  │
│  │  │  auth.ts     │  │ notebook.ts  │  │ graph.ts │   │  │
│  │  │  (注册/登录) │  │ (CRUD/导出)  │  │(AI分析)  │   │  │
│  │  └──────────────┘  └──────────────┘  └──────────┘   │  │
│  └──────────────────────────────────────────────────────┘  │
│         ↓                                                    │
│  ┌──────────────────────────────────────────────────────┐  │
│  │              Business Logic Layer                    │  │
│  │  - Controllers: 请求处理                            │  │
│  │  - Services: JWT、密码处理                          │  │
│  │  - Validation: 请求数据验证                         │  │
│  │  - LLM Integration: OpenAI 兼容 API              │  │
│  └──────────────────────────────────────────────────────┘  │
│         ↓                                                    │
│  ┌──────────────────────────────────────────────────────┐  │
│  │         Database Layer (Prisma ORM)                 │  │
│  │  - Schema: User, Notebook, Version                  │  │
│  │  - Relationships: 用户→笔记→版本                     │  │
│  │  - Indexes: userId, shareId for performance        │  │
│  └──────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────┘
         ↓
┌─────────────────────────────────────────────────────────────┐
│                    PostgreSQL 数据库                         │
│  - User 表:用户账户信息                                     │
│  - Notebook 表:笔记内容、关系图数据                         │
│  - Version 表:版本历史和变更追踪                           │
└─────────────────────────────────────────────────────────────┘

外部服务:
├── LLM 服务(OpenAI 兼容格式,LLM_BASE_URL 可配置)
└── 数据库服务
    └── PostgreSQL 服务

技术栈

前端

技术 版本 用途
Vue 3.5+ 核心框架
TypeScript 5.x 类型系统
Vite 7.x 构建工具
TailwindCSS 3.x 样式框架
Pinia 2.x 状态管理
Vue Router 4.x 路由管理
Axios 1.x HTTP 客户端
G6 5.x 图表可视化
Tiptap 2.x 富文本编辑

后端

技术 版本 用途
Express.js 4.x Web 框架
TypeScript 5.x 类型系统
Prisma 5.x ORM
PostgreSQL 14.x 数据库
JWT - 认证
Bcrypt - 密码加密
Zod - 数据验证

系统架构

3 层架构设计

┌─────────────────────────────────────────────────────────┐
│              Presentation Layer (展示层)                │
│  - Vue 组件(Views、Components)                        │
│  - Pinia Store(状态管理)                              │
│  - 路由管理(Vue Router)                              │
└─────────────────────────────────────────────────────────┘
                         ↓
┌─────────────────────────────────────────────────────────┐
│            Business Logic Layer (业务逻辑层)            │
│  - Services(API 调用、业务操作)                       │
│  - Controllers(请求处理)                             │
│  - Utils(JWT、密码等工具)                            │
└─────────────────────────────────────────────────────────┘
                         ↓
┌─────────────────────────────────────────────────────────┐
│          Data Access Layer (数据访问层)                │
│  - Prisma ORM(数据库交互)                            │
│  - PostgreSQL(数据存储)                              │
└─────────────────────────────────────────────────────────┘

前后端通信模式

前端 Axios Service
        ↓
HTTP Request + JWT Token (Authorization header)
        ↓
后端 Middleware Stack
├─ CORS 检查
├─ 身份验证 (auth.ts)
├─ 请求验证 (validation.ts)
└─ 速率限制
        ↓
Route Handler → Controller → Business Logic
        ↓
Prisma ORM → PostgreSQL
        ↓
Response JSON
        ↓
前端 Axios 拦截器处理
├─ 成功:数据保存到 Store
├─ 401 Unauthorized:清除 token,重定向到登录
└─ 其他错误:错误处理

数据模型

User 模型

User {
  id: String (CUID)           // 唯一标识符
  email: String @unique       // 邮箱(唯一)
  username: String @unique    // 用户名(唯一)
  password: String            // 加密密码 (bcrypt)
  avatar: String?             // 头像 URL(可选)
  createdAt: DateTime         // 创建时间
  updatedAt: DateTime         // 更新时间

  // 关系
  notebooks: Notebook[]       // 用户拥有的笔记
  versions: Version[]         // 用户创建的版本
}

Notebook 模型

Notebook {
  id: String (CUID)                   // 笔记唯一 ID
  shareId: String @unique             // 共享 ID(8 字符)
  title: String                       // 笔记标题
  description: String?                // 笔记描述
  content: String                     // 笔记内容(Markdown/HTML)
  userId: String (FK)                 // 所有者 ID
  graph: Json {                       // 关系图数据
    nodes: [{
      id: String                      // 节点唯一 ID
      label: String                   // 节点显示文本
      type: String                    // 节点类型 (concept/person/place/event/other)
      properties: Object              // 其他属性
    }]
    edges: [{
      id: String                      // 边唯一 ID
      source: String                  // 源节点 ID
      target: String                  // 目标节点 ID
      label: String?                  // 边标签
      type: String                    // 边类型
    }]
    layout: Object                    // 布局配置
  }
  isPublic: Boolean @default(false)   // 是否公开
  tags: String[]                      // 标签数组
  createdAt: DateTime                 // 创建时间
  updatedAt: DateTime                 // 更新时间

  // 关系
  user: User                          // 所有者
  versions: Version[]                 // 版本历史

  // 索引
  @@index([userId])
  @@index([shareId])
}

Version 模型

Version {
  id: String (CUID)                   // 版本唯一 ID
  notebookId: String (FK)             // 关联笔记 ID
  content: String                     // 该版本的内容
  graphSnapshot: Json                 // 该版本的图表数据快照
  action: String                      // 操作类型 (create/edit/delete)
  userId: String (FK)                 // 操作用户 ID
  createdAt: DateTime                 // 创建时间

  // 关系
  notebook: Notebook
  user: User

  // 索引
  @@index([notebookId])
  @@index([userId])
}

关系图示

User (1) ──→ (Many) Notebook
             ├─ id
             ├─ title
             ├─ content
             ├─ graph (nodes + edges)
             └─ shareId (用于分享)

User (1) ──→ (Many) Version
Notebook (1) ──→ (Many) Version

前端架构

目录结构

graphnote-web/src/
├── main.ts                        # 应用入口(Vue + Pinia + Router)
├── App.vue                        # 根组件
├── assets/                        # 静态资源
├── router/
│   └── index.ts                   # 路由配置和守卫
├── stores/                        # Pinia 状态管理
│   ├── user.ts                    # 用户认证状态(token + refreshToken)
│   └── notebook.ts                # 笔记列表和编辑状态
├── services/                      # API 服务层
│   ├── api.ts                     # Axios 配置、401 自动刷新 token 并重试
│   ├── auth.ts                    # 认证 API
│   └── notebook.ts                # 笔记 API
├── composables/                   # Vue 组合式函数
│   └── useNotification.ts         # 全局通知系统(模块级共享状态)
├── views/                         # 页面组件
│   ├── HomePage.vue               # 首页
│   ├── LoginPage.vue              # 登录页
│   ├── RegisterPage.vue           # 注册页
│   ├── NotebookPage.vue           # 笔记编辑页(主要功能页)
│   ├── SharePage.vue              # 公开分享页(只读,无需登录)
│   └── SettingsPage.vue           # 设置页
├── components/                    # 可复用组件
│   ├── NotificationCenter.vue     # 通知中心
│   ├── editor/
│   │   └── RichTextEditor.vue     # Tiptap 富文本编辑器
│   ├── graph/
│   │   ├── GraphContainer.vue     # G6 图表容器
│   │   ├── NodeEditModal.vue      # 节点编辑弹窗
│   │   ├── EdgeEditModal.vue      # 边编辑弹窗
│   │   ├── NodeTypeStyleEditor.vue# 节点类型样式编辑
│   │   ├── EdgeTypeStyleEditor.vue# 边类型样式编辑
│   │   └── ContextMenu.vue        # 右键菜单
│   └── [其他通用组件]
├── utils/                         # 工具函数
├── types/                         # TypeScript 类型定义
└── style.css                      # 全局样式

核心数据流

1. 用户认证流程

LoginPage
    ↓
authService.login(email, password)
    ↓
API POST /api/auth/login
    ↓
Backend: hash 验证 → 生成 JWT token
    ↓
Response: { token, user }
    ↓
localStorage.setItem('token', token)
apiClient 拦截器自动添加到所有请求头
    ↓
userStore.setUser(user)
    ↓
Router 重定向到 NotebookPage

2. 笔记加载流程

NotebookPage mounted
    ↓
notebookStore.loadNotebooks()
    ↓
API GET /api/notebooks
    ↓
Backend: Prisma 查询 User 的所有 Notebooks
    ↓
Response: Notebook[]
    ↓
notebookStore.setNotebooks(data)
    ↓
模板渲染笔记列表或显示当前笔记

3. AI 分析流程

NotebookPage - 用户输入文本
    ↓
点击 "解析关系图" 按钮
    ↓
notebookService.analyzeText(text)
    ↓
API POST /api/graphs/analyze { text }
    ↓
后端路由到 graphController.analyzeText()
    ↓
analyzeWithLLM(text)
    ↓
调用 OpenAI 兼容接口(LLM_BASE_URL 可指向官方或第三方服务)
    ↓
系统提示词:提取 3-5 个实体和 3-5 条关系
    ↓
LLM 返回 JSON: { nodes: [], edges: [] }
    ↓
enrichGraphDataWithIds(graphData)
├─ 剥离可能存在的 markdown 代码围栏
├─ 为每个 node 生成 id (node_1, node_2...)
├─ 建立 label → id 映射
├─ 为每条边生成 id
└─ 验证 edge 的 source/target 存在
    ↓
Response: graphData { nodes, edges }
    ↓
前端接收数据
    ↓
graphStore.updateGraph(graphData)
    ↓
G6 容器刷新显示新的图表

4. 笔记保存流程

用户编辑笔记或图表
    ↓
更改监听器触发
    ↓
notebookService.updateNotebook(shareId, { content, graph })
    ↓
API PUT /api/notebooks/:shareId
    ↓
Backend: authMiddleware 验证用户
    ↓
Backend: 权限检查 (userId == notebook.userId)
    ↓
Prisma 更新 notebook 记录
    ↓
创建 Version 记录(用于版本控制)
    ↓
Response: 更新后的 Notebook 对象
    ↓
前端 notebookStore 更新本地状态
    ↓
显示保存成功通知

状态管理结构

userStore (用户认证)

interface UserState {
  user: User | null
  token: string | null           // access token(1 小时)
  refreshToken: string | null    // refresh token(7 天)
  isAuthenticated: boolean
}

// 401 时 axios 拦截器自动调用 /auth/refresh 换新 token 并重试原请求
setUser(user)
setToken(token)
setRefreshToken(token)
logout()

notebookStore (笔记管理)

interface NotebookState {
  notebooks: Notebook[]
  currentNotebook: Notebook | null
  isLoading: boolean
  error: string | null
}

// saveNotebook 响应返回时校验 shareId 是否仍是当前笔记,
// 防止慢响应覆盖切换后的新笔记(竞态保护)
createNotebook()
loadNotebooks()
setCurrentNotebook(notebook)
updateCurrentNotebook(updates)
deleteNotebook(id)

graphStore / uiStore

已移除(原为空壳死代码)。图表状态由 GraphContainer 组件内部管理, UI 通知由 useNotification 的模块级共享状态管理。


后端架构

目录结构

backend/src/
├── main.ts                        # Express 应用入口
├── routes/                        # 路由定义
│   ├── auth.ts                    # 认证路由 (public + protected)
│   ├── notebooks.ts               # 笔记 CRUD 路由
│   ├── graphs.ts                  # 图表分析路由
│   └── shared.ts                  # 公开分享路由(无需认证)
├── controllers/                   # 请求处理器
│   ├── auth.ts                    # authController
│   ├── notebook.ts                # notebookController
│   └── graph.ts                   # graphController (LLM 集成)
├── middlewares/                   # 中间件
│   ├── auth.ts                    # JWT 验证中间件
│   ├── errorHandler.ts            # 全局错误处理
│   ├── validation.ts              # 请求验证(Zod)
├── utils/                         # 工具函数
│   ├── jwt.ts                     # JWT 生成/验证(access + refresh)
│   ├── password.ts                # 密码加密/比较
│   └── graph.ts                   # LLM 图数据校验/补全
├── schemas/                       # Zod 验证 schemas
│   └── validation.ts              # 所有验证规则
├── lib/
│   └── prisma.ts                  # Prisma 单例
└── prisma/
    ├── schema.prisma              # 数据库 Schema
    └── migrations/                # 数据库迁移文件

backend/tests/                     # vitest 单元测试(npm test)
├── graph.test.ts                  # 图数据校验/补全
├── jwt.test.ts                    # access/refresh token
└── validation.test.ts             # 输入校验边界

中间件栈(按执行顺序)

1. helmet()
   └─ 设置安全 HTTP 头

2. cors()
   └─ 处理跨域请求

3. rateLimit()
   └─ 全局限速(15min window, 600 requests max)
   └─ LLM 分析接口单独限速(15min window, 30 requests max)

4. express.json()
   └─ 解析 JSON body

5. express.urlencoded()
   └─ 解析 URL 编码数据

6. authMiddleware (selective)
   └─ 验证 JWT token(仅在受保护路由上)

7. validationMiddleware (selective)
   └─ 验证请求数据(Zod schemas)

8. routeHandlers
   └─ 实际的路由处理器

9. errorHandler
   └─ 全局错误处理

请求处理流程

HTTP Request
    ↓
Middleware Stack (helmet, cors, rate-limit)
    ↓
Body Parser (JSON, urlencoded)
    ↓
Route Matching
    ↓
authMiddleware (if protected)
├─ 提取 Authorization header 中的 token
├─ 使用 JWT 验证和解析
├─ 将 user 对象注入到 req
└─ 如果验证失败,返回 401
    ↓
validationMiddleware (if required)
├─ 使用 Zod schema 验证 req.body
├─ 如果验证失败,返回 400
└─ 继续处理
    ↓
Controller Handler
├─ 接收验证后的数据
├─ 处理业务逻辑
├─ 调用 Prisma 或外部 API
└─ 返回响应
    ↓
Response JSON
    ↓
errorHandler (if error)
├─ 捕获未处理的错误
├─ 标准化错误响应
└─ 记录日志
    ↓
HTTP Response

认证流程详解

注册

POST /api/auth/register
Body: { email, username, password }
    ↓
validationMiddleware 验证格式
    ↓
authController.register()
├─ 检查 email 和 username 是否已存在
├─ bcrypt 加密密码
├─ Prisma 创建 User 记录
├─ 生成 JWT token (payload: {userId, email})
└─ 返回 { user, token }

登录

POST /api/auth/login
Body: { email, password }
    ↓
authController.login()
├─ Prisma 查询 User by email
├─ 如果不存在,返回 401
├─ bcrypt 比较密码
├─ 如果不匹配,返回 401
├─ 生成新 JWT token
└─ 返回 { user, token }

受保护的路由

GET /api/notebooks
Header: { Authorization: "Bearer {token}" }
    ↓
authMiddleware
├─ 提取 token 从 header
├─ jwt.verify(token)
├─ 解析 payload 得到 userId
├─ 将 { userId, email } 注入到 req.user
└─ 继续处理
    ↓
notebookController.listNotebooks()
├─ 使用 req.user.userId 查询笔记
└─ 返回该用户的所有笔记

控制器功能说明

authController

函数 功能 认证
register 用户注册
login 用户登录
getCurrentUser 获取当前用户信息
logout 用户登出

notebookController

函数 功能 认证
createNotebook 创建新笔记
listNotebooks 列出用户的所有笔记
getNotebook 获取单个笔记详情
updateNotebook 更新笔记内容或图表
deleteNotebook 删除笔记
getLatestNotebook 获取最新笔记
exportNotebook 导出笔记(JSON/CSV)

graphController

函数 功能 认证
analyzeText AI 文本分析,生成图表数据

LLM 集成详解

后端通过 OpenAI 兼容格式(POST {LLM_BASE_URL}/chat/completions)调用 LLM, 可指向官方 API 或任何兼容该格式的第三方服务,通过三个环境变量配置:

  • LLM_API_KEY:API 密钥(必填)
  • LLM_BASE_URL:接口地址(默认 https://api.openai.com/v1
  • LLM_MODEL:模型名称(默认 gpt-4.1-nano

调用流程

analyzeText(text)
    ↓
analyzeWithLLM(text)
├─ 构建 systemPrompt
│  └─ "你是一个知识图谱构建专家..."
│     "提取 3-5 个主要实体和 3-5 条关系"
├─ API 调用: {LLM_BASE_URL}/chat/completions
├─ Model: LLM_MODEL 环境变量(默认 gpt-4.1-nano)
├─ Timeout: 30s
├─ Temperature: 0.7
├─ Max tokens: 1000
└─ Headers: Authorization: Bearer {LLM_API_KEY}
    ↓
LLM 返回 JSON response
├─ stripCodeFences:剥离可能携带的 markdown 代码围栏
├─ 解析 JSON 字符串
└─ catch 错误 → 返回 "Invalid response format"
    ↓
enrichGraphDataWithIds(graphData)(src/utils/graph.ts)
├─ 节点缺 id 时生成 node_N
├─ 边 source/target 先按 id 匹配、再按 label 匹配
├─ 过滤悬空边、重名 label 保留第一个并告警
└─ 边缺 id 时生成 edge_N
    ↓
Response: graphData with ids

关键数据流

完整用户操作流程

1. 用户打开应用
   ↓
2. 检查 localStorage 中的 token
   ├─ 如果存在:自动登录(获取用户信息)
   └─ 如果不存在:重定向到 LoginPage

3. 登录成功
   ↓
4. 进入 NotebookPage
   ↓
5. 加载笔记列表
   ├─ API GET /api/notebooks
   └─ 显示笔记列表或创建新笔记

6. 选择或创建笔记
   ├─ 如果创建:API POST /api/notebooks
   └─ 如果选择:加载笔记内容和图表

7. 编辑笔记文本
   ├─ RichTextEditor 组件处理编辑
   └─ 保存到 notebookStore

8. 点击 "解析关系图"
   ├─ 收集文本内容
   ├─ API POST /api/graphs/analyze
   ├─ 后端调用 LLM API
   └─ 返回 { nodes, edges }

9. 更新图表显示
   ├─ G6 容器接收新数据
   └─ 渲染可交互的图表

10. 编辑图表(可选)
    ├─ 拖拽节点
    ├─ 修改节点/边属性
    └─ 删除节点/边

11. 保存笔记
    ├─ 收集最新的 content 和 graph
    ├─ API PUT /api/notebooks/:shareId
    ├─ 后端创建 Version 记录
    └─ 显示保存成功

12. 导出笔记(可选)
    ├─ API GET /api/notebooks/:shareId/export?format=json
    ├─ 后端返回导出数据
    └─ 前端下载文件

13. 登出
    ├─ 清除 localStorage token
    ├─ 重置所有 stores
    └─ 重定向到 LoginPage

API 端点

认证端点

POST /api/auth/register
  请求: { email, username, password }
  响应: { user, token }
  认证: ✗

POST /api/auth/login
  请求: { email, password }
  响应: { user, token }
  认证: ✗

GET /api/auth/me
  响应: { user }
  认证: ✓

POST /api/auth/logout
  响应: { message }
  认证: ✓

POST /api/auth/refresh
  请求: { refreshToken }
  响应: { token, refreshToken }(签发新的 access/refresh token;JWT 无状态,旧 refresh token 在过期前仍有效)
  认证: ✗

笔记端点

POST /api/notebooks
  请求: { title?, content?, description? }
  响应: { Notebook }
  认证: ✓

GET /api/notebooks
  查询参数: page?, limit?
  响应: { notebooks: [Notebook] }
  认证: ✓

GET /api/notebooks/:shareId
  响应: { Notebook }
  认证: ✓

PUT /api/notebooks/:shareId
  请求: { title?, content?, graph?, description?, isPublic?, tags? }
  响应: { Notebook }
  认证: ✓

DELETE /api/notebooks/:shareId
  响应: { message }
  认证: ✓

GET /api/notebooks/:shareId/export/json
  响应: 笔记完整数据(带下载头)
  认证: ✓

GET /api/notebooks/:shareId/export/csv/nodes
GET /api/notebooks/:shareId/export/csv/edges
  响应: CSV 文件(带 UTF-8 BOM)
  认证: ✓

GET /api/notebooks/:shareId/versions
  响应: { versions: [{id, action, createdAt, userId}] }
  认证: ✓

GET /api/notebooks/latest/fetch
  响应: { Notebook } 或 null(无笔记时)
  认证: ✓

GET /api/shared/:shareId
  响应: { Notebook }(仅当 isPublic=true,否则 404)
  认证: ✗(公开分享端点)

图表端点

POST /api/graphs/analyze
  请求: { text }
  响应: { nodes, edges }
  认证: ✓
  说明: 使用 LLM 分析文本生成知识图谱

安全性设计

认证安全

  • 密码加密:使用 bcryptjs,盐轮数为 10
  • JWT 令牌
    • Access Token 有效期:1 小时
    • Refresh Token 有效期:7 天
    • 密钥存储在 .env 文件中
    • Token 中包含 userId 和 email

请求验证

  • Zod Schema 验证

    • 注册/登录:验证邮箱格式、密码长度
    • 笔记操作:验证标题、内容类型
    • 图表分析:验证文本长度和格式
  • 中间件验证链

    HTTP Request
      → Helmet (安全头)
      → CORS (跨域检查)
      → Rate Limit (速率限制)
      → Body Parse
      → Auth (JWT验证)
      → Validation (Zod schema)
      → Handler
    

权限控制

  • 用户隔离

    • 笔记只能由所有者访问和修改
    • 每个笔记 CRUD 操作都检查 userId
    • 版本记录关联到用户
  • SQL 注入防护

    • Prisma ORM 使用参数化查询
    • 无原生 SQL 查询

XSS 防护

  • Vue 3 自动转义

    • 所有模板插值 {{ }} 自动转义
    • 仅在必要时使用 v-html
  • Tiptap 内容清理

    • 富文本编辑器清理 HTML 内容
    • 防止恶意脚本注入

CORS 配置

cors({
  origin: process.env.CORS_ORIGIN || 'http://localhost:5173',
  credentials: true  // 允许发送 cookie
})

速率限制

  • 全局:15 分钟窗口内限制 600 个请求(适配前端自动保存频率)
  • LLM 分析接口POST /api/graphs/analyze 单独限制 30 个请求/15 分钟,防止 API 费用被刷

扩展和优化建议

短期优化

  1. 数据库优化

    • 添加更多索引(如 email, username)
    • 实现查询缓存
  2. API 性能

    • 实现分页(笔记列表)
    • 添加响应压缩
  3. 错误处理

    • 更细粒度的错误代码
    • 详细的错误日志

中期扩展

  1. 多用户协作

    • WebSocket 实时同步
    • CRDT 冲突解决
    • 权限管理(OWNER/EDITOR/VIEWER)
  2. 高级功能

    • 笔记搜索和全文索引
    • AI 自动标签
    • 关系强度计算
  3. 数据导入导出

    • Markdown 导入
    • Obsidian 同步
    • Neo4j 导出

长期展望

  1. 离线支持

    • IndexedDB 本地存储
    • Service Worker 缓存
  2. 移动应用

    • React Native 客户端
    • 移动特定的 UI 优化
  3. 企业功能

    • SAML/OAuth 认证
    • 审计日志
    • 数据备份和恢复

总结

GraphNote 采用前后端分离、三层架构、微服务就绪的设计模式,具有:

  • 清晰的职责划分:表示层、业务逻辑层、数据访问层
  • 强大的安全机制:JWT 认证、请求验证、权限控制
  • 灵活的 LLM 集成:OpenAI 兼容格式,接口地址和模型均可配置
  • 完整的错误处理:全局中间件、异常捕获
  • 可扩展的架构:预留多用户协作、实时同步、高级搜索等扩展点

通过 Pinia Store 和 Composition API,前端实现了响应式的状态管理和复用逻辑。后端通过 Express 中间件栈和 Prisma ORM,提供了安全、高效的 API 服务。整个系统具有良好的可维护性和扩展性。