likebocai-nuxt
单个 Nuxt 4 应用,按二级域名分流,一个 Node 服务撑起全部子站。
以「个人品牌 + 社区互动」为核心的多子域名门户网站前端。
后端为独立 Java 项目(Spring Security + Knife4j),前端通过 RESTful API 交互。
目录
🌐 子站架构
www.likebocai.com → 🏠 主站门户(导航 + 动态聚合)
blog.likebocai.com → 📝 博客(长文 + 📸 随手拍 / 朋友圈式轻分享)
mail.likebocai.com → ⏳ 时光邮箱(未来信件 + 公开信)
game.likebocai.com → 🎮 游戏站(平台绑定 + 游戏墙 + 教程 + 论坛)
admin.likebocai.com → 📊 管理后台
- 代码组织:单仓库 + 单应用,不拆 monorepo,组件放
app/components/ 天然共享
- 域名分流:方案 B——
pages/ 按子站前缀组织(blog/、mail/、game/ 等),中间件根据 Host 头 rewrite
🛠️ 技术栈
核心框架
| 类别 |
方案 |
版本(精确锁定) |
| 框架 |
Nuxt 4 + Vue 3 + TypeScript |
nuxt 4.4.8 / vue 3.5.39 / typescript 6.0.3 |
| Node |
22.16.0(brew install node@22) |
.nvmrc 精确锁 |
| 包管理器 |
pnpm + Corepack |
pnpm@11.10.0(packageManager 字段锁) |
| 渲染模式 |
SSR / SSG |
内容页保 SEO |
样式 & UI
| 类别 |
方案 |
说明 |
| CSS 方案 |
Tailwind CSS v3(@nuxtjs/tailwindcss) |
稳字当头,v4 生态成熟后再升级 |
| UI 组件 |
手写为主 + Reka UI 按需 |
追求活力/原创/扩展性;Reka UI 是 Headless 库,SSR/SEO 友好 |
| 组件命名 |
Nuxt 自动导入(文件即路由) |
子目录自动添加前缀(如 blog/ArticleCard.vue → <BlogArticleCard>) |
| 动效 |
分层:CSS/motion → GSAP |
CSS 优先,复杂动画后期引入 GSAP;composable 封装,兼容升级 |
| 深色模式 |
Tailwind darkMode: 'class' + useDark() |
@vueuse/core |
| 移动端 |
响应式 / 移动优先 |
Tailwind 响应式工具类 |
内容渲染 & 编辑
| 场景 |
编辑器 |
存储格式 |
渲染引擎 |
用户 |
| 博客长文 / 游戏教程 |
md-editor-v3(分屏 MD) |
Markdown |
markdown-it + Shiki |
懂 MD 的作者 |
| 时光邮箱 / 评论 |
Tiptap(所见即所得) |
JSON |
@tiptap/html generateHTML() |
零门槛泛人群 |
渲染一致性保证:
- Tiptap 编辑器 +
generateHTML() 用同一套 extensions 配置
- 所有 UGC 输出必须经过
isomorphic-dompurify(SSR 同构版)消毒
- 禁止在
onMounted 或 <ClientOnly> 里做正文渲染(毁 SEO)
状态管理 & 工具
| 类别 |
方案 |
说明 |
| 状态管理 |
Pinia(复杂业务)+ useState(轻量) |
@pinia/nuxt |
| 工具库 |
@vueuse/core + @vueuse/nuxt |
Vue 瑞士军刀 |
| API 封装 |
app/composables/useApi.ts |
$fetch.create + 双 Token 刷新 + 401 拦截 |
| Markdown 渲染 |
app/composables/useMarkdown.ts |
markdown-it + Shiki 高亮 + DOMPurify |
| Tiptap 渲染 |
app/composables/useTiptapRender.ts |
generateHTML() + DOMPurify |
性能 & SEO & PWA
| 类别 |
方案 |
说明 |
| 图片优化 |
@nuxt/image |
懒加载 + WebP/AVIF + 响应式(图多,重中之重) |
| 字体优化 |
@nuxt/fonts |
|
| 第三方脚本 |
@nuxt/scripts |
延迟加载 |
| PWA |
@vite-pwa/nuxt |
可安装 + 离线 + 推送 |
| SEO |
@nuxtjs/sitemap + useSeoMeta |
按域名动态生成 sitemap / robots |
| 打包分析 |
nuxi analyze |
按路由分包 |
搜索方案
| 类别 |
方案 |
说明 |
| 后端引擎 |
Meilisearch |
后端已选型,全文检索/分词/高亮/拼写容错 |
| 范围 |
全站聚合搜索 + 各子站精搜 |
主站大搜索框,各站也有自己的搜索 |
| 前端交互 |
即时搜索(打字实时出结果) |
Meilisearch 天生擅长 |
| 前端对接 |
JS SDK / instant-meilisearch |
只用只读 Search API Key,或走 Java 代理 |
| 安全 |
前端直连限只读 Key;防抖 + 最小字符数 |
⚠️ Phase 2 开发到此模块时重点处理 |
代码规范 & 测试
| 类别 |
方案 |
说明 |
| ESLint |
@nuxt/eslint |
Nuxt 官方模块,flat config |
| Prettier |
独立配置 .prettierrc |
semi: false, singleQuote, trailingComma: all |
| Husky |
pre-commit: lint + format; pre-push: test |
提交前自动检查 |
| commitlint |
@commitlint/config-conventional |
feat:/fix:/docs:/chore:... |
| 单元测试 |
Vitest + @nuxt/test-utils |
轻量策略,只测核心逻辑 |
| E2E |
Playwright(后期补) |
项目稳定后再写用例 |
| 错误监控 |
Phase 1 最小化(onErrorCaptured + 日志) |
Phase 2 上 Sentry |
| IDE |
WebStorm 主力,VS Code 备用 |
.editorconfig 跨 IDE 统一格式 |
TS 类型同步
- 开发时手写在
shared/types/
- 后端 Knife4j 提供
/v3/api-docs(OpenAPI JSON)
- CI 中跑 openapi-typescript 自动生成到
shared/types/api.d.ts
- 前后端类型强制一致
部署
| 类别 |
方案 |
说明 |
| 进程守护 |
PM2 |
ecosystem.config.cjs,平滑重启 |
| 反向代理 |
Nginx |
所有子域名反代到同一 Nuxt 端口,透传 Host 头 |
| HTTPS |
全站强制 |
SSO Cookie Secure 的前提 |
| CI/CD |
Forgejo Actions |
push → lint → test → build → 传服务器 → pm2 reload |
| 版本号 |
3.0.0.260708_Likebocai-nuxt |
和后端 3.0.0.260708_Likebocai 对齐 |
🚀 快速开始
# 1. 确保 Node >= 22.16.0(见 .nvmrc)
node --version
# 2. 启用 Corepack(锁死 pnpm 版本)
corepack enable
# 3. 安装依赖(冻结 lockfile,可复现)
pnpm install --frozen-lockfile
# 4. 启动开发服务器
pnpm dev
# → http://localhost:3000
🏗️ 项目架构
1. 域名分流(命根子)
一个 Nuxt 应用,靠读取请求的 Host 头判断访问的是哪个子站,然后切换布局 + 内容。
流程
用户浏览器 → Nginx → Nuxt SSR 服务
↓
domain.global.ts(全局中间件)
→ useRequestHeaders(['host']) 读 Host
→ getSiteByHost(host) 解析子站
→ useState('site') 注入全站
→ setPageLayout() 切换布局
→ 渲染对应内容
实现
- 域名映射表集中在
app/utils/site-config.ts
- 页面按子站前缀组织在
pages/ 下(方案 B)
- 各子站布局文件在
layouts/ 下
useSite() composable 供全站读取当前子站信息
关键前提
- Nginx 必须
proxy_set_header Host $host; —— 漏了分流全废
- 全站 HTTPS —— SSO Cookie 需
Secure
- 开发环境:配
/etc/hosts 模拟多域名
2. SSO 鉴权(单点登录)
总体方案
JWT 放在 httpOnly Cookie(不放 localStorage,防 XSS)
Cookie domain: .likebocai.com → 所有子域名共享登录态
属性:HttpOnly + Secure + SameSite=Lax
双 Token 无感知刷新
| Token |
生命周期 |
Cookie 类型 |
说明 |
| Access Token(JWT) |
15~30 分钟 |
会话 Cookie(不设 Max-Age) |
实际鉴权用 |
| Refresh Token |
7~30 天 |
持久 Cookie(设 Max-Age) |
换新 Access Token |
API 返回 401(Access Token 过期)
→ 前端自动调 POST /api/auth/refresh
→ Java 验 Refresh Token
→ 通过:签发新 Access Token(Set-Cookie),重试原请求
→ 失败(Refresh 也过期):真·401,跳登录页
前端职责
- 应用启动时调
GET /api/auth/me 获取用户信息 → 存入 Pinia
- API 请求时浏览器自动带 Cookie,前端不手动加 Token
- SSR 时用
useRequestHeaders(['cookie']) 转发 Cookie → Java
- 响应 401 → 自动 Refresh → 重试 → 再失败跳
/auth/login
auth.ts 中间件做登录保护
Phase 1 范围
- 邮箱 + 密码注册/登录
- OAuth(GitHub/Google/微信)→ Phase 2 TODO
需要的后端接口
| 方法 |
路径 |
说明 |
POST |
/api/auth/login |
邮箱密码登录,Set-Cookie 返回双 Token |
GET |
/api/auth/me |
获取当前用户信息 |
POST |
/api/auth/refresh |
刷新 Access Token |
POST |
/api/auth/logout |
登出,清除 Cookie |
详见 BACKEND_INTEGRATION.md。
3. 两条内容管线
|
博客 / 游戏教程 |
时光邮箱 / 评论 |
| 用户群 |
作者 / 懂 MD 的人 |
泛人群(多为小白) |
| 编辑器 |
md-editor-v3(分屏 MD) |
Tiptap(所见即所得) |
| 编辑体验 |
写 # 标题 |
点按钮加粗/插图 |
| 存储格式 |
Markdown 字符串 |
Tiptap JSON(getJSON()) |
| 图片上传 |
编辑器配置 OSS 上传 URL |
编辑器 Image 扩展 + 上传回调 |
| 渲染 |
markdown-it(SSR 阶段) |
@tiptap/html generateHTML() |
| 代码高亮 |
Shiki |
— |
| XSS 消毒 |
isomorphic-dompurify |
isomorphic-dompurify |
| 特殊能力 |
代码块 / 数学公式(可扩展) |
自定义表情包(仅评论区用) |
表情包归属: 全站只有评论区需要自定义表情包。博客、游戏教程、时光邮箱只需正常图片上传,不涉及表情语法。
Server API(给 Java 后端调用):
| 方法 |
路径 |
说明 |
POST |
/api/render-md |
Markdown → HTML(供 Java 渲染博客/教程内容) |
POST |
/api/render-tiptap |
Tiptap JSON → HTML(供 Java 渲染邮箱/评论内容) |
4. API 请求封装
统一走 app/composables/useApi.ts:
- baseURL 自动读取
runtimeConfig.public.apiBaseUrl
- 客户端:Cookie 自动带(同域名
.likebocai.com)
- SSR:转发客户端 Cookie → Java API
- 401:自动 Refresh → 重试 → 再失败跳
/auth/login
- 防并发刷新(同时多个 API 401 只发一次 refresh)
RESTful 约定
统一响应结构:
{
"code": 0,
"message": "ok",
"data": {}
}
分页:
{
"code": 0,
"data": {
"list": [],
"total": 100,
"page": 1,
"pageSize": 10
}
}
5. SSR 渲染铁律
正文渲染必须在服务端完成,绝不放在客户端。
| ✅ 正确(SEO 友好) |
❌ 错误(毁 SEO) |
useAsyncData 里渲染 |
onMounted 里渲染 |
computed 里渲染 |
<ClientOnly> 包裹正文 |
| SSR 输出完整 HTML |
爬虫看到空壳 |
markdown-it 和 @tiptap/html 的 generateHTML() 都是纯 JS 函数,
在 Node 端可以正常跑,关键在于调用时机。
isomorphic-dompurify 是同构版本,服务端和浏览器都能消毒。
6. 环境变量管理
| 环境 |
配置方式 |
| 本地开发 |
.env + .env.development(Nuxt 原生支持) |
| PM2 生产 |
ecosystem.config.cjs 的 env 字段 |
runtimeConfig 划分:
| 级别 |
范围 |
示例 |
public |
前端可访问 |
apiBaseUrl, siteUrl |
private |
仅 Nitro 服务端 |
内部 API Token、密钥 |
当前变量:
| 变量 |
用途 |
NUXT_PUBLIC_API_BASE_URL |
Java 后端 API 地址(默认 https://api.likebocai.com) |
NUXT_PUBLIC_SITE_URL |
Nuxt 自身地址,OAuth 回调 / sitemap 生成用(默认 https://www.likebocai.com) |
.env.example 提交到仓库做示范。
📂 目录结构
likebocai-nuxt/
├── app/
│ ├── assets/css/ # Tailwind 入口 + 各子站主题变量
│ │ └── themes/ # blog.css / mail.css / game.css
│ ├── components/ # 组件(Nuxt 自动导入)
│ │ ├── AppHeader.vue # 全站通用头部
│ │ ├── AppFooter.vue # 全站通用页脚
│ │ ├── ThemeToggle.vue # 深色模式切换
│ │ ├── base/ # 手写基础组件
│ │ │ ├── BaseButton.vue # 精心打磨,全站复用
│ │ │ ├── BaseCard.vue
│ │ │ ├── BaseInput.vue
│ │ │ └── BaseModal.vue # 复杂交互内部用 Reka UI
│ │ ├── blog/ # 博客专属
│ │ │ ├── MarkdownRenderer.vue # markdown-it + Shiki + DOMPurify
│ │ │ └── moment/ # 随手拍
│ │ ├── mail/ # 时光邮箱专属
│ │ │ ├── LetterEditor.vue # Tiptap 封装
│ │ │ ├── MailPreview.vue # 邮件模板预览(双视图对照)
│ │ │ └── EnvelopeOpen.vue # 招牌信封动画
│ │ └── comment/ # 评论组件(跨站复用)
│ │ ├── CommentEditor.vue # Tiptap + 自定义表情包 + 安全护栏
│ │ ├── CommentList.vue # 首屏 SSR + "加载更多"
│ │ └── CommentItem.vue
│ ├── composables/ # 组合式函数(自动导入)
│ │ ├── useSite.ts # 当前子站信息(由域名中间件注入)
│ │ ├── useAuth.ts # 登录态 / SSO
│ │ ├── useTheme.ts # 深色模式
│ │ ├── useApi.ts # API 请求封装(双 Token 刷新 + 401 处理)
│ │ ├── useMarkdown.ts # MD → HTML 渲染(SSR 安全)
│ │ ├── useTiptapRender.ts # Tiptap JSON → HTML(SSR 安全)
│ │ └── useCardHover.ts # 动效封装示例(便于升级 GSAP)
│ ├── layouts/ # 布局(各子站不同风格)
│ │ ├── default.vue # 主站 / 兜底
│ │ ├── blog.vue # 博客
│ │ ├── mail.vue # 时光邮箱
│ │ ├── game.vue # 游戏站
│ │ └── admin.vue # 管理后台(侧边栏布局)
│ ├── middleware/ # 路由中间件
│ │ ├── domain.global.ts # 🔑 全局域名分流(核心中间件)
│ │ └── auth.ts # 登录保护(按需使用)
│ ├── pages/ # 页面(按子站前缀组织)
│ │ ├── index.vue # 主站首页(www)
│ │ ├── blog/
│ │ │ ├── index.vue # 博客首页 / 列表
│ │ │ ├── [slug].vue # 文章详情
│ │ │ └── moments.vue # 随手拍时间流
│ │ ├── mail/
│ │ │ ├── index.vue # 公共信件广场
│ │ │ ├── write.vue # 写信(Tiptap)
│ │ │ └── [id].vue # 信件详情
│ │ ├── game/ # 游戏站(Phase 2)
│ │ ├── user/
│ │ │ ├── [username].vue # 个人主页
│ │ │ └── settings.vue # 用户设置
│ │ └── auth/
│ │ ├── login.vue # 登录
│ │ └── callback.vue # OAuth 回调
│ ├── plugins/ # 插件(TipTap 客户端初始化等)
│ ├── stores/ # Pinia
│ │ ├── auth.ts # 用户登录态
│ │ └── ui.ts # 主题、全局 UI 状态
│ ├── utils/ # 纯工具函数
│ │ ├── site-config.ts # 域名 ↔ 子站映射表(唯一数据源)
│ │ ├── sanitize.ts # DOMPurify 封装
│ │ └── date.ts # 日期工具(信件解锁判断、格式化)
│ ├── app.vue # 根组件
│ └── error.vue # 错误页
│
├── server/ # Nitro 服务端
│ ├── api/
│ │ ├── render-md.post.ts # Markdown → HTML(给 Java 调)
│ │ └── render-tiptap.post.ts # Tiptap JSON → HTML(给 Java 调)
│ └── routes/
│ └── sitemap.xml.ts # 按域名动态生成 sitemap
│
├── shared/ # 前后端共享
│ ├── types/ # TS 类型
│ │ ├── api.ts # API 响应结构 + 分页
│ │ ├── user.ts # User 实体
│ │ ├── blog.ts # BlogArticle 实体
│ │ └── mail.ts # MailLetter 实体
│ ├── constants/ # 常量(子站/分类/权限枚举)
│ └── email-templates/ # 📮 邮件模板(前后端同源)
│
├── tests/
│ ├── unit/ # Vitest 单元测试
│ └── e2e/ # Playwright E2E(后期)
│
├── .forgejo/workflows/ci.yml # Forgejo Actions CI/CD
├── ecosystem.config.cjs # PM2 部署配置
├── nuxt.config.ts # Nuxt 配置
├── tailwind.config.js # Tailwind v3
├── eslint.config.mjs # ESLint(@nuxt/eslint flat config)
├── .prettierrc # Prettier
├── .prettierignore
├── .editorconfig # 跨 IDE 统一格式
├── commitlint.config.js # 提交信息规范
├── vitest.config.ts # Vitest
├── tsconfig.json # TypeScript
├── .nvmrc # Node 版本锁
├── .npmrc # save-exact + engine-strict
├── .gitignore
├── README.md # 本文档
├── PRODUCT_PLAN.md # 产品全景需求文档
├── SETUP_HANDOFF.md # 技术选型 & 决策记录
└── BACKEND_INTEGRATION.md # 后端对接文档(鉴权/API/类型同步)
💻 本地多域名调试
# 1. 配 /etc/hosts
sudo sh -c 'cat >> /etc/hosts << EOF
127.0.0.1 www.likebocai.local blog.likebocai.local game.likebocai.local mail.likebocai.local admin.likebocai.local
EOF'
| 访问地址 |
子站 |
http://localhost:3000 |
未知(默认主站布局) |
http://blog.likebocai.local:3000 |
博客 |
http://mail.likebocai.local:3000 |
时光邮箱 |
http://game.likebocai.local:3000 |
游戏站 |
用 curl 验证 SSR 分流:
curl http://localhost:3000/ # → 当前子站:未知
curl -H "Host: blog.likebocai.local" localhost:3000/ # → 当前子站:博客
curl -H "Host: mail.likebocai.local" localhost:3000/ # → 当前子站:时光邮箱
📋 常用命令
| 命令 |
用途 |
pnpm dev |
启动开发服务器 |
pnpm build |
生产构建 |
pnpm preview |
本地预览生产构建 |
pnpm lint |
ESLint 检查 |
pnpm format |
Prettier 格式化 |
pnpm test |
Vitest 测试(watch 模式) |
pnpm test:run |
Vitest 测试(单次运行) |
pnpm typecheck |
vue-tsc 类型检查 |
pnpm analyze |
nuxi analyze 打包体积分析 |
🔒 版本锁定规范
Owner 上个项目因为没锁版本吃了依赖漂移的大亏,以下每一条都是血的教训。
| 层级 |
手段 |
作用 |
| Node |
.nvmrc + package.json engines + .npmrc engine-strict=true |
锁运行时版本 |
| 包管理器 |
package.json packageManager 字段 + Corepack |
锁 pnpm 版本 |
| 直接依赖 |
.npmrc save-exact=true(精确版本,不用 ^ ~) |
锁自己装的包 |
| 依赖树 |
提交 pnpm-lock.yaml + CI 用 pnpm install --frozen-lockfile |
锁所有间接依赖 |
| 主动升级 |
pnpm outdated 手动 review 升级 |
有意识升级,不被动漂移 |
升级纪律
pnpm outdated # 查看可升级的包
pnpm up <包名> # 手动升级(精确版本)
# 升完必须跑测试
pnpm test:run
📏 代码规范
ESLint
- 使用
@nuxt/eslint(Nuxt 官方模块,flat config)
- 配置文件:
eslint.config.mjs
Prettier
{
"semi": false,
"singleQuote": true,
"trailingComma": "all",
"printWidth": 100,
"tabWidth": 2
}
Git Hooks
| Hook |
做什么 |
| pre-commit |
lint-staged(ESLint fix + Prettier write) |
| pre-push |
pnpm test:run |
Commit 规范
feat: 新功能
fix: 修 Bug
docs: 文档
style: 格式(不影响逻辑)
refactor: 重构
perf: 性能优化
test: 测试
chore: 杂项(依赖/构建/配置)
ci: CI/CD
build: 构建系统
🧪 测试策略
轻量策略 —— 只测最怕出错的核心逻辑,不为了测试而测试。
优先级
| 优先级 |
模块 |
测什么 |
| ⭐⭐⭐ |
时光邮箱权限判断 |
仅双方可见/可公开/甄选/匿名——隐私泄露后果严重 |
| ⭐⭐⭐ |
时光邮箱解锁时间 |
到期才开放、时区边界——未到期绝不能泄露 |
| ⭐⭐⭐ |
Markdown 渲染 + XSS |
渲染正确性 + 脚本过滤——安全红线 |
| ⭐⭐ |
评论安全护栏 |
长度限制、图片数量限制、格式收窄——是否生效 |
| ⭐⭐ |
SSO 登录态 |
Cookie 读取、路由保护中间件 |
| ⭐⭐ |
游戏数据处理(Phase 2) |
游戏墙排序、成就聚合、年度报告统计 |
| ⭐ |
通用工具函数 |
日期格式化、数据转换——成本最低,最好测 |
运行
pnpm test # watch 模式
pnpm test:run # 单次运行(CI 用)
🚢 部署
PM2
ecosystem.config.cjs:
module.exports = {
apps: [
{
name: 'likebocai-nuxt',
script: './.output/server/index.mjs',
env: {
NUXT_PUBLIC_API_BASE_URL: 'https://api.likebocai.com',
NUXT_PUBLIC_SITE_URL: 'https://www.likebocai.com',
},
},
],
}
pnpm build
pm2 start ecosystem.config.cjs
pm2 reload ecosystem.config.cjs # 平滑重启,不断服
Nginx 反代关键点
# 所有子域名反代到同一个 Nuxt 端口
server {
server_name ~^(www|blog|game|mail|admin)\.likebocai\.com$;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host; # ⚠️ 命根子:漏了域名分流全废
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# 静态资源可让 Nginx 直接托管 .output/public,减轻 Node 压力
# location /_nuxt/ { alias /path/to/.output/public/_nuxt/; }
}
全站必须 HTTPS —— SSO Cookie 的 Secure 标志要求。
CI/CD(Forgejo Actions)
.forgejo/workflows/ci.yml:
push (main / dev)
→ install --frozen-lockfile
→ lint
→ test:run
→ build
→ 传 .output 到服务器
→ pm2 reload
⚠️ 服务器地址、SSH 密钥等需和 owner 确认。
🗺️ MVP 分期
🚀 Phase 1(第一版上线)
| 模块 |
范围 |
| 主站门户 |
完整 |
| 博客(长文 + 随手拍) |
完整 |
| 时光邮箱 |
完整 |
| 用户系统 + SSO |
邮箱密码 |
| 评论系统 |
完整(含自定义表情包) |
| 友链 |
完整 |
| SEO |
完整(SSR/sitemap/meta) |
| 深色模式 |
完整 |
| 移动端适配 |
完整 |
| PWA |
完整 |
| RSS |
完整 |
🔧 Phase 2
| 模块 |
范围 |
| 游戏站 |
平台绑定 + 游戏墙 + 教程 |
| 作品集 |
完整 |
| 消息通知 |
完整 |
| 管理后台 |
完整 |
| 全局搜索 |
Meilisearch 即时搜索 |
| OAuth |
GitHub / Google / 微信 |
| Sentry |
前端错误监控 |
🎯 Phase 3
| 模块 |
范围 |
| 游戏站 |
ToC 论坛 + 年度报告 |
| 多语言 |
英文支持 |
| 统计埋点 |
GA / Umami |
📦 各模块功能概要
主站门户(www)
- 个人品牌展示(头像、简介、社交链接)
- 各子站最新内容聚合
- 导航到各子站
博客(blog)
- 长文:多分类(技术/生活/其他)、MD 编辑、草稿/发布/定时、标签、RSS、评论、社交分享
- 随手拍:短图文、多图九宫格、位置标记、心情标记、时间流、点赞评论、权限控制(公开/好友/自己)
时光邮箱(mail)
- 给自己写信:设未来日期,到期才能打开
- 公开信件:发布到公共广场
- 给别人写信:指定收件人
- 隐私控制:仅双方可见/可公开/甄选信件
- 匿名/实名选项
- 邮件通知:前端提供邮件模板预览(双视图对照编辑)
游戏站(game)—— Phase 2
- 平台绑定:Steam/PSN/Xbox/Nintendo Switch
- 数据同步:游戏库、游玩时长、成就、奖杯
- 游戏墙:有稀有成就/白金奖杯优先排列
- 教程 & 评测(Markdown,与博客共享编辑体验)
- 社区:ToC 论坛、组队招募(Phase 3)
- 年度游戏报告(Phase 3)
评论系统(跨站复用)
- 两层结构(评论 + 楼中楼回复平铺)
- Tiptap 富文本(加粗/链接/列表/代码/图片/自定义表情包)
- 安全护栏:XSS 消毒、长度限制、图片数量限制、格式收窄
- 首屏第一页 SSR,"加载更多"按钮客户端加载
管理后台(admin)—— Phase 2
- 文章管理 / 用户管理 / 信件管理审核 / 论坛管理 / 数据统计看板
🔜 待办