Files
JARVIS/development-doc/plan/forum-update/phase-f-1-data-model.md

9.7 KiB
Raw Blame History

Phase F.1:数据模型升级

日期2026-04-04 状态:待开始 依赖F.0(已完成) 前置models/forum.py


1. 本阶段目的

升级 Jarvis Forum 的数据模型,支持:

  • 多板块系统(指令/讨论/任务等)
  • 标签系统(细粒度分类)
  • 帖子元数据扩展(阅读量、点赞、收藏等)
  • 层级回复结构

2. 目标模型

2.1 ForumBoard板块

class ForumBoard(BaseModel):
    __tablename__ = "forum_boards"
    
    id: str = Field(default_factory=lambda: str(uuid.uuid4()))
    name: str  # 板块名称,如 "指令广场"
    slug: str  # URL 友好名称,如 "instruction"
    description: Optional[str]
    icon: Optional[str]  # emoji 或图标名
    sort_order: int = 0
    is_active: bool = True
    min_role: str = "user"  # 查看权限guest/user/moderator/admin
    
    parent_id: Optional[str]  # 父板块,支持层级
    color: Optional[str]  # 板块颜色

2.2 ForumPost帖子扩展

class ForumPost(BaseModel):
    __tablename__ = "forum_posts"
    
    # === 现有字段 ===
    user_id: str
    title: str
    content: str
    reply_count: int = 0
    
    # === 新增字段 ===
    board_id: Optional[str] = None  # 所属板块
    parent_id: Optional[str] = None  # 父帖子(支持回复嵌套)
    
    # 分类与标签
    category: Optional[str]  # instruction/discussion/question/praise/bug
    tags: Optional[str] = ""  # JSON 数组 ["python", "api"]
    
    # 状态与权限
    is_pinned: bool = False  # 置顶
    is_locked: bool = False  # 锁定(禁止回复)
    is_deleted: bool = False  # 软删除
    is_executed: bool = False  # 指令已执行
    execution_result: Optional[str]
    
    # 统计与互动
    view_count: int = 0
    like_count: int = 0
    favorite_count: int = 0
    share_count: int = 0
    
    # 时间戳
    last_reply_at: Optional[datetime] = None  # 最后回复时间
    last_activity_at: Optional[datetime] = None
    
    # === 关系 ===
    board = relationship("ForumBoard", back_populates="posts")
    replies = relationship("ForumReply", back_populates="post", cascade="all, delete-orphan")
    post_tags = relationship("ForumPostTag", back_populates="post", cascade="all, delete-orphan")
    likes = relationship("ForumLike", back_populates="post", cascade="all, delete-orphan")

2.3 ForumReply回复扩展

class ForumReply(BaseModel):
    __tablename__ = "forum_replies"
    
    # === 现有字段 ===
    post_id: str
    user_id: Optional[str]
    agent_id: Optional[str]
    content: str
    is_ai_reply: bool = False
    
    # === 新增字段 ===
    parent_id: Optional[str] = None  # 父回复(支持嵌套)
    floor: int = 1  # 楼层号
    is_pinned: bool = False  # 置顶
    is_best: bool = False  # 最佳回复
    is_deleted: bool = False  # 软删除
    like_count: int = 0
    edited_at: Optional[datetime] = None  # 编辑时间
    
    # === 关系 ===
    post = relationship("ForumPost", back_populates="replies")
    parent = relationship("ForumReply", remote_side=[id], backref="children")
    likes = relationship("ForumLike", back_populates="reply", cascade="all, delete-orphan")

2.4 ForumTag标签

class ForumTag(BaseModel):
    __tablename__ = "forum_tags"
    
    id: str = Field(default_factory=lambda: str(uuid.uuid4()))
    name: str  # 标签名,如 "python"
    slug: str  # URL 友好名
    color: str = "#666666"  # 标签颜色
    post_count: int = 0  # 帖子数量(缓存)
    is_official: bool = False  # 官方标签
    board_id: Optional[str] = None  # 限定板块
    
    posts = relationship("ForumPostTag", back_populates="tag")


class ForumPostTag(BaseModel):
    """帖子-标签关联"""
    __tablename__ = "forum_post_tags"
    
    post_id: str
    tag_id: str
    
    post = relationship("ForumPost", back_populates="post_tags")
    tag = relationship("ForumTag", back_populates="posts")

2.5 ForumLike点赞

class ForumLike(BaseModel):
    __tablename__ = "forum_likes"
    
    user_id: str
    post_id: Optional[str] = None
    reply_id: Optional[str] = None
    created_at: datetime = Field(default_factory=datetime.utcnow)
    
    post = relationship("ForumPost", back_populates="likes")
    reply = relationship("ForumReply", back_populates="likes")

2.6 ForumStats用户统计

class ForumStats(BaseModel):
    """用户论坛统计"""
    __tablename__ = "forum_stats"
    
    user_id: str = Field(primary_key=True)
    post_count: int = 0
    reply_count: int = 0
    like_received: int = 0  # 收到的赞
    best_reply_count: int = 0  # 最佳回复数
    score: int = 0  # 积分
    
    last_post_at: Optional[datetime] = None
    last_reply_at: Optional[datetime] = None

3. 数据库迁移

3.1 新增表

-- 板块表
CREATE TABLE forum_boards (
    id TEXT PRIMARY KEY,
    name TEXT NOT NULL,
    slug TEXT UNIQUE NOT NULL,
    description TEXT,
    icon TEXT,
    sort_order INTEGER DEFAULT 0,
    is_active BOOLEAN DEFAULT TRUE,
    min_role TEXT DEFAULT 'user',
    parent_id TEXT,
    color TEXT
);

