Files
stash/HANDOFF.md
T
CNWei 27e411fd2c refactor(db): 删除旧分区展示块与兼容字段
- v23 迁移删除 section_block 表,以及 node 的 view_mode / empty_text / show_in_sidebar / allow_groups
- 重建 node 表并保留 44 条内容、15 个分组、5 张卡片,外键检查通过
- 种子库直接生成 card / card_group,不再依赖 section_block
- 删除旧 /api/catalog、/api/categories、/api/groups/{id} 与 categories 模块
- 分组接口不再接收/返回 format,前端 GroupNode 同步移除
- README/HANDOFF 更新到 v23;管理页提示改为『格式由每条内容决定』
2026-11-02 20:24:08 +08:00

14 KiB
Raw Blame History

Stash 交接文档

写于 2026-10-29。新会话第一件事:读这份 + docs/ADMIN-PLAN.md + stash-ui/README.md。

⚠️ 这是一份历史快照,只保留当时的决策背景。 2026-11-01 之后又做了这些改动, 下面正文里提到的文件名与页面结构可能已经不同,以 README.md 为准:

  • 前端 App.tsx → AppNext.tsx,后台 admin/AdminPage.tsx → admin/AdminNext.tsx(旧文件已删除);
  • 后台从横向 Tabs 改成左侧导航 + 右侧内容,页头归到「首页管理」下, Tab 名改为 分组管理 / 数据管理 / 首页管理(页头·侧边栏·内容卡片)/ 资料管理 / 系统管理;
  • 新增 /interface 接口一览页;侧栏「查看接口」走站内路由,不再直接开 /api/projects;
  • 接入 @stash/ui 组件库:前后台所有卡片、表格、开关、文字按钮都来自库里, 明暗主题(浅色 / 深色 / 跟随系统)由令牌接管;
  • 内容库表结构升到 v23 并有了自动迁移,卡片模型是 card + card_group;section_block 与旧 node 兼容字段已删除。

0. 一句话现状

Stash 已从「只读本地导航站」升级为可登录、可配置、可编辑内容的本地发布台:

  • 登录(单用户,argon2id + Cookie 会话);
  • /admin 设置页(页头滚动信息 / 首页卡片 / 归类 / 侧栏 / 资料 / 系统);
  • 条目就地编辑(Drawer + 乐观锁);
  • 分区新增/删除、条目新增/删除(可选分区与分组)、分组(子分类)新建/改名/删除、侧栏子分类配置、浏览/点赞/分享/跳转;
  • 数据库自动迁移到 v18;
  • 前端 100% 使用组件库 @stash/ui(v0.3.1,42 个组件)。

当前数据库已设置管理员密码(2026-10-30 由使用者设置);忘记密码按 §6 删除 admin 行即可回到首次设置。

1. 仓库与运行环境

项目 路径 分支 端口 说明
新版(组件重构) D:\CNWei\CNW\Rust\stash feat/use-stash-ui 8080 所有新功能都在这里
旧版(1:1 基线) D:\CNWei\CNW\Rust\stash-old(worktree) develop 8081 只用于视觉对照,不要改
组件库 D:\CNWei\CNW\Rust\stash-ui master — tag v0.1.0 / v0.2.0 / v0.3.0 / v0.3.1

后端:Rust 2024 + Axum 0.8 + rusqlite(bundled)。前端:React 19 + Vite + TS + CSS Modules,@stash/ui 通过 file: 依赖引入。

启动 / 构建(顺序重要)

# 1) 前端(产物会被 build.rs 内嵌,必须先构建)
cd D:\CNWei\CNW\Rust\stash\stash-web
npm run build

# 2) 先杀掉正在运行的 stash.exe,否则 cargo 会报「拒绝访问」
Get-Process stash -ErrorAction SilentlyContinue | Where-Object { $_.Path -like '*stash\target*' } | Stop-Process -Force

# 3) 后端
cd ..
cargo build
Start-Process .\target\debug\stash.exe -RedirectStandardOutput "$env:TEMP\stash.log" -RedirectStandardError "$env:TEMP\stash-err.log" -WindowStyle Hidden

旧版(8081,仅在需要对照时):

D:\CNWei\CNW\Rust\stash-old\target\debug\stash.exe --port 8081

测试

Windows 下 TEMP 权限有问题,跑测试要覆盖临时目录:

$env:TEMP = "D:\CNWei\CNW\Rust\stash\target\tmp"; $env:TMP = $env:TEMP
cargo test        # 当前 48 passed

2. 目录 / 文件地图

src/
  main.rs / lib.rs            启动、日志
  config.rs                   端口 / 数据目录(默认 target/debug/data)
  server.rs                   全部路由(API + 内嵌前端 + SPA 回落)
  error.rs                    StashError(含 Conflict → 409)
  db/
    mod.rs                    Db 门面(所有方法)+ 迁移测试
    schema.rs                 建表、种子、版本迁移(0/15→16→17)
    auth.rs                   管理员、密码哈希、会话(token 只存 sha256)
    settings.rs               settings JSON(header/sidebar/sections/profile)
    entries.rs                条目读取/编辑、浏览数、点赞、审计
    categories.rs             分区新增/删除
    catalog.rs                查询组装(前端三种视图)
