@llryiop/avatar-boot-cli 1.0.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 +309 -0
- package/bin/cli.js +3 -0
- package/docs/plans/2026-03-12-avatar-boot-cli-design.md +73 -0
- package/docs/plans/2026-03-12-avatar-boot-cli-plan.md +681 -0
- package/package.json +28 -0
- package/src/index.js +78 -0
- package/src/prompts.js +78 -0
- package/src/template.js +37 -0
- package/src/transform.js +172 -0
- package/src/utils.js +34 -0
- package/templates/.claude/rules/architecture-redlines.md +146 -0
- package/templates/.claude/rules/code-review-standards.md +137 -0
- package/templates/.claude/rules/coding-standards.md +56 -0
- package/templates/.claude/rules/git-commit.md +59 -0
- package/templates/.claude/rules/layered-architecture.md +201 -0
- package/templates/.claude/rules/mybatis-plus.md +263 -0
- package/templates/.claude/rules/tech-stack.md +41 -0
- package/templates/.claude/rules/version.md +467 -0
- package/templates/.claude/settings.local.json +18 -0
- package/templates/.claude/skills/ai-tool-guide/SKILL.md +314 -0
- package/templates/.claude/skills/api-design/SKILL.md +200 -0
- package/templates/.claude/skills/api-doc-generator/SKILL.md +380 -0
- package/templates/.claude/skills/api-service-module-creator/SKILL.md +1114 -0
- package/templates/.claude/skills/avatar-boot-starter-feign/SKILL.md +243 -0
- package/templates/.claude/skills/avatar-boot-starter-job/SKILL.md +437 -0
- package/templates/.claude/skills/avatar-boot-starter-kafka/SKILL.md +580 -0
- package/templates/.claude/skills/avatar-boot-starter-mysql/SKILL.md +572 -0
- package/templates/.claude/skills/avatar-boot-starter-nacos/SKILL.md +901 -0
- package/templates/.claude/skills/avatar-boot-starter-oss/SKILL.md +594 -0
- package/templates/.claude/skills/avatar-boot-starter-redis/SKILL.md +586 -0
- package/templates/.claude/skills/avatar-boot-starter-rocketmq/SKILL.md +662 -0
- package/templates/.claude/skills/avatar-boot-starter-web/SKILL.md +1007 -0
- package/templates/.claude/skills/changelog-generator/SKILL.md +114 -0
- package/templates/.claude/skills/code-review/SKILL.md +239 -0
- package/templates/.claude/skills/crud-generator/SKILL.md +824 -0
- package/templates/.claude/skills/database-design/SKILL.md +377 -0
- package/templates/.claude/skills/deployment-config/SKILL.md +277 -0
- package/templates/.claude/skills/incident-analysis/SKILL.md +241 -0
- package/templates/.claude/skills/integration-test-generator/SKILL.md +496 -0
- package/templates/.claude/skills/prompt-engineering/SKILL.md +249 -0
- package/templates/.claude/skills/requirement-management/SKILL.md +244 -0
- package/templates/.claude/skills/security-audit/SKILL.md +330 -0
- package/templates/.claude/skills/test-case-design/SKILL.md +257 -0
- package/templates/.claude/skills/testing-workflow/SKILL.md +68 -0
- package/templates/.claude/skills/troubleshooting/SKILL.md +240 -0
- package/templates/CLAUDE.md +173 -0
- package/templates/README.md +303 -0
- package/templates/avatar-scaffold-api/pom.xml +41 -0
- package/templates/avatar-scaffold-api/src/main/java/com/iflytek/avatar/login/api/LoginFeignClient.java +40 -0
- package/templates/avatar-scaffold-api/src/main/java/com/iflytek/avatar/login/constant/LoginConstant.java +21 -0
- package/templates/avatar-scaffold-api/src/main/java/com/iflytek/avatar/login/dto/request/LoginRequest.java +17 -0
- package/templates/avatar-scaffold-api/src/main/java/com/iflytek/avatar/login/dto/request/RefreshTokenRequest.java +14 -0
- package/templates/avatar-scaffold-api/src/main/java/com/iflytek/avatar/login/dto/response/LoginResponse.java +31 -0
- package/templates/avatar-scaffold-api/src/main/java/com/iflytek/avatar/login/dto/response/TokenInfoResponse.java +25 -0
- package/templates/avatar-scaffold-api/src/main/java/com/iflytek/avatar/login/enums/LoginTypeEnum.java +23 -0
- package/templates/avatar-scaffold-api/src/main/java/com/iflytek/avatar/login/exception/LoginException.java +23 -0
- package/templates/avatar-scaffold-service/k8s-app/Dockerfile +14 -0
- package/templates/avatar-scaffold-service/k8s-app/Dockerfile-arm64 +14 -0
- package/templates/avatar-scaffold-service/packaging/assembly.xml +16 -0
- package/templates/avatar-scaffold-service/pom.xml +150 -0
- package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/Application.java +21 -0
- package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/login/config/LoginConfig.java +20 -0
- package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/login/controller/LoginController.java +37 -0
- package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/login/converter/LoginConverter.java +54 -0
- package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/login/feign/DemoFeign.java +21 -0
- package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/login/repository/entity/UserLoginEntity.java +33 -0
- package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/login/repository/entity/UserTokenEntity.java +39 -0
- package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/login/repository/mapper/UserLoginMapper.java +20 -0
- package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/login/service/LoginService.java +22 -0
- package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/login/service/impl/LoginServiceImpl.java +43 -0
- package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/login/utils/LoginUtils.java +31 -0
- package/templates/avatar-scaffold-service/src/main/resources/application-dev.yaml +29 -0
- package/templates/avatar-scaffold-service/src/main/resources/application-local.yaml +61 -0
- package/templates/avatar-scaffold-service/src/main/resources/application-prod.yaml +28 -0
- package/templates/avatar-scaffold-service/src/main/resources/application-test.yaml +28 -0
- package/templates/avatar-scaffold-service/src/main/resources/application.yaml +12 -0
- package/templates/pom.xml +98 -0
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: database-design
|
|
3
|
+
description: |
|
|
4
|
+
根据业务需求生成数据库表 DDL 和索引建议,遵循项目数据库设计规范。
|
|
5
|
+
触发词: database design, table design, DDL, schema, ER, 数据库设计, 表设计, 建表
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# 数据库设计技能 (Database Design Skill)
|
|
9
|
+
|
|
10
|
+
## 概述
|
|
11
|
+
|
|
12
|
+
本技能根据业务需求描述,生成符合 Avatar Boot 项目规范的数据库表 DDL、索引设计和优化建议。输出可直接用于 CRUD 代码生成。
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## 输入要求
|
|
17
|
+
|
|
18
|
+
提供业务需求描述,例如:
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
设计一个订单管理系统,需要管理:
|
|
22
|
+
- 订单信息:订单号、用户ID、订单金额、订单状态、备注
|
|
23
|
+
- 订单商品明细:关联订单、商品ID、商品名称、数量、单价、小计
|
|
24
|
+
- 订单状态包括:待支付、已支付、已发货、已完成、已取消
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 输出内容
|
|
30
|
+
|
|
31
|
+
1. **DDL 建表语句** — 完整的 CREATE TABLE 语句
|
|
32
|
+
2. **索引建议** — 索引设计及理由
|
|
33
|
+
3. **设计说明** — 关键设计决策的说明
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## 命名规范
|
|
38
|
+
|
|
39
|
+
### 表命名
|
|
40
|
+
|
|
41
|
+
| 规则 | 说明 | 正确示例 | 错误示例 |
|
|
42
|
+
|------|------|----------|----------|
|
|
43
|
+
| snake_case 全小写 | 统一使用下划线分隔 | `t_user_order` | `T_UserOrder`, `tUserOrder` |
|
|
44
|
+
| 模块前缀 `t_` | 所有业务表以 `t_` 开头 | `t_user` | `user`, `tb_user` |
|
|
45
|
+
| 有意义的英文名词 | 清晰表达表的业务含义 | `t_order_item` | `t_oi`, `t_table1` |
|
|
46
|
+
| 关联表命名 | 两个实体名拼接 | `t_user_role` | `t_ur` |
|
|
47
|
+
|
|
48
|
+
### 字段命名
|
|
49
|
+
|
|
50
|
+
| 规则 | 说明 | 正确示例 | 错误示例 |
|
|
51
|
+
|------|------|----------|----------|
|
|
52
|
+
| snake_case 全小写 | 统一使用下划线分隔 | `user_name` | `userName`, `UserName` |
|
|
53
|
+
| 布尔字段 `is_` 前缀 | 表示是否的字段 | `is_deleted`, `is_active` | `deleted`, `active` |
|
|
54
|
+
| 时间字段 `_time` 后缀 | 表示时间的字段 | `create_time`, `pay_time` | `created`, `payDate` |
|
|
55
|
+
| 状态字段 `status` | 表示状态的字段 | `order_status` | `order_state`, `sts` |
|
|
56
|
+
| 外键字段 `_id` 后缀 | 引用其他表主键 | `user_id`, `order_id` | `user`, `fk_user` |
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## 必需字段
|
|
61
|
+
|
|
62
|
+
每张业务表必须包含以下四个字段:
|
|
63
|
+
|
|
64
|
+
```sql
|
|
65
|
+
-- 主键:BIGINT 类型,雪花算法生成,不自增
|
|
66
|
+
id BIGINT NOT NULL COMMENT '主键ID',
|
|
67
|
+
|
|
68
|
+
-- 创建时间:记录数据创建时间
|
|
69
|
+
create_time DATETIME NOT NULL COMMENT '创建时间',
|
|
70
|
+
|
|
71
|
+
-- 更新时间:记录数据最后更新时间
|
|
72
|
+
update_time DATETIME NOT NULL COMMENT '更新时间',
|
|
73
|
+
|
|
74
|
+
-- 逻辑删除:0-未删除 1-已删除,不做物理删除
|
|
75
|
+
is_deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除:0-未删除 1-已删除',
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
> 注意:`id` 使用 BIGINT 而非 AUTO_INCREMENT,由应用层(MyBatis Plus ASSIGN_ID)生成雪花 ID。
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## 数据类型指南
|
|
83
|
+
|
|
84
|
+
### 类型选择原则
|
|
85
|
+
|
|
86
|
+
| 场景 | 推荐类型 | 说明 |
|
|
87
|
+
|------|----------|------|
|
|
88
|
+
| 主键、外键 | `BIGINT` | 统一使用 BIGINT,兼容雪花 ID |
|
|
89
|
+
| 短文本(名称、标题) | `VARCHAR(n)` | 明确指定长度,n ≤ 255 |
|
|
90
|
+
| 长文本(描述、备注) | `VARCHAR(n)` 或 `TEXT` | 长度可预估用 VARCHAR,不可预估用 TEXT |
|
|
91
|
+
| 超长文本(文章内容) | `TEXT` / `LONGTEXT` | 仅在必要时使用 |
|
|
92
|
+
| 金额、价格 | `DECIMAL(p, s)` | 禁止使用 FLOAT / DOUBLE,推荐 DECIMAL(10, 2) |
|
|
93
|
+
| 整数计数 | `INT` | 一般场景 |
|
|
94
|
+
| 小整数(状态、类型) | `TINYINT` | 0-127 范围的枚举值 |
|
|
95
|
+
| 日期时间 | `DATETIME` | 不使用 TIMESTAMP(2038 年问题) |
|
|
96
|
+
| 仅日期 | `DATE` | 如生日、有效日期 |
|
|
97
|
+
| 布尔值 | `TINYINT` | 0 和 1,不使用 BIT |
|
|
98
|
+
| JSON 数据 | `JSON` | MySQL 5.7+ 支持,需要 JSON 查询时使用 |
|
|
99
|
+
| 大字段(图片、文件) | 不存库 | 存储到对象存储(OSS),数据库只存 URL |
|
|
100
|
+
|
|
101
|
+
### 字段长度建议
|
|
102
|
+
|
|
103
|
+
| 字段类型 | 推荐长度 | 说明 |
|
|
104
|
+
|----------|----------|------|
|
|
105
|
+
| 用户名 | VARCHAR(64) | |
|
|
106
|
+
| 手机号 | VARCHAR(20) | 预留国际号码长度 |
|
|
107
|
+
| 邮箱 | VARCHAR(128) | |
|
|
108
|
+
| URL | VARCHAR(512) | |
|
|
109
|
+
| IP 地址 | VARCHAR(45) | 兼容 IPv6 |
|
|
110
|
+
| 标题 | VARCHAR(200) | |
|
|
111
|
+
| 备注/描述 | VARCHAR(500) | |
|
|
112
|
+
| 订单号 | VARCHAR(32) | |
|
|
113
|
+
| 密码哈希 | VARCHAR(128) | BCrypt 等哈希结果 |
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## 索引设计原则
|
|
118
|
+
|
|
119
|
+
### 索引类型
|
|
120
|
+
|
|
121
|
+
| 索引类型 | 使用场景 | DDL 语法 |
|
|
122
|
+
|----------|----------|----------|
|
|
123
|
+
| 主键索引 | 每表必须有 | `PRIMARY KEY (id)` |
|
|
124
|
+
| 唯一索引 | 业务唯一约束 | `UNIQUE KEY uk_xxx (col)` |
|
|
125
|
+
| 普通索引 | 高频查询条件 | `KEY idx_xxx (col)` |
|
|
126
|
+
| 组合索引 | 多条件联合查询 | `KEY idx_xxx (col1, col2)` |
|
|
127
|
+
|
|
128
|
+
### 索引命名规范
|
|
129
|
+
|
|
130
|
+
| 索引类型 | 前缀 | 示例 |
|
|
131
|
+
|----------|------|------|
|
|
132
|
+
| 主键 | `pk_` | `PRIMARY KEY (id)` |
|
|
133
|
+
| 唯一索引 | `uk_` | `UNIQUE KEY uk_username (username)` |
|
|
134
|
+
| 普通索引 | `idx_` | `KEY idx_user_id (user_id)` |
|
|
135
|
+
| 组合索引 | `idx_` | `KEY idx_status_create_time (status, create_time)` |
|
|
136
|
+
|
|
137
|
+
### 组合索引最左前缀原则
|
|
138
|
+
|
|
139
|
+
组合索引 `(a, b, c)` 可以满足以下查询:
|
|
140
|
+
- `WHERE a = ?` — 命中
|
|
141
|
+
- `WHERE a = ? AND b = ?` — 命中
|
|
142
|
+
- `WHERE a = ? AND b = ? AND c = ?` — 命中
|
|
143
|
+
- `WHERE b = ?` — 不命中
|
|
144
|
+
- `WHERE b = ? AND c = ?` — 不命中
|
|
145
|
+
|
|
146
|
+
设计组合索引时,将区分度高的列放在前面。
|
|
147
|
+
|
|
148
|
+
### 覆盖索引
|
|
149
|
+
|
|
150
|
+
当查询的所有字段都在索引中时,MySQL 可以直接从索引中读取数据,无需回表:
|
|
151
|
+
|
|
152
|
+
```sql
|
|
153
|
+
-- 索引: idx_status_create_time (status, create_time)
|
|
154
|
+
-- 覆盖索引查询(只查索引中的字段)
|
|
155
|
+
SELECT status, create_time FROM t_order WHERE status = 1;
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### 索引设计建议
|
|
159
|
+
|
|
160
|
+
1. **高频查询条件**必须建索引(WHERE、JOIN 条件)
|
|
161
|
+
2. **区分度低的字段**不建议单独建索引(如 `status` 只有几个值)
|
|
162
|
+
3. **区分度低 + 高频**可组合其他字段建联合索引
|
|
163
|
+
4. 单表索引数量建议不超过 **5 个**
|
|
164
|
+
5. 索引字段总长度建议不超过 **256 字节**
|
|
165
|
+
6. **频繁更新的字段**不建议建索引
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## 外键设计
|
|
170
|
+
|
|
171
|
+
### 逻辑外键(推荐)
|
|
172
|
+
|
|
173
|
+
使用逻辑外键,不创建物理外键约束:
|
|
174
|
+
|
|
175
|
+
```sql
|
|
176
|
+
-- 推荐:逻辑外键,不添加 FOREIGN KEY 约束
|
|
177
|
+
CREATE TABLE t_order_item (
|
|
178
|
+
id BIGINT NOT NULL COMMENT '主键ID',
|
|
179
|
+
order_id BIGINT NOT NULL COMMENT '订单ID', -- 逻辑外键
|
|
180
|
+
product_id BIGINT NOT NULL COMMENT '商品ID', -- 逻辑外键
|
|
181
|
+
...
|
|
182
|
+
PRIMARY KEY (id),
|
|
183
|
+
KEY idx_order_id (order_id)
|
|
184
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单商品明细表';
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### 物理外键(禁止)
|
|
188
|
+
|
|
189
|
+
```sql
|
|
190
|
+
-- 禁止:物理外键约束,影响性能和运维
|
|
191
|
+
FOREIGN KEY (order_id) REFERENCES t_order(id)
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
**原因**:
|
|
195
|
+
- 物理外键影响数据库写入性能
|
|
196
|
+
- 增加数据库运维复杂度(数据迁移、分库分表受限)
|
|
197
|
+
- 级联操作可能导致意外的数据变更
|
|
198
|
+
- 数据完整性由应用层保证
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## 大表分区策略
|
|
203
|
+
|
|
204
|
+
当预估单表数据量超过 **500 万行**时,考虑分区或分表:
|
|
205
|
+
|
|
206
|
+
### 时间范围分区
|
|
207
|
+
|
|
208
|
+
适用于日志表、流水表等按时间增长的数据:
|
|
209
|
+
|
|
210
|
+
```sql
|
|
211
|
+
CREATE TABLE t_operation_log (
|
|
212
|
+
id BIGINT NOT NULL COMMENT '主键ID',
|
|
213
|
+
operation_type VARCHAR(32) NOT NULL COMMENT '操作类型',
|
|
214
|
+
content TEXT COMMENT '操作内容',
|
|
215
|
+
create_time DATETIME NOT NULL COMMENT '创建时间',
|
|
216
|
+
PRIMARY KEY (id, create_time)
|
|
217
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='操作日志表'
|
|
218
|
+
PARTITION BY RANGE (TO_DAYS(create_time)) (
|
|
219
|
+
PARTITION p202601 VALUES LESS THAN (TO_DAYS('2026-02-01')),
|
|
220
|
+
PARTITION p202602 VALUES LESS THAN (TO_DAYS('2026-03-01')),
|
|
221
|
+
PARTITION p202603 VALUES LESS THAN (TO_DAYS('2026-04-01')),
|
|
222
|
+
PARTITION pmax VALUES LESS THAN MAXVALUE
|
|
223
|
+
);
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### 分表建议
|
|
227
|
+
|
|
228
|
+
当分区无法满足需求时,考虑按业务维度分表:
|
|
229
|
+
|
|
230
|
+
- **按用户 ID 取模分表**:`t_order_00` ~ `t_order_15`
|
|
231
|
+
- **按时间分表**:`t_order_202601` ~ `t_order_202612`
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## DDL 完整示例
|
|
236
|
+
|
|
237
|
+
以订单系统为例:
|
|
238
|
+
|
|
239
|
+
```sql
|
|
240
|
+
-- ----------------------------
|
|
241
|
+
-- 订单表
|
|
242
|
+
-- ----------------------------
|
|
243
|
+
CREATE TABLE t_order (
|
|
244
|
+
id BIGINT NOT NULL COMMENT '主键ID',
|
|
245
|
+
order_no VARCHAR(32) NOT NULL COMMENT '订单号',
|
|
246
|
+
user_id BIGINT NOT NULL COMMENT '用户ID',
|
|
247
|
+
total_amount DECIMAL(10, 2) NOT NULL DEFAULT 0.00 COMMENT '订单总金额',
|
|
248
|
+
order_status TINYINT NOT NULL DEFAULT 0 COMMENT '订单状态:0-待支付 1-已支付 2-已发货 3-已完成 4-已取消',
|
|
249
|
+
remark VARCHAR(500) DEFAULT NULL COMMENT '备注',
|
|
250
|
+
pay_time DATETIME DEFAULT NULL COMMENT '支付时间',
|
|
251
|
+
create_time DATETIME NOT NULL COMMENT '创建时间',
|
|
252
|
+
update_time DATETIME NOT NULL COMMENT '更新时间',
|
|
253
|
+
is_deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除:0-未删除 1-已删除',
|
|
254
|
+
PRIMARY KEY (id),
|
|
255
|
+
UNIQUE KEY uk_order_no (order_no),
|
|
256
|
+
KEY idx_user_id (user_id),
|
|
257
|
+
KEY idx_status_create_time (order_status, create_time)
|
|
258
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单表';
|
|
259
|
+
|
|
260
|
+
-- ----------------------------
|
|
261
|
+
-- 订单商品明细表
|
|
262
|
+
-- ----------------------------
|
|
263
|
+
CREATE TABLE t_order_item (
|
|
264
|
+
id BIGINT NOT NULL COMMENT '主键ID',
|
|
265
|
+
order_id BIGINT NOT NULL COMMENT '订单ID',
|
|
266
|
+
product_id BIGINT NOT NULL COMMENT '商品ID',
|
|
267
|
+
product_name VARCHAR(200) NOT NULL COMMENT '商品名称',
|
|
268
|
+
quantity INT NOT NULL DEFAULT 1 COMMENT '数量',
|
|
269
|
+
unit_price DECIMAL(10, 2) NOT NULL COMMENT '单价',
|
|
270
|
+
subtotal DECIMAL(10, 2) NOT NULL COMMENT '小计',
|
|
271
|
+
create_time DATETIME NOT NULL COMMENT '创建时间',
|
|
272
|
+
update_time DATETIME NOT NULL COMMENT '更新时间',
|
|
273
|
+
is_deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除:0-未删除 1-已删除',
|
|
274
|
+
PRIMARY KEY (id),
|
|
275
|
+
KEY idx_order_id (order_id),
|
|
276
|
+
KEY idx_product_id (product_id)
|
|
277
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单商品明细表';
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
## 审查清单
|
|
283
|
+
|
|
284
|
+
设计完成后,按以下清单逐项检查:
|
|
285
|
+
|
|
286
|
+
### 表结构审查
|
|
287
|
+
|
|
288
|
+
- [ ] 表名符合 `t_模块_实体` 命名规范
|
|
289
|
+
- [ ] 字段名符合 snake_case 命名规范
|
|
290
|
+
- [ ] 包含 `id`, `create_time`, `update_time`, `is_deleted` 四个必需字段
|
|
291
|
+
- [ ] `id` 使用 `BIGINT NOT NULL`,不自增
|
|
292
|
+
- [ ] 每个字段都有 `COMMENT` 注释
|
|
293
|
+
- [ ] 字段类型选择合理(金额用 DECIMAL,时间用 DATETIME)
|
|
294
|
+
- [ ] VARCHAR 长度合理,不过大也不过小
|
|
295
|
+
- [ ] NOT NULL / DEFAULT 约束合理
|
|
296
|
+
- [ ] 表有 `COMMENT` 注释
|
|
297
|
+
- [ ] 字符集使用 `utf8mb4`
|
|
298
|
+
|
|
299
|
+
### 索引审查
|
|
300
|
+
|
|
301
|
+
- [ ] 主键索引存在
|
|
302
|
+
- [ ] 业务唯一字段有唯一索引
|
|
303
|
+
- [ ] 高频查询条件有索引覆盖
|
|
304
|
+
- [ ] 外键字段有普通索引
|
|
305
|
+
- [ ] 组合索引遵循最左前缀原则
|
|
306
|
+
- [ ] 索引命名符合 `uk_` / `idx_` 前缀规范
|
|
307
|
+
- [ ] 单表索引数量不超过 5 个
|
|
308
|
+
- [ ] 无冗余索引(已被其他组合索引覆盖的单列索引)
|
|
309
|
+
|
|
310
|
+
### 关联关系审查
|
|
311
|
+
|
|
312
|
+
- [ ] 使用逻辑外键,无物理 FOREIGN KEY 约束
|
|
313
|
+
- [ ] 外键字段类型与引用表主键类型一致(BIGINT)
|
|
314
|
+
- [ ] 关联关系在 COMMENT 中说明
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
## 最佳实践
|
|
319
|
+
|
|
320
|
+
1. **先理解业务再建表** — 充分理解业务需求后再设计表结构,避免反复修改
|
|
321
|
+
2. **适度冗余** — 允许适度的数据冗余以减少 JOIN 查询(如订单表存商品名称)
|
|
322
|
+
3. **预留扩展** — 状态字段使用 TINYINT 而非 ENUM,方便扩展
|
|
323
|
+
4. **避免过度设计** — 不要为不确定的未来需求添加字段
|
|
324
|
+
5. **字段默认值** — 尽量为字段设置合理的默认值
|
|
325
|
+
6. **注释完整** — 每个字段和表都要有清晰的中文注释
|
|
326
|
+
7. **金额用分** — 如果精度要求高,可以考虑用 BIGINT 存储分,避免浮点精度问题
|
|
327
|
+
8. **状态值说明** — 状态字段的 COMMENT 中列出所有可能的值及含义
|
|
328
|
+
|
|
329
|
+
---
|
|
330
|
+
|
|
331
|
+
## 常见问题排查
|
|
332
|
+
|
|
333
|
+
### Q: VARCHAR 和 TEXT 如何选择?
|
|
334
|
+
|
|
335
|
+
- 长度可预估且 ≤ 65535 字节:使用 `VARCHAR(n)`
|
|
336
|
+
- 长度不可预估或超长内容:使用 `TEXT`
|
|
337
|
+
- VARCHAR 可以建索引,TEXT 只能建前缀索引
|
|
338
|
+
- VARCHAR 参与排序和分组性能优于 TEXT
|
|
339
|
+
|
|
340
|
+
### Q: DATETIME 和 TIMESTAMP 如何选择?
|
|
341
|
+
|
|
342
|
+
推荐统一使用 `DATETIME`:
|
|
343
|
+
- DATETIME 范围:1000-01-01 ~ 9999-12-31
|
|
344
|
+
- TIMESTAMP 范围:1970-01-01 ~ 2038-01-19(存在 2038 年问题)
|
|
345
|
+
- DATETIME 不受时区影响,存什么取什么
|
|
346
|
+
- TIMESTAMP 自动时区转换,跨时区可能导致混乱
|
|
347
|
+
|
|
348
|
+
### Q: 如何处理枚举值字段?
|
|
349
|
+
|
|
350
|
+
推荐使用 `TINYINT` + COMMENT 说明:
|
|
351
|
+
|
|
352
|
+
```sql
|
|
353
|
+
-- 推荐
|
|
354
|
+
order_status TINYINT NOT NULL DEFAULT 0 COMMENT '订单状态:0-待支付 1-已支付 2-已发货 3-已完成 4-已取消'
|
|
355
|
+
|
|
356
|
+
-- 不推荐:MySQL ENUM 类型
|
|
357
|
+
order_status ENUM('PENDING', 'PAID', 'SHIPPED') COMMENT '订单状态'
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
原因:TINYINT 更灵活,新增枚举值不需要 ALTER TABLE。
|
|
361
|
+
|
|
362
|
+
### Q: 需要存储树形结构怎么设计?
|
|
363
|
+
|
|
364
|
+
推荐使用 `parent_id` 邻接表模式:
|
|
365
|
+
|
|
366
|
+
```sql
|
|
367
|
+
CREATE TABLE t_department (
|
|
368
|
+
id BIGINT NOT NULL COMMENT '主键ID',
|
|
369
|
+
parent_id BIGINT NOT NULL DEFAULT 0 COMMENT '父级ID,顶级为0',
|
|
370
|
+
name VARCHAR(100) NOT NULL COMMENT '部门名称',
|
|
371
|
+
sort INT NOT NULL DEFAULT 0 COMMENT '排序号',
|
|
372
|
+
...
|
|
373
|
+
KEY idx_parent_id (parent_id)
|
|
374
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='部门表';
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
如需高效查询整棵子树,可额外添加 `path` 字段存储路径(如 `/1/3/7/`)。
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: deployment-config
|
|
3
|
+
description: |
|
|
4
|
+
部署配置技能 - 生成 Docker / Kubernetes 部署配置模板。
|
|
5
|
+
triggers: Docker, Dockerfile, K8s, Kubernetes, deployment, 部署配置
|
|
6
|
+
globs:
|
|
7
|
+
- "Dockerfile"
|
|
8
|
+
- "docker-compose*.yml"
|
|
9
|
+
- "k8s/**/*.yml"
|
|
10
|
+
- "k8s/**/*.yaml"
|
|
11
|
+
- "deploy/**/*.yml"
|
|
12
|
+
- "deploy/**/*.yaml"
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# 部署配置 (Deployment Config)
|
|
16
|
+
|
|
17
|
+
## 概述
|
|
18
|
+
|
|
19
|
+
为 Avatar Boot (Spring Boot 3.5.3 + Java 21) 项目生成生产级 Docker 与 Kubernetes
|
|
20
|
+
部署配置,涵盖多阶段构建、资源限制、健康检查、环境变量注入等。
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 1. Dockerfile 多阶段构建
|
|
25
|
+
|
|
26
|
+
```dockerfile
|
|
27
|
+
# ==================== 构建阶段 ====================
|
|
28
|
+
FROM maven:3.9-eclipse-temurin-21-alpine AS builder
|
|
29
|
+
|
|
30
|
+
WORKDIR /build
|
|
31
|
+
COPY pom.xml .
|
|
32
|
+
# 先下载依赖,利用 Docker 缓存层
|
|
33
|
+
RUN mvn dependency:go-offline -B
|
|
34
|
+
|
|
35
|
+
COPY src ./src
|
|
36
|
+
RUN mvn package -DskipTests -B && \
|
|
37
|
+
# 使用 Spring Boot layertools 拆分 jar,优化镜像层缓存
|
|
38
|
+
java -Djarmode=layertools -jar target/*.jar extract --destination extracted
|
|
39
|
+
|
|
40
|
+
# ==================== 运行阶段 ====================
|
|
41
|
+
FROM eclipse-temurin:21-jre-alpine AS runtime
|
|
42
|
+
|
|
43
|
+
# 安全: 不使用 root 用户
|
|
44
|
+
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
|
|
45
|
+
USER appuser
|
|
46
|
+
|
|
47
|
+
WORKDIR /app
|
|
48
|
+
|
|
49
|
+
# 按变更频率分层 COPY,最大化缓存命中
|
|
50
|
+
COPY --from=builder /build/extracted/dependencies/ ./
|
|
51
|
+
COPY --from=builder /build/extracted/spring-boot-loader/ ./
|
|
52
|
+
COPY --from=builder /build/extracted/snapshot-dependencies/ ./
|
|
53
|
+
COPY --from=builder /build/extracted/application/ ./
|
|
54
|
+
|
|
55
|
+
# JVM 调优参数
|
|
56
|
+
ENV JAVA_OPTS="-XX:+UseG1GC \
|
|
57
|
+
-XX:MaxRAMPercentage=75.0 \
|
|
58
|
+
-XX:+UseContainerSupport \
|
|
59
|
+
-Djava.security.egd=file:/dev/./urandom"
|
|
60
|
+
|
|
61
|
+
EXPOSE 8080
|
|
62
|
+
|
|
63
|
+
# 健康检查
|
|
64
|
+
HEALTHCHECK --interval=30s --timeout=5s --start-period=60s --retries=3 \
|
|
65
|
+
CMD wget -qO- http://localhost:8080/actuator/health || exit 1
|
|
66
|
+
|
|
67
|
+
ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} org.springframework.boot.loader.launch.JarLauncher"]
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## 2. Kubernetes Deployment
|
|
73
|
+
|
|
74
|
+
```yaml
|
|
75
|
+
apiVersion: apps/v1
|
|
76
|
+
kind: Deployment
|
|
77
|
+
metadata:
|
|
78
|
+
name: ${APP_NAME}
|
|
79
|
+
namespace: ${NAMESPACE}
|
|
80
|
+
labels:
|
|
81
|
+
app: ${APP_NAME}
|
|
82
|
+
version: ${APP_VERSION}
|
|
83
|
+
spec:
|
|
84
|
+
replicas: 2
|
|
85
|
+
revisionHistoryLimit: 5
|
|
86
|
+
strategy:
|
|
87
|
+
type: RollingUpdate
|
|
88
|
+
rollingUpdate:
|
|
89
|
+
maxSurge: 1
|
|
90
|
+
maxUnavailable: 0
|
|
91
|
+
selector:
|
|
92
|
+
matchLabels:
|
|
93
|
+
app: ${APP_NAME}
|
|
94
|
+
template:
|
|
95
|
+
metadata:
|
|
96
|
+
labels:
|
|
97
|
+
app: ${APP_NAME}
|
|
98
|
+
version: ${APP_VERSION}
|
|
99
|
+
annotations:
|
|
100
|
+
prometheus.io/scrape: "true"
|
|
101
|
+
prometheus.io/port: "8080"
|
|
102
|
+
prometheus.io/path: "/actuator/prometheus"
|
|
103
|
+
spec:
|
|
104
|
+
serviceAccountName: ${APP_NAME}
|
|
105
|
+
terminationGracePeriodSeconds: 60
|
|
106
|
+
containers:
|
|
107
|
+
- name: ${APP_NAME}
|
|
108
|
+
image: ${REGISTRY}/${APP_NAME}:${APP_VERSION}
|
|
109
|
+
imagePullPolicy: IfNotPresent
|
|
110
|
+
ports:
|
|
111
|
+
- name: http
|
|
112
|
+
containerPort: 8080
|
|
113
|
+
protocol: TCP
|
|
114
|
+
# -------- 资源限制 --------
|
|
115
|
+
resources:
|
|
116
|
+
requests:
|
|
117
|
+
cpu: "250m"
|
|
118
|
+
memory: "512Mi"
|
|
119
|
+
limits:
|
|
120
|
+
cpu: "1000m"
|
|
121
|
+
memory: "1024Mi"
|
|
122
|
+
# -------- 健康检查 --------
|
|
123
|
+
startupProbe:
|
|
124
|
+
httpGet:
|
|
125
|
+
path: /actuator/health/liveness
|
|
126
|
+
port: http
|
|
127
|
+
initialDelaySeconds: 30
|
|
128
|
+
periodSeconds: 10
|
|
129
|
+
failureThreshold: 10
|
|
130
|
+
livenessProbe:
|
|
131
|
+
httpGet:
|
|
132
|
+
path: /actuator/health/liveness
|
|
133
|
+
port: http
|
|
134
|
+
periodSeconds: 15
|
|
135
|
+
timeoutSeconds: 3
|
|
136
|
+
failureThreshold: 3
|
|
137
|
+
readinessProbe:
|
|
138
|
+
httpGet:
|
|
139
|
+
path: /actuator/health/readiness
|
|
140
|
+
port: http
|
|
141
|
+
periodSeconds: 10
|
|
142
|
+
timeoutSeconds: 3
|
|
143
|
+
failureThreshold: 3
|
|
144
|
+
# -------- 环境变量 --------
|
|
145
|
+
env:
|
|
146
|
+
- name: SPRING_PROFILES_ACTIVE
|
|
147
|
+
value: "${PROFILE}"
|
|
148
|
+
- name: JAVA_OPTS
|
|
149
|
+
value: "-XX:+UseG1GC -XX:MaxRAMPercentage=75.0"
|
|
150
|
+
- name: TZ
|
|
151
|
+
value: "Asia/Shanghai"
|
|
152
|
+
envFrom:
|
|
153
|
+
- configMapRef:
|
|
154
|
+
name: ${APP_NAME}-config
|
|
155
|
+
- secretRef:
|
|
156
|
+
name: ${APP_NAME}-secret
|
|
157
|
+
# -------- 挂载 --------
|
|
158
|
+
volumeMounts:
|
|
159
|
+
- name: logs
|
|
160
|
+
mountPath: /app/logs
|
|
161
|
+
volumes:
|
|
162
|
+
- name: logs
|
|
163
|
+
emptyDir: {}
|
|
164
|
+
imagePullSecrets:
|
|
165
|
+
- name: registry-secret
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## 3. Kubernetes Service
|
|
171
|
+
|
|
172
|
+
```yaml
|
|
173
|
+
apiVersion: v1
|
|
174
|
+
kind: Service
|
|
175
|
+
metadata:
|
|
176
|
+
name: ${APP_NAME}
|
|
177
|
+
namespace: ${NAMESPACE}
|
|
178
|
+
labels:
|
|
179
|
+
app: ${APP_NAME}
|
|
180
|
+
spec:
|
|
181
|
+
type: ClusterIP
|
|
182
|
+
ports:
|
|
183
|
+
- name: http
|
|
184
|
+
port: 80
|
|
185
|
+
targetPort: http
|
|
186
|
+
protocol: TCP
|
|
187
|
+
selector:
|
|
188
|
+
app: ${APP_NAME}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## 4. Kubernetes Ingress
|
|
194
|
+
|
|
195
|
+
```yaml
|
|
196
|
+
apiVersion: networking.k8s.io/v1
|
|
197
|
+
kind: Ingress
|
|
198
|
+
metadata:
|
|
199
|
+
name: ${APP_NAME}
|
|
200
|
+
namespace: ${NAMESPACE}
|
|
201
|
+
annotations:
|
|
202
|
+
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
|
|
203
|
+
nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
|
|
204
|
+
nginx.ingress.kubernetes.io/proxy-send-timeout: "60"
|
|
205
|
+
nginx.ingress.kubernetes.io/ssl-redirect: "true"
|
|
206
|
+
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
|
207
|
+
spec:
|
|
208
|
+
ingressClassName: nginx
|
|
209
|
+
tls:
|
|
210
|
+
- hosts:
|
|
211
|
+
- ${APP_DOMAIN}
|
|
212
|
+
secretName: ${APP_NAME}-tls
|
|
213
|
+
rules:
|
|
214
|
+
- host: ${APP_DOMAIN}
|
|
215
|
+
http:
|
|
216
|
+
paths:
|
|
217
|
+
- path: /
|
|
218
|
+
pathType: Prefix
|
|
219
|
+
backend:
|
|
220
|
+
service:
|
|
221
|
+
name: ${APP_NAME}
|
|
222
|
+
port:
|
|
223
|
+
name: http
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## 5. ConfigMap 与 Secret
|
|
229
|
+
|
|
230
|
+
```yaml
|
|
231
|
+
# ConfigMap - 非敏感配置
|
|
232
|
+
apiVersion: v1
|
|
233
|
+
kind: ConfigMap
|
|
234
|
+
metadata:
|
|
235
|
+
name: ${APP_NAME}-config
|
|
236
|
+
namespace: ${NAMESPACE}
|
|
237
|
+
data:
|
|
238
|
+
NACOS_SERVER_ADDR: "nacos.middleware:8848"
|
|
239
|
+
NACOS_NAMESPACE: "production"
|
|
240
|
+
APP_LOG_LEVEL: "INFO"
|
|
241
|
+
---
|
|
242
|
+
# Secret - 敏感配置 (值需 base64 编码)
|
|
243
|
+
apiVersion: v1
|
|
244
|
+
kind: Secret
|
|
245
|
+
metadata:
|
|
246
|
+
name: ${APP_NAME}-secret
|
|
247
|
+
namespace: ${NAMESPACE}
|
|
248
|
+
type: Opaque
|
|
249
|
+
data:
|
|
250
|
+
DB_PASSWORD: "cGFzc3dvcmQ=" # echo -n 'password' | base64
|
|
251
|
+
REDIS_PASSWORD: "cmVkaXNwYXNz" # echo -n 'redispass' | base64
|
|
252
|
+
KAFKA_SASL_PASSWORD: "a2Fma2FwYXNz" # echo -n 'kafkapass' | base64
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## Best Practices
|
|
258
|
+
|
|
259
|
+
1. **镜像构建**: 使用多阶段构建减小镜像体积;利用 Spring Boot layertools 拆分 jar 层,加速增量构建。
|
|
260
|
+
2. **非 root 运行**: 容器内使用非 root 用户,降低安全风险。
|
|
261
|
+
3. **资源限制**: 始终设置 requests 和 limits;`MaxRAMPercentage=75.0` 预留内存给堆外。
|
|
262
|
+
4. **健康检查三件套**: startupProbe (启动) + livenessProbe (存活) + readinessProbe (就绪) 缺一不可。
|
|
263
|
+
5. **滚动更新**: `maxUnavailable: 0` 保证更新期间无损;`terminationGracePeriodSeconds` 给足优雅关闭时间。
|
|
264
|
+
6. **敏感信息**: 密码、密钥必须放 Secret,禁止写入 ConfigMap 或镜像中。
|
|
265
|
+
7. **时区**: 容器默认 UTC,需显式设置 `TZ=Asia/Shanghai`。
|
|
266
|
+
|
|
267
|
+
## Troubleshooting
|
|
268
|
+
|
|
269
|
+
| 问题 | 排查方向 |
|
|
270
|
+
|------|----------|
|
|
271
|
+
| Pod 启动 CrashLoopBackOff | 检查 `startupProbe` 配置,增大 `initialDelaySeconds` 或 `failureThreshold` |
|
|
272
|
+
| OOMKilled | 调大 `resources.limits.memory`,检查 JVM `MaxRAMPercentage` 是否合理 |
|
|
273
|
+
| 镜像拉取失败 | 确认 `imagePullSecrets` 配置正确,镜像 tag 是否存在 |
|
|
274
|
+
| 服务不可达 | 检查 Service selector 与 Pod labels 是否匹配;确认 `readinessProbe` 通过 |
|
|
275
|
+
| 配置未生效 | ConfigMap / Secret 更新后需重启 Pod,或使用 Nacos 动态配置 |
|
|
276
|
+
| 滚动更新卡住 | 检查新 Pod 是否通过 readinessProbe;`kubectl rollout status` 查看详情 |
|
|
277
|
+
| 日志中文乱码 | Dockerfile 中添加 `ENV LANG=C.UTF-8` |
|