blog-demo · 归档与说明
内容架构与工程化设计
站点从框架原型转向真实内容档案时的早期决策记录。
- 状态
- 历史记录
- 最后核对
- 源码修订
e0d3baa2
内容架构与工程化设计
- 日期:2026-08-27
- 状态:历史设计记录,保留当时的决策背景;实现与字段以内容模型与维护指南和
src/content.config.ts为准。 - 适用范围:迩迩的小站(Astro + GitHub Pages)从「框架原型」转向「真实内容站」
1. 背景
站点框架已经搭完:布局统一、暗色模式、跨页转场、CI 自动部署、19 项浏览器冒烟测试、 构建期数据抓取带三级降级。但七个兴趣页装的都是一次性交互 demo,没有真实内容, 也没有把内容装进去的顺手办法。
这份文档定的是:内容怎么组织、页面怎么长、用什么工具往里写。
2. 目标与非目标
目标
- 三种内容类型覆盖全部兴趣板块,代码写一次、七个页面共用
- 有一个图形界面能写图文,不用再记「哪个文件放哪个目录」
- 站点保持零成本、零运维
非目标(明确不做,避免反复)
- 不引入后端服务和数据库。 见 §3 决策一
- 不做评论、不做访问统计、不做多人协作
- 不做移动端发布(编辑器只在本机跑)
3. 关键决策记录
记下来是为了将来不再重新讨论一遍。
决策一:不上后端和数据库,git 就是数据库
曾考虑「前后端数据库解耦」以求工程上更专业,否决。
对内容站而言这是架构错配:
- git 已经提供了想要的一切:版本记录、变更历史、逐行 diff、任意回滚、异地备份,且免费
- 引入 PostgreSQL + API 服务器会带来服务器账单、运维负担、备份责任、可用性风险, 换来的新功能是零
- 真正需要后端的是评论、多人协作、动态查询、实时更新——本站一个都不需要
将来什么情况下该重新考虑: 想要评论系统、想跨设备实时编辑、 或内容量大到构建时间不可接受(数千篇量级)。在此之前不要动这个决定。
决策二:图片直接进 git 仓库
发布节奏是「随手记,一周几张」,一年百来张。构建期压缩转 WebP 后, 一年增量约几十 MB,几年内碰不到 GitHub 的任何限制。
但图片路径要抽一层(统一走一个 helper,不在内容里写死 URL), 将来真要迁到对象存储只改一个配置,不动内容、不动页面。
决策三:摄影与旅行合并为 /moments/,提到顶层导航
两者重复:拍照的动机是记录日常,不是作品集,按「摄影/旅行」分类是给自己找活干。 合并后按时间线排,并提到顶层——它会是更新最频繁的内容,埋在兴趣二级页里太深。
旧链接 /interests/photography/、/interests/travel/ 合并后失效,
确认不做重定向(从未对外分享过)。
决策四:moment 与 essay 的界限
- moment:不超过一段话。超过就该写成 essay
- essay:成篇的文章
界限必须清楚,否则两边都想发、两边都懒得发。
决策五:交互 demo 降为页内彩蛋,股票页除外
- 股票页(大盘复盘 + 自选股)本身就是内容——真数据、每天变,保持现状不动
- 钢琴、代码沙箱、菜谱计算器等纯玩具:收到对应兴趣页底部的小区块,不再挡在内容前面
4. 内容模型
三个 content collection 覆盖全部需求。
src/content/
essays/ 长文:音乐故事、读书感触、现有博客三合一
items/ 收藏条目:歌、书(将来加影视也放这里)
moments/ 图文动态:摄影 + 旅行合并后的时间线
4.1 essays(长文)
| 字段 | 类型 | 说明 |
|---|---|---|
title |
string | |
description |
string | 列表与分享卡片用 |
pubDate |
date | |
topic |
enum | blog / music / reading / cooking / coding |
tags |
string[] | |
draft |
boolean | 默认 false |
长文这边不存关联字段。关联只在 item 侧填一次(
items.essay), 长文页需要时反查即可。两边都存必然有一天不同步。
现有 src/content/posts/ 的三篇文章迁移到这里,topic: 'blog'。
4.2 items(收藏条目)
| 字段 | 类型 | 说明 |
|---|---|---|
kind |
enum | song / book |
title |
string | |
creator |
string | 歌手 / 作者 |
cover |
image? | 封面 |
date |
date | 歌:听到的时间;书:读完的时间,在读的书用开始时间 |
rating |
number? | 1–5 |
blurb |
string | 一句话短评 |
status |
enum? | want / doing / done,书架分区用;歌可留空 |
essay |
string? | 关联长文的 slug |
4.3 moments(图文动态)
| 字段 | 类型 | 说明 |
|---|---|---|
date |
datetime | 优先取 EXIF 拍摄时间 |
place |
string? | 地点 |
photos |
array | { src, alt, exif? } |
text |
string | 一段话,不超过一段 |
exif 子字段(编辑器自动填,见 §7):camera / lens / focal / aperture / shutter / iso。
4.4 双向关联
items.essay ←→ essays.relatedItem 构成双向链接:
- 书架点一本书 → 跳到读后感
- 读后感页顶部显示这本书的封面与评分
这样「歌单」和「故事会」不是两块割裂区域,而是同一批数据的两种视图, 不会出现「歌单里有的歌,故事会里找不到」。
一致性由构建期校验保证:essay 指向不存在的 slug 时构建报错,不留到线上。
5. 路由与页面
| 路由 | 内容 | 备注 |
|---|---|---|
/ |
首页 | 增加最新 moments 入口 |
/blog/ |
essays(全部 topic) | 现有 |
/moments/ |
图文时间线 | 新增,进主导航 |
/interests/music/ |
歌单(items kind=song)+ 故事入口 | 钢琴降为彩蛋 |
/interests/reading/ |
书架(items kind=book,按 status 分区)+ 读后感入口 | |
/interests/stocks/ |
大盘复盘 + 自选股 | 不动 |
/interests/cooking/ 等 |
内容 + 底部 demo 彩蛋 | |
/year/2026/ |
年度回顾 | 阶段三,形态待定,见 §9 |
排版沿用既定规则:索引页 = 宽双栏,阅读页 = 窄单栏。
6. 阶段划分
每个阶段单独走一遍设计 → 计划 → 实施,不一口气糊完。
阶段一:内容模型 + 页面组件
定义三种类型的 schema,把七个手写 demo 页重构成按类型渲染,迁移现有文章。
完成标志:手写 Markdown 就能发内容。虽然还不舒服,但站已经能装东西了—— 这一步有独立价值,不必等编辑器做完才能开始填。
阶段二:本地编辑器
npm run studio 开浏览器写图文。见 §7。
阶段三:工程化收尾
见 §8。
7. 阶段二:本地编辑器(方向已定,实现待验证)
形态:本地跑的网页应用,零外部服务、零 OAuth。能力:
- 图形界面填写三种内容类型的字段,带校验
- 拖入图片 → 自动压缩转 WebP → 写入仓库
- 自动读取 EXIF 填元数据
- 一键 git commit + push,推送前跑一遍构建校验
EXIF 提取的实际边界
器材是索尼 A7C II(ILCE-7CM2),不是 interests.ts 里写的富士——那句是占位文案, 阶段一一并改掉。
能自动读到:拍摄时间、机身型号、镜头型号、光圈、快门、ISO、焦距。
读不到地点:A7C II 机身没有 GPS 模块。除非用索尼 Creators’ App 连手机同步位置,
否则 place 字段仍需手填。手机拍的照片则通常带 GPS,可以自动填。
文档里写明这一点,免得实施时误以为能全自动。
实现路径待定,先做验证
| 方案 | 取舍 |
|---|---|
| 甲:自己写小 studio | 内容类型只有三种、字段少,自己写反而简单;能精确匹配工作流;不引入大依赖 |
| 乙:用 Keystatic | 专为 Astro 做的内容管理层,支持本地模式写文件系统,能省大量工作;但当前版本的实际状态需要先验证 |
| 丙:Obsidian / VS Code 插件 | 零开发量,但字段校验、图片压缩、发布流程全靠自觉,等于没解决「不直观」 |
结论:先花少量时间验证乙,不行就走甲。 如果 Keystatic 好用,自己写是浪费; 如果它别扭,自己写反而干净。这个验证是阶段二开工的第一件事。
8. 阶段三:工程化收尾
- CHANGELOG.md 自动生成 —— 提交信息已经在用
feat:/fix:前缀,直接能生成 - 站内搜索 —— Pagefind,构建期生成索引,纯静态零后端,与现有架构兼容
- 年度回顾页 —— 时间线数据天然能做:这一年去了几个地方、读了几本书、拍了多少张
- 测试补齐:现在只有冒烟,内容类型多了之后需要 schema 校验测试
关于「日志管理」:静态站没有运行时,因而没有运行时日志。 构建日志在 GitHub Actions 里已经有了。这一项没有对应物,不做。
9. 未决问题
- Keystatic 是否可用(阶段二开工前验证)
- 年度回顾页的具体形态(等有真实数据后再设计,现在设计等于空想)
- 首页如何呈现 moments(等时间线页做完,看实际观感再定)