# NovaBlog 开发者文档 本文档面向希望深度定制 NovaBlog 的开发者,详细介绍系统架构、API 接口、数据库结构以及扩展开发指南。 --- ## 目录 1. [系统架构](#系统架构) 2. [项目结构](#项目结构) 3. [API 接口文档](#api-接口文档) 4. [数据库结构](#数据库结构) 5. [前端组件开发](#前端组件开发) 6. [后端服务扩展](#后端服务扩展) 7. [部署配置](#部署配置) 8. [性能优化](#性能优化) --- ## 系统架构 NovaBlog 采用 **静态渲染 + 轻量级微服务** 的解耦架构: ``` ┌─────────────────────────────────────────────────────────────┐ │ 用户浏览器 │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ Nginx 反向代理 │ │ (静态文件服务 + API 请求转发) │ └─────────────────────────────────────────────────────────────┘ │ │ ▼ ▼ ┌─────────────────────┐ ┌──────────────────────────┐ │ 静态文件 (CDN) │ │ API Server (Go) │ │ HTML/CSS/JS/图片 │ │ - 用户认证 │ │ │ │ - 评论管理 │ │ 构建时生成 │ │ - 点赞系统 │ └─────────────────────┘ │ - SQLite 数据库 │ └──────────────────────────┘ ``` ### 技术栈 | 层级 | 技术 | 说明 | |------|------|------| | 前端框架 | Astro 5.x | Islands Architecture,零 JS 默认输出 | | UI 组件 | Vue 3 | 交互式岛屿组件 | | 样式方案 | Tailwind CSS 4.x | 原子化 CSS | | 后端框架 | Go + Gin | 极致轻量,内存占用 < 20MB | | 数据库 | SQLite | 文件型数据库,无需额外服务 | | 认证方案 | JWT | 无状态认证 | ### 架构优势 1. **极致性能**:静态页面零运行时,JS 按需加载 2. **低资源占用**:Go 服务 + SQLite 可在 512MB 内存环境运行 3. **SEO 友好**:纯静态 HTML 输出,搜索引擎完美抓取 4. **开发体验**:组件化开发,热重载支持 --- ## 项目结构 ``` NovaBlog/ ├── src/ # 前端源码 │ ├── components/ # Vue/Astro 组件 │ │ ├── CommentSection.vue # 评论区组件 │ │ ├── LikeButton.vue # 点赞按钮 │ │ ├── LoginForm.vue # 登录表单 │ │ ├── UserStatus.vue # 用户状态栏 │ │ ├── Counter.vue # 计数器示例 │ │ ├── TypstBlock.astro # Typst 渲染组件 │ │ └── TableOfContents.astro # 目录组件 │ ├── content/ # 内容集合 │ │ ├── config.ts # 内容配置 │ │ └── blog/ # 博客文章 │ ├── layouts/ # 布局组件 │ │ ├── BaseLayout.astro # 基础布局 │ │ └── PostLayout.astro # 文章布局 │ ├── pages/ # 页面路由 │ │ ├── index.astro # 首页 │ │ ├── login.astro # 登录页 │ │ ├── blog/ # 博客相关页面 │ │ ├── tags/ # 标签页面 │ │ └── categories/ # 分类页面 │ ├── styles/ # 全局样式 │ │ └── global.css # CSS 变量和全局样式 │ ├── env.d.ts # 类型声明 │ └── mdx-components.ts # MDX 组件注册 ├── public/ # 静态资源 │ ├── images/ # 图片资源 │ └── favicon.svg # 网站图标 ├── server/ # 后端服务 │ ├── cmd/server/main.go # 服务入口 │ ├── internal/ # 内部模块 │ │ ├── config/ # 配置管理 │ │ ├── database/ # 数据库连接 │ │ ├── handlers/ # HTTP 处理器 │ │ ├── middleware/ # 中间件 │ │ ├── models/ # 数据模型 │ │ └── utils/ # 工具函数 │ ├── data/ # 数据文件 (SQLite) │ ├── migrations/ # 数据库迁移 │ ├── Dockerfile # Docker 构建文件 │ └── go.mod # Go 依赖 ├── docs/ # 文档 ├── astro.config.mjs # Astro 配置 ├── tailwind.config.mjs # Tailwind 配置 ├── docker-compose.yml # Docker Compose 配置 ├── nginx.conf # Nginx 配置 └── package.json # NPM 依赖 ``` --- ## API 接口文档 ### 基础信息 - **Base URL**: `http://localhost:8080/api` - **认证方式**: JWT Bearer Token - **内容格式**: JSON ### 认证接口 #### 注册用户 ```http POST /api/auth/register Content-Type: application/json { "username": "string", // 必填,3-50字符 "email": "string", // 必填,有效邮箱 "password": "string", // 必填,6-50字符 "nickname": "string" // 可选 } ``` **响应**: ```json { "token": "eyJhbGciOiJIUzI1NiIs...", "user": { "id": 1, "username": "testuser", "email": "test@example.com", "nickname": "测试用户", "role": "user", "created_at": "2024-01-15T10:00:00Z" } } ``` **错误码**: - `400`: 请求参数无效 - `409`: 用户名或邮箱已存在 #### 用户登录 ```http POST /api/auth/login Content-Type: application/json { "username": "string", // 用户名或邮箱 "password": "string" } ``` **响应**: 同注册接口 #### 获取当前用户 ```http GET /api/auth/me Authorization: Bearer ``` **响应**: ```json { "user": { "id": 1, "username": "testuser", "email": "test@example.com", "nickname": "测试用户", "avatar": "https://...", "bio": "个人简介", "role": "user" } } ``` #### 更新用户资料 ```http PUT /api/auth/profile Authorization: Bearer Content-Type: application/json { "nickname": "string", "avatar": "string", "bio": "string" } ``` ### 评论接口 #### 获取文章评论 ```http GET /api/comments?post_id={post_id}&page=1&page_size=20 ``` **参数**: - `post_id` (必填): 文章 ID - `page` (可选): 页码,默认 1 - `page_size` (可选): 每页数量,默认 20,最大 100 **响应**: ```json { "data": [ { "id": 1, "post_id": "hello-novablog", "user_id": 1, "content": "很棒的文章!", "status": "approved", "created_at": "2024-01-15T10:00:00Z", "user": { "id": 1, "username": "testuser", "nickname": "测试用户", "avatar": "https://..." }, "replies": [ { "id": 2, "parent_id": 1, "content": "感谢支持!", "user": {...} } ] } ], "pagination": { "page": 1, "page_size": 20, "total": 100, "total_page": 5 } } ``` #### 创建评论 ```http POST /api/comments Authorization: Bearer Content-Type: application/json { "post_id": "string", // 必填 "content": "string", // 必填,1-2000字符 "parent_id": 1 // 可选,回复的评论ID } ``` #### 删除评论 ```http DELETE /api/comments/:id Authorization: Bearer ``` **权限**: 本人或管理员可删除 ### 点赞接口 #### 切换点赞状态 ```http POST /api/likes/toggle Content-Type: application/json Authorization: Bearer // 可选 { "post_id": "string" // 必填 } ``` **响应**: ```json { "liked": true, // 当前是否已点赞 "like_count": 42 // 文章总点赞数 } ``` **说明**: - 已登录用户:基于 user_id 判断 - 未登录用户:基于 IP Hash 判断(加盐防反向推导) #### 获取点赞状态 ```http GET /api/likes/status?post_id={post_id} Authorization: Bearer // 可选 ``` **响应**: 同切换接口 ### 错误响应格式 ```json { "error": "错误信息描述" } ``` --- ## 数据库结构 ### users 表 ```sql CREATE TABLE users ( id INTEGER PRIMARY KEY AUTOINCREMENT, created_at DATETIME, updated_at DATETIME, deleted_at DATETIME, -- 软删除 username VARCHAR(50) UNIQUE NOT NULL, email VARCHAR(100) UNIQUE NOT NULL, password VARCHAR(255) NOT NULL, -- bcrypt 哈希 nickname VARCHAR(50), avatar VARCHAR(255), role VARCHAR(20) DEFAULT 'user', -- 'admin' | 'user' bio VARCHAR(500) ); CREATE INDEX idx_users_deleted_at ON users(deleted_at); CREATE INDEX idx_users_username ON users(username); CREATE INDEX idx_users_email ON users(email); ``` ### comments 表 ```sql CREATE TABLE comments ( id INTEGER PRIMARY KEY AUTOINCREMENT, created_at DATETIME, updated_at DATETIME, deleted_at DATETIME, post_id VARCHAR(100) NOT NULL, -- 文章 slug user_id INTEGER NOT NULL, -- 关联 users.id parent_id INTEGER, -- 父评论ID,用于嵌套回复 content TEXT NOT NULL, status VARCHAR(20) DEFAULT 'approved', -- 'pending' | 'approved' | 'spam' FOREIGN KEY (user_id) REFERENCES users(id), FOREIGN KEY (parent_id) REFERENCES comments(id) ); CREATE INDEX idx_comments_post_id ON comments(post_id); CREATE INDEX idx_comments_user_id ON comments(user_id); CREATE INDEX idx_comments_parent_id ON comments(parent_id); CREATE INDEX idx_comments_deleted_at ON comments(deleted_at); ``` ### likes 表 ```sql CREATE TABLE likes ( id INTEGER PRIMARY KEY AUTOINCREMENT, created_at DATETIME, post_id VARCHAR(100) NOT NULL, user_id INTEGER, -- 登录用户ID,可为空 ip_hash VARCHAR(64), -- 访客IP哈希 FOREIGN KEY (user_id) REFERENCES users(id) ); -- 防止同一用户重复点赞 CREATE UNIQUE INDEX idx_post_user ON likes(post_id, user_id); -- 防止同一IP重复点赞 CREATE UNIQUE INDEX idx_post_ip ON likes(post_id, ip_hash); CREATE INDEX idx_likes_user_id ON likes(user_id); ``` ### like_counts 表 ```sql CREATE TABLE like_counts ( post_id VARCHAR(100) PRIMARY KEY, count INTEGER DEFAULT 0 ); ``` ### post_meta 表(预留) ```sql CREATE TABLE post_meta ( id INTEGER PRIMARY KEY AUTOINCREMENT, post_id VARCHAR(100) UNIQUE NOT NULL, view_count INTEGER DEFAULT 0, like_count INTEGER DEFAULT 0, created_at DATETIME, updated_at DATETIME ); CREATE INDEX idx_post_meta_post_id ON post_meta(post_id); ``` --- ## 前端组件开发 ### 创建 Vue 组件 在 `src/components/` 下创建 `.vue` 文件: ```vue ``` ### 在 MDX 中使用 ```mdx import MyComponent from '../components/MyComponent.vue'; ``` ### 创建 Astro 组件 Astro 组件用于静态渲染,无客户端交互: ```astro --- // src/components/StaticCard.astro interface Props { title: string; content: string; } const { title, content } = Astro.props; ---

