"description":"Danh sách permission strings (ghi đà toàn bộ permissions hiện tại)",
"example":[
"posts:read",
"posts:write",
"posts:delete"
]
}
}
}
}
},
},
...
@@ -4915,59 +5143,70 @@
...
@@ -4915,59 +5143,70 @@
}
}
}
}
},
},
"/api/v1.0/term/{id}":{
"/api/v1.0/user/{id}/status":{
"get":{
"patch":{
"tags":[
"tags":[
"Term"
"User"
],
"summary":"Toggle user status (enable/disable)",
"description":"Bật hoặc tắt trạng thái tài khoản user. Chỉ users:write mới có quyền.",
"security":[
{
"BearerAuth":[]
}
],
],
"summary":"Get term by ID",
"description":"Retrieve a single term with positions and members",
"parameters":[
"parameters":[
{
{
"name":"id",
"name":"id",
"in":"path",
"in":"path",
"required":true,
"required":true,
"description":"Term ID",
"description":"User ID",
"schema":{
"schema":{
"type":"string",
"type":"string",
"format":"uuid"
"format":"uuid"
}
}
}
}
],
],
"responses":{
"requestBody":{
"200":{
"required":true,
"description":"Term retrieved successfully",
"content":{
"content":{
"application/json":{
"application/json":{
"schema":{
"schema":{
"allOf":[
{
"$ref":"#/components/schemas/ApiResponse"
},
{
"type":"object",
"type":"object",
"properties":{
"properties":{
"responseData":{
"status":{
"$ref":"#/components/schemas/TermResponse"
"type":"string",
}
"enum":[
"active",
"inactive"
],
"description":"Trạng thái mới của user"
}
}
}
}
]
}
}
}
}
}
}
},
},
"responses":{
"200":{
"description":"Status updated successfully"
},
"403":{
"description":"Cannot change your own status"
},
"404":{
"404":{
"description":"Term not found"
"description":"User not found"
}
}
}
}
}
},
},
"put":{
"/api/v1.0/user/{id}/role":{
"post":{
"tags":[
"tags":[
"Term"
"User"
],
],
"summary":"Update term by ID",
"summary":"Assign role to user",
"description":"Update term fields and optionally replace positions and members",
"description":"Assign one or more roles to a user. Replaces existing non-primary roles.",
"security":[
"security":[
{
{
"BearerAuth":[]
"BearerAuth":[]
...
@@ -4978,7 +5217,7 @@
...
@@ -4978,7 +5217,7 @@
"name":"id",
"name":"id",
"in":"path",
"in":"path",
"required":true,
"required":true,
"description":"Term ID",
"description":"User ID",
"schema":{
"schema":{
"type":"string",
"type":"string",
"format":"uuid"
"format":"uuid"
...
@@ -4990,26 +5229,214 @@
...
@@ -4990,26 +5229,214 @@
"content":{
"content":{
"application/json":{
"application/json":{
"schema":{
"schema":{
"$ref":"#/components/schemas/TermUpdateRequest"
"type":"object",
"properties":{
"role_id":{
"type":"string",
"format":"uuid",
"description":"Role ID to assign"
},
"is_primary":{
"type":"boolean",
"default":false,
"description":"Set as primary role"
}
}
}
}
}
}
}
}
},
},
"responses":{
"responses":{
"200":{
"200":{
"description":"Term updated successfully",
"description":"Role assigned successfully"
"content":{
"application/json":{
"schema":{
"allOf":[
{
"$ref":"#/components/schemas/ApiResponse"
},
},
{
"404":{
"type":"object",
"description":"User or role not found"
"properties":{
}
"responseData":{
}
"$ref":"#/components/schemas/TermResponse"
},
"delete":{
"tags":[
"User"
],
"summary":"Remove role from user",
"description":"Remove a role from a user",
"security":[
{
"BearerAuth":[]
}
],
"parameters":[
{
"name":"id",
"in":"path",
"required":true,
"description":"User ID",
"schema":{
"type":"string",
"format":"uuid"
}
}
],
"requestBody":{
"required":true,
"content":{
"application/json":{
"schema":{
"type":"object",
"properties":{
"role_id":{
"type":"string",
"format":"uuid",
"description":"Role ID to remove"
}
}
}
}
}
},
"responses":{
"200":{
"description":"Role removed successfully"
},
"404":{
"description":"User or role assignment not found"
}
}
}
},
"/api/v1.0/user/{id}/reset-password":{
"post":{
"tags":[
"User"
],
"summary":"Reset user password to default",
"description":"Reset password của user về mật khẩu mặc định vcci@2026. Chỉ users:write mới có quyền.",
"security":[
{
"BearerAuth":[]
}
],
"parameters":[
{
"name":"id",
"in":"path",
"required":true,
"description":"User ID",
"schema":{
"type":"string",
"format":"uuid"
}
}
],
"responses":{
"200":{
"description":"Password reset successfully"
},
"403":{
"description":"Cannot reset your own password"
},
"404":{
"description":"User not found"
}
}
}
},
"/api/v1.0/term/{id}":{
"get":{
"tags":[
"Term"
],
"summary":"Get term by ID",
"description":"Retrieve a single term with positions and members",
"parameters":[
{
"name":"id",
"in":"path",
"required":true,
"description":"Term ID",
"schema":{
"type":"string",
"format":"uuid"
}
}
],
"responses":{
"200":{
"description":"Term retrieved successfully",
"content":{
"application/json":{
"schema":{
"allOf":[
{
"$ref":"#/components/schemas/ApiResponse"
},
{
"type":"object",
"properties":{
"responseData":{
"$ref":"#/components/schemas/TermResponse"
}
}
}
]
}
}
}
},
"404":{
"description":"Term not found"
}
}
},
"put":{
"tags":[
"Term"
],
"summary":"Update term by ID",
"description":"Update term fields and optionally replace positions and members",
"security":[
{
"BearerAuth":[]
}
],
"parameters":[
{
"name":"id",
"in":"path",
"required":true,
"description":"Term ID",
"schema":{
"type":"string",
"format":"uuid"
}
}
],
"requestBody":{
"required":true,
"content":{
"application/json":{
"schema":{
"$ref":"#/components/schemas/TermUpdateRequest"
}
}
}
},
"responses":{
"200":{
"description":"Term updated successfully",
"content":{
"application/json":{
"schema":{
"allOf":[
{
"$ref":"#/components/schemas/ApiResponse"
},
{
"type":"object",
"properties":{
"responseData":{
"$ref":"#/components/schemas/TermResponse"
}
}
}
}
}
}
...
@@ -5957,6 +6384,38 @@
...
@@ -5957,6 +6384,38 @@
}
}
},
},
"/api/v1.0/role/{id}":{
"/api/v1.0/role/{id}":{
"get":{
"tags":[
"Role"
],
"summary":"Get role by ID",
"description":"Retrieve a single role by its ID, including users assigned to this role",
"security":[
{
"BearerAuth":[]
}
],
"parameters":[
{
"name":"id",
"in":"path",
"required":true,
"description":"Role ID",
"schema":{
"type":"string",
"format":"uuid"
}
}
],
"responses":{
"200":{
"description":"Successfully retrieved role"
},
"404":{
"description":"Role not found"
}
}
},
"put":{
"put":{
"tags":[
"tags":[
"Role"
"Role"
...
@@ -5992,29 +6451,45 @@
...
@@ -5992,29 +6451,45 @@
},
},
"responses":{
"responses":{
"200":{
"200":{
"description":"Role updated successfully",
"description":"Role updated successfully"
"content":{
"application/json":{
"schema":{
"allOf":[
{
"$ref":"#/components/schemas/ApiResponse"
},
},
{
"400":{
"type":"object",
"description":"Invalid input data"
"properties":{
},
"responseData":{
"404":{
"$ref":"#/components/schemas/Role"
"description":"Role not found"
}
}
}
}
}
]
},
"delete":{
"tags":[
"Role"
],
"summary":"Delete role by ID",
"description":"Delete a single role by its ID. Cannot delete system roles (system_admin).",
"security":[
{
"BearerAuth":[]
}
}
],
"parameters":[
{
"name":"id",
"in":"path",
"required":true,
"description":"Role ID",
"schema":{
"type":"string",
"format":"uuid"
}
}
}
}
],
"responses":{
"200":{
"description":"Role deleted successfully"
},
},
"400":{
"400":{
"description":"Invalid input data"
"description":"Cannot delete system role"
},
},
"404":{
"404":{
"description":"Role not found"
"description":"Role not found"
...
@@ -6029,6 +6504,11 @@
...
@@ -6029,6 +6504,11 @@
],
],
"summary":"Get all roles",
"summary":"Get all roles",
"description":"Retrieve a list of roles with pagination, filtering and sorting",
"description":"Retrieve a list of roles with pagination, filtering and sorting",
"security":[
{
"BearerAuth":[]
}
],
"parameters":[
"parameters":[
{
{
"$ref":"#/components/parameters/filters"
"$ref":"#/components/parameters/filters"
...
@@ -6058,15 +6538,13 @@
...
@@ -6058,15 +6538,13 @@
}
}
}
}
}
}
}
},
},
"/api/v1.0/role/bulk":{
"post":{
"post":{
"tags":[
"tags":[
"Role"
"Role"
],
],
"summary":"Bulk create roles",
"summary":"Create a new role",
"description":"Create multiple role records at once",
"description":"Create a new role with permissions",
"security":[
"security":[
{
{
"BearerAuth":[]
"BearerAuth":[]
...
@@ -6077,8 +6555,51 @@
...
@@ -6077,8 +6555,51 @@
"content":{
"content":{
"application/json":{
"application/json":{
"schema":{
"schema":{
"$ref":"#/components/schemas/RoleBulkCreate"
"type":"object",
}
"properties":{
"name":{
"type":"string"
},
"description":{
"type":"string"
},
"permissions":{
"type":"array",
"items":{
"type":"string"
}
}
}
}
}
}
},
"responses":{
"200":{
"description":"Role created successfully"
}
}
}
},
"/api/v1.0/role/bulk":{
"post":{
"tags":[
"Role"
],
"summary":"Bulk create roles",
"description":"Create multiple role records at once",
"security":[
{
"BearerAuth":[]
}
],
"requestBody":{
"required":true,
"content":{
"application/json":{
"schema":{
"$ref":"#/components/schemas/RoleBulkCreate"
}
}
}
}
}
},
},
...
@@ -7553,13 +8074,37 @@
...
@@ -7553,13 +8074,37 @@
}
}
}
}
},
},
"/api/v1.0/permission/sync":{
"post":{
"tags":[
"Permission"
],
"summary":"Sync permissions from config",
"description":"Sync permissions từ file config vào database. Chỉ system_admin mới có quyền.",
"security":[
{
"BearerAuth":[]
}
],
"responses":{
"200":{
"description":"Permissions synced successfully"
}
}
}
},
"/api/v1.0/permission":{
"/api/v1.0/permission":{
"get":{
"get":{
"tags":[
"tags":[
"Permission"
"Permission"
],
],
"summary":"Get all permissions",
"summary":"Get all permissions",
"description":"Retrieve a list of permissions with pagination, filtering and sorting",
"description":"Retrieve a list of permissions with pagination, filtering and sorting. Also returns structured permissions grouped by resource.",
"security":[
{
"BearerAuth":[]
}
],
"parameters":[
"parameters":[
{
{
"$ref":"#/components/parameters/filters"
"$ref":"#/components/parameters/filters"
...
@@ -7706,6 +8251,183 @@
...
@@ -7706,6 +8251,183 @@
}
}
}
}
},
},
"/api/v1.0/password-reset-request":{
"get":{
"tags":[
"PasswordResetRequest"
],
"summary":"List password reset requests (admin)",
"description":"Lấy danh sách yêu cầu reset mật khẩu. Yêu cầu quyền users:write.",
"security":[
{
"BearerAuth":[]
}
],
"parameters":[
{
"in":"query",
"name":"page",
"schema":{
"type":"integer",
"default":1
}
},
{
"in":"query",
"name":"pageSize",
"schema":{
"type":"integer",
"default":10
}
},
{
"in":"query",
"name":"status",
"schema":{
"type":"string",
"enum":[
"PENDING",
"RESOLVED",
"REJECTED",
"all"
],
"default":"all"
}
},
{
"in":"query",
"name":"sortField",
"schema":{
"type":"string",
"default":"created_at"
}
},
{
"in":"query",
"name":"sortOrder",
"schema":{
"type":"string",
"enum":[
"asc",
"desc"
],
"default":"desc"
}
}
],
"responses":{
"200":{
"description":"List of password reset requests"
},
"401":{
"description":"Unauthorized"
},
"403":{
"description":"Forbidden"
}
}
}
},
"/api/v1.0/password-reset-request/{id}/resolve":{
"post":{
"tags":[
"PasswordResetRequest"
],
"summary":"Resolve a password reset request (reset password)",
"description":"Admin xử lý yêu cầu reset mật khẩu.\n- Reset password cho user về mật khẩu mặc định (vcci@2026) hoặc mật khẩu tùy chỉnh.\n- Set must_change_password=true để user phải đổi mật khẩu khi login.\n- Đánh dấu request là RESOLVED.\n",
"security":[
{
"BearerAuth":[]
}
],
"parameters":[
{
"in":"path",
"name":"id",
"required":true,
"schema":{
"type":"string",
"format":"uuid"
}
}
],
"requestBody":{
"content":{
"application/json":{
"schema":{
"type":"object",
"properties":{
"newPassword":{
"type":"string",
"description":"Mật khẩu mới (nếu bỏ trống sẽ dùng vcci@2026)"
},
"resolveNote":{
"type":"string",
"description":"Ghi chú của admin"
}
}
}
}
}
},
"responses":{
"200":{
"description":"Password reset successfully"
},
"404":{
"description":"Request not found"
}
}
}
},
"/api/v1.0/password-reset-request/{id}/reject":{
"post":{
"tags":[
"PasswordResetRequest"
],
"summary":"Reject a password reset request",
"description":"Admin từ chối yêu cầu reset mật khẩu.",
"security":[
{
"BearerAuth":[]
}
],
"parameters":[
{
"in":"path",
"name":"id",
"required":true,
"schema":{
"type":"string",
"format":"uuid"
}
}
],
"requestBody":{
"content":{
"application/json":{
"schema":{
"type":"object",
"properties":{
"resolveNote":{
"type":"string",
"description":"Lý do từ chối"
}
}
}
}
}
},
"responses":{
"200":{
"description":"Request rejected"
},
"404":{
"description":"Request not found"
}
}
}
},
"/api/v1.0/pageConfig/{id}":{
"/api/v1.0/pageConfig/{id}":{
"get":{
"get":{
"tags":[
"tags":[
...
@@ -10469,6 +11191,363 @@
...
@@ -10469,6 +11191,363 @@
}
}
}
}
}
}
},
"/api/v1.0/auth/forgot-password/request":{
"post":{
"tags":[
"Authentication"
],
"summary":"Forgot password - submit reset request to admin",
"description":"User quên mật khẩu gửi yêu cầu reset về admin.\nAdmin sẽ xem và xử lý (reset password) thay vì gửi OTP qua email.\nAnti-enumeration: luôn trả 200 kể cả khi email không tồn tại.\n",
"requestBody":{
"required":true,
"content":{
"application/json":{
"schema":{
"type":"object",
"required":[
"email"
],
"properties":{
"email":{
"type":"string",
"format":"email"
},
"note":{
"type":"string",
"description":"Ghi chú thêm từ user (tên, lý do, etc.)"
}
}
}
}
}
},
"responses":{
"200":{
"description":"Yêu cầu đã được ghi nhận"
},
"400":{
"description":"Email không hợp lệ"
},
"429":{
"description":"Too many requests"
}
}
}
},
"/api/v1.0/advertisement/{id}":{
"get":{
"tags":[
"Advertisement"
],
"summary":"Get advertisement by ID",
"description":"Retrieve a single advertisement record by its ID",