kizumi_header_banner_img

Hello! 欢迎光临Aurora.歆の小破站!

加载中

文章导读

槐序笔记:一个个人笔记系统的构建过程


avatar
Aurora.歆Official 2026年9月7日 14

在信息碎片化的时代,如何高效地收集、整理和内化知识,是许多人都面临的挑战。我们常常在多个平台间切换,笔记散落各处,难以形成体系。为了解决这一痛点,同时也为了深入实践全栈开发技能,我们构建了“槐序笔记” —— 一个干净、专注、功能完整的个人笔记与知识管理平台。

一、 项目概览

“槐序”一词取自“槐花飘香,时序更迭”,寓意着在时间的流转中,通过记录和思考来沉淀智慧。槐序笔记不仅是一个笔记应用,更是一个个人知识库和微型博客平台。它允许用户创建私有笔记,并一键将内容公开分享,构建属于自己的个人主页。

核心功能一览

  • 笔记管理 (CRUD):支持笔记的创建、读取、更新和删除,并具备分类、置顶、搜索和排序功能。

  • 回收站机制:删除的笔记会先进入回收站,提供误删恢复的缓冲期,支持彻底删除。

  • 个人主页与社交分享:每个用户拥有独立的公开主页,可展示用户信息与公开笔记,访客无需登录即可浏览。

  • 公开笔记分享:用户可将笔记设为公开,并生成分享链接,方便在社交平台传播。

  • 个人资料与主题定制:支持用户自定义头像、昵称、个人简介,并内置了深色/浅色模式及多种主题色。

  • PWA 支持:项目支持渐进式 Web 应用(PWA),可安装到桌面或手机,提供接近原生应用的体验。

  • Markdown 与附件支持:编辑器支持 Markdown 语法,并集成了文件上传功能,让笔记内容更丰富。

二、 技术栈详解

槐序笔记采用前后端分离的架构,选用了现代、成熟的 Web 技术栈,兼顾了开发效率与运行性能。

后端技术栈

  • 核心框架: Node.js + Express.js

    • 轻量、高效,非常适合构建 API 服务。

  • 数据库: SQLite + Prisma ORM

    • SQLite 提供了零配置、文件即数据库的便捷性;Prisma 提供了类型安全的数据库访问和便捷的迁移工具,极大地提升了开发体验。

  • 认证与安全: JWT (JSON Web Tokens) + Bcrypt

    • 使用 JWT 进行无状态身份认证,使用 Bcrypt 对用户密码进行加盐哈希加密,保障用户数据安全。

  • 文件存储: Multer

    • 用于处理 multipart/form-data 类型的文件上传请求,支持头像和笔记附件上传。

前端技术栈

  • 核心框架: 原生 JavaScript (ES Modules)

    • 项目未使用 React/Vue 等重型框架,而是采用原生 JS 模块化开发,轻量、直接,掌控力强。

  • 构建工具: Vite

    • Vite 提供了极速的开发服务器启动和热更新,以及高效的打包能力,大幅优化了开发体验。

  • 样式与主题: CSS3 (自定义属性/变量)

    • 完全使用原生 CSS 构建界面,并通过 CSS 变量(var(--primary))实现了动态主题切换(深色/浅色模式与多种主题色)。

  • Markdown 解析: Marked.js

    • 一个高性能的 Markdown 解析器,用于将用户输入的 Markdown 格式文本实时渲染为 HTML,展示在笔记预览和详情页中。

  • HTTP 客户端: Axios

    • 用于在前端发起 HTTP 请求,并利用其拦截器统一处理认证 Token 和全局错误。

  • PWA: 通过 manifest.jsonsw.js (Service Worker) 实现离线缓存和可安装性。

服务端与部署 (生产环境)

  • Web 服务器: Nginx

    • 作为反向代理服务器,负责处理静态资源请求,并将 API 请求代理转发至后端服务,同时处理 HTTPS 和负载均衡。

  • 进程管理: PM2 或 Node 原生守护进程

    • 用于在生产环境中管理 Node.js 进程,提供日志记录、崩溃自动重启和负载均衡功能。

  • 操作系统与环境: Linux (CentOS/Ubuntu) + 宝塔面板

    • 项目运行于 Linux 服务器,通过宝塔面板进行可视化的网站、数据库和文件管理。

三、 核心模块深度解析

1. 笔记管理模块

笔记管理是系统的核心。其数据模型(Prisma Schema)设计如下:

prisma
model Note {
  id         Int      @id @default(autoincrement())
  title      String
  content    String   @default("")
  category   String   @default("默认")
  isPinned   Boolean  @default(false)
  isPublic   Boolean  @default(false)
  viewCount  Int      @default(0)
  userId     Int
  user       User     @relation(fields: [userId], references: [id], onDelete: Cascade)
  deletedAt  DateTime?
  createdAt  DateTime @default(now())
  updatedAt  DateTime @updatedAt
  tags       Tag[]    @relation("NoteTags")
}

该设计支持了关键业务逻辑:

  • 软删除:通过 deletedAt 字段实现回收站功能。

  • 置顶:通过 isPinned 字段实现笔记置顶。

  • 公开分享:通过 isPublic 字段控制笔记的公开状态。

  • 用户关联:通过 userId 与用户关联,并设置 onDelete: Cascade,删除用户时其所有笔记也将被删除。

2. 用户认证与权限控制