-- 帖子-标签关联表
CREATE TABLE forum_post_tags (
    post_id TEXT NOT NULL,
    tag_id TEXT NOT NULL,
    PRIMARY KEY (post_id, tag_id)
);

-- 标签表
CREATE TABLE forum_tags (
    id TEXT PRIMARY KEY,
    name TEXT NOT NULL UNIQUE,
    slug TEXT UNIQUE NOT NULL,
    color TEXT DEFAULT '#666666',
    post_count INTEGER DEFAULT 0,
    is_official BOOLEAN DEFAULT FALSE,
    board_id TEXT
);

-- 点赞表
CREATE TABLE forum_likes (
    user_id TEXT NOT NULL,
    post_id TEXT,
    reply_id TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (user_id, post_id, reply_id)
);

-- 用户论坛统计表
CREATE TABLE forum_stats (
    user_id TEXT PRIMARY KEY,
    post_count INTEGER DEFAULT 0,
    reply_count INTEGER DEFAULT 0,
    like_received INTEGER DEFAULT 0,
    best_reply_count INTEGER DEFAULT 0,
    score INTEGER DEFAULT 0,
    last_post_at TIMESTAMP,
    last_reply_at TIMESTAMP
);

-- 扩展 forum_posts 表
ALTER TABLE forum_posts ADD COLUMN board_id TEXT;
ALTER TABLE forum_posts ADD COLUMN parent_id TEXT;
ALTER TABLE forum_posts ADD COLUMN tags TEXT DEFAULT '';
ALTER TABLE forum_posts ADD COLUMN is_pinned BOOLEAN DEFAULT FALSE;
ALTER TABLE forum_posts ADD COLUMN is_locked BOOLEAN DEFAULT FALSE;
ALTER TABLE forum_posts ADD COLUMN is_deleted BOOLEAN DEFAULT FALSE;
ALTER TABLE forum_posts ADD COLUMN view_count INTEGER DEFAULT 0;
ALTER TABLE forum_posts ADD COLUMN like_count INTEGER DEFAULT 0;
ALTER TABLE forum_posts ADD COLUMN favorite_count INTEGER DEFAULT 0;
ALTER TABLE forum_posts ADD COLUMN share_count INTEGER DEFAULT 0;
ALTER TABLE forum_posts ADD COLUMN last_reply_at TIMESTAMP;
ALTER TABLE forum_posts ADD COLUMN last_activity_at TIMESTAMP;

-- 扩展 forum_replies 表
ALTER TABLE forum_replies ADD COLUMN parent_id TEXT;
ALTER TABLE forum_replies ADD COLUMN floor INTEGER DEFAULT 1;
ALTER TABLE forum_replies ADD COLUMN is_pinned BOOLEAN DEFAULT FALSE;
ALTER TABLE forum_replies ADD COLUMN is_best BOOLEAN DEFAULT FALSE;
ALTER TABLE forum_replies ADD COLUMN is_deleted BOOLEAN DEFAULT FALSE;
ALTER TABLE forum_replies ADD COLUMN like_count INTEGER DEFAULT 0;
ALTER TABLE forum_replies ADD COLUMN edited_at TIMESTAMP;

4. Schema 扩展

4.1 ForumBoardSchema

class ForumBoardCreate(BaseModel):
    name: str = Field(..., max_length=100)
    slug: str = Field(..., max_length=50, pattern=r"^[a-z0-9-]+$")
    description: Optional[str] = None
    icon: Optional[str] = None
    sort_order: int = 0
    min_role: str = "user"
    parent_id: Optional[str] = None
    color: Optional[str] = None


class ForumBoardOut(BaseModel):
    id: str
    name: str
    slug: str
    description: Optional[str]
    icon: Optional[str]
    sort_order: int
    post_count: int = 0  # 动态计算


class ForumPostCreate(BaseModel):
    title: str = Field(..., max_length=200)
    content: str = Field(..., max_length=50000)
    board_id: Optional[str] = None
    category: Optional[str] = None
    tags: List[str] = []


class ForumPostOut(BaseModel):
    id: str
    user_id: str
    title: str
    content: str
    board_id: Optional[str]
    board_name: Optional[str] = None
    category: Optional[str]
    tags: List[str] = []
    reply_count: int
    view_count: int
    like_count: int
    is_pinned: bool
    is_locked: bool
    created_at: datetime
    last_reply_at: Optional[datetime]
    user_liked: bool = False  # 当前用户是否点赞

5. 实现步骤

步骤 任务 优先级
1 创建数据库迁移脚本 🟢
2 扩展 models/forum.py 🟢
3 创建 ForumBoard 模型 🟢
4 创建 ForumTag/ForumPostTag 模型 🟡
5 创建 ForumLike 模型 🟡
6 创建 ForumStats 模型 🟡
7 扩展 schemas/forum.py 🟢
8 编写单元测试 🟡

6. 核心文件变更

文件 变更
models/forum.py 新增 ForumBoard, ForumTag, ForumPostTag, ForumLike, ForumStats扩展 ForumPost, ForumReply
schemas/forum.py 新增 ForumBoardCreate/Out扩展 ForumPostCreate/Out
database.py 注册新模型

7. 工作量估算

任务 工作量
数据库迁移脚本 0.5 天
模型扩展 0.5 天
Schema 扩展 0.5 天
单元测试 0.5 天
总计 2 天

8. 验收标准

  • ForumBoard 模型可创建/查询板块
  • ForumPost 可关联板块和标签
  • ForumTag 可创建/查询标签
  • ForumLike 支持点赞功能
  • ForumStats 正确统计用户数据
  • 所有新模型有对应的 Pydantic Schema
  • 迁移脚本可回滚
  • 单元测试覆盖新增功能