docs+feat: 重构规格与 Gitea 式 SSR 骨架(首页)
在 rebuild/gitea-ssr 落地产品规格、Cursor 规则,以及 Go 模板 SSR 首页/板块列表;未迁移路径仍回落 SPA,便于对照 main。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
185
docs/rebuild-spec/01-product.md
Normal file
185
docs/rebuild-spec/01-product.md
Normal file
@@ -0,0 +1,185 @@
|
||||
# 01 · 产品定位与模块地图
|
||||
|
||||
> **读者**:重构架构师 / 产品对齐
|
||||
> **前置**:[README.md](README.md)
|
||||
> **后续**:[02-features.md](02-features.md)
|
||||
> **源码**:[docs/introduction.md](../introduction.md)、[README.md](../../README.md)
|
||||
|
||||
---
|
||||
|
||||
## 1. 定位
|
||||
|
||||
姜十三论坛不做大而全公网社区,只服务「几人到几百人」的内部交流:
|
||||
|
||||
| 场景 | 说明 |
|
||||
|------|------|
|
||||
| 团队 / 工作室 | 需求讨论、进度同步、知识沉淀 |
|
||||
| 兴趣小圈子 | 同好交流、作品分享、活动组织 |
|
||||
| 项目配套社区 | 可与 Gitea 通过 OIDC(开放身份连接)做 SSO(单点登录) |
|
||||
| 个人站长 | 希望数据自管、部署简单 |
|
||||
|
||||
**产品口号气质**:能聊 · 好看 · 好装(部署简单)。
|
||||
|
||||
**规模预期**:非百万用户级;信息密度接近 V2EX / NGA 一类,而非大留白营销站。
|
||||
|
||||
---
|
||||
|
||||
## 2. 产品 vs 运维(拆开看待)
|
||||
|
||||
| 维度 | 当前实现 | 重构时 |
|
||||
|------|----------|--------|
|
||||
| **产品** | 论坛功能全集(见模块地图) | **必须对齐**功能与规则 |
|
||||
| **运维** | 单二进制 + 内嵌 SPA + SQLite + `app.ini` | **可选保留**;可换容器 / PG / 分离部署 |
|
||||
|
||||
规格文档把「用户能做什么」写死;把「怎么打包发布」放在 [07-config-ops.md](07-config-ops.md) 供参考。
|
||||
|
||||
---
|
||||
|
||||
## 3. 角色模型
|
||||
|
||||
| 角色 | 识别 | 能力摘要 |
|
||||
|------|------|----------|
|
||||
| **游客** | 未登录 | 浏览公开内容;可发表游客评论(需昵称等);门控内容按规则遮盖 |
|
||||
| **登录用户** | JWT Cookie 有效且未禁言 | 发帖、评论、点赞收藏、私信、签到抽奖、友链申请、举报等 |
|
||||
| **认证用户** | `user.verified = true` | 与管理员一样:**发帖/评论免审**(`SkipsModeration`) |
|
||||
| **管理员** | `role = admin` | 全部后台能力;免审;看待审/被拒内容 |
|
||||
| **系统** | 私信 `from_user_id = 0` | 发系统通知(审核、回复提醒、举报结果等) |
|
||||
|
||||
**引导规则**:站点**第一个注册用户自动成为管理员**(无安装向导单独建管步骤)。
|
||||
|
||||
禁言用户(`banned`):带鉴权的写接口被拒绝;浏览策略以实现为准,前端通常视为不可正常互动。
|
||||
|
||||
---
|
||||
|
||||
## 4. 模块地图
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph core [核心社区]
|
||||
auth[认证与账号]
|
||||
board[板块]
|
||||
feed[Feed与搜索]
|
||||
post[帖子与特殊类型]
|
||||
comment[评论]
|
||||
gate[内容门控]
|
||||
end
|
||||
subgraph social [社交]
|
||||
like[点赞收藏]
|
||||
msg[私信与通知]
|
||||
profile[用户主页]
|
||||
report[举报]
|
||||
end
|
||||
subgraph economy [经济与成长]
|
||||
points[积分钱包]
|
||||
checkin[签到抽奖]
|
||||
badge[徽章]
|
||||
level[等级Exp]
|
||||
end
|
||||
subgraph site [站点扩展]
|
||||
page[自定义单页]
|
||||
links[友情链接]
|
||||
gitea[Gitea码桶]
|
||||
brand[品牌与SEO]
|
||||
end
|
||||
subgraph admin [管理与集成]
|
||||
mod[审核回收站]
|
||||
settings[系统设置]
|
||||
oidc[OIDC Provider]
|
||||
storage[本地或S3存储]
|
||||
mail[SMTP邮件]
|
||||
end
|
||||
auth --> feed
|
||||
board --> feed
|
||||
feed --> post
|
||||
post --> comment
|
||||
post --> gate
|
||||
post --> like
|
||||
comment --> msg
|
||||
points --> gate
|
||||
points --> checkin
|
||||
auth --> oidc
|
||||
settings --> mail
|
||||
settings --> storage
|
||||
```
|
||||
|
||||
### 4.1 认证与账号
|
||||
|
||||
- 注册 / 登录 / 登出;可选邮箱验证码;忘记密码重置
|
||||
- 图形验证码(注册场景)
|
||||
- 个人资料:昵称、签名、头像、改密
|
||||
- 邮件未配置时可能关闭公开注册(见业务规则)
|
||||
|
||||
### 4.2 板块与 Feed
|
||||
|
||||
- 多板块;图标与色板;排序
|
||||
- 首页「全部」+ `/board/:id`
|
||||
- 排序:最新发帖 / 最新回复 / 热门
|
||||
- 搜索:关键词、标签、作者、仅标题
|
||||
- 列表样式:仅标题 / 摘要 / 缩略图(后台可配)
|
||||
|
||||
### 4.3 帖子
|
||||
|
||||
- 富文本正文(HTML,TipTap 产出)+ 可选 Markdown 编辑面
|
||||
- 标签、修订历史与 diff
|
||||
- 五种类型:`normal` | `question` | `poll` | `bounty` | `lottery`
|
||||
- 运营标记:全局置顶、版内置顶、精华、禁止编辑、禁止评论
|
||||
- 审核状态:`pending` | `published` | `rejected`;软删回收站
|
||||
|
||||
### 4.4 内容门控
|
||||
|
||||
正文内嵌自定义标签(非独立表行,存在 `posts.content` HTML 中):
|
||||
|
||||
| 标签 | 含义 |
|
||||
|------|------|
|
||||
| `<members-only>` | 登录可见 |
|
||||
| `<reply-only>` | 本帖已回复可见 |
|
||||
| `<points-only data-cost="N">` | 积分解锁;按块计费 |
|
||||
|
||||
### 4.5 评论
|
||||
|
||||
- 楼层号;回复指定楼;嵌套展示;引用;@ 提及
|
||||
- 游客评论字段;私密评论(仅相关人可见)
|
||||
- 点赞、编辑时限、审核、软删
|
||||
|
||||
### 4.6 积分经济与成长
|
||||
|
||||
- **Points**:可消费积分(签到、抽奖、解锁、悬赏托管等)
|
||||
- **Exp**:不可消费经验 → 等级 Lv1–10
|
||||
- **CreatorIncomeTotal**:创作分成累计(徽章指标)
|
||||
- 徽章:自动(门槛)+ 限定(管理员发放)
|
||||
|
||||
### 4.7 私信与通知
|
||||
|
||||
统一走 `private_messages` 表,用 `kind` 区分用户私信与系统事件。
|
||||
|
||||
### 4.8 友链与站点页
|
||||
|
||||
- 管理员维护品牌友链 JSON;用户申请审核(可选回链检测)
|
||||
- 自定义单页(关于、版规等):slug、发布、导航/页脚展示
|
||||
|
||||
### 4.9 Gitea 开源码桶
|
||||
|
||||
后台配置后定时同步公开仓库到 `gitea_repos`,前台 `/projects` 展示。
|
||||
|
||||
### 4.10 OIDC Provider
|
||||
|
||||
本站作为 IdP:Discovery / Authorize / Token / UserInfo / Logout / JWKS;多 OAuth 客户端。
|
||||
|
||||
### 4.11 管理后台
|
||||
|
||||
仪表盘、板块、单页、友链、帖/评、举报、用户、徽章、媒体、系统设置、SQLite 备份。
|
||||
|
||||
### 4.12 SEO / 发现
|
||||
|
||||
`robots.txt`、`sitemap.xml`、Open Graph / Twitter / JSON-LD;当前另有爬虫 HTML。新站应用 SSR 统一,但 **meta 字段集合应保留**(见 [07-config-ops.md](07-config-ops.md))。
|
||||
|
||||
---
|
||||
|
||||
## 5. 权限一句话
|
||||
|
||||
- **读公开内容**:人人可(含游客)
|
||||
- **写内容**:登录(部分评论允许游客)
|
||||
- **审与运营**:管理员
|
||||
- **免审写**:管理员或 `verified`
|
||||
|
||||
细节状态机见 [05-business-rules.md](05-business-rules.md)。
|
||||
211
docs/rebuild-spec/02-features.md
Normal file
211
docs/rebuild-spec/02-features.md
Normal file
@@ -0,0 +1,211 @@
|
||||
# 02 · 功能清单(验收级)
|
||||
|
||||
> **读者**:实现与验收
|
||||
> **前置**:[01-product.md](01-product.md)
|
||||
> **交叉**:[05-business-rules.md](05-business-rules.md)、[06-pages-ux.md](06-pages-ux.md)
|
||||
> **源码对照**:[`frontend/src/App.tsx`](../../frontend/src/App.tsx)、[`router/router.go`](../../router/router.go)、[`README.md`](../../README.md)
|
||||
|
||||
用复选框做验收;重构完成时应全部可勾选(或书面声明砍掉的功能)。
|
||||
|
||||
---
|
||||
|
||||
## A. 浏览与布局
|
||||
|
||||
- [ ] 三栏布局:左导航 / 中 Feed / 右栏小组件
|
||||
- [ ] 浅色 / 暗色主题;跟随系统偏好并本地记忆
|
||||
- [ ] 响应式:平板/手机收起侧栏
|
||||
- [ ] 长列表虚拟滚动或等价流畅方案
|
||||
- [ ] Feed 排序:`latest`(最新发帖)/ `reply`(最新回复)/ `hot`(热门)
|
||||
- [ ] 板块筛选:全部 + 单板块
|
||||
- [ ] 列表样式可配:`title` | `excerpt` | `thumbnail`
|
||||
- [ ] 搜索:关键词、标签、作者、仅标题(`title_only`)
|
||||
- [ ] 右栏:热门帖、标签云、最新评论、最新用户、友链(可开关排序)
|
||||
- [ ] 登录用户右栏/侧边:签到与抽奖入口
|
||||
- [ ] 下拉刷新(移动端)
|
||||
- [ ] 可选伪静态:`/post/123.html` 等形式(后缀后台可配)
|
||||
- [ ] 404 页
|
||||
|
||||
---
|
||||
|
||||
## B. 认证与个人中心
|
||||
|
||||
- [ ] 注册(用户名、密码、昵称、邮箱;可选邮箱验证码)
|
||||
- [ ] 图形验证码接口(注册流程)
|
||||
- [ ] 登录 / 登出(会话 Cookie)
|
||||
- [ ] 忘记密码:邮箱验证码 + 重置
|
||||
- [ ] 注册配置接口:是否首用户、邮件是否就绪、是否开放注册
|
||||
- [ ] 首个用户自动成为管理员
|
||||
- [ ] 个人中心:改昵称、签名、密码、上传头像(可裁剪)
|
||||
- [ ] 个人活动统计:帖数、评数、收藏数、获赞
|
||||
- [ ] 公开用户主页 `/user/:id`(无邮箱)
|
||||
- [ ] 禁言用户无法使用需登录写接口
|
||||
|
||||
---
|
||||
|
||||
## C. 板块
|
||||
|
||||
- [ ] 列出板块(含帖数等展示字段)
|
||||
- [ ] 管理员:创建 / 改 / 删板块
|
||||
- [ ] 板块名称、描述、图标、色板索引、排序
|
||||
- [ ] 默认板块保障(空站可引导创建)
|
||||
|
||||
---
|
||||
|
||||
## D. 帖子(通用)
|
||||
|
||||
- [ ] 发帖:选板块、标题、标签、正文
|
||||
- [ ] 正文图片上传
|
||||
- [ ] TipTap 富文本能力(见 [06-pages-ux.md](06-pages-ux.md) 编辑器节)
|
||||
- [ ] Markdown 编辑模式(与富文本互转/双模)
|
||||
- [ ] 编辑帖子(时限、锁帖约束)
|
||||
- [ ] 删除帖子 → 软删进回收站
|
||||
- [ ] 修订历史列表与单条详情(可做 diff)
|
||||
- [ ] 点赞切换;收藏切换;收藏列表页
|
||||
- [ ] 浏览量(可 `skip_view=1` 跳过计数)
|
||||
- [ ] 举报帖子
|
||||
- [ ] 内容审核状态展示(作者可见待审/被拒)
|
||||
|
||||
### D.1 帖子类型
|
||||
|
||||
- [ ] `normal` 普通讨论
|
||||
- [ ] `question` 问答:可标记已解决 / 未解决
|
||||
- [ ] `poll` 投票:2–10 选项;单选/多选;可选截止时间;投票;作者可结束
|
||||
- [ ] `bounty` 悬赏:发帖托管积分;采纳评论发奖;可退款(规则见 05)
|
||||
- [ ] `lottery` 抽奖帖:设定中奖人数;从评论参与者开奖
|
||||
|
||||
### D.2 运营标记(管理员)
|
||||
|
||||
- [ ] 全局置顶 / 取消
|
||||
- [ ] 版内置顶 / 取消(仅板块列表抬升)
|
||||
- [ ] 精华 / 取消
|
||||
- [ ] 禁止编辑(edit lock)
|
||||
- [ ] 禁止评论 / 结贴(comments lock)
|
||||
- [ ] 审核通过 / 拒绝(拒绝可通知作者)
|
||||
- [ ] 回收站:恢复 / 彻底删除
|
||||
|
||||
---
|
||||
|
||||
## E. 内容门控
|
||||
|
||||
- [ ] 编辑器可插入「登录可见」块
|
||||
- [ ] 编辑器可插入「回复可见」块
|
||||
- [ ] 编辑器可插入「积分可见」块(可设价格)
|
||||
- [ ] 未登录:遮盖 members-only 与 reply-only 正文,保留长度提示
|
||||
- [ ] 已登录未回复:遮盖 reply-only(作者与管理员始终可见)
|
||||
- [ ] 积分块:未解锁遮盖;`POST .../unlock` 扣积分并返回 inner HTML
|
||||
- [ ] 搜索 / SEO 出口对门控内容做红action,不泄露正文
|
||||
|
||||
---
|
||||
|
||||
## F. 评论
|
||||
|
||||
- [ ] 按帖拉取评论列表(楼层、嵌套父级、引用目标)
|
||||
- [ ] 发表评论(登录);支持 `reply_to`、私密评论
|
||||
- [ ] 游客评论(公开接口可写,字段 guest_*)
|
||||
- [ ] 编辑评论(时限);删除评论
|
||||
- [ ] 评论点赞
|
||||
- [ ] 评论举报
|
||||
- [ ] @ 提及 → 通知
|
||||
- [ ] 回复提醒(站内信 + 可选邮件)
|
||||
- [ ] 审核中 / 被拒评论可见性规则
|
||||
- [ ] 管理员:通过 / 拒绝 / 回收站 / 查看评论修订
|
||||
|
||||
---
|
||||
|
||||
## G. 私信与通知
|
||||
|
||||
- [ ] 会话列表(含系统会话 peer=0)
|
||||
- [ ] 会话消息(分页 / before 游标)
|
||||
- [ ] 发送私信
|
||||
- [ ] 未读数(可分私信 / 通知)
|
||||
- [ ] 标记会话已读 / 通知已读 / 全部已读
|
||||
- [ ] 系统通知种类:`system` / `reject` / `report_result` / `reply` / `mention` / `moderation` 等
|
||||
|
||||
---
|
||||
|
||||
## H. 积分、签到、抽奖、徽章、等级
|
||||
|
||||
- [ ] 积分流水查询
|
||||
- [ ] 每日签到:基础 5,连签每日 +1,封顶 15
|
||||
- [ ] 每日抽奖:奖池加权(0/2/5/10/20),成本 0
|
||||
- [ ] 积分解锁分成:读者付全额,作者约 70%
|
||||
- [ ] 短龄同 IP 互刷拒绝分成
|
||||
- [ ] Exp → 等级 Lv1–10
|
||||
- [ ] 自动徽章(注册天数 / 获赞 / 创作分成)
|
||||
- [ ] 限定徽章:管理员定义与授予/撤销
|
||||
- [ ] 管理员调整积分、设定等级
|
||||
|
||||
---
|
||||
|
||||
## I. 友链
|
||||
|
||||
- [ ] 前台友链页;导航/页脚入口可配
|
||||
- [ ] 用户申请(名称、URL、Logo、是否上首页、回链页)
|
||||
- [ ] Logo 上传
|
||||
- [ ] 我的申请列表;修改待审申请;取消
|
||||
- [ ] 管理员审核:通过 / 拒绝 / 重新检测回链
|
||||
- [ ] 管理员维护品牌友链列表(设置里 JSON)
|
||||
|
||||
---
|
||||
|
||||
## J. 站点单页
|
||||
|
||||
- [ ] 公开:`/page/:slug` 列表入口(nav/footer)
|
||||
- [ ] 管理员 CRUD;发布开关;排序;nav/footer 展示开关
|
||||
|
||||
---
|
||||
|
||||
## K. Gitea 码桶
|
||||
|
||||
- [ ] 后台开关、Base URL、Token、同步间隔
|
||||
- [ ] 手动同步 + 后台定时同步
|
||||
- [ ] 前台 `/projects` 列表与搜索
|
||||
|
||||
---
|
||||
|
||||
## L. OIDC Provider
|
||||
|
||||
- [ ] Discovery、JWKS、Authorize、Token、UserInfo、Logout
|
||||
- [ ] 多 OAuth 客户端 CRUD;密钥哈希存储;PKCE 字段支持
|
||||
- [ ] groups claim 映射 admin/user 组
|
||||
|
||||
---
|
||||
|
||||
## M. 媒体与存储
|
||||
|
||||
- [ ] 本地 uploads 或 S3 兼容存储(可热切换配置)
|
||||
- [ ] 头像 / 帖图 / 站点品牌资源分类
|
||||
- [ ] 图片展示可选 WebP 转换(`/media/thumb/...`)
|
||||
- [ ] 管理后台媒体列表与删除
|
||||
- [ ] 媒体索引表同步
|
||||
|
||||
---
|
||||
|
||||
## N. 管理后台其它
|
||||
|
||||
- [ ] 仪表盘:计数 + 待审帖/评/举报/友链 + 最近帖
|
||||
- [ ] 敏感词文件读写
|
||||
- [ ] 论坛限流与字数等 Limits
|
||||
- [ ] SMTP 配置与测试信
|
||||
- [ ] 站点品牌:名称、标语、简介、keywords、Logo、Favicon、OG 图、ICP
|
||||
- [ ] SQLite 一键备份与下载
|
||||
|
||||
---
|
||||
|
||||
## O. 基础设施
|
||||
|
||||
- [ ] `GET /health`
|
||||
- [ ] `robots.txt` / `sitemap.xml`
|
||||
- [ ] 静态上传文件可达
|
||||
- [ ] 限流:发帖、评论、注册、登录、举报、私信、友链等
|
||||
|
||||
---
|
||||
|
||||
## 明确不在当前规格内(计划中可后做)
|
||||
|
||||
摘自 [`ROADMAP.md`](../../ROADMAP.md),**不是**现网必交验收项:
|
||||
|
||||
- 通知动态 UX 大幅优化
|
||||
- 帖子搜索增强(组合筛选更强)
|
||||
|
||||
若新站一并实现,可作为加分项,不阻塞「功能对等」验收。
|
||||
452
docs/rebuild-spec/03-data-model.md
Normal file
452
docs/rebuild-spec/03-data-model.md
Normal file
@@ -0,0 +1,452 @@
|
||||
# 03 · 数据模型
|
||||
|
||||
> **读者**:实现数据库与领域层的 AI
|
||||
> **前置**:[01-product.md](01-product.md)
|
||||
> **后续**:[04-api.md](04-api.md)、[05-business-rules.md](05-business-rules.md)
|
||||
> **源码**:[`model/models.go`](../../model/models.go)、[`model/oauth.go`](../../model/oauth.go)、[`model/gitea.go`](../../model/gitea.go)、[`model/level.go`](../../model/level.go)、[`model/db.go`](../../model/db.go)、[`model/user_view.go`](../../model/user_view.go)、[`service/settings.go`](../../service/settings.go)
|
||||
|
||||
当前无独立 SQL migration;表由 GORM `AutoMigrate` 创建。新站可用正式 migration,但**字段语义应对齐**。
|
||||
|
||||
---
|
||||
|
||||
## 1. ER 概览
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
User ||--o{ Post : authors
|
||||
User ||--o{ Comment : authors
|
||||
Board ||--o{ Post : contains
|
||||
Post ||--o{ Comment : has
|
||||
Post ||--o{ PostLike : likes
|
||||
Post ||--o{ PostFavorite : favorites
|
||||
Post ||--o{ PostRevision : revisions
|
||||
Comment ||--o{ CommentLike : likes
|
||||
Comment ||--o{ CommentRevision : revisions
|
||||
Post ||--o| Poll : poll
|
||||
Poll ||--o{ PollOption : options
|
||||
PollOption ||--o{ PollVote : votes
|
||||
Post ||--o{ PostLotteryWinner : winners
|
||||
Post ||--o{ PostContentUnlock : unlocks
|
||||
User ||--o{ PointLedger : ledger
|
||||
User ||--o{ CheckIn : checkins
|
||||
User ||--o{ LotteryDraw : draws
|
||||
User ||--o{ UserBadge : earns
|
||||
BadgeDef ||--o{ UserBadge : defines
|
||||
User ||--o{ PrivateMessage : sends
|
||||
User ||--o{ PostReport : reports
|
||||
User ||--o{ FriendLinkApply : applies
|
||||
User ||--o{ Media : uploads
|
||||
```
|
||||
|
||||
另有:`ForumSetting`(键值)、`OAuthClient` / `OAuthAuthCode`、`GiteaRepo`、`SitePage`。
|
||||
|
||||
---
|
||||
|
||||
## 2. 表与字段
|
||||
|
||||
说明:`json:"-"` 表示默认 API 序列化隐藏;软删列 `deleted_at` 表示 GORM soft delete。
|
||||
|
||||
### 2.1 users
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| id | uint PK | | |
|
||||
| username | string(128) | unique, not null | 登录名 |
|
||||
| email | string(128) | index, default '' | 公开主页不返回 |
|
||||
| password | string(128) | not null | bcrypt 哈希,永不返回 |
|
||||
| nickname | string(64) | | 展示名 |
|
||||
| signature | string(512) | default '' | 个人签名 |
|
||||
| avatar | string(512) | | 相对或绝对 URL |
|
||||
| role | string(16) | default `user` | `user` \| `admin` |
|
||||
| verified | bool | index | 站长认证,免审 |
|
||||
| exp | int | default 0 | 经验(不可消费) |
|
||||
| points | int | default 0 | 可用积分 |
|
||||
| creator_income_total | int | default 0 | 创作分成累计 |
|
||||
| banned | bool | | 禁言 |
|
||||
| banned_at | *time | | |
|
||||
| last_login_at | *time | json 隐藏 | |
|
||||
| last_login_ip | string(45) | json 隐藏 | |
|
||||
| last_access_at | *time | json 隐藏 | 带鉴权访问 |
|
||||
| created_at / updated_at | time | | |
|
||||
| deleted_at | soft | | |
|
||||
|
||||
**非落库展示字段**:`level`(由 Exp 推导)、`badges`(附加)。
|
||||
|
||||
视图结构:`UserPublic` / `UserSelf` / `UserAdmin`(见 [`model/user_view.go`](../../model/user_view.go))。
|
||||
|
||||
### 2.2 boards
|
||||
|
||||
| 字段 | 说明 |
|
||||
|------|------|
|
||||
| id, name(64), description(512) | |
|
||||
| icon(64), color_index(default -1) | -1=按 id 自动取色 |
|
||||
| sort_order | 升序 |
|
||||
| created_at, updated_at, deleted_at | |
|
||||
|
||||
### 2.3 posts
|
||||
|
||||
| 字段 | 说明 |
|
||||
|------|------|
|
||||
| id, board_id, user_id | FK 索引 |
|
||||
| title(256), content(text) | HTML 正文 |
|
||||
| content_plain(text) | 纯文本搜索索引,`json:"-"` |
|
||||
| tags(256) | 逗号或空格分隔标签串 |
|
||||
| post_type | `normal`\|`question`\|`poll`\|`bounty`\|`lottery` |
|
||||
| question_resolved | 仅问答 |
|
||||
| bounty_points, bounty_status, bounty_comment_id | 悬赏 |
|
||||
| lottery_winner_count, lottery_status | 抽奖帖 |
|
||||
| pinned | 全局置顶 |
|
||||
| board_pinned | 版内置顶 |
|
||||
| featured | 精华 |
|
||||
| edit_locked | 禁止编辑 |
|
||||
| comments_locked | 禁止新评论 |
|
||||
| status | `pending`\|`published`\|`rejected` |
|
||||
| like_count, view_count | |
|
||||
| timestamps + soft delete | |
|
||||
|
||||
关联:Board, User, Comments。
|
||||
|
||||
### 2.4 post_revisions
|
||||
|
||||
每次修改前保存旧版:`post_id`, `editor_id`, `title`, `content`, `tags`, `created_at`。
|
||||
|
||||
### 2.5 comments
|
||||
|
||||
| 字段 | 说明 |
|
||||
|------|------|
|
||||
| post_id, user_id | user_id=0 表示游客 |
|
||||
| floor | 楼层号 |
|
||||
| content | HTML/富文本 |
|
||||
| reply_to | *uint 回复目标评论 |
|
||||
| guest_nick / guest_email / guest_url | 游客信息 |
|
||||
| is_private | 私密评论 |
|
||||
| status | pending\|published\|rejected |
|
||||
| like_count | |
|
||||
| soft delete | |
|
||||
|
||||
**非落库**:`reply_target`, `thread_parent_id`, `content_hidden`, `liked`。
|
||||
|
||||
### 2.6 comment_revisions
|
||||
|
||||
`comment_id`, `editor_id`, `content`, `created_at`(管理员可查)。
|
||||
|
||||
### 2.7 post_likes / comment_likes / post_favorites
|
||||
|
||||
唯一索引:(post_id|comment_id, user_id)。收藏带 Post 关联。
|
||||
|
||||
### 2.8 private_messages
|
||||
|
||||
| 字段 | 说明 |
|
||||
|------|------|
|
||||
| from_user_id | 0=系统 |
|
||||
| to_user_id | |
|
||||
| subject(256), content(text) | |
|
||||
| kind | 见枚举 |
|
||||
| related_post_id, related_report_id | 可选 |
|
||||
| is_read | |
|
||||
| created_at | |
|
||||
|
||||
### 2.9 post_reports
|
||||
|
||||
帖或评举报:`post_id` 必填;`comment_id` 有值则为评论举报。
|
||||
`reason`, `detail`, `status`, `handler_id`, `handle_note`, `handled_at`。
|
||||
|
||||
### 2.10 friend_link_applies
|
||||
|
||||
申请字段:name, url, description, logo, reciprocal_page_url, link_on_homepage,
|
||||
reciprocal_verified / check_note / checked_at, status, review_note, reviewed_at + soft delete。
|
||||
|
||||
### 2.11 media
|
||||
|
||||
上传索引:`category`=`avatars`\|`posts`\|`site`;`name`, `url`(unique), `size`, `content_type`, `storage_type`=`local`\|`s3`, `user_id`。
|
||||
|
||||
### 2.12 point_ledgers
|
||||
|
||||
`user_id`, `delta`, `balance`(变动后), `reason`, `ref_type`, `ref_id`, `note`, `created_at`。
|
||||
|
||||
### 2.13 check_ins
|
||||
|
||||
唯一 `(user_id, day)`,day=`YYYY-MM-DD`;`points`, `streak`。
|
||||
|
||||
### 2.14 lottery_draws
|
||||
|
||||
每日抽奖唯一 `(user_id, day)`;`points` 可为 0。
|
||||
|
||||
### 2.15 post_content_unlocks
|
||||
|
||||
唯一 `(user_id, post_id, block_key)`;`cost`。
|
||||
|
||||
### 2.16 site_pages
|
||||
|
||||
`title`, `slug`(unique), `content`, `published`, `sort_order`, `show_in_footer`, `show_in_nav` + soft delete。
|
||||
|
||||
### 2.17 polls / poll_options / poll_votes
|
||||
|
||||
- Poll:`post_id` unique;`multi`, `max_choices`, `closed`, `ends_at`
|
||||
- Option:`post_id`, `text`(64), `sort_order`, `vote_count`
|
||||
- Vote:唯一 `(post_id, option_id, user_id)`(多选时多行)
|
||||
|
||||
### 2.18 post_lottery_winners
|
||||
|
||||
`post_id`, `user_id`, `comment_id`, `created_at`。
|
||||
|
||||
### 2.19 badge_defs / user_badges
|
||||
|
||||
BadgeDef:`code` unique, `name`, `description`, `icon`, `kind`=`auto`\|`limited`, `metric`, `threshold`, `sort_order`, `enabled`。
|
||||
UserBadge:唯一 `(user_id, badge_id)`;`awarded_at`, `awarded_by`(0=系统)。
|
||||
|
||||
### 2.20 forum_settings
|
||||
|
||||
| 字段 | 说明 |
|
||||
|------|------|
|
||||
| key | PK string(64) |
|
||||
| value | string(2048) |
|
||||
|
||||
### 2.21 oauth_clients / oauth_auth_codes
|
||||
|
||||
Client:`client_id` unique, `client_secret_hash`, `name`, `redirect_uris`(可多行), `enabled`。
|
||||
AuthCode:一次性码 + PKCE 字段 + `expires_at` + `used`。
|
||||
|
||||
### 2.22 gitea_repos
|
||||
|
||||
同步缓存:`gitea_id` unique, owner/name/full_name, description, html_url, language, stars/forks, private, updated_at_remote, forum_user_id, synced_at。
|
||||
|
||||
---
|
||||
|
||||
## 3. 枚举全集
|
||||
|
||||
### 3.1 角色 Role
|
||||
|
||||
`user` | `admin`
|
||||
|
||||
### 3.2 内容状态 ContentStatus
|
||||
|
||||
`pending` | `published` | `rejected`
|
||||
|
||||
### 3.3 帖类型 PostType
|
||||
|
||||
`normal` | `question` | `poll` | `bounty` | `lottery`
|
||||
|
||||
### 3.4 悬赏 BountyStatus
|
||||
|
||||
`open` | `awarded` | `refunded`(空串视为非悬赏)
|
||||
|
||||
### 3.5 帖内抽奖 PostLotteryStatus
|
||||
|
||||
`open` | `drawn`
|
||||
|
||||
### 3.6 私信 kind
|
||||
|
||||
| 值 | 含义 |
|
||||
|----|------|
|
||||
| user | 用户互发 |
|
||||
| system | 系统通知 |
|
||||
| reject | 帖/评被拒 |
|
||||
| report_result | 举报处理结果 |
|
||||
| reply | 被回复 |
|
||||
| mention | 被 @ |
|
||||
| moderation | 待审提醒管理员 |
|
||||
|
||||
### 3.7 举报
|
||||
|
||||
Status:`pending` | `resolved` | `dismissed`
|
||||
Reason:`spam` | `abuse` | `illegal` | `irrelevant` | `other`
|
||||
|
||||
### 3.8 友链申请
|
||||
|
||||
`pending` | `approved` | `rejected`
|
||||
|
||||
### 3.9 积分 reason
|
||||
|
||||
| 值 | 含义 |
|
||||
|----|------|
|
||||
| check_in | 签到 |
|
||||
| lottery | 每日抽奖 |
|
||||
| unlock_spend | 解锁消费 |
|
||||
| creator_income | 创作分成 |
|
||||
| admin_adjust | 管理员调账 |
|
||||
| bounty_escrow | 悬赏托管 |
|
||||
| bounty_award | 悬赏发放 |
|
||||
| bounty_refund | 悬赏退回 |
|
||||
|
||||
### 3.10 徽章
|
||||
|
||||
Kind:`auto` | `limited`
|
||||
Metric:`tenure_days` | `likes_received` | `creator_income`
|
||||
|
||||
---
|
||||
|
||||
## 4. 等级(Exp → Level)
|
||||
|
||||
源:[`model/level.go`](../../model/level.go)
|
||||
|
||||
| Level | 最低 Exp |
|
||||
|-------|----------|
|
||||
| 1 | 0 |
|
||||
| 2 | 20 |
|
||||
| 3 | 50 |
|
||||
| 4 | 100 |
|
||||
| 5 | 200 |
|
||||
| 6 | 400 |
|
||||
| 7 | 800 |
|
||||
| 8 | 1500 |
|
||||
| 9 | 3000 |
|
||||
| 10 | 5000 |
|
||||
|
||||
管理员设等级时,应把 Exp 调到该等级门槛(见后台 API)。
|
||||
|
||||
---
|
||||
|
||||
## 5. 内置自动徽章(seed)
|
||||
|
||||
源:[`model/db.go`](../../model/db.go) `seedDefaultBadges`
|
||||
|
||||
| code | 名称 | metric | threshold |
|
||||
|------|------|--------|-----------|
|
||||
| tenure_30 | 初来乍到 | tenure_days | 30 |
|
||||
| tenure_365 | 资深居民 | tenure_days | 365 |
|
||||
| likes_10 | 小有人气 | likes_received | 10 |
|
||||
| likes_100 | 人气作者 | likes_received | 100 |
|
||||
| likes_1000 | 人气巨星 | likes_received | 1000 |
|
||||
| income_100 | 小有进账 | creator_income | 100 |
|
||||
| income_1000 | 创作达人 | creator_income | 1000 |
|
||||
|
||||
已存在同 `code` 则跳过插入。
|
||||
|
||||
---
|
||||
|
||||
## 6. forum_settings 键与默认值
|
||||
|
||||
源:[`service/settings.go`](../../service/settings.go)、[`service/permalink.go`](../../service/permalink.go)
|
||||
|
||||
### 6.1 论坛限制
|
||||
|
||||
| Key | 默认 | 说明 |
|
||||
|-----|------|------|
|
||||
| post_edit_window_hours | 24 | 0 可表示特殊策略,以实现为准 |
|
||||
| comment_edit_window_minutes | 3 | |
|
||||
| rate_limit_post | 10 | 窗口内次数 |
|
||||
| rate_limit_comment | 10 | |
|
||||
| rate_limit_register | 10 | |
|
||||
| rate_limit_login | 10 | |
|
||||
| rate_limit_window_sec | 60 | |
|
||||
| post_title_max | 128 | |
|
||||
| post_tags_max | 256 | |
|
||||
| post_content_max | 50000 | |
|
||||
| comment_max | 5000 | |
|
||||
| search_keyword_min | 1 | |
|
||||
| search_keyword_max | 50 | |
|
||||
| page_size_default | 30 | API 硬上限 100 |
|
||||
| password_min_len | 6 | |
|
||||
| avatar_max_mb | 2 | |
|
||||
| signature_max | 200 | |
|
||||
| open_posts_in_new_tab | 1 | |
|
||||
| open_content_links_in_new_tab | 1 | |
|
||||
|
||||
### 6.2 Feed / 侧栏 / 友链展示
|
||||
|
||||
| Key | 默认 |
|
||||
|-----|------|
|
||||
| feed_list_style | `title`(另有 `excerpt` / `thumbnail`) |
|
||||
| aside_show_tag_cloud | 0 |
|
||||
| aside_show_recent_comments | 0 |
|
||||
| aside_show_friend_links | 1 |
|
||||
| aside_widgets | JSON 数组,见下 |
|
||||
| nav_show_friend_links | 1 |
|
||||
| footer_show_friend_links | 1 |
|
||||
| friend_link_reciprocal_check | 0 |
|
||||
| permalink_enabled | 0 |
|
||||
| permalink_ext | `html` |
|
||||
|
||||
默认 `aside_widgets`:
|
||||
|
||||
```json
|
||||
[
|
||||
{"id":"tag_cloud","enabled":false},
|
||||
{"id":"recent_comments","enabled":false},
|
||||
{"id":"friend_links","enabled":true}
|
||||
]
|
||||
```
|
||||
|
||||
合法 widget id:`tag_cloud` | `recent_comments` | `recent_users` | `friend_links`。
|
||||
|
||||
### 6.3 SMTP
|
||||
|
||||
| Key | 默认 |
|
||||
|-----|------|
|
||||
| smtp_enabled | 0 |
|
||||
| smtp_host | |
|
||||
| smtp_port | 465 |
|
||||
| smtp_username / smtp_password | |
|
||||
| smtp_from | |
|
||||
| smtp_from_name | 姜十三论坛 |
|
||||
| smtp_encryption | `ssl`(另有 `none` / `starttls`) |
|
||||
|
||||
### 6.4 OIDC
|
||||
|
||||
| Key | 默认 |
|
||||
|-----|------|
|
||||
| oidc_enabled | 0 |
|
||||
| oidc_root_url | |
|
||||
| oidc_group_claim | groups |
|
||||
| oidc_admin_group | gitea-admin |
|
||||
| oidc_user_group | gitea-users |
|
||||
|
||||
### 6.5 Gitea 同步
|
||||
|
||||
| Key | 默认 |
|
||||
|-----|------|
|
||||
| gitea_sync_enabled | 0 |
|
||||
| gitea_base_url | |
|
||||
| gitea_token | |
|
||||
| gitea_sync_interval_min | 60 |
|
||||
|
||||
### 6.6 存储
|
||||
|
||||
| Key | 默认 |
|
||||
|-----|------|
|
||||
| storage_type | local |
|
||||
| storage_endpoint / region / bucket | region 默认 us-east-1 |
|
||||
| storage_access_key / storage_secret_key | |
|
||||
| storage_public_base_url / storage_prefix | |
|
||||
| storage_force_path_style | 1 |
|
||||
| storage_image_delivery | webp(或 original) |
|
||||
|
||||
### 6.7 站点品牌
|
||||
|
||||
| Key | 默认 |
|
||||
|-----|------|
|
||||
| site_name | 姜十三论坛 |
|
||||
| site_slogan | 拾三一隅,自在交流 |
|
||||
| site_description / site_keywords | 空 |
|
||||
| site_logo_mark | 姜 |
|
||||
| site_logo / site_favicon / site_og_image | 空 |
|
||||
| site_icp_beian | 空 |
|
||||
| site_icp_beian_url | https://beian.miit.gov.cn/ |
|
||||
| site_friend_links | `[]` JSON,最多 20 条 |
|
||||
|
||||
---
|
||||
|
||||
## 7. 升级兼容补丁(现网 InitDB)
|
||||
|
||||
[`model/db.go`](../../model/db.go) 在 AutoMigrate 后:
|
||||
|
||||
- 空 `status` 的帖/评 → `published`
|
||||
- 空 `post_type` → `normal`
|
||||
- Exp=0 用户按存量内容粗算经验:`posts*10 + comments*2 + like_sum`
|
||||
|
||||
新站若从空库开始可忽略;若迁移旧库需保留等价 backfill。
|
||||
|
||||
---
|
||||
|
||||
## 8. 内容门控在库中的形态
|
||||
|
||||
**无独立表**存放门控块;存在 `posts.content` HTML 中,例如:
|
||||
|
||||
```html
|
||||
<members-only>...</members-only>
|
||||
<reply-only>...</reply-only>
|
||||
<points-only data-cost="10">...</points-only>
|
||||
```
|
||||
|
||||
积分解锁 `block_key` = `sha256(innerHTML)[:16]`(hex),见 [`service/unlock.go`](../../service/unlock.go)。
|
||||
376
docs/rebuild-spec/04-api.md
Normal file
376
docs/rebuild-spec/04-api.md
Normal file
@@ -0,0 +1,376 @@
|
||||
# 04 · HTTP API 合约
|
||||
|
||||
> **读者**:实现后端 / BFF / 前端数据层的 AI
|
||||
> **前置**:[03-data-model.md](03-data-model.md)
|
||||
> **源码**:[`router/router.go`](../../router/router.go)、[`frontend/src/api/client.ts`](../../frontend/src/api/client.ts)、[`frontend/src/api/types.ts`](../../frontend/src/api/types.ts)、[`middleware/auth.go`](../../middleware/auth.go)
|
||||
|
||||
不要求 OpenAPI YAML;以下表格 + JSON 形状即为合约。新站可加 `/v1` 前缀,但**字段名建议保持**以便对照迁移。
|
||||
|
||||
---
|
||||
|
||||
## 1. 通用约定
|
||||
|
||||
| 项 | 约定 |
|
||||
|----|------|
|
||||
| Base | 同源;前端 `credentials: 'same-origin'` |
|
||||
| 成功 | HTTP 2xx + JSON body |
|
||||
| 失败 | 非 2xx + `{ "error": "人类可读中文或英文消息" }` |
|
||||
| 鉴权 | Cookie `jiang13_token`(HttpOnly);部分也接受 Authorization Bearer(以实现为准) |
|
||||
| 内容类型 | JSON 默认;部分写接口用 `multipart/form-data`(FormData) |
|
||||
| OptionalAuth | 有 cookie 则解析用户,无则游客继续 |
|
||||
| RequireAuth | 必须登录且未禁言 |
|
||||
| RequireAdmin | 必须 `role=admin` |
|
||||
|
||||
### 分页形态差异
|
||||
|
||||
| 场景 | 典型字段 |
|
||||
|------|----------|
|
||||
| 前台帖列表 | `posts`, `total`, `page`, `size`, `has_more` |
|
||||
| 后台多数列表 | `total`, `page`, `total_pages` + 实体数组 |
|
||||
| 私信会话消息 | `before` 游标式 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 基础设施 / SEO / 静态
|
||||
|
||||
| 方法 | 路径 | 鉴权 | 说明 |
|
||||
|------|------|------|------|
|
||||
| GET | `/health` | 无 | `{ "status": "ok" }`(DB ping 失败则非 ok,以实现为准) |
|
||||
| GET | `/robots.txt` | 无 | 文本 |
|
||||
| GET | `/sitemap.xml` | 无 | XML |
|
||||
| GET | `/media/thumb/*filepath` | 无 | 缩略图 / WebP 等 |
|
||||
| GET | `/uploads/*` | 无 | 静态上传文件 |
|
||||
|
||||
---
|
||||
|
||||
## 3. OIDC Provider
|
||||
|
||||
| 方法 | 路径 | 鉴权 | 说明 |
|
||||
|------|------|------|------|
|
||||
| GET | `/.well-known/openid-configuration` | 无 | Discovery |
|
||||
| GET | `/oauth/jwks` | 无 | JWKS |
|
||||
| GET | `/oauth/authorize` | OptionalAuth | 授权码流程 |
|
||||
| POST | `/oauth/token` | 无(客户端凭证) | 换 token |
|
||||
| GET/POST | `/oauth/userinfo` | Bearer | 用户信息 |
|
||||
| GET/POST | `/oauth/logout` | 视实现 | 登出 |
|
||||
|
||||
细节以 [`service/oidc.go`](../../service/oidc.go) / [`handler/oidc.go`](../../handler/oidc.go) 为准。
|
||||
|
||||
---
|
||||
|
||||
## 4. 公开 API(`/api` + OptionalAuth)
|
||||
|
||||
### 4.1 会话与站点
|
||||
|
||||
| 方法 | 路径 | 响应要点 |
|
||||
|------|------|----------|
|
||||
| GET | `/api/me` | `{ user: UserSelf \| null }` |
|
||||
| GET | `/api/stats` | `{ users, posts, boards, comments }` |
|
||||
| GET | `/api/forum-limits` | `ForumLimitsPublic`(无限流内部字段) |
|
||||
| GET | `/api/site-branding` | `SiteBranding`(可含 `site_url`) |
|
||||
| GET | `/api/captcha` | `{ id, image }` image 为 data URL 或 base64 |
|
||||
| GET | `/api/register/config` | 见下 |
|
||||
|
||||
**RegisterConfig**
|
||||
|
||||
```json
|
||||
{
|
||||
"is_first_user": true,
|
||||
"mail_ready": false,
|
||||
"require_email_code": false,
|
||||
"register_open": true,
|
||||
"email_code_len": 6
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 认证(限流)
|
||||
|
||||
| 方法 | 路径 | Body | 响应 |
|
||||
|------|------|------|------|
|
||||
| POST | `/api/register` | Form: username, password, nickname, email, email_code? | 成功后通常种 cookie |
|
||||
| POST | `/api/login` | Form: username, password | 种 cookie |
|
||||
| POST | `/api/register/email-code` | JSON `{ email }` | `{ message }` |
|
||||
| POST | `/api/password-reset/email-code` | JSON `{ email }` | `{ message }` |
|
||||
| POST | `/api/password-reset` | JSON `{ email, email_code, new_password }` | `{ message }` |
|
||||
|
||||
### 4.3 内容只读
|
||||
|
||||
| 方法 | 路径 | Query / 说明 |
|
||||
|------|------|----------------|
|
||||
| GET | `/api/boards` | `{ boards: Board[] }` |
|
||||
| GET | `/api/posts` | 见下表 |
|
||||
| GET | `/api/posts/hot` | 热门列表 |
|
||||
| GET | `/api/posts/:id` | `skip_view=1` 可选;返回 `PostDetailResponse` |
|
||||
| GET | `/api/posts/:id/comments` | `my_ids` 可选(逗号分隔,便于标自己的楼) |
|
||||
| GET | `/api/tags` | `limit` 默认 40 → `{ tags: [{name,count}] }` |
|
||||
| GET | `/api/comments/recent` | `{ comments: RecentComment[] }` |
|
||||
| GET | `/api/users/search` | `q`, `limit` |
|
||||
| GET | `/api/users/recent` | `{ users: RecentUser[] }` |
|
||||
| GET | `/api/users/:id` | `{ user: UserPublic, stats }` |
|
||||
| GET | `/api/pages` | 已发布摘要列表 |
|
||||
| GET | `/api/pages/:slug` | 单页详情 |
|
||||
| GET | `/api/projects` | `page`, `limit`, `q` |
|
||||
|
||||
**GET `/api/posts` Query**
|
||||
|
||||
| 参数 | 说明 |
|
||||
|------|------|
|
||||
| page | 默认 1 |
|
||||
| size | 默认 page_size_default,上限 100 |
|
||||
| board_id | 0 或不传=全部 |
|
||||
| user_id | 某用户的帖 |
|
||||
| keyword | 搜索词 |
|
||||
| tag | 标签 |
|
||||
| author | 用户名优先,否则昵称精确匹配 |
|
||||
| title_only | `1`/`true` 仅搜标题 |
|
||||
| sort | `latest` \| `reply` \| `hot` |
|
||||
|
||||
**响应示例**
|
||||
|
||||
```json
|
||||
{
|
||||
"posts": [ /* PostItem */ ],
|
||||
"total": 100,
|
||||
"page": 1,
|
||||
"size": 30,
|
||||
"has_more": true
|
||||
}
|
||||
```
|
||||
|
||||
**PostDetailResponse 要点**
|
||||
|
||||
```json
|
||||
{
|
||||
"post": { /* PostItem + content */ },
|
||||
"comment_count": 0,
|
||||
"liked": false,
|
||||
"favorited": false,
|
||||
"has_replied": false,
|
||||
"can_edit": true,
|
||||
"edit_block_reason": "",
|
||||
"is_edited": false,
|
||||
"post_edit_window_hours": 24,
|
||||
"poll": { /* PollView 可选 */ },
|
||||
"lottery": { /* PostLotteryView 可选 */ },
|
||||
"bounty_can_refund": false,
|
||||
"bounty_refund_block_reason": "",
|
||||
"bounty_eligible_reply_count": 0
|
||||
}
|
||||
```
|
||||
|
||||
### 4.4 游客可写评论
|
||||
|
||||
| 方法 | 路径 | 限流 | Body |
|
||||
|------|------|------|------|
|
||||
| POST | `/api/posts/:id/comments` | comment | Form: content, reply_to?, is_private?, 以及游客字段(以实现为准) |
|
||||
|
||||
登录用户发评也走此路径(RequireAuth 组外公开组已注册该路由)。
|
||||
|
||||
---
|
||||
|
||||
## 5. 需登录 API(`/api` + RequireAuth)
|
||||
|
||||
### 5.1 会话与资料
|
||||
|
||||
| 方法 | 路径 | Body | 响应 |
|
||||
|------|------|------|------|
|
||||
| POST | `/api/logout` | | 清 cookie |
|
||||
| GET | `/api/favorites` | | `{ favorites, total }` |
|
||||
| GET | `/api/profile/stats` | | `{ stats: UserActivityStats }` |
|
||||
| POST | `/api/profile/nickname` | Form nickname | |
|
||||
| POST | `/api/profile/signature` | Form signature | `{ message, user }` |
|
||||
| POST | `/api/profile/password` | Form old_password, new_password | |
|
||||
| POST | `/api/profile/avatar` | Form avatar=file | `{ avatar }` |
|
||||
| POST | `/api/uploads/image` | Form image=file | `{ url }` |
|
||||
|
||||
### 5.2 帖子写操作
|
||||
|
||||
| 方法 | 路径 | Body | 响应 |
|
||||
|------|------|------|------|
|
||||
| POST | `/api/posts` | Form: board_id, title, content, tags?, post_type?, poll_options?, bounty_points?, lottery_winner_count? | `{ message, post_id, status }` |
|
||||
| PUT | `/api/posts/:id` | Form: title, content, tags?, board_id?, post_type? | `{ message }` |
|
||||
| DELETE | `/api/posts/:id` | | 软删 |
|
||||
| GET | `/api/posts/:id/revisions` | | `{ revisions }` |
|
||||
| GET | `/api/posts/:id/revisions/:revId` | | `{ revision }` |
|
||||
| POST | `/api/posts/:id/like` | | `{ liked, like_count }` |
|
||||
| POST | `/api/posts/:id/favorite` | | `{ favorited }` |
|
||||
| POST | `/api/posts/:id/resolve` | Form resolved=`1`\|`0` | `{ question_resolved }` |
|
||||
| POST | `/api/posts/:id/poll/vote` | JSON `{ option_ids: number[] }` | `{ poll }` |
|
||||
| POST | `/api/posts/:id/poll/close` | | `{ poll }` |
|
||||
| POST | `/api/posts/:id/bounty/award` | Form comment_id | |
|
||||
| POST | `/api/posts/:id/bounty/refund` | | |
|
||||
| POST | `/api/posts/:id/lottery/draw` | | `{ lottery }` |
|
||||
| POST | `/api/posts/:id/report` | JSON `{ reason, detail? }` | `{ report }` |
|
||||
| POST | `/api/posts/:id/unlock` | JSON `{ block_key }` | 见下 |
|
||||
|
||||
**poll_options JSON 示例**(Form 字段字符串)
|
||||
|
||||
```json
|
||||
{
|
||||
"multi": false,
|
||||
"max_choices": 1,
|
||||
"ends_at": "2026-09-01T12:00:00Z",
|
||||
"options": [{ "text": "选项A" }, { "text": "选项B" }]
|
||||
}
|
||||
```
|
||||
|
||||
**unlock 响应**
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "...",
|
||||
"unlock": {
|
||||
"block_key": "abcdef0123456789",
|
||||
"cost": 10,
|
||||
"points_balance": 90,
|
||||
"inner_html": "<p>...</p>"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5.3 评论写操作
|
||||
|
||||
| 方法 | 路径 | Body |
|
||||
|------|------|------|
|
||||
| POST | `/api/comments/:id/like` | → `{ liked, like_count }` |
|
||||
| POST | `/api/comments/:id/report` | JSON `{ reason, detail? }` |
|
||||
| PUT | `/api/comments/:id` | Form content |
|
||||
| DELETE | `/api/comments/:id` | |
|
||||
|
||||
### 5.4 私信
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| GET | `/api/messages/unread-count` | `{ count, dm_count?, notify_count? }` |
|
||||
| GET | `/api/messages/notifications` | page, size, kind |
|
||||
| POST | `/api/messages/notifications/read` | |
|
||||
| GET | `/api/messages/conversations` | page, size |
|
||||
| GET | `/api/messages/conversations/:peerId` | size, before;peerId=0 为系统 |
|
||||
| POST | `/api/messages/conversations/:peerId/read` | |
|
||||
| POST | `/api/messages` | JSON `{ to_user_id, subject?, content }` |
|
||||
| POST | `/api/messages/read-all` | |
|
||||
|
||||
### 5.5 经济
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| GET | `/api/me/points` | page;含 ledger、check_in、lottery |
|
||||
| GET/POST | `/api/me/check-in` | 状态 / 执行签到 |
|
||||
| GET/POST | `/api/me/lottery` | 状态 / 抽奖 |
|
||||
|
||||
### 5.6 友链申请
|
||||
|
||||
| 方法 | 路径 | Body |
|
||||
|------|------|------|
|
||||
| POST | `/api/friend-links/apply` | JSON name, url, logo, link_on_homepage, reciprocal_page_url? |
|
||||
| POST | `/api/friend-links/logo` | Form logo=file → `{ url }` |
|
||||
| GET | `/api/friend-links/my-applies` | |
|
||||
| PUT | `/api/friend-links/applies/:id` | 同申请字段 |
|
||||
| DELETE | `/api/friend-links/applies/:id` | 取消 |
|
||||
|
||||
---
|
||||
|
||||
## 6. 管理 API(`/api/admin` + Auth + Admin)
|
||||
|
||||
### 6.1 仪表盘与设置
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| GET | `/dashboard` | AdminDashboard |
|
||||
| GET | `/settings` | AdminSettings 聚合 |
|
||||
| PUT | `/settings/forum` | ForumLimits |
|
||||
| PUT | `/settings/mail` | MailConfig |
|
||||
| POST | `/settings/mail/test` | `{ to }` |
|
||||
| PUT | `/settings/oidc` | OIDCConfig |
|
||||
| PUT | `/settings/gitea` | GiteaSyncConfig |
|
||||
| POST | `/settings/gitea/sync` | 手动同步 |
|
||||
| PUT | `/settings/storage` | StorageConfig |
|
||||
| PUT | `/settings/branding` | SiteBranding |
|
||||
| POST | `/settings/branding/upload` | Form kind=`logo`\|`favicon`\|`og_image`, file |
|
||||
| POST | `/settings/branding/clear` | JSON `{ kind }` |
|
||||
| GET/PUT | `/settings/filter-words` | GET 读;PUT `{ content }` |
|
||||
|
||||
(上表路径均相对于 `/api/admin`。)
|
||||
|
||||
### 6.2 OAuth 客户端
|
||||
|
||||
| 方法 | 路径 |
|
||||
|------|------|
|
||||
| GET/POST | `/oauth/clients` |
|
||||
| PUT/DELETE | `/oauth/clients/:id` |
|
||||
|
||||
创建/更新 body:`name`, `redirect_uris`, `client_id?`, `enabled?`, `client_secret?`, `rotate_secret?`。
|
||||
|
||||
### 6.3 板块 / 单页 / 友链
|
||||
|
||||
| 方法 | 路径 |
|
||||
|------|------|
|
||||
| POST/PUT/DELETE | `/boards`, `/boards/:id` |
|
||||
| GET/POST | `/pages` |
|
||||
| GET/PUT/DELETE | `/pages/:id` |
|
||||
| PUT | `/pages/:id/published` → `{ published }` |
|
||||
| GET | `/friend-link-applies` |
|
||||
| PUT | `/friend-link-settings` |
|
||||
| POST | `/friend-link-applies/:id/approve` \| `reject` \| `recheck` |
|
||||
|
||||
### 6.4 帖子审核与运营
|
||||
|
||||
| 方法 | 路径 | Body |
|
||||
|------|------|------|
|
||||
| GET | `/posts` | page, keyword, status |
|
||||
| GET | `/posts/trash` | |
|
||||
| POST | `/posts/:id/pin` | `{ pinned }` |
|
||||
| POST | `/posts/:id/board-pin` | `{ board_pinned }` |
|
||||
| POST | `/posts/:id/feature` | `{ featured }` |
|
||||
| POST | `/posts/:id/lock` | `{ locked }` → edit_locked |
|
||||
| POST | `/posts/:id/comments-lock` | `{ locked }` |
|
||||
| POST | `/posts/:id/approve` | |
|
||||
| POST | `/posts/:id/reject` | `{ reason }` |
|
||||
| POST | `/posts/:id/restore` | |
|
||||
| DELETE | `/posts/:id/purge` | 硬删 |
|
||||
| DELETE | `/posts/:id` | 软删 |
|
||||
|
||||
### 6.5 评论 / 举报 / 用户 / 徽章 / 媒体 / 备份
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| GET | `/comments`, `/comments/trash` | |
|
||||
| GET | `/comments/:id/revisions` | |
|
||||
| POST | `/comments/:id/approve` \| `reject` \| `restore` | reject 可带 reason |
|
||||
| DELETE | `/comments/:id`, `/comments/:id/purge` | |
|
||||
| GET | `/reports` | page, status |
|
||||
| POST | `/reports/:id/handle` | `{ action, handle_note?, reject_reason? }`;action=`dismiss`\|`resolve`\|`reject_post`\|`reject_comment` |
|
||||
| GET | `/users` | page, keyword, filter |
|
||||
| POST | `/users/:id/ban` | `{ banned }` |
|
||||
| POST | `/users/:id/verify` | `{ verified }` |
|
||||
| POST | `/users/:id/level` | `{ level }` |
|
||||
| POST | `/users/:id/points` | `{ delta, note? }` |
|
||||
| POST | `/users/:id/badges` | `{ badge_id, revoke? }` |
|
||||
| GET/POST | `/badges` | 列表 / upsert |
|
||||
| GET | `/media` | category, page, size, q |
|
||||
| POST | `/media/delete` | `{ urls: string[] }` |
|
||||
| POST | `/backup` | `{ filename, download }` |
|
||||
| GET | `/backup/download/:name` | 文件下载 |
|
||||
|
||||
---
|
||||
|
||||
## 7. 核心类型速查(与前端对齐)
|
||||
|
||||
详见 [`frontend/src/api/types.ts`](../../frontend/src/api/types.ts)。实现时至少对齐:
|
||||
|
||||
- `User` / `UserPublic` / `UserActivityStats`
|
||||
- `Board` / `PostItem` / `PostDetailResponse` / `Comment`
|
||||
- `ForumLimits` / `ForumLimitsPublic` / `SiteBranding`
|
||||
- `PollView` / `PostLotteryView`
|
||||
- `PrivateMessage` / `MessageConversation`
|
||||
- `PostReport` / `FriendLinkApply` / `BadgeDef` / `PointLedger`
|
||||
- `CheckInStatus` / `LotteryStatus`
|
||||
- `AdminDashboard` / `AdminSettings` / `StorageConfig` / `MailConfig` / `OIDCConfig`
|
||||
|
||||
---
|
||||
|
||||
## 8. 鉴权错误语义(现网)
|
||||
|
||||
中间件对未登录 / 过期 / 禁言返回 JSON error(并可能清 cookie)。前端统一 `throw new Error(data.error)`。新站应保持可区分的错误文案或错误码,避免前端无法提示。
|
||||
|
||||
源:[`middleware/auth.go`](../../middleware/auth.go)。
|
||||
228
docs/rebuild-spec/05-business-rules.md
Normal file
228
docs/rebuild-spec/05-business-rules.md
Normal file
@@ -0,0 +1,228 @@
|
||||
# 05 · 业务规则与状态机
|
||||
|
||||
> **读者**:实现领域逻辑的 AI(最易「看起来像但算错」)
|
||||
> **前置**:[03-data-model.md](03-data-model.md)、[04-api.md](04-api.md)
|
||||
> **源码**:[`service/`](../../service/)、[`model/models.go`](../../model/models.go)
|
||||
|
||||
---
|
||||
|
||||
## 1. 注册与引导
|
||||
|
||||
源:[`handler/handlers.go`](../../handler/handlers.go) `APIRegisterConfig`、[`service/auth.go`](../../service/auth.go)
|
||||
|
||||
| 规则 | 细节 |
|
||||
|------|------|
|
||||
| 首用户 = 管理员 | `UserCount() == 0` 时注册的用户 `role=admin` |
|
||||
| 开放注册 | `register_open = (userCount == 0) \|\| mailReady` |
|
||||
| 邮箱验证码 | `require_email_code = mailReady`;邮件未就绪时首用户仍可无码注册 |
|
||||
| 后续用户 | 邮件未配置则注册关闭,直到管理员配好 SMTP |
|
||||
|
||||
密码:bcrypt;最小长度来自 `password_min_len`(默认 6)。
|
||||
|
||||
---
|
||||
|
||||
## 2. 内容审核
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> pending: 普通用户发帖或评论
|
||||
[*] --> published: admin或verified免审
|
||||
pending --> published: 管理员通过
|
||||
pending --> rejected: 管理员拒绝
|
||||
published --> pending: 非免审用户编辑后可再进审
|
||||
```
|
||||
|
||||
| 规则 | 细节 |
|
||||
|------|------|
|
||||
| 免审 | `role=admin` 或 `verified=true`(`SkipsModeration`) |
|
||||
| 可见性 | `pending`/`rejected`:**仅作者与管理员**可见(对外表现为 404) |
|
||||
| 列表 | 公开 Feed 只出 `published` |
|
||||
| 拒绝 | 可写原因;通知作者(站内信 kind=`reject`,可选邮件) |
|
||||
| 待审提醒 | 通知管理员(kind=`moderation`) |
|
||||
| 游客评论 | 通常直接或按实现进入审核;勿假设与登录用户完全相同 |
|
||||
|
||||
源:[`service/post.go`](../../service/post.go) `CanViewPost`、[`service/comment.go`](../../service/comment.go)。
|
||||
|
||||
---
|
||||
|
||||
## 3. 编辑时限与锁
|
||||
|
||||
| 对象 | 规则 |
|
||||
|------|------|
|
||||
| 帖子 | 普通用户在 `post_edit_window_hours`(默认 24)内可编;超时不可(管理员除外) |
|
||||
| 帖子 | `edit_locked=true` 时非管理员不可编 |
|
||||
| 评论 | `comment_edit_window_minutes`(默认 3) |
|
||||
| 评论 | 帖子 `comments_locked` 时禁止新评论 |
|
||||
|
||||
详情接口返回 `can_edit`、`edit_block_reason`、`post_edit_window_hours`。
|
||||
|
||||
修订:每次成功修改前写入 `post_revisions` / `comment_revisions`(旧内容快照)。
|
||||
|
||||
---
|
||||
|
||||
## 4. 经验 Exp(不可消费)
|
||||
|
||||
| 事件 | Delta |
|
||||
|------|------|
|
||||
| 发帖成功(公开路径) | +10 |
|
||||
| 评论成功 | +2 |
|
||||
| 帖子被点赞 | +1(作者) |
|
||||
|
||||
源:[`service/post.go`](../../service/post.go)、[`service/comment.go`](../../service/comment.go)、[`service/badge.go`](../../service/badge.go) `AddExp`。
|
||||
|
||||
等级门槛见 [03-data-model.md](03-data-model.md) §4。管理员设 level 时应同步 Exp 到门槛值。
|
||||
|
||||
---
|
||||
|
||||
## 5. 内容门控(红action)
|
||||
|
||||
源:[`service/content.go`](../../service/content.go)、[`handler/api.go`](../../handler/api.go) `APIPostDetail`、[`service/unlock.go`](../../service/unlock.go)
|
||||
|
||||
### 5.1 出口顺序(详情)
|
||||
|
||||
1. `SanitizePostHTML`(消毒)
|
||||
2. 若 **游客**:`RedactMembersOnlyHTML` + `RedactReplyOnlyHTML`
|
||||
3. 若 **已登录** 且非管理员、非作者、且未回复:仅 `RedactReplyOnlyHTML`
|
||||
4. 作者与管理员:members/reply 块不遮
|
||||
5. 积分块:按已解锁 key 集合 `RedactPointsOnlyHTML`;作者/管理员策略以实现为准(作者可免费解锁记录)
|
||||
|
||||
搜索 / SEO:`RedactGatedPostHTML` = members + reply + points 全遮。
|
||||
|
||||
### 5.2 积分解锁
|
||||
|
||||
| 项 | 值 |
|
||||
|----|-----|
|
||||
| block_key | `hex(sha256(innerHTML))[:16]` |
|
||||
| cost | `data-cost`,最小 1 |
|
||||
| 读者 | 扣 `cost`(reason=`unlock_spend`) |
|
||||
| 作者分成 | `cost * 70 / 100`(`CreatorSharePercent`),reason=`creator_income`;并累加 `creator_income_total` |
|
||||
| 平台留存 | 剩余 30%(无单独流水,表现为读者扣全额、作者只加 70%) |
|
||||
| 作者自己 | cost=0 记解锁,无分成 |
|
||||
| 已解锁 | 返回错误「已解锁」 |
|
||||
| 防刷 | 双方账号注册未满 **7 天** 且 **LastLoginIP 相同** → 拒绝整单 |
|
||||
|
||||
---
|
||||
|
||||
## 6. 特殊帖类型
|
||||
|
||||
### 6.1 问答 question
|
||||
|
||||
- `question_resolved` 布尔;作者(或管理员)可切换
|
||||
- 列表/详情用图标展示已解决状态
|
||||
|
||||
### 6.2 投票 poll
|
||||
|
||||
| 规则 | 细节 |
|
||||
|------|------|
|
||||
| 选项数 | 2–10;单选项 ≤64 字 |
|
||||
| 多选 | `multi`;`max_choices` 钳制在 1..选项数 |
|
||||
| 截止 | `ends_at` 可选;过期或 `closed` 不可再投 |
|
||||
| 投票 | 每用户每帖;已投不可改(`ErrPollAlreadyVoted`) |
|
||||
| 结束 | 作者或管理员 `poll/close` |
|
||||
|
||||
### 6.3 悬赏 bounty
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> open: 发帖托管积分
|
||||
open --> awarded: 采纳他人已发布评论
|
||||
open --> refunded: 退款
|
||||
```
|
||||
|
||||
| 规则 | 细节 |
|
||||
|------|------|
|
||||
| 发帖 | 积分 ≥1;立即 `bounty_escrow` 扣作者积分 |
|
||||
| 采纳 | 不能采纳自己的回复;评论须 published;全额给评论作者 `bounty_award` |
|
||||
| 退款 | 状态 open;作者在**无他人已发布回复**时可退;**管理员始终可强制退** |
|
||||
| 退款后 | status=`refunded`,`bounty_points=0`,积分退回作者 |
|
||||
|
||||
### 6.4 抽奖帖 lottery
|
||||
|
||||
| 规则 | 细节 |
|
||||
|------|------|
|
||||
| 中奖人数 | 1–20 |
|
||||
| 参与者 | 已发布评论且 **非楼主**;按用户去重(保留最早评论) |
|
||||
| 开奖 | 作者/管理员;人数不足报错;随机抽取;写 `post_lottery_winners`;status=`drawn` |
|
||||
|
||||
---
|
||||
|
||||
## 7. 签到与每日抽奖
|
||||
|
||||
源:[`service/points.go`](../../service/points.go)
|
||||
|
||||
### 签到
|
||||
|
||||
- 自然日 `YYYY-MM-DD`(服务器本地时区)每用户一次
|
||||
- 连续:若昨日报到则 streak+1,否则 1
|
||||
- 奖励:`5 + (streak-1)`,封顶 **15**,保底 5
|
||||
- 写 `check_ins` + `point_ledgers` reason=`check_in`
|
||||
|
||||
### 每日抽奖
|
||||
|
||||
- 每天一次;`cost=0`
|
||||
- 奖池权重:0×40, 2×30, 5×18, 10×10, 20×2
|
||||
- 中奖积分入账 reason=`lottery`
|
||||
|
||||
---
|
||||
|
||||
## 8. 评论特殊规则
|
||||
|
||||
| 规则 | 细节 |
|
||||
|------|------|
|
||||
| 楼层 | 按帖递增 |
|
||||
| 私密评论 | 仅作者、帖作者、管理员、以及相关可见链可见(见 `canViewPrivate`) |
|
||||
| 嵌套 | `thread_parent_id` 在父不可见时回挂祖先 |
|
||||
| @提及 | 解析后发 kind=`mention` |
|
||||
| 回复提醒 | kind=`reply`;可选 SMTP |
|
||||
| HasUserReplied | 已发布或审核中的评论算「已回复」(不含被拒),用于 reply-only |
|
||||
|
||||
---
|
||||
|
||||
## 9. 举报处理
|
||||
|
||||
管理员 `handle` action:
|
||||
|
||||
| action | 效果 |
|
||||
|--------|------|
|
||||
| dismiss | 驳回举报 |
|
||||
| resolve | 标记已处理(不必然删内容) |
|
||||
| reject_post | 拒绝/下架帖 |
|
||||
| reject_comment | 拒绝评论 |
|
||||
|
||||
结果通知举报人(kind=`report_result`)。
|
||||
|
||||
---
|
||||
|
||||
## 10. 友链
|
||||
|
||||
| 规则 | 细节 |
|
||||
|------|------|
|
||||
| 申请 | 登录用户;可上传 logo |
|
||||
| 回链检测 | 设置开启时抓取 reciprocal 页检查是否含本站链接 |
|
||||
| 通过 | 可写入品牌 `site_friend_links`(视实现:首页展示链接) |
|
||||
| 展示开关 | nav / footer / aside 独立 |
|
||||
|
||||
---
|
||||
|
||||
## 11. 敏感词与限流
|
||||
|
||||
- 敏感词文件:`data/filter_words.txt`;发帖/评/私信等路径过滤
|
||||
- 限流动作键:post / comment / register / login / report / message / friend_link 等;窗口秒与次数来自 settings
|
||||
|
||||
---
|
||||
|
||||
## 12. 徽章自动授予
|
||||
|
||||
定期或触发时检查 `BadgeDef`(kind=auto):tenure_days / likes_received / creator_income 达阈值则写入 `user_badges`。限定徽章仅管理员发放。
|
||||
|
||||
---
|
||||
|
||||
## 13. 置顶排序语义
|
||||
|
||||
| 标记 | 首页全部 Feed | 板块 Feed |
|
||||
|------|---------------|-----------|
|
||||
| `pinned` | 抬升 | 抬升 |
|
||||
| `board_pinned` | **不**抬升 | 抬升 |
|
||||
| `featured` | 标记展示,不一定改变排序 | 同左 |
|
||||
|
||||
具体 SQL/排序实现见 [`service/post.go`](../../service/post.go) ListItems。
|
||||
215
docs/rebuild-spec/06-pages-ux.md
Normal file
215
docs/rebuild-spec/06-pages-ux.md
Normal file
@@ -0,0 +1,215 @@
|
||||
# 06 · 页面、交互与信息架构
|
||||
|
||||
> **读者**:实现前台 / 后台 UI 的 AI
|
||||
> **前置**:[02-features.md](02-features.md)
|
||||
> **源码**:[`frontend/src/App.tsx`](../../frontend/src/App.tsx)、[`frontend/src/pages/`](../../frontend/src/pages/)、[`frontend/src/components/`](../../frontend/src/components/)、[`frontend/src/layouts/`](../../frontend/src/layouts/)
|
||||
|
||||
视觉可重设;**信息架构与关键操作流应对齐**。新站建议 SSR 直出同等信息,而不是先空壳再 fetch。
|
||||
|
||||
---
|
||||
|
||||
## 1. 路由表
|
||||
|
||||
### 1.1 认证(无 MainLayout 壳或独立简洁壳)
|
||||
|
||||
| 路径 | 页面 | 说明 |
|
||||
|------|------|------|
|
||||
| `/login` | LoginPage | |
|
||||
| `/register` | RegisterPage | 读 register/config;可能关闭 |
|
||||
| `/forgot-password` | ForgotPasswordPage | 依赖邮件 |
|
||||
|
||||
### 1.2 前台(MainLayout)
|
||||
|
||||
| 路径 | 页面 |
|
||||
|------|------|
|
||||
| `/` | HomePage(全部 Feed) |
|
||||
| `/board/:id` | HomePage(板块 Feed;id 可带伪静态后缀) |
|
||||
| `/post/:id` | PostDetailPage |
|
||||
| `/compose` | ComposePage 发帖 |
|
||||
| `/post/:id/edit` | ComposePage 编辑 |
|
||||
| `/profile` | ProfilePage(需登录) |
|
||||
| `/user/:id` | UserProfilePage |
|
||||
| `/favorites` | FavoritesPage |
|
||||
| `/projects` | ProjectsPage(Gitea 码桶) |
|
||||
| `/links` | LinksPage |
|
||||
| `/messages` | MessagesPage |
|
||||
| `/page/:slug` | SitePageView |
|
||||
| `*` | NotFoundPage |
|
||||
|
||||
重定向:`/boards` → `/admin/boards`。
|
||||
|
||||
### 1.3 后台(AdminLayout,需管理员)
|
||||
|
||||
| 路径 | 页面 |
|
||||
|------|------|
|
||||
| `/admin` → `/admin/dashboard` | 仪表盘 |
|
||||
| `/admin/boards` | 板块管理 |
|
||||
| `/admin/pages` | 单页列表 |
|
||||
| `/admin/pages/new`、`/admin/pages/:id/edit` | 单页编辑 |
|
||||
| `/admin/links` | 友链与申请 |
|
||||
| `/admin/posts` | 帖子审核/运营 |
|
||||
| `/admin/comments` | 评论 |
|
||||
| `/admin/reports` | 举报 |
|
||||
| `/admin/users` | 用户 |
|
||||
| `/admin/badges` | 徽章定义 |
|
||||
| `/admin/media` | 媒体 |
|
||||
| `/admin/settings` | 系统设置(多 Tab) |
|
||||
|
||||
---
|
||||
|
||||
## 2. 三栏布局(桌面)
|
||||
|
||||
```text
|
||||
+------------------+---------------------------+------------------+
|
||||
| Sidebar | Feed / 主内容 | RightPanel |
|
||||
| - 全部/收藏/码桶 | - FeedHeader / SortBar | - 签到条(登录) |
|
||||
| - 板块列表 | - VirtualPostList | - 热门帖 |
|
||||
| - 站点页/友链 | - 或 PostDetail 等 | - aside_widgets |
|
||||
| - 管理入口 | | 标签云/评论/ |
|
||||
| | | 用户/友链 |
|
||||
+------------------+---------------------------+------------------+
|
||||
| Footer: ICP / 友链入口 / 站点页链接 |
|
||||
+------------------------------------------------------------------+
|
||||
```
|
||||
|
||||
### 2.1 左栏 Sidebar
|
||||
|
||||
- 全部帖子、我的收藏(登录)、开源码桶
|
||||
- 板块列表(图标 + 色点 + 名称);空站引导「创建第一个板块」
|
||||
- 站点区:友链入口(`nav_show_friend_links`)、`show_in_nav` 的站点页
|
||||
- 管理员:管理后台入口
|
||||
|
||||
### 2.2 中栏
|
||||
|
||||
**Feed**:排序条(最新发帖 / 最新回复 / 热门)+ 搜索面板(关键词、标签、作者、仅标题)+ 虚拟列表项(标题、作者、板块徽章、标签、回复数、最后回复、置顶/精华标记)。列表样式随 `feed_list_style`。
|
||||
|
||||
**帖子详情**:标题区操作(赞、藏、举报、编辑、管理操作)→ 特殊组件(投票卡 / 悬赏条 / 抽奖卡)→ 正文 `PostContent`(门控块 UI)→ 文章目录 → 作者卡片 → 修订入口 → 评论线程 + 评论框。
|
||||
|
||||
### 2.3 右栏 RightPanel
|
||||
|
||||
- 登录用户:`AsideCheckInStrip`(签到 + 抽奖 + 积分入口)
|
||||
- 热门帖
|
||||
- 可配置 widgets:`tag_cloud` / `recent_comments` / `recent_users` / `friend_links`(顺序与开关来自 settings)
|
||||
|
||||
### 2.4 移动端
|
||||
|
||||
- 侧栏抽屉化;顶栏搜索/发帖/登录触手可及
|
||||
- `PullToRefresh` 下拉刷新
|
||||
- 触控友好列表行高
|
||||
|
||||
### 2.5 主题
|
||||
|
||||
- 浅色 / 暗色;`localStorage` 记忆;可跟随系统
|
||||
|
||||
---
|
||||
|
||||
## 3. 发帖页 Compose
|
||||
|
||||
组件:`ComposeHeader`、`ComposeContextBar`(帖类型)、`ComposeSpecialFields`、`ComposeDocument` / `ArticleEditor`。
|
||||
|
||||
### 3.1 帖类型切换
|
||||
|
||||
| 类型 | 附加 UI |
|
||||
|------|---------|
|
||||
| 讨论 | 无 |
|
||||
| 问答 | 无额外字段(解决状态在详情) |
|
||||
| 投票 | 选项列表、多选开关、最多可选、截止时间或无截止 |
|
||||
| 悬赏 | 积分输入(显示余额) |
|
||||
| 抽奖 | 中奖人数 1–20 |
|
||||
|
||||
### 3.2 编辑器能力(应对齐)
|
||||
|
||||
源:[`ArticleEditor.tsx`](../../frontend/src/components/ArticleEditor.tsx) 与 `editor/` 扩展
|
||||
|
||||
- 标题 h2–h6(无 h1,避免与帖标题冲突)
|
||||
- 粗体/斜体/删除线等基础标记
|
||||
- 链接对话框
|
||||
- 代码块(语言、选项对话框)
|
||||
- 表格插入/编辑
|
||||
- 图片上传 + 图片组布局 + 浮动/清除浮动
|
||||
- 表情 / 贴纸选择器(多套:bilibili/douyin/tieba/weibo 等静态资源)
|
||||
- **登录可见** / **回复可见** / **积分可见**(价格 1–9999)节点
|
||||
- 富文本 ↔ Markdown 双模(门控块有 markdown 约定,见 [`utils/markdownContent.ts`](../../frontend/src/utils/markdownContent.ts))
|
||||
- Tab 缩进
|
||||
|
||||
未保存离开:`UnsavedChangesDialog`。
|
||||
|
||||
---
|
||||
|
||||
## 4. 帖子详情关键交互
|
||||
|
||||
| 模块 | 行为 |
|
||||
|------|------|
|
||||
| 门控块 | 锁定态显示长度/价格;解锁按钮调 API 后替换 inner HTML |
|
||||
| 投票卡 | 选选项提交;显示百分比;作者可结束 |
|
||||
| 悬赏条 | 显示积分与状态;采纳按钮在他人评论上;退款按钮按规则禁用并提示 |
|
||||
| 抽奖卡 | 显示参与人数;开奖;中奖名单 |
|
||||
| 评论 | 楼层列表、回复、引用、私密开关、@ 用户搜索、点赞、编辑、举报 |
|
||||
| 修订 | 面板列出历史,可选对比 |
|
||||
| 图片 | Lightbox 查看 |
|
||||
|
||||
---
|
||||
|
||||
## 5. 消息页
|
||||
|
||||
- 左:会话列表(系统会话单独)
|
||||
- 右:消息时间线;发送框
|
||||
- 顶:未读角标(全局导航也可显示)
|
||||
- 通知筛选(kind)
|
||||
|
||||
---
|
||||
|
||||
## 6. 个人中心 / 公开主页
|
||||
|
||||
- 资料编辑、头像裁剪、密码
|
||||
- 积分钱包面板(流水、签到状态)
|
||||
- 徽章与等级徽记展示
|
||||
- 公开页:签名、徽章、统计、最近帖(按现实现)
|
||||
|
||||
---
|
||||
|
||||
## 7. 友链页
|
||||
|
||||
- 展示已通过/品牌友链
|
||||
- 「申请友链」对话框:名称、URL、Logo 上传、是否上首页、回链页 URL
|
||||
- 我的申请状态列表
|
||||
|
||||
---
|
||||
|
||||
## 8. 管理后台操作流(按页)
|
||||
|
||||
| 页 | 关键操作 |
|
||||
|----|----------|
|
||||
| Dashboard | 看计数与待办;点进对应列表 |
|
||||
| Boards | 拖拽或数字排序;图标/色板选择;增删改 |
|
||||
| Pages | 列表发布开关;进编辑器写正文;nav/footer 勾选 |
|
||||
| Links | 品牌友链 CRUD;申请队列通过/拒绝/复检;回链检测开关;nav/footer/aside 开关 |
|
||||
| Posts | 按状态筛;通过/拒绝;置顶/版顶/精华/锁编/锁评;进回收站恢复/清除 |
|
||||
| Comments | 审核;修订查看;回收站 |
|
||||
| Reports | 处理动作四选一 |
|
||||
| Users | 搜索;禁言;认证;设等级;调积分;授徽章 |
|
||||
| Badges | 定义自动/限定徽章 |
|
||||
| Media | 分类浏览;批量删 |
|
||||
| Settings | Tab:论坛限制、侧栏组件、伪静态、邮件、OIDC+客户端、Gitea、存储、品牌、敏感词、备份 |
|
||||
|
||||
---
|
||||
|
||||
## 9. 全局 UX 细节
|
||||
|
||||
- Toast(sonner)反馈成功/失败
|
||||
- 路由级 ErrorBoundary / AppRouteError
|
||||
- 懒加载页面 + retry(`lazyWithRetry`)
|
||||
- 新标签打开帖子 / 正文外链:受 `open_posts_in_new_tab`、`open_content_links_in_new_tab` 控制
|
||||
- 文档标题:`站点名 - 标语`;详情页应换成帖标题(SSR 时首屏即正确)
|
||||
|
||||
---
|
||||
|
||||
## 10. SSR 重构提示(交互层)
|
||||
|
||||
当前 SPA 在客户端挂载后才拉 `/api/posts/:id`。新站应:
|
||||
|
||||
1. 服务端渲染列表项与帖文 HTML(已按门控红action)
|
||||
2. 水合后接上赞/评/解锁等交互
|
||||
3. 管理后台仍可为 CSR,但前台公开页优先 SSR
|
||||
|
||||
勿再维护「爬虫一套 HTML、用户一套空壳」双轨,除非过渡期兼容。
|
||||
150
docs/rebuild-spec/07-config-ops.md
Normal file
150
docs/rebuild-spec/07-config-ops.md
Normal file
@@ -0,0 +1,150 @@
|
||||
# 07 · 配置、运维与 SEO
|
||||
|
||||
> **读者**:部署与运维、以及实现配置层的 AI
|
||||
> **前置**:[README.md](README.md)
|
||||
> **源码**:[`app.ini.example`](../../app.ini.example)、[`config/`](../../config/)、[`README.md`](../../README.md)、[`handler/seo.go`](../../handler/seo.go)、[`handler/seo_bot.go`](../../handler/seo_bot.go)、[`embed_static/`](../../embed_static/)
|
||||
|
||||
运维形态可改;下列描述**现网**行为,便于迁移数据与对齐环境变量语义。
|
||||
|
||||
---
|
||||
|
||||
## 1. 进程配置优先级
|
||||
|
||||
**命令行显式参数 > 环境变量 > `app.ini` > 内置默认**
|
||||
|
||||
| CLI | 环境变量 | INI | 默认 | 说明 |
|
||||
|-----|----------|-----|------|------|
|
||||
| `--port` | `JIANG13_HTTP_PORT` | `[server] HTTP_PORT` | 3000 | 监听端口 |
|
||||
| `--data` | `JIANG13_DATA` | `[paths] DATA` | `data` | 数据目录 |
|
||||
| `--jwt-secret` | `JIANG13_JWT_SECRET` | `[security] JWT_SECRET` | 自动生成 | JWT 密钥 |
|
||||
| `--config` | `JIANG13_CONFIG` | | `{work}/app.ini` | 配置文件路径 |
|
||||
| `--work-path` | `JIANG13_WORK_PATH` | | 可执行文件目录 | 工作目录 |
|
||||
| `--service` | | | | install/uninstall/start/stop/restart/status |
|
||||
|
||||
`app.ini` 示例见 [`app.ini.example`](../../app.ini.example)。业务配置(邮件、OIDC、Gitea、存储、品牌等)在 **DB `forum_settings`**,管理后台热更新,不必写进 ini。
|
||||
|
||||
---
|
||||
|
||||
## 2. 数据目录结构
|
||||
|
||||
```text
|
||||
data/
|
||||
├── jiang13.db # SQLite 主库
|
||||
├── jiang13.log # 运行日志
|
||||
├── filter_words.txt # 敏感词
|
||||
├── .jwt_secret # 自动生成的 JWT 密钥(勿提交仓库)
|
||||
├── uploads/
|
||||
│ ├── avatars/
|
||||
│ ├── posts/
|
||||
│ └── site/ # 品牌资源等
|
||||
└── jiang13_backup_*.db # 后台导出备份
|
||||
```
|
||||
|
||||
开发时后端常与 `dist/data` 共用,避免 dev 与产物数据分裂(见根 README)。
|
||||
|
||||
---
|
||||
|
||||
## 3. 部署方式(现网)
|
||||
|
||||
| 方式 | 说明 |
|
||||
|------|------|
|
||||
| 单二进制 | `build.bat` / `make build` → `dist/jiang13(.exe)` |
|
||||
| Docker | 镜像挂载 `/data`;健康检查 `GET /health` |
|
||||
| Compose | `docker compose up -d --build` |
|
||||
| systemd / Windows Service | `--service install` 后启停 |
|
||||
|
||||
构建约定见 [`.cursor/rules/build-scripts.mdc`](../../.cursor/rules/build-scripts.mdc):Windows 用 `build.bat`,勿直接 `make` / `.\build.ps1`。
|
||||
|
||||
容器常用环境变量与上表 `JIANG13_*` 一致。旧镜像权限问题:数据目录属主 uid 1000。
|
||||
|
||||
---
|
||||
|
||||
## 4. 存储后端
|
||||
|
||||
| type | 行为 |
|
||||
|------|------|
|
||||
| `local` | 文件落在 `data/uploads`;URL 通常 `/uploads/...` |
|
||||
| `s3` | S3 兼容;endpoint、bucket、密钥、public_base_url、prefix、force_path_style |
|
||||
|
||||
`image_delivery`:`webp`(默认,经 `/media/thumb`)或 `original`。上传始终可保留原图策略以实现为准。
|
||||
|
||||
媒体索引表 `media` 供后台列表;启动时可后台 SyncMediaIndex。
|
||||
|
||||
---
|
||||
|
||||
## 5. SEO / 社交分享字段集合
|
||||
|
||||
新站应用真 SSR,但 **meta 字段应对齐**:
|
||||
|
||||
| 字段 | 来源 |
|
||||
|------|------|
|
||||
| `<title>` | 站点 DocumentTitle 或帖标题 |
|
||||
| meta description | 站点简介优先,否则标语;帖文则摘要 |
|
||||
| meta keywords | 站点 keywords |
|
||||
| canonical | 绝对 URL |
|
||||
| og:type / site_name / locale / title / description / url / image | |
|
||||
| twitter:card / title / description / image | |
|
||||
| JSON-LD | 结构化数据(站点或 Article) |
|
||||
| robots | 个别页可 noindex(以实现为准) |
|
||||
|
||||
### 现网额外机制(可废弃)
|
||||
|
||||
| 机制 | 说明 |
|
||||
|------|------|
|
||||
| SPA 壳注入 | [`embed_static`](../../embed_static/) 注入 title / branding JSON,**无帖文 DOM** |
|
||||
| 爬虫 HTML | User-Agent 命中时 [`seo_bot.go`](../../handler/seo_bot.go) 返回简易 HTML |
|
||||
| robots.txt / sitemap.xml | 动态生成 |
|
||||
|
||||
重构验收:用普通浏览器「查看网页源代码」应能看到帖文正文,而不仅是空 div + script。
|
||||
|
||||
---
|
||||
|
||||
## 6. 伪静态 Permalink
|
||||
|
||||
设置:`permalink_enabled`、`permalink_ext`(默认 `html`)。
|
||||
|
||||
规范路径示例:
|
||||
|
||||
- `/post/123.html`
|
||||
- `/user/1.html`
|
||||
- `/board/2.html`
|
||||
- `/page/about.html`
|
||||
|
||||
路由应同时接受无后缀与有后缀形式。解析逻辑见 [`service/permalink.go`](../../service/permalink.go)。
|
||||
|
||||
---
|
||||
|
||||
## 7. 安全相关运维注意
|
||||
|
||||
| 项 | 说明 |
|
||||
|----|------|
|
||||
| JWT 密钥 | 生产必须固定且保密;勿提交 `.jwt_secret` |
|
||||
| Cookie | `jiang13_token` HttpOnly;生产应 Secure + 合适 SameSite |
|
||||
| 上传 | 类型/大小限制(头像 MB、帖图策略) |
|
||||
| 敏感词 | 后台可改;影响发帖评论私信等 |
|
||||
| OAuth 密钥 | 仅存 bcrypt 哈希;创建时明文只回显一次 |
|
||||
| 备份 | 含用户哈希与私信,下载需管理员权限、传输加密 |
|
||||
|
||||
---
|
||||
|
||||
## 8. 健康检查
|
||||
|
||||
`GET /health` → JSON `status`。Docker / 负载均衡探活依赖此接口;实现应在 DB 不可用时返回非 200。
|
||||
|
||||
---
|
||||
|
||||
## 9. 从旧站迁数据建议
|
||||
|
||||
1. 导出 / 复制 `jiang13.db`(或 dump 到新库并映射表)
|
||||
2. 复制 `uploads/` 与 `filter_words.txt`
|
||||
3. 迁移 `forum_settings` 键值(或后台重新配置)
|
||||
4. 会话:旧 JWT 密钥兼容一阶段,或强制全员重登
|
||||
5. OIDC 客户端:`oauth_clients` 表 + 重新下发密钥(若无法迁移哈希)
|
||||
|
||||
表语义以 [03-data-model.md](03-data-model.md) 为准。
|
||||
|
||||
---
|
||||
|
||||
## 10. 文档包索引
|
||||
|
||||
返回 [README.md](README.md) 阅读顺序;功能验收用 [02-features.md](02-features.md);规则用 [05-business-rules.md](05-business-rules.md)。
|
||||
58
docs/rebuild-spec/08-gitea-ssr-architecture.md
Normal file
58
docs/rebuild-spec/08-gitea-ssr-architecture.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# 08 · Gitea 式 SSR 架构(开发约定)
|
||||
|
||||
> **读者**:在本仓库 `rebuild/gitea-ssr` 分支上开发的 AI / 开发者
|
||||
> **前置**:[README.md](README.md)
|
||||
> **对照上游**:[go-gitea/gitea](https://github.com/go-gitea/gitea)
|
||||
|
||||
---
|
||||
|
||||
## 目标栈(已确认)
|
||||
|
||||
| 层 | 选择 |
|
||||
|----|------|
|
||||
| 公开页渲染 | Go `html/template` **真 SSR**(完整 HTML,含帖文/列表 DOM) |
|
||||
| 渐进增强 | `web_src/` 少量 CSS/JS,构建后嵌入 |
|
||||
| 发布 | 单二进制 + `go:embed` |
|
||||
| 业务语义 | 仍以本目录 `01`–`07` 为准 |
|
||||
| 不做 | React/Next 公开页 SPA;用户与爬虫双轨 HTML |
|
||||
|
||||
---
|
||||
|
||||
## 开发分支与对照
|
||||
|
||||
| 分支 | 用途 |
|
||||
|------|------|
|
||||
| `main` | 现网 **React SPA** 对照,勿在此做破坏性 SSR 替换 |
|
||||
| `rebuild/gitea-ssr` | **唯一** Gitea 式重构开发分支 |
|
||||
|
||||
对照运行:
|
||||
|
||||
```bash
|
||||
git checkout main # 旧 SPA
|
||||
# 或
|
||||
git worktree add ../jiang13-spa main
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 目录职责(演进中)
|
||||
|
||||
```text
|
||||
routers/web/ # 返回 HTML 的页面路由
|
||||
templates/ # Go 模板源文件(嵌入)
|
||||
web_src/ # CSS/JS 源码
|
||||
public/assets/ # web_src 构建产物(嵌入,URL 前缀 `/ssr-assets/`)
|
||||
modules/ # 横切(模板渲染等)
|
||||
docs/rebuild-spec/ # 产品规格
|
||||
.cursor/rules/ # AI 开发规则
|
||||
```
|
||||
|
||||
现有 `model/`、`service/`、`handler/`(JSON API)可先复用,公开页出口改为模板。
|
||||
|
||||
---
|
||||
|
||||
## 渲染原则
|
||||
|
||||
1. 用户访问已迁移路径时,「查看源代码」须可见内容 DOM,而非空壳。
|
||||
2. JSON `/api` 留给交互增强与后台;**不得**作为公开页首屏唯一数据来源。
|
||||
3. 模板默认 HTML 转义;可信 HTML(已消毒正文)用明确的安全管道,禁止随意 `| safe`。
|
||||
137
docs/rebuild-spec/README.md
Normal file
137
docs/rebuild-spec/README.md
Normal file
@@ -0,0 +1,137 @@
|
||||
# 姜十三论坛 · 重构规格文档包
|
||||
|
||||
> **读者**:准备用新栈(建议真 SSR)重写站点的 AI / 开发者
|
||||
> **事实来源**:本仓库现有代码;规格描述「产品必须保留什么」,不是「必须继续用 Go + React SPA」
|
||||
> **交叉引用**:[01-product](01-product.md) · [02-features](02-features.md) · [03-data-model](03-data-model.md) · [04-api](04-api.md) · [05-business-rules](05-business-rules.md) · [06-pages-ux](06-pages-ux.md) · [07-config-ops](07-config-ops.md) · [08-gitea-ssr-architecture](08-gitea-ssr-architecture.md)
|
||||
|
||||
> **实现栈(重构分支)**:Gitea 式 Go 模板 SSR;开发分支 `rebuild/gitea-ssr`;`main` 保留 React SPA 对照。详见 [08](08-gitea-ssr-architecture.md)。
|
||||
|
||||
---
|
||||
|
||||
## 阅读顺序(请按序投喂)
|
||||
|
||||
| 顺序 | 文件 | 用途 |
|
||||
|------|------|------|
|
||||
| 1 | 本文 `README.md` | 架构痛点、重构约束、术语 |
|
||||
| 2 | [01-product.md](01-product.md) | 产品定位、角色、模块地图 |
|
||||
| 3 | [02-features.md](02-features.md) | 验收级功能清单(可打勾) |
|
||||
| 4 | [03-data-model.md](03-data-model.md) | 表结构、枚举、设置键、等级徽章 |
|
||||
| 5 | [04-api.md](04-api.md) | HTTP 合约(路径 / 鉴权 / 请求响应) |
|
||||
| 6 | [05-business-rules.md](05-business-rules.md) | 状态机与数值规则 |
|
||||
| 7 | [06-pages-ux.md](06-pages-ux.md) | 路由、布局、编辑器、后台流程 |
|
||||
| 8 | [07-config-ops.md](07-config-ops.md) | 配置、数据目录、部署、SEO 字段 |
|
||||
| 9 | [08-gitea-ssr-architecture.md](08-gitea-ssr-architecture.md) | Gitea 式 SSR 分支与目录约定 |
|
||||
|
||||
单次 context 不够时:先投喂 `README` + `01` + `02`;实现某模块时再追加对应 `03`–`06` 章节。
|
||||
|
||||
---
|
||||
|
||||
## 当前产品是什么
|
||||
|
||||
**姜十三论坛(Jiang13 Forum)** 面向小圈子 / 团队 / 同好社群的轻量论坛。
|
||||
|
||||
当前实现技术栈(**可抛弃,仅作对照**):
|
||||
|
||||
| 层 | 技术 |
|
||||
|----|------|
|
||||
| 后端 | Go · Gin · GORM · SQLite |
|
||||
| 前端 | React 18 SPA · TipTap · Tailwind · TanStack Virtual |
|
||||
| 发布 | Vite 构建 → `go:embed` 打进单二进制 |
|
||||
| 认证 | bcrypt + JWT Cookie(`jiang13_token`) |
|
||||
|
||||
演示站:https://bbs.iioio.com/
|
||||
|
||||
---
|
||||
|
||||
## 为何要重构:架构痛点(必须打破)
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
browser[Browser]
|
||||
spa[ReactSPA]
|
||||
gin[GinAPI]
|
||||
sqlite[SQLite]
|
||||
bot[BotHTML]
|
||||
browser -->|"用户"| spa
|
||||
spa -->|"JSON /api"| gin
|
||||
gin --> sqlite
|
||||
browser -->|"爬虫 UA"| bot
|
||||
bot --> gin
|
||||
```
|
||||
|
||||
| 痛点 | 现状 | 对用户的影响 |
|
||||
|------|------|----------------|
|
||||
| 非真 SSR | 生产入口 [`embed_static`](../../embed_static/) 只注入 title / branding / Open Graph,**不渲染帖文 DOM** | 刷新先出壳再灌数据,体验不如 SSR |
|
||||
| 爬虫双轨 | [`handler/seo_bot.go`](../../handler/seo_bot.go) 对爬虫返回独立 HTML | 用户与爬虫看到的不是同一套渲染路径 |
|
||||
| 无正式 migration | Schema 靠 GORM `AutoMigrate`([`model/db.go`](../../model/db.go)) | 升级靠「加字段」,难做破坏性迁移与审计 |
|
||||
| Cookie JWT | 无 session 表,密钥在 `data/.jwt_secret` | 可保留语义,实现可换成更好的会话方案 |
|
||||
|
||||
**新站目标**:用户首屏即可看到帖文 / 列表的服务端渲染(SSR)HTML;SEO meta 与正文同源。技术选型自定(Next.js / Nuxt / Remix / 其它均可)。
|
||||
|
||||
---
|
||||
|
||||
## 重构时必须保留 vs 可以改
|
||||
|
||||
### 必须保留(产品语义)
|
||||
|
||||
- [02-features.md](02-features.md) 中列出的功能能力
|
||||
- [03-data-model.md](03-data-model.md) 中的实体关系与枚举含义(表名可改,语义对齐)
|
||||
- [05-business-rules.md](05-business-rules.md) 中的数值与状态机(积分、审核、门控、悬赏分成等)
|
||||
- 角色模型:游客 / 用户 / 认证用户(`verified` 免审)/ 管理员;首个注册用户为管理员
|
||||
|
||||
### 建议兼容(降低迁移成本)
|
||||
|
||||
- [04-api.md](04-api.md) 的 JSON 字段命名与路径形状(可做版本前缀,但旧字段名便于对照)
|
||||
- Cookie 名 `jiang13_token` 或提供清晰的会话迁移方案
|
||||
- 数据目录语义:`jiang13.db`、`uploads/`、`filter_words.txt`
|
||||
|
||||
### 可以彻底改
|
||||
|
||||
- 语言与框架(不必再 Go + React SPA)
|
||||
- 单二进制 / `go:embed`(可改为前后端分离部署)
|
||||
- SQLite(可换 PostgreSQL 等;规格不强制)
|
||||
- UI 视觉(布局信息密度见 [06-pages-ux.md](06-pages-ux.md),视觉可重设)
|
||||
- 爬虫专用 HTML 双轨(用真 SSR 取代)
|
||||
|
||||
---
|
||||
|
||||
## 术语表(首次出现)
|
||||
|
||||
| 术语 | 中文 | 说明 |
|
||||
|------|------|------|
|
||||
| SSR | 服务端渲染 | 首屏 HTML 含正文,非纯客户端壳 |
|
||||
| SPA | 单页应用 | 当前前台实现形态 |
|
||||
| OIDC | 开放身份连接 | 本站可作 Provider,供 Gitea 等 SSO |
|
||||
| JWT | JSON Web Token | 当前登录凭证,存 Cookie |
|
||||
| Feed | 信息流 | 首页 / 板块帖列表 |
|
||||
| 门控 | Content gate | 登录可见 / 回复可见 / 积分可见区块 |
|
||||
| 伪静态 | Permalink | 如 `/post/123.html` 的可选后缀 |
|
||||
|
||||
---
|
||||
|
||||
## 源码速查(核对规格时)
|
||||
|
||||
| 主题 | 路径 |
|
||||
|------|------|
|
||||
| 路由总表 | [`router/router.go`](../../router/router.go) |
|
||||
| GORM 模型 | [`model/models.go`](../../model/models.go) |
|
||||
| AutoMigrate | [`model/db.go`](../../model/db.go) |
|
||||
| 论坛设置键 | [`service/settings.go`](../../service/settings.go) |
|
||||
| 前端 API 客户端 | [`frontend/src/api/client.ts`](../../frontend/src/api/client.ts) |
|
||||
| 前端类型 | [`frontend/src/api/types.ts`](../../frontend/src/api/types.ts) |
|
||||
| 页面路由 | [`frontend/src/App.tsx`](../../frontend/src/App.tsx) |
|
||||
| 产品介绍 | [`docs/introduction.md`](../introduction.md)、[`README.md`](../../README.md) |
|
||||
|
||||
---
|
||||
|
||||
## 文档包完成标准
|
||||
|
||||
另一 AI 仅阅读本目录、**不打开业务源码**,应能:
|
||||
|
||||
1. 列出全部用户可见功能与后台能力
|
||||
2. 画出核心表 ER 并理解枚举
|
||||
3. 实现或 mock 与现网兼容的 API 形状
|
||||
4. 复现审核 / 积分 / 门控 / 特殊帖规则
|
||||
5. 搭出等价的页面信息架构与关键交互
|
||||
|
||||
若规格与代码冲突:**以代码为准**,并应回写修正本目录文档。
|
||||
Reference in New Issue
Block a user