nodebbs 0.1.0 → 0.2.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.
@@ -3,37 +3,22 @@ services:
3
3
  postgres:
4
4
  image: postgres:16-alpine
5
5
  container_name: nodebbs-postgres
6
- restart: always
6
+ restart: unless-stopped
7
7
  environment:
8
8
  POSTGRES_USER: postgres
9
- POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
9
+ POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres_password}
10
10
  POSTGRES_DB: ${POSTGRES_DB:-nodebbs}
11
- TZ: ${TZ:-Asia/Shanghai}
11
+ TZ: Asia/Shanghai
12
12
  volumes:
13
13
  - postgres_data:/var/lib/postgresql/data
14
- # 生产环境默认不暴露数据库端口到主机,只在 Docker 网络内部访问
15
- # 如果需要外部访问 (如开发调试),可以将下面两行取消注释
16
- # ports:
17
- # - "${POSTGRES_PORT:-5432}:5432"
14
+ - ${INIT_DB_PATH:-./scripts/init-db.sql}:/docker-entrypoint-initdb.d/init.sql:ro
15
+ ports:
16
+ - "${POSTGRES_PORT:-5432}:5432"
18
17
  healthcheck:
19
18
  test: ["CMD-SHELL", "pg_isready -U postgres"]
20
- interval: 30s
21
- timeout: 10s
19
+ interval: 10s
20
+ timeout: 5s
22
21
  retries: 5
23
- start_period: 40s
24
- deploy:
25
- resources:
26
- limits:
27
- cpus: '1'
28
- memory: 512M
29
- reservations:
30
- cpus: '0.25'
31
- memory: 256M
32
- logging:
33
- driver: "json-file"
34
- options:
35
- max-size: "10m"
36
- max-file: "3"
37
22
  networks:
38
23
  - nodebbs-network
39
24
 
@@ -41,62 +26,45 @@ services:
41
26
  redis:
42
27
  image: redis:7-alpine
43
28
  container_name: nodebbs-redis
44
- restart: always
45
- command: >
46
- redis-server
47
- --requirepass ${REDIS_PASSWORD}
48
- --appendonly yes
49
- --appendfsync everysec
50
- --maxmemory 256mb
51
- --maxmemory-policy allkeys-lru
29
+ restart: unless-stopped
30
+ command: redis-server --requirepass ${REDIS_PASSWORD:-redis_password} --appendonly yes
31
+ environment:
32
+ TZ: Asia/Shanghai
52
33
  volumes:
53
34
  - redis_data:/data
54
- # 生产环境默认不暴露 Redis 端口到主机
55
- # ports:
56
- # - "${REDIS_PORT:-6379}:6379"
35
+ ports:
36
+ - "${REDIS_PORT:-6379}:6379"
57
37
  healthcheck:
58
38
  test: ["CMD", "redis-cli", "--raw", "incr", "ping"]
59
- interval: 30s
60
- timeout: 10s
39
+ interval: 10s
40
+ timeout: 5s
61
41
  retries: 5
62
- start_period: 20s
63
- deploy:
64
- resources:
65
- limits:
66
- cpus: '0.5'
67
- memory: 256M
68
- reservations:
69
- cpus: '0.1'
70
- memory: 128M
71
- logging:
72
- driver: "json-file"
73
- options:
74
- max-size: "10m"
75
- max-file: "3"
76
42
  networks:
77
43
  - nodebbs-network
78
44
 
79
45
  # API 服务
80
46
  api:
81
- image: ${API_IMAGE:-ghcr.io/aiprojecthub/nodebbs-api:latest}
47
+ build:
48
+ context: . # 从 monorepo 根目录构建(turbo prune 需要完整的 workspace)
49
+ dockerfile: apps/api/Dockerfile
82
50
  container_name: nodebbs-api
83
- restart: always
51
+ restart: unless-stopped
84
52
  environment:
85
53
  NODE_ENV: production
86
54
  APP_NAME: ${APP_NAME:-nodebbs}
87
55
  HOST: 0.0.0.0
88
56
  PORT: 7100
