贡献指南
欢迎参与 DMHub 的开发!
开发环境
前置要求
- Node.js ≥ 20
- pnpm ≥ 9
- PostgreSQL 16(推荐)或 MariaDB 10.2.7+ / MySQL 8.0.13+
搭建步骤
bash
# 1. 克隆仓库
git clone https://github.com/FishpondStu/dmhub.git
cd dmhub
# 2. Fork 后克隆你自己的 fork
# git clone https://github.com/<你的用户名>/dmhub.git
# 3. 安装依赖
pnpm install
# 4. 构建依赖包
pnpm --filter @dmhub/shared build
pnpm --filter @dmhub/dns-providers build
# 5. 启动开发服务器
pnpm dev:server # 后端 :8088
pnpm dev:web # 前端 :5173
# 6. 访问 http://localhost:5173 进入初始化引导环境变量
复制 .env.example 为 .env:
bash
JWT_SECRET=your_jwt_secret
ENCRYPTION_KEY=your_encryption_key
PORT=8088数据库
开发环境可通过 Docker 快速启动:
bash
# PostgreSQL(推荐)
docker run -d --name dmhub-postgres \
-e POSTGRES_USER=dmhub \
-e POSTGRES_PASSWORD=dmhub \
-e POSTGRES_DB=dmhub \
-p 5432:5432 \
postgres:16-alpine
# MariaDB
docker run -d --name dmhub-mariadb \
-e MARIADB_ROOT_PASSWORD=dmhub \
-e MARIADB_DATABASE=dmhub \
-e MARIADB_USER=dmhub \
-e MARIADB_PASSWORD=dmhub \
-p 3306:3306 \
mariadb:11代码结构
Monorepo 结构
dmhub/
├── apps/web/ # 前端(Vue 3 + Vite)
├── apps/server/ # 后端(Fastify + TypeScript)
├── packages/shared/ # 共享类型、Schema、常量
└── packages/dns-providers/ # DNS 适配器后端约定
apps/server/src/
├── routes/ # 路由处理,仅做参数校验和调用 service
├── services/ # 业务逻辑,所有数据库操作在此
├── middleware/ # 中间件(authenticate, requireRole, requireDomainAccess 等)
├── db/
│ ├── schema-pg.ts # PostgreSQL schema(pg-core,20 张表)
│ ├── schema-mysql.ts # MySQL/MariaDB schema(mysql-core,20 张表)
│ ├── schema.ts # 启动时根据 DB_TYPE 动态 re-export
│ ├── helpers.ts # 跨方言 DB 帮手(insertReturningOne 等)
│ └── index.ts # 维护 pgDb / mysqlDb 双实例
├── lib/ # 工具库(JWT, cron, WHOIS, 通知等)
└── config/ # Zod 校验的环境变量新增功能的流程:
- 在
db/schema-pg.ts添加表定义 - 在
db/schema-mysql.ts添加对应的 MySQL 版本 - 在
db/schema.ts的 re-export 列表中导出 - 在
services/setup.ts的迁移脚本中添加建表语句 - 在
services/添加业务逻辑(使用 helpers 的跨方言写法) - 在
routes/添加路由 - 在
index.ts注册路由
前端约定
apps/web/src/
├── views/ # 页面组件(对应路由)
├── components/ # 通用组件
│ └── ui/ # Radix Vue 组件库
├── stores/ # Pinia 状态管理
├── router/ # 路由配置
└── lib/ # 工具函数代码规范
TypeScript
- 严格模式(
strict: true) - 禁止未使用的变量和参数
- 使用 ESM 模块(
module: "ESNext")
后端
- 路由文件只做参数校验和 service 调用,不写业务逻辑
- Service 文件包含所有业务逻辑和数据库操作
- 使用 Drizzle ORM 链式调用,注意
.where()返回新对象 - 错误通过
throw new Error('...')抛出
前端
- 使用 Vue 3 Composition API(
<script setup lang="ts">) - 使用 Pinia composition store 风格
- UI 组件使用 Radix Vue,不要引入其他 UI 库
- 样式使用 Tailwind CSS 工具类
通用
- 缩进:2 空格
- 不添加多余注释
- 中文作为 UI 文案和错误提示语言
跨方言注意事项
DMHub 同时支持 PG 和 MySQL,业务代码必须跨方言兼容:
typescript
// 错:MySQL 不支持 .returning()
const [row] = await db.insert(users).values(v).returning({ id: users.id });
// 对:用 helpers
import { insertReturningOne, insertIgnore } from '../db/helpers.js';
const row = await insertReturningOne(users, v, { id: users.id });
// 错:MySQL 不支持 .onConflictDoNothing()
await db.insert(t).values(v).onConflictDoNothing();
// 对
await insertIgnore(t, v);JSON 列默认值:MySQL 8.0.13+ / MariaDB 10.2.7+ 之前不支持 JSON 列默认值。迁移脚本需显式写 DEFAULT (JSON_ARRAY())。
构建与部署
bash
# 构建所有包
pnpm --filter @dmhub/shared build
pnpm --filter @dmhub/dns-providers build
# 构建后端
cd apps/server && npm run build # tsc → dist/
# 构建前端
cd apps/web && npm run build # vite build → dist/
# Docker 构建
docker compose up -d --build提交规范
- Fork 仓库,从
main创建功能分支 - 提交信息简洁明了
- 一个 PR 解决一个问题
- 确保
pnpm lint通过 - 确保 TypeScript 编译无错误
关键注意事项
Drizzle ORM
.where() 返回新的查询对象,不会修改原对象:
typescript
// 错误
const q = db.select().from(table);
q.where(eq(table.id, id));
return q;
// 正确
return db.select().from(table).where(eq(table.id, id));JWT Token
- Access Token:
{ userId, role }— 15 分钟 - Refresh Token:
{ userId, scope: 'refresh' }— 7 天 - 2FA Token:
{ userId, scope: '2fa' }— 5 分钟
文件上传
开发模式需确保 vite.config.ts 代理了 /uploads 路径。Nginx client_max_body_size 设为 6M。
