首页、相册目录、相册详情、后台编辑、图片上传和发布链路均已具备。
Executive Summary
这是一个已经上线、可持续维护的摄影档案站,不再只是静态页面原型。
当前最准确的定位是:面向公众的静态摄影前台,配合一个受保护的单人内容后台。它适合当前 53 张照片、4 个相册和单管理员场景,但还不是多用户通用 CMS。
- 公网状态HTTPS 正常
- 内容发布后台保存后静态重建
- 照片组织二级相册 + 多次引用
- 主要待办备份、安全收口、内容同步
系统支持二级相册与一图多相册,但生产数据仍是 4 个平级相册,尚未验证真实分类规模。
服务器 Redis 6379 端口可从公网连接,应优先关闭公网访问或绑定到本机。
System Logic
系统采用“后台管理动态数据,前台发布静态结果”的双层结构。
访客请求不经过数据库和后台业务逻辑,直接由 Nginx 返回构建好的 HTML 与图片;只有管理员编辑时才进入 Node 后台。这使浏览速度、稳定性和维护成本符合个人摄影站的实际需求。
为什么当前结构合理
网站规模小、更新频率有限、写入者只有一人。使用 JSON 目录而不是数据库,减少了常驻服务、迁移和备份复杂度;使用 Astro 静态构建,让公开页面没有运行时查询负担。
一次内容更新会发生什么
管理员在后台修改相册或照片关系,Node 服务先验证引用并更新目录,再调用发布脚本生成新版本。Nginx 的 current 链接切换到新版本,公开站点随后展示新内容。
静态前台与持久照片库分开:发布新版本不会重复复制线上原图,也不会因为删除旧发布版本而丢失照片。
Public Experience
前台围绕“先看代表照片,再进入完整相册”组织。
首页不是传统文字介绍页,而是一条视觉入口:完整 Hero 照片、精选照片墙,以及每行一个相册的轮播摘要。照片卡片不显示文件名,轮播箭头和圆点只移动当前相册照片,不误跳转到详情页。
| 页面 / 能力 | 当前逻辑 | 状态 |
|---|---|---|
| 首页 Hero | 使用站点设置中的 Hero 照片;响应式 WebP,保留完整构图。 | 已完成 |
| 精选照片墙 | 从各相册的精选照片聚合,按文件名去重;点击进入所属相册。 | 已完成 |
| 相册列表 | 一行一个相册;父相册与子相册都可展示;轮播拥有独立箭头、圆点与滑动逻辑。 | 已完成 |
| 相册详情 | 一级路径为 /albums/slug/,二级路径为 /albums/parent/child/。 | 已完成 |
| 图片加载 | 480 / 960 / 1600 / 2400 四档 WebP;原图与预览图由 Nginx 长缓存。 | 已完成 |
| 搜索 / 筛选 | 当前相册量很小,没有站内搜索、标签筛选或物种检索。 | 按规模再做 |
| SEO 与分享 | 已有基础标题和 description;尚缺 Open Graph、sitemap、robots 与结构化数据。 | 待完善 |
Admin Workflow
后台将常用动作放回相册上下文,目标是让一次编辑尽量只走一步。
管理员不需要先维护一套照片库、再去另一个页面建立关系。创建相册时可直接导入文件夹;打开相册后可上传新照片、引用库内照片、移除照片、设置封面和精选。
照片删除采用两层语义
从相册移除只删除这个相册对照片的引用,原始照片仍留在资源库,也不影响其他相册。
从照片库永久删除会先检查 Hero、相册照片、封面和精选等所有引用。存在任何引用时,后端返回冲突并拒绝删除;只有零引用照片才能连同衍生图一起删除。
例如同一张白头鹎照片可同时出现在“拍鸟”和“白头鹎”中,磁盘只保留一份文件,目录中记录两次引用。
| 后台能力 | 操作方式 | 系统保护 |
|---|---|---|
| 站点设置 | 修改网站名称、描述、Hero 照片和导航。 | 统一写入目录并触发发布。 |
| 新建相册 | 可创建空相册,也可选择文件夹并一次导入全部 JPG。 | slug 唯一校验;上传分批处理。 |
| 二级相册 | 创建或编辑时选择一个一级相册作为父级。 | 最多两级;禁止循环或三级嵌套。 |
| 添加照片 | 在相册内直接上传,或从资源库引用已有照片。 | 相同内容按 SHA-256 复用,不重复存储。 |
| 相册内移除 | 照片条目上的移除动作只解除当前相册关系。 | 其他相册、Hero、原图均不受影响。 |
| 永久删除 | 从照片库发起删除。 | 后端检查全部引用;有引用则拒绝。 |
| 删除相册 | 删除相册记录,不自动删除照片资源。 | 删除一级相册时,其子相册提升为一级。 |
| 重建预览 | 后台可为照片重新生成 JPEG 与 WebP 衍生图。 | 原图保留不动,失败不提交半成品。 |
Content & Data
资源、相册和发布页面是三种不同对象。
理解这三个层次,就能理解为什么一张照片可以出现在多个相册、为什么从相册移除不会删掉原图,以及父相册如何汇总子相册内容。
一份原图 + 一组衍生图,以文件名和内容哈希识别。它不天然属于任何相册。
相册的 files 列表记录照片文件名。同一文件名可被多个相册引用。
构建时将目录转换成首页与相册页面;父相册还会汇总已发布子相册照片并去重。
当前生产相册分布
4 个相册合计 52 个照片引用;资源库有 53 张照片,因此有 1 张资源当前没有相册引用。现有相册之间尚无重复引用,但系统已经允许重复引用。
| 相册 | 照片 | 精选 | 日期 |
|---|---|---|---|
| 雪后园林 | 14 | 4 | 2026-01 |
| 室内光线 | 17 | 4 | 2026-02 |
| 山路光线 | 10 | 4 | 2026-03 |
| 海岸笔记 | 11 | 4 | 2026-04 |
二级相册现在怎样工作
- 一级相册可以直接有照片,也可以只有子相册。
- 父相册页面聚合自身照片和已发布子相册照片,并按文件名去重。
- 子相册不能脱离未发布的父相册单独公开。
- 首页相册列表允许同时展示一级和二级相册。
图片文件怎样生成
- 每张原图生成最长边 1200 的渐进式 JPEG 预览。
- 另生成 480、960、1600、2400 四档 WebP。
- 浏览器根据视口与像素密度选择合适尺寸。
- 原图仍可通过公开照片路径直接访问。
Deployment & Operations
生产环境健康,发布路径清晰,回滚与持久数据已经分离。
截至本次检查,Nginx 与 stillframe-admin 均为 active,API 健康检查正常,没有 failed systemd units。服务器资源仍有明显余量。
Nginx 监听 80/443,HTTP 自动跳转 HTTPS,TLS 1.2/1.3。
systemd 托管 Node,绑定 127.0.0.1:8787,失败自动重启。
Let's Encrypt,覆盖 liangmx.cn 与 www,有效至 2026-10-15,自动续期计时器正常。
根分区使用约 5.7 / 40 GB,约 16%,当前容量不是瓶颈。
使用约 691 MiB / 1.6 GiB;静态前台降低了常驻内存需求。
NoNewPrivileges、PrivateTmp、ProtectHome、ProtectSystem 已启用。
发布目录
/var/www/stillframe/releases 保存不可变发布版本,/var/www/stillframe/current 指向当前版本,默认保留最近 5 版。
持久目录
/var/lib/stillframe/catalog.json 保存目录;photos 和 previews 保存原图与衍生图。它们不随发布版本删除。
后台代码
/opt/stillframe/app 保存应用代码。Nginx 仅把受 Basic Auth 保护的 /admin/ 与 /api/ 转发到本机 Node。
release 可以回退页面和应用代码,但 catalog.json、原图与预览图属于持续变化的持久数据。当前仓库没有发现自动定时备份脚本,因此应把这三类数据单独做异地或对象存储备份。
Risks & Gaps
当前没有阻断使用的功能缺陷,但有一项服务器暴露需要立即处理。
风险优先级按“外部可利用性、数据损失影响、维护成本”排列。P0 应立即处理,P1 应在下一轮维护完成,P2 可随增长逐步建设。
服务器上的 Redis 监听在 0.0.0.0:6379,且从外部网络实测可连接;UFW 当前未启用。这很可能是遗留服务,不属于 Stillframe 必需组件。应立即在云防火墙关闭 6379,并将 Redis 绑定到 localhost;若已无用途则停用服务。
| 级别 | 事项 | 现状与影响 | 建议动作 |
|---|---|---|---|
| P0 | Redis 公网暴露 | 6379 可从公网连接,扩大未授权访问和数据破坏风险。 | 云安全组关闭端口;绑定 127.0.0.1;不用则停用。 |
| P1 | 持久数据无自动备份证据 | 发布回滚不覆盖目录与照片,误删或磁盘故障可能造成不可恢复损失。 | 每日备份 catalog + 原图;保留多版本并做恢复演练。 |
| P1 | 站内说明已经过时 | “关于”页仍描述纯静态原型,“报告”页仍写没有报告,与当前后台和生产部署不一致。 | 更新公开文案,避免使用者误判能力。 |
| P1 | 后台是单账号 Basic Auth | 适合单人使用,但没有会话、角色、审计、CSRF 令牌和细粒度权限。 | 保持单人时可继续用;增加编辑者前先升级认证。 |
| P1 | 缺少部分安全响应头 | 已有 nosniff 与 Referrer-Policy,尚未观察到 HSTS、CSP、Permissions-Policy。 | 逐步补齐,先在报告模式验证 CSP。 |
| P2 | 原图可公开直访 | 访客若知道照片 URL,可下载完整原图;对版权与带宽有影响。 | 明确是否允许;否则公开站只暴露大尺寸 WebP 或加水印版本。 |
| P2 | 只接受 JPG | HEIC、PNG、TIFF 等工作流需要先手工转换。 | 有真实需求时再做导入转码,避免扩大处理面。 |
| P2 | SEO / 分享信息不完整 | 缺少社交分享图、sitemap 和结构化数据,搜索发现能力有限。 | 补 Open Graph、canonical、sitemap、robots。 |
| P2 | 两级结构固定 | 适合“拍鸟 → 白头鹎”,不适合无限层级或复杂标签体系。 | 优先增加标签而不是继续加深目录层级。 |
Extension Roadmap
下一步不应先重写系统,而应先把现有系统变得可恢复、可发现、可扩容。
当前架构与规模匹配。只有当照片量、编辑人数或查询复杂度发生实质变化时,数据库和对象存储才会带来净收益。
关闭 Redis 公网入口;建立目录与原图自动备份;更新过时的关于和报告页面。
正式录入二级相册;增加标签、拍摄地点、物种等字段;补充 SEO 与分享元数据。
图片迁移到对象存储与 CDN;增加缓存失效策略;选择是否隐藏原图。
当出现多编辑者时,再引入账号体系、角色、审计日志、数据库与任务队列。
继续沿用当前架构的条件
- 主要由一人编辑,更新频率不高。
- 照片仍在数千张以内,目录文件可快速读写。
- 分类以两级相册和少量标签为主。
- 每次更新允许进行一次静态重建。
考虑数据库 / 对象存储的信号
- 多位编辑者同时操作,需要权限和审计。
- 照片达到约 5,000 张以上,筛选与批量操作明显变慢。
- 需要复杂检索、EXIF 查询、标签组合或公开 API。
- 源站带宽成为瓶颈,需要 CDN 和自动图像服务。
1. 关闭 6379 公网访问;2. 建立并验证自动备份;3. 更新站内说明;4. 用真实“拍鸟 → 白头鹎”数据运行二级相册;5. 再根据检索需求设计标签,不急于迁移数据库。