Browse Source

docs(spec): admin user list stats and public profile links

Made-with: Cursor
main
npmrun 8 hours ago
parent
commit
584aabe5b8
  1. 64
      docs/superpowers/specs/2026-04-18-admin-user-stats-design.md

64
docs/superpowers/specs/2026-04-18-admin-user-stats-design.md

@ -0,0 +1,64 @@
# 设计:管理员用户列表 — 逐用户统计与公开页链接
**日期**:2026-04-18
**状态**:已定稿(与产品对话一致)
## 1. 背景与目标
管理员(代码中与 **`role === 'admin'`** 一致,沿用 `requireAdmin`;不引入新角色)在「用户管理」页需要:
1. **逐用户统计**(表格列):文章数、时间线条目数、RSS 订阅源数。
2. **跳转与复制**:当用户存在 **`publicSlug`** 时,可打开站内公开主页 `/@{publicSlug}`,并可将 **完整 URL**(`origin + '/@' + publicSlug`)复制到剪贴板。
**明确不包含(第一期)**:RSS 条目总数(`rss_items`)、全局汇总卡片、代用户登录、仅按可见性过滤后的计数。
## 2. 统计语义
对每位用户,三个计数均为对应表中 **`user_id` 等于该用户 id 的全表行数**,**不按** `visibility` 或其它展示规则过滤。理由:该页面向运营/审计,需反映库内真实数据量;若未来要「仅公开内容」计数,应单独开需求并改字段命名以免歧义。
## 3. 架构与方案选择
在已选方案下:**扩展现有 `GET /api/admin/users`**,在同一分页响应中为每个用户返回三个非负整数字段,避免二次请求与 id 合并问题。
未采用:独立 stats 接口、用户表冗余计数列。
## 4. API 契约
- **路径**:`GET /api/admin/users`(不变)。
- **鉴权**:现有全局 auth + `requireAdmin`
- **分页**:沿用现有 `limit`(默认 50,最大 100)、`offset`。
- **响应**:`users` 数组元素在现有字段(`id`, `username`, `email`, `role`, `status`, `publicSlug`, `createdAt`)基础上增加:
| 字段 | 类型 | 说明 |
|------|------|------|
| `postCount` | 整数 ≥ 0 | `posts` 表中该 `user_id` 行数 |
| `timelineEventCount` | 整数 ≥ 0 | `timeline_events` 表中该 `user_id` 行数 |
| `rssFeedCount` | 整数 ≥ 0 | `rss_feeds` 表中该 `user_id` 行数 |
实现细节:使用 Drizzle + SQLite 可维护的聚合方式(例如相关子查询或等价 join),以保证与分页 `ORDER BY` 一致且性能可接受;`user_id` 上应可利用现有外键/索引。
## 5. 前端(用户管理页)
**文件**:`app/pages/me/admin/users/index.vue`(为主变更点)。
- 表格新增三列,展示上述三个计数。
- **`publicSlug` 非空**:
- **打开**:链到路由 `/@{publicSlug}`(与站内其它公开页一致)。
- **复制**:点击后写入剪贴板的 URL 应与浏览器打开 `/@{publicSlug}` 时一致;推荐使用 `URL(\`/@${publicSlug}\`, window.location.origin).href` 生成,避免手写拼接与编码不一致。
- **`publicSlug` 为空**:不渲染可点击外链;复制按钮禁用或隐藏,并显示「—」等占位。
- **复制失败**:向用户展示简短错误提示(与项目现有 toast/通知模式一致)。
## 6. 错误与边界
- 计数为 `0` 时正常显示。
- 网络或权限错误沿用现有 `request`/`unwrap` 行为。
## 7. 测试
第一期以手动验证为主。若仓库已有 admin 列表或 Drizzle 集成测试惯例,可补充最小用例(例如种子数据下某用户的三个计数);非强制阻塞项,在实现计划中标注。
## 8. 非目标
- 不修改 `users` 表结构。
- 不增加 `rss_items` 计数列。
- 不实现「超级管理员」与 `admin` 的区分。
Loading…
Cancel
Save