认证流程基于 JWT 实现,通过前端请求拦截器和后端的中间件形成闭环。

  • 登录/注册:用户在登录页提交凭证,后端验证通过后生成一个包含 userIdrole 的 JWT Token 返回给前端。

  • Token 存储:前端将 Token 存储在 localStorage 中。

  • 请求拦截:前端 Axios 请求拦截器会自动在所有请求头中添加 Authorization: Bearer <token>

  • 身份验证中间件:后端中间件(auth.js)会拦截所有需要登录的路由,验证 Token 的有效性,并将解码后的用户信息挂载到 req.user 上,供后续控制器使用。

javascript
// 核心验证中间件逻辑
const decoded = verifyToken(token);
if (!decoded) {
  return res.status(401).json({ msg: '登录已过期,请重新登录' });
}
req.user = decoded;
next();

3. 个人主页系统

个人主页是槐序笔记的亮点功能,它整合了用户信息展示与内容发布。

  • 路由设计:前端通过 profile.html?user=username 的方式加载个人主页,后端通过 GET /api/user/:username 获取用户公开信息。

  • 公开笔记查询:后端控制器在查询笔记时,会严格过滤 isPublic: truedeletedAt: null 的条件,确保只有公开且未被删除的笔记才会被展示。

  • 主题同步:个人主页和设置页面会读取 localStorage 中的用户主题偏好,实现与主站一致的视觉体验。

4. 附件上传功能

为笔记添加附件(图片、文档等)是增强内容表现力的重要途径。

  • 后端:使用 Multer 中间件处理 multipart/form-data,将文件保存到服务器特定目录(/public/uploads/attachments),并将访问 URL 返回给前端。

  • 前端编辑器:在编辑器工具栏添加了 📎 按钮,点击后触发隐藏的 input[type="file"],上传成功后自动在光标处插入 Markdown 格式的图片或链接语法(如 ![图片名](url)[📎 文件名](url))。

四、 开发与部署中的关键挑战与解决方案

在项目开发和部署过程中,我们遇到并解决了几个关键问题,这些经历也塑造了项目的最终形态。

1. 数据库迁移与字段兼容性问题

挑战:在项目迭代中,我们需要为 User 表新增 updatedAt 字段,并设定为 DateTime 类型。然而,已有的旧数据中该字段为空,导致 Prisma 迁移失败 (P2032 错误)。
解决方案:我们采用了方案一:将 Schema 中的 updatedAt 字段设为可选(DateTime?),并在代码中手动管理该字段的更新,例如:

javascript
data: {
  // ... 其他字段
  updatedAt: new Date()
}

启示:在修改已有生产数据库结构时,必须谨慎考虑数据的兼容性,通过“字段可选”或“设置默认值”的方式来平滑过渡。

2. 动态路由与静态路径的冲突

挑战:在 user.routes.js 中,我们将 /:username 这样的动态路由放在了 router.use(auth) 中间件之后,导致所有用户相关的请求(如 /profile)都会被 /:username 捕获,并去数据库查询名为 profile 的用户,最终返回 404。
解决方案:我们调整了路由顺序,将所有的静态/固定路径(如 /profile, /me, /theme)以及需要鉴权的路由,全部放在动态路由 /:username 之前
启示:在 Express 中,路由匹配是按顺序进行的。动态路由(尤其是 /:xxx 形式)必须定义在最后,否则它会“吞噬”所有以该路径开头的请求。

3. 前端构建与资源引用问题

挑战:在 Vite 构建过程中,settings.html 中硬编码的 assets/settings-xxx.js 文件路径找不到,导致构建失败。
解决方案:我们在 settings.html 中删除了所有硬编码的 <script><link> 标签,改为使用 type="module" 并直接引用源码文件(如 /src/api.js),然后由 Vite 在构建时自动处理依赖和路径。
启示:在 Vite 等现代构建工具中,应充分利用其模块解析和依赖追踪能力,避免手动管理哈希文件名。

五、 未来展望

槐序笔记目前已经具备了作为一个个人知识管理工具的核心能力。未来,我们计划从以下几个方向继续完善它:

  1. AI 功能集成:引入 AI 能力,实现笔记的智能摘要、标签自动生成或写作辅助。

  2. 全文搜索:当前搜索基于 SQL LIKE,未来可集成 Elasticsearch 或 Meilisearch 等搜索引擎,提供更快速、更准确的全文检索。

  3. 移动端适配与优化:进一步优化移动端的交互体验,使其在手机上的使用更加流畅和自然。

  4. 数据导入/导出:支持从其他笔记应用(如 Notion、语雀)导入数据,并提供更丰富的导出格式(如 PDF、HTML)。

  5. 协作功能:探索笔记的协同编辑或评论功能,从“个人知识库”迈向“轻量级内容协作平台”。

六、 结语

槐序笔记是一个从零开始、完全自主构建的全栈项目。它不仅是一个可用的工具,更是对现代 Web 开发技术栈的一次深入实践。从数据库设计、后端 API 开发,到前端交互、主题系统,再到最终的部署上线,每个环节都充满了挑战与学习的乐趣。

我们希望槐序笔记能为你提供一个清爽、高效的知识管理空间,也希望能为正在学习全栈开发的同好们提供一份有价值的实践参考。

项目将持续迭代,欢迎体验和反馈。

感谢您的支持
微信赞赏

微信扫一扫

支付宝赞赏

支付宝扫一扫



评论(0)

查看评论列表

暂无评论


发表评论

表情 颜文字
插入代码
Aurora.歆の小破站

About Me

avatar

Aurora.歆Official

网易音乐人、歌手、制作人

35
文章
18
评论
5
用户

Ads