SeaCMS 产品文档(一)
SeaCMS 产品文档
版本:1.0.0
更新日期:2026-04-17
官方网站:SeaCMS
目录
第一部分:技术文档
1. 产品概述
SeaCMS 是一个基于 Python Flask 框架和 SQLite 数据库构建的轻量级内容管理系统(CMS),专为个人博客、企业官网、技术文档站点等场景设计。系统采用前后端一体化架构,提供完整的后台管理界面和响应式前端展示。
1.1 核心特性
特性 | 说明 |
|---|---|
文章管理 | 支持文章创建、编辑、发布、定时发布、版本控制、SEO优化 |
页面管理 | 支持自定义页面创建、排序、模板选择 |
分类与标签 | 支持分类层级、标签聚合、多维度内容组织 |
富文本编辑器 | 自研 SeaEditor,支持图片/文件上传、表格、代码块等 |
媒体管理 | 支持图片、文档上传,自动生成缩略图信息 |
评论系统 | 支持评论审核、嵌套回复、状态管理 |
用户与权限 | 基于RBAC的角色权限体系,支持5种角色 |
双因素认证 | 支持TOTP双因素认证(Google Authenticator兼容) |
API接口 | RESTful API,支持Token认证,便于第三方集成 |
安全防护 | 内置WAF中间件,CSRF保护,SQL注入/XSS防护 |
访问统计 | 访客追踪、页面浏览统计、来源分析 |
数据备份 | 数据库备份、恢复、下载 |
SEO优化 | Sitemap自动生成、Meta标签管理、SEO分析评分 |
暗色模式 | 全站支持亮色/暗色主题切换 |
响应式设计 | 完美适配桌面端和移动端 |
Docker部署 | 提供Dockerfile和docker-compose配置 |
1.2 技术栈
类别 | 技术 | 版本 |
|---|---|---|
后端框架 | Flask | 3.1.0 |
ORM | Flask-SQLAlchemy (SQLAlchemy) | 3.1.1 / 2.0.36 |
数据库 | SQLite | 系统内置 |
认证 | Flask-Login | 0.6.3 |
权限 | Flask-Principal | 0.4.0 |
表单 | Flask-WTF (WTForms) | 1.2.2 / 3.2.1 |
数据库迁移 | Flask-Migrate | 4.0.7 |
缓存 | Flask-Caching | 2.3.0 |
API | Flask-RESTful | 0.3.10 |
邮件 | Flask-Mail | 0.10.0 |
限流 | Flask-Limiter | 3.9.0 |
密码加密 | bcrypt | 4.2.1 |
2FA | pyotp | 2.9.0 |
二维码 | qrcode | 7.4.2 |
图片处理 | Pillow | - |
HTML清洗 | bleach | 6.2.0 |
定时任务 | APScheduler | 3.10.4 |
生产服务器 | Gunicorn | 23.0.0 |
前端CSS | Tailwind CSS | CDN |
前端图标 | Font Awesome | CDN |
反向代理 | Nginx | Alpine |
2. 技术架构
2.1 系统架构图
┌─────────────────────────────────────────────────┐
│ Nginx (反向代理) │
│ 静态文件缓存 / SSL终止 / 负载均衡 │
└──────────────────────┬──────────────────────────┘
│
┌──────────────────────▼──────────────────────────┐
│ Gunicorn (WSGI服务器) │
│ 4 Workers / 120s超时 │
└──────────────────────┬──────────────────────────┘
│
┌──────────────────────▼──────────────────────────┐
│ Flask 应用 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Auth BP │ │ Admin BP │ │ Main BP │ │
│ │ /auth │ │ /admin │ │ / │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ API BP │ │ WAF │ │ Scheduler│ │
│ │ /api │ │ 中间件 │ │ 定时任务 │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ ┌──────────────────────────────────────┐ │
│ │ Extensions Layer │ │
│ │ DB | Login | CSRF | Cache | Mail │ │
│ │ Migrate | Principal | Limiter │ │
│ └──────────────────────────────────────┘ │
└──────────────────────┬──────────────────────────┘
│
┌──────────────────────▼──────────────────────────┐
│ SQLite 数据库 │
│ (instance/seacms.db) │
└─────────────────────────────────────────────────┘2.2 请求处理流程
客户端请求
│
▼
Nginx (静态文件直接返回,其他转发)
│
▼
Gunicorn
│
▼
Flask App
│
├── WAF中间件检查 (SQL注入/XSS/路径遍历检测)
│
├── CSRF验证 (POST/PUT/DELETE请求)
│
├── 限流检查 (Flask-Limiter)
│
├── 路由分发 (Blueprint)
│ ├── /auth/* → 认证模块
│ ├── /admin/* → 后台管理模块
│ ├── / → 前台展示模块
│ └── /api/* → API模块
│
├── 业务逻辑处理
│
├── 模板渲染 (Jinja2)
│
└── 返回响应2.3 蓝图注册
蓝图 | URL前缀 | 功能 |
|---|---|---|
|
| 用户认证(登录、注册、2FA) |
|
| 后台管理(文章、页面、设置等) |
|
| 前台展示(首页、博客、文章详情等) |
|
| RESTful API接口 |
3. 项目结构
seacms/
├── app/ # 应用主目录
│ ├── __init__.py # 应用工厂函数 create_app()
│ ├── extensions.py # Flask扩展初始化
│ ├── middleware.py # WAF中间件
│ ├── models.py # 数据模型定义
│ ├── tasks.py # 定时任务(定时发布)
│ ├── admin/ # 后台管理模块
│ │ ├── __init__.py
│ │ ├── forms.py # WTForms表单定义
│ │ └── routes.py # 后台路由(50+接口)
│ ├── api/ # API模块
│ │ ├── __init__.py
│ │ └── routes.py # RESTful API路由
│ ├── auth/ # 认证模块
│ │ ├── __init__.py
│ │ ├── forms.py # 登录/注册/资料表单
│ │ └── routes.py # 认证路由
│ ├── main/ # 前台模块
│ │ ├── __init__.py
│ │ └── routes.py # 前台路由
│ ├── static/ # 静态资源
│ │ ├── css/
│ │ │ └── sea-editor.css # 富文本编辑器样式
│ │ ├── js/
│ │ │ └── sea-editor.js # 富文本编辑器脚本
│ │ └── uploads/ # 上传文件目录
│ └── templates/ # Jinja2模板
│ ├── admin/ # 后台模板(25个)
│ ├── auth/ # 认证模板(6个)
│ └── main/ # 前台模板(7个)
├── instance/ # 实例目录
│ └── seacms.db # SQLite数据库文件
├── backups/ # 数据库备份目录
├── scripts/
│ └── init_db.py # 数据库初始化脚本
├── config.py # 配置类
├── run.py # 应用入口
├── Dockerfile # Docker镜像构建
├── docker-compose.yml # Docker编排
├── nginx.conf # Nginx配置
├── requirements.txt # Python依赖
├── .env.example # 环境变量示例
└── start.sh # 启动脚本4. 数据库设计
4.1 ER关系图
┌──────────┐ ┌──────────────┐ ┌──────────┐
│ User │────<│ user_roles │>────│ Role │
└────┬─────┘ └──────────────┘ └──────────┘
│
│ 1:N
│
┌────▼─────┐ ┌──────────┐ ┌──────────┐
│ Post │>────│ post_tags │<────│ Tag │
└────┬─────┘ └──────────┘ └──────────┘
│
│ N:1 ┌──────────┐
├──────────────>│ Category │
│ └──────────┘
│ N:1
├──────────────>│ User │ (author)
│
│ 1:N
├──────────────>│ Comment │
│
│ 1:N
└──────────────>│PostVersion│
┌──────────┐ ┌──────────────┐ ┌──────────────┐
│ Page │ │ Media │ │ Setting │
└──────────┘ └──────────────┘ └──────────────┘
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ OperationLog │ │ APIToken │ │ContactMessage│
└──────────────┘ └──────────────┘ └──────────────┘
┌──────────────┐ ┌──────────────┐
│ VisitLog │ │ContentTemplate│
└──────────────┘ └──────────────┘4.2 数据表详细设计
users - 用户表
字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
id | INTEGER | PK, AUTO | 主键 |
username | VARCHAR(64) | UNIQUE, NOT NULL | 用户名 |
VARCHAR(120) | UNIQUE, NOT NULL | 邮箱 | |
password_hash | VARCHAR(256) | NOT NULL | bcrypt加密密码 |
nickname | VARCHAR(64) | - | 昵称 |
avatar | VARCHAR(255) | DEFAULT 'default_avatar.png' | 头像 |
bio | TEXT | - | 个人简介 |
is_active | BOOLEAN | DEFAULT TRUE | 是否启用 |
is_confirmed | BOOLEAN | DEFAULT FALSE | 邮箱是否验证 |
login_attempts | INTEGER | DEFAULT 0 | 登录尝试次数 |
locked_until | DATETIME | - | 锁定截止时间 |
last_login_at | DATETIME | - | 最后登录时间 |
last_login_ip | VARCHAR(45) | - | 最后登录IP |
totp_secret | VARCHAR(32) | - | TOTP密钥 |
two_factor_enabled | BOOLEAN | DEFAULT FALSE | 是否启用2FA |
created_at | DATETIME | DEFAULT UTCNOW | 创建时间 |
updated_at | DATETIME | ON UPDATE UTCNOW | 更新时间 |
roles - 角色表
字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
id | INTEGER | PK, AUTO | 主键 |
name | VARCHAR(64) | UNIQUE, NOT NULL, INDEX | 角色名称 |
description | VARCHAR(255) | - | 角色描述 |
permissions | TEXT | DEFAULT '' | 权限列表(逗号分隔) |
created_at | DATETIME | DEFAULT UTCNOW | 创建时间 |
预置角色:
角色 | 描述 | 权限 |
|---|---|---|
superadmin | 超级管理员 | all |
admin | 管理员 | manage_users,manage_posts,manage_pages,manage_media,manage_settings |
editor | 编辑 | manage_posts,manage_pages,manage_media |
author | 作者 | write_post,manage_own_posts |
user | 普通用户 | comment |
posts - 文章表
字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
id | INTEGER | PK, AUTO | 主键 |
title | VARCHAR(200) | NOT NULL | 标题 |
slug | VARCHAR(200) | UNIQUE, NOT NULL, INDEX | URL别名 |
content | TEXT | - | 内容(HTML) |
summary | TEXT | - | 摘要 |
cover_image | VARCHAR(255) | - | 封面图URL |
status | VARCHAR(20) | DEFAULT 'draft', INDEX | 状态: draft/pending/published/trash |
is_top | BOOLEAN | DEFAULT FALSE, INDEX | 是否置顶 |
allow_comment | BOOLEAN | DEFAULT TRUE | 允许评论 |
view_count | INTEGER | DEFAULT 0 | 浏览次数 |
meta_title | VARCHAR(200) | - | SEO标题 |
meta_description | VARCHAR(300) | - | SEO描述 |
meta_keywords | VARCHAR(255) | - | SEO关键词 |
author_id | INTEGER | FK→users.id, INDEX | 作者ID |
category_id | INTEGER | FK→categories.id, INDEX | 分类ID |
published_at | DATETIME | - | 发布时间 |
scheduled_at | DATETIME | - | 定时发布时间 |
language | VARCHAR(10) | DEFAULT 'zh' | 语言 |
created_at | DATETIME | DEFAULT UTCNOW, INDEX | 创建时间 |
updated_at | DATETIME | ON UPDATE UTCNOW | 更新时间 |
categories - 分类表
字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
id | INTEGER | PK, AUTO | 主键 |
name | VARCHAR(64) | NOT NULL | 分类名称 |
slug | VARCHAR(64) | UNIQUE, NOT NULL, INDEX | URL别名 |
description | VARCHAR(255) | - | 描述 |
parent_id | INTEGER | FK→categories.id | 父分类ID |
sort_order | INTEGER | DEFAULT 0 | 排序 |
created_at | DATETIME | DEFAULT UTCNOW | 创建时间 |
tags - 标签表
字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
id | INTEGER | PK, AUTO | 主键 |
name | VARCHAR(64) | NOT NULL, UNIQUE | 标签名称 |
slug | VARCHAR(64) | UNIQUE, NOT NULL, INDEX | URL别名 |
created_at | DATETIME | DEFAULT UTCNOW | 创建时间 |
pages - 页面表
字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
id | INTEGER | PK, AUTO | 主键 |
title | VARCHAR(200) | NOT NULL | 标题 |
slug | VARCHAR(200) | UNIQUE, NOT NULL, INDEX | URL别名 |
content | TEXT | - | 内容(HTML) |
template | VARCHAR(100) | DEFAULT 'default' | 模板名称 |
sort_order | INTEGER | DEFAULT 0 | 排序 |
is_home | BOOLEAN | DEFAULT FALSE | 是否首页 |
status | VARCHAR(20) | DEFAULT 'published' | 状态 |
meta_title | VARCHAR(200) | - | SEO标题 |
meta_description | VARCHAR(300) | - | SEO描述 |
meta_keywords | VARCHAR(255) | - | SEO关键词 |
author_id | INTEGER | FK→users.id | 作者ID |
language | VARCHAR(10) | DEFAULT 'zh' | 语言 |
created_at | DATETIME | DEFAULT UTCNOW | 创建时间 |
updated_at | DATETIME | ON UPDATE UTCNOW | 更新时间 |
comments - 评论表
字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
id | INTEGER | PK, AUTO | 主键 |
content | TEXT | NOT NULL | 评论内容 |
author_name | VARCHAR(64) | - | 评论者名称 |
author_email | VARCHAR(120) | - | 评论者邮箱 |
author_url | VARCHAR(255) | - | 评论者网址 |
author_id | INTEGER | FK→users.id | 注册用户ID |
post_id | INTEGER | FK→posts.id, INDEX | 文章ID |
parent_id | INTEGER | FK→comments.id | 父评论ID |
status | VARCHAR(20) | DEFAULT 'pending', INDEX | 状态: pending/approved/spam/trash |
ip_address | VARCHAR(45) | - | IP地址 |
created_at | DATETIME | DEFAULT UTCNOW | 创建时间 |
media - 媒体文件表
字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
id | INTEGER | PK, AUTO | 主键 |
filename | VARCHAR(255) | NOT NULL | 存储文件名(UUID) |
original_name | VARCHAR(255) | NOT NULL | 原始文件名 |
file_path | VARCHAR(500) | NOT NULL | 文件路径 |
file_size | INTEGER | - | 文件大小(字节) |
file_type | VARCHAR(50) | - | 类型: image/document |
mime_type | VARCHAR(100) | - | MIME类型 |
alt_text | VARCHAR(255) | - | 替代文本 |
width | INTEGER | - | 图片宽度 |
height | INTEGER | - | 图片高度 |
uploader_id | INTEGER | FK→users.id | 上传者ID |
created_at | DATETIME | DEFAULT UTCNOW, INDEX | 创建时间 |
post_versions - 文章版本表
字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
id | INTEGER | PK, AUTO | 主键 |
post_id | INTEGER | FK→posts.id, INDEX, NOT NULL | 文章ID |
version_number | INTEGER | NOT NULL | 版本号 |
title | VARCHAR(200) | - | 版本标题 |
content | TEXT | - | 版本内容 |
summary | TEXT | - | 版本摘要 |
user_id | INTEGER | FK→users.id | 操作用户ID |
change_summary | VARCHAR(255) | - | 变更说明 |
created_at | DATETIME | DEFAULT UTCNOW | 创建时间 |
settings - 系统设置表
字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
id | INTEGER | PK, AUTO | 主键 |
key | VARCHAR(100) | UNIQUE, NOT NULL, INDEX | 设置键 |
value | TEXT | - | 设置值 |
description | VARCHAR(255) | - | 描述 |
group | VARCHAR(50) | DEFAULT 'general' | 分组: general/seo/comment/upload/mail/theme/security/performance/editor |
created_at | DATETIME | DEFAULT UTCNOW | 创建时间 |
updated_at | DATETIME | ON UPDATE UTCNOW | 更新时间 |
visit_logs - 访问日志表
字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
id | INTEGER | PK, AUTO | 主键 |
url | VARCHAR(500) | NOT NULL, INDEX | 访问URL |
referrer | VARCHAR(500) | - | 来源URL |
ip_address | VARCHAR(45), INDEX | - | IP地址 |
user_agent | VARCHAR(500) | - | 浏览器UA |
visitor_id | VARCHAR(36), INDEX | - | 访客标识(Cookie) |
post_id | INTEGER | FK→posts.id | 关联文章ID |
created_at | DATETIME | DEFAULT UTCNOW, INDEX | 创建时间 |
operation_logs - 操作日志表
字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
id | INTEGER | PK, AUTO | 主键 |
user_id | INTEGER | FK→users.id | 操作用户ID |
action | VARCHAR(100) | NOT NULL | 操作类型 |
target_type | VARCHAR(50) | - | 目标类型 |
target_id | INTEGER | - | 目标ID |
detail | TEXT | - | 操作详情 |
ip_address | VARCHAR(45) | - | IP地址 |
created_at | DATETIME | DEFAULT UTCNOW, INDEX | 创建时间 |
api_tokens - API令牌表
字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
id | INTEGER | PK, AUTO | 主键 |
name | VARCHAR(100) | NOT NULL | 令牌名称 |
token | VARCHAR(64) | UNIQUE, NOT NULL, INDEX | 令牌值 |
user_id | INTEGER | FK→users.id, NOT NULL | 所属用户ID |
is_active | BOOLEAN | DEFAULT TRUE | 是否启用 |
last_used_at | DATETIME | - | 最后使用时间 |
created_at | DATETIME | DEFAULT UTCNOW | 创建时间 |
contact_messages - 联系消息表
字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
id | INTEGER | PK, AUTO | 主键 |
name | VARCHAR(64) | NOT NULL | 发送者姓名 |
VARCHAR(120) | NOT NULL | 发送者邮箱 | |
subject | VARCHAR(200) | - | 主题 |
message | TEXT | NOT NULL | 消息内容 |
is_read | BOOLEAN | DEFAULT FALSE | 是否已读 |
ip_address | VARCHAR(45) | - | IP地址 |
created_at | DATETIME | DEFAULT UTCNOW | 创建时间 |
content_templates - 内容模板表
字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
id | INTEGER | PK, AUTO | 主键 |
name | VARCHAR(100) | NOT NULL | 模板名称 |
description | VARCHAR(255) | - | 描述 |
content | TEXT | - | 模板内容(HTML) |
template_type | VARCHAR(20) | DEFAULT 'post' | 类型: post/page |
is_builtin | BOOLEAN | DEFAULT FALSE | 是否内置 |
created_at | DATETIME | DEFAULT UTCNOW | 创建时间 |
updated_at | DATETIME | ON UPDATE UTCNOW | 更新时间 |
关联表
user_roles - 用户角色关联
字段 | 类型 | 约束 |
|---|---|---|
user_id | INTEGER | FK→users.id, PK |
role_id | INTEGER | FK→roles.id, PK |
post_tags - 文章标签关联
字段 | 类型 | 约束 |
|---|---|---|
post_id | INTEGER | FK→posts.id, PK |
tag_id | INTEGER | FK→tags.id, PK |
5. API 接口文档
5.1 公开接口
获取文章列表
GET /api/public/posts参数:
参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
page | int | 1 | 页码 |
per_page | int | 10 | 每页数量 |
category_id | int | - | 按分类筛选 |
响应字段:
字段 | 类型 | 说明 |
|---|---|---|
id | int | 文章ID |
title | string | 标题 |
slug | string | URL别名 |
content | string | 内容 |
summary | string | 摘要 |
cover_image | string | 封面图 |
status | string | 状态 |
view_count | int | 浏览次数 |
is_top | bool | 是否置顶 |
meta_title | string | SEO标题 |
meta_description | string | SEO描述 |
meta_keywords | string | SEO关键词 |
published_at | datetime | 发布时间 |
created_at | datetime | 创建时间 |
updated_at | datetime | 更新时间 |
获取文章详情
GET /api/public/posts/<slug>获取分类列表
GET /api/public/categories获取页面列表
GET /api/public/pages获取页面详情
GET /api/public/pages/<slug>获取站点信息
GET /api/public/site-info响应示例:
{
"site_name": "SeaCMS",
"site_description": "一个基于Flask的内容管理系统",
"site_keywords": "CMS,Flask,内容管理",
"total_posts": 42,
"total_categories": 5,
"total_tags": 18
}提交评论
POST /api/comments请求体:
{
"post_id": 1,
"content": "评论内容",
"author_name": "访客",
"author_email": "visitor@example.com"
}用户认证
POST /api/auth请求体:
{
"username": "admin",
"password": "password"
}5.2 管理接口(需Token认证)
所有管理接口需在请求头中携带API Token:
Authorization: Bearer <your-api-token>管理文章列表
GET /api/manage/posts?page=1&per_page=20创建文章
POST /api/manage/posts请求体:
{
"title": "文章标题",
"content": "文章内容",
"summary": "文章摘要",
"status": "draft"
}获取/更新/删除文章
GET /api/manage/posts/<id>
PUT /api/manage/posts/<id>
DELETE /api/manage/posts/<id>PUT请求体(部分更新):
{
"title": "新标题",
"content": "新内容",
"status": "published"
}DELETE操作: 将文章状态设为 trash,不物理删除。
评论 (0)