# 验收清单:持久排序(folders + bookmarks)+ 触屏拖拽 > 目标:文件夹与书签都能在 PC/手机端拖动排序,刷新后顺序保持;同时无滚动条但仍可滚动;根目录(未分组)视为一个“虚拟文件夹组”。 ## 0. 前置条件 - 已启动 Postgres,且 `.env` 配置正确(支持放在 repo 根目录 `.env` 或 `apps/server/.env`)。 - 推荐先重建数据库(开发阶段方便确保 schema 一致)。 ### 0.1(可选)确认 `.env` 参考根目录 `.env.example`。 关键项: - `DATABASE_HOST/DATABASE_PORT/DATABASE_NAME/DATABASE_USER/DATABASE_PASSWORD` - `AUTH_JWT_SECRET` - `ADMIN_EMAIL`(可选,用于验收管理端) ## 1. 重建数据库(强烈建议) > 注意:此操作会 DROP 表并清空数据,仅用于开发环境。 在仓库根目录执行: - `npm -w apps/server run db:reset` 预期:命令成功结束;下次启动服务不会再出现缺列(例如 `sort_order`)相关报错。 ### 1.1(可选)用 SQL 验证列存在 - `\d bookmarks` 应包含 `sort_order` - `\d bookmark_folders` 应包含 `sort_order` 或执行: ```sql select column_name from information_schema.columns where table_schema=current_schema() and table_name='bookmarks' order by column_name; ``` ## 2. 启动(server + web) 在仓库根目录各开一个终端: - Server:`npm -w apps/server run dev` - Web:`npm -w apps/web run dev` 预期: - Server 健康检查:`GET http://localhost:3001/health` 返回 `{ ok: true }` - Web 能正常访问并登录。 ## 3. UI/交互验收(PC) ### 3.1 “无滚动条但可滚动” - 进入 Web 页面(任意长列表页) - 鼠标滚轮/触控板滚动 预期:页面可以滚动,但看不到滚动条(侧边/底部不出现条)。 ### 3.2 “我的书签”展开/折叠 - 进入 `/my` - 点击任意文件夹头部 预期:能展开/收起;不会出现“点击没反应”。 ### 3.3 文件夹拖拽排序(同父级) - 保证至少有 2 个同级文件夹(同一个 parent 下) - 在 `/my` 使用文件夹右侧的拖拽柄(⋮⋮)拖动排序 预期: - 能拖动、松手后顺序变化 - 刷新页面后顺序保持 约束预期: - 不允许跨父级拖动(不同 parent 的文件夹不能混排) ### 3.4 书签拖拽排序(根目录 + 文件夹内) - 在“未分组(根目录)”组内拖动书签排序 - 展开某个文件夹,在该文件夹内拖动书签排序 预期: - 两处都能拖动排序 - 刷新页面后顺序保持 - 拖拽柄拖动不会误触打开链接 ### 3.5 搜索模式禁用排序 - 在 `/my` 的搜索框输入关键字(进入过滤状态) - 尝试拖动(文件夹/书签) 预期:拖拽排序不生效(避免搜索时误操作导致重排)。 ## 4. 触屏验收(手机/模拟器) - 打开 `/my` - 长按拖拽柄(⋮⋮)并移动 预期: - 文件夹可拖动排序(同父级) - 书签可拖动排序(根目录/文件夹内) - 刷新后顺序保持 ## 5. 管理端验收(可选,需要 ADMIN_EMAIL) ### 5.1 设置管理员 - `.env` 设置 `ADMIN_EMAIL=你用来登录的邮箱` - 重新启动 server ### 5.2 访问管理端 - 用该邮箱登录 - 打开 `/admin` 预期: - 能看到用户列表 - 选择用户后,能看到该用户的文件夹与书签(按 sortOrder 展示) - 删除书签/删除文件夹/复制书签到管理员账号能正常工作 ## 6. 常见失败点与定位 - 拖拽接口返回 409:数据库 schema 未包含 `sort_order`,请先跑 `npm -w apps/server run db:migrate` 或直接 `db:reset`。 - 拖拽后刷新不保存:检查 server 日志是否收到 `/folders/reorder`、`/bookmarks/reorder`;以及 web 是否使用同一个 `VITE_SERVER_BASE_URL`。 - “点击文件夹没反应”:优先查看浏览器控制台是否有运行时错误(应已修复模板误用 `.value` 的问题)。