@nebula-skills/nebula-code-standards 0.1.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 +45 -0
- package/bin/cli.cjs +50 -0
- package/package.json +45 -0
- package/scripts/postinstall.cjs +18 -0
- package/skill/SKILL.md +133 -0
- package/skill/backend-standards.md +611 -0
- package/skill/boot-components-catalog.md +546 -0
- package/skill/db-standards.md +232 -0
- package/skill/framework-standards.md +610 -0
- package/skill/frontend-standards.md +310 -0
- package/skill/full-crud-example.md +608 -0
- package/skill/init-new-project.md +842 -0
- package/skill/microapp-guide.md +510 -0
- package/skill/pitfalls-checklist.md +188 -0
- package/skill/rpc-api-reference.md +313 -0
- package/skill/upgrade-decision.md +151 -0
- package/skill/workspace-overview.md +194 -0
|
@@ -0,0 +1,842 @@
|
|
|
1
|
+
# 新 Nebula 项目初始化向导
|
|
2
|
+
|
|
3
|
+
> 用户说「初始化新 nebula 项目」「按 nebula 规范起一个项目」「新建业务模块(前后端)」时,AI 进入本向导。目标:**一条指令把前后端跑起来 + Swagger 能调通 + 主应用菜单能点开子应用**。
|
|
4
|
+
>
|
|
5
|
+
> 本向导是规则文档,**不依赖任何具体业务样板项目**。生成的代码 100% 来自规则推导。
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 一、技术栈基线(强制)
|
|
10
|
+
|
|
11
|
+
生成的项目**必须**对齐这套版本,避免和现有生态不兼容:
|
|
12
|
+
|
|
13
|
+
| 技术 | 版本 | 备注 |
|
|
14
|
+
|------|------|------|
|
|
15
|
+
| JDK | `17` | 强制;用 nebula-boot 必须 JDK 17 |
|
|
16
|
+
| Gradle | `8.12`(Wrapper) | 必须通过 `gradlew` 调用,不依赖本机 Gradle |
|
|
17
|
+
| Spring Boot | `3.5.9` | 由 `nebula-boot-dependencies` BOM 管理 |
|
|
18
|
+
| Spring Cloud | `2025.0.0` | 由 BOM 管理 |
|
|
19
|
+
| MyBatis-Plus | `3.5.9` | 由 BOM 管理 |
|
|
20
|
+
| nebula-support | `0.1.22-SNAPSHOT` | 实际以最新发布版为准 |
|
|
21
|
+
| nebula-boot | `0.1.22-SNAPSHOT` | |
|
|
22
|
+
| nebula-auth | `0.1.8-SNAPSHOT` | |
|
|
23
|
+
| nebula-system | `0.2.47-SNAPSHOT` | |
|
|
24
|
+
| Vue | `3.5.x` | 前端 |
|
|
25
|
+
| Vite | `5.x` | |
|
|
26
|
+
| TypeScript | `5.5+` | |
|
|
27
|
+
| Node.js | `>= 22` | 强制 |
|
|
28
|
+
| pnpm | `>= 9` | 强制 |
|
|
29
|
+
| IceStark | `2.8.x` | 微前端 |
|
|
30
|
+
|
|
31
|
+
### IntelliJ IDEA 必备配置
|
|
32
|
+
|
|
33
|
+
向导结束时**必须**告知用户在 IDEA 中调整以下设置(否则编译会失败或行为异常):
|
|
34
|
+
|
|
35
|
+
1. **Project SDK**:`File → Project Structure → Project → SDK = 17`
|
|
36
|
+
2. **Project language level**:`17`
|
|
37
|
+
3. **Gradle JVM**:`File → Settings → Build, Execution, Deployment → Build Tools → Gradle → Gradle JVM = 17`
|
|
38
|
+
4. **Gradle build and run using**:选 `Gradle`(而非 IDEA)以保证 Wrapper 行为一致
|
|
39
|
+
5. **Java Compiler target bytecode version**:`17`
|
|
40
|
+
6. **Annotation Processing**:`File → Settings → Build, Execution, Deployment → Compiler → Annotation Processors → Enable annotation processing`(Lombok / MapStruct 必需)
|
|
41
|
+
7. **File Encoding**:`Settings → Editor → File Encodings → 全选 UTF-8 + Transparent native-to-ascii conversion ✅`
|
|
42
|
+
8. 必装插件:`Lombok` / `MapStruct Support` / `MyBatisX` / `Save Actions`(可选)
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## 二、触发关键词
|
|
47
|
+
|
|
48
|
+
以下任一关键词触发本向导:
|
|
49
|
+
|
|
50
|
+
- 「初始化 / 新建 / 起一个 nebula 项目 / 业务模块」
|
|
51
|
+
- 「按 nebula 规范创建新工程」
|
|
52
|
+
- 「一条指令把前后端跑起来」
|
|
53
|
+
- 用户指定项目名(如 `mes` / `scm` / `oa`),且当前不存在对应仓库
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## 三、向导总览
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
阶段 1:需求摸底(AskUserQuestion 7 道题)
|
|
61
|
+
↓
|
|
62
|
+
阶段 2:依赖连通性检测(Bash nc + mysql/redis-cli)
|
|
63
|
+
↓
|
|
64
|
+
阶段 3:后端骨架生成(Gradle 四层 + Application + application.yml + Flyway + Demo CRUD + 3 个必备 SPI 空实现)
|
|
65
|
+
↓
|
|
66
|
+
阶段 4:前端骨架生成(独立仓库 / monorepo 内置二选一,参考 [[microapp-guide]])
|
|
67
|
+
↓
|
|
68
|
+
阶段 5:启动验证 + 配置修改指引(Gradle 命令 + MySQL/Redis 修改位置)
|
|
69
|
+
↓
|
|
70
|
+
阶段 6:收尾交付清单(git init / 启动命令 / IDEA 配置 / 后续 TODO)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
每个阶段如遇异常(端口冲突、连接失败、文件已存在、Nexus 拉取失败),AI **必须** 用 AskUserQuestion 让用户决策,**禁止** 自行覆盖或跳过。
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## 四、阶段 1:需求摸底
|
|
78
|
+
|
|
79
|
+
按以下顺序发出 AskUserQuestion(一次发一题或合并发,但不能跳过):
|
|
80
|
+
|
|
81
|
+
### Q1:项目范围
|
|
82
|
+
- 仅后端
|
|
83
|
+
- 仅前端
|
|
84
|
+
- 前后端一起(推荐)
|
|
85
|
+
|
|
86
|
+
### Q2:项目 domain(小写英文)
|
|
87
|
+
- 用户输入示例:`mes` / `scm` / `oa`
|
|
88
|
+
- AI 自动派生(再让用户确认或自定义):
|
|
89
|
+
|
|
90
|
+
| 派生项 | 规则 | 示例(domain=mes) |
|
|
91
|
+
|--------|------|-------------------|
|
|
92
|
+
| 后端 group | `com.huida.{domain}` | `com.huida.mes` |
|
|
93
|
+
| 后端工件 | `nebula-{domain}-{api/core/starter/server}` | `nebula-mes-api/core/starter/server` |
|
|
94
|
+
| 后端端口(建议) | `80XX` 段,避开 `9010` / `8081` / `8080` | `8082` |
|
|
95
|
+
| 数据库名 | `nebula_{domain}` | `nebula_mes` |
|
|
96
|
+
| 表前缀 | `t_` | `t_demo` |
|
|
97
|
+
| 前端工件 | `nebula-{domain}-web` | `nebula-mes-web` |
|
|
98
|
+
| IceStark name | `nebula{PascalDomain}App` / `{domain}app` | `nebulaMesApp` / `mesapp` |
|
|
99
|
+
| 前端端口(建议) | `30XX` 段,避开 `3000/3001/3002` | `3004` |
|
|
100
|
+
| API 前缀 | `/nebula-{domain}` | `/nebula-mes` |
|
|
101
|
+
|
|
102
|
+
### Q3:MySQL 配置
|
|
103
|
+
- host(默认 `localhost`)
|
|
104
|
+
- port(默认 `3306`)
|
|
105
|
+
- 用户名 / 密码
|
|
106
|
+
- 数据库不存在时:自动建 / 手动建 / 跳过
|
|
107
|
+
|
|
108
|
+
### Q4:Redis 配置
|
|
109
|
+
- host / port / password / db index(默认 db=0)
|
|
110
|
+
|
|
111
|
+
### Q5:其他中间件(多选)
|
|
112
|
+
- RocketMQ / Nacos / Elasticsearch / MongoDB
|
|
113
|
+
|
|
114
|
+
> 选了什么,对应 starter 才会引入;不选可后续按需添加。
|
|
115
|
+
|
|
116
|
+
### Q6:示例 CRUD 资源名
|
|
117
|
+
- 默认 `demo`(生成 `t_demo` 表 + DemoController/Service/Mapper/VO)
|
|
118
|
+
|
|
119
|
+
### Q7:前端形态(仅 Q1 含前端时)
|
|
120
|
+
- 独立仓库(**默认**,推荐业务域)
|
|
121
|
+
- monorepo 内置(仅平台公共域推荐)
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## 五、阶段 2:依赖连通性检测
|
|
126
|
+
|
|
127
|
+
按顺序执行(每项失败时给出 3 条排查建议 + AskUserQuestion 让用户选「修复重试 / 跳过 / 改配置」):
|
|
128
|
+
|
|
129
|
+
### 5.1 内网 Nexus(最先检测,不通后面都没意义)
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
curl -s -o /dev/null -w "%{http_code}" http://10.10.1.130:8081/repository/nebula-public/
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
| 返回码 | 处理 |
|
|
136
|
+
|--------|------|
|
|
137
|
+
| `200` / `301` / `302` | ✅ 通 |
|
|
138
|
+
| `503` | ⚠️ Nexus 暂时不可用,等几分钟重试 |
|
|
139
|
+
| 连接超时 / `Connection refused` | ❌ **未连接公司内网或 VPN**,先解决网络再继续 |
|
|
140
|
+
|
|
141
|
+
**遇到任何拉不到 nebula 包的情况,第一句话必须是:**「请确认已连接公司内网或 VPN,可访问 `http://10.10.1.130:8081`,然后重试。」
|
|
142
|
+
|
|
143
|
+
### 5.2 MySQL
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
nc -z {host} {port}
|
|
147
|
+
mysql --protocol=tcp -h {host} -P {port} -u {user} -p{pw} -e 'SELECT 1' 2>&1
|
|
148
|
+
# 选了自动建库:
|
|
149
|
+
mysql --protocol=tcp -h {host} -P {port} -u {user} -p{pw} \
|
|
150
|
+
-e "CREATE DATABASE IF NOT EXISTS nebula_{domain} DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci"
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
失败排查建议:
|
|
154
|
+
1. 端口不通 → 检查 mysql 是否启动、防火墙、安全组
|
|
155
|
+
2. 账号失败 → 检查用户名密码、`mysql.user` 是否有当前 host 权限
|
|
156
|
+
3. SSL/TLS 报错 → 在 URL 加 `useSSL=false`
|
|
157
|
+
|
|
158
|
+
### 5.3 Redis
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
nc -z {host} {port}
|
|
162
|
+
redis-cli -h {host} -p {port} [-a {pw}] -n {db} ping
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### 5.4 RocketMQ / Nacos / ES / MongoDB(按 Q5 选择)
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
nc -z {host} 9876 # RocketMQ NameServer
|
|
169
|
+
nc -z {host} 8848 && curl -sf "http://{host}:8848/nacos/v1/console/health/liveness" # Nacos
|
|
170
|
+
curl -sf "http://{host}:9200" | head -20 # Elasticsearch
|
|
171
|
+
nc -z {host} 27017 # MongoDB
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
任何一项失败 **必须** 询问用户,**不要** 默认跳过。
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## 六、阶段 3:后端骨架生成
|
|
179
|
+
|
|
180
|
+
仅当 Q1 含「后端」时执行。
|
|
181
|
+
|
|
182
|
+
### 6.1 目录结构
|
|
183
|
+
|
|
184
|
+
```
|
|
185
|
+
nebula-{domain}/
|
|
186
|
+
├── settings.gradle
|
|
187
|
+
├── build.gradle # 根 build.gradle
|
|
188
|
+
├── gradle.properties # projectGroup / version / nebula 各版本
|
|
189
|
+
├── gradlew / gradlew.bat # Gradle Wrapper
|
|
190
|
+
├── gradle/wrapper/
|
|
191
|
+
│ ├── gradle-wrapper.jar
|
|
192
|
+
│ └── gradle-wrapper.properties
|
|
193
|
+
├── .gitignore # 见 §六-3-.gitignore
|
|
194
|
+
├── README.md # 启动文档
|
|
195
|
+
├── nebula-{domain}-api/
|
|
196
|
+
│ ├── build.gradle
|
|
197
|
+
│ └── src/main/java/com/huida/{domain}/{domain}/
|
|
198
|
+
│ ├── constant/{Domain}Constants.java
|
|
199
|
+
│ ├── dto/ # 跨服务 DTO
|
|
200
|
+
│ └── provider/ # RPC 接口(FeignClient)
|
|
201
|
+
├── nebula-{domain}-core/
|
|
202
|
+
│ ├── build.gradle
|
|
203
|
+
│ └── src/main/java/com/huida/{domain}/{domain}/
|
|
204
|
+
│ ├── controller/
|
|
205
|
+
│ ├── service/ + service/impl/
|
|
206
|
+
│ ├── mapper/ + mapper/ext/
|
|
207
|
+
│ ├── entity/
|
|
208
|
+
│ ├── vo/{param,resp}/
|
|
209
|
+
│ ├── convert/
|
|
210
|
+
│ ├── feign/local/ # LocalStub
|
|
211
|
+
│ └── infra/ # 必备 SPI 空实现(见 §六-4)
|
|
212
|
+
├── nebula-{domain}-starter/
|
|
213
|
+
│ ├── build.gradle
|
|
214
|
+
│ └── src/main/
|
|
215
|
+
│ ├── java/com/huida/{domain}/autoconfigure/{Domain}AutoConfiguration.java
|
|
216
|
+
│ └── resources/META-INF/spring/
|
|
217
|
+
│ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports
|
|
218
|
+
└── nebula-{domain}-server/
|
|
219
|
+
├── build.gradle
|
|
220
|
+
└── src/main/
|
|
221
|
+
├── java/com/huida/{domain}/Nebula{Domain}Application.java
|
|
222
|
+
└── resources/
|
|
223
|
+
├── application.yml
|
|
224
|
+
├── application-dev.yml
|
|
225
|
+
├── application-uat.yml
|
|
226
|
+
├── application-prod.yml
|
|
227
|
+
├── log4j2-dev.xml
|
|
228
|
+
├── log4j2-uat.xml
|
|
229
|
+
├── log4j2-prod.xml
|
|
230
|
+
├── banner.txt # 见 §六-5
|
|
231
|
+
└── db/migration/V1.0.0__init.sql
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### 6.2 关键文件模板
|
|
235
|
+
|
|
236
|
+
**`gradle.properties`**
|
|
237
|
+
```properties
|
|
238
|
+
projectGroup=com.huida.{domain}
|
|
239
|
+
projectVersion=0.1.0-SNAPSHOT
|
|
240
|
+
nebulaSupportVersion=0.1.22-SNAPSHOT
|
|
241
|
+
nebulaBootVersion=0.1.22-SNAPSHOT
|
|
242
|
+
nebulaAuthVersion=0.1.8-SNAPSHOT
|
|
243
|
+
nebulaSystemVersion=0.2.47-SNAPSHOT
|
|
244
|
+
|
|
245
|
+
org.gradle.jvmargs=-Xmx2g -Dfile.encoding=UTF-8
|
|
246
|
+
org.gradle.parallel=true
|
|
247
|
+
org.gradle.caching=true
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
**根 `build.gradle`**(关键是 Nexus 仓库 + 子项目通用依赖)
|
|
251
|
+
```gradle
|
|
252
|
+
plugins { id 'java-library' }
|
|
253
|
+
|
|
254
|
+
allprojects {
|
|
255
|
+
group = projectGroup
|
|
256
|
+
version = projectVersion
|
|
257
|
+
repositories {
|
|
258
|
+
// 公司内网 Nexus(必须连内网或 VPN 才能访问)
|
|
259
|
+
maven {
|
|
260
|
+
url 'http://10.10.1.130:8081/repository/nebula-public/'
|
|
261
|
+
allowInsecureProtocol = true
|
|
262
|
+
}
|
|
263
|
+
mavenCentral()
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
subprojects {
|
|
268
|
+
apply plugin: 'java-library'
|
|
269
|
+
java {
|
|
270
|
+
sourceCompatibility = JavaVersion.VERSION_17
|
|
271
|
+
targetCompatibility = JavaVersion.VERSION_17
|
|
272
|
+
}
|
|
273
|
+
tasks.withType(JavaCompile) {
|
|
274
|
+
options.encoding = 'UTF-8'
|
|
275
|
+
options.compilerArgs += ['-parameters']
|
|
276
|
+
}
|
|
277
|
+
dependencies {
|
|
278
|
+
api platform("com.huida.nebula:nebula-support-dependencies:${nebulaSupportVersion}")
|
|
279
|
+
api platform("com.huida.nebula.boot:nebula-boot-dependencies:${nebulaBootVersion}")
|
|
280
|
+
compileOnly 'org.projectlombok:lombok'
|
|
281
|
+
annotationProcessor 'org.projectlombok:lombok'
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
**`settings.gradle`**
|
|
287
|
+
```gradle
|
|
288
|
+
rootProject.name = 'nebula-{domain}'
|
|
289
|
+
include 'nebula-{domain}-api'
|
|
290
|
+
include 'nebula-{domain}-core'
|
|
291
|
+
include 'nebula-{domain}-starter'
|
|
292
|
+
include 'nebula-{domain}-server'
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
**`nebula-{domain}-server/build.gradle`**
|
|
296
|
+
```gradle
|
|
297
|
+
plugins {
|
|
298
|
+
id 'org.springframework.boot' version '3.5.9'
|
|
299
|
+
id 'io.spring.dependency-management' version '1.1.6'
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
dependencies {
|
|
303
|
+
api project(':nebula-{domain}-starter')
|
|
304
|
+
api "com.huida.nebula.boot:nebula-boot-starter:${nebulaBootVersion}"
|
|
305
|
+
api "com.huida.nebula.boot:nebula-boot-starter-security:${nebulaBootVersion}"
|
|
306
|
+
api "com.huida.nebula:nebula-auth-starter:${nebulaAuthVersion}"
|
|
307
|
+
api "com.huida.nebula:nebula-system-starter:${nebulaSystemVersion}"
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
bootJar { archiveFileName = "${project.name}.jar" }
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
**`Nebula{Domain}Application.java`**
|
|
314
|
+
```java
|
|
315
|
+
package com.huida.{domain};
|
|
316
|
+
|
|
317
|
+
import org.springframework.boot.SpringApplication;
|
|
318
|
+
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
|
319
|
+
import org.springframework.scheduling.annotation.EnableAsync;
|
|
320
|
+
import org.springframework.scheduling.annotation.EnableScheduling;
|
|
321
|
+
|
|
322
|
+
@SpringBootApplication(scanBasePackages = {"com.huida.{domain}", "com.huida.nebula"})
|
|
323
|
+
@EnableScheduling
|
|
324
|
+
@EnableAsync
|
|
325
|
+
public class Nebula{Domain}Application {
|
|
326
|
+
public static void main(String[] args) {
|
|
327
|
+
SpringApplication.run(Nebula{Domain}Application.class, args);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
**`application.yml`**
|
|
333
|
+
```yaml
|
|
334
|
+
spring:
|
|
335
|
+
profiles:
|
|
336
|
+
active: dev
|
|
337
|
+
application:
|
|
338
|
+
name: nebula-{domain}
|
|
339
|
+
|
|
340
|
+
server:
|
|
341
|
+
port: ${PORT:{PORT}}
|
|
342
|
+
|
|
343
|
+
logging:
|
|
344
|
+
config: classpath:log4j2-${spring.profiles.active}.xml
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
**`application-dev.yml`**
|
|
348
|
+
```yaml
|
|
349
|
+
spring:
|
|
350
|
+
datasource:
|
|
351
|
+
url: jdbc:mysql://{mysql-host}:{mysql-port}/nebula_{domain}?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
|
|
352
|
+
username: {mysql-user}
|
|
353
|
+
password: {mysql-pw}
|
|
354
|
+
driver-class-name: com.mysql.cj.jdbc.Driver
|
|
355
|
+
data:
|
|
356
|
+
redis:
|
|
357
|
+
host: {redis-host}
|
|
358
|
+
port: {redis-port}
|
|
359
|
+
password: {redis-pw}
|
|
360
|
+
database: {redis-db}
|
|
361
|
+
|
|
362
|
+
nebula:
|
|
363
|
+
flyway:
|
|
364
|
+
enabled: true
|
|
365
|
+
tenant:
|
|
366
|
+
enabled: true
|
|
367
|
+
isolation-mode: FIELD
|
|
368
|
+
swagger:
|
|
369
|
+
enabled: true
|
|
370
|
+
|
|
371
|
+
springdoc:
|
|
372
|
+
swagger-ui:
|
|
373
|
+
path: /swagger-ui.html
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
> log4j2-{dev/uat/prod}.xml 模板见 [framework-standards.md](framework-standards.md) §三-E。
|
|
377
|
+
|
|
378
|
+
### 6.3 .gitignore(项目根目录,必须)
|
|
379
|
+
|
|
380
|
+
```gitignore
|
|
381
|
+
# ---------------- Gradle ----------------
|
|
382
|
+
.gradle/
|
|
383
|
+
build/
|
|
384
|
+
!gradle/wrapper/gradle-wrapper.jar
|
|
385
|
+
gradle-app.setting
|
|
386
|
+
!**/src/main/**/build/
|
|
387
|
+
!**/src/test/**/build/
|
|
388
|
+
|
|
389
|
+
# ---------------- IDE: IntelliJ IDEA ----------------
|
|
390
|
+
.idea/
|
|
391
|
+
*.iml
|
|
392
|
+
*.iws
|
|
393
|
+
*.ipr
|
|
394
|
+
out/
|
|
395
|
+
|
|
396
|
+
# ---------------- IDE: VS Code ----------------
|
|
397
|
+
.vscode/
|
|
398
|
+
.vscode-server/
|
|
399
|
+
|
|
400
|
+
# ---------------- IDE: Eclipse ----------------
|
|
401
|
+
.classpath
|
|
402
|
+
.project
|
|
403
|
+
.settings/
|
|
404
|
+
.factorypath
|
|
405
|
+
|
|
406
|
+
# ---------------- OS ----------------
|
|
407
|
+
.DS_Store
|
|
408
|
+
Thumbs.db
|
|
409
|
+
|
|
410
|
+
# ---------------- Java ----------------
|
|
411
|
+
*.class
|
|
412
|
+
*.log
|
|
413
|
+
hs_err_pid*
|
|
414
|
+
|
|
415
|
+
# ---------------- Spring Boot ----------------
|
|
416
|
+
*.original
|
|
417
|
+
|
|
418
|
+
# ---------------- Local config / secrets ----------------
|
|
419
|
+
application-local.yml
|
|
420
|
+
application-local.yaml
|
|
421
|
+
application-local.properties
|
|
422
|
+
*.local.yml
|
|
423
|
+
.env.local
|
|
424
|
+
|
|
425
|
+
# ---------------- Logs / temp ----------------
|
|
426
|
+
logs/
|
|
427
|
+
*.log.gz
|
|
428
|
+
tmp/
|
|
429
|
+
|
|
430
|
+
# ---------------- Node (前端目录) ----------------
|
|
431
|
+
node_modules/
|
|
432
|
+
dist/
|
|
433
|
+
*.tsbuildinfo
|
|
434
|
+
.pnpm-store/
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
### 6.4 必备 SPI 空实现(`nebula-framework-task` 启动期依赖)
|
|
438
|
+
|
|
439
|
+
`nebula-framework-task` 模块定义了 3 个持久化 SPI,业务项目**必须**提供实现(哪怕空实现)才能让 task starter 起来。
|
|
440
|
+
|
|
441
|
+
放在 `nebula-{domain}-core/src/main/java/com/huida/{domain}/{domain}/infra/`:
|
|
442
|
+
|
|
443
|
+
**`DefaultApiLogRepository.java`**
|
|
444
|
+
```java
|
|
445
|
+
package com.huida.{domain}.{domain}.infra;
|
|
446
|
+
|
|
447
|
+
import com.huida.nebula.framework.task.apilog.ApiLogModel;
|
|
448
|
+
import com.huida.nebula.framework.task.apilog.ApiLogRepository;
|
|
449
|
+
import lombok.extern.slf4j.Slf4j;
|
|
450
|
+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
|
451
|
+
import org.springframework.stereotype.Component;
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* API 日志默认占位实现。
|
|
455
|
+
* 业务方按需替换为真实存储(DB / ES / 日志文件)。
|
|
456
|
+
*/
|
|
457
|
+
@Slf4j
|
|
458
|
+
@Component
|
|
459
|
+
@ConditionalOnMissingBean(ApiLogRepository.class)
|
|
460
|
+
public class DefaultApiLogRepository implements ApiLogRepository {
|
|
461
|
+
@Override
|
|
462
|
+
public void saveAsync(ApiLogModel logModel) {
|
|
463
|
+
log.debug("[ApiLog skipped] {}", logModel);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
**`DefaultTaskInstanceRepository.java`**
|
|
469
|
+
```java
|
|
470
|
+
package com.huida.{domain}.{domain}.infra;
|
|
471
|
+
|
|
472
|
+
import com.huida.nebula.framework.task.core.executor.TaskInstanceRepository;
|
|
473
|
+
import com.huida.nebula.framework.task.core.model.TaskContext;
|
|
474
|
+
import lombok.extern.slf4j.Slf4j;
|
|
475
|
+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
|
476
|
+
import org.springframework.stereotype.Component;
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* 任务实例持久化默认占位实现。
|
|
480
|
+
* 业务方启用任务调度时需实现真实持久化。
|
|
481
|
+
*/
|
|
482
|
+
@Slf4j
|
|
483
|
+
@Component
|
|
484
|
+
@ConditionalOnMissingBean(TaskInstanceRepository.class)
|
|
485
|
+
public class DefaultTaskInstanceRepository implements TaskInstanceRepository {
|
|
486
|
+
@Override public void markRunning(Long instanceId) { log.debug("[task] running id={}", instanceId); }
|
|
487
|
+
@Override public void markSuccess(Long instanceId, TaskContext ctx) { log.debug("[task] success id={} ctx={}", instanceId, ctx); }
|
|
488
|
+
@Override public void markFailed(Long instanceId, String errorMsg) { log.debug("[task] failed id={} err={}", instanceId, errorMsg); }
|
|
489
|
+
@Override public void markCancelled(Long instanceId) { log.debug("[task] cancelled id={}", instanceId); }
|
|
490
|
+
@Override public void updateProgress(Long instanceId, int progress, long successCount, long failCount) {
|
|
491
|
+
log.debug("[task] progress id={} pct={} ok={} fail={}", instanceId, progress, successCount, failCount);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
**`DefaultTaskQueueService.java`**
|
|
497
|
+
```java
|
|
498
|
+
package com.huida.{domain}.{domain}.infra;
|
|
499
|
+
|
|
500
|
+
import com.huida.nebula.framework.task.core.model.TaskMessage;
|
|
501
|
+
import com.huida.nebula.framework.task.queue.TaskQueueService;
|
|
502
|
+
import lombok.extern.slf4j.Slf4j;
|
|
503
|
+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
|
504
|
+
import org.springframework.stereotype.Component;
|
|
505
|
+
|
|
506
|
+
/**
|
|
507
|
+
* 任务队列默认占位实现:内存直投,方便本地启动。
|
|
508
|
+
* 生产环境应替换为 RocketMQ / Disruptor 实现。
|
|
509
|
+
*/
|
|
510
|
+
@Slf4j
|
|
511
|
+
@Component
|
|
512
|
+
@ConditionalOnMissingBean(TaskQueueService.class)
|
|
513
|
+
public class DefaultTaskQueueService implements TaskQueueService {
|
|
514
|
+
@Override
|
|
515
|
+
public void publish(TaskMessage message) {
|
|
516
|
+
log.debug("[task-queue] publish {}", message);
|
|
517
|
+
// 本地占位:不真投递。生产需替换为 RocketMQ / 内存直投处理器
|
|
518
|
+
}
|
|
519
|
+
@Override
|
|
520
|
+
public String queueType() {
|
|
521
|
+
return "noop";
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
> 这 3 个类**禁止** 写真实业务逻辑,只是为了让 starter 在缺少业务实现时能启动。日志级别保持 `debug`,避免污染 INFO。
|
|
527
|
+
|
|
528
|
+
### 6.5 banner.txt(项目身份标识)
|
|
529
|
+
|
|
530
|
+
`nebula-{domain}-server/src/main/resources/banner.txt`,规则:
|
|
531
|
+
|
|
532
|
+
- **禁止** 出现任何其他业务项目名(含历史样板项目名)的字眼
|
|
533
|
+
- 显示当前项目名 + 版本 + Spring Boot 版本
|
|
534
|
+
- 标题用 `Nebula {DomainUpper}`(中文项目名可加在副标题)
|
|
535
|
+
|
|
536
|
+
通用模板(按当前项目名替换):
|
|
537
|
+
|
|
538
|
+
```
|
|
539
|
+
_ _ _ _ {Domain}
|
|
540
|
+
| \ | | ___| |__ _ _| | __ _ ________________
|
|
541
|
+
| \| |/ _ \ '_ \| | | | |/ _` | {业务中文名}
|
|
542
|
+
| |\ | __/ |_) | |_| | | (_| |
|
|
543
|
+
|_| \_|\___|_.__/ \__,_|_|\__,_| v${project.version}
|
|
544
|
+
|
|
545
|
+
:: Spring Boot :: (v${spring-boot.version})
|
|
546
|
+
:: Active Profile :: ${spring.profiles.active}
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
AI 生成时**必须**把 `{Domain}` / `{业务中文名}` 替换为当前项目的对应值,不能保留任何样板字眼。
|
|
550
|
+
|
|
551
|
+
### 6.6 Flyway 建表脚本
|
|
552
|
+
|
|
553
|
+
**`V1.0.0__init.sql`**(必须含 11 公共字段 + Demo 表)
|
|
554
|
+
|
|
555
|
+
```sql
|
|
556
|
+
-- 示例资源表(11 个公共字段 + 业务字段)
|
|
557
|
+
CREATE TABLE IF NOT EXISTS t_{demoResource} (
|
|
558
|
+
id BIGINT NOT NULL COMMENT '主键',
|
|
559
|
+
tenant_id BIGINT DEFAULT NULL COMMENT '租户ID',
|
|
560
|
+
create_user_id BIGINT DEFAULT NULL COMMENT '创建人ID',
|
|
561
|
+
creator VARCHAR(128) DEFAULT NULL COMMENT '创建人',
|
|
562
|
+
create_time DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) COMMENT '创建时间',
|
|
563
|
+
modify_user_id BIGINT DEFAULT NULL COMMENT '更新人ID',
|
|
564
|
+
updater VARCHAR(128) DEFAULT NULL COMMENT '更新人',
|
|
565
|
+
modify_time DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6) COMMENT '更新时间',
|
|
566
|
+
delete_flag INT NOT NULL DEFAULT 0 COMMENT '逻辑删除(0:正常 1:已删)',
|
|
567
|
+
remark VARCHAR(500) DEFAULT NULL COMMENT '备注',
|
|
568
|
+
custom_fields TEXT DEFAULT NULL COMMENT '扩展字段(JSON)',
|
|
569
|
+
-- 业务字段
|
|
570
|
+
demo_name VARCHAR(128) NOT NULL COMMENT '名称',
|
|
571
|
+
demo_code VARCHAR(64) NOT NULL COMMENT '编码',
|
|
572
|
+
status INT NOT NULL DEFAULT 0 COMMENT '状态(0:启用 1:禁用)',
|
|
573
|
+
PRIMARY KEY (id),
|
|
574
|
+
UNIQUE KEY uk_{demoResource}_code (tenant_id, demo_code),
|
|
575
|
+
KEY idx_{demoResource}_name (demo_name)
|
|
576
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='示例资源';
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
### 6.7 Demo CRUD 完整生成
|
|
580
|
+
|
|
581
|
+
按 [full-crud-example.md](full-crud-example.md) 模板生成完整六件套:
|
|
582
|
+
|
|
583
|
+
- `entity/{Demo}DO.java`(extends BaseEntity)
|
|
584
|
+
- `mapper/{Demo}Mapper.java`(extends BaseMapper<{Demo}DO>)
|
|
585
|
+
- `mapper/ext/{Demo}MapperExt.java`(分页两段式 / 唯一性检查)
|
|
586
|
+
- `convert/{Demo}Convert.java`(MapStruct + BaseMapperConfig)
|
|
587
|
+
- `service/I{Demo}Service.java` + `service/impl/{Demo}ServiceImpl.java`
|
|
588
|
+
- `controller/{Demo}Controller.java`(POST /page、GET /{id}、POST、PUT、DELETE、PATCH /{id}/v、PATCH /{id}/x)
|
|
589
|
+
- `vo/param/{Demo}PageParamVO.java` + `{Demo}SaveParamVO.java`
|
|
590
|
+
- `vo/resp/{Demo}RespVO.java` + `{Demo}DetailVO.java`
|
|
591
|
+
|
|
592
|
+
> 不要重新发明示例代码,直接抄 [full-crud-example.md](full-crud-example.md) 并替换名字。
|
|
593
|
+
|
|
594
|
+
---
|
|
595
|
+
|
|
596
|
+
## 七、阶段 4:前端骨架生成
|
|
597
|
+
|
|
598
|
+
仅当 Q1 含「前端」时执行。Q7 决定形态。
|
|
599
|
+
|
|
600
|
+
### 7.1 独立仓库形态(默认)
|
|
601
|
+
|
|
602
|
+
**严格按 [microapp-guide.md](microapp-guide.md) §二必备文件清单 + §三关键配置详解** 逐文件生成。**禁止** 拷贝任何现有业务样板项目(含其历史业务名、banner、README 等)。
|
|
603
|
+
|
|
604
|
+
每个文件按 microapp-guide 中给出的模板写,替换以下占位符:
|
|
605
|
+
|
|
606
|
+
| 占位符 | 取值 |
|
|
607
|
+
|--------|------|
|
|
608
|
+
| `{domain}` | Q2 派生 |
|
|
609
|
+
| `{Domain}` | 首字母大写 |
|
|
610
|
+
| `{DOMAIN}` | 全大写 |
|
|
611
|
+
| `{PascalDomain}` | 同 `{Domain}` |
|
|
612
|
+
| `{PORT}` | Q2 派生(30XX 段) |
|
|
613
|
+
| `{业务中文名}` | 询问用户 |
|
|
614
|
+
| `{your-host-domain}` | 询问用户(联调线上后端域名) |
|
|
615
|
+
| `{your-gitlab-host}` | 询问用户(GitLab 域名) |
|
|
616
|
+
|
|
617
|
+
### 7.2 前端 .gitignore
|
|
618
|
+
|
|
619
|
+
```gitignore
|
|
620
|
+
node_modules/
|
|
621
|
+
dist/
|
|
622
|
+
*.tsbuildinfo
|
|
623
|
+
.pnpm-store/
|
|
624
|
+
.DS_Store
|
|
625
|
+
.idea/
|
|
626
|
+
.vscode/
|
|
627
|
+
*.log
|
|
628
|
+
.env.local
|
|
629
|
+
.env.*.local
|
|
630
|
+
src/types/auto-imports.d.ts
|
|
631
|
+
src/types/components.d.ts
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
### 7.3 monorepo 内置形态(备选)
|
|
635
|
+
|
|
636
|
+
按 [microapp-guide.md](microapp-guide.md) 同样的配置,但放进 `nebula-web/apps/nebula-web-{domain}/`,依赖改成 `workspace:*`,scripts 沿用 monorepo 根的 dev/build。
|
|
637
|
+
|
|
638
|
+
### 7.4 主应用注册
|
|
639
|
+
|
|
640
|
+
按 [microapp-guide.md](microapp-guide.md) §四执行。
|
|
641
|
+
|
|
642
|
+
---
|
|
643
|
+
|
|
644
|
+
## 八、阶段 5:启动验证 + 配置修改指引
|
|
645
|
+
|
|
646
|
+
### 8.1 启动命令(必须告诉用户)
|
|
647
|
+
|
|
648
|
+
**后端**(在 `nebula-{domain}` 根目录执行):
|
|
649
|
+
|
|
650
|
+
```bash
|
|
651
|
+
# 第一次构建(拉依赖 + 编译)—— 若挂内网/VPN,5~10 分钟
|
|
652
|
+
./gradlew clean build -x test
|
|
653
|
+
|
|
654
|
+
# 本地启动(推荐,IDE 外)
|
|
655
|
+
./gradlew :nebula-{domain}-server:bootRun
|
|
656
|
+
|
|
657
|
+
# 用 IDE 启动:右键 Nebula{Domain}Application.java → Run
|
|
658
|
+
#(IDE 启动前确认 §一-IDEA 必备配置已完成)
|
|
659
|
+
|
|
660
|
+
# 打可执行 jar
|
|
661
|
+
./gradlew :nebula-{domain}-server:bootJar
|
|
662
|
+
# 产物:nebula-{domain}-server/build/libs/nebula-{domain}-server.jar
|
|
663
|
+
java -jar nebula-{domain}-server/build/libs/nebula-{domain}-server.jar
|
|
664
|
+
```
|
|
665
|
+
|
|
666
|
+
**前端**(在 `nebula-{domain}-web` 根目录执行):
|
|
667
|
+
|
|
668
|
+
```bash
|
|
669
|
+
# 配置 GitLab token(首次必做)
|
|
670
|
+
export GITLAB_TOKEN=glpat-xxxxx
|
|
671
|
+
|
|
672
|
+
# 安装依赖
|
|
673
|
+
pnpm install
|
|
674
|
+
|
|
675
|
+
# 本地启动(本地 IP 后端)
|
|
676
|
+
pnpm dev
|
|
677
|
+
|
|
678
|
+
# 联调线上后端
|
|
679
|
+
pnpm dev:remote
|
|
680
|
+
|
|
681
|
+
# 类型检查
|
|
682
|
+
pnpm typecheck
|
|
683
|
+
|
|
684
|
+
# 构建
|
|
685
|
+
pnpm build
|
|
686
|
+
```
|
|
687
|
+
|
|
688
|
+
### 8.2 MySQL / Redis 配置修改位置(必须告诉用户)
|
|
689
|
+
|
|
690
|
+
后端项目 application 配置入口:
|
|
691
|
+
|
|
692
|
+
| 想修改的内容 | 文件路径 | 关键 key |
|
|
693
|
+
|------------|---------|---------|
|
|
694
|
+
| MySQL 连接 | `nebula-{domain}-server/src/main/resources/application-dev.yml` | `spring.datasource.url` / `username` / `password` |
|
|
695
|
+
| Redis 连接 | 同上 | `spring.data.redis.host` / `port` / `password` / `database` |
|
|
696
|
+
| 服务端口 | `application.yml` | `server.port` |
|
|
697
|
+
| 当前 profile | `application.yml` | `spring.profiles.active`(默认 `dev`) |
|
|
698
|
+
| Flyway 开关 | `application-dev.yml` | `nebula.flyway.enabled` |
|
|
699
|
+
| 多租户隔离模式 | `application-dev.yml` | `nebula.tenant.isolation-mode`(FIELD / SCHEMA / DATABASE) |
|
|
700
|
+
| Swagger 开关 | `application-dev.yml` | `nebula.swagger.enabled` |
|
|
701
|
+
| 日志级别 | `nebula-{domain}-server/src/main/resources/log4j2-dev.xml` | `<Logger level="..."/>` |
|
|
702
|
+
|
|
703
|
+
> 生产环境改 `application-prod.yml`,**永远不要**改 `application.yml` 主文件中的具体连接串。
|
|
704
|
+
|
|
705
|
+
### 8.3 启动验证(AI 自动 Bash)
|
|
706
|
+
|
|
707
|
+
```bash
|
|
708
|
+
# 后端 Swagger
|
|
709
|
+
curl -fs "http://localhost:{PORT}/v3/api-docs" > /dev/null && echo "✅ Swagger OK"
|
|
710
|
+
|
|
711
|
+
# 后端 Demo 接口(无 token 应返回 401 而非 connection refused)
|
|
712
|
+
curl -s -o /dev/null -w "%{http_code}\n" "http://localhost:{PORT}/{domain}/{demo}/1"
|
|
713
|
+
|
|
714
|
+
# 主应用
|
|
715
|
+
curl -fs "http://127.0.0.1:3000/" > /dev/null && echo "✅ 主应用 OK"
|
|
716
|
+
|
|
717
|
+
# 子应用 mount 文件
|
|
718
|
+
curl -fs "http://127.0.0.1:{frontend-PORT}/" > /dev/null && echo "✅ 子应用 OK"
|
|
719
|
+
```
|
|
720
|
+
|
|
721
|
+
### 8.4 浏览器手工验证
|
|
722
|
+
|
|
723
|
+
告知用户依次操作:
|
|
724
|
+
|
|
725
|
+
1. 打开 `http://localhost:{PORT}/swagger-ui.html` → 看到 Demo CRUD 接口列表
|
|
726
|
+
2. 打开 `http://127.0.0.1:3000/` → 登录
|
|
727
|
+
3. 菜单点击「{业务中文名}」→ 应看到子应用页面
|
|
728
|
+
|
|
729
|
+
白屏时立即查 [pitfalls-checklist.md](pitfalls-checklist.md) §G。
|
|
730
|
+
|
|
731
|
+
---
|
|
732
|
+
|
|
733
|
+
## 九、阶段 6:收尾交付清单
|
|
734
|
+
|
|
735
|
+
AI 输出给用户的最终消息必须包含以下结构(按项目情况增删):
|
|
736
|
+
|
|
737
|
+
```markdown
|
|
738
|
+
## ✅ 后端项目已创建
|
|
739
|
+
|
|
740
|
+
- 位置:`{path}/nebula-{domain}`
|
|
741
|
+
- Group:`com.huida.{domain}`
|
|
742
|
+
- 启动命令:
|
|
743
|
+
- `cd {path}/nebula-{domain} && ./gradlew :nebula-{domain}-server:bootRun`
|
|
744
|
+
- 或在 IDE 中运行 `Nebula{Domain}Application.java`
|
|
745
|
+
- Swagger:http://localhost:{PORT}/swagger-ui.html
|
|
746
|
+
- 数据库:`nebula_{domain}`(已建库,已执行 V1.0.0__init.sql)
|
|
747
|
+
- 示例资源:`t_{demo}`(CRUD 8 个接口可用)
|
|
748
|
+
- 关键技术栈:JDK 17 / Spring Boot 3.5.9 / Gradle 8.12 / MyBatis-Plus 3.5.9
|
|
749
|
+
- 依赖版本:nebula-boot=0.1.22-SNAPSHOT / nebula-auth=0.1.8-SNAPSHOT / nebula-system=0.2.47-SNAPSHOT
|
|
750
|
+
|
|
751
|
+
## ✅ 前端项目已创建
|
|
752
|
+
|
|
753
|
+
- 位置:`{path}/nebula-{domain}-web`
|
|
754
|
+
- 启动命令:
|
|
755
|
+
- `cd {path}/nebula-{domain}-web && pnpm install && pnpm dev`
|
|
756
|
+
- 端口:{frontend-PORT}
|
|
757
|
+
- 主应用菜单入口:/{domain}app
|
|
758
|
+
|
|
759
|
+
## 🔧 修改 MySQL / Redis 配置
|
|
760
|
+
|
|
761
|
+
- 开发环境:`nebula-{domain}-server/src/main/resources/application-dev.yml`
|
|
762
|
+
- 生产环境:`application-prod.yml`
|
|
763
|
+
- 服务端口:`application.yml`
|
|
764
|
+
|
|
765
|
+
## 🔧 IntelliJ IDEA 必须调整的设置
|
|
766
|
+
|
|
767
|
+
1. Project SDK = 17
|
|
768
|
+
2. Project language level = 17
|
|
769
|
+
3. Gradle JVM = 17
|
|
770
|
+
4. Annotation Processing 启用(Lombok / MapStruct 必需)
|
|
771
|
+
5. File Encoding 全 UTF-8
|
|
772
|
+
6. 必装插件:Lombok / MapStruct Support / MyBatisX
|
|
773
|
+
|
|
774
|
+
## 🌐 公司内网约束
|
|
775
|
+
|
|
776
|
+
- 拉依赖必须连公司内网或 VPN(Nexus:`http://10.10.1.130:8081/repository/nebula-public/`)
|
|
777
|
+
- 拉不到包时第一时间检查网络
|
|
778
|
+
|
|
779
|
+
## 📋 后续仍需要做
|
|
780
|
+
|
|
781
|
+
1. 在 `nebula-system` 中配置菜单 + 权限
|
|
782
|
+
2. 接入 `nebula-auth` 登录(如果独立部署)
|
|
783
|
+
3. 把 §六-4 的 3 个占位 SPI 替换为真实持久化实现(启用任务调度时)
|
|
784
|
+
4. 配置生产环境 Nginx
|
|
785
|
+
5. 配置 `deploy/build-deploy.sh` 的 `SERVER_HOST`
|
|
786
|
+
6. `git remote` 设置 + 首次 `git push`
|
|
787
|
+
```
|
|
788
|
+
|
|
789
|
+
---
|
|
790
|
+
|
|
791
|
+
## 十、阶段中决策点速查
|
|
792
|
+
|
|
793
|
+
向导执行中常见的二次询问:
|
|
794
|
+
|
|
795
|
+
| 场景 | AskUserQuestion 选项 |
|
|
796
|
+
|------|---------------------|
|
|
797
|
+
| 数据库不存在 | 自动建库 / 手动建 / 仅生成脚本不执行 |
|
|
798
|
+
| 端口冲突 | 自动 +1 探测可用端口 / 用户手动指定 / 终止流程 |
|
|
799
|
+
| 选 MQ 但本机没装 | 跳过 MQ starter / 用 docker 起 / 改用本地内存模拟 |
|
|
800
|
+
| Demo 资源名与现有冲突 | 改名 / 跳过 Demo 生成 |
|
|
801
|
+
| 已有同名项目目录 | 备份原目录 / 用新目录名 / 终止 |
|
|
802
|
+
| GITLAB_TOKEN 未设置(前端) | 引导设置 / 跳过 install / 终止 |
|
|
803
|
+
| Nexus 503 / 连不上 | **提示连公司内网或 VPN** / 重试 / 跳过 |
|
|
804
|
+
| Gradle 拉依赖超时 | 同上 / 增加超时配置 |
|
|
805
|
+
|
|
806
|
+
---
|
|
807
|
+
|
|
808
|
+
## 十一、依赖拉取异常处理
|
|
809
|
+
|
|
810
|
+
### 11.1 现象
|
|
811
|
+
|
|
812
|
+
- `Could not resolve com.huida.nebula:...`
|
|
813
|
+
- `Connection refused: /10.10.1.130:8081`
|
|
814
|
+
- `Read timed out`
|
|
815
|
+
- `503 Service Unavailable`
|
|
816
|
+
|
|
817
|
+
### 11.2 AI 处理流程
|
|
818
|
+
|
|
819
|
+
1. **第一步必须做**:用 `curl -s -o /dev/null -w "%{http_code}" http://10.10.1.130:8081/repository/nebula-public/` 检测连通性
|
|
820
|
+
2. 不通 → **明确告知用户「请确认已连接公司内网或 VPN」**
|
|
821
|
+
3. 通了仍报错 → 检查依赖版本号是否在 Nexus 实际存在
|
|
822
|
+
4. `503` → 暂时性问题,等 1~2 分钟重试;连续 503 反馈给 Nexus 管理员
|
|
823
|
+
|
|
824
|
+
**严禁**:自动替换为其他公网镜像源(如阿里云 maven 镜像)—— nebula 包不在公网仓库。
|
|
825
|
+
|
|
826
|
+
---
|
|
827
|
+
|
|
828
|
+
## 十二、本向导与其他文档的依赖关系
|
|
829
|
+
|
|
830
|
+
向导执行时大量引用:
|
|
831
|
+
|
|
832
|
+
- 后端结构 → [backend-standards.md](backend-standards.md)
|
|
833
|
+
- 后端 CRUD 模板 → [full-crud-example.md](full-crud-example.md)
|
|
834
|
+
- 后端建表规范 → [db-standards.md](db-standards.md)
|
|
835
|
+
- 框架工具与日志模板 → [framework-standards.md](framework-standards.md)
|
|
836
|
+
- Boot 组件引入 → [boot-components-catalog.md](boot-components-catalog.md)
|
|
837
|
+
- RPC 接入 auth/system → [rpc-api-reference.md](rpc-api-reference.md)
|
|
838
|
+
- 前端独立仓库样板 → [microapp-guide.md](microapp-guide.md)
|
|
839
|
+
- 前端 monorepo 子应用 → [frontend-standards.md](frontend-standards.md)
|
|
840
|
+
- 异常处理 → [pitfalls-checklist.md](pitfalls-checklist.md)
|
|
841
|
+
|
|
842
|
+
> AI 在执行向导时,对应阶段务必先读上述同 skill 内的文档,**禁止** 去本地项目源码目录验证,**禁止** 拷贝任何现有业务样板项目。
|