@shadimakhoul/ggcoach 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/config/config.ts +7 -0
- package/config/index.ts +2 -0
- package/config/initExpress.ts +27 -0
- package/config/redis.ts +38 -0
- package/config/swagger-ui.ts +84 -0
- package/config/swagger.ts +4417 -0
- package/dist/config/config.d.ts +8 -0
- package/dist/config/config.d.ts.map +1 -0
- package/dist/config/config.js +11 -0
- package/dist/config/config.js.map +1 -0
- package/dist/config/index.d.ts +3 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +19 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/initExpress.d.ts +2 -0
- package/dist/config/initExpress.d.ts.map +1 -0
- package/dist/config/initExpress.js +29 -0
- package/dist/config/initExpress.js.map +1 -0
- package/dist/config/redis.d.ts +6 -0
- package/dist/config/redis.d.ts.map +1 -0
- package/dist/config/redis.js +34 -0
- package/dist/config/redis.js.map +1 -0
- package/dist/config/swagger-ui.d.ts +6 -0
- package/dist/config/swagger-ui.d.ts.map +1 -0
- package/dist/config/swagger-ui.js +88 -0
- package/dist/config/swagger-ui.js.map +1 -0
- package/dist/config/swagger.d.ts +9 -0
- package/dist/config/swagger.d.ts.map +1 -0
- package/dist/config/swagger.js +4406 -0
- package/dist/config/swagger.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/admin-auth.d.ts +4 -0
- package/dist/middleware/admin-auth.d.ts.map +1 -0
- package/dist/middleware/admin-auth.js +55 -0
- package/dist/middleware/admin-auth.js.map +1 -0
- package/dist/middleware/auth.d.ts +4 -0
- package/dist/middleware/auth.d.ts.map +1 -0
- package/dist/middleware/auth.js +86 -0
- package/dist/middleware/auth.js.map +1 -0
- package/dist/middleware/cors.d.ts +16 -0
- package/dist/middleware/cors.d.ts.map +1 -0
- package/dist/middleware/cors.js +45 -0
- package/dist/middleware/cors.js.map +1 -0
- package/dist/middleware/errorHandler.d.ts +3 -0
- package/dist/middleware/errorHandler.d.ts.map +1 -0
- package/dist/middleware/errorHandler.js +58 -0
- package/dist/middleware/errorHandler.js.map +1 -0
- package/dist/middleware/index.d.ts +9 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +25 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/middleware/internalAuth.d.ts +4 -0
- package/dist/middleware/internalAuth.d.ts.map +1 -0
- package/dist/middleware/internalAuth.js +23 -0
- package/dist/middleware/internalAuth.js.map +1 -0
- package/dist/middleware/rateLimiter.d.ts +4 -0
- package/dist/middleware/rateLimiter.d.ts.map +1 -0
- package/dist/middleware/rateLimiter.js +24 -0
- package/dist/middleware/rateLimiter.js.map +1 -0
- package/dist/middleware/swagger.d.ts +16 -0
- package/dist/middleware/swagger.d.ts.map +1 -0
- package/dist/middleware/swagger.js +49 -0
- package/dist/middleware/swagger.js.map +1 -0
- package/dist/middleware/validation.d.ts +4 -0
- package/dist/middleware/validation.d.ts.map +1 -0
- package/dist/middleware/validation.js +24 -0
- package/dist/middleware/validation.js.map +1 -0
- package/dist/types/admin-auth.d.ts +44 -0
- package/dist/types/admin-auth.d.ts.map +1 -0
- package/dist/types/admin-auth.js +3 -0
- package/dist/types/admin-auth.js.map +1 -0
- package/dist/types/auth.d.ts +53 -0
- package/dist/types/auth.d.ts.map +1 -0
- package/dist/types/auth.js +3 -0
- package/dist/types/auth.js.map +1 -0
- package/dist/types/enums/auth.d.ts +7 -0
- package/dist/types/enums/auth.d.ts.map +1 -0
- package/dist/types/enums/auth.js +11 -0
- package/dist/types/enums/auth.js.map +1 -0
- package/dist/types/enums/index.d.ts +2 -0
- package/dist/types/enums/index.d.ts.map +1 -0
- package/dist/types/enums/index.js +18 -0
- package/dist/types/enums/index.js.map +1 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +20 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +20 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/jwt.d.ts +5 -0
- package/dist/utils/jwt.d.ts.map +1 -0
- package/dist/utils/jwt.js +67 -0
- package/dist/utils/jwt.js.map +1 -0
- package/dist/utils/logger.d.ts +6 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +69 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/openapi.d.ts +9 -0
- package/dist/utils/openapi.d.ts.map +1 -0
- package/dist/utils/openapi.js +90 -0
- package/dist/utils/openapi.js.map +1 -0
- package/dist/utils/validation.d.ts +12 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +108 -0
- package/dist/utils/validation.js.map +1 -0
- package/index.ts +4 -0
- package/logs/combined.log +85182 -0
- package/logs/error.log +48814 -0
- package/middleware/admin-auth.ts +93 -0
- package/middleware/auth.ts +100 -0
- package/middleware/cors.ts +48 -0
- package/middleware/errorHandler.ts +62 -0
- package/middleware/index.ts +8 -0
- package/middleware/internalAuth.ts +25 -0
- package/middleware/rateLimiter.ts +18 -0
- package/middleware/swagger.ts +69 -0
- package/middleware/validation.ts +24 -0
- package/package.json +43 -0
- package/public/swagger.css +114 -0
- package/tsconfig.json +10 -0
- package/types/admin-auth.ts +47 -0
- package/types/auth.ts +66 -0
- package/types/enums/auth.ts +6 -0
- package/types/enums/index.ts +1 -0
- package/types/index.ts +3 -0
- package/utils/index.ts +3 -0
- package/utils/jwt.ts +66 -0
- package/utils/logger.ts +90 -0
- package/utils/openapi.ts +125 -0
|
@@ -0,0 +1,4417 @@
|
|
|
1
|
+
import swaggerJsdoc from "swagger-jsdoc";
|
|
2
|
+
import { Request, Response } from "express";
|
|
3
|
+
|
|
4
|
+
const options = {
|
|
5
|
+
definition: {
|
|
6
|
+
openapi: "3.0.0",
|
|
7
|
+
info: {
|
|
8
|
+
title: "GGCoach API",
|
|
9
|
+
version: "1.0.0",
|
|
10
|
+
description:
|
|
11
|
+
"Comprehensive API documentation for GGCoach microservices platform",
|
|
12
|
+
contact: {
|
|
13
|
+
name: "Shadi Makhoul",
|
|
14
|
+
email: "shadimakhoul570@gmail.com",
|
|
15
|
+
},
|
|
16
|
+
license: {
|
|
17
|
+
name: "ISC",
|
|
18
|
+
url: "https://opensource.org/licenses/ISC",
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
servers: [
|
|
22
|
+
{
|
|
23
|
+
url: "http://localhost:4000",
|
|
24
|
+
description: "Development API Gateway Server",
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
url: "https://gg.staging.brainexy.com",
|
|
28
|
+
description: "Staging API Gateway Server",
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
components: {
|
|
32
|
+
securitySchemes: {
|
|
33
|
+
bearerAuth: {
|
|
34
|
+
type: "http",
|
|
35
|
+
scheme: "bearer",
|
|
36
|
+
bearerFormat: "JWT",
|
|
37
|
+
description:
|
|
38
|
+
'JWT Authorization header using the Bearer scheme. Example: "Authorization: Bearer {token}"',
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
schemas: {
|
|
42
|
+
User: {
|
|
43
|
+
type: "object",
|
|
44
|
+
properties: {
|
|
45
|
+
id: {
|
|
46
|
+
type: "integer",
|
|
47
|
+
description: "User unique identifier",
|
|
48
|
+
example: 1,
|
|
49
|
+
},
|
|
50
|
+
firstName: {
|
|
51
|
+
type: "string",
|
|
52
|
+
description: "User first name",
|
|
53
|
+
example: "John",
|
|
54
|
+
minLength: 2,
|
|
55
|
+
maxLength: 100,
|
|
56
|
+
},
|
|
57
|
+
lastName: {
|
|
58
|
+
type: "string",
|
|
59
|
+
description: "User last name",
|
|
60
|
+
example: "Doe",
|
|
61
|
+
minLength: 2,
|
|
62
|
+
maxLength: 100,
|
|
63
|
+
},
|
|
64
|
+
email: {
|
|
65
|
+
type: "string",
|
|
66
|
+
format: "email",
|
|
67
|
+
description: "User email address",
|
|
68
|
+
example: "john.doe@example.com",
|
|
69
|
+
},
|
|
70
|
+
phoneNumber: {
|
|
71
|
+
type: "string",
|
|
72
|
+
description: "User phone number",
|
|
73
|
+
example: "+1234567890",
|
|
74
|
+
pattern: "^[\\+]?[1-9][\\d]{0,15}$",
|
|
75
|
+
},
|
|
76
|
+
accountType: {
|
|
77
|
+
type: "string",
|
|
78
|
+
description: "Type of account",
|
|
79
|
+
enum: ["Client", "Provider", "Admin", "SuperAdmin"],
|
|
80
|
+
example: "Client",
|
|
81
|
+
},
|
|
82
|
+
is_active: {
|
|
83
|
+
type: "boolean",
|
|
84
|
+
description: "User account status",
|
|
85
|
+
example: true,
|
|
86
|
+
},
|
|
87
|
+
created_at: {
|
|
88
|
+
type: "string",
|
|
89
|
+
format: "date-time",
|
|
90
|
+
description: "Account creation timestamp",
|
|
91
|
+
example: "2024-01-15T10:30:00.000Z",
|
|
92
|
+
},
|
|
93
|
+
updated_at: {
|
|
94
|
+
type: "string",
|
|
95
|
+
format: "date-time",
|
|
96
|
+
description: "Last update timestamp",
|
|
97
|
+
example: "2024-01-15T10:30:00.000Z",
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
required: ["id", "firstName", "lastName", "email", "accountType", "is_active"],
|
|
101
|
+
},
|
|
102
|
+
UserSignup: {
|
|
103
|
+
type: "object",
|
|
104
|
+
properties: {
|
|
105
|
+
firstName: {
|
|
106
|
+
type: "string",
|
|
107
|
+
description: "User first name",
|
|
108
|
+
example: "John",
|
|
109
|
+
minLength: 2,
|
|
110
|
+
maxLength: 100,
|
|
111
|
+
},
|
|
112
|
+
lastName: {
|
|
113
|
+
type: "string",
|
|
114
|
+
description: "User last name",
|
|
115
|
+
example: "Doe",
|
|
116
|
+
minLength: 2,
|
|
117
|
+
maxLength: 100,
|
|
118
|
+
},
|
|
119
|
+
email: {
|
|
120
|
+
type: "string",
|
|
121
|
+
format: "email",
|
|
122
|
+
description: "User email address",
|
|
123
|
+
example: "john.doe@example.com",
|
|
124
|
+
},
|
|
125
|
+
phoneNumber: {
|
|
126
|
+
type: "string",
|
|
127
|
+
description: "User phone number",
|
|
128
|
+
example: "+1234567890",
|
|
129
|
+
pattern: "^[\\+]?[1-9][\\d]{0,15}$",
|
|
130
|
+
},
|
|
131
|
+
password: {
|
|
132
|
+
type: "string",
|
|
133
|
+
description: "User password",
|
|
134
|
+
example: "securePassword123",
|
|
135
|
+
minLength: 6,
|
|
136
|
+
maxLength: 255,
|
|
137
|
+
},
|
|
138
|
+
accountType: {
|
|
139
|
+
type: "string",
|
|
140
|
+
description: "Type of account to create",
|
|
141
|
+
enum: ["Client", "Provider", "Admin", "SuperAdmin"],
|
|
142
|
+
example: "Client",
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
required: ["firstName", "lastName", "email", "password", "accountType"],
|
|
146
|
+
},
|
|
147
|
+
UserSignin: {
|
|
148
|
+
type: "object",
|
|
149
|
+
properties: {
|
|
150
|
+
identifier: {
|
|
151
|
+
type: "string",
|
|
152
|
+
description: "Email address or phone number",
|
|
153
|
+
example: "john.doe@example.com",
|
|
154
|
+
},
|
|
155
|
+
password: {
|
|
156
|
+
type: "string",
|
|
157
|
+
description: "User password",
|
|
158
|
+
example: "securePassword123",
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
required: ["identifier", "password"],
|
|
162
|
+
},
|
|
163
|
+
RefreshToken: {
|
|
164
|
+
type: "object",
|
|
165
|
+
properties: {
|
|
166
|
+
refresh_token: {
|
|
167
|
+
type: "string",
|
|
168
|
+
description: "Refresh token for getting new access token",
|
|
169
|
+
example: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
required: ["refresh_token"],
|
|
173
|
+
},
|
|
174
|
+
ConfirmEmail: {
|
|
175
|
+
type: "object",
|
|
176
|
+
properties: {
|
|
177
|
+
token: {
|
|
178
|
+
type: "string",
|
|
179
|
+
description: "Email verification token",
|
|
180
|
+
example: "3b9a4c0f6b0b4c9e8a0f3a9d1f2a3b4c",
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
required: ["token"],
|
|
184
|
+
},
|
|
185
|
+
ResendConfirmation: {
|
|
186
|
+
type: "object",
|
|
187
|
+
properties: {
|
|
188
|
+
email: {
|
|
189
|
+
type: "string",
|
|
190
|
+
format: "email",
|
|
191
|
+
description: "User email address",
|
|
192
|
+
example: "john.doe@example.com",
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
required: ["email"],
|
|
196
|
+
},
|
|
197
|
+
ForgotPassword: {
|
|
198
|
+
type: "object",
|
|
199
|
+
properties: {
|
|
200
|
+
email: {
|
|
201
|
+
type: "string",
|
|
202
|
+
format: "email",
|
|
203
|
+
description: "User email address",
|
|
204
|
+
example: "john.doe@example.com",
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
required: ["email"],
|
|
208
|
+
},
|
|
209
|
+
ResetPassword: {
|
|
210
|
+
type: "object",
|
|
211
|
+
properties: {
|
|
212
|
+
token: {
|
|
213
|
+
type: "string",
|
|
214
|
+
description: "Password reset token",
|
|
215
|
+
example: "9f0e1d2c3b4a5f67890123456789abcd",
|
|
216
|
+
},
|
|
217
|
+
new_password: {
|
|
218
|
+
type: "string",
|
|
219
|
+
description: "New account password",
|
|
220
|
+
example: "securePassword123",
|
|
221
|
+
minLength: 6,
|
|
222
|
+
maxLength: 255,
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
required: ["token", "new_password"],
|
|
226
|
+
},
|
|
227
|
+
PhoneVerificationRequest: {
|
|
228
|
+
type: "object",
|
|
229
|
+
properties: {
|
|
230
|
+
phoneNumber: {
|
|
231
|
+
type: "string",
|
|
232
|
+
description: "User phone number",
|
|
233
|
+
example: "+1234567890",
|
|
234
|
+
pattern: "^[\\+]?[1-9][\\d]{0,15}$",
|
|
235
|
+
},
|
|
236
|
+
},
|
|
237
|
+
required: ["phoneNumber"],
|
|
238
|
+
},
|
|
239
|
+
PhoneVerificationConfirm: {
|
|
240
|
+
type: "object",
|
|
241
|
+
properties: {
|
|
242
|
+
phoneNumber: {
|
|
243
|
+
type: "string",
|
|
244
|
+
description: "User phone number",
|
|
245
|
+
example: "+1234567890",
|
|
246
|
+
pattern: "^[\\+]?[1-9][\\d]{0,15}$",
|
|
247
|
+
},
|
|
248
|
+
code: {
|
|
249
|
+
type: "string",
|
|
250
|
+
description: "Verification code",
|
|
251
|
+
example: "123456",
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
required: ["phoneNumber", "code"],
|
|
255
|
+
},
|
|
256
|
+
Tokens: {
|
|
257
|
+
type: "object",
|
|
258
|
+
properties: {
|
|
259
|
+
access_token: {
|
|
260
|
+
type: "string",
|
|
261
|
+
description: "JWT access token",
|
|
262
|
+
example: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
|
263
|
+
},
|
|
264
|
+
refresh_token: {
|
|
265
|
+
type: "string",
|
|
266
|
+
description: "JWT refresh token",
|
|
267
|
+
example: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
|
268
|
+
},
|
|
269
|
+
},
|
|
270
|
+
required: ["access_token", "refresh_token"],
|
|
271
|
+
},
|
|
272
|
+
AuthResponse: {
|
|
273
|
+
type: "object",
|
|
274
|
+
properties: {
|
|
275
|
+
success: {
|
|
276
|
+
type: "boolean",
|
|
277
|
+
description: "Request success status",
|
|
278
|
+
example: true,
|
|
279
|
+
},
|
|
280
|
+
message: {
|
|
281
|
+
type: "string",
|
|
282
|
+
description: "Response message",
|
|
283
|
+
example: "User created successfully",
|
|
284
|
+
},
|
|
285
|
+
data: {
|
|
286
|
+
type: "object",
|
|
287
|
+
properties: {
|
|
288
|
+
user: {
|
|
289
|
+
$ref: "#/components/schemas/User",
|
|
290
|
+
},
|
|
291
|
+
tokens: {
|
|
292
|
+
$ref: "#/components/schemas/Tokens",
|
|
293
|
+
},
|
|
294
|
+
},
|
|
295
|
+
},
|
|
296
|
+
error: {
|
|
297
|
+
type: "string",
|
|
298
|
+
description: "Error message (only in development)",
|
|
299
|
+
example: "Validation error",
|
|
300
|
+
},
|
|
301
|
+
},
|
|
302
|
+
required: ["success", "message"],
|
|
303
|
+
},
|
|
304
|
+
ErrorResponse: {
|
|
305
|
+
type: "object",
|
|
306
|
+
properties: {
|
|
307
|
+
success: {
|
|
308
|
+
type: "boolean",
|
|
309
|
+
description: "Request success status",
|
|
310
|
+
example: false,
|
|
311
|
+
},
|
|
312
|
+
message: {
|
|
313
|
+
type: "string",
|
|
314
|
+
description: "Error message",
|
|
315
|
+
example: "Invalid credentials",
|
|
316
|
+
},
|
|
317
|
+
error: {
|
|
318
|
+
type: "string",
|
|
319
|
+
description: "Detailed error message (only in development)",
|
|
320
|
+
example: "User not found",
|
|
321
|
+
},
|
|
322
|
+
},
|
|
323
|
+
required: ["success", "message"],
|
|
324
|
+
},
|
|
325
|
+
HealthResponse: {
|
|
326
|
+
type: "object",
|
|
327
|
+
properties: {
|
|
328
|
+
success: {
|
|
329
|
+
type: "boolean",
|
|
330
|
+
description: "Service health status",
|
|
331
|
+
example: true,
|
|
332
|
+
},
|
|
333
|
+
message: {
|
|
334
|
+
type: "string",
|
|
335
|
+
description: "Health check message",
|
|
336
|
+
example: "API Gateway is healthy",
|
|
337
|
+
},
|
|
338
|
+
timestamp: {
|
|
339
|
+
type: "string",
|
|
340
|
+
format: "date-time",
|
|
341
|
+
description: "Response timestamp",
|
|
342
|
+
example: "2024-01-15T10:30:00.000Z",
|
|
343
|
+
},
|
|
344
|
+
service: {
|
|
345
|
+
type: "string",
|
|
346
|
+
description: "Service name",
|
|
347
|
+
example: "api-gateway",
|
|
348
|
+
},
|
|
349
|
+
version: {
|
|
350
|
+
type: "string",
|
|
351
|
+
description: "Service version",
|
|
352
|
+
example: "1.0.0",
|
|
353
|
+
},
|
|
354
|
+
},
|
|
355
|
+
required: ["success", "message", "timestamp", "service", "version"],
|
|
356
|
+
},
|
|
357
|
+
ServiceStatus: {
|
|
358
|
+
type: "object",
|
|
359
|
+
properties: {
|
|
360
|
+
success: {
|
|
361
|
+
type: "boolean",
|
|
362
|
+
description: "Request success status",
|
|
363
|
+
example: true,
|
|
364
|
+
},
|
|
365
|
+
message: {
|
|
366
|
+
type: "string",
|
|
367
|
+
description: "Status message",
|
|
368
|
+
example: "Service status retrieved",
|
|
369
|
+
},
|
|
370
|
+
data: {
|
|
371
|
+
type: "object",
|
|
372
|
+
properties: {
|
|
373
|
+
services: {
|
|
374
|
+
type: "object",
|
|
375
|
+
properties: {
|
|
376
|
+
gateway: {
|
|
377
|
+
type: "object",
|
|
378
|
+
properties: {
|
|
379
|
+
name: {
|
|
380
|
+
type: "string",
|
|
381
|
+
example: "api-gateway",
|
|
382
|
+
},
|
|
383
|
+
status: {
|
|
384
|
+
type: "string",
|
|
385
|
+
example: "healthy",
|
|
386
|
+
},
|
|
387
|
+
url: {
|
|
388
|
+
type: "string",
|
|
389
|
+
example: "http://localhost:4000",
|
|
390
|
+
},
|
|
391
|
+
},
|
|
392
|
+
},
|
|
393
|
+
auth: {
|
|
394
|
+
type: "object",
|
|
395
|
+
properties: {
|
|
396
|
+
name: {
|
|
397
|
+
type: "string",
|
|
398
|
+
example: "auth-service",
|
|
399
|
+
},
|
|
400
|
+
status: {
|
|
401
|
+
type: "string",
|
|
402
|
+
example: "healthy",
|
|
403
|
+
},
|
|
404
|
+
url: {
|
|
405
|
+
type: "string",
|
|
406
|
+
example: "http://localhost:4001",
|
|
407
|
+
},
|
|
408
|
+
},
|
|
409
|
+
},
|
|
410
|
+
},
|
|
411
|
+
},
|
|
412
|
+
timestamp: {
|
|
413
|
+
type: "string",
|
|
414
|
+
format: "date-time",
|
|
415
|
+
example: "2024-01-15T10:30:00.000Z",
|
|
416
|
+
},
|
|
417
|
+
},
|
|
418
|
+
},
|
|
419
|
+
},
|
|
420
|
+
},
|
|
421
|
+
UserProfile: {
|
|
422
|
+
type: "object",
|
|
423
|
+
properties: {
|
|
424
|
+
id: { type: "integer", example: 1 },
|
|
425
|
+
userId: {
|
|
426
|
+
type: "integer",
|
|
427
|
+
description: "Related user id",
|
|
428
|
+
example: 1,
|
|
429
|
+
},
|
|
430
|
+
birthday: { type: "string", format: "date", example: "1990-05-20" },
|
|
431
|
+
gender: {
|
|
432
|
+
type: "string",
|
|
433
|
+
example: "male",
|
|
434
|
+
enum: ["male", "female", "other"],
|
|
435
|
+
},
|
|
436
|
+
height: {
|
|
437
|
+
type: "number",
|
|
438
|
+
description: "Height in centimeters",
|
|
439
|
+
example: 180,
|
|
440
|
+
},
|
|
441
|
+
weight: {
|
|
442
|
+
type: "number",
|
|
443
|
+
description: "Weight in kilograms",
|
|
444
|
+
example: 75,
|
|
445
|
+
},
|
|
446
|
+
avatar: {
|
|
447
|
+
type: "string",
|
|
448
|
+
description: "Avatar file URL",
|
|
449
|
+
example:
|
|
450
|
+
"gg.staging.brainexy.com/uploads/avatar/1768735674627-779883386.jpg",
|
|
451
|
+
},
|
|
452
|
+
created_at: {
|
|
453
|
+
type: "string",
|
|
454
|
+
format: "date-time",
|
|
455
|
+
example: "2024-01-15T10:30:00.000Z",
|
|
456
|
+
},
|
|
457
|
+
updated_at: {
|
|
458
|
+
type: "string",
|
|
459
|
+
format: "date-time",
|
|
460
|
+
example: "2024-01-15T10:30:00.000Z",
|
|
461
|
+
},
|
|
462
|
+
},
|
|
463
|
+
},
|
|
464
|
+
ProfileResponse: {
|
|
465
|
+
type: "object",
|
|
466
|
+
properties: {
|
|
467
|
+
success: { type: "boolean", example: true },
|
|
468
|
+
message: { type: "string", example: "Profile created" },
|
|
469
|
+
data: {
|
|
470
|
+
type: "object",
|
|
471
|
+
properties: {
|
|
472
|
+
profile: { $ref: "#/components/schemas/UserProfile" },
|
|
473
|
+
},
|
|
474
|
+
},
|
|
475
|
+
},
|
|
476
|
+
},
|
|
477
|
+
Media: {
|
|
478
|
+
type: "object",
|
|
479
|
+
properties: {
|
|
480
|
+
id: { type: "integer", example: 1 },
|
|
481
|
+
filename: {
|
|
482
|
+
type: "string",
|
|
483
|
+
description: "Media file name",
|
|
484
|
+
example: "avatar-1609459200000.png",
|
|
485
|
+
},
|
|
486
|
+
originalName: {
|
|
487
|
+
type: "string",
|
|
488
|
+
description: "Original file name",
|
|
489
|
+
example: "avatar.png",
|
|
490
|
+
},
|
|
491
|
+
mimetype: {
|
|
492
|
+
type: "string",
|
|
493
|
+
description: "File MIME type",
|
|
494
|
+
example: "image/png",
|
|
495
|
+
},
|
|
496
|
+
size: {
|
|
497
|
+
type: "integer",
|
|
498
|
+
description: "File size in bytes",
|
|
499
|
+
example: 102400,
|
|
500
|
+
},
|
|
501
|
+
path: {
|
|
502
|
+
type: "string",
|
|
503
|
+
description: "File storage path",
|
|
504
|
+
example: "/uploads/avatar/avatar-1609459200000.png",
|
|
505
|
+
},
|
|
506
|
+
userId: {
|
|
507
|
+
type: "integer",
|
|
508
|
+
description: "User who uploaded the file",
|
|
509
|
+
example: 1,
|
|
510
|
+
},
|
|
511
|
+
type: {
|
|
512
|
+
type: "string",
|
|
513
|
+
description: "Media type (avatar or private)",
|
|
514
|
+
enum: ["avatar", "private"],
|
|
515
|
+
example: "avatar",
|
|
516
|
+
},
|
|
517
|
+
created_at: {
|
|
518
|
+
type: "string",
|
|
519
|
+
format: "date-time",
|
|
520
|
+
example: "2024-01-15T10:30:00.000Z",
|
|
521
|
+
},
|
|
522
|
+
updated_at: {
|
|
523
|
+
type: "string",
|
|
524
|
+
format: "date-time",
|
|
525
|
+
example: "2024-01-15T10:30:00.000Z",
|
|
526
|
+
},
|
|
527
|
+
},
|
|
528
|
+
},
|
|
529
|
+
MediaResponse: {
|
|
530
|
+
type: "object",
|
|
531
|
+
properties: {
|
|
532
|
+
success: { type: "boolean", example: true },
|
|
533
|
+
message: { type: "string", example: "File uploaded successfully" },
|
|
534
|
+
data: {
|
|
535
|
+
type: "object",
|
|
536
|
+
properties: { media: { $ref: "#/components/schemas/Media" } },
|
|
537
|
+
},
|
|
538
|
+
},
|
|
539
|
+
},
|
|
540
|
+
UserSpecializationProfile: {
|
|
541
|
+
type: "object",
|
|
542
|
+
properties: {
|
|
543
|
+
userId: {
|
|
544
|
+
type: "integer",
|
|
545
|
+
description: "User ID associated with this specialization",
|
|
546
|
+
example: 1,
|
|
547
|
+
},
|
|
548
|
+
specializationId: {
|
|
549
|
+
type: "integer",
|
|
550
|
+
description: "Specialization ID assigned to the user",
|
|
551
|
+
example: 2,
|
|
552
|
+
},
|
|
553
|
+
specializationName: {
|
|
554
|
+
type: "string",
|
|
555
|
+
nullable: true,
|
|
556
|
+
description: "Name of the specialization",
|
|
557
|
+
example: "Doctor",
|
|
558
|
+
},
|
|
559
|
+
},
|
|
560
|
+
required: ["userId", "specializationId", "specializationName"],
|
|
561
|
+
},
|
|
562
|
+
UserSpecializationProfileResponse: {
|
|
563
|
+
type: "object",
|
|
564
|
+
properties: {
|
|
565
|
+
success: { type: "boolean", example: true },
|
|
566
|
+
message: { type: "string", example: "User specialization profile retrieved successfully" },
|
|
567
|
+
data: {
|
|
568
|
+
oneOf: [
|
|
569
|
+
{ $ref: "#/components/schemas/UserSpecializationProfile" },
|
|
570
|
+
{
|
|
571
|
+
type: "array",
|
|
572
|
+
items: { $ref: "#/components/schemas/UserSpecializationProfile" },
|
|
573
|
+
},
|
|
574
|
+
],
|
|
575
|
+
},
|
|
576
|
+
},
|
|
577
|
+
required: ["success", "message"],
|
|
578
|
+
},
|
|
579
|
+
UserMetadata: {
|
|
580
|
+
type: "object",
|
|
581
|
+
description: "Flexible JSON object storing user-specific metadata, preferences, and settings",
|
|
582
|
+
additionalProperties: true,
|
|
583
|
+
example: {
|
|
584
|
+
theme: "dark",
|
|
585
|
+
language: "en",
|
|
586
|
+
notifications: {
|
|
587
|
+
email: true,
|
|
588
|
+
push: false
|
|
589
|
+
},
|
|
590
|
+
customField: "customValue"
|
|
591
|
+
}
|
|
592
|
+
},
|
|
593
|
+
UserMetadataResponse: {
|
|
594
|
+
type: "object",
|
|
595
|
+
properties: {
|
|
596
|
+
success: { type: "boolean", example: true },
|
|
597
|
+
message: { type: "string", example: "Metadata retrieved successfully" },
|
|
598
|
+
data: {
|
|
599
|
+
oneOf: [
|
|
600
|
+
{ $ref: "#/components/schemas/UserMetadata" },
|
|
601
|
+
{
|
|
602
|
+
type: "object",
|
|
603
|
+
description: "Single metadata field response",
|
|
604
|
+
additionalProperties: true,
|
|
605
|
+
example: { theme: "dark" }
|
|
606
|
+
}
|
|
607
|
+
]
|
|
608
|
+
}
|
|
609
|
+
},
|
|
610
|
+
required: ["success", "message"]
|
|
611
|
+
},
|
|
612
|
+
AppRole: {
|
|
613
|
+
type: "object",
|
|
614
|
+
properties: {
|
|
615
|
+
id: {
|
|
616
|
+
type: "integer",
|
|
617
|
+
description: "Role unique identifier",
|
|
618
|
+
example: 1,
|
|
619
|
+
},
|
|
620
|
+
name: {
|
|
621
|
+
type: "string",
|
|
622
|
+
description: "Role name",
|
|
623
|
+
example: "admin",
|
|
624
|
+
minLength: 2,
|
|
625
|
+
maxLength: 100,
|
|
626
|
+
},
|
|
627
|
+
description: {
|
|
628
|
+
type: "string",
|
|
629
|
+
description: "Role description",
|
|
630
|
+
example: "Administrator role with full system access",
|
|
631
|
+
nullable: true,
|
|
632
|
+
},
|
|
633
|
+
permissions: {
|
|
634
|
+
type: "array",
|
|
635
|
+
description: "Array of permissions assigned to this role",
|
|
636
|
+
items: {
|
|
637
|
+
type: "object",
|
|
638
|
+
properties: {
|
|
639
|
+
id: { type: "integer", example: 1 },
|
|
640
|
+
name: { type: "string", example: "users.manage" },
|
|
641
|
+
description: { type: "string", example: "Manage users" },
|
|
642
|
+
},
|
|
643
|
+
},
|
|
644
|
+
example: [
|
|
645
|
+
{ id: 1, name: "users.create", description: "Create users" },
|
|
646
|
+
{ id: 2, name: "users.update", description: "Update users" },
|
|
647
|
+
{ id: 3, name: "users.delete", description: "Delete users" },
|
|
648
|
+
],
|
|
649
|
+
},
|
|
650
|
+
isActive: {
|
|
651
|
+
type: "boolean",
|
|
652
|
+
description: "Role status",
|
|
653
|
+
example: true,
|
|
654
|
+
},
|
|
655
|
+
created_at: {
|
|
656
|
+
type: "string",
|
|
657
|
+
format: "date-time",
|
|
658
|
+
description: "Role creation timestamp",
|
|
659
|
+
example: "2024-01-15T10:30:00.000Z",
|
|
660
|
+
},
|
|
661
|
+
updated_at: {
|
|
662
|
+
type: "string",
|
|
663
|
+
format: "date-time",
|
|
664
|
+
description: "Last update timestamp",
|
|
665
|
+
example: "2024-01-15T10:30:00.000Z",
|
|
666
|
+
},
|
|
667
|
+
},
|
|
668
|
+
required: ["id", "name", "isActive"],
|
|
669
|
+
},
|
|
670
|
+
CreateAppRoleRequest: {
|
|
671
|
+
type: "object",
|
|
672
|
+
properties: {
|
|
673
|
+
name: {
|
|
674
|
+
type: "string",
|
|
675
|
+
description: "Role name",
|
|
676
|
+
example: "moderator",
|
|
677
|
+
minLength: 2,
|
|
678
|
+
maxLength: 100,
|
|
679
|
+
},
|
|
680
|
+
description: {
|
|
681
|
+
type: "string",
|
|
682
|
+
description: "Role description",
|
|
683
|
+
example: "Moderator role with limited access",
|
|
684
|
+
nullable: true,
|
|
685
|
+
},
|
|
686
|
+
permissions: {
|
|
687
|
+
type: "array",
|
|
688
|
+
description: "Array of permission IDs to assign to this role",
|
|
689
|
+
items: { type: "integer" },
|
|
690
|
+
example: [1, 2, 3],
|
|
691
|
+
},
|
|
692
|
+
isActive: {
|
|
693
|
+
type: "boolean",
|
|
694
|
+
description: "Role status (active or inactive)",
|
|
695
|
+
example: true,
|
|
696
|
+
default: true,
|
|
697
|
+
},
|
|
698
|
+
},
|
|
699
|
+
required: ["name"],
|
|
700
|
+
},
|
|
701
|
+
UpdateAppRoleRequest: {
|
|
702
|
+
type: "object",
|
|
703
|
+
properties: {
|
|
704
|
+
name: {
|
|
705
|
+
type: "string",
|
|
706
|
+
description: "Role name",
|
|
707
|
+
example: "moderator",
|
|
708
|
+
minLength: 2,
|
|
709
|
+
maxLength: 100,
|
|
710
|
+
},
|
|
711
|
+
description: {
|
|
712
|
+
type: "string",
|
|
713
|
+
description: "Role description",
|
|
714
|
+
example: "Updated moderator description",
|
|
715
|
+
nullable: true,
|
|
716
|
+
},
|
|
717
|
+
permissions: {
|
|
718
|
+
type: "array",
|
|
719
|
+
description: "Array of permission IDs to assign to this role",
|
|
720
|
+
items: { type: "integer" },
|
|
721
|
+
example: [1, 2, 3],
|
|
722
|
+
},
|
|
723
|
+
isActive: {
|
|
724
|
+
type: "boolean",
|
|
725
|
+
description: "Role status",
|
|
726
|
+
example: true,
|
|
727
|
+
},
|
|
728
|
+
},
|
|
729
|
+
},
|
|
730
|
+
AdminRoleResponse: {
|
|
731
|
+
type: "object",
|
|
732
|
+
properties: {
|
|
733
|
+
success: {
|
|
734
|
+
type: "boolean",
|
|
735
|
+
description: "Request success status",
|
|
736
|
+
example: true,
|
|
737
|
+
},
|
|
738
|
+
message: {
|
|
739
|
+
type: "string",
|
|
740
|
+
description: "Response message",
|
|
741
|
+
example: "Role created successfully",
|
|
742
|
+
},
|
|
743
|
+
data: {
|
|
744
|
+
oneOf: [
|
|
745
|
+
{ $ref: "#/components/schemas/AppRole" },
|
|
746
|
+
{
|
|
747
|
+
type: "array",
|
|
748
|
+
items: { $ref: "#/components/schemas/AppRole" },
|
|
749
|
+
},
|
|
750
|
+
],
|
|
751
|
+
},
|
|
752
|
+
},
|
|
753
|
+
required: ["success", "message"],
|
|
754
|
+
},
|
|
755
|
+
Specialization: {
|
|
756
|
+
type: "object",
|
|
757
|
+
properties: {
|
|
758
|
+
id: {
|
|
759
|
+
type: "integer",
|
|
760
|
+
description: "Specialization unique identifier",
|
|
761
|
+
example: 1,
|
|
762
|
+
},
|
|
763
|
+
name: {
|
|
764
|
+
type: "string",
|
|
765
|
+
description: "Specialization name",
|
|
766
|
+
example: "Doctor",
|
|
767
|
+
},
|
|
768
|
+
parentId: {
|
|
769
|
+
type: "integer",
|
|
770
|
+
nullable: true,
|
|
771
|
+
description: "Parent specialization ID (null for root)",
|
|
772
|
+
example: null,
|
|
773
|
+
},
|
|
774
|
+
description: {
|
|
775
|
+
type: "string",
|
|
776
|
+
nullable: true,
|
|
777
|
+
description: "Specialization description",
|
|
778
|
+
example: "Medical doctor specialization",
|
|
779
|
+
},
|
|
780
|
+
imageUrl: {
|
|
781
|
+
type: "string",
|
|
782
|
+
nullable: true,
|
|
783
|
+
description: "Specialization image URL",
|
|
784
|
+
example: "https://example.com/images/doctor.png",
|
|
785
|
+
},
|
|
786
|
+
created_at: {
|
|
787
|
+
type: "string",
|
|
788
|
+
format: "date-time",
|
|
789
|
+
description: "Creation timestamp",
|
|
790
|
+
example: "2024-01-15T10:30:00.000Z",
|
|
791
|
+
},
|
|
792
|
+
updated_at: {
|
|
793
|
+
type: "string",
|
|
794
|
+
format: "date-time",
|
|
795
|
+
description: "Last update timestamp",
|
|
796
|
+
example: "2024-01-15T10:30:00.000Z",
|
|
797
|
+
},
|
|
798
|
+
},
|
|
799
|
+
required: ["id", "name"],
|
|
800
|
+
},
|
|
801
|
+
SpecializationTree: {
|
|
802
|
+
type: "object",
|
|
803
|
+
properties: {
|
|
804
|
+
id: {
|
|
805
|
+
type: "integer",
|
|
806
|
+
description: "Specialization unique identifier",
|
|
807
|
+
example: 1,
|
|
808
|
+
},
|
|
809
|
+
name: {
|
|
810
|
+
type: "string",
|
|
811
|
+
description: "Specialization name",
|
|
812
|
+
example: "Health",
|
|
813
|
+
},
|
|
814
|
+
description: {
|
|
815
|
+
type: "string",
|
|
816
|
+
nullable: true,
|
|
817
|
+
description: "Specialization description",
|
|
818
|
+
example: "Health specialization category",
|
|
819
|
+
},
|
|
820
|
+
imageUrl: {
|
|
821
|
+
type: "string",
|
|
822
|
+
nullable: true,
|
|
823
|
+
description: "Specialization image URL",
|
|
824
|
+
example: "https://example.com/images/health.png",
|
|
825
|
+
},
|
|
826
|
+
created_at: {
|
|
827
|
+
type: "string",
|
|
828
|
+
format: "date-time",
|
|
829
|
+
description: "Creation timestamp",
|
|
830
|
+
example: "2024-01-15T10:30:00.000Z",
|
|
831
|
+
},
|
|
832
|
+
updated_at: {
|
|
833
|
+
type: "string",
|
|
834
|
+
format: "date-time",
|
|
835
|
+
description: "Last update timestamp",
|
|
836
|
+
example: "2024-01-15T10:30:00.000Z",
|
|
837
|
+
},
|
|
838
|
+
children: {
|
|
839
|
+
type: "array",
|
|
840
|
+
description: "Child specializations",
|
|
841
|
+
items: {
|
|
842
|
+
type: "object",
|
|
843
|
+
properties: {
|
|
844
|
+
id: { type: "integer" },
|
|
845
|
+
name: { type: "string" },
|
|
846
|
+
description: { type: "string", nullable: true },
|
|
847
|
+
imageUrl: { type: "string", nullable: true },
|
|
848
|
+
created_at: { type: "string", format: "date-time" },
|
|
849
|
+
updated_at: { type: "string", format: "date-time" },
|
|
850
|
+
children: { type: "array" },
|
|
851
|
+
},
|
|
852
|
+
},
|
|
853
|
+
example: [
|
|
854
|
+
{
|
|
855
|
+
id: 2,
|
|
856
|
+
name: "Doctor",
|
|
857
|
+
description: "Medical doctor",
|
|
858
|
+
imageUrl: "https://example.com/images/doctor.png",
|
|
859
|
+
created_at: "2024-01-15T10:30:00.000Z",
|
|
860
|
+
updated_at: "2024-01-15T10:30:00.000Z",
|
|
861
|
+
children: [
|
|
862
|
+
{
|
|
863
|
+
id: 3,
|
|
864
|
+
name: "Dentist",
|
|
865
|
+
description: "Dental specialization",
|
|
866
|
+
imageUrl: "https://example.com/images/dentist.png",
|
|
867
|
+
created_at: "2024-01-15T10:30:00.000Z",
|
|
868
|
+
updated_at: "2024-01-15T10:30:00.000Z",
|
|
869
|
+
children: [],
|
|
870
|
+
},
|
|
871
|
+
],
|
|
872
|
+
},
|
|
873
|
+
],
|
|
874
|
+
},
|
|
875
|
+
},
|
|
876
|
+
required: ["id", "name"],
|
|
877
|
+
},
|
|
878
|
+
MarketingContact: {
|
|
879
|
+
type: "object",
|
|
880
|
+
properties: {
|
|
881
|
+
id: { type: "integer", example: 1 },
|
|
882
|
+
email: {
|
|
883
|
+
type: "string",
|
|
884
|
+
format: "email",
|
|
885
|
+
nullable: true,
|
|
886
|
+
example: "user@example.com",
|
|
887
|
+
},
|
|
888
|
+
phone: {
|
|
889
|
+
type: "string",
|
|
890
|
+
nullable: true,
|
|
891
|
+
example: "+1234567890",
|
|
892
|
+
},
|
|
893
|
+
status: {
|
|
894
|
+
type: "string",
|
|
895
|
+
enum: ["lead", "subscriber", "customer", "suppressed"],
|
|
896
|
+
example: "lead",
|
|
897
|
+
},
|
|
898
|
+
source: {
|
|
899
|
+
type: "string",
|
|
900
|
+
enum: ["fitness_app", "brainexy", "landing_page", "other"],
|
|
901
|
+
example: "landing_page",
|
|
902
|
+
},
|
|
903
|
+
created_at: {
|
|
904
|
+
type: "string",
|
|
905
|
+
format: "date-time",
|
|
906
|
+
example: "2024-01-15T10:30:00.000Z",
|
|
907
|
+
},
|
|
908
|
+
updated_at: {
|
|
909
|
+
type: "string",
|
|
910
|
+
format: "date-time",
|
|
911
|
+
example: "2024-01-15T10:30:00.000Z",
|
|
912
|
+
},
|
|
913
|
+
},
|
|
914
|
+
required: ["id", "status", "source"],
|
|
915
|
+
},
|
|
916
|
+
CreateMarketingContactRequest: {
|
|
917
|
+
type: "object",
|
|
918
|
+
properties: {
|
|
919
|
+
email: { type: "string", format: "email" },
|
|
920
|
+
phone: { type: "string" },
|
|
921
|
+
status: {
|
|
922
|
+
type: "string",
|
|
923
|
+
enum: ["lead", "subscriber", "customer", "suppressed"],
|
|
924
|
+
default: "lead",
|
|
925
|
+
},
|
|
926
|
+
source: {
|
|
927
|
+
type: "string",
|
|
928
|
+
enum: ["fitness_app", "brainexy", "landing_page", "other"],
|
|
929
|
+
default: "landing_page",
|
|
930
|
+
},
|
|
931
|
+
},
|
|
932
|
+
anyOf: [{ required: ["email"] }, { required: ["phone"] }],
|
|
933
|
+
},
|
|
934
|
+
MarketingConsent: {
|
|
935
|
+
type: "object",
|
|
936
|
+
properties: {
|
|
937
|
+
id: { type: "integer", example: 1 },
|
|
938
|
+
contact_id: { type: "integer", example: 1 },
|
|
939
|
+
channel: {
|
|
940
|
+
type: "string",
|
|
941
|
+
enum: ["email", "sms", "push"],
|
|
942
|
+
example: "email",
|
|
943
|
+
},
|
|
944
|
+
purpose: {
|
|
945
|
+
type: "string",
|
|
946
|
+
enum: ["marketing", "transactional"],
|
|
947
|
+
example: "marketing",
|
|
948
|
+
},
|
|
949
|
+
granted_at: {
|
|
950
|
+
type: "string",
|
|
951
|
+
format: "date-time",
|
|
952
|
+
example: "2024-01-15T10:30:00.000Z",
|
|
953
|
+
},
|
|
954
|
+
revoked_at: {
|
|
955
|
+
type: "string",
|
|
956
|
+
format: "date-time",
|
|
957
|
+
nullable: true,
|
|
958
|
+
example: null,
|
|
959
|
+
},
|
|
960
|
+
source: { type: "string", nullable: true, example: "landing_page" },
|
|
961
|
+
created_at: {
|
|
962
|
+
type: "string",
|
|
963
|
+
format: "date-time",
|
|
964
|
+
example: "2024-01-15T10:30:00.000Z",
|
|
965
|
+
},
|
|
966
|
+
updated_at: {
|
|
967
|
+
type: "string",
|
|
968
|
+
format: "date-time",
|
|
969
|
+
example: "2024-01-15T10:30:00.000Z",
|
|
970
|
+
},
|
|
971
|
+
},
|
|
972
|
+
required: ["id", "contact_id", "channel", "purpose", "granted_at"],
|
|
973
|
+
},
|
|
974
|
+
CreateMarketingConsentRequest: {
|
|
975
|
+
type: "object",
|
|
976
|
+
properties: {
|
|
977
|
+
contact_id: { type: "integer" },
|
|
978
|
+
channel: { type: "string", enum: ["email", "sms", "push"] },
|
|
979
|
+
purpose: { type: "string", enum: ["marketing", "transactional"] },
|
|
980
|
+
granted_at: { type: "string", format: "date-time" },
|
|
981
|
+
revoked_at: { type: "string", format: "date-time", nullable: true },
|
|
982
|
+
source: { type: "string", nullable: true },
|
|
983
|
+
},
|
|
984
|
+
required: ["contact_id", "channel", "purpose"],
|
|
985
|
+
},
|
|
986
|
+
SegmentCondition: {
|
|
987
|
+
type: "object",
|
|
988
|
+
properties: {
|
|
989
|
+
type: { type: "string", enum: ["condition"], example: "condition" },
|
|
990
|
+
field: {
|
|
991
|
+
type: "string",
|
|
992
|
+
enum: ["status", "source", "email", "phone", "created_at", "updated_at"],
|
|
993
|
+
},
|
|
994
|
+
op: {
|
|
995
|
+
type: "string",
|
|
996
|
+
enum: [
|
|
997
|
+
"eq",
|
|
998
|
+
"neq",
|
|
999
|
+
"in",
|
|
1000
|
+
"not_in",
|
|
1001
|
+
"contains",
|
|
1002
|
+
"starts_with",
|
|
1003
|
+
"ends_with",
|
|
1004
|
+
"gte",
|
|
1005
|
+
"lte",
|
|
1006
|
+
],
|
|
1007
|
+
},
|
|
1008
|
+
value: {
|
|
1009
|
+
oneOf: [
|
|
1010
|
+
{ type: "string" },
|
|
1011
|
+
{ type: "number" },
|
|
1012
|
+
{ type: "boolean" },
|
|
1013
|
+
{ type: "array", items: { oneOf: [{ type: "string" }, { type: "number" }] } },
|
|
1014
|
+
],
|
|
1015
|
+
},
|
|
1016
|
+
},
|
|
1017
|
+
required: ["type", "field", "op", "value"],
|
|
1018
|
+
},
|
|
1019
|
+
SegmentGroup: {
|
|
1020
|
+
type: "object",
|
|
1021
|
+
properties: {
|
|
1022
|
+
type: { type: "string", enum: ["group"], example: "group" },
|
|
1023
|
+
match: { type: "string", enum: ["all", "any"], example: "all" },
|
|
1024
|
+
children: {
|
|
1025
|
+
type: "array",
|
|
1026
|
+
items: { $ref: "#/components/schemas/SegmentNode" },
|
|
1027
|
+
},
|
|
1028
|
+
},
|
|
1029
|
+
required: ["type", "match", "children"],
|
|
1030
|
+
},
|
|
1031
|
+
SegmentNode: {
|
|
1032
|
+
oneOf: [
|
|
1033
|
+
{ $ref: "#/components/schemas/SegmentCondition" },
|
|
1034
|
+
{ $ref: "#/components/schemas/SegmentGroup" },
|
|
1035
|
+
],
|
|
1036
|
+
},
|
|
1037
|
+
MarketingSegment: {
|
|
1038
|
+
type: "object",
|
|
1039
|
+
properties: {
|
|
1040
|
+
id: { type: "integer", example: 1 },
|
|
1041
|
+
name: { type: "string", example: "New Leads" },
|
|
1042
|
+
definition: { $ref: "#/components/schemas/SegmentNode" },
|
|
1043
|
+
created_at: {
|
|
1044
|
+
type: "string",
|
|
1045
|
+
format: "date-time",
|
|
1046
|
+
example: "2024-01-15T10:30:00.000Z",
|
|
1047
|
+
},
|
|
1048
|
+
updated_at: {
|
|
1049
|
+
type: "string",
|
|
1050
|
+
format: "date-time",
|
|
1051
|
+
example: "2024-01-15T10:30:00.000Z",
|
|
1052
|
+
},
|
|
1053
|
+
},
|
|
1054
|
+
required: ["id", "name", "definition"],
|
|
1055
|
+
},
|
|
1056
|
+
CreateMarketingSegmentRequest: {
|
|
1057
|
+
type: "object",
|
|
1058
|
+
properties: {
|
|
1059
|
+
name: { type: "string", minLength: 2, maxLength: 100 },
|
|
1060
|
+
definition: { $ref: "#/components/schemas/SegmentNode" },
|
|
1061
|
+
},
|
|
1062
|
+
required: ["name", "definition"],
|
|
1063
|
+
},
|
|
1064
|
+
MarketingCampaign: {
|
|
1065
|
+
type: "object",
|
|
1066
|
+
properties: {
|
|
1067
|
+
id: { type: "integer", example: 1 },
|
|
1068
|
+
name: { type: "string", example: "Welcome Campaign" },
|
|
1069
|
+
channel: { type: "string", enum: ["email", "sms", "push"] },
|
|
1070
|
+
segment_id: { type: "integer", example: 1 },
|
|
1071
|
+
template_key: { type: "string", example: "welcome_v1" },
|
|
1072
|
+
schedule: { type: "object", nullable: true, additionalProperties: true },
|
|
1073
|
+
status: {
|
|
1074
|
+
type: "string",
|
|
1075
|
+
enum: ["draft", "active", "paused"],
|
|
1076
|
+
example: "draft",
|
|
1077
|
+
},
|
|
1078
|
+
created_at: {
|
|
1079
|
+
type: "string",
|
|
1080
|
+
format: "date-time",
|
|
1081
|
+
example: "2024-01-15T10:30:00.000Z",
|
|
1082
|
+
},
|
|
1083
|
+
updated_at: {
|
|
1084
|
+
type: "string",
|
|
1085
|
+
format: "date-time",
|
|
1086
|
+
example: "2024-01-15T10:30:00.000Z",
|
|
1087
|
+
},
|
|
1088
|
+
},
|
|
1089
|
+
required: ["id", "name", "channel", "segment_id", "template_key"],
|
|
1090
|
+
},
|
|
1091
|
+
CreateMarketingCampaignRequest: {
|
|
1092
|
+
type: "object",
|
|
1093
|
+
properties: {
|
|
1094
|
+
name: { type: "string", minLength: 2, maxLength: 150 },
|
|
1095
|
+
channel: { type: "string", enum: ["email", "sms", "push"] },
|
|
1096
|
+
segment_id: { type: "integer" },
|
|
1097
|
+
template_key: { type: "string", maxLength: 255 },
|
|
1098
|
+
schedule: { type: "object", additionalProperties: true },
|
|
1099
|
+
status: { type: "string", enum: ["draft", "active", "paused"], default: "draft" },
|
|
1100
|
+
},
|
|
1101
|
+
required: ["name", "channel", "segment_id", "template_key"],
|
|
1102
|
+
},
|
|
1103
|
+
MarketingCampaignRun: {
|
|
1104
|
+
type: "object",
|
|
1105
|
+
properties: {
|
|
1106
|
+
id: { type: "integer", example: 1 },
|
|
1107
|
+
campaign_id: { type: "integer", example: 1 },
|
|
1108
|
+
run_at: { type: "string", format: "date-time" },
|
|
1109
|
+
status: {
|
|
1110
|
+
type: "string",
|
|
1111
|
+
enum: ["running", "completed", "failed"],
|
|
1112
|
+
example: "running",
|
|
1113
|
+
},
|
|
1114
|
+
total_recipients: { type: "integer", example: 10 },
|
|
1115
|
+
success_count: { type: "integer", example: 10 },
|
|
1116
|
+
failure_count: { type: "integer", example: 0 },
|
|
1117
|
+
error: { type: "string", nullable: true, example: null },
|
|
1118
|
+
created_at: { type: "string", format: "date-time" },
|
|
1119
|
+
},
|
|
1120
|
+
required: ["id", "campaign_id", "run_at", "status"],
|
|
1121
|
+
},
|
|
1122
|
+
MarketingContactResponse: {
|
|
1123
|
+
type: "object",
|
|
1124
|
+
properties: {
|
|
1125
|
+
success: { type: "boolean", example: true },
|
|
1126
|
+
data: { $ref: "#/components/schemas/MarketingContact" },
|
|
1127
|
+
},
|
|
1128
|
+
required: ["success", "data"],
|
|
1129
|
+
},
|
|
1130
|
+
MarketingConsentResponse: {
|
|
1131
|
+
type: "object",
|
|
1132
|
+
properties: {
|
|
1133
|
+
success: { type: "boolean", example: true },
|
|
1134
|
+
data: { $ref: "#/components/schemas/MarketingConsent" },
|
|
1135
|
+
},
|
|
1136
|
+
required: ["success", "data"],
|
|
1137
|
+
},
|
|
1138
|
+
MarketingSegmentResponse: {
|
|
1139
|
+
type: "object",
|
|
1140
|
+
properties: {
|
|
1141
|
+
success: { type: "boolean", example: true },
|
|
1142
|
+
data: { $ref: "#/components/schemas/MarketingSegment" },
|
|
1143
|
+
},
|
|
1144
|
+
required: ["success", "data"],
|
|
1145
|
+
},
|
|
1146
|
+
MarketingCampaignResponse: {
|
|
1147
|
+
type: "object",
|
|
1148
|
+
properties: {
|
|
1149
|
+
success: { type: "boolean", example: true },
|
|
1150
|
+
data: { $ref: "#/components/schemas/MarketingCampaign" },
|
|
1151
|
+
},
|
|
1152
|
+
required: ["success", "data"],
|
|
1153
|
+
},
|
|
1154
|
+
MarketingCampaignRunResponse: {
|
|
1155
|
+
type: "object",
|
|
1156
|
+
properties: {
|
|
1157
|
+
success: { type: "boolean", example: true },
|
|
1158
|
+
data: { $ref: "#/components/schemas/MarketingCampaignRun" },
|
|
1159
|
+
},
|
|
1160
|
+
required: ["success", "data"],
|
|
1161
|
+
},
|
|
1162
|
+
MessagingMessage: {
|
|
1163
|
+
type: "object",
|
|
1164
|
+
properties: {
|
|
1165
|
+
id: { type: "integer", example: 1 },
|
|
1166
|
+
type: {
|
|
1167
|
+
type: "string",
|
|
1168
|
+
enum: ["transactional", "product", "marketing"],
|
|
1169
|
+
example: "marketing",
|
|
1170
|
+
},
|
|
1171
|
+
channel: {
|
|
1172
|
+
type: "string",
|
|
1173
|
+
enum: ["email", "sms", "push"],
|
|
1174
|
+
example: "email",
|
|
1175
|
+
},
|
|
1176
|
+
template_key: { type: "string", example: "welcome" },
|
|
1177
|
+
recipient: { type: "string", example: "user@example.com" },
|
|
1178
|
+
payload: { type: "object", additionalProperties: true },
|
|
1179
|
+
source_service: { type: "string", example: "marketing-service" },
|
|
1180
|
+
status: {
|
|
1181
|
+
type: "string",
|
|
1182
|
+
enum: ["pending", "sent", "failed"],
|
|
1183
|
+
example: "pending",
|
|
1184
|
+
},
|
|
1185
|
+
scheduled_at: {
|
|
1186
|
+
type: "string",
|
|
1187
|
+
format: "date-time",
|
|
1188
|
+
nullable: true,
|
|
1189
|
+
example: null,
|
|
1190
|
+
},
|
|
1191
|
+
sent_at: {
|
|
1192
|
+
type: "string",
|
|
1193
|
+
format: "date-time",
|
|
1194
|
+
nullable: true,
|
|
1195
|
+
example: null,
|
|
1196
|
+
},
|
|
1197
|
+
created_at: {
|
|
1198
|
+
type: "string",
|
|
1199
|
+
format: "date-time",
|
|
1200
|
+
example: "2024-01-15T10:30:00.000Z",
|
|
1201
|
+
},
|
|
1202
|
+
updated_at: {
|
|
1203
|
+
type: "string",
|
|
1204
|
+
format: "date-time",
|
|
1205
|
+
example: "2024-01-15T10:30:00.000Z",
|
|
1206
|
+
},
|
|
1207
|
+
},
|
|
1208
|
+
required: ["id", "type", "channel", "template_key", "recipient", "status"],
|
|
1209
|
+
},
|
|
1210
|
+
CreateMessagingMessageRequest: {
|
|
1211
|
+
type: "object",
|
|
1212
|
+
properties: {
|
|
1213
|
+
channel: { type: "string", enum: ["email", "sms", "push"] },
|
|
1214
|
+
type: { type: "string", enum: ["transactional", "product", "marketing"] },
|
|
1215
|
+
template_key: { type: "string" },
|
|
1216
|
+
recipient: { type: "string", format: "email" },
|
|
1217
|
+
payload: { type: "object", additionalProperties: true },
|
|
1218
|
+
source_service: { type: "string" },
|
|
1219
|
+
},
|
|
1220
|
+
required: ["channel", "type", "template_key", "recipient", "source_service"],
|
|
1221
|
+
},
|
|
1222
|
+
ScheduleMessagingMessageRequest: {
|
|
1223
|
+
type: "object",
|
|
1224
|
+
properties: {
|
|
1225
|
+
channel: { type: "string", enum: ["email", "sms", "push"] },
|
|
1226
|
+
type: { type: "string", enum: ["transactional", "product", "marketing"] },
|
|
1227
|
+
template_key: { type: "string" },
|
|
1228
|
+
recipient: { type: "string", format: "email" },
|
|
1229
|
+
payload: { type: "object", additionalProperties: true },
|
|
1230
|
+
source_service: { type: "string" },
|
|
1231
|
+
scheduled_at: { type: "string", format: "date-time" },
|
|
1232
|
+
},
|
|
1233
|
+
required: [
|
|
1234
|
+
"channel",
|
|
1235
|
+
"type",
|
|
1236
|
+
"template_key",
|
|
1237
|
+
"recipient",
|
|
1238
|
+
"source_service",
|
|
1239
|
+
"scheduled_at",
|
|
1240
|
+
],
|
|
1241
|
+
},
|
|
1242
|
+
MessagingAcceptedResponse: {
|
|
1243
|
+
type: "object",
|
|
1244
|
+
properties: {
|
|
1245
|
+
success: { type: "boolean", example: true },
|
|
1246
|
+
message: { type: "string", example: "Message accepted for processing" },
|
|
1247
|
+
data: {
|
|
1248
|
+
type: "object",
|
|
1249
|
+
properties: {
|
|
1250
|
+
message_id: { type: "integer", example: 1 },
|
|
1251
|
+
scheduled_at: { type: "string", format: "date-time", nullable: true },
|
|
1252
|
+
},
|
|
1253
|
+
},
|
|
1254
|
+
},
|
|
1255
|
+
required: ["success", "message", "data"],
|
|
1256
|
+
},
|
|
1257
|
+
MessagingMessageResponse: {
|
|
1258
|
+
type: "object",
|
|
1259
|
+
properties: {
|
|
1260
|
+
success: { type: "boolean", example: true },
|
|
1261
|
+
data: { $ref: "#/components/schemas/MessagingMessage" },
|
|
1262
|
+
},
|
|
1263
|
+
required: ["success", "data"],
|
|
1264
|
+
},
|
|
1265
|
+
},
|
|
1266
|
+
},
|
|
1267
|
+
// Centralized path definitions for endpoints that were previously declared inline in route files
|
|
1268
|
+
paths: {
|
|
1269
|
+
"/health": {
|
|
1270
|
+
get: {
|
|
1271
|
+
summary: "API Gateway Health Check",
|
|
1272
|
+
description:
|
|
1273
|
+
"Check if the API Gateway service is running and healthy",
|
|
1274
|
+
tags: ["Health"],
|
|
1275
|
+
responses: {
|
|
1276
|
+
"200": {
|
|
1277
|
+
description: "API Gateway is healthy",
|
|
1278
|
+
content: {
|
|
1279
|
+
"application/json": {
|
|
1280
|
+
schema: { $ref: "#/components/schemas/HealthResponse" },
|
|
1281
|
+
},
|
|
1282
|
+
},
|
|
1283
|
+
},
|
|
1284
|
+
"500": {
|
|
1285
|
+
description: "Internal server error",
|
|
1286
|
+
content: {
|
|
1287
|
+
"application/json": {
|
|
1288
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
1289
|
+
},
|
|
1290
|
+
},
|
|
1291
|
+
},
|
|
1292
|
+
},
|
|
1293
|
+
},
|
|
1294
|
+
},
|
|
1295
|
+
"/status": {
|
|
1296
|
+
get: {
|
|
1297
|
+
summary: "Service Status Overview",
|
|
1298
|
+
description:
|
|
1299
|
+
"Get the status of all microservices in the GGCoach platform",
|
|
1300
|
+
tags: ["Health"],
|
|
1301
|
+
responses: {
|
|
1302
|
+
"200": {
|
|
1303
|
+
description: "Service status retrieved successfully",
|
|
1304
|
+
content: {
|
|
1305
|
+
"application/json": {
|
|
1306
|
+
schema: { $ref: "#/components/schemas/ServiceStatus" },
|
|
1307
|
+
},
|
|
1308
|
+
},
|
|
1309
|
+
},
|
|
1310
|
+
"500": {
|
|
1311
|
+
description: "Internal server error",
|
|
1312
|
+
content: {
|
|
1313
|
+
"application/json": {
|
|
1314
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
1315
|
+
},
|
|
1316
|
+
},
|
|
1317
|
+
},
|
|
1318
|
+
},
|
|
1319
|
+
},
|
|
1320
|
+
},
|
|
1321
|
+
"/api/auth": {
|
|
1322
|
+
get: {
|
|
1323
|
+
summary: "Authentication proxy (root)",
|
|
1324
|
+
description:
|
|
1325
|
+
"Authentication service endpoints (proxied by the API Gateway). Use specific auth paths for signup/signin/refresh/profile under /api/auth/*.",
|
|
1326
|
+
tags: ["Authentication"],
|
|
1327
|
+
responses: {
|
|
1328
|
+
"200": { description: "Successful response from auth service" },
|
|
1329
|
+
"401": { description: "Unauthorized" },
|
|
1330
|
+
"500": { description: "Internal server error" },
|
|
1331
|
+
},
|
|
1332
|
+
},
|
|
1333
|
+
},
|
|
1334
|
+
"/api/auth/signup": {
|
|
1335
|
+
post: {
|
|
1336
|
+
summary: "User Registration",
|
|
1337
|
+
description: "Create a new user account with email and phone number",
|
|
1338
|
+
tags: ["Authentication"],
|
|
1339
|
+
requestBody: {
|
|
1340
|
+
required: true,
|
|
1341
|
+
content: {
|
|
1342
|
+
"application/json": {
|
|
1343
|
+
schema: { $ref: "#/components/schemas/UserSignup" },
|
|
1344
|
+
},
|
|
1345
|
+
},
|
|
1346
|
+
},
|
|
1347
|
+
responses: {
|
|
1348
|
+
"201": {
|
|
1349
|
+
description: "User created successfully",
|
|
1350
|
+
content: {
|
|
1351
|
+
"application/json": {
|
|
1352
|
+
schema: { $ref: "#/components/schemas/AuthResponse" },
|
|
1353
|
+
},
|
|
1354
|
+
},
|
|
1355
|
+
},
|
|
1356
|
+
"409": {
|
|
1357
|
+
description: "User already exists",
|
|
1358
|
+
content: {
|
|
1359
|
+
"application/json": {
|
|
1360
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
1361
|
+
},
|
|
1362
|
+
},
|
|
1363
|
+
},
|
|
1364
|
+
"400": {
|
|
1365
|
+
description: "Validation error",
|
|
1366
|
+
content: {
|
|
1367
|
+
"application/json": {
|
|
1368
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
1369
|
+
},
|
|
1370
|
+
},
|
|
1371
|
+
},
|
|
1372
|
+
"500": {
|
|
1373
|
+
description: "Internal server error",
|
|
1374
|
+
content: {
|
|
1375
|
+
"application/json": {
|
|
1376
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
1377
|
+
},
|
|
1378
|
+
},
|
|
1379
|
+
},
|
|
1380
|
+
},
|
|
1381
|
+
},
|
|
1382
|
+
},
|
|
1383
|
+
"/api/auth/signin": {
|
|
1384
|
+
post: {
|
|
1385
|
+
summary: "User Login",
|
|
1386
|
+
description: "Authenticate user with email/phone and password",
|
|
1387
|
+
tags: ["Authentication"],
|
|
1388
|
+
requestBody: {
|
|
1389
|
+
required: true,
|
|
1390
|
+
content: {
|
|
1391
|
+
"application/json": {
|
|
1392
|
+
schema: { $ref: "#/components/schemas/UserSignin" },
|
|
1393
|
+
},
|
|
1394
|
+
},
|
|
1395
|
+
},
|
|
1396
|
+
responses: {
|
|
1397
|
+
"200": {
|
|
1398
|
+
description: "Login successful",
|
|
1399
|
+
content: {
|
|
1400
|
+
"application/json": {
|
|
1401
|
+
schema: { $ref: "#/components/schemas/AuthResponse" },
|
|
1402
|
+
},
|
|
1403
|
+
},
|
|
1404
|
+
},
|
|
1405
|
+
"401": {
|
|
1406
|
+
description: "Invalid credentials or account deactivated",
|
|
1407
|
+
content: {
|
|
1408
|
+
"application/json": {
|
|
1409
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
1410
|
+
},
|
|
1411
|
+
},
|
|
1412
|
+
},
|
|
1413
|
+
"400": {
|
|
1414
|
+
description: "Validation error",
|
|
1415
|
+
content: {
|
|
1416
|
+
"application/json": {
|
|
1417
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
1418
|
+
},
|
|
1419
|
+
},
|
|
1420
|
+
},
|
|
1421
|
+
"500": {
|
|
1422
|
+
description: "Internal server error",
|
|
1423
|
+
content: {
|
|
1424
|
+
"application/json": {
|
|
1425
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
1426
|
+
},
|
|
1427
|
+
},
|
|
1428
|
+
},
|
|
1429
|
+
},
|
|
1430
|
+
},
|
|
1431
|
+
},
|
|
1432
|
+
"/api/auth/refresh-token": {
|
|
1433
|
+
post: {
|
|
1434
|
+
summary: "Refresh Access Token",
|
|
1435
|
+
description: "Get a new access token using refresh token",
|
|
1436
|
+
tags: ["Authentication"],
|
|
1437
|
+
requestBody: {
|
|
1438
|
+
required: true,
|
|
1439
|
+
content: {
|
|
1440
|
+
"application/json": {
|
|
1441
|
+
schema: { $ref: "#/components/schemas/RefreshToken" },
|
|
1442
|
+
},
|
|
1443
|
+
},
|
|
1444
|
+
},
|
|
1445
|
+
responses: {
|
|
1446
|
+
"200": {
|
|
1447
|
+
description: "Token refreshed successfully",
|
|
1448
|
+
content: { "application/json": { schema: { type: "object" } } },
|
|
1449
|
+
},
|
|
1450
|
+
"401": {
|
|
1451
|
+
description: "Invalid refresh token",
|
|
1452
|
+
content: {
|
|
1453
|
+
"application/json": {
|
|
1454
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
1455
|
+
},
|
|
1456
|
+
},
|
|
1457
|
+
},
|
|
1458
|
+
"400": {
|
|
1459
|
+
description: "Refresh token is required",
|
|
1460
|
+
content: {
|
|
1461
|
+
"application/json": {
|
|
1462
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
1463
|
+
},
|
|
1464
|
+
},
|
|
1465
|
+
},
|
|
1466
|
+
},
|
|
1467
|
+
},
|
|
1468
|
+
},
|
|
1469
|
+
"/api/auth/user": {
|
|
1470
|
+
get: {
|
|
1471
|
+
summary: "Get User Auth info",
|
|
1472
|
+
description: "Get current authenticated user's information",
|
|
1473
|
+
tags: ["Authentication"],
|
|
1474
|
+
security: [{ bearerAuth: [] }],
|
|
1475
|
+
responses: {
|
|
1476
|
+
"200": {
|
|
1477
|
+
description: "User retrieved successfully",
|
|
1478
|
+
content: {
|
|
1479
|
+
"application/json": {
|
|
1480
|
+
schema: { $ref: "#/components/schemas/AuthResponse" },
|
|
1481
|
+
},
|
|
1482
|
+
},
|
|
1483
|
+
},
|
|
1484
|
+
"401": {
|
|
1485
|
+
description: "Unauthorized - Invalid or missing token",
|
|
1486
|
+
content: {
|
|
1487
|
+
"application/json": {
|
|
1488
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
1489
|
+
},
|
|
1490
|
+
},
|
|
1491
|
+
},
|
|
1492
|
+
"404": {
|
|
1493
|
+
description: "User not found",
|
|
1494
|
+
content: {
|
|
1495
|
+
"application/json": {
|
|
1496
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
1497
|
+
},
|
|
1498
|
+
},
|
|
1499
|
+
},
|
|
1500
|
+
"500": {
|
|
1501
|
+
description: "Internal server error",
|
|
1502
|
+
content: {
|
|
1503
|
+
"application/json": {
|
|
1504
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
1505
|
+
},
|
|
1506
|
+
},
|
|
1507
|
+
},
|
|
1508
|
+
},
|
|
1509
|
+
},
|
|
1510
|
+
},
|
|
1511
|
+
"/api/auth/confirm-email": {
|
|
1512
|
+
post: {
|
|
1513
|
+
summary: "Confirm Email",
|
|
1514
|
+
description: "Confirm email address using a verification token",
|
|
1515
|
+
tags: ["Authentication"],
|
|
1516
|
+
requestBody: {
|
|
1517
|
+
required: true,
|
|
1518
|
+
content: {
|
|
1519
|
+
"application/json": {
|
|
1520
|
+
schema: { $ref: "#/components/schemas/ConfirmEmail" },
|
|
1521
|
+
},
|
|
1522
|
+
},
|
|
1523
|
+
},
|
|
1524
|
+
responses: {
|
|
1525
|
+
"200": {
|
|
1526
|
+
description: "Email confirmed successfully",
|
|
1527
|
+
content: {
|
|
1528
|
+
"application/json": {
|
|
1529
|
+
schema: { type: "object" },
|
|
1530
|
+
},
|
|
1531
|
+
},
|
|
1532
|
+
},
|
|
1533
|
+
"400": {
|
|
1534
|
+
description: "Invalid or expired token",
|
|
1535
|
+
content: {
|
|
1536
|
+
"application/json": {
|
|
1537
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
1538
|
+
},
|
|
1539
|
+
},
|
|
1540
|
+
},
|
|
1541
|
+
"404": {
|
|
1542
|
+
description: "User not found",
|
|
1543
|
+
content: {
|
|
1544
|
+
"application/json": {
|
|
1545
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
1546
|
+
},
|
|
1547
|
+
},
|
|
1548
|
+
},
|
|
1549
|
+
"500": {
|
|
1550
|
+
description: "Internal server error",
|
|
1551
|
+
content: {
|
|
1552
|
+
"application/json": {
|
|
1553
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
1554
|
+
},
|
|
1555
|
+
},
|
|
1556
|
+
},
|
|
1557
|
+
},
|
|
1558
|
+
},
|
|
1559
|
+
get: {
|
|
1560
|
+
summary: "Confirm Email (Query)",
|
|
1561
|
+
description: "Confirm email address using a token in query string",
|
|
1562
|
+
tags: ["Authentication"],
|
|
1563
|
+
parameters: [
|
|
1564
|
+
{
|
|
1565
|
+
name: "token",
|
|
1566
|
+
in: "query",
|
|
1567
|
+
required: true,
|
|
1568
|
+
schema: { type: "string" },
|
|
1569
|
+
description: "Email verification token",
|
|
1570
|
+
},
|
|
1571
|
+
],
|
|
1572
|
+
responses: {
|
|
1573
|
+
"200": {
|
|
1574
|
+
description: "Email confirmed successfully",
|
|
1575
|
+
content: {
|
|
1576
|
+
"application/json": {
|
|
1577
|
+
schema: { type: "object" },
|
|
1578
|
+
},
|
|
1579
|
+
},
|
|
1580
|
+
},
|
|
1581
|
+
"400": {
|
|
1582
|
+
description: "Invalid or expired token",
|
|
1583
|
+
content: {
|
|
1584
|
+
"application/json": {
|
|
1585
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
1586
|
+
},
|
|
1587
|
+
},
|
|
1588
|
+
},
|
|
1589
|
+
"404": {
|
|
1590
|
+
description: "User not found",
|
|
1591
|
+
content: {
|
|
1592
|
+
"application/json": {
|
|
1593
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
1594
|
+
},
|
|
1595
|
+
},
|
|
1596
|
+
},
|
|
1597
|
+
"500": {
|
|
1598
|
+
description: "Internal server error",
|
|
1599
|
+
content: {
|
|
1600
|
+
"application/json": {
|
|
1601
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
1602
|
+
},
|
|
1603
|
+
},
|
|
1604
|
+
},
|
|
1605
|
+
},
|
|
1606
|
+
},
|
|
1607
|
+
},
|
|
1608
|
+
"/api/auth/resend-confirmation": {
|
|
1609
|
+
post: {
|
|
1610
|
+
summary: "Resend Email Confirmation",
|
|
1611
|
+
description: "Resend the email confirmation link",
|
|
1612
|
+
tags: ["Authentication"],
|
|
1613
|
+
requestBody: {
|
|
1614
|
+
required: true,
|
|
1615
|
+
content: {
|
|
1616
|
+
"application/json": {
|
|
1617
|
+
schema: { $ref: "#/components/schemas/ResendConfirmation" },
|
|
1618
|
+
},
|
|
1619
|
+
},
|
|
1620
|
+
},
|
|
1621
|
+
responses: {
|
|
1622
|
+
"200": {
|
|
1623
|
+
description: "Confirmation email sent if the address exists",
|
|
1624
|
+
content: {
|
|
1625
|
+
"application/json": {
|
|
1626
|
+
schema: { type: "object" },
|
|
1627
|
+
},
|
|
1628
|
+
},
|
|
1629
|
+
},
|
|
1630
|
+
"400": {
|
|
1631
|
+
description: "Validation error",
|
|
1632
|
+
content: {
|
|
1633
|
+
"application/json": {
|
|
1634
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
1635
|
+
},
|
|
1636
|
+
},
|
|
1637
|
+
},
|
|
1638
|
+
"500": {
|
|
1639
|
+
description: "Internal server error",
|
|
1640
|
+
content: {
|
|
1641
|
+
"application/json": {
|
|
1642
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
1643
|
+
},
|
|
1644
|
+
},
|
|
1645
|
+
},
|
|
1646
|
+
},
|
|
1647
|
+
},
|
|
1648
|
+
},
|
|
1649
|
+
"/api/auth/password/forgot": {
|
|
1650
|
+
post: {
|
|
1651
|
+
summary: "Request Password Reset",
|
|
1652
|
+
description: "Request a password reset link",
|
|
1653
|
+
tags: ["Authentication"],
|
|
1654
|
+
requestBody: {
|
|
1655
|
+
required: true,
|
|
1656
|
+
content: {
|
|
1657
|
+
"application/json": {
|
|
1658
|
+
schema: { $ref: "#/components/schemas/ForgotPassword" },
|
|
1659
|
+
},
|
|
1660
|
+
},
|
|
1661
|
+
},
|
|
1662
|
+
responses: {
|
|
1663
|
+
"200": {
|
|
1664
|
+
description: "Reset link sent if the email exists",
|
|
1665
|
+
content: {
|
|
1666
|
+
"application/json": {
|
|
1667
|
+
schema: { type: "object" },
|
|
1668
|
+
},
|
|
1669
|
+
},
|
|
1670
|
+
},
|
|
1671
|
+
"400": {
|
|
1672
|
+
description: "Validation error",
|
|
1673
|
+
content: {
|
|
1674
|
+
"application/json": {
|
|
1675
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
1676
|
+
},
|
|
1677
|
+
},
|
|
1678
|
+
},
|
|
1679
|
+
"500": {
|
|
1680
|
+
description: "Internal server error",
|
|
1681
|
+
content: {
|
|
1682
|
+
"application/json": {
|
|
1683
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
1684
|
+
},
|
|
1685
|
+
},
|
|
1686
|
+
},
|
|
1687
|
+
},
|
|
1688
|
+
},
|
|
1689
|
+
},
|
|
1690
|
+
"/api/auth/password/reset": {
|
|
1691
|
+
post: {
|
|
1692
|
+
summary: "Reset Password",
|
|
1693
|
+
description: "Reset account password using a reset token",
|
|
1694
|
+
tags: ["Authentication"],
|
|
1695
|
+
requestBody: {
|
|
1696
|
+
required: true,
|
|
1697
|
+
content: {
|
|
1698
|
+
"application/json": {
|
|
1699
|
+
schema: { $ref: "#/components/schemas/ResetPassword" },
|
|
1700
|
+
},
|
|
1701
|
+
},
|
|
1702
|
+
},
|
|
1703
|
+
responses: {
|
|
1704
|
+
"200": {
|
|
1705
|
+
description: "Password reset successfully",
|
|
1706
|
+
content: {
|
|
1707
|
+
"application/json": {
|
|
1708
|
+
schema: { type: "object" },
|
|
1709
|
+
},
|
|
1710
|
+
},
|
|
1711
|
+
},
|
|
1712
|
+
"400": {
|
|
1713
|
+
description: "Invalid token or validation error",
|
|
1714
|
+
content: {
|
|
1715
|
+
"application/json": {
|
|
1716
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
1717
|
+
},
|
|
1718
|
+
},
|
|
1719
|
+
},
|
|
1720
|
+
"500": {
|
|
1721
|
+
description: "Internal server error",
|
|
1722
|
+
content: {
|
|
1723
|
+
"application/json": {
|
|
1724
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
1725
|
+
},
|
|
1726
|
+
},
|
|
1727
|
+
},
|
|
1728
|
+
},
|
|
1729
|
+
},
|
|
1730
|
+
},
|
|
1731
|
+
"/api/auth/phone/verify/request": {
|
|
1732
|
+
post: {
|
|
1733
|
+
summary: "Request Phone Verification",
|
|
1734
|
+
description: "Send a phone verification code",
|
|
1735
|
+
tags: ["Authentication"],
|
|
1736
|
+
requestBody: {
|
|
1737
|
+
required: true,
|
|
1738
|
+
content: {
|
|
1739
|
+
"application/json": {
|
|
1740
|
+
schema: { $ref: "#/components/schemas/PhoneVerificationRequest" },
|
|
1741
|
+
},
|
|
1742
|
+
},
|
|
1743
|
+
},
|
|
1744
|
+
responses: {
|
|
1745
|
+
"200": {
|
|
1746
|
+
description: "Verification code sent if the phone exists",
|
|
1747
|
+
content: {
|
|
1748
|
+
"application/json": {
|
|
1749
|
+
schema: { type: "object" },
|
|
1750
|
+
},
|
|
1751
|
+
},
|
|
1752
|
+
},
|
|
1753
|
+
"400": {
|
|
1754
|
+
description: "Validation error",
|
|
1755
|
+
content: {
|
|
1756
|
+
"application/json": {
|
|
1757
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
1758
|
+
},
|
|
1759
|
+
},
|
|
1760
|
+
},
|
|
1761
|
+
"500": {
|
|
1762
|
+
description: "Internal server error",
|
|
1763
|
+
content: {
|
|
1764
|
+
"application/json": {
|
|
1765
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
1766
|
+
},
|
|
1767
|
+
},
|
|
1768
|
+
},
|
|
1769
|
+
},
|
|
1770
|
+
},
|
|
1771
|
+
},
|
|
1772
|
+
"/api/auth/phone/verify/confirm": {
|
|
1773
|
+
post: {
|
|
1774
|
+
summary: "Confirm Phone Verification",
|
|
1775
|
+
description: "Confirm phone verification using a code",
|
|
1776
|
+
tags: ["Authentication"],
|
|
1777
|
+
requestBody: {
|
|
1778
|
+
required: true,
|
|
1779
|
+
content: {
|
|
1780
|
+
"application/json": {
|
|
1781
|
+
schema: { $ref: "#/components/schemas/PhoneVerificationConfirm" },
|
|
1782
|
+
},
|
|
1783
|
+
},
|
|
1784
|
+
},
|
|
1785
|
+
responses: {
|
|
1786
|
+
"200": {
|
|
1787
|
+
description: "Phone number verified successfully",
|
|
1788
|
+
content: {
|
|
1789
|
+
"application/json": {
|
|
1790
|
+
schema: { type: "object" },
|
|
1791
|
+
},
|
|
1792
|
+
},
|
|
1793
|
+
},
|
|
1794
|
+
"400": {
|
|
1795
|
+
description: "Invalid or expired verification code",
|
|
1796
|
+
content: {
|
|
1797
|
+
"application/json": {
|
|
1798
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
1799
|
+
},
|
|
1800
|
+
},
|
|
1801
|
+
},
|
|
1802
|
+
"404": {
|
|
1803
|
+
description: "User not found",
|
|
1804
|
+
content: {
|
|
1805
|
+
"application/json": {
|
|
1806
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
1807
|
+
},
|
|
1808
|
+
},
|
|
1809
|
+
},
|
|
1810
|
+
"500": {
|
|
1811
|
+
description: "Internal server error",
|
|
1812
|
+
content: {
|
|
1813
|
+
"application/json": {
|
|
1814
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
1815
|
+
},
|
|
1816
|
+
},
|
|
1817
|
+
},
|
|
1818
|
+
},
|
|
1819
|
+
},
|
|
1820
|
+
},
|
|
1821
|
+
"/api/user/profile": {
|
|
1822
|
+
get: {
|
|
1823
|
+
summary: "Get User Profile",
|
|
1824
|
+
description: "Get current user's profile information",
|
|
1825
|
+
tags: ["User"],
|
|
1826
|
+
security: [{ bearerAuth: [] }],
|
|
1827
|
+
responses: {
|
|
1828
|
+
"200": {
|
|
1829
|
+
description: "Profile retrieved successfully",
|
|
1830
|
+
content: {
|
|
1831
|
+
"application/json": {
|
|
1832
|
+
schema: { $ref: "#/components/schemas/ProfileResponse" },
|
|
1833
|
+
},
|
|
1834
|
+
},
|
|
1835
|
+
},
|
|
1836
|
+
"401": {
|
|
1837
|
+
description: "Unauthorized - Invalid or missing token",
|
|
1838
|
+
content: {
|
|
1839
|
+
"application/json": {
|
|
1840
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
1841
|
+
},
|
|
1842
|
+
},
|
|
1843
|
+
},
|
|
1844
|
+
"404": {
|
|
1845
|
+
description: "User not found",
|
|
1846
|
+
content: {
|
|
1847
|
+
"application/json": {
|
|
1848
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
1849
|
+
},
|
|
1850
|
+
},
|
|
1851
|
+
},
|
|
1852
|
+
"500": {
|
|
1853
|
+
description: "Internal server error",
|
|
1854
|
+
content: {
|
|
1855
|
+
"application/json": {
|
|
1856
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
1857
|
+
},
|
|
1858
|
+
},
|
|
1859
|
+
},
|
|
1860
|
+
},
|
|
1861
|
+
},
|
|
1862
|
+
post: {
|
|
1863
|
+
summary: "Create User Profile",
|
|
1864
|
+
description:
|
|
1865
|
+
"Create a profile for the authenticated user. Supports avatar upload (multipart/form-data).",
|
|
1866
|
+
tags: ["User"],
|
|
1867
|
+
security: [{ bearerAuth: [] }],
|
|
1868
|
+
requestBody: {
|
|
1869
|
+
required: true,
|
|
1870
|
+
content: {
|
|
1871
|
+
"application/json": {
|
|
1872
|
+
schema: {
|
|
1873
|
+
type: "object",
|
|
1874
|
+
properties: {
|
|
1875
|
+
birthday: { type: "string", format: "date" },
|
|
1876
|
+
gender: {
|
|
1877
|
+
type: "string",
|
|
1878
|
+
enum: ["male", "female", "other"],
|
|
1879
|
+
},
|
|
1880
|
+
height: { type: "number" },
|
|
1881
|
+
weight: { type: "number" },
|
|
1882
|
+
avatar: {
|
|
1883
|
+
type: "string",
|
|
1884
|
+
format: "string",
|
|
1885
|
+
description: "Avatar image path",
|
|
1886
|
+
},
|
|
1887
|
+
},
|
|
1888
|
+
},
|
|
1889
|
+
},
|
|
1890
|
+
},
|
|
1891
|
+
},
|
|
1892
|
+
responses: {
|
|
1893
|
+
"201": {
|
|
1894
|
+
description: "Profile created",
|
|
1895
|
+
content: {
|
|
1896
|
+
"application/json": {
|
|
1897
|
+
schema: { $ref: "#/components/schemas/ProfileResponse" },
|
|
1898
|
+
},
|
|
1899
|
+
},
|
|
1900
|
+
},
|
|
1901
|
+
"400": {
|
|
1902
|
+
description: "Validation error",
|
|
1903
|
+
content: {
|
|
1904
|
+
"application/json": {
|
|
1905
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
1906
|
+
},
|
|
1907
|
+
},
|
|
1908
|
+
},
|
|
1909
|
+
"401": {
|
|
1910
|
+
description: "Unauthorized",
|
|
1911
|
+
content: {
|
|
1912
|
+
"application/json": {
|
|
1913
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
1914
|
+
},
|
|
1915
|
+
},
|
|
1916
|
+
},
|
|
1917
|
+
"500": {
|
|
1918
|
+
description: "Internal server error",
|
|
1919
|
+
content: {
|
|
1920
|
+
"application/json": {
|
|
1921
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
1922
|
+
},
|
|
1923
|
+
},
|
|
1924
|
+
},
|
|
1925
|
+
},
|
|
1926
|
+
},
|
|
1927
|
+
put: {
|
|
1928
|
+
summary: "Update User Profile",
|
|
1929
|
+
description:
|
|
1930
|
+
"Update the authenticated user profile. Supports avatar upload (multipart/form-data).",
|
|
1931
|
+
tags: ["User"],
|
|
1932
|
+
security: [{ bearerAuth: [] }],
|
|
1933
|
+
requestBody: {
|
|
1934
|
+
required: false,
|
|
1935
|
+
content: {
|
|
1936
|
+
"application/json": {
|
|
1937
|
+
schema: {
|
|
1938
|
+
type: "object",
|
|
1939
|
+
properties: {
|
|
1940
|
+
birthday: { type: "string", format: "date" },
|
|
1941
|
+
gender: {
|
|
1942
|
+
type: "string",
|
|
1943
|
+
enum: ["male", "female", "other"],
|
|
1944
|
+
},
|
|
1945
|
+
height: { type: "number" },
|
|
1946
|
+
weight: { type: "number" },
|
|
1947
|
+
avatar: {
|
|
1948
|
+
type: "string",
|
|
1949
|
+
format: "string",
|
|
1950
|
+
description: "Avatar image path",
|
|
1951
|
+
},
|
|
1952
|
+
},
|
|
1953
|
+
},
|
|
1954
|
+
},
|
|
1955
|
+
},
|
|
1956
|
+
},
|
|
1957
|
+
responses: {
|
|
1958
|
+
"200": {
|
|
1959
|
+
description: "Profile updated",
|
|
1960
|
+
content: {
|
|
1961
|
+
"application/json": {
|
|
1962
|
+
schema: { $ref: "#/components/schemas/ProfileResponse" },
|
|
1963
|
+
},
|
|
1964
|
+
},
|
|
1965
|
+
},
|
|
1966
|
+
"400": {
|
|
1967
|
+
description: "Validation error",
|
|
1968
|
+
content: {
|
|
1969
|
+
"application/json": {
|
|
1970
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
1971
|
+
},
|
|
1972
|
+
},
|
|
1973
|
+
},
|
|
1974
|
+
"401": {
|
|
1975
|
+
description: "Unauthorized",
|
|
1976
|
+
content: {
|
|
1977
|
+
"application/json": {
|
|
1978
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
1979
|
+
},
|
|
1980
|
+
},
|
|
1981
|
+
},
|
|
1982
|
+
"404": {
|
|
1983
|
+
description: "Profile not found",
|
|
1984
|
+
content: {
|
|
1985
|
+
"application/json": {
|
|
1986
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
1987
|
+
},
|
|
1988
|
+
},
|
|
1989
|
+
},
|
|
1990
|
+
"500": {
|
|
1991
|
+
description: "Internal server error",
|
|
1992
|
+
content: {
|
|
1993
|
+
"application/json": {
|
|
1994
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
1995
|
+
},
|
|
1996
|
+
},
|
|
1997
|
+
},
|
|
1998
|
+
},
|
|
1999
|
+
},
|
|
2000
|
+
delete: {
|
|
2001
|
+
summary: "Delete User Profile",
|
|
2002
|
+
description: "Delete the authenticated user profile.",
|
|
2003
|
+
tags: ["User"],
|
|
2004
|
+
security: [{ bearerAuth: [] }],
|
|
2005
|
+
responses: {
|
|
2006
|
+
"200": {
|
|
2007
|
+
description: "Profile deleted",
|
|
2008
|
+
content: {
|
|
2009
|
+
"application/json": {
|
|
2010
|
+
schema: {
|
|
2011
|
+
type: "object",
|
|
2012
|
+
properties: {
|
|
2013
|
+
success: { type: "boolean" },
|
|
2014
|
+
message: { type: "string" },
|
|
2015
|
+
},
|
|
2016
|
+
},
|
|
2017
|
+
},
|
|
2018
|
+
},
|
|
2019
|
+
},
|
|
2020
|
+
"401": {
|
|
2021
|
+
description: "Unauthorized",
|
|
2022
|
+
content: {
|
|
2023
|
+
"application/json": {
|
|
2024
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
2025
|
+
},
|
|
2026
|
+
},
|
|
2027
|
+
},
|
|
2028
|
+
"404": {
|
|
2029
|
+
description: "Profile not found",
|
|
2030
|
+
content: {
|
|
2031
|
+
"application/json": {
|
|
2032
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
2033
|
+
},
|
|
2034
|
+
},
|
|
2035
|
+
},
|
|
2036
|
+
"500": {
|
|
2037
|
+
description: "Internal server error",
|
|
2038
|
+
content: {
|
|
2039
|
+
"application/json": {
|
|
2040
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
2041
|
+
},
|
|
2042
|
+
},
|
|
2043
|
+
},
|
|
2044
|
+
},
|
|
2045
|
+
},
|
|
2046
|
+
},
|
|
2047
|
+
"/api/user/admin/user-specialization": {
|
|
2048
|
+
get: {
|
|
2049
|
+
summary: "Get All User Specializations",
|
|
2050
|
+
description: "Retrieve all user specialization profiles (paginated). Authentication required.",
|
|
2051
|
+
tags: ["Admin User Specializations Profile"],
|
|
2052
|
+
security: [{ bearerAuth: [] }],
|
|
2053
|
+
responses: {
|
|
2054
|
+
"200": {
|
|
2055
|
+
description: "User specialization profiles retrieved successfully",
|
|
2056
|
+
content: {
|
|
2057
|
+
"application/json": {
|
|
2058
|
+
schema: { $ref: "#/components/schemas/UserSpecializationProfileResponse" },
|
|
2059
|
+
},
|
|
2060
|
+
},
|
|
2061
|
+
},
|
|
2062
|
+
"401": {
|
|
2063
|
+
description: "Unauthorized - Invalid or missing token",
|
|
2064
|
+
content: {
|
|
2065
|
+
"application/json": {
|
|
2066
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
2067
|
+
},
|
|
2068
|
+
},
|
|
2069
|
+
},
|
|
2070
|
+
"500": {
|
|
2071
|
+
description: "Internal server error",
|
|
2072
|
+
content: {
|
|
2073
|
+
"application/json": {
|
|
2074
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
2075
|
+
},
|
|
2076
|
+
},
|
|
2077
|
+
},
|
|
2078
|
+
},
|
|
2079
|
+
},
|
|
2080
|
+
},
|
|
2081
|
+
"/api/user/user-specialization": {
|
|
2082
|
+
post: {
|
|
2083
|
+
summary: "Create User Specializations",
|
|
2084
|
+
description: "Bulk create user specialization profiles. Accepts an array of specialization IDs. Authentication required.",
|
|
2085
|
+
tags: ["User Specializations Profile"],
|
|
2086
|
+
security: [{ bearerAuth: [] }],
|
|
2087
|
+
requestBody: {
|
|
2088
|
+
required: true,
|
|
2089
|
+
content: {
|
|
2090
|
+
"application/json": {
|
|
2091
|
+
schema: {
|
|
2092
|
+
type: "object",
|
|
2093
|
+
properties: {
|
|
2094
|
+
specializations: {
|
|
2095
|
+
type: "array",
|
|
2096
|
+
description: "Array of specialization IDs to assign to the user",
|
|
2097
|
+
items: {
|
|
2098
|
+
type: "integer"
|
|
2099
|
+
},
|
|
2100
|
+
example: [1, 2, 5],
|
|
2101
|
+
minItems: 1
|
|
2102
|
+
}
|
|
2103
|
+
},
|
|
2104
|
+
required: ["specializations"],
|
|
2105
|
+
},
|
|
2106
|
+
},
|
|
2107
|
+
},
|
|
2108
|
+
},
|
|
2109
|
+
responses: {
|
|
2110
|
+
"201": {
|
|
2111
|
+
description: "User specialization profile created successfully",
|
|
2112
|
+
content: {
|
|
2113
|
+
"application/json": {
|
|
2114
|
+
schema: { $ref: "#/components/schemas/UserSpecializationProfileResponse" },
|
|
2115
|
+
},
|
|
2116
|
+
},
|
|
2117
|
+
},
|
|
2118
|
+
"400": {
|
|
2119
|
+
description: "Validation error",
|
|
2120
|
+
content: {
|
|
2121
|
+
"application/json": {
|
|
2122
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
2123
|
+
},
|
|
2124
|
+
},
|
|
2125
|
+
},
|
|
2126
|
+
"401": {
|
|
2127
|
+
description: "Unauthorized - Invalid or missing token",
|
|
2128
|
+
content: {
|
|
2129
|
+
"application/json": {
|
|
2130
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
2131
|
+
},
|
|
2132
|
+
},
|
|
2133
|
+
},
|
|
2134
|
+
"500": {
|
|
2135
|
+
description: "Internal server error",
|
|
2136
|
+
content: {
|
|
2137
|
+
"application/json": {
|
|
2138
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
2139
|
+
},
|
|
2140
|
+
},
|
|
2141
|
+
},
|
|
2142
|
+
},
|
|
2143
|
+
},
|
|
2144
|
+
put: {
|
|
2145
|
+
summary: "Update User Specializations",
|
|
2146
|
+
description: "Replace all specializations for the authenticated user. Deletes existing specializations and creates new ones. Authentication required.",
|
|
2147
|
+
tags: ["User Specializations Profile"],
|
|
2148
|
+
security: [{ bearerAuth: [] }],
|
|
2149
|
+
requestBody: {
|
|
2150
|
+
required: true,
|
|
2151
|
+
content: {
|
|
2152
|
+
"application/json": {
|
|
2153
|
+
schema: {
|
|
2154
|
+
type: "object",
|
|
2155
|
+
properties: {
|
|
2156
|
+
specializations: {
|
|
2157
|
+
type: "array",
|
|
2158
|
+
description: "Array of specialization IDs to assign to the user",
|
|
2159
|
+
items: {
|
|
2160
|
+
type: "integer"
|
|
2161
|
+
},
|
|
2162
|
+
example: [3, 4, 6],
|
|
2163
|
+
minItems: 1
|
|
2164
|
+
}
|
|
2165
|
+
},
|
|
2166
|
+
required: ["specializations"],
|
|
2167
|
+
},
|
|
2168
|
+
},
|
|
2169
|
+
},
|
|
2170
|
+
},
|
|
2171
|
+
responses: {
|
|
2172
|
+
"200": {
|
|
2173
|
+
description: "User specializations updated successfully",
|
|
2174
|
+
content: {
|
|
2175
|
+
"application/json": {
|
|
2176
|
+
schema: { $ref: "#/components/schemas/UserSpecializationProfileResponse" },
|
|
2177
|
+
},
|
|
2178
|
+
},
|
|
2179
|
+
},
|
|
2180
|
+
"400": {
|
|
2181
|
+
description: "Validation error",
|
|
2182
|
+
content: {
|
|
2183
|
+
"application/json": {
|
|
2184
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
2185
|
+
},
|
|
2186
|
+
},
|
|
2187
|
+
},
|
|
2188
|
+
"401": {
|
|
2189
|
+
description: "Unauthorized - Invalid or missing token",
|
|
2190
|
+
content: {
|
|
2191
|
+
"application/json": {
|
|
2192
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
2193
|
+
},
|
|
2194
|
+
},
|
|
2195
|
+
},
|
|
2196
|
+
"500": {
|
|
2197
|
+
description: "Internal server error",
|
|
2198
|
+
content: {
|
|
2199
|
+
"application/json": {
|
|
2200
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
2201
|
+
},
|
|
2202
|
+
},
|
|
2203
|
+
},
|
|
2204
|
+
},
|
|
2205
|
+
},
|
|
2206
|
+
delete: {
|
|
2207
|
+
summary: "Delete User Specializations",
|
|
2208
|
+
description: "Delete all specializations for the authenticated user. Authentication required.",
|
|
2209
|
+
tags: ["User Specializations Profile"],
|
|
2210
|
+
security: [{ bearerAuth: [] }],
|
|
2211
|
+
responses: {
|
|
2212
|
+
"200": {
|
|
2213
|
+
description: "User specializations deleted successfully",
|
|
2214
|
+
content: {
|
|
2215
|
+
"application/json": {
|
|
2216
|
+
schema: {
|
|
2217
|
+
type: "object",
|
|
2218
|
+
properties: {
|
|
2219
|
+
success: { type: "boolean", example: true },
|
|
2220
|
+
message: { type: "string", example: "User specialization profile deleted successfully" },
|
|
2221
|
+
},
|
|
2222
|
+
},
|
|
2223
|
+
},
|
|
2224
|
+
},
|
|
2225
|
+
},
|
|
2226
|
+
"401": {
|
|
2227
|
+
description: "Unauthorized - Invalid or missing token",
|
|
2228
|
+
content: {
|
|
2229
|
+
"application/json": {
|
|
2230
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
2231
|
+
},
|
|
2232
|
+
},
|
|
2233
|
+
},
|
|
2234
|
+
"404": {
|
|
2235
|
+
description: "User specialization profile not found",
|
|
2236
|
+
content: {
|
|
2237
|
+
"application/json": {
|
|
2238
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
2239
|
+
},
|
|
2240
|
+
},
|
|
2241
|
+
},
|
|
2242
|
+
"500": {
|
|
2243
|
+
description: "Internal server error",
|
|
2244
|
+
content: {
|
|
2245
|
+
"application/json": {
|
|
2246
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
2247
|
+
},
|
|
2248
|
+
},
|
|
2249
|
+
},
|
|
2250
|
+
},
|
|
2251
|
+
},
|
|
2252
|
+
},
|
|
2253
|
+
"/api/user/user-specialization/me": {
|
|
2254
|
+
get: {
|
|
2255
|
+
summary: "Get Current User Specialization Profile",
|
|
2256
|
+
description: "Retrieve all specializations assigned to the authenticated user.",
|
|
2257
|
+
tags: ["User Specializations Profile"],
|
|
2258
|
+
security: [{ bearerAuth: [] }],
|
|
2259
|
+
responses: {
|
|
2260
|
+
"200": {
|
|
2261
|
+
description: "Current user specializations retrieved successfully",
|
|
2262
|
+
content: {
|
|
2263
|
+
"application/json": {
|
|
2264
|
+
schema: { $ref: "#/components/schemas/UserSpecializationProfileResponse" },
|
|
2265
|
+
},
|
|
2266
|
+
},
|
|
2267
|
+
},
|
|
2268
|
+
"401": {
|
|
2269
|
+
description: "Unauthorized - Invalid or missing token",
|
|
2270
|
+
content: {
|
|
2271
|
+
"application/json": {
|
|
2272
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
2273
|
+
},
|
|
2274
|
+
},
|
|
2275
|
+
},
|
|
2276
|
+
"500": {
|
|
2277
|
+
description: "Internal server error",
|
|
2278
|
+
content: {
|
|
2279
|
+
"application/json": {
|
|
2280
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
2281
|
+
},
|
|
2282
|
+
},
|
|
2283
|
+
},
|
|
2284
|
+
},
|
|
2285
|
+
},
|
|
2286
|
+
},
|
|
2287
|
+
"/api/user/admin/user-specialization/user/{userId}": {
|
|
2288
|
+
get: {
|
|
2289
|
+
summary: "Get User Specializations by User ID",
|
|
2290
|
+
description: "Retrieve all specializations assigned to a specific user. Authentication required.",
|
|
2291
|
+
tags: ["Admin User Specializations Profile"],
|
|
2292
|
+
security: [{ bearerAuth: [] }],
|
|
2293
|
+
parameters: [
|
|
2294
|
+
{
|
|
2295
|
+
name: "userId",
|
|
2296
|
+
in: "path",
|
|
2297
|
+
required: true,
|
|
2298
|
+
description: "User ID to retrieve specializations for",
|
|
2299
|
+
schema: { type: "integer", example: 1 },
|
|
2300
|
+
},
|
|
2301
|
+
],
|
|
2302
|
+
responses: {
|
|
2303
|
+
"200": {
|
|
2304
|
+
description: "User specializations retrieved successfully",
|
|
2305
|
+
content: {
|
|
2306
|
+
"application/json": {
|
|
2307
|
+
schema: { $ref: "#/components/schemas/UserSpecializationProfileResponse" },
|
|
2308
|
+
},
|
|
2309
|
+
},
|
|
2310
|
+
},
|
|
2311
|
+
"401": {
|
|
2312
|
+
description: "Unauthorized - Invalid or missing token",
|
|
2313
|
+
content: {
|
|
2314
|
+
"application/json": {
|
|
2315
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
2316
|
+
},
|
|
2317
|
+
},
|
|
2318
|
+
},
|
|
2319
|
+
"404": {
|
|
2320
|
+
description: "User not found",
|
|
2321
|
+
content: {
|
|
2322
|
+
"application/json": {
|
|
2323
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
2324
|
+
},
|
|
2325
|
+
},
|
|
2326
|
+
},
|
|
2327
|
+
"500": {
|
|
2328
|
+
description: "Internal server error",
|
|
2329
|
+
content: {
|
|
2330
|
+
"application/json": {
|
|
2331
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
2332
|
+
},
|
|
2333
|
+
},
|
|
2334
|
+
},
|
|
2335
|
+
},
|
|
2336
|
+
},
|
|
2337
|
+
},
|
|
2338
|
+
"/api/user/admin/user-specialization/{id}": {
|
|
2339
|
+
get: {
|
|
2340
|
+
summary: "Get User Specialization by ID",
|
|
2341
|
+
description: "Retrieve a specific user specialization profile by its ID. Authentication required.",
|
|
2342
|
+
tags: ["Admin User Specializations Profile"],
|
|
2343
|
+
security: [{ bearerAuth: [] }],
|
|
2344
|
+
parameters: [
|
|
2345
|
+
{
|
|
2346
|
+
name: "id",
|
|
2347
|
+
in: "path",
|
|
2348
|
+
required: true,
|
|
2349
|
+
description: "User specialization profile ID",
|
|
2350
|
+
schema: { type: "integer", example: 1 },
|
|
2351
|
+
},
|
|
2352
|
+
],
|
|
2353
|
+
responses: {
|
|
2354
|
+
"200": {
|
|
2355
|
+
description: "User specialization profile retrieved successfully",
|
|
2356
|
+
content: {
|
|
2357
|
+
"application/json": {
|
|
2358
|
+
schema: { $ref: "#/components/schemas/UserSpecializationProfileResponse" },
|
|
2359
|
+
},
|
|
2360
|
+
},
|
|
2361
|
+
},
|
|
2362
|
+
"401": {
|
|
2363
|
+
description: "Unauthorized - Invalid or missing token",
|
|
2364
|
+
content: {
|
|
2365
|
+
"application/json": {
|
|
2366
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
2367
|
+
},
|
|
2368
|
+
},
|
|
2369
|
+
},
|
|
2370
|
+
"404": {
|
|
2371
|
+
description: "User specialization profile not found",
|
|
2372
|
+
content: {
|
|
2373
|
+
"application/json": {
|
|
2374
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
2375
|
+
},
|
|
2376
|
+
},
|
|
2377
|
+
},
|
|
2378
|
+
"500": {
|
|
2379
|
+
description: "Internal server error",
|
|
2380
|
+
content: {
|
|
2381
|
+
"application/json": {
|
|
2382
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
2383
|
+
},
|
|
2384
|
+
},
|
|
2385
|
+
},
|
|
2386
|
+
},
|
|
2387
|
+
},
|
|
2388
|
+
put: {
|
|
2389
|
+
summary: "Update User Specialization",
|
|
2390
|
+
description: "Update a user specialization profile. Authentication required.",
|
|
2391
|
+
tags: ["User"],
|
|
2392
|
+
security: [{ bearerAuth: [] }],
|
|
2393
|
+
parameters: [
|
|
2394
|
+
{
|
|
2395
|
+
name: "id",
|
|
2396
|
+
in: "path",
|
|
2397
|
+
required: true,
|
|
2398
|
+
description: "User specialization profile ID",
|
|
2399
|
+
schema: { type: "integer", example: 1 },
|
|
2400
|
+
},
|
|
2401
|
+
],
|
|
2402
|
+
requestBody: {
|
|
2403
|
+
required: true,
|
|
2404
|
+
content: {
|
|
2405
|
+
"application/json": {
|
|
2406
|
+
schema: {
|
|
2407
|
+
type: "object",
|
|
2408
|
+
properties: {
|
|
2409
|
+
specialization: {
|
|
2410
|
+
type: "integer",
|
|
2411
|
+
description: "Specialization ID (optional)",
|
|
2412
|
+
example: 2,
|
|
2413
|
+
},
|
|
2414
|
+
metadata: {
|
|
2415
|
+
type: "object",
|
|
2416
|
+
description: "Specialization metadata (optional)",
|
|
2417
|
+
nullable: true,
|
|
2418
|
+
example: { permissions: ["read", "write", "delete"] },
|
|
2419
|
+
},
|
|
2420
|
+
},
|
|
2421
|
+
},
|
|
2422
|
+
},
|
|
2423
|
+
},
|
|
2424
|
+
},
|
|
2425
|
+
responses: {
|
|
2426
|
+
"200": {
|
|
2427
|
+
description: "User specialization profile updated successfully",
|
|
2428
|
+
content: {
|
|
2429
|
+
"application/json": {
|
|
2430
|
+
schema: { $ref: "#/components/schemas/UserSpecializationProfileResponse" },
|
|
2431
|
+
},
|
|
2432
|
+
},
|
|
2433
|
+
},
|
|
2434
|
+
"400": {
|
|
2435
|
+
description: "Validation error",
|
|
2436
|
+
content: {
|
|
2437
|
+
"application/json": {
|
|
2438
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
2439
|
+
},
|
|
2440
|
+
},
|
|
2441
|
+
},
|
|
2442
|
+
"401": {
|
|
2443
|
+
description: "Unauthorized - Invalid or missing token",
|
|
2444
|
+
content: {
|
|
2445
|
+
"application/json": {
|
|
2446
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
2447
|
+
},
|
|
2448
|
+
},
|
|
2449
|
+
},
|
|
2450
|
+
"404": {
|
|
2451
|
+
description: "User specialization profile not found",
|
|
2452
|
+
content: {
|
|
2453
|
+
"application/json": {
|
|
2454
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
2455
|
+
},
|
|
2456
|
+
},
|
|
2457
|
+
},
|
|
2458
|
+
"500": {
|
|
2459
|
+
description: "Internal server error",
|
|
2460
|
+
content: {
|
|
2461
|
+
"application/json": {
|
|
2462
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
2463
|
+
},
|
|
2464
|
+
},
|
|
2465
|
+
},
|
|
2466
|
+
},
|
|
2467
|
+
},
|
|
2468
|
+
delete: {
|
|
2469
|
+
summary: "Delete User Specialization",
|
|
2470
|
+
description: "Delete a user specialization profile. Authentication required.",
|
|
2471
|
+
tags: ["User"],
|
|
2472
|
+
security: [{ bearerAuth: [] }],
|
|
2473
|
+
parameters: [
|
|
2474
|
+
{
|
|
2475
|
+
name: "id",
|
|
2476
|
+
in: "path",
|
|
2477
|
+
required: true,
|
|
2478
|
+
description: "User specialization profile ID",
|
|
2479
|
+
schema: { type: "integer", example: 1 },
|
|
2480
|
+
},
|
|
2481
|
+
],
|
|
2482
|
+
responses: {
|
|
2483
|
+
"200": {
|
|
2484
|
+
description: "User specialization profile deleted successfully",
|
|
2485
|
+
content: {
|
|
2486
|
+
"application/json": {
|
|
2487
|
+
schema: {
|
|
2488
|
+
type: "object",
|
|
2489
|
+
properties: {
|
|
2490
|
+
success: { type: "boolean" },
|
|
2491
|
+
message: { type: "string" },
|
|
2492
|
+
},
|
|
2493
|
+
},
|
|
2494
|
+
},
|
|
2495
|
+
},
|
|
2496
|
+
},
|
|
2497
|
+
"401": {
|
|
2498
|
+
description: "Unauthorized - Invalid or missing token",
|
|
2499
|
+
content: {
|
|
2500
|
+
"application/json": {
|
|
2501
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
2502
|
+
},
|
|
2503
|
+
},
|
|
2504
|
+
},
|
|
2505
|
+
"404": {
|
|
2506
|
+
description: "User specialization profile not found",
|
|
2507
|
+
content: {
|
|
2508
|
+
"application/json": {
|
|
2509
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
2510
|
+
},
|
|
2511
|
+
},
|
|
2512
|
+
},
|
|
2513
|
+
"500": {
|
|
2514
|
+
description: "Internal server error",
|
|
2515
|
+
content: {
|
|
2516
|
+
"application/json": {
|
|
2517
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
2518
|
+
},
|
|
2519
|
+
},
|
|
2520
|
+
},
|
|
2521
|
+
},
|
|
2522
|
+
},
|
|
2523
|
+
},
|
|
2524
|
+
"/api/user/specializations": {
|
|
2525
|
+
get: {
|
|
2526
|
+
summary: "Get All Specializations",
|
|
2527
|
+
description: "Retrieve all specializations in a flat list",
|
|
2528
|
+
tags: ["Specializations"],
|
|
2529
|
+
responses: {
|
|
2530
|
+
"200": {
|
|
2531
|
+
description: "Specializations retrieved successfully",
|
|
2532
|
+
content: {
|
|
2533
|
+
"application/json": {
|
|
2534
|
+
schema: {
|
|
2535
|
+
type: "object",
|
|
2536
|
+
properties: {
|
|
2537
|
+
success: { type: "boolean" },
|
|
2538
|
+
data: {
|
|
2539
|
+
type: "array",
|
|
2540
|
+
items: { $ref: "#/components/schemas/Specialization" }
|
|
2541
|
+
}
|
|
2542
|
+
}
|
|
2543
|
+
}
|
|
2544
|
+
}
|
|
2545
|
+
}
|
|
2546
|
+
},
|
|
2547
|
+
"400": {
|
|
2548
|
+
description: "Error retrieving specializations",
|
|
2549
|
+
content: {
|
|
2550
|
+
"application/json": {
|
|
2551
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" }
|
|
2552
|
+
}
|
|
2553
|
+
}
|
|
2554
|
+
}
|
|
2555
|
+
}
|
|
2556
|
+
},
|
|
2557
|
+
post: {
|
|
2558
|
+
summary: "Create Specialization",
|
|
2559
|
+
description: "Create a new specialization",
|
|
2560
|
+
tags: ["Specializations"],
|
|
2561
|
+
requestBody: {
|
|
2562
|
+
required: true,
|
|
2563
|
+
content: {
|
|
2564
|
+
"application/json": {
|
|
2565
|
+
schema: {
|
|
2566
|
+
type: "object",
|
|
2567
|
+
properties: {
|
|
2568
|
+
name: {
|
|
2569
|
+
type: "string",
|
|
2570
|
+
description: "Specialization name",
|
|
2571
|
+
example: "Doctor"
|
|
2572
|
+
},
|
|
2573
|
+
parentId: {
|
|
2574
|
+
type: "integer",
|
|
2575
|
+
nullable: true,
|
|
2576
|
+
description: "Parent specialization ID (null for root)",
|
|
2577
|
+
example: null
|
|
2578
|
+
},
|
|
2579
|
+
description: {
|
|
2580
|
+
type: "string",
|
|
2581
|
+
nullable: true,
|
|
2582
|
+
description: "Specialization description",
|
|
2583
|
+
example: "Medical doctor specialization"
|
|
2584
|
+
},
|
|
2585
|
+
imageUrl: {
|
|
2586
|
+
type: "string",
|
|
2587
|
+
nullable: true,
|
|
2588
|
+
description: "Specialization image URL",
|
|
2589
|
+
example: "https://example.com/images/doctor.png"
|
|
2590
|
+
}
|
|
2591
|
+
},
|
|
2592
|
+
required: ["name"]
|
|
2593
|
+
}
|
|
2594
|
+
}
|
|
2595
|
+
}
|
|
2596
|
+
},
|
|
2597
|
+
responses: {
|
|
2598
|
+
"201": {
|
|
2599
|
+
description: "Specialization created successfully",
|
|
2600
|
+
content: {
|
|
2601
|
+
"application/json": {
|
|
2602
|
+
schema: {
|
|
2603
|
+
type: "object",
|
|
2604
|
+
properties: {
|
|
2605
|
+
success: { type: "boolean" },
|
|
2606
|
+
data: { $ref: "#/components/schemas/Specialization" }
|
|
2607
|
+
}
|
|
2608
|
+
}
|
|
2609
|
+
}
|
|
2610
|
+
}
|
|
2611
|
+
},
|
|
2612
|
+
"400": {
|
|
2613
|
+
description: "Validation error",
|
|
2614
|
+
content: {
|
|
2615
|
+
"application/json": {
|
|
2616
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" }
|
|
2617
|
+
}
|
|
2618
|
+
}
|
|
2619
|
+
}
|
|
2620
|
+
}
|
|
2621
|
+
}
|
|
2622
|
+
},
|
|
2623
|
+
"/api/user/specializations/tree": {
|
|
2624
|
+
get: {
|
|
2625
|
+
summary: "Get Specializations Tree",
|
|
2626
|
+
description: "Retrieve specializations in hierarchical tree structure",
|
|
2627
|
+
tags: ["Specializations"],
|
|
2628
|
+
responses: {
|
|
2629
|
+
"200": {
|
|
2630
|
+
description: "Specializations tree retrieved successfully",
|
|
2631
|
+
content: {
|
|
2632
|
+
"application/json": {
|
|
2633
|
+
schema: {
|
|
2634
|
+
type: "object",
|
|
2635
|
+
properties: {
|
|
2636
|
+
success: { type: "boolean" },
|
|
2637
|
+
data: {
|
|
2638
|
+
type: "array",
|
|
2639
|
+
items: { $ref: "#/components/schemas/SpecializationTree" }
|
|
2640
|
+
}
|
|
2641
|
+
}
|
|
2642
|
+
}
|
|
2643
|
+
}
|
|
2644
|
+
}
|
|
2645
|
+
},
|
|
2646
|
+
"400": {
|
|
2647
|
+
description: "Error retrieving specializations",
|
|
2648
|
+
content: {
|
|
2649
|
+
"application/json": {
|
|
2650
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" }
|
|
2651
|
+
}
|
|
2652
|
+
}
|
|
2653
|
+
}
|
|
2654
|
+
}
|
|
2655
|
+
}
|
|
2656
|
+
},
|
|
2657
|
+
"/api/user/specializations/{id}": {
|
|
2658
|
+
get: {
|
|
2659
|
+
summary: "Get Specialization by ID",
|
|
2660
|
+
description: "Retrieve a specific specialization by its ID",
|
|
2661
|
+
tags: ["Specializations"],
|
|
2662
|
+
parameters: [
|
|
2663
|
+
{
|
|
2664
|
+
name: "id",
|
|
2665
|
+
in: "path",
|
|
2666
|
+
required: true,
|
|
2667
|
+
description: "Specialization ID",
|
|
2668
|
+
schema: { type: "integer", example: 1 }
|
|
2669
|
+
}
|
|
2670
|
+
],
|
|
2671
|
+
responses: {
|
|
2672
|
+
"200": {
|
|
2673
|
+
description: "Specialization retrieved successfully",
|
|
2674
|
+
content: {
|
|
2675
|
+
"application/json": {
|
|
2676
|
+
schema: {
|
|
2677
|
+
type: "object",
|
|
2678
|
+
properties: {
|
|
2679
|
+
success: { type: "boolean" },
|
|
2680
|
+
data: { $ref: "#/components/schemas/Specialization" }
|
|
2681
|
+
}
|
|
2682
|
+
}
|
|
2683
|
+
}
|
|
2684
|
+
}
|
|
2685
|
+
},
|
|
2686
|
+
"404": {
|
|
2687
|
+
description: "Specialization not found",
|
|
2688
|
+
content: {
|
|
2689
|
+
"application/json": {
|
|
2690
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" }
|
|
2691
|
+
}
|
|
2692
|
+
}
|
|
2693
|
+
},
|
|
2694
|
+
"400": {
|
|
2695
|
+
description: "Error retrieving specialization",
|
|
2696
|
+
content: {
|
|
2697
|
+
"application/json": {
|
|
2698
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" }
|
|
2699
|
+
}
|
|
2700
|
+
}
|
|
2701
|
+
}
|
|
2702
|
+
}
|
|
2703
|
+
},
|
|
2704
|
+
put: {
|
|
2705
|
+
summary: "Update Specialization",
|
|
2706
|
+
description: "Update a specialization",
|
|
2707
|
+
tags: ["Specializations"],
|
|
2708
|
+
parameters: [
|
|
2709
|
+
{
|
|
2710
|
+
name: "id",
|
|
2711
|
+
in: "path",
|
|
2712
|
+
required: true,
|
|
2713
|
+
description: "Specialization ID",
|
|
2714
|
+
schema: { type: "integer", example: 1 }
|
|
2715
|
+
}
|
|
2716
|
+
],
|
|
2717
|
+
requestBody: {
|
|
2718
|
+
required: true,
|
|
2719
|
+
content: {
|
|
2720
|
+
"application/json": {
|
|
2721
|
+
schema: {
|
|
2722
|
+
type: "object",
|
|
2723
|
+
properties: {
|
|
2724
|
+
name: {
|
|
2725
|
+
type: "string",
|
|
2726
|
+
description: "Specialization name",
|
|
2727
|
+
example: "Dentist"
|
|
2728
|
+
},
|
|
2729
|
+
parentId: {
|
|
2730
|
+
type: "integer",
|
|
2731
|
+
nullable: true,
|
|
2732
|
+
description: "Parent specialization ID",
|
|
2733
|
+
example: 1
|
|
2734
|
+
},
|
|
2735
|
+
description: {
|
|
2736
|
+
type: "string",
|
|
2737
|
+
nullable: true,
|
|
2738
|
+
description: "Specialization description",
|
|
2739
|
+
example: "Dental specialization"
|
|
2740
|
+
},
|
|
2741
|
+
imageUrl: {
|
|
2742
|
+
type: "string",
|
|
2743
|
+
nullable: true,
|
|
2744
|
+
description: "Specialization image URL",
|
|
2745
|
+
example: "https://example.com/images/dentist.png"
|
|
2746
|
+
}
|
|
2747
|
+
}
|
|
2748
|
+
}
|
|
2749
|
+
}
|
|
2750
|
+
}
|
|
2751
|
+
},
|
|
2752
|
+
responses: {
|
|
2753
|
+
"200": {
|
|
2754
|
+
description: "Specialization updated successfully",
|
|
2755
|
+
content: {
|
|
2756
|
+
"application/json": {
|
|
2757
|
+
schema: {
|
|
2758
|
+
type: "object",
|
|
2759
|
+
properties: {
|
|
2760
|
+
success: { type: "boolean" },
|
|
2761
|
+
data: { $ref: "#/components/schemas/Specialization" }
|
|
2762
|
+
}
|
|
2763
|
+
}
|
|
2764
|
+
}
|
|
2765
|
+
}
|
|
2766
|
+
},
|
|
2767
|
+
"404": {
|
|
2768
|
+
description: "Specialization not found",
|
|
2769
|
+
content: {
|
|
2770
|
+
"application/json": {
|
|
2771
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" }
|
|
2772
|
+
}
|
|
2773
|
+
}
|
|
2774
|
+
},
|
|
2775
|
+
"400": {
|
|
2776
|
+
description: "Validation or update error",
|
|
2777
|
+
content: {
|
|
2778
|
+
"application/json": {
|
|
2779
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" }
|
|
2780
|
+
}
|
|
2781
|
+
}
|
|
2782
|
+
}
|
|
2783
|
+
}
|
|
2784
|
+
},
|
|
2785
|
+
delete: {
|
|
2786
|
+
summary: "Delete Specialization",
|
|
2787
|
+
description: "Delete a specialization (cannot delete if has children)",
|
|
2788
|
+
tags: ["Specializations"],
|
|
2789
|
+
parameters: [
|
|
2790
|
+
{
|
|
2791
|
+
name: "id",
|
|
2792
|
+
in: "path",
|
|
2793
|
+
required: true,
|
|
2794
|
+
description: "Specialization ID",
|
|
2795
|
+
schema: { type: "integer", example: 1 }
|
|
2796
|
+
}
|
|
2797
|
+
],
|
|
2798
|
+
responses: {
|
|
2799
|
+
"200": {
|
|
2800
|
+
description: "Specialization deleted successfully",
|
|
2801
|
+
content: {
|
|
2802
|
+
"application/json": {
|
|
2803
|
+
schema: {
|
|
2804
|
+
type: "object",
|
|
2805
|
+
properties: {
|
|
2806
|
+
success: { type: "boolean" },
|
|
2807
|
+
message: { type: "string" }
|
|
2808
|
+
}
|
|
2809
|
+
}
|
|
2810
|
+
}
|
|
2811
|
+
}
|
|
2812
|
+
},
|
|
2813
|
+
"404": {
|
|
2814
|
+
description: "Specialization not found",
|
|
2815
|
+
content: {
|
|
2816
|
+
"application/json": {
|
|
2817
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" }
|
|
2818
|
+
}
|
|
2819
|
+
}
|
|
2820
|
+
},
|
|
2821
|
+
"400": {
|
|
2822
|
+
description: "Cannot delete specialization with children or other error",
|
|
2823
|
+
content: {
|
|
2824
|
+
"application/json": {
|
|
2825
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" }
|
|
2826
|
+
}
|
|
2827
|
+
}
|
|
2828
|
+
}
|
|
2829
|
+
}
|
|
2830
|
+
}
|
|
2831
|
+
},
|
|
2832
|
+
"/api/user/metadata": {
|
|
2833
|
+
get: {
|
|
2834
|
+
summary: "Get All Metadata",
|
|
2835
|
+
description: "Retrieve all metadata for the authenticated user. Returns the entire metadata JSON object.",
|
|
2836
|
+
tags: ["User Metadata"],
|
|
2837
|
+
security: [{ bearerAuth: [] }],
|
|
2838
|
+
responses: {
|
|
2839
|
+
"200": {
|
|
2840
|
+
description: "Metadata retrieved successfully",
|
|
2841
|
+
content: {
|
|
2842
|
+
"application/json": {
|
|
2843
|
+
schema: { $ref: "#/components/schemas/UserMetadataResponse" }
|
|
2844
|
+
}
|
|
2845
|
+
}
|
|
2846
|
+
},
|
|
2847
|
+
"401": {
|
|
2848
|
+
description: "Unauthorized - Invalid or missing token",
|
|
2849
|
+
content: {
|
|
2850
|
+
"application/json": {
|
|
2851
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" }
|
|
2852
|
+
}
|
|
2853
|
+
}
|
|
2854
|
+
},
|
|
2855
|
+
"404": {
|
|
2856
|
+
description: "User profile not found",
|
|
2857
|
+
content: {
|
|
2858
|
+
"application/json": {
|
|
2859
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" }
|
|
2860
|
+
}
|
|
2861
|
+
}
|
|
2862
|
+
},
|
|
2863
|
+
"500": {
|
|
2864
|
+
description: "Internal server error",
|
|
2865
|
+
content: {
|
|
2866
|
+
"application/json": {
|
|
2867
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" }
|
|
2868
|
+
}
|
|
2869
|
+
}
|
|
2870
|
+
}
|
|
2871
|
+
}
|
|
2872
|
+
},
|
|
2873
|
+
post: {
|
|
2874
|
+
summary: "Set Metadata",
|
|
2875
|
+
description: "Set entire metadata object (overwrites all existing metadata). Use PATCH to merge instead.",
|
|
2876
|
+
tags: ["User Metadata"],
|
|
2877
|
+
security: [{ bearerAuth: [] }],
|
|
2878
|
+
requestBody: {
|
|
2879
|
+
required: true,
|
|
2880
|
+
content: {
|
|
2881
|
+
"application/json": {
|
|
2882
|
+
schema: {
|
|
2883
|
+
type: "object",
|
|
2884
|
+
properties: {
|
|
2885
|
+
metadata: {
|
|
2886
|
+
$ref: "#/components/schemas/UserMetadata"
|
|
2887
|
+
}
|
|
2888
|
+
},
|
|
2889
|
+
required: ["metadata"]
|
|
2890
|
+
}
|
|
2891
|
+
}
|
|
2892
|
+
}
|
|
2893
|
+
},
|
|
2894
|
+
responses: {
|
|
2895
|
+
"200": {
|
|
2896
|
+
description: "Metadata set successfully",
|
|
2897
|
+
content: {
|
|
2898
|
+
"application/json": {
|
|
2899
|
+
schema: { $ref: "#/components/schemas/UserMetadataResponse" }
|
|
2900
|
+
}
|
|
2901
|
+
}
|
|
2902
|
+
},
|
|
2903
|
+
"400": {
|
|
2904
|
+
description: "Validation error - metadata must be a valid object",
|
|
2905
|
+
content: {
|
|
2906
|
+
"application/json": {
|
|
2907
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" }
|
|
2908
|
+
}
|
|
2909
|
+
}
|
|
2910
|
+
},
|
|
2911
|
+
"401": {
|
|
2912
|
+
description: "Unauthorized - Invalid or missing token",
|
|
2913
|
+
content: {
|
|
2914
|
+
"application/json": {
|
|
2915
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" }
|
|
2916
|
+
}
|
|
2917
|
+
}
|
|
2918
|
+
},
|
|
2919
|
+
"404": {
|
|
2920
|
+
description: "User profile not found",
|
|
2921
|
+
content: {
|
|
2922
|
+
"application/json": {
|
|
2923
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" }
|
|
2924
|
+
}
|
|
2925
|
+
}
|
|
2926
|
+
},
|
|
2927
|
+
"500": {
|
|
2928
|
+
description: "Internal server error",
|
|
2929
|
+
content: {
|
|
2930
|
+
"application/json": {
|
|
2931
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" }
|
|
2932
|
+
}
|
|
2933
|
+
}
|
|
2934
|
+
}
|
|
2935
|
+
}
|
|
2936
|
+
},
|
|
2937
|
+
patch: {
|
|
2938
|
+
summary: "Update Metadata",
|
|
2939
|
+
description: "Merge updates into existing metadata. Only specified fields are updated, others are preserved.",
|
|
2940
|
+
tags: ["User Metadata"],
|
|
2941
|
+
security: [{ bearerAuth: [] }],
|
|
2942
|
+
requestBody: {
|
|
2943
|
+
required: true,
|
|
2944
|
+
content: {
|
|
2945
|
+
"application/json": {
|
|
2946
|
+
schema: {
|
|
2947
|
+
type: "object",
|
|
2948
|
+
properties: {
|
|
2949
|
+
updates: {
|
|
2950
|
+
type: "object",
|
|
2951
|
+
description: "Partial metadata object with fields to update",
|
|
2952
|
+
additionalProperties: true,
|
|
2953
|
+
example: { theme: "light", language: "fr" }
|
|
2954
|
+
}
|
|
2955
|
+
},
|
|
2956
|
+
required: ["updates"]
|
|
2957
|
+
}
|
|
2958
|
+
}
|
|
2959
|
+
}
|
|
2960
|
+
},
|
|
2961
|
+
responses: {
|
|
2962
|
+
"200": {
|
|
2963
|
+
description: "Metadata merged successfully",
|
|
2964
|
+
content: {
|
|
2965
|
+
"application/json": {
|
|
2966
|
+
schema: { $ref: "#/components/schemas/UserMetadataResponse" }
|
|
2967
|
+
}
|
|
2968
|
+
}
|
|
2969
|
+
},
|
|
2970
|
+
"400": {
|
|
2971
|
+
description: "Validation error - updates must be a valid object",
|
|
2972
|
+
content: {
|
|
2973
|
+
"application/json": {
|
|
2974
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" }
|
|
2975
|
+
}
|
|
2976
|
+
}
|
|
2977
|
+
},
|
|
2978
|
+
"401": {
|
|
2979
|
+
description: "Unauthorized - Invalid or missing token",
|
|
2980
|
+
content: {
|
|
2981
|
+
"application/json": {
|
|
2982
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" }
|
|
2983
|
+
}
|
|
2984
|
+
}
|
|
2985
|
+
},
|
|
2986
|
+
"404": {
|
|
2987
|
+
description: "User profile not found",
|
|
2988
|
+
content: {
|
|
2989
|
+
"application/json": {
|
|
2990
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" }
|
|
2991
|
+
}
|
|
2992
|
+
}
|
|
2993
|
+
},
|
|
2994
|
+
"500": {
|
|
2995
|
+
description: "Internal server error",
|
|
2996
|
+
content: {
|
|
2997
|
+
"application/json": {
|
|
2998
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" }
|
|
2999
|
+
}
|
|
3000
|
+
}
|
|
3001
|
+
}
|
|
3002
|
+
}
|
|
3003
|
+
},
|
|
3004
|
+
delete: {
|
|
3005
|
+
summary: "Clear All Metadata",
|
|
3006
|
+
description: "Delete all metadata for the authenticated user. Sets metadata to null.",
|
|
3007
|
+
tags: ["User Metadata"],
|
|
3008
|
+
security: [{ bearerAuth: [] }],
|
|
3009
|
+
responses: {
|
|
3010
|
+
"200": {
|
|
3011
|
+
description: "All metadata cleared successfully",
|
|
3012
|
+
content: {
|
|
3013
|
+
"application/json": {
|
|
3014
|
+
schema: {
|
|
3015
|
+
type: "object",
|
|
3016
|
+
properties: {
|
|
3017
|
+
success: { type: "boolean", example: true },
|
|
3018
|
+
message: { type: "string", example: "All metadata cleared successfully" }
|
|
3019
|
+
}
|
|
3020
|
+
}
|
|
3021
|
+
}
|
|
3022
|
+
}
|
|
3023
|
+
},
|
|
3024
|
+
"401": {
|
|
3025
|
+
description: "Unauthorized - Invalid or missing token",
|
|
3026
|
+
content: {
|
|
3027
|
+
"application/json": {
|
|
3028
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" }
|
|
3029
|
+
}
|
|
3030
|
+
}
|
|
3031
|
+
},
|
|
3032
|
+
"404": {
|
|
3033
|
+
description: "User profile not found",
|
|
3034
|
+
content: {
|
|
3035
|
+
"application/json": {
|
|
3036
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" }
|
|
3037
|
+
}
|
|
3038
|
+
}
|
|
3039
|
+
},
|
|
3040
|
+
"500": {
|
|
3041
|
+
description: "Internal server error",
|
|
3042
|
+
content: {
|
|
3043
|
+
"application/json": {
|
|
3044
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" }
|
|
3045
|
+
}
|
|
3046
|
+
}
|
|
3047
|
+
}
|
|
3048
|
+
}
|
|
3049
|
+
}
|
|
3050
|
+
},
|
|
3051
|
+
"/api/user/metadata/{key}": {
|
|
3052
|
+
get: {
|
|
3053
|
+
summary: "Get Metadata Field",
|
|
3054
|
+
description: "Retrieve a specific metadata field value by key.",
|
|
3055
|
+
tags: ["User Metadata"],
|
|
3056
|
+
security: [{ bearerAuth: [] }],
|
|
3057
|
+
parameters: [
|
|
3058
|
+
{
|
|
3059
|
+
name: "key",
|
|
3060
|
+
in: "path",
|
|
3061
|
+
required: true,
|
|
3062
|
+
description: "Metadata field key",
|
|
3063
|
+
schema: { type: "string", example: "theme" }
|
|
3064
|
+
}
|
|
3065
|
+
],
|
|
3066
|
+
responses: {
|
|
3067
|
+
"200": {
|
|
3068
|
+
description: "Metadata field retrieved successfully",
|
|
3069
|
+
content: {
|
|
3070
|
+
"application/json": {
|
|
3071
|
+
schema: { $ref: "#/components/schemas/UserMetadataResponse" }
|
|
3072
|
+
}
|
|
3073
|
+
}
|
|
3074
|
+
},
|
|
3075
|
+
"401": {
|
|
3076
|
+
description: "Unauthorized - Invalid or missing token",
|
|
3077
|
+
content: {
|
|
3078
|
+
"application/json": {
|
|
3079
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" }
|
|
3080
|
+
}
|
|
3081
|
+
}
|
|
3082
|
+
},
|
|
3083
|
+
"404": {
|
|
3084
|
+
description: "Metadata field not found",
|
|
3085
|
+
content: {
|
|
3086
|
+
"application/json": {
|
|
3087
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" }
|
|
3088
|
+
}
|
|
3089
|
+
}
|
|
3090
|
+
},
|
|
3091
|
+
"500": {
|
|
3092
|
+
description: "Internal server error",
|
|
3093
|
+
content: {
|
|
3094
|
+
"application/json": {
|
|
3095
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" }
|
|
3096
|
+
}
|
|
3097
|
+
}
|
|
3098
|
+
}
|
|
3099
|
+
}
|
|
3100
|
+
},
|
|
3101
|
+
post: {
|
|
3102
|
+
summary: "Set Metadata Field",
|
|
3103
|
+
description: "Set or update a specific metadata field. Creates or overwrites the field value.",
|
|
3104
|
+
tags: ["User Metadata"],
|
|
3105
|
+
security: [{ bearerAuth: [] }],
|
|
3106
|
+
parameters: [
|
|
3107
|
+
{
|
|
3108
|
+
name: "key",
|
|
3109
|
+
in: "path",
|
|
3110
|
+
required: true,
|
|
3111
|
+
description: "Metadata field key",
|
|
3112
|
+
schema: { type: "string", example: "theme" }
|
|
3113
|
+
}
|
|
3114
|
+
],
|
|
3115
|
+
requestBody: {
|
|
3116
|
+
required: true,
|
|
3117
|
+
content: {
|
|
3118
|
+
"application/json": {
|
|
3119
|
+
schema: {
|
|
3120
|
+
type: "object",
|
|
3121
|
+
properties: {
|
|
3122
|
+
value: {
|
|
3123
|
+
description: "Value to set for the metadata field (any type)",
|
|
3124
|
+
example: "dark"
|
|
3125
|
+
}
|
|
3126
|
+
},
|
|
3127
|
+
required: ["value"]
|
|
3128
|
+
}
|
|
3129
|
+
}
|
|
3130
|
+
}
|
|
3131
|
+
},
|
|
3132
|
+
responses: {
|
|
3133
|
+
"200": {
|
|
3134
|
+
description: "Metadata field updated successfully",
|
|
3135
|
+
content: {
|
|
3136
|
+
"application/json": {
|
|
3137
|
+
schema: { $ref: "#/components/schemas/UserMetadataResponse" }
|
|
3138
|
+
}
|
|
3139
|
+
}
|
|
3140
|
+
},
|
|
3141
|
+
"401": {
|
|
3142
|
+
description: "Unauthorized - Invalid or missing token",
|
|
3143
|
+
content: {
|
|
3144
|
+
"application/json": {
|
|
3145
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" }
|
|
3146
|
+
}
|
|
3147
|
+
}
|
|
3148
|
+
},
|
|
3149
|
+
"404": {
|
|
3150
|
+
description: "User profile not found",
|
|
3151
|
+
content: {
|
|
3152
|
+
"application/json": {
|
|
3153
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" }
|
|
3154
|
+
}
|
|
3155
|
+
}
|
|
3156
|
+
},
|
|
3157
|
+
"500": {
|
|
3158
|
+
description: "Internal server error",
|
|
3159
|
+
content: {
|
|
3160
|
+
"application/json": {
|
|
3161
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" }
|
|
3162
|
+
}
|
|
3163
|
+
}
|
|
3164
|
+
}
|
|
3165
|
+
}
|
|
3166
|
+
},
|
|
3167
|
+
delete: {
|
|
3168
|
+
summary: "Delete Metadata Field",
|
|
3169
|
+
description: "Remove a specific metadata field by key.",
|
|
3170
|
+
tags: ["User Metadata"],
|
|
3171
|
+
security: [{ bearerAuth: [] }],
|
|
3172
|
+
parameters: [
|
|
3173
|
+
{
|
|
3174
|
+
name: "key",
|
|
3175
|
+
in: "path",
|
|
3176
|
+
required: true,
|
|
3177
|
+
description: "Metadata field key to delete",
|
|
3178
|
+
schema: { type: "string", example: "theme" }
|
|
3179
|
+
}
|
|
3180
|
+
],
|
|
3181
|
+
responses: {
|
|
3182
|
+
"200": {
|
|
3183
|
+
description: "Metadata field deleted successfully",
|
|
3184
|
+
content: {
|
|
3185
|
+
"application/json": {
|
|
3186
|
+
schema: {
|
|
3187
|
+
type: "object",
|
|
3188
|
+
properties: {
|
|
3189
|
+
success: { type: "boolean", example: true },
|
|
3190
|
+
message: { type: "string", example: "Metadata field 'theme' deleted successfully" },
|
|
3191
|
+
data: {
|
|
3192
|
+
$ref: "#/components/schemas/UserMetadata",
|
|
3193
|
+
description: "Remaining metadata after deletion"
|
|
3194
|
+
}
|
|
3195
|
+
}
|
|
3196
|
+
}
|
|
3197
|
+
}
|
|
3198
|
+
}
|
|
3199
|
+
},
|
|
3200
|
+
"401": {
|
|
3201
|
+
description: "Unauthorized - Invalid or missing token",
|
|
3202
|
+
content: {
|
|
3203
|
+
"application/json": {
|
|
3204
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" }
|
|
3205
|
+
}
|
|
3206
|
+
}
|
|
3207
|
+
},
|
|
3208
|
+
"404": {
|
|
3209
|
+
description: "Metadata field not found",
|
|
3210
|
+
content: {
|
|
3211
|
+
"application/json": {
|
|
3212
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" }
|
|
3213
|
+
}
|
|
3214
|
+
}
|
|
3215
|
+
},
|
|
3216
|
+
"500": {
|
|
3217
|
+
description: "Internal server error",
|
|
3218
|
+
content: {
|
|
3219
|
+
"application/json": {
|
|
3220
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" }
|
|
3221
|
+
}
|
|
3222
|
+
}
|
|
3223
|
+
}
|
|
3224
|
+
}
|
|
3225
|
+
}
|
|
3226
|
+
},
|
|
3227
|
+
"/api/media/avatar/upload": {
|
|
3228
|
+
post: {
|
|
3229
|
+
summary: "Upload Avatar",
|
|
3230
|
+
description: "Upload a user avatar image. Authentication required.",
|
|
3231
|
+
tags: ["Media"],
|
|
3232
|
+
security: [{ bearerAuth: [] }],
|
|
3233
|
+
requestBody: {
|
|
3234
|
+
required: true,
|
|
3235
|
+
content: {
|
|
3236
|
+
"multipart/form-data": {
|
|
3237
|
+
schema: {
|
|
3238
|
+
type: "object",
|
|
3239
|
+
properties: {
|
|
3240
|
+
images: {
|
|
3241
|
+
type: "array",
|
|
3242
|
+
items: {
|
|
3243
|
+
type: "string",
|
|
3244
|
+
format: "binary",
|
|
3245
|
+
},
|
|
3246
|
+
description: "Avatar image files to upload (max 10)",
|
|
3247
|
+
},
|
|
3248
|
+
},
|
|
3249
|
+
required: ["images"],
|
|
3250
|
+
},
|
|
3251
|
+
},
|
|
3252
|
+
},
|
|
3253
|
+
},
|
|
3254
|
+
responses: {
|
|
3255
|
+
"201": {
|
|
3256
|
+
description: "Avatar uploaded successfully",
|
|
3257
|
+
content: {
|
|
3258
|
+
"application/json": {
|
|
3259
|
+
schema: { $ref: "#/components/schemas/MediaResponse" },
|
|
3260
|
+
},
|
|
3261
|
+
},
|
|
3262
|
+
},
|
|
3263
|
+
"400": {
|
|
3264
|
+
description: "Invalid file or validation error",
|
|
3265
|
+
content: {
|
|
3266
|
+
"application/json": {
|
|
3267
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3268
|
+
},
|
|
3269
|
+
},
|
|
3270
|
+
},
|
|
3271
|
+
"401": {
|
|
3272
|
+
description: "Unauthorized - Authentication required",
|
|
3273
|
+
content: {
|
|
3274
|
+
"application/json": {
|
|
3275
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3276
|
+
},
|
|
3277
|
+
},
|
|
3278
|
+
},
|
|
3279
|
+
"413": {
|
|
3280
|
+
description: "File too large",
|
|
3281
|
+
content: {
|
|
3282
|
+
"application/json": {
|
|
3283
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3284
|
+
},
|
|
3285
|
+
},
|
|
3286
|
+
},
|
|
3287
|
+
"500": {
|
|
3288
|
+
description: "Internal server error",
|
|
3289
|
+
content: {
|
|
3290
|
+
"application/json": {
|
|
3291
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3292
|
+
},
|
|
3293
|
+
},
|
|
3294
|
+
},
|
|
3295
|
+
},
|
|
3296
|
+
},
|
|
3297
|
+
},
|
|
3298
|
+
"/api/media/avatar/{filename}": {
|
|
3299
|
+
get: {
|
|
3300
|
+
summary: "Get Avatar Image",
|
|
3301
|
+
description:
|
|
3302
|
+
"Retrieve a user avatar image by filename. Authentication required.",
|
|
3303
|
+
tags: ["Media"],
|
|
3304
|
+
security: [{ bearerAuth: [] }],
|
|
3305
|
+
parameters: [
|
|
3306
|
+
{
|
|
3307
|
+
name: "filename",
|
|
3308
|
+
in: "path",
|
|
3309
|
+
required: true,
|
|
3310
|
+
description: "Avatar filename",
|
|
3311
|
+
schema: { type: "string", example: "avatar-1609459200000.png" },
|
|
3312
|
+
},
|
|
3313
|
+
],
|
|
3314
|
+
responses: {
|
|
3315
|
+
"200": {
|
|
3316
|
+
description: "Avatar image retrieved successfully",
|
|
3317
|
+
content: { "image/*": {} },
|
|
3318
|
+
},
|
|
3319
|
+
"401": {
|
|
3320
|
+
description: "Unauthorized - Authentication required",
|
|
3321
|
+
content: {
|
|
3322
|
+
"application/json": {
|
|
3323
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3324
|
+
},
|
|
3325
|
+
},
|
|
3326
|
+
},
|
|
3327
|
+
"404": {
|
|
3328
|
+
description: "Avatar not found",
|
|
3329
|
+
content: {
|
|
3330
|
+
"application/json": {
|
|
3331
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3332
|
+
},
|
|
3333
|
+
},
|
|
3334
|
+
},
|
|
3335
|
+
"500": {
|
|
3336
|
+
description: "Internal server error",
|
|
3337
|
+
content: {
|
|
3338
|
+
"application/json": {
|
|
3339
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3340
|
+
},
|
|
3341
|
+
},
|
|
3342
|
+
},
|
|
3343
|
+
},
|
|
3344
|
+
},
|
|
3345
|
+
delete: {
|
|
3346
|
+
summary: "Delete Avatar",
|
|
3347
|
+
description:
|
|
3348
|
+
"Delete a user avatar by filename. Authentication required.",
|
|
3349
|
+
tags: ["Media"],
|
|
3350
|
+
security: [{ bearerAuth: [] }],
|
|
3351
|
+
parameters: [
|
|
3352
|
+
{
|
|
3353
|
+
name: "filename",
|
|
3354
|
+
in: "path",
|
|
3355
|
+
required: true,
|
|
3356
|
+
description: "Avatar filename",
|
|
3357
|
+
schema: { type: "string", example: "avatar-1609459200000.png" },
|
|
3358
|
+
},
|
|
3359
|
+
],
|
|
3360
|
+
responses: {
|
|
3361
|
+
"200": {
|
|
3362
|
+
description: "Avatar deleted successfully",
|
|
3363
|
+
content: {
|
|
3364
|
+
"application/json": {
|
|
3365
|
+
schema: {
|
|
3366
|
+
type: "object",
|
|
3367
|
+
properties: {
|
|
3368
|
+
success: { type: "boolean" },
|
|
3369
|
+
message: { type: "string" },
|
|
3370
|
+
},
|
|
3371
|
+
},
|
|
3372
|
+
},
|
|
3373
|
+
},
|
|
3374
|
+
},
|
|
3375
|
+
"401": {
|
|
3376
|
+
description: "Unauthorized - Authentication required",
|
|
3377
|
+
content: {
|
|
3378
|
+
"application/json": {
|
|
3379
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3380
|
+
},
|
|
3381
|
+
},
|
|
3382
|
+
},
|
|
3383
|
+
"404": {
|
|
3384
|
+
description: "Avatar not found",
|
|
3385
|
+
content: {
|
|
3386
|
+
"application/json": {
|
|
3387
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3388
|
+
},
|
|
3389
|
+
},
|
|
3390
|
+
},
|
|
3391
|
+
"500": {
|
|
3392
|
+
description: "Internal server error",
|
|
3393
|
+
content: {
|
|
3394
|
+
"application/json": {
|
|
3395
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3396
|
+
},
|
|
3397
|
+
},
|
|
3398
|
+
},
|
|
3399
|
+
},
|
|
3400
|
+
},
|
|
3401
|
+
},
|
|
3402
|
+
"/api/media/private/upload": {
|
|
3403
|
+
post: {
|
|
3404
|
+
summary: "Upload Private File",
|
|
3405
|
+
description: "Upload a private file. Authentication required.",
|
|
3406
|
+
tags: ["Media"],
|
|
3407
|
+
security: [{ bearerAuth: [] }],
|
|
3408
|
+
requestBody: {
|
|
3409
|
+
required: true,
|
|
3410
|
+
content: {
|
|
3411
|
+
"multipart/form-data": {
|
|
3412
|
+
schema: {
|
|
3413
|
+
type: "object",
|
|
3414
|
+
properties: {
|
|
3415
|
+
images: {
|
|
3416
|
+
type: "array",
|
|
3417
|
+
items: {
|
|
3418
|
+
type: "string",
|
|
3419
|
+
format: "binary",
|
|
3420
|
+
},
|
|
3421
|
+
description: "Files to upload (max 10)",
|
|
3422
|
+
},
|
|
3423
|
+
},
|
|
3424
|
+
required: ["images"],
|
|
3425
|
+
},
|
|
3426
|
+
},
|
|
3427
|
+
},
|
|
3428
|
+
},
|
|
3429
|
+
responses: {
|
|
3430
|
+
"201": {
|
|
3431
|
+
description: "File uploaded successfully",
|
|
3432
|
+
content: {
|
|
3433
|
+
"application/json": {
|
|
3434
|
+
schema: { $ref: "#/components/schemas/MediaResponse" },
|
|
3435
|
+
},
|
|
3436
|
+
},
|
|
3437
|
+
},
|
|
3438
|
+
"400": {
|
|
3439
|
+
description: "Invalid file or validation error",
|
|
3440
|
+
content: {
|
|
3441
|
+
"application/json": {
|
|
3442
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3443
|
+
},
|
|
3444
|
+
},
|
|
3445
|
+
},
|
|
3446
|
+
"401": {
|
|
3447
|
+
description: "Unauthorized - Authentication required",
|
|
3448
|
+
content: {
|
|
3449
|
+
"application/json": {
|
|
3450
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3451
|
+
},
|
|
3452
|
+
},
|
|
3453
|
+
},
|
|
3454
|
+
"413": {
|
|
3455
|
+
description: "File too large",
|
|
3456
|
+
content: {
|
|
3457
|
+
"application/json": {
|
|
3458
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3459
|
+
},
|
|
3460
|
+
},
|
|
3461
|
+
},
|
|
3462
|
+
"500": {
|
|
3463
|
+
description: "Internal server error",
|
|
3464
|
+
content: {
|
|
3465
|
+
"application/json": {
|
|
3466
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3467
|
+
},
|
|
3468
|
+
},
|
|
3469
|
+
},
|
|
3470
|
+
},
|
|
3471
|
+
},
|
|
3472
|
+
},
|
|
3473
|
+
"/api/media/private/{filename}": {
|
|
3474
|
+
get: {
|
|
3475
|
+
summary: "Get Private File",
|
|
3476
|
+
description:
|
|
3477
|
+
"Retrieve a private file by filename. Authentication required.",
|
|
3478
|
+
tags: ["Media"],
|
|
3479
|
+
security: [{ bearerAuth: [] }],
|
|
3480
|
+
parameters: [
|
|
3481
|
+
{
|
|
3482
|
+
name: "filename",
|
|
3483
|
+
in: "path",
|
|
3484
|
+
required: true,
|
|
3485
|
+
description: "File filename",
|
|
3486
|
+
schema: { type: "string", example: "document-1609459200000.pdf" },
|
|
3487
|
+
},
|
|
3488
|
+
],
|
|
3489
|
+
responses: {
|
|
3490
|
+
"200": {
|
|
3491
|
+
description: "File retrieved successfully",
|
|
3492
|
+
content: { "application/*": {} },
|
|
3493
|
+
},
|
|
3494
|
+
"401": {
|
|
3495
|
+
description: "Unauthorized - Authentication required",
|
|
3496
|
+
content: {
|
|
3497
|
+
"application/json": {
|
|
3498
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3499
|
+
},
|
|
3500
|
+
},
|
|
3501
|
+
},
|
|
3502
|
+
"404": {
|
|
3503
|
+
description: "File not found",
|
|
3504
|
+
content: {
|
|
3505
|
+
"application/json": {
|
|
3506
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3507
|
+
},
|
|
3508
|
+
},
|
|
3509
|
+
},
|
|
3510
|
+
"500": {
|
|
3511
|
+
description: "Internal server error",
|
|
3512
|
+
content: {
|
|
3513
|
+
"application/json": {
|
|
3514
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3515
|
+
},
|
|
3516
|
+
},
|
|
3517
|
+
},
|
|
3518
|
+
},
|
|
3519
|
+
},
|
|
3520
|
+
delete: {
|
|
3521
|
+
summary: "Delete Private File",
|
|
3522
|
+
description:
|
|
3523
|
+
"Delete a private file by filename. Authentication required.",
|
|
3524
|
+
tags: ["Media"],
|
|
3525
|
+
security: [{ bearerAuth: [] }],
|
|
3526
|
+
parameters: [
|
|
3527
|
+
{
|
|
3528
|
+
name: "filename",
|
|
3529
|
+
in: "path",
|
|
3530
|
+
required: true,
|
|
3531
|
+
description: "File filename",
|
|
3532
|
+
schema: { type: "string", example: "document-1609459200000.pdf" },
|
|
3533
|
+
},
|
|
3534
|
+
],
|
|
3535
|
+
responses: {
|
|
3536
|
+
"200": {
|
|
3537
|
+
description: "File deleted successfully",
|
|
3538
|
+
content: {
|
|
3539
|
+
"application/json": {
|
|
3540
|
+
schema: {
|
|
3541
|
+
type: "object",
|
|
3542
|
+
properties: {
|
|
3543
|
+
success: { type: "boolean" },
|
|
3544
|
+
message: { type: "string" },
|
|
3545
|
+
},
|
|
3546
|
+
},
|
|
3547
|
+
},
|
|
3548
|
+
},
|
|
3549
|
+
},
|
|
3550
|
+
"401": {
|
|
3551
|
+
description: "Unauthorized - Authentication required",
|
|
3552
|
+
content: {
|
|
3553
|
+
"application/json": {
|
|
3554
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3555
|
+
},
|
|
3556
|
+
},
|
|
3557
|
+
},
|
|
3558
|
+
"404": {
|
|
3559
|
+
description: "File not found",
|
|
3560
|
+
content: {
|
|
3561
|
+
"application/json": {
|
|
3562
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3563
|
+
},
|
|
3564
|
+
},
|
|
3565
|
+
},
|
|
3566
|
+
"500": {
|
|
3567
|
+
description: "Internal server error",
|
|
3568
|
+
content: {
|
|
3569
|
+
"application/json": {
|
|
3570
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3571
|
+
},
|
|
3572
|
+
},
|
|
3573
|
+
},
|
|
3574
|
+
},
|
|
3575
|
+
},
|
|
3576
|
+
},
|
|
3577
|
+
"/api/user/admin/roles": {
|
|
3578
|
+
get: {
|
|
3579
|
+
summary: "Get All Application Roles (Admin Only)",
|
|
3580
|
+
description: "Retrieve all available application roles. Admin access required.",
|
|
3581
|
+
tags: ["Admin"],
|
|
3582
|
+
security: [{ bearerAuth: [] }],
|
|
3583
|
+
responses: {
|
|
3584
|
+
"200": {
|
|
3585
|
+
description: "Roles retrieved successfully",
|
|
3586
|
+
content: {
|
|
3587
|
+
"application/json": {
|
|
3588
|
+
schema: { $ref: "#/components/schemas/AdminRoleResponse" },
|
|
3589
|
+
},
|
|
3590
|
+
},
|
|
3591
|
+
},
|
|
3592
|
+
"401": {
|
|
3593
|
+
description: "Unauthorized - Authentication required",
|
|
3594
|
+
content: {
|
|
3595
|
+
"application/json": {
|
|
3596
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3597
|
+
},
|
|
3598
|
+
},
|
|
3599
|
+
},
|
|
3600
|
+
"403": {
|
|
3601
|
+
description: "Forbidden - Admin access required",
|
|
3602
|
+
content: {
|
|
3603
|
+
"application/json": {
|
|
3604
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3605
|
+
},
|
|
3606
|
+
},
|
|
3607
|
+
},
|
|
3608
|
+
"500": {
|
|
3609
|
+
description: "Internal server error",
|
|
3610
|
+
content: {
|
|
3611
|
+
"application/json": {
|
|
3612
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3613
|
+
},
|
|
3614
|
+
},
|
|
3615
|
+
},
|
|
3616
|
+
},
|
|
3617
|
+
},
|
|
3618
|
+
post: {
|
|
3619
|
+
summary: "Create New Application Role (Super Admin Only)",
|
|
3620
|
+
description: "Create a new application role with specified permissions. Super Admin access required.",
|
|
3621
|
+
tags: ["Admin"],
|
|
3622
|
+
security: [{ bearerAuth: [] }],
|
|
3623
|
+
requestBody: {
|
|
3624
|
+
required: true,
|
|
3625
|
+
content: {
|
|
3626
|
+
"application/json": {
|
|
3627
|
+
schema: { $ref: "#/components/schemas/CreateAppRoleRequest" },
|
|
3628
|
+
},
|
|
3629
|
+
},
|
|
3630
|
+
},
|
|
3631
|
+
responses: {
|
|
3632
|
+
"201": {
|
|
3633
|
+
description: "Role created successfully",
|
|
3634
|
+
content: {
|
|
3635
|
+
"application/json": {
|
|
3636
|
+
schema: { $ref: "#/components/schemas/AdminRoleResponse" },
|
|
3637
|
+
},
|
|
3638
|
+
},
|
|
3639
|
+
},
|
|
3640
|
+
"400": {
|
|
3641
|
+
description: "Validation error",
|
|
3642
|
+
content: {
|
|
3643
|
+
"application/json": {
|
|
3644
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3645
|
+
},
|
|
3646
|
+
},
|
|
3647
|
+
},
|
|
3648
|
+
"401": {
|
|
3649
|
+
description: "Unauthorized - Authentication required",
|
|
3650
|
+
content: {
|
|
3651
|
+
"application/json": {
|
|
3652
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3653
|
+
},
|
|
3654
|
+
},
|
|
3655
|
+
},
|
|
3656
|
+
"403": {
|
|
3657
|
+
description: "Forbidden - Super Admin access required",
|
|
3658
|
+
content: {
|
|
3659
|
+
"application/json": {
|
|
3660
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3661
|
+
},
|
|
3662
|
+
},
|
|
3663
|
+
},
|
|
3664
|
+
"500": {
|
|
3665
|
+
description: "Internal server error",
|
|
3666
|
+
content: {
|
|
3667
|
+
"application/json": {
|
|
3668
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3669
|
+
},
|
|
3670
|
+
},
|
|
3671
|
+
},
|
|
3672
|
+
},
|
|
3673
|
+
},
|
|
3674
|
+
},
|
|
3675
|
+
"/api/user/admin/roles/active": {
|
|
3676
|
+
get: {
|
|
3677
|
+
summary: "Get Active Application Roles (Admin Only)",
|
|
3678
|
+
description: "Retrieve only active application roles. Admin access required.",
|
|
3679
|
+
tags: ["Admin"],
|
|
3680
|
+
security: [{ bearerAuth: [] }],
|
|
3681
|
+
responses: {
|
|
3682
|
+
"200": {
|
|
3683
|
+
description: "Active roles retrieved successfully",
|
|
3684
|
+
content: {
|
|
3685
|
+
"application/json": {
|
|
3686
|
+
schema: { $ref: "#/components/schemas/AdminRoleResponse" },
|
|
3687
|
+
},
|
|
3688
|
+
},
|
|
3689
|
+
},
|
|
3690
|
+
"401": {
|
|
3691
|
+
description: "Unauthorized - Authentication required",
|
|
3692
|
+
content: {
|
|
3693
|
+
"application/json": {
|
|
3694
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3695
|
+
},
|
|
3696
|
+
},
|
|
3697
|
+
},
|
|
3698
|
+
"403": {
|
|
3699
|
+
description: "Forbidden - Admin access required",
|
|
3700
|
+
content: {
|
|
3701
|
+
"application/json": {
|
|
3702
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3703
|
+
},
|
|
3704
|
+
},
|
|
3705
|
+
},
|
|
3706
|
+
"500": {
|
|
3707
|
+
description: "Internal server error",
|
|
3708
|
+
content: {
|
|
3709
|
+
"application/json": {
|
|
3710
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3711
|
+
},
|
|
3712
|
+
},
|
|
3713
|
+
},
|
|
3714
|
+
},
|
|
3715
|
+
},
|
|
3716
|
+
},
|
|
3717
|
+
"/api/user/admin/roles/{id}": {
|
|
3718
|
+
get: {
|
|
3719
|
+
summary: "Get Application Role by ID (Admin Only)",
|
|
3720
|
+
description: "Retrieve a specific application role by its ID. Admin access required.",
|
|
3721
|
+
tags: ["Admin"],
|
|
3722
|
+
security: [{ bearerAuth: [] }],
|
|
3723
|
+
parameters: [
|
|
3724
|
+
{
|
|
3725
|
+
name: "id",
|
|
3726
|
+
in: "path",
|
|
3727
|
+
required: true,
|
|
3728
|
+
description: "Role ID",
|
|
3729
|
+
schema: { type: "integer", example: 1 },
|
|
3730
|
+
},
|
|
3731
|
+
],
|
|
3732
|
+
responses: {
|
|
3733
|
+
"200": {
|
|
3734
|
+
description: "Role retrieved successfully",
|
|
3735
|
+
content: {
|
|
3736
|
+
"application/json": {
|
|
3737
|
+
schema: { $ref: "#/components/schemas/AdminRoleResponse" },
|
|
3738
|
+
},
|
|
3739
|
+
},
|
|
3740
|
+
},
|
|
3741
|
+
"401": {
|
|
3742
|
+
description: "Unauthorized - Authentication required",
|
|
3743
|
+
content: {
|
|
3744
|
+
"application/json": {
|
|
3745
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3746
|
+
},
|
|
3747
|
+
},
|
|
3748
|
+
},
|
|
3749
|
+
"403": {
|
|
3750
|
+
description: "Forbidden - Admin access required",
|
|
3751
|
+
content: {
|
|
3752
|
+
"application/json": {
|
|
3753
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3754
|
+
},
|
|
3755
|
+
},
|
|
3756
|
+
},
|
|
3757
|
+
"404": {
|
|
3758
|
+
description: "Role not found",
|
|
3759
|
+
content: {
|
|
3760
|
+
"application/json": {
|
|
3761
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3762
|
+
},
|
|
3763
|
+
},
|
|
3764
|
+
},
|
|
3765
|
+
"500": {
|
|
3766
|
+
description: "Internal server error",
|
|
3767
|
+
content: {
|
|
3768
|
+
"application/json": {
|
|
3769
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3770
|
+
},
|
|
3771
|
+
},
|
|
3772
|
+
},
|
|
3773
|
+
},
|
|
3774
|
+
},
|
|
3775
|
+
put: {
|
|
3776
|
+
summary: "Update Application Role (Super Admin Only)",
|
|
3777
|
+
description: "Update an existing application role. Super Admin access required.",
|
|
3778
|
+
tags: ["Admin"],
|
|
3779
|
+
security: [{ bearerAuth: [] }],
|
|
3780
|
+
parameters: [
|
|
3781
|
+
{
|
|
3782
|
+
name: "id",
|
|
3783
|
+
in: "path",
|
|
3784
|
+
required: true,
|
|
3785
|
+
description: "Role ID",
|
|
3786
|
+
schema: { type: "integer", example: 1 },
|
|
3787
|
+
},
|
|
3788
|
+
],
|
|
3789
|
+
requestBody: {
|
|
3790
|
+
required: true,
|
|
3791
|
+
content: {
|
|
3792
|
+
"application/json": {
|
|
3793
|
+
schema: { $ref: "#/components/schemas/UpdateAppRoleRequest" },
|
|
3794
|
+
},
|
|
3795
|
+
},
|
|
3796
|
+
},
|
|
3797
|
+
responses: {
|
|
3798
|
+
"200": {
|
|
3799
|
+
description: "Role updated successfully",
|
|
3800
|
+
content: {
|
|
3801
|
+
"application/json": {
|
|
3802
|
+
schema: { $ref: "#/components/schemas/AdminRoleResponse" },
|
|
3803
|
+
},
|
|
3804
|
+
},
|
|
3805
|
+
},
|
|
3806
|
+
"400": {
|
|
3807
|
+
description: "Validation error",
|
|
3808
|
+
content: {
|
|
3809
|
+
"application/json": {
|
|
3810
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3811
|
+
},
|
|
3812
|
+
},
|
|
3813
|
+
},
|
|
3814
|
+
"401": {
|
|
3815
|
+
description: "Unauthorized - Authentication required",
|
|
3816
|
+
content: {
|
|
3817
|
+
"application/json": {
|
|
3818
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3819
|
+
},
|
|
3820
|
+
},
|
|
3821
|
+
},
|
|
3822
|
+
"403": {
|
|
3823
|
+
description: "Forbidden - Super Admin access required",
|
|
3824
|
+
content: {
|
|
3825
|
+
"application/json": {
|
|
3826
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3827
|
+
},
|
|
3828
|
+
},
|
|
3829
|
+
},
|
|
3830
|
+
"404": {
|
|
3831
|
+
description: "Role not found",
|
|
3832
|
+
content: {
|
|
3833
|
+
"application/json": {
|
|
3834
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3835
|
+
},
|
|
3836
|
+
},
|
|
3837
|
+
},
|
|
3838
|
+
"500": {
|
|
3839
|
+
description: "Internal server error",
|
|
3840
|
+
content: {
|
|
3841
|
+
"application/json": {
|
|
3842
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3843
|
+
},
|
|
3844
|
+
},
|
|
3845
|
+
},
|
|
3846
|
+
},
|
|
3847
|
+
},
|
|
3848
|
+
delete: {
|
|
3849
|
+
summary: "Delete Application Role (Super Admin Only)",
|
|
3850
|
+
description: "Delete an application role. Super Admin access required.",
|
|
3851
|
+
tags: ["Admin"],
|
|
3852
|
+
security: [{ bearerAuth: [] }],
|
|
3853
|
+
parameters: [
|
|
3854
|
+
{
|
|
3855
|
+
name: "id",
|
|
3856
|
+
in: "path",
|
|
3857
|
+
required: true,
|
|
3858
|
+
description: "Role ID",
|
|
3859
|
+
schema: { type: "integer", example: 1 },
|
|
3860
|
+
},
|
|
3861
|
+
],
|
|
3862
|
+
responses: {
|
|
3863
|
+
"200": {
|
|
3864
|
+
description: "Role deleted successfully",
|
|
3865
|
+
content: {
|
|
3866
|
+
"application/json": {
|
|
3867
|
+
schema: {
|
|
3868
|
+
type: "object",
|
|
3869
|
+
properties: {
|
|
3870
|
+
success: { type: "boolean" },
|
|
3871
|
+
message: { type: "string" },
|
|
3872
|
+
},
|
|
3873
|
+
},
|
|
3874
|
+
},
|
|
3875
|
+
},
|
|
3876
|
+
},
|
|
3877
|
+
"401": {
|
|
3878
|
+
description: "Unauthorized - Authentication required",
|
|
3879
|
+
content: {
|
|
3880
|
+
"application/json": {
|
|
3881
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3882
|
+
},
|
|
3883
|
+
},
|
|
3884
|
+
},
|
|
3885
|
+
"403": {
|
|
3886
|
+
description: "Forbidden - Super Admin access required",
|
|
3887
|
+
content: {
|
|
3888
|
+
"application/json": {
|
|
3889
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3890
|
+
},
|
|
3891
|
+
},
|
|
3892
|
+
},
|
|
3893
|
+
"404": {
|
|
3894
|
+
description: "Role not found",
|
|
3895
|
+
content: {
|
|
3896
|
+
"application/json": {
|
|
3897
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3898
|
+
},
|
|
3899
|
+
},
|
|
3900
|
+
},
|
|
3901
|
+
"500": {
|
|
3902
|
+
description: "Internal server error",
|
|
3903
|
+
content: {
|
|
3904
|
+
"application/json": {
|
|
3905
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3906
|
+
},
|
|
3907
|
+
},
|
|
3908
|
+
},
|
|
3909
|
+
},
|
|
3910
|
+
},
|
|
3911
|
+
},
|
|
3912
|
+
"/api/marketing/contacts": {
|
|
3913
|
+
post: {
|
|
3914
|
+
summary: "Create Marketing Contact",
|
|
3915
|
+
description: "Create a new marketing contact (email or phone required).",
|
|
3916
|
+
tags: ["Marketing"],
|
|
3917
|
+
requestBody: {
|
|
3918
|
+
required: true,
|
|
3919
|
+
content: {
|
|
3920
|
+
"application/json": {
|
|
3921
|
+
schema: { $ref: "#/components/schemas/CreateMarketingContactRequest" },
|
|
3922
|
+
},
|
|
3923
|
+
},
|
|
3924
|
+
},
|
|
3925
|
+
responses: {
|
|
3926
|
+
"201": {
|
|
3927
|
+
description: "Contact created successfully",
|
|
3928
|
+
content: {
|
|
3929
|
+
"application/json": {
|
|
3930
|
+
schema: { $ref: "#/components/schemas/MarketingContactResponse" },
|
|
3931
|
+
},
|
|
3932
|
+
},
|
|
3933
|
+
},
|
|
3934
|
+
"400": {
|
|
3935
|
+
description: "Validation error",
|
|
3936
|
+
content: {
|
|
3937
|
+
"application/json": {
|
|
3938
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3939
|
+
},
|
|
3940
|
+
},
|
|
3941
|
+
},
|
|
3942
|
+
"500": {
|
|
3943
|
+
description: "Internal server error",
|
|
3944
|
+
content: {
|
|
3945
|
+
"application/json": {
|
|
3946
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3947
|
+
},
|
|
3948
|
+
},
|
|
3949
|
+
},
|
|
3950
|
+
},
|
|
3951
|
+
},
|
|
3952
|
+
},
|
|
3953
|
+
"/api/marketing/consents": {
|
|
3954
|
+
post: {
|
|
3955
|
+
summary: "Create Marketing Consent",
|
|
3956
|
+
description: "Create a consent record for a contact.",
|
|
3957
|
+
tags: ["Marketing"],
|
|
3958
|
+
requestBody: {
|
|
3959
|
+
required: true,
|
|
3960
|
+
content: {
|
|
3961
|
+
"application/json": {
|
|
3962
|
+
schema: { $ref: "#/components/schemas/CreateMarketingConsentRequest" },
|
|
3963
|
+
},
|
|
3964
|
+
},
|
|
3965
|
+
},
|
|
3966
|
+
responses: {
|
|
3967
|
+
"201": {
|
|
3968
|
+
description: "Consent created successfully",
|
|
3969
|
+
content: {
|
|
3970
|
+
"application/json": {
|
|
3971
|
+
schema: { $ref: "#/components/schemas/MarketingConsentResponse" },
|
|
3972
|
+
},
|
|
3973
|
+
},
|
|
3974
|
+
},
|
|
3975
|
+
"404": {
|
|
3976
|
+
description: "Contact not found",
|
|
3977
|
+
content: {
|
|
3978
|
+
"application/json": {
|
|
3979
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3980
|
+
},
|
|
3981
|
+
},
|
|
3982
|
+
},
|
|
3983
|
+
"400": {
|
|
3984
|
+
description: "Validation error",
|
|
3985
|
+
content: {
|
|
3986
|
+
"application/json": {
|
|
3987
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3988
|
+
},
|
|
3989
|
+
},
|
|
3990
|
+
},
|
|
3991
|
+
"500": {
|
|
3992
|
+
description: "Internal server error",
|
|
3993
|
+
content: {
|
|
3994
|
+
"application/json": {
|
|
3995
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
3996
|
+
},
|
|
3997
|
+
},
|
|
3998
|
+
},
|
|
3999
|
+
},
|
|
4000
|
+
},
|
|
4001
|
+
},
|
|
4002
|
+
"/api/marketing/segments": {
|
|
4003
|
+
post: {
|
|
4004
|
+
summary: "Create Marketing Segment",
|
|
4005
|
+
description: "Create a new segment definition.",
|
|
4006
|
+
tags: ["Marketing"],
|
|
4007
|
+
requestBody: {
|
|
4008
|
+
required: true,
|
|
4009
|
+
content: {
|
|
4010
|
+
"application/json": {
|
|
4011
|
+
schema: { $ref: "#/components/schemas/CreateMarketingSegmentRequest" },
|
|
4012
|
+
},
|
|
4013
|
+
},
|
|
4014
|
+
},
|
|
4015
|
+
responses: {
|
|
4016
|
+
"201": {
|
|
4017
|
+
description: "Segment created successfully",
|
|
4018
|
+
content: {
|
|
4019
|
+
"application/json": {
|
|
4020
|
+
schema: { $ref: "#/components/schemas/MarketingSegmentResponse" },
|
|
4021
|
+
},
|
|
4022
|
+
},
|
|
4023
|
+
},
|
|
4024
|
+
"400": {
|
|
4025
|
+
description: "Invalid segment definition",
|
|
4026
|
+
content: {
|
|
4027
|
+
"application/json": {
|
|
4028
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
4029
|
+
},
|
|
4030
|
+
},
|
|
4031
|
+
},
|
|
4032
|
+
"500": {
|
|
4033
|
+
description: "Internal server error",
|
|
4034
|
+
content: {
|
|
4035
|
+
"application/json": {
|
|
4036
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
4037
|
+
},
|
|
4038
|
+
},
|
|
4039
|
+
},
|
|
4040
|
+
},
|
|
4041
|
+
},
|
|
4042
|
+
},
|
|
4043
|
+
"/api/marketing/campaigns": {
|
|
4044
|
+
post: {
|
|
4045
|
+
summary: "Create Marketing Campaign",
|
|
4046
|
+
description: "Create a new marketing campaign.",
|
|
4047
|
+
tags: ["Marketing"],
|
|
4048
|
+
requestBody: {
|
|
4049
|
+
required: true,
|
|
4050
|
+
content: {
|
|
4051
|
+
"application/json": {
|
|
4052
|
+
schema: { $ref: "#/components/schemas/CreateMarketingCampaignRequest" },
|
|
4053
|
+
},
|
|
4054
|
+
},
|
|
4055
|
+
},
|
|
4056
|
+
responses: {
|
|
4057
|
+
"201": {
|
|
4058
|
+
description: "Campaign created successfully",
|
|
4059
|
+
content: {
|
|
4060
|
+
"application/json": {
|
|
4061
|
+
schema: { $ref: "#/components/schemas/MarketingCampaignResponse" },
|
|
4062
|
+
},
|
|
4063
|
+
},
|
|
4064
|
+
},
|
|
4065
|
+
"404": {
|
|
4066
|
+
description: "Segment not found",
|
|
4067
|
+
content: {
|
|
4068
|
+
"application/json": {
|
|
4069
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
4070
|
+
},
|
|
4071
|
+
},
|
|
4072
|
+
},
|
|
4073
|
+
"400": {
|
|
4074
|
+
description: "Validation error",
|
|
4075
|
+
content: {
|
|
4076
|
+
"application/json": {
|
|
4077
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
4078
|
+
},
|
|
4079
|
+
},
|
|
4080
|
+
},
|
|
4081
|
+
"500": {
|
|
4082
|
+
description: "Internal server error",
|
|
4083
|
+
content: {
|
|
4084
|
+
"application/json": {
|
|
4085
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
4086
|
+
},
|
|
4087
|
+
},
|
|
4088
|
+
},
|
|
4089
|
+
},
|
|
4090
|
+
},
|
|
4091
|
+
},
|
|
4092
|
+
"/api/marketing/campaigns/{campaignId}/execute": {
|
|
4093
|
+
post: {
|
|
4094
|
+
summary: "Execute Marketing Campaign",
|
|
4095
|
+
description: "Trigger execution of a campaign and create a run record.",
|
|
4096
|
+
tags: ["Marketing"],
|
|
4097
|
+
parameters: [
|
|
4098
|
+
{
|
|
4099
|
+
name: "campaignId",
|
|
4100
|
+
in: "path",
|
|
4101
|
+
required: true,
|
|
4102
|
+
description: "Campaign ID",
|
|
4103
|
+
schema: { type: "integer", example: 1 },
|
|
4104
|
+
},
|
|
4105
|
+
],
|
|
4106
|
+
responses: {
|
|
4107
|
+
"202": {
|
|
4108
|
+
description: "Campaign execution queued",
|
|
4109
|
+
content: {
|
|
4110
|
+
"application/json": {
|
|
4111
|
+
schema: { $ref: "#/components/schemas/MarketingCampaignRunResponse" },
|
|
4112
|
+
},
|
|
4113
|
+
},
|
|
4114
|
+
},
|
|
4115
|
+
"400": {
|
|
4116
|
+
description: "Invalid campaign id",
|
|
4117
|
+
content: {
|
|
4118
|
+
"application/json": {
|
|
4119
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
4120
|
+
},
|
|
4121
|
+
},
|
|
4122
|
+
},
|
|
4123
|
+
"404": {
|
|
4124
|
+
description: "Campaign or segment not found",
|
|
4125
|
+
content: {
|
|
4126
|
+
"application/json": {
|
|
4127
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
4128
|
+
},
|
|
4129
|
+
},
|
|
4130
|
+
},
|
|
4131
|
+
"500": {
|
|
4132
|
+
description: "Internal server error",
|
|
4133
|
+
content: {
|
|
4134
|
+
"application/json": {
|
|
4135
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
4136
|
+
},
|
|
4137
|
+
},
|
|
4138
|
+
},
|
|
4139
|
+
},
|
|
4140
|
+
},
|
|
4141
|
+
},
|
|
4142
|
+
"/api/messaging/send": {
|
|
4143
|
+
post: {
|
|
4144
|
+
summary: "Send Message",
|
|
4145
|
+
description: "Send a message for immediate processing.",
|
|
4146
|
+
tags: ["Messaging"],
|
|
4147
|
+
requestBody: {
|
|
4148
|
+
required: true,
|
|
4149
|
+
content: {
|
|
4150
|
+
"application/json": {
|
|
4151
|
+
schema: { $ref: "#/components/schemas/CreateMessagingMessageRequest" },
|
|
4152
|
+
},
|
|
4153
|
+
},
|
|
4154
|
+
},
|
|
4155
|
+
responses: {
|
|
4156
|
+
"202": {
|
|
4157
|
+
description: "Message accepted for processing",
|
|
4158
|
+
content: {
|
|
4159
|
+
"application/json": {
|
|
4160
|
+
schema: { $ref: "#/components/schemas/MessagingAcceptedResponse" },
|
|
4161
|
+
},
|
|
4162
|
+
},
|
|
4163
|
+
},
|
|
4164
|
+
"400": {
|
|
4165
|
+
description: "Validation error",
|
|
4166
|
+
content: {
|
|
4167
|
+
"application/json": {
|
|
4168
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
4169
|
+
},
|
|
4170
|
+
},
|
|
4171
|
+
},
|
|
4172
|
+
"500": {
|
|
4173
|
+
description: "Internal server error",
|
|
4174
|
+
content: {
|
|
4175
|
+
"application/json": {
|
|
4176
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
4177
|
+
},
|
|
4178
|
+
},
|
|
4179
|
+
},
|
|
4180
|
+
},
|
|
4181
|
+
},
|
|
4182
|
+
},
|
|
4183
|
+
"/api/messaging/schedule": {
|
|
4184
|
+
post: {
|
|
4185
|
+
summary: "Schedule Message",
|
|
4186
|
+
description: "Schedule a message for future processing.",
|
|
4187
|
+
tags: ["Messaging"],
|
|
4188
|
+
requestBody: {
|
|
4189
|
+
required: true,
|
|
4190
|
+
content: {
|
|
4191
|
+
"application/json": {
|
|
4192
|
+
schema: { $ref: "#/components/schemas/ScheduleMessagingMessageRequest" },
|
|
4193
|
+
},
|
|
4194
|
+
},
|
|
4195
|
+
},
|
|
4196
|
+
responses: {
|
|
4197
|
+
"202": {
|
|
4198
|
+
description: "Message scheduled for processing",
|
|
4199
|
+
content: {
|
|
4200
|
+
"application/json": {
|
|
4201
|
+
schema: { $ref: "#/components/schemas/MessagingAcceptedResponse" },
|
|
4202
|
+
},
|
|
4203
|
+
},
|
|
4204
|
+
},
|
|
4205
|
+
"400": {
|
|
4206
|
+
description: "Validation error",
|
|
4207
|
+
content: {
|
|
4208
|
+
"application/json": {
|
|
4209
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
4210
|
+
},
|
|
4211
|
+
},
|
|
4212
|
+
},
|
|
4213
|
+
"500": {
|
|
4214
|
+
description: "Internal server error",
|
|
4215
|
+
content: {
|
|
4216
|
+
"application/json": {
|
|
4217
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
4218
|
+
},
|
|
4219
|
+
},
|
|
4220
|
+
},
|
|
4221
|
+
},
|
|
4222
|
+
},
|
|
4223
|
+
},
|
|
4224
|
+
"/api/messaging/{messageId}": {
|
|
4225
|
+
get: {
|
|
4226
|
+
summary: "Get Message Status",
|
|
4227
|
+
description: "Fetch a message and its delivery status by ID.",
|
|
4228
|
+
tags: ["Messaging"],
|
|
4229
|
+
parameters: [
|
|
4230
|
+
{
|
|
4231
|
+
name: "messageId",
|
|
4232
|
+
in: "path",
|
|
4233
|
+
required: true,
|
|
4234
|
+
description: "Message ID",
|
|
4235
|
+
schema: { type: "string", example: "1" },
|
|
4236
|
+
},
|
|
4237
|
+
],
|
|
4238
|
+
responses: {
|
|
4239
|
+
"200": {
|
|
4240
|
+
description: "Message retrieved successfully",
|
|
4241
|
+
content: {
|
|
4242
|
+
"application/json": {
|
|
4243
|
+
schema: { $ref: "#/components/schemas/MessagingMessageResponse" },
|
|
4244
|
+
},
|
|
4245
|
+
},
|
|
4246
|
+
},
|
|
4247
|
+
"404": {
|
|
4248
|
+
description: "Message not found",
|
|
4249
|
+
content: {
|
|
4250
|
+
"application/json": {
|
|
4251
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
4252
|
+
},
|
|
4253
|
+
},
|
|
4254
|
+
},
|
|
4255
|
+
"500": {
|
|
4256
|
+
description: "Internal server error",
|
|
4257
|
+
content: {
|
|
4258
|
+
"application/json": {
|
|
4259
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
4260
|
+
},
|
|
4261
|
+
},
|
|
4262
|
+
},
|
|
4263
|
+
},
|
|
4264
|
+
},
|
|
4265
|
+
},
|
|
4266
|
+
},
|
|
4267
|
+
tags: [
|
|
4268
|
+
{
|
|
4269
|
+
name: "Health",
|
|
4270
|
+
description: "Health check and service status endpoints",
|
|
4271
|
+
},
|
|
4272
|
+
{
|
|
4273
|
+
name: "Authentication",
|
|
4274
|
+
description: "User authentication and authorization endpoints",
|
|
4275
|
+
},
|
|
4276
|
+
{
|
|
4277
|
+
name: "User",
|
|
4278
|
+
description: "User management endpoints",
|
|
4279
|
+
},
|
|
4280
|
+
{
|
|
4281
|
+
name: "Specializations",
|
|
4282
|
+
description: "Specialization hierarchy management endpoints",
|
|
4283
|
+
},
|
|
4284
|
+
{
|
|
4285
|
+
name: "Media",
|
|
4286
|
+
description:
|
|
4287
|
+
"Media management endpoints for uploads, retrieval, and deletion",
|
|
4288
|
+
},
|
|
4289
|
+
{
|
|
4290
|
+
name: "Marketing",
|
|
4291
|
+
description: "Marketing service endpoints for contacts, consents, segments, and campaigns",
|
|
4292
|
+
},
|
|
4293
|
+
{
|
|
4294
|
+
name: "Messaging",
|
|
4295
|
+
description: "Messaging service endpoints for sending and tracking messages",
|
|
4296
|
+
},
|
|
4297
|
+
{
|
|
4298
|
+
name: "User Metadata",
|
|
4299
|
+
description: "Endpoints for managing user-specific metadata",
|
|
4300
|
+
},
|
|
4301
|
+
{
|
|
4302
|
+
name: "User Specializations Profile",
|
|
4303
|
+
description: "Endpoints for managing user specializations profiles",
|
|
4304
|
+
},
|
|
4305
|
+
{
|
|
4306
|
+
name: "Admin",
|
|
4307
|
+
description: "Admin-only endpoints for managing application roles and permissions. Requires authentication and admin/super-admin role.",
|
|
4308
|
+
},
|
|
4309
|
+
],
|
|
4310
|
+
},
|
|
4311
|
+
apis: [
|
|
4312
|
+
"./apps/api-gateway-service/src/routes/*.ts",
|
|
4313
|
+
"./apps/auth-service/src/routes/*.ts",
|
|
4314
|
+
"./apps/user-service/src/routes/*.ts",
|
|
4315
|
+
"./apps/media-service/src/routes/*.ts",
|
|
4316
|
+
"./apps/marketing-service/src/routes/*.ts",
|
|
4317
|
+
"./apps/messaging-service/src/routes/*.ts",
|
|
4318
|
+
"./apps/api-gateway-service/src/routes/*.js",
|
|
4319
|
+
"./apps/auth-service/src/routes/*.js",
|
|
4320
|
+
"./apps/user-service/src/routes/*.js",
|
|
4321
|
+
"./apps/media-service/src/routes/*.js",
|
|
4322
|
+
"./apps/marketing-service/src/routes/*.js",
|
|
4323
|
+
"./apps/messaging-service/src/routes/*.js",
|
|
4324
|
+
],
|
|
4325
|
+
};
|
|
4326
|
+
|
|
4327
|
+
export const swaggerSpec = swaggerJsdoc(options);
|
|
4328
|
+
|
|
4329
|
+
export const swaggerUiOptions = {
|
|
4330
|
+
customCss: `
|
|
4331
|
+
/* Main background and text */
|
|
4332
|
+
body {
|
|
4333
|
+
background-color: #1a1a1a;
|
|
4334
|
+
color: #f0f0f0 !important;
|
|
4335
|
+
}
|
|
4336
|
+
|
|
4337
|
+
.swagger-ui {
|
|
4338
|
+
background-color: #1a1a1a;
|
|
4339
|
+
color: #f0f0f0 !important;
|
|
4340
|
+
}
|
|
4341
|
+
|
|
4342
|
+
/* Force ALL text to be white */
|
|
4343
|
+
.swagger-ui *,
|
|
4344
|
+
.swagger-ui .opblock-tag,
|
|
4345
|
+
.swagger-ui .opblock .opblock-summary-operation-id,
|
|
4346
|
+
.swagger-ui .opblock .opblock-summary-path,
|
|
4347
|
+
.swagger-ui .opblock .opblock-summary-path span,
|
|
4348
|
+
.swagger-ui .opblock .opblock-summary-description,
|
|
4349
|
+
.swagger-ui .model-title,
|
|
4350
|
+
.swagger-ui label,
|
|
4351
|
+
.swagger-ui span,
|
|
4352
|
+
.swagger-ui h1, .swagger-ui h2, .swagger-ui h3, .swagger-ui h4, .swagger-ui h5, .swagger-ui h6,
|
|
4353
|
+
.swagger-ui .parameter__name,
|
|
4354
|
+
.swagger-ui .parameter__type,
|
|
4355
|
+
.swagger-ui table thead tr th,
|
|
4356
|
+
.swagger-ui table tbody tr td,
|
|
4357
|
+
.swagger-ui .response-col_status,
|
|
4358
|
+
.swagger-ui .response-col_description,
|
|
4359
|
+
.swagger-ui .tab li,
|
|
4360
|
+
.swagger-ui section.models h4,
|
|
4361
|
+
.swagger-ui section.models h5,
|
|
4362
|
+
.swagger-ui .servers > label {
|
|
4363
|
+
color: #f0f0f0 !important;
|
|
4364
|
+
}
|
|
4365
|
+
|
|
4366
|
+
/* Override any SVGs or special elements */
|
|
4367
|
+
.swagger-ui svg {
|
|
4368
|
+
fill: #f0f0f0 !important;
|
|
4369
|
+
}
|
|
4370
|
+
|
|
4371
|
+
.swagger-ui .scheme-container {
|
|
4372
|
+
background-color: #1a1a1a;
|
|
4373
|
+
}
|
|
4374
|
+
|
|
4375
|
+
.swagger-ui .opblock .opblock-section-header {
|
|
4376
|
+
background-color: #1a1a1a;
|
|
4377
|
+
}
|
|
4378
|
+
|
|
4379
|
+
.swagger-ui .dialog-ux .modal-ux {
|
|
4380
|
+
background-color: #1a1a1a;
|
|
4381
|
+
}
|
|
4382
|
+
|
|
4383
|
+
/* Operation blocks */
|
|
4384
|
+
.swagger-ui .opblock {
|
|
4385
|
+
background-color: #2d2d2d;
|
|
4386
|
+
border-color: #444;
|
|
4387
|
+
}
|
|
4388
|
+
|
|
4389
|
+
/* Input fields */
|
|
4390
|
+
.swagger-ui input[type=text],
|
|
4391
|
+
.swagger-ui textarea {
|
|
4392
|
+
background-color: rgb(12, 12, 12);
|
|
4393
|
+
color: white !important;
|
|
4394
|
+
}
|
|
4395
|
+
|
|
4396
|
+
.swagger-ui input,
|
|
4397
|
+
.swagger-ui select,
|
|
4398
|
+
.swagger-ui textarea {
|
|
4399
|
+
background-color: #333;
|
|
4400
|
+
color: white !important;
|
|
4401
|
+
}
|
|
4402
|
+
|
|
4403
|
+
/* Code blocks */
|
|
4404
|
+
.swagger-ui .highlight-code,
|
|
4405
|
+
.swagger-ui .microlight {
|
|
4406
|
+
background-color:rgb(69, 69, 68) !important;
|
|
4407
|
+
color: #f8f8f2 !important;
|
|
4408
|
+
}
|
|
4409
|
+
`,
|
|
4410
|
+
customSiteTitle: "GGCoach API Documentation",
|
|
4411
|
+
customfavIcon: "/favicon.ico",
|
|
4412
|
+
};
|
|
4413
|
+
|
|
4414
|
+
export const swaggerHandler = (_req: Request, res: Response) => {
|
|
4415
|
+
res.setHeader("Content-Type", "application/json");
|
|
4416
|
+
res.send(swaggerSpec);
|
|
4417
|
+
};
|