nodebbs 0.2.0 → 0.3.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -7,11 +7,13 @@
7
7
 
8
8
  ## 📖 简介
9
9
 
10
- NodeBBS CLI 是一个专为全栈开发者设计的命令行工具,用于简化 NodeBBS 项目的开发、部署和管理流程。它提供了直观的命令接口,让你可以轻松管理 Docker 容器、查看日志、操作数据库等。
10
+ NodeBBS CLI 是一个专为全栈开发者设计的命令行工具,用于简化 NodeBBS 项目的开发、部署和管理流程。它能够自动识别 **源码项目** 和 **纯净镜像部署** 两种场景,并提供开箱即用的 Docker 容器管理能力。
11
11
 
12
12
  ### 特性
13
13
 
14
- - �️ **交互式菜单** - 支持键盘导航的可视化命令选择
14
+ - **交互式菜单** - 支持键盘导航的可视化命令选择
15
+ - 🧠 **智能识别** - 自动检测源码模式或镜像模式
16
+ - 🔄 **平滑升级** - 一个命令完成更新(自动选择重建或拉取镜像)
15
17
  - 🎯 **全栈友好** - 命令设计贴近开发者思维
16
18
  - 📊 **实时日志** - 方便查看各服务日志
17
19
  - 💾 **数据库管理** - 内置数据库迁移和管理工具
@@ -45,206 +47,63 @@ npx nodebbs [command]
45
47
  ```bash
46
48
  npx nodebbs
47
49
  ```
48
- - **start**: 开始部署(首次使用推荐选择此项)
49
- - **rebuild**: 重新构建并启动(跳过检查,通常在代码更新后选择此项)
50
-
51
- ## 📚 命令参考
52
-
53
- #### `nodebbs start`
54
- 开始部署
55
-
56
- ```bash
57
- # 交互式启动
58
- npx nodebbs start
59
-
60
- # 指定环境启动
61
- npx nodebbs start -e production
62
-
63
- # 重新构建并启动(跳过检查)
64
- npx nodebbs start --build
65
- ```
66
-
67
- **参数**:
68
- - `-e, --env` - 部署环境(production, lowmem, basic)
69
- - `-b, --build` - 重新构建镜像并启动(跳过健康检查和初始化)
70
50
 