stash-web/src/
  App.tsx                     主页壳、登录弹窗、编辑器、设置应用
  main.tsx                    入口分流(/admin 与 /login)
  auth.ts / settings.ts / items.ts   前端 API 客户端
  components/
    header/SiteHeader.tsx     品牌 + 滚动信息 + 操作图标
    admin/AdminPage.tsx       /admin 全部 Tab
    auth/LoginDialog.tsx      Modal 登录
    auth/PasswordInput.tsx    带显隐切换的密码框
    content/                  首页、分区、条目、文章、编辑器
    sidebar/                  资料卡、服务面板、导航
docs/ADMIN-PLAN.md            后台方案 + P0–P4 实施记录 + 未做项
README.md                     运行、路由、库结构、登录说明

3. 功能清单(已完成)

登录

  • 单用户 admin,密码 argon2id;
  • 会话:随机 32 字节 token,HttpOnly + SameSite=Strict + Path=/,7 天,库里存 sha256;
  • 登录失败 5 次锁 60 秒;写接口校验 Origin;写接口需要会话。

/admin(新原子模型)

Tab 能力
分组管理 树形表格:新建根分组(左侧)、加子分组、编辑(名称/上级/图标/排序/状态)、删除;格式已下沉到条目,不再在分组上设置
内容 选分组以列表展示条目(选主分组时包含所有子分组);列:标题 / 格式 / 跳转链接 / 所属分组 / 操作;每条内容单独选格式(应用/海报/图文),同一分组可混合
侧边栏 顶部「侧栏卡片」控制本地管理员 / 本地服务显隐;下方「分组导航」逐项勾选;开关即保存
首页卡片 左侧列表含「本地服务」只读表(不可删除,但可拖动排序)+ 自建卡片;右侧分组表格;表格内开关/条数即时保存,标题用「保存」按钮
页头 启用开关、速度、条目、标签与色调
资料 头像 URL、名称、角色、简介、位置
系统 修改密码、下载备份

保存:分组/内容/卡片逐项保存;侧边栏、页头、资料走 PATCH /api/settings(version 乐观锁)。

内容编辑

  • 详情页 [编辑] 只在登录后显示;
  • 打开右侧 Drawer:标题、简介、标签、一句话评价、正文 Markdown、封面、跳转地址;
  • PATCH /api/items/{key},updatedAt 乐观锁;
  • 保存后 catalog.reload() 局部刷新,不整页刷新。