89
- DATABASE_URL: postgres://postgres:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-nodebbs}
90
- REDIS_URL: redis://default:${REDIS_PASSWORD}@redis:6379/0
91
- USER_CACHE_TTL: ${USER_CACHE_TTL:-300}
92
- JWT_SECRET: ${JWT_SECRET}
57
+ DATABASE_URL: postgres://postgres:${POSTGRES_PASSWORD:-postgres_password}@postgres:5432/${POSTGRES_DB:-nodebbs}
58
+ REDIS_URL: redis://default:${REDIS_PASSWORD:-redis_password}@redis:6379/0
59
+ USER_CACHE_TTL: ${USER_CACHE_TTL:-120}
60
+ JWT_SECRET: ${JWT_SECRET:-change-this-to-a-secure-random-string-in-production}
93
61
  JWT_ACCESS_TOKEN_EXPIRES_IN: ${JWT_ACCESS_TOKEN_EXPIRES_IN:-1y}
94
62
  CORS_ORIGIN: ${CORS_ORIGIN:-*}
95
63
  APP_URL: ${APP_URL:-http://localhost:3100}
96
- TZ: ${TZ:-Asia/Shanghai}
97
- NODE_OPTIONS: "--max-old-space-size=512"
64
+ TZ: Asia/Shanghai
98
65
  volumes:
99
66
  - api_uploads:/app/apps/api/uploads
67
+ - ./apps/api/src:/app/apps/api/src:ro
100
68
  ports:
101
69
  - "${API_PORT:-7100}:7100"
102
70
  depends_on:
@@ -110,35 +78,26 @@ services:
110
78
  timeout: 10s
111
79
  retries: 3
112
80
  start_period: 40s
113
- deploy:
114
- resources:
115
- limits:
116
- cpus: '1'
117
- memory: 768M
118
- reservations:
119
- cpus: '0.3'
120
- memory: 384M
121
- logging:
122
- driver: "json-file"
123
- options:
124
- max-size: "20m"
125
- max-file: "5"
126
81
  networks:
127
82
  - nodebbs-network
128
83
 
129
84
  # Web 前端服务
130
85
  web:
131
- image: ${WEB_IMAGE:-ghcr.io/aiprojecthub/nodebbs-web:latest}
86
+ build:
87
+ context: . # 从 monorepo 根目录构建(turbo prune 需要完整的 workspace)
88
+ dockerfile: apps/web/Dockerfile
89
+ args:
90
+ NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-http://localhost:7100}
91
+ NEXT_PUBLIC_APP_URL: ${NEXT_PUBLIC_APP_URL:-http://localhost:3100}
132
92
  container_name: nodebbs-web
133
- restart: always
93
+ restart: unless-stopped
134
94
  environment:
135
95
  NODE_ENV: production
136
96
  APP_NAME: ${APP_NAME:-nodebbs}
137
97
  PORT: 3100
138
98
  NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-http://localhost:7100}
139
99
  NEXT_PUBLIC_APP_URL: ${NEXT_PUBLIC_APP_URL:-http://localhost:3100}
140
- TZ: ${TZ:-Asia/Shanghai}
141
- NODE_OPTIONS: "--max-old-space-size=512"
100
+ TZ: Asia/Shanghai
142
101
  ports:
143
102
  - "${WEB_PORT:-3100}:3100"
144
103
  depends_on:
@@ -150,19 +109,6 @@ services:
150
109
  timeout: 10s
151
110
  retries: 3
152
111
  start_period: 40s
153
- deploy:
154
- resources:
155
- limits:
156
- cpus: '1'
157
- memory: 768M
158
- reservations:
159
- cpus: '0.3'
160
- memory: 384M
161
- logging:
162
- driver: "json-file"
163
- options:
164
- max-size: "20m"
165
- max-file: "5"
166
112
  networks:
167
113
  - nodebbs-network
168
114
 
@@ -179,6 +125,3 @@ volumes:
179
125
  networks:
180
126
  nodebbs-network:
181
127
  driver: bridge
182
- ipam:
183
- config:
184
- - subnet: 172.28.0.0/16
@@ -1,27 +1,13 @@
1
1
  # ========================================
2
- # NodeBBS 部署环境变量配置示例
2
+ # NodeBBS Docker Compose 环境变量配置
3
3
  # ========================================
4
4
 
5
- # ========================================
6
- # 基础配置
7
- # ========================================
8
- # 应用名称(用于 Docker 容器前缀)
5
+ # 应用名称
9
6
  APP_NAME=nodebbs
10
7
 
11
- # 部署环境 (prod, dev)
12
- NODE_ENV=production
13
-
14
- # 镜像配置
15
- # 默认为 GitHub Container Registry
16
- # 注意:使用 `nodebbs start` 时,可以选择版本 tag 覆盖此处的默认 latest tag
17
- # 如果需要固定特定版本 (如 v1.0),请修改以下配置或在部署时输入对应的 tag
18
- API_IMAGE=ghcr.io/aiprojecthub/nodebbs-api:latest
19
- WEB_IMAGE=ghcr.io/aiprojecthub/nodebbs-web:latest
20
-
21
8
  # ========================================
22
9
  # 数据库配置
23
10
  # ========================================
24
- # 务必修改为强密码!
25
11
  POSTGRES_PASSWORD=your_secure_postgres_password_here
26
12
  POSTGRES_DB=nodebbs
27
13
  POSTGRES_PORT=5432
@@ -29,7 +15,6 @@ POSTGRES_PORT=5432
29
15
  # ========================================
30
16
  # Redis 配置
31
17
  # ========================================
32
- # 务必修改为强密码!
33
18
  REDIS_PASSWORD=your_secure_redis_password_here
34
19
  REDIS_PORT=6379
35
20
 
@@ -39,8 +24,8 @@ REDIS_PORT=6379
39
24
  API_PORT=7100
40
25
 
41
26
  # 用户缓存 TTL(秒)
42
- # 生产环境建议: 120-300
43
- USER_CACHE_TTL=300
27
+ # 开发环境: 30-60, 生产环境: 120-300
28
+ USER_CACHE_TTL=120
44
29
 
45
30
  # JWT 配置
46
31
  # 使用 `openssl rand -base64 32` 生成安全的密钥
@@ -52,7 +37,6 @@ JWT_ACCESS_TOKEN_EXPIRES_IN=1y
52
37
  CORS_ORIGIN=*
53
38
 
54
39
  # 应用 URL(OAuth 回调使用)
55
- # 生产环境请修改为公网域名
56
40
  APP_URL=http://localhost:3100
57
41
 
58
42
  # ========================================
@@ -61,16 +45,17 @@ APP_URL=http://localhost:3100
61
45
  WEB_PORT=3100
62
46
 
63
47
  # API 地址(公网访问地址)
64
- # 生产环境请修改为公网域名,例如: https://api.yourdomain.com
65
- # 或者是 Nginx 反向代理后的地址,例如: https://yourdomain.com/api
66
- NEXT_PUBLIC_API_URL=http://localhost:7100
48
+ # 使用 docker 部署必须指定 IP 或域名(避免SSR跨容器通信问题)
49
+ # 开发环境: http://192.168.0.100:7100
50
+ # 生产环境: https://api.yourdomain.com
51
+ NEXT_PUBLIC_API_URL=http://192.168.0.100:7100
67
52
 
68
53
  # 应用 URL(公网访问地址)
69
- # 生产环境请修改为公网域名,例如: https://yourdomain.com
54
+ # 开发环境: http://localhost:3100
55
+ # 生产环境: https://yourdomain.com
70
56
  NEXT_PUBLIC_APP_URL=http://localhost:3100
71
57
 
72
58
  # ========================================
73
- # 其他配置
59
+ # 时区配置
74
60
  # ========================================
75
- # 时区
76
61
  TZ=Asia/Shanghai
@@ -0,0 +1,14 @@
1
+ -- PostgreSQL 初始化脚本
2
+ -- 这个脚本会在数据库首次创建时执行
3
+
4
+ -- 创建扩展(如果需要)
5
+ -- CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
6
+ -- CREATE EXTENSION IF NOT EXISTS "pg_trgm";
7
+
8
+ -- 设置时区
9
+ SET timezone = 'Asia/Shanghai';
10
+
11
+ -- 数据库已由 POSTGRES_DB 环境变量创建
12
+ -- 这里可以添加其他初始化 SQL
13
+
14
+ \echo '数据库初始化完成'
@@ -5,7 +5,7 @@
5
5
  * - 如果存在,则优先使用项目根目录的配置。
6
6
  * - 如果不存在,则使用 CLI 内置的模板文件。
7
7
  *
8
- * @param env - 运行环境 ('production' | 'lowmem')
8
+ * @param env - 运行环境 ('production' | 'lowmem' | 'basic')
9
9
  * @returns 对象包含文件路径数组和是否使用内置模板的标志
10
10
  */
11
11
  export declare function getComposeFiles(env: string): Promise<{
@@ -12,7 +12,7 @@ const fileExists = promisify(exists);
12
12
  * - 如果存在,则优先使用项目根目录的配置。
13
13
  * - 如果不存在,则使用 CLI 内置的模板文件。
14
14
  *
15
- * @param env - 运行环境 ('production' | 'lowmem')
15
+ * @param env - 运行环境 ('production' | 'lowmem' | 'basic')
16
16
  * @returns 对象包含文件路径数组和是否使用内置模板的标志
17
17
  */
18
18
  export async function getComposeFiles(env) {
@@ -29,7 +29,7 @@ export async function getComposeFiles(env) {
29
29
  }
30
30
  const files = [baseFile];
31
31
  if (env === 'production') {
32
- // Production now uses the default file (merged config)
32
+ files.push(path.join(templateDir, 'docker-compose.prod.yml'));
33
33
  }
34
34
  else if (env === 'lowmem') {
35
35
  files.push(path.join(templateDir, 'docker-compose.lowmem.yml'));
@@ -68,6 +68,9 @@ export async function runCompose(files, args, isBuiltIn = false) {
68
68
  const composeArgs = files.flatMap(f => ['-f', f]);
69
69
  if (isBuiltIn) {
70
70
  composeArgs.push('--project-directory', process.cwd());
71
+ // 将 INIT_DB_PATH 设置为内置 sql 文件
72
+ const templateDir = path.dirname(files[0]);
73
+ process.env.INIT_DB_PATH = path.join(templateDir, 'init-db.sql');
71
74
  }
72
75
  composeArgs.push(...args);
73
76
  // 使用 stdio: 'inherit' 实时显示输出
@@ -1,2 +1,2 @@
1
1
  export declare function initEnv(): Promise<void>;
2
- export declare function checkEnv(envType: 'production' | 'lowmem'): Promise<void>;
2
+ export declare function checkEnv(envType: 'production' | 'lowmem' | 'basic'): Promise<void>;
@@ -1,4 +1,4 @@
1
- export type EnvType = 'production' | 'lowmem';
1
+ export type EnvType = 'production' | 'lowmem' | 'basic';
2
2
  export declare const EnvFlag: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
3
3
  export declare function setStoredEnv(env: EnvType): Promise<void>;
4
4
  export declare function clearStoredEnv(): Promise<void>;
@@ -6,14 +6,14 @@ import path from 'node:path';
6
6
  const ENV_MARKER_FILE = '.env.lock';
7
7
  export const EnvFlag = Flags.string({
8
8
  char: 'e',
9
- description: '部署环境 (production, lowmem)',
10
- options: ['production', 'lowmem'],
9
+ description: '部署环境 (production, lowmem, basic)',
10
+ options: ['production', 'lowmem', 'basic'],
11
11
  });
12
12
  async function getStoredEnv() {
13
13
  try {
14
14
  const content = await fs.readFile(path.resolve(process.cwd(), ENV_MARKER_FILE), 'utf-8');
15
15
  const env = content.trim();
16
- if (['production', 'lowmem'].includes(env)) {
16
+ if (['production', 'lowmem', 'basic'].includes(env)) {
17
17
  return env;
18
18
  }
19
19
  }
@@ -51,8 +51,9 @@ export async function selectEnvironment(env, options = {}) {
51
51
  const selected = await select({
52
52
  message: options.prompt || '请选择运行环境:',
53
53
  choices: [
54
- { name: '标准环境 (推荐)', value: 'production' },
55
- { name: '低配环境 (1C1G)', value: 'lowmem' },
54
+ { name: '标准生产环境 (2C4G+) [推荐]', value: 'production' },
55
+ { name: '低配环境 (1C1G/1C2G)', value: 'lowmem' },
56
+ { name: '基础环境 (仅用于测试)', value: 'basic' },
56
57
  { name: '❌ 取消', value: '__CANCEL__' },
57
58
  ],
58
59
  loop: true,