既然数据要私有,我就自己设计了博客系统的底层表结构。这念头不是今天才有的,是从去年被 Notion API 坑了之后就开始盘算的。当时做自动化流程,Notion 那边一个字段类型更新,我这边几十个 n8n 工作流全得跟着改,那种被平台捏住脖子的感觉太他妈熟悉了。数据不在自己手里,什么 IP 都是空中楼阁。
所以这次,从根上就得是自己的。我不用 WordPress,不用 Ghost,那些东西太“重”了,插件、主题、更新,全是依赖。我要的是一个极简的、能让我用 Markdown 写完,自动发布,并且所有元数据都能被我自己的脚本随意调用的东西。核心就三张表:文章表、分类表、标签表。听着简单是吧?但字段设计上,我踩过的坑全反映出来了。
文章表(`posts`)是心脏。`id`(主键,自增)、`title`、`slug`(用于生成 URL,必须唯一)、`content_md`(原始 Markdown)、`content_html`(渲染后的 HTML,避免每次请求都实时转换)、`excerpt`(摘要,用于列表页和 SEO 描述)、`cover_image`(头图 URL)、`status`(草稿、已发布、已归档)、`visibility`(公开、私密、密码保护)。这几个是基础。关键来了:`created_at`、`updated_at`、`published_at`。这三个时间戳必须分开。`created_at` 记录第一次创建,`updated_at` 记录任何修改,`published_at` 才是真正的“上线”时间。这样我才能回溯写作节奏,分析从写完到发布的“拖延周期”,这是做内容的人最该看的数据。
还有两个字段是血泪教训:`word_count` 和 `read_time`。别小看这两个数。早年做 SEO 站群,谷歌的算法对内容长度和用户停留时间有隐性的权重。`word_count` 我让系统在保存时自动统计,`read_time` 按平均阅读速度估算出来。未来做数据分析,比如“多少字的文章转发率最高”,全靠它。最后一个字段是 `meta_json`,一个 JSON 类型的字段,用来塞任何我暂时没想到、但又需要临时存储的元数据,比如文章的情绪分值、AI 辅助生成的提示词版本号,或者未来可能集成的第三方平台 ID。这个“垃圾袋”字段必须留,给未来的自己留条活路。
分类表(`categories`)和标签表(`tags`)就是多对多的关系,标准设计。但我强制分类只能有一个,标签可以多个。分类是树干,标签是树叶。分类用于导航和内容架构,标签用于关联和长尾流量。这里有个细节:标签表里我加了个 `use_count` 字段,实时统计被使用的次数。过一阵子我就能一眼看出,我到底是在反复炒那几个概念的冷饭,还是真的在拓展认知边界。
表关系图在我脑子里画了无数遍。用外键关联,但应用层代码要处理好级联更新和删除。索引必须建:`slug`、`status`、`published_at`、`category_id`。尤其是 `published_at` 和 `status` 的联合索引,列表页查询就靠它。数据库引擎用 InnoDB,事务支持必须要有,虽然现在看起来用不上,但保不齐以后要批量操作数据。
这套结构现在跑在 Docker 容器里,背后是 MySQL 8.0,前面用 Go 写了点简单的 API,前端是极简的静态生成。部署一次,全部搞定。没有后台管理界面,我直接用 VS Code 写 Markdown,git push 上去,CI/CD 流水线自动构建、渲染、入库、部署。对,入库这个操作也是在流水线里用脚本完成的,把 Markdown 文件解析后,通过 API 塞进我自己的数据库。这就彻底闭环了。
弄完这个,我坐在那儿看了半天命令行滚动的日志。2024年底了,还在亲手搭博客,听起来挺复古的。但感觉不一样。以前学 Axure 画原型,学 Python 写爬虫,那种焦虑是怕被行业甩掉。现在亲手设计表结构,这种掌控感,是为了不被任何平台或工具绑架。数据私有,才是数字时代“超级个体”真正的生产资料。别的都是虚的。