71
- 启动流程包含:
72
- - Docker 环境检查
73
- - 环境变量验证
74
- - 镜像构建
75
- - 服务启动
76
- - 健康检查(默认开启,使用 `--build` 跳过)
77
- - 数据库初始化(默认开启,使用 `--build` 跳过)
78
-
79
- #### `nodebbs restart`
80
- 重启所有服务(不更新镜像,支持环境选择)
81
-
82
- ```bash
83
- npx nodebbs restart
84
- npx nodebbs restart -e production
85
- ```
86
-
87
- #### `nodebbs stop`
88
- 停止服务(支持环境选择)
89
-
90
- ```bash
91
- npx nodebbs stop
92
- npx nodebbs stop -e production
93
-
94
- # 停止服务并删除数据卷(危险!)
95
- npx nodebbs stop --volumes
96
- npx nodebbs stop -v
97
- ```
98
-
99
- **参数**:
100
- - `-v, --volumes` - 同时删除数据卷
101
-
102
- #### `nodebbs status`
103
- 查看服务状态
104
-
105
- ```bash
106
- npx nodebbs status
107
- # 查看指定环境状态
108
- npx nodebbs status -e production
109
- ```
110
-
111
- ### 日志管理
112
-
113
- #### `nodebbs logs`
114
- 查看服务日志
115
-
116
- ```bash
117
- # 查看所有日志
118
- npx nodebbs logs
119
- # 查看指定环境日志
120
- npx nodebbs logs -e production
121
- ```
122
-
123
- #### `nodebbs logs:api`
124
- 查看 API 服务日志
125
-
126
- ```bash
127
- npx nodebbs logs:api
128
- ```
129
-
130
- #### `nodebbs logs:web`
131
- 查看 Web 服务日志
132
-
133
- ```bash
134
- npx nodebbs logs:web
135
- ```
136
-
137
- #### `nodebbs logs:db`
138
- 查看数据库日志
139
-
140
- ```bash
141
- npx nodebbs logs:db
142
- ```
143
-
144
- #### `nodebbs logs:redis`
145
- 查看 Redis 日志
146
-
147
- ```bash
148
- npx nodebbs logs:redis
149
- ```
150
-
151
- ### 离线部署
152
-
153
- #### `nodebbs pack`
154
- 生成离线部署包(包含镜像、配置文件和安装脚本)
155
-
156
- ```bash
157
- npx nodebbs pack
158
- npx nodebbs pack -o my-deployment.tar.gz
159
- ```
160
-
161
- **参数**:
162
- - `-o, --output` - 输出文件名 (默认: nodebbs-offline.tar.gz)
163
-
164
-
165
- ### Shell 访问
166
-
167
- #### `nodebbs shell`
168
- 进入容器 Shell (支持 api, web, db, redis)
169
-
170
- ```bash
171
- # 进入 API 容器
172
- npx nodebbs shell:api
173
- # 进入生产环境 API 容器
174
- npx nodebbs shell:api -e production
175
- ```
176
-
177
- #### `nodebbs shell:web`
178
- 进入 Web 容器
179
-
180
- ```bash
181
- npx nodebbs shell:web
182
- ```
183
-
184
- #### `nodebbs shell:db`
185
- 进入数据库(自动启动 psql)
186
-
187
- ```bash
188
- npx nodebbs shell:db
189
- ```
190
-
191
- #### `nodebbs shell:redis`
192
- 进入 Redis(自动启动 redis-cli)
193
-
194
- ```bash
195
- npx nodebbs shell:redis
196
- ```
197
-
198
- ### 数据库管理
199
-
200
- #### `nodebbs db:push`
201
- 推送数据库 schema
202
-
203
- ```bash
204
- npx nodebbs db:push
205
- ```
206
-
207
- #### `nodebbs db:seed`
208
- 初始化数据库数据
209
-
210
- ```bash
211
- npx nodebbs db:seed
212
- ```
213
-
214
- #### `nodebbs db:reset`
215
- 重置并重新初始化数据(危险!)
216
-
217
- ```bash
218
- npx nodebbs db:reset
219
- ```
220
-
221
- #### `nodebbs db:backup`
222
- 备份数据库
223
-
224
- ```bash
225
- npx nodebbs db:backup
226
- npx nodebbs db:backup -o backup.sql
227
- ```
228
-
229
- #### `nodebbs clean`
230
- 清理 Docker 缓存和残留资源
231
-
232
- ```bash
233
- # 交互式选择清理项目
234
- npx nodebbs clean
235
-
236
- # 自动清理所有(构建缓存、无用镜像、网络)
237
- npx nodebbs clean -a
238
-
239
- # 仅清理构建缓存
240
- npx nodebbs clean --cache
241
- ```
242
-
243
- ## 🎯 使用场景
51
+ - **start**: 开始部署(首次使用推荐选择此项)
52
+ - **upgrade**: 升级并重启(自动检测更新策略)
53
+
54
+ ## 📚 部署模式
55
+
56
+ CLI 会自动根据当前目录内容判断部署模式:
57
+
58
+ 1. **源码模式 (Source Mode)**
59
+ - 检测到 `package.json`。
60
+ - 行为:使用本地源码执行 `docker build` 构建镜像。
61
+ - 适用:开发环境、二次开发。
62
+
63
+ 2. **镜像模式 (Image Mode)**
64
+ - 未检测到源码。
65
+ - 行为:直接从远程仓库拉取预构建镜像。
66
+ - 适用:生产环境部署、快速体验。
67
+ - **配置**:首次启动时会提示输入镜像版本(默认为 `latest`),并自动写入 `.env`。
68
+
69
+ ## 🛠️ 常用命令
70
+
71
+ ```bash
72
+ $ nodebbs
73
+ ? 选择命令:
74
+ start 启动服务
75
+ stop 停止服务
76
+ restart 重启服务
77
+ upgrade 升级服务
78
+ status 查看服务状态
79
+ logs 查看服务日志 [+]
80
+ shell 进入容器终端 [+]
81
+ db 数据库操作 (备份, 迁移, 种子数据等) [+]
82
+ pack 生成离线部署包
83
+ clean 清理 Docker 缓存和残留资源
84
+ help 显示帮助信息
85
+ ❌ 退出
86
+ ```
87
+
88
+ #### 命令说明
89
+
90
+ | 命令 | 说明 |
91
+ |------|---------|
92
+ | **start** | 启动服务(根据当前配置环境)|
93
+ | **stop** | 停止所有服务 |
94
+ | **restart** | 重启服务(相当于 `docker compose up --force-recreate`)|
95
+ | **upgrade** | 升级服务(拉取最新 Docker 镜像或重新构建本地镜像)|
96
+ | **status** | 查看所有容器的运行状态和健康检查结果 |
97
+ | **logs** | 查看服务日志(支持选择特定服务 API/Web/DB/Redis)|
98
+ | **shell** | 进入容器终端进行调试(支持选择特定服务)|
99
+ | **db** | 数据库高级操作:<br>• 备份 (backup)<br>• 恢复 (import)<br>• 迁移 (migrate)<br>• 种子数据 (seed) |
100
+ | **pack** | 生成离线部署包(**仅限源码模式**),方便在无网环境部署 |
101
+ | **clean** | 清理工具(删除未使用镜像、容器、卷,释放磁盘空间)|
244
102
 
