muno-claude-plugin 1.7.0 → 1.9.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 +120 -0
- package/bin/cli.js +4 -1
- package/package.json +6 -3
- package/templates/WORKFLOW.md +1 -0
- package/templates/agents/code-reviewer.md +646 -0
- package/templates/commands/app-designer.md +9 -0
- package/templates/personas/app-designer.md +182 -0
- package/templates/skills/app-design/SKILL.md +640 -0
- package/templates/skills/app-design/reference/component-examples.md +953 -0
- package/templates/skills/app-design/reference/design-system-template.md +628 -0
- package/templates/skills/app-design/reference/design-tokens.json +231 -0
- package/templates/skills/swagger-docs-generator/SKILL.md +699 -0
- package/templates/skills/swagger-docs-generator/reference/api-docs-template.md +666 -0
|
@@ -0,0 +1,666 @@
|
|
|
1
|
+
# [서비스 이름] API 문서
|
|
2
|
+
|
|
3
|
+
> Generated from Swagger/OpenAPI
|
|
4
|
+
> Version: [version]
|
|
5
|
+
> Generated Date: [YYYY-MM-DD]
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 📋 목차
|
|
10
|
+
|
|
11
|
+
- [개요](#개요)
|
|
12
|
+
- [서버 정보](#서버-정보)
|
|
13
|
+
- [인증](#인증)
|
|
14
|
+
- [API 엔드포인트](#api-엔드포인트)
|
|
15
|
+
- [데이터 모델](#데이터-모델)
|
|
16
|
+
- [에러 코드](#에러-코드)
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 개요
|
|
21
|
+
|
|
22
|
+
**서비스명**: [Service Title]
|
|
23
|
+
**버전**: [version]
|
|
24
|
+
**설명**: [description]
|
|
25
|
+
|
|
26
|
+
### 주요 기능
|
|
27
|
+
|
|
28
|
+
- 기능 1
|
|
29
|
+
- 기능 2
|
|
30
|
+
- 기능 3
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 서버 정보
|
|
35
|
+
|
|
36
|
+
### Base URLs
|
|
37
|
+
|
|
38
|
+
| 환경 | URL | 설명 |
|
|
39
|
+
|------|-----|------|
|
|
40
|
+
| Local | `http://localhost:8080` | 로컬 개발 서버 |
|
|
41
|
+
| Development | `https://dev-api.example.com` | 개발 환경 |
|
|
42
|
+
| Staging | `https://staging-api.example.com` | 스테이징 환경 |
|
|
43
|
+
| Production | `https://api.example.com` | 프로덕션 환경 |
|
|
44
|
+
|
|
45
|
+
### Contact
|
|
46
|
+
|
|
47
|
+
- **Email**: [contact email]
|
|
48
|
+
- **License**: [license name]
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## 인증
|
|
53
|
+
|
|
54
|
+
### Bearer Token
|
|
55
|
+
|
|
56
|
+
이 API는 Bearer Token 인증을 사용합니다.
|
|
57
|
+
|
|
58
|
+
**Header**:
|
|
59
|
+
```
|
|
60
|
+
Authorization: Bearer {token}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**토큰 획득 방법**:
|
|
64
|
+
1. `/auth/login` 엔드포인트로 로그인
|
|
65
|
+
2. 응답에서 `accessToken` 획득
|
|
66
|
+
3. 모든 요청의 Authorization 헤더에 포함
|
|
67
|
+
|
|
68
|
+
**Example**:
|
|
69
|
+
```bash
|
|
70
|
+
curl -X GET "https://api.example.com/api/users" \
|
|
71
|
+
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## API 엔드포인트
|
|
77
|
+
|
|
78
|
+
### 👤 User
|
|
79
|
+
|
|
80
|
+
사용자 관리 관련 API
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
#### `GET /api/users`
|
|
85
|
+
|
|
86
|
+
사용자 목록을 조회합니다.
|
|
87
|
+
|
|
88
|
+
**Parameters**:
|
|
89
|
+
|
|
90
|
+
| Name | In | Type | Required | Description | Default |
|
|
91
|
+
|------|-----|------|----------|-------------|---------|
|
|
92
|
+
| page | query | integer | ❌ | Page number | 1 |
|
|
93
|
+
| size | query | integer | ❌ | Page size | 20 |
|
|
94
|
+
| sort | query | string | ❌ | Sort field | createdAt |
|
|
95
|
+
| order | query | string | ❌ | Sort order (asc/desc) | desc |
|
|
96
|
+
|
|
97
|
+
**Request Example**:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
curl -X GET "http://localhost:8080/api/users?page=1&size=20" \
|
|
101
|
+
-H "Authorization: Bearer {token}"
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**Response**:
|
|
105
|
+
|
|
106
|
+
- **200 OK**
|
|
107
|
+
|
|
108
|
+
```json
|
|
109
|
+
{
|
|
110
|
+
"data": [
|
|
111
|
+
{
|
|
112
|
+
"id": 1,
|
|
113
|
+
"name": "John Doe",
|
|
114
|
+
"email": "john@example.com",
|
|
115
|
+
"role": "USER",
|
|
116
|
+
"createdAt": "2025-01-01T00:00:00Z"
|
|
117
|
+
}
|
|
118
|
+
],
|
|
119
|
+
"pagination": {
|
|
120
|
+
"page": 1,
|
|
121
|
+
"size": 20,
|
|
122
|
+
"totalElements": 100,
|
|
123
|
+
"totalPages": 5
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
- **401 Unauthorized**
|
|
129
|
+
|
|
130
|
+
```json
|
|
131
|
+
{
|
|
132
|
+
"error": "UNAUTHORIZED",
|
|
133
|
+
"message": "Invalid or missing authentication token"
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
**Code Examples**:
|
|
138
|
+
|
|
139
|
+
<details>
|
|
140
|
+
<summary>JavaScript (fetch)</summary>
|
|
141
|
+
|
|
142
|
+
```javascript
|
|
143
|
+
const response = await fetch('http://localhost:8080/api/users?page=1&size=20', {
|
|
144
|
+
method: 'GET',
|
|
145
|
+
headers: {
|
|
146
|
+
'Authorization': `Bearer ${token}`,
|
|
147
|
+
'Content-Type': 'application/json'
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
const data = await response.json();
|
|
151
|
+
console.log(data);
|
|
152
|
+
```
|
|
153
|
+
</details>
|
|
154
|
+
|
|
155
|
+
<details>
|
|
156
|
+
<summary>Python (requests)</summary>
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
import requests
|
|
160
|
+
|
|
161
|
+
headers = {
|
|
162
|
+
'Authorization': f'Bearer {token}',
|
|
163
|
+
'Content-Type': 'application/json'
|
|
164
|
+
}
|
|
165
|
+
response = requests.get(
|
|
166
|
+
'http://localhost:8080/api/users',
|
|
167
|
+
headers=headers,
|
|
168
|
+
params={'page': 1, 'size': 20}
|
|
169
|
+
)
|
|
170
|
+
print(response.json())
|
|
171
|
+
```
|
|
172
|
+
</details>
|
|
173
|
+
|
|
174
|
+
<details>
|
|
175
|
+
<summary>Java (Spring WebClient)</summary>
|
|
176
|
+
|
|
177
|
+
```java
|
|
178
|
+
WebClient client = WebClient.create("http://localhost:8080");
|
|
179
|
+
UserListResponse response = client.get()
|
|
180
|
+
.uri(uriBuilder -> uriBuilder
|
|
181
|
+
.path("/api/users")
|
|
182
|
+
.queryParam("page", 1)
|
|
183
|
+
.queryParam("size", 20)
|
|
184
|
+
.build())
|
|
185
|
+
.header("Authorization", "Bearer " + token)
|
|
186
|
+
.retrieve()
|
|
187
|
+
.bodyToMono(UserListResponse.class)
|
|
188
|
+
.block();
|
|
189
|
+
```
|
|
190
|
+
</details>
|
|
191
|
+
|
|
192
|
+
<details>
|
|
193
|
+
<summary>Kotlin (Spring WebClient)</summary>
|
|
194
|
+
|
|
195
|
+
```kotlin
|
|
196
|
+
val client = WebClient.create("http://localhost:8080")
|
|
197
|
+
val response = client.get()
|
|
198
|
+
.uri { uriBuilder ->
|
|
199
|
+
uriBuilder
|
|
200
|
+
.path("/api/users")
|
|
201
|
+
.queryParam("page", 1)
|
|
202
|
+
.queryParam("size", 20)
|
|
203
|
+
.build()
|
|
204
|
+
}
|
|
205
|
+
.header("Authorization", "Bearer $token")
|
|
206
|
+
.retrieve()
|
|
207
|
+
.awaitBody<UserListResponse>()
|
|
208
|
+
```
|
|
209
|
+
</details>
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
#### `GET /api/users/{id}`
|
|
214
|
+
|
|
215
|
+
특정 사용자의 상세 정보를 조회합니다.
|
|
216
|
+
|
|
217
|
+
**Parameters**:
|
|
218
|
+
|
|
219
|
+
| Name | In | Type | Required | Description |
|
|
220
|
+
|------|-----|------|----------|-------------|
|
|
221
|
+
| id | path | integer | ✅ | User ID |
|
|
222
|
+
|
|
223
|
+
**Request Example**:
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
curl -X GET "http://localhost:8080/api/users/1" \
|
|
227
|
+
-H "Authorization: Bearer {token}"
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
**Response**:
|
|
231
|
+
|
|
232
|
+
- **200 OK**
|
|
233
|
+
|
|
234
|
+
```json
|
|
235
|
+
{
|
|
236
|
+
"id": 1,
|
|
237
|
+
"name": "John Doe",
|
|
238
|
+
"email": "john@example.com",
|
|
239
|
+
"role": "USER",
|
|
240
|
+
"profile": {
|
|
241
|
+
"avatar": "https://example.com/avatar.jpg",
|
|
242
|
+
"bio": "Software Engineer"
|
|
243
|
+
},
|
|
244
|
+
"createdAt": "2025-01-01T00:00:00Z",
|
|
245
|
+
"updatedAt": "2025-01-01T00:00:00Z"
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
- **404 Not Found**
|
|
250
|
+
|
|
251
|
+
```json
|
|
252
|
+
{
|
|
253
|
+
"error": "NOT_FOUND",
|
|
254
|
+
"message": "User not found with id: 1"
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
#### `POST /api/users`
|
|
261
|
+
|
|
262
|
+
새로운 사용자를 생성합니다.
|
|
263
|
+
|
|
264
|
+
**Request Body**:
|
|
265
|
+
|
|
266
|
+
```json
|
|
267
|
+
{
|
|
268
|
+
"name": "string",
|
|
269
|
+
"email": "string",
|
|
270
|
+
"password": "string",
|
|
271
|
+
"role": "USER"
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
**Request Example**:
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
curl -X POST "http://localhost:8080/api/users" \
|
|
279
|
+
-H "Authorization: Bearer {token}" \
|
|
280
|
+
-H "Content-Type: application/json" \
|
|
281
|
+
-d '{
|
|
282
|
+
"name": "Jane Doe",
|
|
283
|
+
"email": "jane@example.com",
|
|
284
|
+
"password": "securePassword123",
|
|
285
|
+
"role": "USER"
|
|
286
|
+
}'
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
**Response**:
|
|
290
|
+
|
|
291
|
+
- **201 Created**
|
|
292
|
+
|
|
293
|
+
```json
|
|
294
|
+
{
|
|
295
|
+
"id": 2,
|
|
296
|
+
"name": "Jane Doe",
|
|
297
|
+
"email": "jane@example.com",
|
|
298
|
+
"role": "USER",
|
|
299
|
+
"createdAt": "2025-01-01T00:00:00Z"
|
|
300
|
+
}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
- **400 Bad Request**
|
|
304
|
+
|
|
305
|
+
```json
|
|
306
|
+
{
|
|
307
|
+
"error": "VALIDATION_ERROR",
|
|
308
|
+
"message": "Invalid input",
|
|
309
|
+
"details": [
|
|
310
|
+
{
|
|
311
|
+
"field": "email",
|
|
312
|
+
"message": "Email already exists"
|
|
313
|
+
}
|
|
314
|
+
]
|
|
315
|
+
}
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
#### `PUT /api/users/{id}`
|
|
321
|
+
|
|
322
|
+
사용자 정보를 수정합니다.
|
|
323
|
+
|
|
324
|
+
**Parameters**:
|
|
325
|
+
|
|
326
|
+
| Name | In | Type | Required | Description |
|
|
327
|
+
|------|-----|------|----------|-------------|
|
|
328
|
+
| id | path | integer | ✅ | User ID |
|
|
329
|
+
|
|
330
|
+
**Request Body**:
|
|
331
|
+
|
|
332
|
+
```json
|
|
333
|
+
{
|
|
334
|
+
"name": "string",
|
|
335
|
+
"email": "string",
|
|
336
|
+
"role": "USER"
|
|
337
|
+
}
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
**Request Example**:
|
|
341
|
+
|
|
342
|
+
```bash
|
|
343
|
+
curl -X PUT "http://localhost:8080/api/users/1" \
|
|
344
|
+
-H "Authorization: Bearer {token}" \
|
|
345
|
+
-H "Content-Type: application/json" \
|
|
346
|
+
-d '{
|
|
347
|
+
"name": "John Updated",
|
|
348
|
+
"email": "john.updated@example.com"
|
|
349
|
+
}'
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
**Response**:
|
|
353
|
+
|
|
354
|
+
- **200 OK**
|
|
355
|
+
|
|
356
|
+
```json
|
|
357
|
+
{
|
|
358
|
+
"id": 1,
|
|
359
|
+
"name": "John Updated",
|
|
360
|
+
"email": "john.updated@example.com",
|
|
361
|
+
"role": "USER",
|
|
362
|
+
"updatedAt": "2025-01-01T12:00:00Z"
|
|
363
|
+
}
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
- **404 Not Found**
|
|
367
|
+
|
|
368
|
+
```json
|
|
369
|
+
{
|
|
370
|
+
"error": "NOT_FOUND",
|
|
371
|
+
"message": "User not found with id: 1"
|
|
372
|
+
}
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
---
|
|
376
|
+
|
|
377
|
+
#### `DELETE /api/users/{id}`
|
|
378
|
+
|
|
379
|
+
사용자를 삭제합니다.
|
|
380
|
+
|
|
381
|
+
**Parameters**:
|
|
382
|
+
|
|
383
|
+
| Name | In | Type | Required | Description |
|
|
384
|
+
|------|-----|------|----------|-------------|
|
|
385
|
+
| id | path | integer | ✅ | User ID |
|
|
386
|
+
|
|
387
|
+
**Request Example**:
|
|
388
|
+
|
|
389
|
+
```bash
|
|
390
|
+
curl -X DELETE "http://localhost:8080/api/users/1" \
|
|
391
|
+
-H "Authorization: Bearer {token}"
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
**Response**:
|
|
395
|
+
|
|
396
|
+
- **204 No Content**
|
|
397
|
+
|
|
398
|
+
성공적으로 삭제됨 (본문 없음)
|
|
399
|
+
|
|
400
|
+
- **404 Not Found**
|
|
401
|
+
|
|
402
|
+
```json
|
|
403
|
+
{
|
|
404
|
+
"error": "NOT_FOUND",
|
|
405
|
+
"message": "User not found with id: 1"
|
|
406
|
+
}
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
---
|
|
410
|
+
|
|
411
|
+
### 🔐 Authentication
|
|
412
|
+
|
|
413
|
+
인증 관련 API
|
|
414
|
+
|
|
415
|
+
---
|
|
416
|
+
|
|
417
|
+
#### `POST /auth/login`
|
|
418
|
+
|
|
419
|
+
사용자 로그인
|
|
420
|
+
|
|
421
|
+
**Request Body**:
|
|
422
|
+
|
|
423
|
+
```json
|
|
424
|
+
{
|
|
425
|
+
"email": "string",
|
|
426
|
+
"password": "string"
|
|
427
|
+
}
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
**Request Example**:
|
|
431
|
+
|
|
432
|
+
```bash
|
|
433
|
+
curl -X POST "http://localhost:8080/auth/login" \
|
|
434
|
+
-H "Content-Type: application/json" \
|
|
435
|
+
-d '{
|
|
436
|
+
"email": "john@example.com",
|
|
437
|
+
"password": "password123"
|
|
438
|
+
}'
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
**Response**:
|
|
442
|
+
|
|
443
|
+
- **200 OK**
|
|
444
|
+
|
|
445
|
+
```json
|
|
446
|
+
{
|
|
447
|
+
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
|
448
|
+
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
|
449
|
+
"tokenType": "Bearer",
|
|
450
|
+
"expiresIn": 3600,
|
|
451
|
+
"user": {
|
|
452
|
+
"id": 1,
|
|
453
|
+
"name": "John Doe",
|
|
454
|
+
"email": "john@example.com",
|
|
455
|
+
"role": "USER"
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
- **401 Unauthorized**
|
|
461
|
+
|
|
462
|
+
```json
|
|
463
|
+
{
|
|
464
|
+
"error": "INVALID_CREDENTIALS",
|
|
465
|
+
"message": "Invalid email or password"
|
|
466
|
+
}
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
---
|
|
470
|
+
|
|
471
|
+
#### `POST /auth/refresh`
|
|
472
|
+
|
|
473
|
+
Access Token 갱신
|
|
474
|
+
|
|
475
|
+
**Request Body**:
|
|
476
|
+
|
|
477
|
+
```json
|
|
478
|
+
{
|
|
479
|
+
"refreshToken": "string"
|
|
480
|
+
}
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
**Response**:
|
|
484
|
+
|
|
485
|
+
- **200 OK**
|
|
486
|
+
|
|
487
|
+
```json
|
|
488
|
+
{
|
|
489
|
+
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
|
490
|
+
"tokenType": "Bearer",
|
|
491
|
+
"expiresIn": 3600
|
|
492
|
+
}
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
- **401 Unauthorized**
|
|
496
|
+
|
|
497
|
+
```json
|
|
498
|
+
{
|
|
499
|
+
"error": "INVALID_TOKEN",
|
|
500
|
+
"message": "Refresh token is invalid or expired"
|
|
501
|
+
}
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
---
|
|
505
|
+
|
|
506
|
+
## 데이터 모델
|
|
507
|
+
|
|
508
|
+
### User
|
|
509
|
+
|
|
510
|
+
사용자 정보
|
|
511
|
+
|
|
512
|
+
```json
|
|
513
|
+
{
|
|
514
|
+
"id": "integer",
|
|
515
|
+
"name": "string",
|
|
516
|
+
"email": "string",
|
|
517
|
+
"role": "string",
|
|
518
|
+
"profile": "UserProfile",
|
|
519
|
+
"createdAt": "string (date-time)",
|
|
520
|
+
"updatedAt": "string (date-time)"
|
|
521
|
+
}
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
**Properties**:
|
|
525
|
+
|
|
526
|
+
| Field | Type | Required | Description | Constraints |
|
|
527
|
+
|-------|------|----------|-------------|-------------|
|
|
528
|
+
| id | integer | ✅ | User ID | Auto-generated |
|
|
529
|
+
| name | string | ✅ | User name | 2-50 characters |
|
|
530
|
+
| email | string | ✅ | User email | Valid email format |
|
|
531
|
+
| role | string | ✅ | User role | Enum: USER, ADMIN |
|
|
532
|
+
| profile | UserProfile | ❌ | User profile | - |
|
|
533
|
+
| createdAt | string | ✅ | Created timestamp | ISO 8601 format |
|
|
534
|
+
| updatedAt | string | ✅ | Updated timestamp | ISO 8601 format |
|
|
535
|
+
|
|
536
|
+
---
|
|
537
|
+
|
|
538
|
+
### UserProfile
|
|
539
|
+
|
|
540
|
+
사용자 프로필 정보
|
|
541
|
+
|
|
542
|
+
```json
|
|
543
|
+
{
|
|
544
|
+
"avatar": "string",
|
|
545
|
+
"bio": "string",
|
|
546
|
+
"phone": "string"
|
|
547
|
+
}
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
**Properties**:
|
|
551
|
+
|
|
552
|
+
| Field | Type | Required | Description | Constraints |
|
|
553
|
+
|-------|------|----------|-------------|-------------|
|
|
554
|
+
| avatar | string | ❌ | Avatar URL | Valid URL |
|
|
555
|
+
| bio | string | ❌ | User bio | Max 200 characters |
|
|
556
|
+
| phone | string | ❌ | Phone number | E.164 format |
|
|
557
|
+
|
|
558
|
+
---
|
|
559
|
+
|
|
560
|
+
### PaginationResponse
|
|
561
|
+
|
|
562
|
+
페이지네이션 정보
|
|
563
|
+
|
|
564
|
+
```json
|
|
565
|
+
{
|
|
566
|
+
"page": "integer",
|
|
567
|
+
"size": "integer",
|
|
568
|
+
"totalElements": "integer",
|
|
569
|
+
"totalPages": "integer"
|
|
570
|
+
}
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
**Properties**:
|
|
574
|
+
|
|
575
|
+
| Field | Type | Description |
|
|
576
|
+
|-------|------|-------------|
|
|
577
|
+
| page | integer | Current page number (1-indexed) |
|
|
578
|
+
| size | integer | Page size |
|
|
579
|
+
| totalElements | integer | Total number of elements |
|
|
580
|
+
| totalPages | integer | Total number of pages |
|
|
581
|
+
|
|
582
|
+
---
|
|
583
|
+
|
|
584
|
+
### ErrorResponse
|
|
585
|
+
|
|
586
|
+
에러 응답 형식
|
|
587
|
+
|
|
588
|
+
```json
|
|
589
|
+
{
|
|
590
|
+
"error": "string",
|
|
591
|
+
"message": "string",
|
|
592
|
+
"details": "array"
|
|
593
|
+
}
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
**Properties**:
|
|
597
|
+
|
|
598
|
+
| Field | Type | Description |
|
|
599
|
+
|-------|------|-------------|
|
|
600
|
+
| error | string | Error code |
|
|
601
|
+
| message | string | Human-readable error message |
|
|
602
|
+
| details | array | Additional error details (optional) |
|
|
603
|
+
|
|
604
|
+
---
|
|
605
|
+
|
|
606
|
+
## 에러 코드
|
|
607
|
+
|
|
608
|
+
### HTTP Status Codes
|
|
609
|
+
|
|
610
|
+
| Code | Name | Description |
|
|
611
|
+
|------|------|-------------|
|
|
612
|
+
| 200 | OK | Request succeeded |
|
|
613
|
+
| 201 | Created | Resource created successfully |
|
|
614
|
+
| 204 | No Content | Request succeeded with no response body |
|
|
615
|
+
| 400 | Bad Request | Invalid request parameters |
|
|
616
|
+
| 401 | Unauthorized | Missing or invalid authentication |
|
|
617
|
+
| 403 | Forbidden | Insufficient permissions |
|
|
618
|
+
| 404 | Not Found | Resource not found |
|
|
619
|
+
| 409 | Conflict | Resource conflict (e.g., duplicate email) |
|
|
620
|
+
| 422 | Unprocessable Entity | Validation error |
|
|
621
|
+
| 500 | Internal Server Error | Server error |
|
|
622
|
+
| 503 | Service Unavailable | Service temporarily unavailable |
|
|
623
|
+
|
|
624
|
+
### Application Error Codes
|
|
625
|
+
|
|
626
|
+
| Code | HTTP Status | Description |
|
|
627
|
+
|------|-------------|-------------|
|
|
628
|
+
| VALIDATION_ERROR | 400 | Input validation failed |
|
|
629
|
+
| INVALID_CREDENTIALS | 401 | Invalid email or password |
|
|
630
|
+
| UNAUTHORIZED | 401 | Missing or invalid token |
|
|
631
|
+
| FORBIDDEN | 403 | Insufficient permissions |
|
|
632
|
+
| NOT_FOUND | 404 | Resource not found |
|
|
633
|
+
| DUPLICATE_EMAIL | 409 | Email already exists |
|
|
634
|
+
| INTERNAL_ERROR | 500 | Internal server error |
|
|
635
|
+
|
|
636
|
+
---
|
|
637
|
+
|
|
638
|
+
## 부록
|
|
639
|
+
|
|
640
|
+
### Rate Limiting
|
|
641
|
+
|
|
642
|
+
- **제한**: 100 requests per minute per user
|
|
643
|
+
- **Header**:
|
|
644
|
+
- `X-RateLimit-Limit`: 최대 요청 수
|
|
645
|
+
- `X-RateLimit-Remaining`: 남은 요청 수
|
|
646
|
+
- `X-RateLimit-Reset`: 제한 초기화 시각 (Unix timestamp)
|
|
647
|
+
|
|
648
|
+
### Changelog
|
|
649
|
+
|
|
650
|
+
#### Version 1.0.0 (2025-01-01)
|
|
651
|
+
- Initial release
|
|
652
|
+
- User CRUD operations
|
|
653
|
+
- Authentication (JWT)
|
|
654
|
+
|
|
655
|
+
---
|
|
656
|
+
|
|
657
|
+
## 링크
|
|
658
|
+
|
|
659
|
+
- **Swagger UI**: http://localhost:8080/swagger-ui.html
|
|
660
|
+
- **API Docs JSON**: http://localhost:8080/v3/api-docs
|
|
661
|
+
- **Postman Collection**: [Download](./postman-collection.json)
|
|
662
|
+
|
|
663
|
+
---
|
|
664
|
+
|
|
665
|
+
> 📝 이 문서는 Swagger/OpenAPI 명세로부터 자동 생성되었습니다.
|
|
666
|
+
> 마지막 업데이트: [YYYY-MM-DD HH:mm:ss]
|