Files
jiang13-forum/docs/rebuild-spec/03-data-model.md
freefire fde5f628ec feat: opaque session、安装/发帖 SSR 与最小 Admin 后台
浏览器登录改为 DB sessions(可吊销);敏感词与 OIDC PEM 入 settings;
落地安装向导、注册发帖与 /admin 仪表盘/板块/审核/设置。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-29 05:44:16 +08:00

13 KiB
Raw Blame History

03 · 数据模型

读者:实现数据库与领域层的 AI
前置01-product.md
后续04-api.md05-business-rules.md
源码model/models.gomodel/oauth.gomodel/gitea.gomodel/level.gomodel/db.gomodel/user_view.goservice/settings.go

当前无独立 SQL migration表由 GORM AutoMigrate 创建。新站可用正式 migration字段语义应对齐


1. ER 概览

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(键值)、Session(浏览器 opaque 会话)、OAuthClient / OAuthAuthCodeGiteaRepoSitePage


2. 表与字段

说明:json:"-" 表示默认 API 序列化隐藏;软删列 deleted_at 表示 GORM soft delete。

2.0 sessions

类型 说明
id string(64) PK 密码学随机 opaque idCookie jiang13_session 的值)
user_id uint index 用户
expires_at time index 过期;默认 TTL 7 天,滑动续期
created_at / last_seen_at time
ip / user_agent string 可选审计

登出删单行;禁言 / 改密删该用户全部 session。每次请求以 DB 中 users.role / 禁言为准。

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)。

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

申请字段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|sitename, 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-DDpoints, 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

  • Pollpost_id uniquemulti, max_choices, closed, ends_at
  • Optionpost_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

BadgeDefcode 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

Clientclient_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 举报

Statuspending | resolved | dismissed
Reasonspam | 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 徽章

Kindauto | limited
Metrictenure_days | likes_received | creator_income


4. 等级Exp → Level

源: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 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.goservice/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

[
  {"id":"tag_cloud","enabled":false},
  {"id":"recent_comments","enabled":false},
  {"id":"friend_links","enabled":true}
]

合法 widget idtag_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
oidc_rsa_private_pem (空)启用 OIDC 时懒生成并写入;未启用不落盘 .oidc_rsa.pem

6.4b 敏感词

Key 默认
filter_words 默认词表文本;启动时从旧 filter_words.txt 导入(若键为空)

6.5 Gitea 同步(后置,键保留兼容)

Key 默认
gitea_sync_enabled 0
gitea_base_url
gitea_token
gitea_sync_interval_min 60

本迭代不启同步任务;见 02-features.md §K。

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 在 AutoMigrate 后:

  • status 的帖/评 → published
  • post_typenormal
  • Exp=0 用户按存量内容粗算经验:posts*10 + comments*2 + like_sum

新站若从空库开始可忽略;若迁移旧库需保留等价 backfill。


8. 内容门控在库中的形态

无独立表存放门控块;存在 posts.content HTML 中,例如:

<members-only>...</members-only>
<reply-only>...</reply-only>
<points-only data-cost="10">...</points-only>

积分解锁 block_key = sha256(innerHTML)[:16]hexservice/unlock.go