详情操作条

  • 浏览:进入页面 POST /api/items/{key}/view,数字 +1;
  • 点赞:可切换,POST /like,localStorage 记住状态;
  • 分享:复制当前链接,Toast 反馈;
  • 跳转:保存时规范化 href(www. 自动补 https://,拒绝 javascript: 等协议);为空或 # 时按钮置灰。

4. HTTP API

GET    /api/health
GET    /api/projects            GET /api/projects/events (SSE)
GET    /api/catalog2            分组树 + 卡片(新前台/后台)
GET    /api/cards               卡片列表
POST   /api/nodes               {key,title,parentKey?,icon?,sort?,enabled?}   需登录
PATCH  /api/nodes/{key}         {title,parentKey?,sort?,icon?,enabled?} 需登录
DELETE /api/nodes/{key}                                          需登录,级联
POST   /api/cards               {title}                          需登录
PATCH  /api/cards/{id}          {title?,sort?}                   需登录
DELETE /api/cards/{id}                                           需登录
PUT    /api/cards/{id}/groups   [{groupKey,previewLimit}]        需登录

GET    /api/auth/session        -> {authenticated, has_admin, username}
POST   /api/auth/setup          {password}        仅当无管理员
POST   /api/auth/login          {password}
POST   /api/auth/logout
PATCH  /api/auth/password       {current, next}

GET    /api/settings            -> {version, settings}
PATCH  /api/settings            {version, settings}     需登录

GET    /api/items/{key}         -> 原始字段(编辑表单)
POST   /api/items               {key,nodeKey,item}      需登录
PATCH  /api/items/{key}         {updatedAt, item, nodeKey?}  需登录,nodeKey 可移动条目
DELETE /api/items/{key}                                  需登录
POST   /api/items/{key}/view
POST   /api/items/{key}/like    {liked}

GET    /api/backup              SQLite 快照附件         需登录

5. 数据库与迁移

  • 文件:开发态在 target/debug/data/stash.db;可用 --root / 数据目录覆盖(见 config.rs)。
  • 当前 PRAGMA user_version = 23;schema::migrate 逐级升级:0 建全量、15→16→17→18→19→20→21→22→23、更高版本拒绝启动。
  • 格式在 entry.format(apps / posters / articles),同组可混合;node 不再保存格式。
  • v23 迁移删除 section_block 表与 node 的 view_mode / empty_text / show_in_sidebar / allow_groups 字段。
  • settings.sidebar.show_profile / show_service 控制侧栏两张卡片显隐(默认 true)。
  • 首页滚动:#page-scroll(Layout 的 body)是唯一滚动容器,搜索框固定在其上方;左右两栏顶部对齐,左侧到底后通过 translateY 吸底,右侧继续滚动;滚动条隐藏;页头实底,搜索框 50% 透明,顶部另有一层上下渐隐的软虚化(blur(8px))。
  • 本地服务是运行时卡片,但 card 表里有一行 local-service 只用于排序;内容来自 /api/projects,后端禁止删除/改名/配置分组。
  • node 是统一分组树(根节点 kind='section',子节点 kind='group' 可多层);enabled 控制启停;icon 可为空。
  • 主要表:node、entry、entry_tag、card、card_group、admin、session、setting、audit。
  • entry.updated_at 用于编辑乐观锁;setting 表 key='site' 存站点 JSON。
  • 设置/内容都是 SQLite:备份用 /api/backup,恢复需停机替换文件。

6. 认证运维

  • 忘记密码:删除 admin 行(或整库)后重启 → 回到首次设置。
    node -e "const {DatabaseSync}=require('node:sqlite');const d=new DatabaseSync('target/debug/data/stash.db');d.exec('DELETE FROM admin; DELETE FROM session;')"
    
  • 改密码:/admin → 系统,成功后该账号所有会话失效,需要重新登录。
  • 首个管理员由 /api/auth/setup 创建,密码至少 8 位。

7. 组件库 @stash/ui

  • 42 个组件,文档站:cd stash-ui && npm run dev(也可 npm run build:site 后看 dist-site)。
  • 关键命令:npm run typecheck && npm run lint && npm run build && npm run build:site。
  • 组件契约:docs/COMPONENTS.md;设计规范:DESIGN.md;外部风格接入流程:docs/STYLE-INTAKE.md(闸门:截图 → 映射 → 决策 → 评审 → 再写代码)。
  • 主题:themes/example.css 只改变量;页面禁止写组件内部选择器。
  • 判断归属:全局配置放 /admin;页面版式(间距、布局容器)写在页面 CSS;只有「第二个页面也复用」的才抽组件。

8. 验证与截图

  • 后端逻辑:cargo test(48 passed,覆盖迁移/登录/设置/条目编辑/分区)。
  • 前端构建:stash-web npm run build(tsc -b + vite)。
  • 视觉/交互:Playwright 脚本在 stash-ui/.ref/*.mjs(不提交 git),截图在 stash-ui/shots/。
    • measure-final.mjs 已过时(旧 1:1 对照用),选择器 .app header 仍可用;
    • c3-check.mjs、d-check.mjs、p2-check.mjs 是后期功能检查脚本。
  • 常用冒烟:首页卡片、/admin 各 Tab、详情编辑、登录弹窗。

9. 已知限制 / 未做

项 状态
备份恢复/导入 只提供下载快照;恢复需停机替换 stash.db
回收站/软删除 未做,删除分组会级联删子分组与条目(有二次确认)
图片上传 只支持 URL;上传需存储目录、大小/类型校验
拖拽排序 分组/卡片顺序暂用创建顺序;上移下移/拖拽未做
多用户/角色 未做,当前单管理员
分组移动 编辑弹窗里可改「上级分组」(防环);根分组不能移到子级
条目移动 内容弹窗里可直接换分组(PATCH /api/items/{key} 的 nodeKey)
分组排序 可编辑「排序权重」数值;拖拽排序未做
旧接口 已删除 /api/catalog、/api/categories/*、旧 /api/groups/{id};当前只保留 /api/catalog2 与 /api/nodes
登录限流 进程内计数,重启清空

10. 约定与坑

  • 回复用中文,表格化优先;视觉工作要截图验证。
  • 任何共享组件改动都要在 docs/COMPONENTS.md 补契约 + changelog,并说明兼容性。
  • PowerShell 写文件注意 UTF-8;优先用编辑工具,别用 Set-Content 写带中文的源码。
  • 改前端后必须 npm run build 再 cargo build,否则内嵌资源是旧的。
  • 重启前先杀 stash.exe,否则 cargo 报「拒绝访问」。
  • /login 是旧地址,main.tsx 会重定向到 /;登录已改为弹窗。
  • 前端路由:/、/g/<分组 key>、/g/<分组 key>/i/<条目>;旧 /c/... 地址按第一个路径段当分组 key 兼容,/admin 独立壳。

11. 新会话建议的下一步

  1. 先跑 cargo test + 打开 8080 冒烟,确认基线;
  2. 若要继续产品化:条目移动 UI、回收站、图片上传、拖拽排序;
  3. 若要发布:确认 stash-ui 以 file: 引入的方式在发布构建里如何锁定版本(建议改为 git tag 依赖或构建前 npm pack)。