docs(photo-wall): server-side image storage + deploy notes
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
d038372336
commit
f88686cd21
@ -1,10 +1,14 @@
|
|||||||
# 照片墙 Photo Wall(`#photo` 入口)
|
# 照片墙 Photo Wall(`#photo` 入口)
|
||||||
|
|
||||||
模拟软木板/墙面的互动照片展示页:上传本地照片,以宝丽来风格散落摆放,用胶带、
|
模拟软木板/墙面的互动照片展示页:上传本地照片,以宝丽来风格散落摆放,用胶带、
|
||||||
图钉、便签、贴纸、印章、手绘箭头自由装扮,可导出为一张 PNG。**纯前端**(无后端改动),
|
图钉、便签、贴纸、印章、手绘箭头自由装扮,可导出为一张 PNG。
|
||||||
状态存浏览器 `localStorage`。
|
|
||||||
|
|
||||||
设计来源:`photo-wall-design.docx`(产品设计文档 v1.0)。本页是其 React 重写版。
|
**职责切分**:图片字节**按登录用户存服务器**(最多 10 张/人、严格私有、JWT 鉴权);
|
||||||
|
背景、装饰、以及每张图的排版覆盖**存浏览器 `localStorage`**(按服务器图片 id 关联)。
|
||||||
|
|
||||||
|
设计来源:`photo-wall-design.docx`(产品设计文档 v1.0);服务器存图设计见
|
||||||
|
[specs/2026-06-24-photo-wall-server-storage-design.md](superpowers/specs/2026-06-24-photo-wall-server-storage-design.md)。
|
||||||
|
本页是其 React 重写版。
|
||||||
|
|
||||||
## 入口与鉴权流
|
## 入口与鉴权流
|
||||||
|
|
||||||
@ -22,32 +26,58 @@
|
|||||||
- **已登录**用户访问 `#photo` 会跳过登录页,直接进墙。
|
- **已登录**用户访问 `#photo` 会跳过登录页,直接进墙。
|
||||||
- 墙内右上角「退出」= 清登录态 + 抹掉地址栏 `#photo`,回到导航页(`StartPage`)。
|
- 墙内右上角「退出」= 清登录态 + 抹掉地址栏 `#photo`,回到导航页(`StartPage`)。
|
||||||
|
|
||||||
## 涉及文件(全部前端)
|
## 涉及文件
|
||||||
|
|
||||||
|
前端:
|
||||||
- `Client/src/App.tsx` — 监听 `hashchange`:`#photo` 短路 gate,置 `wantsPhoto`;
|
- `Client/src/App.tsx` — 监听 `hashchange`:`#photo` 短路 gate,置 `wantsPhoto`;
|
||||||
已登录 + `wantsPhoto` → 渲染 `PhotoWallPage`,否则博客页。
|
已登录 + `wantsPhoto` → 渲染 `PhotoWallPage`(传入会话 `token`),否则博客页。
|
||||||
- `Client/src/components/LoginPage.tsx` — 新增 `hideStats` 开关,隐藏顶部
|
- `Client/src/components/LoginPage.tsx` — 新增 `hideStats` 开关,隐藏顶部
|
||||||
`AnnouncementBar`(系统负载栏);把轮询的 `useSystemStats` 拆进只在显示时挂载的
|
`AnnouncementBar`(系统负载栏);把轮询的 `useSystemStats` 拆进只在显示时挂载的
|
||||||
`StatsBar` 子组件,隐藏时不发请求。
|
`StatsBar` 子组件,隐藏时不发请求。
|
||||||
|
- `Client/src/hooks/useAuth.ts` — `Auth` 暴露 `token`(JWT),供图片接口鉴权。
|
||||||
|
- `Client/src/api/photos.ts` — 图片接口封装:`listPhotos`/`uploadPhoto`/`deletePhoto`/
|
||||||
|
`fetchPhotoObjectUrl`(带 `Authorization: Bearer` 头;读取取 blob 成 objectURL)。
|
||||||
- `Client/src/components/PhotoWallPage.tsx` — 照片墙组件本体。
|
- `Client/src/components/PhotoWallPage.tsx` — 照片墙组件本体。
|
||||||
- `Client/src/index.css` — 末尾 `.pw-` 命名空间的全部照片墙美术样式(软木板/宝丽来/
|
- `Client/src/index.css` — 末尾 `.pw-` 命名空间的全部照片墙美术样式。
|
||||||
便签折角/胶带/图钉等,无法用 Tailwind 表达的部分)。
|
|
||||||
|
|
||||||
> 后端零改动:登录走既有 `/api/web/login`,照片墙数据只存浏览器,不落服务器。
|
后端(Rust):
|
||||||
|
- `Server/src/auth.rs` — `issue_token(username)` 签发 HS256 JWT、`verify_token` 校验。
|
||||||
|
- `Server/src/routes/extract.rs` — `AuthUser` 提取器(`Authorization: Bearer` → 用户名,失败 401)。
|
||||||
|
- `Server/src/photos.rs` — `PhotoStore`:按用户隔离到 `PHOTO_DIR/<用户>/`,含路径安全、
|
||||||
|
类型/大小/数量限额(≤10 张、单图 ≤8MiB),save 加锁防并发越额。
|
||||||
|
- `Server/src/routes/web.rs` — 图片接口(见下);登录改签带用户名的 JWT;CORS 放行
|
||||||
|
`DELETE`/`Authorization`;图片路由 body 上限放宽至 16MB。
|
||||||
|
|
||||||
|
## 接口(均经 `AuthUser` 鉴权)
|
||||||
|
|
||||||
|
| 方法 | 路径 | 行为 |
|
||||||
|
|---|---|---|
|
||||||
|
| GET | `/api/web/photos` | 列出当前用户图片 id(`{ items:[{id}], max:10 }`) |
|
||||||
|
| POST | `/api/web/photos` | 上传(body `{ dataUrl }`);满 10 张 409、超 8MiB 413、类型错 415 |
|
||||||
|
| GET | `/api/web/photos/{id}` | 流式返回字节(属主校验,非法/不存在 404) |
|
||||||
|
| DELETE | `/api/web/photos/{id}` | 删除 |
|
||||||
|
|
||||||
|
存储:`PHOTO_DIR`(默认 `photo-wall`,线上 `/opt/internet-project/photo-wall/`)下
|
||||||
|
每用户一子目录,每图随机十六进制文件名。`JWT_SECRET` 环境变量为签名密钥。
|
||||||
|
|
||||||
## 功能
|
## 功能
|
||||||
|
|
||||||
- **照片**:宝丽来白边(底部加大留白)、随机旋转 ±15°、立体投影;三种随机固定方式
|
- **照片**:宝丽来白边(底部加大留白)、随机旋转 ±15°、立体投影;三种随机固定方式
|
||||||
(胶带 / 彩色图钉 / 双角胶带)。
|
(胶带 / 彩色图钉 / 双角胶带)。
|
||||||
- **交互**:拖拽移动、双击编辑标注、右键菜单(旋转 ±5°、放大/缩小、移到最前/最后、
|
- **交互**:拖拽移动、双击编辑标注、右键菜单(旋转 ±15°、放大/缩小、移到最前/最后、
|
||||||
删除;便签额外可改色)。触摸端长按 = 右键。
|
旋转角度预设 0/15/30/45/90°、放大比例预设 0.5/0.75/1/1.5/2×、删除;便签额外可改色)。
|
||||||
|
触摸端长按 = 右键。
|
||||||
- **装饰**:便签(5 色 + 折角)、胶带条、12 预设贴纸 + 自定义文字、SVG 印章、手绘箭头
|
- **装饰**:便签(5 色 + 折角)、胶带条、12 预设贴纸 + 自定义文字、SVG 印章、手绘箭头
|
||||||
(选中后在画布拖动绘制)。
|
(选中后在画布拖动绘制)。
|
||||||
- **背景**:软木板 / 黑板 / 白墙 / 牛皮纸,工具栏循环切换。
|
- **背景**:软木板 / 黑板 / 白墙 / 牛皮纸,工具栏循环切换。
|
||||||
- **上传**:按钮选择 / 拖入画布 / 剪贴板粘贴(`FileReader` 读 Base64)。
|
- **上传**:按钮选择 / 拖入画布 / 剪贴板粘贴(`FileReader` 读 Base64 → 传服务器);
|
||||||
|
满 10 张前端拦下、服务器 409 兜底。
|
||||||
- **历史**:撤销/重做 Ctrl+Z / Ctrl+Y,最多 30 步。
|
- **历史**:撤销/重做 Ctrl+Z / Ctrl+Y,最多 30 步。
|
||||||
- **持久化**:操作后防抖 1s 自动写 `localStorage`,key `photo-wall-state`
|
- **持久化**:图片存服务器;**排版/装饰**操作后防抖 1s 自动写 `localStorage`,key
|
||||||
(`{ bgIndex, els }`);工具栏显示「保存中…/已保存」。
|
`photo-wall-state`(`{ bgIndex, decorations, photoLayout }`,`photoLayout` 按服务器
|
||||||
|
图片 id 关联位置/旋转/缩放/层级/标注/宽度);工具栏显示「保存中…/已保存」。
|
||||||
|
无本地排版的图片首次加载时自动散落摆放。读到旧结构(`{ bgIndex, els }`,照片带
|
||||||
|
base64)时只取其装饰部分,旧照片丢弃。
|
||||||
- **导出**:`html2canvas`(CDN 懒加载)截图画布为 `photo-wall-<时间戳>.png`。
|
- **导出**:`html2canvas`(CDN 懒加载)截图画布为 `photo-wall-<时间戳>.png`。
|
||||||
|
|
||||||
## 实现注记
|
## 实现注记
|
||||||
@ -60,6 +90,7 @@
|
|||||||
|
|
||||||
## 线上访问
|
## 线上访问
|
||||||
|
|
||||||
部署后:`http://8.130.143.54:8548/#photo`(纯前端改动,按
|
`http://8.130.143.54:8548/#photo`。服务器存图引入了后端改动 → 走**全量重部署**
|
||||||
[部署计划](superpowers/plans/2026-06-18-deploy.md)的 frontend-only redeploy 路径上线,
|
(重编 Rust → 传二进制 → `restart_rust.sh` 重启),非 frontend-only。需在服务器
|
||||||
后端无需重启)。
|
`weather.env` 配 `JWT_SECRET`;首次上传自动建 `photo-wall/<用户>/`。**因 token 格式
|
||||||
|
从旧的时间戳哈希变为 JWT,上线后用户需重新登录一次。**
|
||||||
|
|||||||
@ -251,6 +251,15 @@ curl -s -o /dev/null -w '%{http_code}\n' http://8.130.143.54:8548/api/client/hea
|
|||||||
A helper exists on the server: `/opt/internet-project/restart_rust.sh`. The
|
A helper exists on the server: `/opt/internet-project/restart_rust.sh`. The
|
||||||
previous binary is kept as `RustServer.bak` for rollback.
|
previous binary is kept as `RustServer.bak` for rollback.
|
||||||
|
|
||||||
|
**照片墙服务器存图(2026-06-24,后端改动):**
|
||||||
|
照片墙从纯前端 localStorage 改为按用户存服务器(`#photo` 入口,详见
|
||||||
|
[photo-wall.md](../../photo-wall.md))。这引入了后端改动,需**全量重部署**(非
|
||||||
|
frontend-only):重编 Rust → 传二进制 → `restart_rust.sh` 重启。新增两个运行时配置:
|
||||||
|
- `JWT_SECRET`(写在 `/opt/internet-project/weather.env`)—— 登录 token 改为 HS256
|
||||||
|
JWT 的签名密钥,未设则用内置开发密钥并告警。**token 格式变了,上线后用户需重登一次。**
|
||||||
|
- `PHOTO_DIR`(可选,默认 `photo-wall`,即 `/opt/internet-project/photo-wall/`)——
|
||||||
|
图片按用户存到其下子目录,首次上传自动创建。
|
||||||
|
|
||||||
> Startpage backgrounds: large PNG/JPG source images are pre-compressed to WebP
|
> Startpage backgrounds: large PNG/JPG source images are pre-compressed to WebP
|
||||||
> (quality ~82) before building — keeps each background under ~600 KB for the
|
> (quality ~82) before building — keeps each background under ~600 KB for the
|
||||||
> 3 Mbps server link. Two sets live under `Client/src/assets/startpage/`:
|
> 3 Mbps server link. Two sets live under `Client/src/assets/startpage/`:
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user