245
103
  ### 离线服务器部署
246
104
 
247
105
  1. **在开发机打包**:
106
+ > 注意:此命令需要在 **源码模式** 下运行(项目根目录包含 package.json)。
248
107
  ```bash
249
108
  # 生成离线包
250
109
  npx nodebbs pack
@@ -266,131 +125,29 @@ vi .env
266
125
  ./install.sh
267
126
  ```
268
127
 
269
-
270
-
271
128
  ## ⚙️ 环境配置
272
129
 
273
130
  ### 支持的环境
274
131
 
275
- - **basic** - 基础环境(仅用于测试)
276
- - **lowmem** - 低配环境(1C1G/1C2G
277
- - **production** - 生产环境(2C4G+,推荐)
132
+ - **production** - 生产环境(推荐,启用资源限制与安全配置)
133
+ - **lowmem** - 低配环境(适用于 1C2G 服务器)
134
+ - **basic** - 基础环境(测试用,无资源限制)
278
135
 
279
136
  ### 环境变量
280
137
 
281
- `.env` 文件中配置:
138
+ CLI 首次运行时会引导生成 `.env` 文件。
139
+ 在 **镜像模式** 下,会额外生成:
282
140
 
283
141
  ```env
284
- # 数据库配置
285
- POSTGRES_PASSWORD=your_secure_password
286
- POSTGRES_DB=nodebbs
287
-
288
- # Redis 配置
289
- REDIS_PASSWORD=your_redis_password
290
-
291
- # JWT 配置
292
- JWT_SECRET=your_jwt_secret
293
-
294
- # 应用配置
295
- APP_URL=http://localhost:3100
296
- API_URL=http://localhost:7100
297
-
298
- # CORS 配置
299
- CORS_ORIGIN=*
300
- ```
301
-
302
- > **提示**:可以使用 `openssl rand -hex 32` 命令生成安全的随机密钥。
303
-
304
- ### 环境持久化
305
-
306
- CLI 会自动记住您上次启动的环境:
307
-
308
- 1. 当您运行 `nodebbs start` 并选择环境(如 `production`)后,CLI 会在当前目录创建 `.nodebbs-env` 文件记录该选择。
309
- 2. 后续运行 `nodebbs logs`, `nodebbs status` 等命令时,会自动使用该环境,无需再次指定 `-e production`。
310
- 3. 运行 `nodebbs stop` 成功停止服务后,会自动删除 `.nodebbs-env` 文件。
311
-
312
- **注意**:如果您需要临时操作其他环境,仍然可以使用 `-e` 参数强制指定,例如 `nodebbs logs -e basic`。
313
-
314
- ## 🛠️ 高级用法
315
-
316
- ### 内置模板
317
-
318
- NodeBBS CLI 内置了 Docker Compose 配置文件,即使项目中没有这些文件,也可以直接使用:
319
-
320
- ```bash
321
- # 在任何目录运行
322
- npx nodebbs start
323
- ```
324
-
325
- CLI 会自动:
326
- 1. 检查当前目录是否有 `docker-compose.yml`
327
- 2. 如果没有,使用内置模板
328
- 3. 使用当前目录作为项目目录
329
-
330
- ### 自定义配置
331
-
332
- 如果需要自定义配置,在项目根目录创建:
333
- - `docker-compose.yml` - 基础配置
334
- - `docker-compose.prod.yml` - 生产环境配置
335
- - `docker-compose.lowmem.yml` - 低配环境配置
336
-
337
- CLI 会优先使用本地配置文件。
338
-
339
- ## 🐛 故障排除
340
-
341
- ### 服务启动失败
342
-
343
- ```bash
344
- # 查看日志
345
- npx nodebbs logs
346
-
347
- # 查看特定服务日志
348
- npx nodebbs logs:api
349
-
350
- # 检查服务状态
351
- npx nodebbs status
352
- ```
353
-
354
- ### 数据库连接问题
355
-
356
- ```bash
357
- # 进入数据库检查
358
- npx nodebbs shell:db
359
-
360
- # 重置数据库
361
- npx nodebbs db:reset
362
- ```
363
-
364
- ### 端口冲突
365
-
366
- 检查以下端口是否被占用:
367
- - 3100 - Web 前端
368
- - 7100 - API 服务
369
- - 5432 - PostgreSQL
370
- - 6379 - Redis
371
-
372
- ### 清理环境
373
-
374
- ```bash
375
- # 停止所有服务
376
- npx nodebbs stop
377
-
378
- # 停止并删除所有数据(危险!)
379
- npx nodebbs stop --volumes
142
+ API_IMAGE=ghcr.io/aiprojecthub/nodebbs-api:latest
143
+ WEB_IMAGE=ghcr.io/aiprojecthub/nodebbs-web:latest
380
144
  ```
381
145
 
146
+ 如需升级至特定版本,修改 `.env` 中的版本号后运行 `nodebbs upgrade` 即可。
382
147
  ## 🔗 相关链接
383
148
 
384
149
  - [NodeBBS 项目](https://github.com/aiprojecthub/nodebbs)
385
150
  - [问题反馈](https://github.com/aiprojecthub/nodebbs/issues)
386
-
387
- ## 💡 提示
388
-
389
- - 使用 `npx nodebbs --help` 查看所有可用命令
390
- - 使用 `npx nodebbs [command] --help` 查看特定命令的帮助
391
- - 所有命令都支持 `--help` 参数
392
- - 建议在生产环境使用前先在测试环境验证
393
-
394
151
  ---
395
152
 
396
153
  Made with ❤️ by NodeBBS Team
@@ -0,0 +1,9 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class DbImport extends Command {
3
+ static description: string;
4
+ static flags: {
5
+ env: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
6
+ input: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
7
+ };
8
+ run(): Promise<void>;
9
+ }
@@ -0,0 +1,115 @@
1
+ import { Command, Flags } from '@oclif/core';
2
+ import { getComposeFiles } from '../../utils/docker.js';
3
+ import { logger } from '../../utils/logger.js';
4
+ import { execa } from 'execa';
5
+ import fs from 'node:fs';
6
+ import path from 'node:path';
7
+ import dotenv from 'dotenv';
8
+ import { EnvFlag, selectEnvironment } from '../../utils/selection.js';
9
+ import { confirm, select, input } from '@inquirer/prompts';
10
+ export default class DbImport extends Command {
11
+ static description = '导入数据库 (从 SQL 文件恢复)';
12
+ static flags = {
13
+ env: EnvFlag,
14
+ input: Flags.string({
15
+ char: 'i',
16
+ description: '输入文件路径',
17
+ }),
18
+ };
19
+ async run() {
20
+ const { flags } = await this.parse(DbImport);
21
+ // 1. 选择环境
22
+ const env = await selectEnvironment(flags.env);
23
+ // 2. 确定输入文件
24
+ let inputFile = flags.input;
25
+ if (!inputFile) {
26
+ // 尝试自动查找当前目录下的 .sql 文件
27
+ const files = fs.readdirSync(process.cwd())
28
+ .filter(f => f.endsWith('.sql'))
29
+ .sort((a, b) => {
30
+ // 尝试按时间倒序 (虽然文件名可能有时间戳,但用文件修改时间更准)
31
+ const statA = fs.statSync(a);
32
+ const statB = fs.statSync(b);
33
+ return statB.mtime.getTime() - statA.mtime.getTime();
34
+ });
35
+ if (files.length > 0) {
36
+ const choices = files.map(f => ({
37
+ name: `${f} (${(fs.statSync(f).size / 1024 / 1024).toFixed(2)} MB)`,
38
+ value: f
39
+ }));
40
+ choices.push({ name: '手动输入路径', value: '__MANUAL__' });
41
+ const selection = await select({
42
+ message: '请选择导入文件:',
43
+ choices: choices,
44
+ });
45
+ if (selection === '__MANUAL__') {
46
+ inputFile = await input({ message: '请输入文件路径:' });
47
+ }
48
+ else {
49
+ inputFile = selection;
50
+ }
51
+ }
52
+ else {
53
+ inputFile = await input({ message: '未找到 SQL 文件,请输入路径:' });
54
+ }
55
+ }
56
+ // 确保绝对路径并检查是否存在
57
+ const inputPath = path.resolve(process.cwd(), inputFile);
58
+ if (!fs.existsSync(inputPath)) {
59
+ logger.error(`文件未找到: ${inputPath}`);
60
+ this.exit(1);
61
+ }
62
+ // 3. 危险操作确认
63
+ logger.warning('警告: 此操作将清空当前数据库的所有数据并从备份恢复!');
64
+ logger.warning(`目标文件: ${inputPath}`);
65
+ const isConfirmed = await confirm({
66
+ message: '确认继续?(数据丢失不可撤销)',
67
+ default: false
68
+ });
69
+ if (!isConfirmed) {
70
+ logger.info('操作已取消');
71
+ this.exit(0);
72
+ }
73
+ // 4. 获取 Compose 文件
74
+ const { files, isBuiltIn } = await getComposeFiles(env);
75
+ const composeArgs = files.flatMap(f => ['-f', f]);
76
+ if (isBuiltIn) {
77
+ composeArgs.push('--project-directory', process.cwd());
78
+ }
79
+ // 加载环境配置获取数据库信息 (用于可能的连接参数,虽然 docker exec 默认用 postgres 用户通常足够)
80
+ const envConfig = dotenv.config().parsed || {};
81
+ const dbUser = envConfig.POSTGRES_USER || 'postgres';
82
+ const dbName = envConfig.POSTGRES_DB || 'nodebbs';
83
+ const dbPassword = envConfig.POSTGRES_PASSWORD;
84
+ // 5. 执行恢复
85
+ logger.info('正在准备恢复数据库...');
86
+ try {
87
+ // 步骤 A: 重置 Schema (Drop & Create public)
88
+ // 这样做比单纯导入更干净,因为 pg_dump 默认可能不包含 DROP TABLE
89
+ logger.info('正在重置数据库 Schema...');
90
+ const resetCmd = [...composeArgs, 'exec', '-T', 'postgres', 'psql', '-U', dbUser, '-d', dbName, '-c', 'DROP SCHEMA public CASCADE; CREATE SCHEMA public;'];
91
+ // 如果有密码
92
+ const envs = process.env;
93
+ if (dbPassword)
94
+ envs.PGPASSWORD = dbPassword;
95
+ await execa('docker', ['compose', ...resetCmd], { env: envs });
96
+ logger.success('数据库 Schema 已重置');
97
+ // 步骤 B: 导入数据
98
+ logger.info(`正在导入数据 from ${path.basename(inputPath)}...`);
99
+ const importCmd = [...composeArgs, 'exec', '-T', 'postgres', 'psql', '-U', dbUser, '-d', dbName];
100
+ const subprocess = execa('docker', ['compose', ...importCmd], {
101
+ env: envs,
102
+ input: fs.createReadStream(inputPath)
103
+ });
104
+ await subprocess;
105
+ logger.success('数据库导入成功!');
106
+ }
107
+ catch (error) {
108
+ logger.error('数据库导入失败');
109
+ if (error instanceof Error) {
110
+ logger.error(error.message);
111
+ }
112
+ this.exit(1);
113
+ }
114
+ }
115
+ }