{title}

{content}

``` ### 内容集合扩展 在 `src/content/config.ts` 中定义新的内容类型: ```typescript import { defineCollection, z } from 'astro:content'; const docs = defineCollection({ type: 'content', schema: z.object({ title: z.string(), description: z.string().optional(), order: z.number().default(0), }), }); export const collections = { blog: blogCollection, docs, // 新增文档集合 }; ``` ### 自定义页面路由 在 `src/pages/` 下创建 `.astro` 文件: ```astro --- // src/pages/about.astro import BaseLayout from '../layouts/BaseLayout.astro'; ---

关于我

这是一个自定义页面。

``` --- ## 后端服务扩展 ### 添加新的 API 路由 1. 创建处理器 (`server/internal/handlers/`): ```go // server/internal/handlers/post.go package handlers import ( "net/http" "github.com/gin-gonic/gin" ) type PostHandler struct{} func NewPostHandler() *PostHandler { return &PostHandler{} } func (h *PostHandler) GetPosts(c *gin.Context) { // 业务逻辑 c.JSON(http.StatusOK, gin.H{ "data": []string{}, }) } ``` 2. 注册路由 (`server/cmd/server/main.go`): ```go postHandler := handlers.NewPostHandler() api.GET("/posts", postHandler.GetPosts) ``` ### 添加中间件 ```go // server/internal/middleware/rateLimit.go package middleware import ( "github.com/gin-gonic/gin" "time" ) func RateLimit() gin.HandlerFunc { // 实现限流逻辑 return func(c *gin.Context) { // 检查请求频率 c.Next() } } ``` 使用: ```go api.Use(middleware.RateLimit()) ``` ### 添加数据模型 ```go // server/internal/models/models.go type Tag struct { ID uint `json:"id" gorm:"primaryKey"` CreatedAt time.Time `json:"created_at"` Name string `json:"name" gorm:"size:50;uniqueIndex"` Posts []Post `json:"posts" gorm:"many2many:post_tags;"` } ``` 自动迁移会在启动时执行。 --- ## 部署配置 ### Docker 部署 使用 `docker-compose.yml` 一键部署: ```yaml version: '3.8' services: frontend: build: . ports: - "4321:80" depends_on: - api api: build: ./server ports: - "8080:8080" volumes: - ./server/data:/app/data environment: - JWT_SECRET=your-secret-key - ADMIN_USERNAME=admin - ADMIN_PASSWORD=admin123 ``` 启动: ```bash docker-compose up -d ``` ### 手动部署 #### 前端构建 ```bash npm run build ``` 产物在 `dist/` 目录,可部署到任何静态托管服务。 #### 后端构建 ```bash cd server go build -o novablog-server cmd/server/main.go ``` 运行: ```bash ./novablog-server ``` ### Nginx 配置 ```nginx server { listen 80; server_name example.com; # 静态文件 root /var/www/novablog/dist; index index.html; location / { try_files $uri $uri/ /index.html; } # API 代理 location /api { proxy_pass http://localhost:8080; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_cache_bypass $http_upgrade; } } ``` ### 环境变量 | 变量名 | 说明 | 默认值 | |--------|------|--------| | `PORT` | 服务端口 | `8080` | | `JWT_SECRET` | JWT 密钥 | 随机生成 | | `ADMIN_USERNAME` | 管理员用户名 | `admin` | | `ADMIN_PASSWORD` | 管理员密码 | `admin123` | | `DB_PATH` | 数据库路径 | `./data/novablog.db` | --- ## 性能优化 ### 前端优化 1. **图片优化** - 使用 WebP 格式 - 添加 `loading="lazy"` 懒加载 - 使用 `srcset` 响应式图片 2. **代码分割** - Astro 默认零 JS - 交互组件使用 `client:visible` 懒加载 3. **缓存策略** - 静态资源设置长期缓存 - HTML 设置短期缓存或 ETag ### 后端优化 1. **数据库索引** - 已在关键字段建立索引 - 复杂查询使用 EXPLAIN 分析 2. **连接池** - SQLite 使用 WAL 模式 - 设置合理的连接池大小 3. **响应压缩** - 启用 Gzip 压缩 - API 响应体积减少 70%+ ### 监控指标 ```bash # 查看 Go 服务内存占用 ps aux | grep novablog-server # 查看数据库大小 ls -lh server/data/novablog.db ``` --- ## 附录 ### 常用命令 ```bash # 开发 npm run dev # 启动前端开发服务器 cd server && go run . # 启动后端服务 # 构建 npm run build # 构建前端 cd server && go build . # 构建后端 # 数据库 sqlite3 server/data/novablog.db # 打开数据库 CLI # Docker docker-compose up -d # 启动所有服务 docker-compose logs -f # 查看日志 docker-compose down # 停止服务 ``` ### 技术参考 - [Astro 文档](https://docs.astro.build) - [Vue 3 文档](https://vuejs.org) - [Tailwind CSS 文档](https://tailwindcss.com) - [Gin 框架文档](https://gin-gonic.com) - [GORM 文档](https://gorm.io) - [Typst 文档](https://typst.app/docs) --- 如有问题或建议,欢迎提交 Issue 或 Pull Request!