diff --git a/contracts/openapi.external.json b/contracts/openapi.external.json index 24f9b2b5..056cba48 100644 --- a/contracts/openapi.external.json +++ b/contracts/openapi.external.json @@ -1,295 +1,295 @@ { - "components": { - "schemas": { - "AskAssistantRequest": { - "additionalProperties": false, - "properties": { - "locale": { - "nullable": true, - "type": "string" - }, - "question": { - "nullable": true, - "type": "string" - } - }, - "type": "object" - }, - "CityType": { - "enum": [ - 0, - 1, - 2, - 3 + "openapi": "3.0.1", + "info": { + "title": "CCE External API", + "description": "CCE Knowledge Center — CCE External API", + "version": "v1" + }, + "paths": { + "/api/about": { + "get": { + "tags": [ + "About" ], - "format": "int32", - "type": "integer" - }, - "CreatePostRequest": { - "additionalProperties": false, - "properties": { - "content": { - "nullable": true, - "type": "string" + "operationId": "GetPublicAboutSettings", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicAboutSettingsDtoResponse" + } + } + } }, - "isAnswerable": { - "type": "boolean" + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicAboutSettingsDtoResponse" + } + } + } }, - "locale": { - "nullable": true, - "type": "string" + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicAboutSettingsDtoResponse" + } + } + } }, - "topicId": { - "format": "uuid", - "type": "string" - } - }, - "type": "object" - }, - "CreateReplyRequest": { - "additionalProperties": false, - "properties": { - "content": { - "nullable": true, - "type": "string" + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicAboutSettingsDtoResponse" + } + } + } }, - "locale": { - "nullable": true, - "type": "string" + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicAboutSettingsDtoResponse" + } + } + } }, - "parentReplyId": { - "format": "uuid", - "nullable": true, - "type": "string" + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicAboutSettingsDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicAboutSettingsDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicAboutSettingsDtoResponse" + } + } + } } - }, - "type": "object" - }, - "EditReplyRequest": { - "additionalProperties": false, - "properties": { + } + } + }, + "/api/assets": { + "post": { + "tags": [ + "Assets" + ], + "operationId": "UploadAsset", + "requestBody": { "content": { - "nullable": true, - "type": "string" + "multipart/form-data": { + "schema": { + "required": [ + "file" + ], + "type": "object", + "properties": { + "file": { + "type": "string", + "format": "binary" + } + } + }, + "encoding": { + "file": { + "style": "form" + } + } + } } }, - "type": "object" - }, - "KnowledgeLevel": { - "enum": [ - 0, - 1, - 2 + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/assets/{id}": { + "get": { + "tags": [ + "Assets" ], - "format": "int32", - "type": "integer" - }, - "MarkAnswerRequest": { - "additionalProperties": false, - "properties": { - "replyId": { - "format": "uuid", - "type": "string" + "operationId": "GetAssetById", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } } - }, - "type": "object" - }, - "NotificationStatus": { - "enum": [ - 0, - 1, - 2, - 3 ], - "format": "int32", - "type": "integer" - }, - "RatePostRequest": { - "additionalProperties": false, - "properties": { - "stars": { - "format": "int32", - "type": "integer" + "responses": { + "200": { + "description": "OK" } - }, - "type": "object" - }, - "ResourceType": { - "enum": [ - 0, - 1, - 2, - 3, - 4 + } + } + }, + "/api/assistant/query": { + "post": { + "tags": [ + "Assistant" ], - "format": "int32", - "type": "integer" - }, - "RunScenarioRequest": { - "additionalProperties": false, - "properties": { - "cityType": { - "$ref": "#/components/schemas/CityType" - }, - "configurationJson": { - "nullable": true, - "type": "string" + "operationId": "AskAssistant", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AskAssistantRequest" + } + } }, - "targetYear": { - "format": "int32", - "type": "integer" - } + "required": true }, - "type": "object" - }, - "SaveScenarioRequest": { - "additionalProperties": false, - "properties": { - "cityType": { - "$ref": "#/components/schemas/CityType" - }, - "configurationJson": { - "nullable": true, - "type": "string" - }, - "nameAr": { - "nullable": true, - "type": "string" - }, - "nameEn": { - "nullable": true, - "type": "string" - }, - "targetYear": { - "format": "int32", - "type": "integer" + "responses": { + "200": { + "description": "OK" } - }, - "type": "object" - }, - "SearchableType": { - "enum": [ - 0, - 1, - 2, - 3, - 4 + } + } + }, + "/api/auth/register": { + "post": { + "tags": [ + "Auth" ], - "format": "int32", - "type": "integer" - }, - "ServiceRatingRequest": { - "additionalProperties": false, - "properties": { - "commentAr": { - "nullable": true, - "type": "string" + "operationId": "ExternalRegisterUser", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RegisterUserRequest" + } + } }, - "commentEn": { - "nullable": true, - "type": "string" + "required": true + }, + "responses": { + "201": { + "description": "Created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthUserDtoResponse" + } + } + } }, - "locale": { - "nullable": true, - "type": "string" + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthUserDtoResponse" + } + } + } }, - "page": { - "nullable": true, - "type": "string" + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthUserDtoResponse" + } + } + } }, - "rating": { - "format": "int32", - "type": "integer" - } - }, - "type": "object" - }, - "SubmitExpertRequestRequest": { - "additionalProperties": false, - "properties": { - "requestedBioAr": { - "nullable": true, - "type": "string" - }, - "requestedBioEn": { - "nullable": true, - "type": "string" - }, - "requestedTags": { - "items": { - "type": "string" - }, - "nullable": true, - "type": "array" - } - }, - "type": "object" - }, - "UpdateMyProfileRequest": { - "additionalProperties": false, - "properties": { - "avatarUrl": { - "nullable": true, - "type": "string" + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthUserDtoResponse" + } + } + } }, - "countryId": { - "format": "uuid", - "nullable": true, - "type": "string" + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthUserDtoResponse" + } + } + } }, - "interests": { - "items": { - "type": "string" - }, - "nullable": true, - "type": "array" + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthUserDtoResponse" + } + } + } }, - "knowledgeLevel": { - "$ref": "#/components/schemas/KnowledgeLevel" + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthUserDtoResponse" + } + } + } }, - "localePreference": { - "nullable": true, - "type": "string" - } - }, - "type": "object" - } - } - }, - "info": { - "description": "CCE Knowledge Center — CCE External API", - "title": "CCE External API", - "version": "v1" - }, - "openapi": "3.0.1", - "paths": { - "/": { - "get": { - "responses": { - "200": { + "500": { + "description": "Internal Server Error", "content": { - "text/plain": { + "application/json": { "schema": { - "type": "string" + "$ref": "#/components/schemas/AuthUserDtoResponse" } } - }, - "description": "OK" + } } - }, - "tags": [ - "CCE.Api.External" - ] + } } }, - "/api/assistant/query": { + "/api/auth/login": { "post": { - "operationId": "AskAssistant", + "tags": [ + "Auth" + ], + "operationId": "ExternalLogin", "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/AskAssistantRequest" + "$ref": "#/components/schemas/LoginRequest" } } }, @@ -297,35 +297,99 @@ }, "responses": { "200": { - "description": "OK" - } - }, - "tags": [ - "Assistant" - ] - } - }, - "/api/categories": { - "get": { - "operationId": "ListPublicCategories", - "responses": { - "200": { - "description": "OK" + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokenDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokenDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokenDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokenDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokenDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokenDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokenDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokenDtoResponse" + } + } + } } - }, - "tags": [ - "CategoriesPublic" - ] + } } }, - "/api/community/posts": { + "/api/auth/refresh": { "post": { - "operationId": "CreatePost", + "tags": [ + "Auth" + ], + "operationId": "ExternalRefreshToken", "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/CreatePostRequest" + "$ref": "#/components/schemas/RefreshTokenRequest" } } }, @@ -333,57 +397,99 @@ }, "responses": { "200": { - "description": "OK" - } - }, - "tags": [ - "Community" - ] - } - }, - "/api/community/posts/{id}": { - "get": { - "operationId": "GetPublicPostById", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokenDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokenDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokenDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokenDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokenDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokenDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokenDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokenDtoResponse" + } + } } } - ], - "responses": { - "200": { - "description": "OK" - } - }, - "tags": [ - "Community" - ] + } } }, - "/api/community/posts/{id}/mark-answer": { + "/api/auth/forgot-password": { "post": { - "operationId": "MarkPostAnswered", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } + "tags": [ + "Auth" ], + "operationId": "ExternalForgotPassword", "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/MarkAnswerRequest" + "$ref": "#/components/schemas/ForgotPasswordRequest" } } }, @@ -391,105 +497,99 @@ }, "responses": { "200": { - "description": "OK" - } - }, - "tags": [ - "Community" - ] - } - }, - "/api/community/posts/{id}/rate": { - "post": { - "operationId": "RatePost", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RatePostRequest" + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } } } }, - "required": true - }, - "responses": { - "200": { - "description": "OK" - } - }, - "tags": [ - "Community" - ] - } - }, - "/api/community/posts/{id}/replies": { - "get": { - "operationId": "ListPublicPostReplies", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } } }, - { - "in": "query", - "name": "page", - "schema": { - "format": "int32", - "type": "integer" + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } } }, - { - "in": "query", - "name": "pageSize", - "schema": { - "format": "int32", - "type": "integer" + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } } - } - ], - "responses": { - "200": { - "description": "OK" - } - }, - "tags": [ - "Community" - ] - }, - "post": { - "operationId": "CreateReply", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } } } + } + } + }, + "/api/auth/reset-password": { + "post": { + "tags": [ + "Auth" ], + "operationId": "ExternalResetPassword", "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/CreateReplyRequest" + "$ref": "#/components/schemas/ResetPasswordRequest" } } }, @@ -497,33 +597,99 @@ }, "responses": { "200": { - "description": "OK" + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } + } } - }, - "tags": [ - "Community" - ] + } } }, - "/api/community/replies/{id}": { - "put": { - "operationId": "EditReply", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } + "/api/auth/logout": { + "post": { + "tags": [ + "Auth" ], + "operationId": "ExternalLogout", "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/EditReplyRequest" + "$ref": "#/components/schemas/LogoutRequest" } } }, @@ -531,109 +697,143 @@ }, "responses": { "200": { - "description": "OK" - } - }, - "tags": [ - "Community" - ] - } - }, - "/api/community/topics/{id}/posts": { - "get": { - "operationId": "ListPublicPostsInTopic", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } } }, - { - "in": "query", - "name": "page", - "schema": { - "format": "int32", - "type": "integer" + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } } }, - { - "in": "query", - "name": "pageSize", - "schema": { - "format": "int32", - "type": "integer" + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } } } - ], - "responses": { - "200": { - "description": "OK" - } - }, - "tags": [ - "Community" - ] + } } }, - "/api/community/topics/{slug}": { + "/api/categories": { "get": { - "operationId": "GetPublicTopicBySlug", - "parameters": [ - { - "in": "path", - "name": "slug", - "required": true, - "schema": { - "type": "string" - } - } + "tags": [ + "CategoriesPublic" ], + "operationId": "ListPublicCategories", "responses": { "200": { "description": "OK" } - }, - "tags": [ - "Community" - ] + } } }, - "/api/countries": { + "/": { "get": { - "operationId": "ListPublicCountries", - "parameters": [ - { - "in": "query", - "name": "search", - "schema": { - "type": "string" + "tags": [ + "CCE.Api.External" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } } } + } + } + }, + "/auth/echo": { + "get": { + "tags": [ + "CCE.Api.External" ], "responses": { "200": { "description": "OK" } - }, - "tags": [ - "CountriesPublic" - ] + } } }, - "/api/countries/{id}/profile": { + "/auth/login": { "get": { - "operationId": "GetPublicCountryProfile", + "tags": [ + "CCE.Api.External" + ], + "operationId": "AuthLoginShim", "parameters": [ { - "in": "path", - "name": "id", - "required": true, + "name": "returnUrl", + "in": "query", "schema": { - "format": "uuid", "type": "string" } } @@ -642,69 +842,254 @@ "200": { "description": "OK" } - }, + } + } + }, + "/auth/logout": { + "post": { "tags": [ - "CountriesPublic" - ] + "CCE.Api.External" + ], + "operationId": "AuthLogoutShim", + "responses": { + "200": { + "description": "OK" + } + } } }, - "/api/events": { + "/health": { "get": { - "operationId": "ListPublicEvents", + "tags": [ + "CCE.Api.External" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/community/communities": { + "get": { + "tags": [ + "Community" + ], + "operationId": "ListPublicCommunities", "parameters": [ { - "in": "query", "name": "page", + "in": "query", "schema": { - "format": "int32", - "type": "integer" + "type": "integer", + "format": "int32" } }, { - "in": "query", "name": "pageSize", + "in": "query", "schema": { - "format": "int32", - "type": "integer" + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommunityDtoPagedResultResponse" + } + } } }, - { - "in": "query", - "name": "from", - "schema": { - "format": "date-time", - "type": "string" + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommunityDtoPagedResultResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommunityDtoPagedResultResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommunityDtoPagedResultResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommunityDtoPagedResultResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommunityDtoPagedResultResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommunityDtoPagedResultResponse" + } + } } }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommunityDtoPagedResultResponse" + } + } + } + } + } + } + }, + "/api/community/communities/{slug}": { + "get": { + "tags": [ + "Community" + ], + "operationId": "GetCommunityBySlug", + "parameters": [ { - "in": "query", - "name": "to", + "name": "slug", + "in": "path", + "required": true, "schema": { - "format": "date-time", "type": "string" } } ], "responses": { "200": { - "description": "OK" + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommunityDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommunityDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommunityDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommunityDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommunityDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommunityDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommunityDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommunityDtoResponse" + } + } + } } - }, - "tags": [ - "Events" - ] + } } }, - "/api/events/{id}": { + "/api/community/topics/{slug}": { "get": { - "operationId": "GetPublicEventById", + "tags": [ + "Community" + ], + "operationId": "GetPublicTopicBySlug", "parameters": [ { + "name": "slug", "in": "path", - "name": "id", "required": true, "schema": { - "format": "uuid", "type": "string" } } @@ -713,23 +1098,39 @@ "200": { "description": "OK" } - }, - "tags": [ - "Events" - ] + } } }, - "/api/events/{id}.ics": { + "/api/community/topics/{id}/posts": { "get": { - "operationId": "GetPublicEventIcs", + "tags": [ + "Community" + ], + "operationId": "ListPublicPostsInTopic", "parameters": [ { - "in": "path", "name": "id", + "in": "path", "required": true, "schema": { - "format": "uuid", - "type": "string" + "type": "string", + "format": "uuid" + } + }, + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "pageSize", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" } } ], @@ -737,920 +1138,9109 @@ "200": { "description": "OK" } - }, - "tags": [ - "Events" - ] + } } }, - "/api/homepage-sections": { + "/api/community/posts/{id}": { "get": { - "operationId": "ListPublicHomepageSections", + "tags": [ + "Community" + ], + "operationId": "GetPublicPostById", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], "responses": { "200": { "description": "OK" } - }, - "tags": [ - "HomepagePublic" - ] + } } }, - "/api/interactive-city/scenarios/run": { - "post": { - "operationId": "RunScenario", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RunScenarioRequest" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK" - } - }, - "tags": [ - "InteractiveCity" - ] - } - }, - "/api/interactive-city/technologies": { + "/api/community/polls/{id}/results": { "get": { - "operationId": "ListCityTechnologies", - "responses": { - "200": { - "description": "OK" - } - }, "tags": [ - "InteractiveCity" - ] - } - }, - "/api/kapsarc/snapshots/{countryId}": { - "get": { - "operationId": "GetLatestKapsarcSnapshot", + "Community" + ], + "operationId": "GetPollResults", "parameters": [ { + "name": "id", "in": "path", - "name": "countryId", "required": true, "schema": { - "format": "uuid", - "type": "string" + "type": "string", + "format": "uuid" } } ], "responses": { "200": { - "description": "OK" + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PollResultsDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PollResultsDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PollResultsDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PollResultsDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PollResultsDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PollResultsDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PollResultsDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PollResultsDtoResponse" + } + } + } } - }, - "tags": [ - "Kapsarc" - ] + } } }, - "/api/knowledge-maps": { + "/api/community/users/{id}": { "get": { - "operationId": "ListKnowledgeMaps", - "responses": { - "200": { - "description": "OK" - } - }, "tags": [ - "KnowledgeMap" - ] - } - }, - "/api/knowledge-maps/{id}": { - "get": { - "operationId": "GetKnowledgeMapById", + "Community" + ], + "operationId": "GetCommunityUserProfile", "parameters": [ { - "in": "path", "name": "id", + "in": "path", "required": true, "schema": { - "format": "uuid", - "type": "string" + "type": "string", + "format": "uuid" } } ], "responses": { "200": { - "description": "OK" + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommunityUserProfileDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommunityUserProfileDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommunityUserProfileDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommunityUserProfileDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommunityUserProfileDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommunityUserProfileDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommunityUserProfileDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommunityUserProfileDtoResponse" + } + } + } } - }, - "tags": [ - "KnowledgeMap" - ] + } } }, - "/api/knowledge-maps/{id}/edges": { + "/api/community/posts/{id}/share": { "get": { - "operationId": "ListKnowledgeMapEdges", + "tags": [ + "Community" + ], + "operationId": "GetPostShareLink", "parameters": [ { - "in": "path", "name": "id", + "in": "path", "required": true, "schema": { - "format": "uuid", - "type": "string" + "type": "string", + "format": "uuid" } } ], "responses": { "200": { - "description": "OK" + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PostShareLinkDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PostShareLinkDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PostShareLinkDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PostShareLinkDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PostShareLinkDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PostShareLinkDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PostShareLinkDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PostShareLinkDtoResponse" + } + } + } } - }, - "tags": [ - "KnowledgeMap" - ] + } } }, - "/api/knowledge-maps/{id}/nodes": { + "/api/community/replies/{id}/thread": { "get": { - "operationId": "ListKnowledgeMapNodes", + "tags": [ + "Community" + ], + "operationId": "GetReplyThread", "parameters": [ { - "in": "path", "name": "id", + "in": "path", "required": true, "schema": { - "format": "uuid", - "type": "string" + "type": "string", + "format": "uuid" + } + }, + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "pageSize", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" } } ], "responses": { "200": { - "description": "OK" - } - }, - "tags": [ - "KnowledgeMap" - ] - } - }, - "/api/me": { - "get": { - "operationId": "GetMyProfile", - "responses": { - "200": { - "description": "OK" + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicPostReplyDtoPagedResultResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicPostReplyDtoPagedResultResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicPostReplyDtoPagedResultResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicPostReplyDtoPagedResultResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicPostReplyDtoPagedResultResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicPostReplyDtoPagedResultResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicPostReplyDtoPagedResultResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicPostReplyDtoPagedResultResponse" + } + } + } + } + } + } + }, + "/api/community/posts/{id}/replies": { + "get": { + "tags": [ + "Community" + ], + "operationId": "ListPublicPostReplies", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "pageSize", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "post": { + "tags": [ + "Community" + ], + "operationId": "CreateReply", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateReplyRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + } + } + } + }, + "/api/me/follows": { + "get": { + "tags": [ + "Community" + ], + "operationId": "GetMyFollows", + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/me/posts/drafts": { + "get": { + "tags": [ + "Community" + ], + "operationId": "ListMyDrafts", + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "pageSize", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MyDraftDtoPagedResultResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MyDraftDtoPagedResultResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MyDraftDtoPagedResultResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MyDraftDtoPagedResultResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MyDraftDtoPagedResultResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MyDraftDtoPagedResultResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MyDraftDtoPagedResultResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MyDraftDtoPagedResultResponse" + } + } + } + } + } + } + }, + "/api/me/mentions": { + "get": { + "tags": [ + "Community" + ], + "operationId": "ListMyMentions", + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "pageSize", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MyMentionDtoPagedResultResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MyMentionDtoPagedResultResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MyMentionDtoPagedResultResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MyMentionDtoPagedResultResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MyMentionDtoPagedResultResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MyMentionDtoPagedResultResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MyMentionDtoPagedResultResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MyMentionDtoPagedResultResponse" + } + } + } + } + } + } + }, + "/api/community/posts": { + "post": { + "tags": [ + "Community" + ], + "operationId": "CreatePost", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreatePostRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + } + } + } + }, + "/api/community/posts/{id}/draft": { + "put": { + "tags": [ + "Community" + ], + "operationId": "UpdateDraft", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateDraftRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Community" + ], + "operationId": "DeleteDraft", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + } + } + } + }, + "/api/community/posts/{id}/publish": { + "post": { + "tags": [ + "Community" + ], + "operationId": "PublishPost", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + } + } + } + }, + "/api/community/posts/{id}/vote": { + "post": { + "tags": [ + "Community" + ], + "operationId": "VotePost", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VotePostRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + } + } + } + }, + "/api/community/replies/{id}/vote": { + "post": { + "tags": [ + "Community" + ], + "operationId": "VoteReply", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoteReplyRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + } + } + } + }, + "/api/community/posts/{id}/mark-answer": { + "post": { + "tags": [ + "Community" + ], + "operationId": "MarkPostAnswered", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MarkAnswerRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/community/replies/{id}": { + "put": { + "tags": [ + "Community" + ], + "operationId": "EditReply", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EditReplyRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/community/polls/{id}/vote": { + "post": { + "tags": [ + "Community" + ], + "operationId": "CastPollVote", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CastPollVoteRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + } + } + } + }, + "/api/community/communities/{id}/join": { + "post": { + "tags": [ + "Community" + ], + "operationId": "JoinCommunity", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + } + } + } + }, + "/api/community/communities/{id}/leave": { + "post": { + "tags": [ + "Community" + ], + "operationId": "LeaveCommunity", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + } + } + } + }, + "/api/community/communities/{id}/follow": { + "post": { + "tags": [ + "Community" + ], + "operationId": "FollowCommunity", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Community" + ], + "operationId": "UnfollowCommunity", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + } + } + } + }, + "/api/me/follows/topics/{topicId}": { + "post": { + "tags": [ + "Community" + ], + "operationId": "FollowTopic", + "parameters": [ + { + "name": "topicId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "delete": { + "tags": [ + "Community" + ], + "operationId": "UnfollowTopic", + "parameters": [ + { + "name": "topicId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/me/follows/users/{userId}": { + "post": { + "tags": [ + "Community" + ], + "operationId": "FollowUser", + "parameters": [ + { + "name": "userId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "delete": { + "tags": [ + "Community" + ], + "operationId": "UnfollowUser", + "parameters": [ + { + "name": "userId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/me/follows/posts/{postId}": { + "post": { + "tags": [ + "Community" + ], + "operationId": "FollowPost", + "parameters": [ + { + "name": "postId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "delete": { + "tags": [ + "Community" + ], + "operationId": "UnfollowPost", + "parameters": [ + { + "name": "postId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/countries": { + "get": { + "tags": [ + "CountriesPublic" + ], + "operationId": "ListPublicCountries", + "parameters": [ + { + "name": "search", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "pageSize", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "sortBy", + "in": "query", + "schema": { + "$ref": "#/components/schemas/PublicCountrySortBy" + } + }, + { + "name": "sortOrder", + "in": "query", + "schema": { + "$ref": "#/components/schemas/SortOrder" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicCountryDtoPagedResultResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicCountryDtoPagedResultResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicCountryDtoPagedResultResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicCountryDtoPagedResultResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicCountryDtoPagedResultResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicCountryDtoPagedResultResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicCountryDtoPagedResultResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicCountryDtoPagedResultResponse" + } + } + } + } + } + } + }, + "/api/countries/{id}/profile": { + "get": { + "tags": [ + "CountriesPublic" + ], + "operationId": "GetPublicCountryProfile", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicCountryProfileDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicCountryProfileDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicCountryProfileDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicCountryProfileDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicCountryProfileDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicCountryProfileDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicCountryProfileDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicCountryProfileDtoResponse" + } + } + } + } + } + } + }, + "/api/countries/{id}/ndc": { + "get": { + "tags": [ + "CountriesPublic" + ], + "operationId": "DownloadCountryNdc", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/country-codes": { + "get": { + "tags": [ + "CountryCodes" + ], + "operationId": "ListPublicCountryCodes", + "parameters": [ + { + "name": "search", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "isActive", + "in": "query", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/country-codes/{id}": { + "get": { + "tags": [ + "CountryCodes" + ], + "operationId": "GetPublicCountryCodeById", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/dev/sign-in": { + "get": { + "tags": [ + "DevAuth" + ], + "operationId": "DevSignIn", + "parameters": [ + { + "name": "role", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "returnUrl", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/dev/sign-out": { + "post": { + "tags": [ + "DevAuth" + ], + "operationId": "DevSignOut", + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/dev/whoami": { + "get": { + "tags": [ + "DevAuth" + ], + "operationId": "DevWhoAmI", + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/evaluations": { + "post": { + "tags": [ + "Evaluations" + ], + "operationId": "SubmitEvaluation", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubmitEvaluationRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + } + } + } + }, + "/api/events": { + "get": { + "tags": [ + "Events" + ], + "operationId": "ListPublicEvents", + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "pageSize", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "from", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "to", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "topicId", + "in": "query", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "tagIds", + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicEventDtoPagedResultResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicEventDtoPagedResultResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicEventDtoPagedResultResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicEventDtoPagedResultResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicEventDtoPagedResultResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicEventDtoPagedResultResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicEventDtoPagedResultResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicEventDtoPagedResultResponse" + } + } + } + } + } + } + }, + "/api/events/{id}": { + "get": { + "tags": [ + "Events" + ], + "operationId": "GetPublicEventById", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicEventDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicEventDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicEventDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicEventDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicEventDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicEventDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicEventDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicEventDtoResponse" + } + } + } + } + } + } + }, + "/api/events/{id}.ics": { + "get": { + "tags": [ + "Events" + ], + "operationId": "GetPublicEventIcs", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/feed/news-events": { + "get": { + "tags": [ + "Feed" + ], + "operationId": "ListHomepageFeed", + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "pageSize", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "type", + "in": "query", + "schema": { + "$ref": "#/components/schemas/HomepageFeedContentType" + } + }, + { + "name": "topicId", + "in": "query", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "sortBy", + "in": "query", + "schema": { + "$ref": "#/components/schemas/HomepageFeedSortBy" + } + }, + { + "name": "sortOrder", + "in": "query", + "schema": { + "$ref": "#/components/schemas/SortOrder" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HomepageFeedItemDtoPagedResultResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HomepageFeedItemDtoPagedResultResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HomepageFeedItemDtoPagedResultResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HomepageFeedItemDtoPagedResultResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HomepageFeedItemDtoPagedResultResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HomepageFeedItemDtoPagedResultResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HomepageFeedItemDtoPagedResultResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HomepageFeedItemDtoPagedResultResponse" + } + } + } + } + } + } + }, + "/api/feed/featured-posts": { + "get": { + "tags": [ + "Feed" + ], + "operationId": "ListFeaturedPosts", + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "pageSize", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "topicId", + "in": "query", + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FeaturedPostDtoPagedResultResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FeaturedPostDtoPagedResultResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FeaturedPostDtoPagedResultResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FeaturedPostDtoPagedResultResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FeaturedPostDtoPagedResultResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FeaturedPostDtoPagedResultResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FeaturedPostDtoPagedResultResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FeaturedPostDtoPagedResultResponse" + } + } + } + } + } + } + }, + "/api/homepage": { + "get": { + "tags": [ + "Homepage" + ], + "operationId": "GetPublicHomepage", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicHomepageDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicHomepageDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicHomepageDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicHomepageDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicHomepageDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicHomepageDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicHomepageDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicHomepageDtoResponse" + } + } + } + } + } + } + }, + "/api/homepage-sections": { + "get": { + "tags": [ + "HomepagePublic" + ], + "operationId": "ListPublicHomepageSections", + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/interactive-city/technologies": { + "get": { + "tags": [ + "InteractiveCity" + ], + "operationId": "ListCityTechnologies", + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/interactive-city/scenarios/run": { + "post": { + "tags": [ + "InteractiveCity" + ], + "operationId": "RunScenario", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RunScenarioRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/me/interactive-city/scenarios": { + "post": { + "tags": [ + "InteractiveCity" + ], + "operationId": "SaveMyScenario", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SaveScenarioRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + } + } + }, + "get": { + "tags": [ + "InteractiveCity" + ], + "operationId": "ListMyScenarios", + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/me/interactive-city/scenarios/{id}": { + "delete": { + "tags": [ + "InteractiveCity" + ], + "operationId": "DeleteMyScenario", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/kapsarc/snapshots/{countryId}": { + "get": { + "tags": [ + "Kapsarc" + ], + "operationId": "GetLatestKapsarcSnapshot", + "parameters": [ + { + "name": "countryId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/knowledge-maps": { + "get": { + "tags": [ + "KnowledgeMap" + ], + "operationId": "ListKnowledgeMaps", + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/knowledge-maps/{id}": { + "get": { + "tags": [ + "KnowledgeMap" + ], + "operationId": "GetKnowledgeMapById", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/knowledge-maps/{id}/nodes": { + "get": { + "tags": [ + "KnowledgeMap" + ], + "operationId": "ListKnowledgeMapNodes", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/knowledge-maps/{id}/edges": { + "get": { + "tags": [ + "KnowledgeMap" + ], + "operationId": "ListKnowledgeMapEdges", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/media": { + "post": { + "tags": [ + "Media" + ], + "operationId": "UploadMediaExternal", + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "required": [ + "file" + ], + "type": "object", + "properties": { + "file": { + "type": "string", + "format": "binary" + }, + "titleAr": { + "type": "string" + }, + "titleEn": { + "type": "string" + }, + "descriptionAr": { + "type": "string" + }, + "descriptionEn": { + "type": "string" + }, + "altTextAr": { + "type": "string" + }, + "altTextEn": { + "type": "string" + } + } + }, + "encoding": { + "file": { + "style": "form" + }, + "titleAr": { + "style": "form" + }, + "titleEn": { + "style": "form" + }, + "descriptionAr": { + "style": "form" + }, + "descriptionEn": { + "style": "form" + }, + "altTextAr": { + "style": "form" + }, + "altTextEn": { + "style": "form" + } + } + } + } + }, + "responses": { + "201": { + "description": "Created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + } + } + } + }, + "/api/media/{id}": { + "get": { + "tags": [ + "Media" + ], + "operationId": "GetMediaExternal", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileDtoResponse" + } + } + } + } + } + }, + "put": { + "tags": [ + "Media" + ], + "operationId": "UpdateMediaMetadataExternal", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateMediaMetadataCommand" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Media" + ], + "operationId": "DeleteMediaExternal", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + } + } + } + }, + "/api/media/{id}/download": { + "get": { + "tags": [ + "Media" + ], + "operationId": "DownloadMediaExternal", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/news": { + "get": { + "tags": [ + "News" + ], + "operationId": "ListPublicNews", + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "pageSize", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "isFeatured", + "in": "query", + "schema": { + "type": "boolean" + } + }, + { + "name": "topicId", + "in": "query", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "tagIds", + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicNewsDtoPagedResultResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicNewsDtoPagedResultResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicNewsDtoPagedResultResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicNewsDtoPagedResultResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicNewsDtoPagedResultResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicNewsDtoPagedResultResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicNewsDtoPagedResultResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicNewsDtoPagedResultResponse" + } + } + } + } + } + } + }, + "/api/news/{id}": { + "get": { + "tags": [ + "News" + ], + "operationId": "GetPublicNewsById", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicNewsDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicNewsDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicNewsDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicNewsDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicNewsDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicNewsDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicNewsDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicNewsDtoResponse" + } + } + } + } + } + } + }, + "/api/me/notifications": { + "get": { + "tags": [ + "Notifications" + ], + "operationId": "ListMyNotifications", + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "pageSize", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "status", + "in": "query", + "schema": { + "$ref": "#/components/schemas/NotificationStatus" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/me/notifications/unread-count": { + "get": { + "tags": [ + "Notifications" + ], + "operationId": "GetMyUnreadNotificationCount", + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/me/notifications/{id}/mark-read": { + "post": { + "tags": [ + "Notifications" + ], + "operationId": "MarkNotificationRead", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/me/notifications/mark-all-read": { + "post": { + "tags": [ + "Notifications" + ], + "operationId": "MarkAllNotificationsRead", + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/me/notifications/settings": { + "get": { + "tags": [ + "Notifications" + ], + "operationId": "GetMyNotificationSettings", + "responses": { + "200": { + "description": "OK" + } + } + }, + "put": { + "tags": [ + "Notifications" + ], + "operationId": "UpdateMyNotificationSettings", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateMyNotificationSettingsRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/pages/{slug}": { + "get": { + "tags": [ + "PagesPublic" + ], + "operationId": "GetPublicPageBySlug", + "parameters": [ + { + "name": "slug", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/policies": { + "get": { + "tags": [ + "Policies" + ], + "operationId": "GetPublicPoliciesSettings", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicPoliciesSettingsDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicPoliciesSettingsDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicPoliciesSettingsDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicPoliciesSettingsDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicPoliciesSettingsDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicPoliciesSettingsDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicPoliciesSettingsDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicPoliciesSettingsDtoResponse" + } + } + } + } + } + } + }, + "/api/users/register": { + "post": { + "tags": [ + "Profile" + ], + "operationId": "RegisterUser", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RegisterUserRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthUserDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthUserDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthUserDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthUserDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthUserDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthUserDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthUserDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthUserDtoResponse" + } + } + } + } + } + } + }, + "/api/users/expert-request": { + "post": { + "tags": [ + "Profile" + ], + "operationId": "SubmitExpertRequest", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubmitExpertRequestRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/me": { + "get": { + "tags": [ + "Profile" + ], + "operationId": "GetMyProfile", + "responses": { + "200": { + "description": "OK" + } + } + }, + "put": { + "tags": [ + "Profile" + ], + "operationId": "UpdateMyProfile", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateMyProfileRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/me/expert-status": { + "get": { + "tags": [ + "Profile" + ], + "operationId": "GetMyExpertStatus", + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/me/email/request-change": { + "post": { + "tags": [ + "Profile" + ], + "operationId": "RequestEmailChange", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RequestEmailChangeRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/me/email/confirm-change": { + "post": { + "tags": [ + "Profile" + ], + "operationId": "ConfirmEmailChange", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConfirmEmailChangeRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/me/phone/request-change": { + "post": { + "tags": [ + "Profile" + ], + "operationId": "RequestPhoneChange", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RequestPhoneChangeRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/me/phone/confirm-change": { + "post": { + "tags": [ + "Profile" + ], + "operationId": "ConfirmPhoneChange", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConfirmPhoneChangeRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/resources": { + "get": { + "tags": [ + "Resources" + ], + "operationId": "ListPublicResources", + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "pageSize", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "search", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "categoryId", + "in": "query", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "countryId", + "in": "query", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "resourceType", + "in": "query", + "schema": { + "$ref": "#/components/schemas/ResourceType" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicResourceDtoPagedResultResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicResourceDtoPagedResultResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicResourceDtoPagedResultResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicResourceDtoPagedResultResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicResourceDtoPagedResultResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicResourceDtoPagedResultResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicResourceDtoPagedResultResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicResourceDtoPagedResultResponse" + } + } + } + } + } + } + }, + "/api/resources/{id}": { + "get": { + "tags": [ + "Resources" + ], + "operationId": "GetPublicResourceById", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicResourceDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicResourceDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicResourceDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicResourceDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicResourceDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicResourceDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicResourceDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicResourceDtoResponse" + } + } + } + } + } + } + }, + "/api/resources/{id}/download": { + "get": { + "tags": [ + "Resources" + ], + "operationId": "DownloadPublicResource", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/search": { + "get": { + "tags": [ + "Search" + ], + "operationId": "Search", + "parameters": [ + { + "name": "q", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "type", + "in": "query", + "schema": { + "$ref": "#/components/schemas/SearchableType" + } + }, + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "pageSize", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/share/{type}/{id}": { + "get": { + "tags": [ + "Share" + ], + "operationId": "GetShareLink", + "parameters": [ + { + "name": "type", + "in": "path", + "required": true, + "schema": { + "$ref": "#/components/schemas/ShareContentType" + } + }, + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ShareLinkDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ShareLinkDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ShareLinkDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ShareLinkDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ShareLinkDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ShareLinkDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ShareLinkDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ShareLinkDtoResponse" + } + } + } + } + } + } + }, + "/api/surveys/service-rating": { + "post": { + "tags": [ + "Surveys" + ], + "operationId": "SubmitServiceRating", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceRatingRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/tags": { + "get": { + "tags": [ + "Tags" + ], + "operationId": "ListPublicTags", + "parameters": [ + { + "name": "search", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDtoListResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDtoListResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDtoListResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDtoListResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDtoListResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDtoListResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDtoListResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDtoListResponse" + } + } + } + } + } + } + }, + "/api/topics": { + "get": { + "tags": [ + "TopicsPublic" + ], + "operationId": "ListPublicTopics", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicTopicDtoIReadOnlyListResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicTopicDtoIReadOnlyListResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicTopicDtoIReadOnlyListResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicTopicDtoIReadOnlyListResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicTopicDtoIReadOnlyListResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicTopicDtoIReadOnlyListResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicTopicDtoIReadOnlyListResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicTopicDtoIReadOnlyListResponse" + } + } + } + } + } + } + }, + "/verification/request": { + "post": { + "tags": [ + "Verification" + ], + "operationId": "RequestVerification", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RequestVerificationRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RequestVerificationResponseDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RequestVerificationResponseDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RequestVerificationResponseDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RequestVerificationResponseDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RequestVerificationResponseDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RequestVerificationResponseDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RequestVerificationResponseDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RequestVerificationResponseDtoResponse" + } + } + } + } + } + } + }, + "/verification/verify": { + "post": { + "tags": [ + "Verification" + ], + "operationId": "VerifyOtp", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VerifyOtpRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VerifyOtpResponseDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VerifyOtpResponseDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VerifyOtpResponseDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VerifyOtpResponseDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VerifyOtpResponseDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VerifyOtpResponseDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VerifyOtpResponseDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VerifyOtpResponseDtoResponse" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "AskAssistantRequest": { + "type": "object", + "properties": { + "messages": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ChatMessageDto" + }, + "nullable": true + }, + "locale": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "AttachmentKind": { + "enum": [ + 0, + 1 + ], + "type": "integer", + "format": "int32" + }, + "AuthMessageDto": { + "type": "object", + "properties": { + "code": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "AuthMessageDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/AuthMessageDto" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" + } + }, + "additionalProperties": false + }, + "AuthTokenDto": { + "type": "object", + "properties": { + "accessToken": { + "type": "string", + "nullable": true + }, + "accessTokenExpiresAtUtc": { + "type": "string", + "format": "date-time" + }, + "refreshToken": { + "type": "string", + "nullable": true + }, + "refreshTokenExpiresAtUtc": { + "type": "string", + "format": "date-time" + }, + "tokenType": { + "type": "string", + "nullable": true + }, + "user": { + "$ref": "#/components/schemas/AuthUserDto" + } + }, + "additionalProperties": false + }, + "AuthTokenDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/AuthTokenDto" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" + } + }, + "additionalProperties": false + }, + "AuthUserDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "emailAddress": { + "type": "string", + "nullable": true + }, + "firstName": { + "type": "string", + "nullable": true + }, + "lastName": { + "type": "string", + "nullable": true + }, + "roles": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "AuthUserDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/AuthUserDto" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" + } + }, + "additionalProperties": false + }, + "CastPollVoteRequest": { + "type": "object", + "properties": { + "optionIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "ChatMessageDto": { + "type": "object", + "properties": { + "role": { + "type": "string", + "nullable": true + }, + "content": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "CityType": { + "enum": [ + 0, + 1, + 2, + 3 + ], + "type": "integer", + "format": "int32" + }, + "CommunityDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "nameAr": { + "type": "string", + "nullable": true + }, + "nameEn": { + "type": "string", + "nullable": true + }, + "descriptionAr": { + "type": "string", + "nullable": true + }, + "descriptionEn": { + "type": "string", + "nullable": true + }, + "slug": { + "type": "string", + "nullable": true + }, + "visibility": { + "$ref": "#/components/schemas/CommunityVisibility" + }, + "memberCount": { + "type": "integer", + "format": "int32" + }, + "presentationJson": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "CommunityDtoPagedResult": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CommunityDto" + }, + "nullable": true + }, + "page": { + "type": "integer", + "format": "int32" + }, + "pageSize": { + "type": "integer", + "format": "int32" + }, + "total": { + "type": "integer", + "format": "int64" + } + }, + "additionalProperties": false + }, + "CommunityDtoPagedResultResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/CommunityDtoPagedResult" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" + } + }, + "additionalProperties": false + }, + "CommunityDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/CommunityDto" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" + } + }, + "additionalProperties": false + }, + "CommunityUserProfileDto": { + "type": "object", + "properties": { + "userId": { + "type": "string", + "format": "uuid" + }, + "firstName": { + "type": "string", + "nullable": true + }, + "lastName": { + "type": "string", + "nullable": true + }, + "jobTitle": { + "type": "string", + "nullable": true + }, + "organizationName": { + "type": "string", + "nullable": true + }, + "avatarUrl": { + "type": "string", + "nullable": true + }, + "isExpert": { + "type": "boolean" + }, + "postCount": { + "type": "integer", + "format": "int32" + }, + "replyCount": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "CommunityUserProfileDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/CommunityUserProfileDto" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" + } + }, + "additionalProperties": false + }, + "CommunityVisibility": { + "enum": [ + 0, + 1 + ], + "type": "integer", + "format": "int32" + }, + "ConfirmEmailChangeRequest": { + "type": "object", + "properties": { + "verificationId": { + "type": "string", + "format": "uuid" + }, + "code": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "ConfirmPhoneChangeRequest": { + "type": "object", + "properties": { + "verificationId": { + "type": "string", + "format": "uuid" + }, + "code": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "CreatePostRequest": { + "type": "object", + "properties": { + "communityId": { + "type": "string", + "format": "uuid" + }, + "topicId": { + "type": "string", + "format": "uuid" + }, + "type": { + "$ref": "#/components/schemas/PostType" + }, + "title": { + "type": "string", + "nullable": true + }, + "content": { + "type": "string", + "nullable": true + }, + "locale": { + "type": "string", + "nullable": true + }, + "tagIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "nullable": true + }, + "attachments": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PostAttachmentInput" + }, + "nullable": true + }, + "poll": { + "$ref": "#/components/schemas/PollInput" + }, + "saveAsDraft": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "CreateReplyRequest": { + "type": "object", + "properties": { + "content": { + "type": "string", + "nullable": true + }, + "locale": { + "type": "string", + "nullable": true + }, + "parentReplyId": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "mentionedUserIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "EditReplyRequest": { + "type": "object", + "properties": { + "content": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "FeaturedPostDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "topicId": { + "type": "string", + "format": "uuid" + }, + "nameAr": { + "type": "string", + "nullable": true + }, + "nameEn": { + "type": "string", + "nullable": true + }, + "content": { + "type": "string", + "nullable": true + }, + "locale": { + "type": "string", + "nullable": true + }, + "authorId": { + "type": "string", + "format": "uuid" + }, + "publishedByName": { + "type": "string", + "nullable": true + }, + "publishedOn": { + "type": "string", + "format": "date-time" + }, + "ratingCount": { + "type": "integer", + "format": "int32" + }, + "averageStars": { + "type": "number", + "format": "double" + }, + "replyCount": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "FeaturedPostDtoPagedResult": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FeaturedPostDto" + }, + "nullable": true + }, + "page": { + "type": "integer", + "format": "int32" + }, + "pageSize": { + "type": "integer", + "format": "int32" + }, + "total": { + "type": "integer", + "format": "int64" + } + }, + "additionalProperties": false + }, + "FeaturedPostDtoPagedResultResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/FeaturedPostDtoPagedResult" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" + } + }, + "additionalProperties": false + }, + "FieldError": { + "type": "object", + "properties": { + "field": { + "type": "string", + "nullable": true + }, + "code": { + "type": "string", + "nullable": true + }, + "message": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "ForgotPasswordRequest": { + "type": "object", + "properties": { + "emailAddress": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "GuidResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "type": "string", + "format": "uuid", + "readOnly": true + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" + } + }, + "additionalProperties": false + }, + "HomepageFeedContentType": { + "enum": [ + 0, + 1 + ], + "type": "integer", + "format": "int32" + }, + "HomepageFeedItemDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "contentTypeId": { + "type": "integer", + "format": "int32" + }, + "contentType": { + "$ref": "#/components/schemas/HomepageFeedContentType" + }, + "nameEn": { + "type": "string", + "nullable": true + }, + "nameAr": { + "type": "string", + "nullable": true + }, + "topicId": { + "type": "string", + "format": "uuid" + }, + "topicNameEn": { + "type": "string", + "nullable": true + }, + "topicNameAr": { + "type": "string", + "nullable": true + }, + "authorId": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "authorName": { + "type": "string", + "nullable": true + }, + "featuredImageUrl": { + "type": "string", + "nullable": true + }, + "locationEn": { + "type": "string", + "nullable": true + }, + "locationAr": { + "type": "string", + "nullable": true + }, + "publishedOn": { + "type": "string", + "format": "date-time" + } + }, + "additionalProperties": false + }, + "HomepageFeedItemDtoPagedResult": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HomepageFeedItemDto" + }, + "nullable": true + }, + "page": { + "type": "integer", + "format": "int32" + }, + "pageSize": { + "type": "integer", + "format": "int32" + }, + "total": { + "type": "integer", + "format": "int64" + } + }, + "additionalProperties": false + }, + "HomepageFeedItemDtoPagedResultResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/HomepageFeedItemDtoPagedResult" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" + } + }, + "additionalProperties": false + }, + "HomepageFeedSortBy": { + "enum": [ + 0 + ], + "type": "integer", + "format": "int32" + }, + "HomepageSectionType": { + "enum": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 99 + ], + "type": "integer", + "format": "int32" + }, + "KnowledgeLevel": { + "enum": [ + 0, + 1, + 2 + ], + "type": "integer", + "format": "int32" + }, + "LocalizedTextDto": { + "type": "object", + "properties": { + "ar": { + "type": "string", + "nullable": true + }, + "en": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "LoginRequest": { + "type": "object", + "properties": { + "emailAddress": { + "type": "string", + "nullable": true + }, + "password": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "LogoutRequest": { + "type": "object", + "properties": { + "refreshToken": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "MarkAnswerRequest": { + "type": "object", + "properties": { + "replyId": { + "type": "string", + "format": "uuid" + } + }, + "additionalProperties": false + }, + "MediaFileBriefDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "storageKey": { + "type": "string", + "nullable": true + }, + "url": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "MediaFileBriefDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/MediaFileBriefDto" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" + } + }, + "additionalProperties": false + }, + "MediaFileDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "storageKey": { + "type": "string", + "nullable": true + }, + "url": { + "type": "string", + "nullable": true + }, + "originalFileName": { + "type": "string", + "nullable": true + }, + "mimeType": { + "type": "string", + "nullable": true + }, + "sizeBytes": { + "type": "integer", + "format": "int64" + }, + "titleAr": { + "type": "string", + "nullable": true + }, + "titleEn": { + "type": "string", + "nullable": true + }, + "descriptionAr": { + "type": "string", + "nullable": true + }, + "descriptionEn": { + "type": "string", + "nullable": true + }, + "altTextAr": { + "type": "string", + "nullable": true + }, + "altTextEn": { + "type": "string", + "nullable": true + }, + "uploadedById": { + "type": "string", + "format": "uuid" + }, + "uploadedOn": { + "type": "string", + "format": "date-time" + } + }, + "additionalProperties": false + }, + "MediaFileDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/MediaFileDto" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" + } + }, + "additionalProperties": false + }, + "MentionSourceType": { + "enum": [ + 0, + 1 + ], + "type": "integer", + "format": "int32" + }, + "MyDraftDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "topicId": { + "type": "string", + "format": "uuid" + }, + "type": { + "$ref": "#/components/schemas/PostType" + }, + "title": { + "type": "string", + "nullable": true + }, + "content": { + "type": "string", + "nullable": true + }, + "locale": { + "type": "string", + "nullable": true + }, + "createdOn": { + "type": "string", + "format": "date-time" + }, + "lastModifiedOn": { + "type": "string", + "format": "date-time", + "nullable": true + } + }, + "additionalProperties": false + }, + "MyDraftDtoPagedResult": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MyDraftDto" + }, + "nullable": true + }, + "page": { + "type": "integer", + "format": "int32" + }, + "pageSize": { + "type": "integer", + "format": "int32" + }, + "total": { + "type": "integer", + "format": "int64" + } + }, + "additionalProperties": false + }, + "MyDraftDtoPagedResultResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/MyDraftDtoPagedResult" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" + } + }, + "additionalProperties": false + }, + "MyMentionDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "sourceType": { + "$ref": "#/components/schemas/MentionSourceType" + }, + "sourceId": { + "type": "string", + "format": "uuid" + }, + "mentionedByUserId": { + "type": "string", + "format": "uuid" + }, + "createdOn": { + "type": "string", + "format": "date-time" + } + }, + "additionalProperties": false + }, + "MyMentionDtoPagedResult": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MyMentionDto" + }, + "nullable": true + }, + "page": { + "type": "integer", + "format": "int32" + }, + "pageSize": { + "type": "integer", + "format": "int32" + }, + "total": { + "type": "integer", + "format": "int64" + } + }, + "additionalProperties": false + }, + "MyMentionDtoPagedResultResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/MyMentionDtoPagedResult" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" + } + }, + "additionalProperties": false + }, + "NdcDocumentDto": { + "type": "object", + "properties": { + "assetId": { + "type": "string", + "format": "uuid" + }, + "originalFileName": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "NotificationChannel": { + "enum": [ + 0, + 1, + 2 + ], + "type": "integer", + "format": "int32" + }, + "NotificationStatus": { + "enum": [ + 0, + 1, + 2, + 3 + ], + "type": "integer", + "format": "int32" + }, + "OtpVerificationType": { + "enum": [ + 0, + 1 + ], + "type": "integer", + "format": "int32" + }, + "PollInput": { + "type": "object", + "properties": { + "deadline": { + "type": "string", + "format": "date-time" + }, + "allowMultiple": { + "type": "boolean" + }, + "isAnonymous": { + "type": "boolean" + }, + "showResultsBeforeClose": { + "type": "boolean" + }, + "optionLabels": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "PollOptionResultDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "label": { + "type": "string", + "nullable": true + }, + "voteCount": { + "type": "integer", + "format": "int32" + }, + "percentage": { + "type": "number", + "format": "double" + } + }, + "additionalProperties": false + }, + "PollResultsDto": { + "type": "object", + "properties": { + "pollId": { + "type": "string", + "format": "uuid" + }, + "deadline": { + "type": "string", + "format": "date-time" + }, + "isClosed": { + "type": "boolean" + }, + "allowMultiple": { + "type": "boolean" + }, + "resultsVisible": { + "type": "boolean" + }, + "totalVotes": { + "type": "integer", + "format": "int32" + }, + "options": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PollOptionResultDto" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "PollResultsDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/PollResultsDto" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" + } + }, + "additionalProperties": false + }, + "PostAttachmentInput": { + "type": "object", + "properties": { + "assetFileId": { + "type": "string", + "format": "uuid" + }, + "kind": { + "$ref": "#/components/schemas/AttachmentKind" + }, + "sortOrder": { + "type": "integer", + "format": "int32" + }, + "metadataJson": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "PostShareLinkDto": { + "type": "object", + "properties": { + "postId": { + "type": "string", + "format": "uuid" + }, + "url": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "PostShareLinkDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/PostShareLinkDto" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" + } + }, + "additionalProperties": false + }, + "PostType": { + "enum": [ + 0, + 1, + 2 + ], + "type": "integer", + "format": "int32" + }, + "PublicAboutSettingsDto": { + "type": "object", + "properties": { + "description": { + "$ref": "#/components/schemas/LocalizedTextDto" + }, + "howToUseVideoUrl": { + "type": "string", + "nullable": true + }, + "glossary": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PublicGlossaryEntryDto" + }, + "nullable": true + }, + "knowledgePartners": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PublicKnowledgePartnerDto" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "PublicAboutSettingsDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/PublicAboutSettingsDto" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" + } + }, + "additionalProperties": false + }, + "PublicCountryDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "isoAlpha3": { + "type": "string", + "nullable": true + }, + "isoAlpha2": { + "type": "string", + "nullable": true + }, + "nameAr": { + "type": "string", + "nullable": true + }, + "nameEn": { + "type": "string", + "nullable": true + }, + "regionAr": { + "type": "string", + "nullable": true + }, + "regionEn": { + "type": "string", + "nullable": true + }, + "flagUrl": { + "type": "string", + "nullable": true + }, + "cceClassification": { + "type": "string", + "nullable": true + }, + "ccePerformanceScore": { + "type": "number", + "format": "double", + "nullable": true + }, + "cceTotalIndex": { + "type": "number", + "format": "double", + "nullable": true + } + }, + "additionalProperties": false + }, + "PublicCountryDtoPagedResult": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PublicCountryDto" + }, + "nullable": true + }, + "page": { + "type": "integer", + "format": "int32" + }, + "pageSize": { + "type": "integer", + "format": "int32" + }, + "total": { + "type": "integer", + "format": "int64" + } + }, + "additionalProperties": false + }, + "PublicCountryDtoPagedResultResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/PublicCountryDtoPagedResult" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" + } + }, + "additionalProperties": false + }, + "PublicCountryProfileDto": { + "type": "object", + "properties": { + "countryId": { + "type": "string", + "format": "uuid" + }, + "isoAlpha3": { + "type": "string", + "nullable": true + }, + "nameAr": { + "type": "string", + "nullable": true + }, + "nameEn": { + "type": "string", + "nullable": true + }, + "flagUrl": { + "type": "string", + "nullable": true + }, + "descriptionAr": { + "type": "string", + "nullable": true + }, + "descriptionEn": { + "type": "string", + "nullable": true + }, + "keyInitiativesAr": { + "type": "string", + "nullable": true + }, + "keyInitiativesEn": { + "type": "string", + "nullable": true + }, + "contactInfoAr": { + "type": "string", + "nullable": true + }, + "contactInfoEn": { + "type": "string", + "nullable": true + }, + "population": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "areaSqKm": { + "type": "number", + "format": "double", + "nullable": true + }, + "gdpPerCapita": { + "type": "number", + "format": "double", + "nullable": true + }, + "ndcDocument": { + "$ref": "#/components/schemas/NdcDocumentDto" + }, + "cceClassification": { + "type": "string", + "nullable": true + }, + "ccePerformanceScore": { + "type": "number", + "format": "double", + "nullable": true + }, + "cceTotalIndex": { + "type": "number", + "format": "double", + "nullable": true + }, + "cceSnapshotTakenOn": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "lastUpdatedOn": { + "type": "string", + "format": "date-time", + "nullable": true + } + }, + "additionalProperties": false + }, + "PublicCountryProfileDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/PublicCountryProfileDto" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" + } + }, + "additionalProperties": false + }, + "PublicCountrySortBy": { + "enum": [ + 0, + 1, + 2 + ], + "type": "integer", + "format": "int32" + }, + "PublicEventDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "titleAr": { + "type": "string", + "nullable": true + }, + "titleEn": { + "type": "string", + "nullable": true + }, + "descriptionAr": { + "type": "string", + "nullable": true + }, + "descriptionEn": { + "type": "string", + "nullable": true + }, + "startsOn": { + "type": "string", + "format": "date-time" + }, + "endsOn": { + "type": "string", + "format": "date-time" + }, + "locationAr": { + "type": "string", + "nullable": true + }, + "locationEn": { + "type": "string", + "nullable": true + }, + "onlineMeetingUrl": { + "type": "string", + "nullable": true + }, + "featuredImageUrl": { + "type": "string", + "nullable": true + }, + "iCalUid": { + "type": "string", + "nullable": true + }, + "topicId": { + "type": "string", + "format": "uuid" + }, + "topicNameAr": { + "type": "string", + "nullable": true + }, + "topicNameEn": { + "type": "string", + "nullable": true + }, + "tags": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TagDto" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "PublicEventDtoPagedResult": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PublicEventDto" + }, + "nullable": true + }, + "page": { + "type": "integer", + "format": "int32" + }, + "pageSize": { + "type": "integer", + "format": "int32" + }, + "total": { + "type": "integer", + "format": "int64" + } + }, + "additionalProperties": false + }, + "PublicEventDtoPagedResultResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/PublicEventDtoPagedResult" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" + } + }, + "additionalProperties": false + }, + "PublicEventDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/PublicEventDto" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" + } + }, + "additionalProperties": false + }, + "PublicGlossaryEntryDto": { + "type": "object", + "properties": { + "term": { + "$ref": "#/components/schemas/LocalizedTextDto" + }, + "definition": { + "$ref": "#/components/schemas/LocalizedTextDto" + } + }, + "additionalProperties": false + }, + "PublicHomepageCountryDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "isoAlpha3": { + "type": "string", + "nullable": true + }, + "nameAr": { + "type": "string", + "nullable": true + }, + "nameEn": { + "type": "string", + "nullable": true + }, + "flagUrl": { + "type": "string", + "nullable": true + }, + "orderIndex": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "PublicHomepageDto": { + "type": "object", + "properties": { + "videoUrl": { + "type": "string", + "nullable": true + }, + "objective": { + "$ref": "#/components/schemas/LocalizedTextDto" + }, + "cceConceptsAr": { + "type": "string", + "nullable": true + }, + "cceConceptsEn": { + "type": "string", + "nullable": true + }, + "participatingCountries": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PublicHomepageCountryDto" + }, + "nullable": true + }, + "sections": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PublicHomepageSectionDto" + }, + "nullable": true } }, - "tags": [ - "Profile" - ] + "additionalProperties": false }, - "put": { - "operationId": "UpdateMyProfile", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateMyProfileRequest" - } - } + "PublicHomepageDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true }, - "required": true - }, - "responses": { - "200": { - "description": "OK" + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/PublicHomepageDto" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } }, - "tags": [ - "Profile" - ] - } - }, - "/api/me/expert-status": { - "get": { - "operationId": "GetMyExpertStatus", - "responses": { - "200": { - "description": "OK" + "additionalProperties": false + }, + "PublicHomepageSectionDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "sectionType": { + "$ref": "#/components/schemas/HomepageSectionType" + }, + "orderIndex": { + "type": "integer", + "format": "int32" + }, + "contentAr": { + "type": "string", + "nullable": true + }, + "contentEn": { + "type": "string", + "nullable": true } }, - "tags": [ - "Profile" - ] - } - }, - "/api/me/follows": { - "get": { - "operationId": "GetMyFollows", - "responses": { - "200": { - "description": "OK" + "additionalProperties": false + }, + "PublicKnowledgePartnerDto": { + "type": "object", + "properties": { + "name": { + "$ref": "#/components/schemas/LocalizedTextDto" + }, + "logoUrl": { + "type": "string", + "nullable": true + }, + "websiteUrl": { + "type": "string", + "nullable": true + }, + "description": { + "$ref": "#/components/schemas/LocalizedTextDto" } }, - "tags": [ - "Community" - ] - } - }, - "/api/me/follows/posts/{postId}": { - "delete": { - "operationId": "UnfollowPost", - "parameters": [ - { - "in": "path", - "name": "postId", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK" + "additionalProperties": false + }, + "PublicNewsDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "titleAr": { + "type": "string", + "nullable": true + }, + "titleEn": { + "type": "string", + "nullable": true + }, + "contentAr": { + "type": "string", + "nullable": true + }, + "contentEn": { + "type": "string", + "nullable": true + }, + "topicId": { + "type": "string", + "format": "uuid" + }, + "topicNameAr": { + "type": "string", + "nullable": true + }, + "topicNameEn": { + "type": "string", + "nullable": true + }, + "featuredImageUrl": { + "type": "string", + "nullable": true + }, + "publishedOn": { + "type": "string", + "format": "date-time" + }, + "isFeatured": { + "type": "boolean" + }, + "tags": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TagDto" + }, + "nullable": true } }, - "tags": [ - "Community" - ] + "additionalProperties": false }, - "post": { - "operationId": "FollowPost", - "parameters": [ - { - "in": "path", - "name": "postId", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK" + "PublicNewsDtoPagedResult": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PublicNewsDto" + }, + "nullable": true + }, + "page": { + "type": "integer", + "format": "int32" + }, + "pageSize": { + "type": "integer", + "format": "int32" + }, + "total": { + "type": "integer", + "format": "int64" } }, - "tags": [ - "Community" - ] - } - }, - "/api/me/follows/topics/{topicId}": { - "delete": { - "operationId": "UnfollowTopic", - "parameters": [ - { - "in": "path", - "name": "topicId", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK" + "additionalProperties": false + }, + "PublicNewsDtoPagedResultResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/PublicNewsDtoPagedResult" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } }, - "tags": [ - "Community" - ] + "additionalProperties": false }, - "post": { - "operationId": "FollowTopic", - "parameters": [ - { - "in": "path", - "name": "topicId", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK" + "PublicNewsDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/PublicNewsDto" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } }, - "tags": [ - "Community" - ] - } - }, - "/api/me/follows/users/{userId}": { - "delete": { - "operationId": "UnfollowUser", - "parameters": [ - { - "in": "path", - "name": "userId", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } + "additionalProperties": false + }, + "PublicPoliciesSettingsDto": { + "type": "object", + "properties": { + "sections": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PublicPolicySectionDto" + }, + "nullable": true } - ], - "responses": { - "200": { - "description": "OK" + }, + "additionalProperties": false + }, + "PublicPoliciesSettingsDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/PublicPoliciesSettingsDto" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } }, - "tags": [ - "Community" - ] + "additionalProperties": false }, - "post": { - "operationId": "FollowUser", - "parameters": [ - { - "in": "path", - "name": "userId", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } + "PublicPolicySectionDto": { + "type": "object", + "properties": { + "type": { + "type": "integer", + "format": "int32" + }, + "title": { + "$ref": "#/components/schemas/LocalizedTextDto" + }, + "content": { + "$ref": "#/components/schemas/LocalizedTextDto" } - ], - "responses": { - "200": { - "description": "OK" + }, + "additionalProperties": false + }, + "PublicPostReplyDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "postId": { + "type": "string", + "format": "uuid" + }, + "authorId": { + "type": "string", + "format": "uuid" + }, + "content": { + "type": "string", + "nullable": true + }, + "locale": { + "type": "string", + "nullable": true + }, + "parentReplyId": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "isByExpert": { + "type": "boolean" + }, + "depth": { + "type": "integer", + "format": "int32" + }, + "childCount": { + "type": "integer", + "format": "int32" + }, + "upvoteCount": { + "type": "integer", + "format": "int32" + }, + "createdOn": { + "type": "string", + "format": "date-time" } }, - "tags": [ - "Community" - ] - } - }, - "/api/me/interactive-city/scenarios": { - "get": { - "operationId": "ListMyScenarios", - "responses": { - "200": { - "description": "OK" + "additionalProperties": false + }, + "PublicPostReplyDtoPagedResult": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PublicPostReplyDto" + }, + "nullable": true + }, + "page": { + "type": "integer", + "format": "int32" + }, + "pageSize": { + "type": "integer", + "format": "int32" + }, + "total": { + "type": "integer", + "format": "int64" } }, - "tags": [ - "InteractiveCity" - ] + "additionalProperties": false }, - "post": { - "operationId": "SaveMyScenario", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SaveScenarioRequest" - } - } + "PublicPostReplyDtoPagedResultResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true }, - "required": true - }, - "responses": { - "200": { - "description": "OK" + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/PublicPostReplyDtoPagedResult" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } }, - "tags": [ - "InteractiveCity" - ] - } - }, - "/api/me/interactive-city/scenarios/{id}": { - "delete": { - "operationId": "DeleteMyScenario", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", + "additionalProperties": false + }, + "PublicResourceDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "titleAr": { + "type": "string", + "nullable": true + }, + "titleEn": { + "type": "string", + "nullable": true + }, + "descriptionAr": { + "type": "string", + "nullable": true + }, + "descriptionEn": { + "type": "string", + "nullable": true + }, + "resourceType": { + "$ref": "#/components/schemas/ResourceType" + }, + "categoryId": { + "type": "string", + "format": "uuid" + }, + "categoryNameAr": { + "type": "string", + "nullable": true + }, + "categoryNameEn": { + "type": "string", + "nullable": true + }, + "assetFileId": { + "type": "string", + "format": "uuid" + }, + "assetFileName": { + "type": "string", + "nullable": true + }, + "countryIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "nullable": true + }, + "countryNames": { + "type": "array", + "items": { "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK" + }, + "nullable": true + }, + "publishedOn": { + "type": "string", + "format": "date-time" + }, + "viewCount": { + "type": "integer", + "format": "int64" } }, - "tags": [ - "InteractiveCity" - ] - } - }, - "/api/me/notifications": { - "get": { - "operationId": "ListMyNotifications", - "parameters": [ - { - "in": "query", - "name": "page", - "schema": { - "format": "int32", - "type": "integer" - } + "additionalProperties": false + }, + "PublicResourceDtoPagedResult": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PublicResourceDto" + }, + "nullable": true }, - { - "in": "query", - "name": "pageSize", - "schema": { - "format": "int32", - "type": "integer" - } + "page": { + "type": "integer", + "format": "int32" }, - { - "in": "query", - "name": "status", - "schema": { - "$ref": "#/components/schemas/NotificationStatus" - } + "pageSize": { + "type": "integer", + "format": "int32" + }, + "total": { + "type": "integer", + "format": "int64" } - ], - "responses": { - "200": { - "description": "OK" + }, + "additionalProperties": false + }, + "PublicResourceDtoPagedResultResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/PublicResourceDtoPagedResult" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } }, - "tags": [ - "Notifications" - ] - } - }, - "/api/me/notifications/mark-all-read": { - "post": { - "operationId": "MarkAllNotificationsRead", - "responses": { - "200": { - "description": "OK" + "additionalProperties": false + }, + "PublicResourceDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/PublicResourceDto" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } }, - "tags": [ - "Notifications" - ] - } - }, - "/api/me/notifications/unread-count": { - "get": { - "operationId": "GetMyUnreadNotificationCount", - "responses": { - "200": { - "description": "OK" + "additionalProperties": false + }, + "PublicTopicDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "nameAr": { + "type": "string", + "nullable": true + }, + "nameEn": { + "type": "string", + "nullable": true + }, + "descriptionAr": { + "type": "string", + "nullable": true + }, + "descriptionEn": { + "type": "string", + "nullable": true + }, + "slug": { + "type": "string", + "nullable": true + }, + "parentId": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "iconUrl": { + "type": "string", + "nullable": true + }, + "orderIndex": { + "type": "integer", + "format": "int32" } }, - "tags": [ - "Notifications" - ] - } - }, - "/api/me/notifications/{id}/mark-read": { - "post": { - "operationId": "MarkNotificationRead", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } + "additionalProperties": false + }, + "PublicTopicDtoIReadOnlyListResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PublicTopicDto" + }, + "nullable": true, + "readOnly": true + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } - ], - "responses": { - "200": { - "description": "OK" + }, + "additionalProperties": false + }, + "RefreshTokenRequest": { + "type": "object", + "properties": { + "refreshToken": { + "type": "string", + "nullable": true } }, - "tags": [ - "Notifications" - ] - } - }, - "/api/news": { - "get": { - "operationId": "ListPublicNews", - "parameters": [ - { - "in": "query", - "name": "page", - "schema": { - "format": "int32", - "type": "integer" - } + "additionalProperties": false + }, + "RegisterUserRequest": { + "type": "object", + "properties": { + "firstName": { + "type": "string", + "nullable": true }, - { - "in": "query", - "name": "pageSize", - "schema": { - "format": "int32", - "type": "integer" - } + "lastName": { + "type": "string", + "nullable": true }, - { - "in": "query", - "name": "isFeatured", - "schema": { - "type": "boolean" - } - } - ], - "responses": { - "200": { - "description": "OK" + "emailAddress": { + "type": "string", + "nullable": true + }, + "jobTitle": { + "type": "string", + "nullable": true + }, + "organizationName": { + "type": "string", + "nullable": true + }, + "phoneNumber": { + "type": "string", + "nullable": true + }, + "password": { + "type": "string", + "nullable": true + }, + "confirmPassword": { + "type": "string", + "nullable": true + }, + "countryCodeId": { + "type": "string", + "format": "uuid", + "nullable": true } }, - "tags": [ - "News" - ] - } - }, - "/api/news/{slug}": { - "get": { - "operationId": "GetPublicNewsBySlug", - "parameters": [ - { - "in": "path", - "name": "slug", - "required": true, - "schema": { - "type": "string" - } + "additionalProperties": false + }, + "RequestEmailChangeRequest": { + "type": "object", + "properties": { + "newEmail": { + "type": "string", + "nullable": true } - ], - "responses": { - "200": { - "description": "OK" + }, + "additionalProperties": false + }, + "RequestPhoneChangeRequest": { + "type": "object", + "properties": { + "newPhone": { + "type": "string", + "nullable": true + }, + "countryCodeId": { + "type": "string", + "format": "uuid", + "nullable": true } }, - "tags": [ - "News" - ] - } - }, - "/api/pages/{slug}": { - "get": { - "operationId": "GetPublicPageBySlug", - "parameters": [ - { - "in": "path", - "name": "slug", - "required": true, - "schema": { - "type": "string" - } + "additionalProperties": false + }, + "RequestVerificationRequest": { + "type": "object", + "properties": { + "token": { + "type": "string", + "nullable": true + }, + "providerName": { + "type": "string", + "nullable": true + }, + "contact": { + "type": "string", + "nullable": true + }, + "typeId": { + "$ref": "#/components/schemas/OtpVerificationType" } - ], - "responses": { - "200": { - "description": "OK" + }, + "additionalProperties": false + }, + "RequestVerificationResponseDto": { + "type": "object", + "properties": { + "verificationId": { + "type": "string", + "format": "uuid" + }, + "expiresAt": { + "type": "string", + "format": "date-time" + }, + "cooldownSeconds": { + "type": "integer", + "format": "int32" } }, - "tags": [ - "PagesPublic" - ] - } - }, - "/api/resources": { - "get": { - "operationId": "ListPublicResources", - "parameters": [ - { - "in": "query", - "name": "page", - "schema": { - "format": "int32", - "type": "integer" - } + "additionalProperties": false + }, + "RequestVerificationResponseDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true }, - { - "in": "query", - "name": "pageSize", - "schema": { - "format": "int32", - "type": "integer" - } + "code": { + "type": "string", + "nullable": true, + "readOnly": true }, - { - "in": "query", - "name": "categoryId", - "schema": { - "format": "uuid", - "type": "string" - } + "message": { + "type": "string", + "nullable": true, + "readOnly": true }, - { - "in": "query", - "name": "countryId", - "schema": { - "format": "uuid", - "type": "string" - } + "data": { + "$ref": "#/components/schemas/RequestVerificationResponseDto" }, - { - "in": "query", - "name": "resourceType", - "schema": { - "$ref": "#/components/schemas/ResourceType" - } + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" + } + }, + "additionalProperties": false + }, + "ResetPasswordRequest": { + "type": "object", + "properties": { + "emailAddress": { + "type": "string", + "nullable": true + }, + "token": { + "type": "string", + "nullable": true + }, + "newPassword": { + "type": "string", + "nullable": true + }, + "confirmPassword": { + "type": "string", + "nullable": true } + }, + "additionalProperties": false + }, + "ResourceType": { + "enum": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 ], - "responses": { - "200": { - "description": "OK" + "type": "integer", + "format": "int32" + }, + "RunScenarioRequest": { + "type": "object", + "properties": { + "cityType": { + "$ref": "#/components/schemas/CityType" + }, + "targetYear": { + "type": "integer", + "format": "int32" + }, + "configurationJson": { + "type": "string", + "nullable": true } }, - "tags": [ - "Resources" - ] - } - }, - "/api/resources/{id}": { - "get": { - "operationId": "GetPublicResourceById", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } + "additionalProperties": false + }, + "SaveScenarioRequest": { + "type": "object", + "properties": { + "nameAr": { + "type": "string", + "nullable": true + }, + "nameEn": { + "type": "string", + "nullable": true + }, + "cityType": { + "$ref": "#/components/schemas/CityType" + }, + "targetYear": { + "type": "integer", + "format": "int32" + }, + "configurationJson": { + "type": "string", + "nullable": true } + }, + "additionalProperties": false + }, + "SearchableType": { + "enum": [ + 0, + 1, + 2, + 3, + 4 ], - "responses": { - "200": { - "description": "OK" + "type": "integer", + "format": "int32" + }, + "ServiceRatingRequest": { + "type": "object", + "properties": { + "rating": { + "type": "integer", + "format": "int32" + }, + "commentAr": { + "type": "string", + "nullable": true + }, + "commentEn": { + "type": "string", + "nullable": true + }, + "page": { + "type": "string", + "nullable": true + }, + "locale": { + "type": "string", + "nullable": true } }, - "tags": [ - "Resources" - ] - } - }, - "/api/resources/{id}/download": { - "get": { - "operationId": "DownloadPublicResource", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } + "additionalProperties": false + }, + "ShareContentType": { + "enum": [ + 0, + 1, + 2 ], - "responses": { - "200": { - "description": "OK" + "type": "integer", + "format": "int32" + }, + "ShareLinkDto": { + "type": "object", + "properties": { + "link": { + "type": "string", + "nullable": true + }, + "title": { + "type": "string", + "nullable": true + }, + "imageUrl": { + "type": "string", + "nullable": true } }, - "tags": [ - "Resources" - ] - } - }, - "/api/search": { - "get": { - "operationId": "Search", - "parameters": [ - { - "in": "query", - "name": "q", - "required": true, - "schema": { - "type": "string" - } + "additionalProperties": false + }, + "ShareLinkDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true }, - { - "in": "query", - "name": "type", - "schema": { - "$ref": "#/components/schemas/SearchableType" - } + "code": { + "type": "string", + "nullable": true, + "readOnly": true }, - { - "in": "query", - "name": "page", - "schema": { - "format": "int32", - "type": "integer" - } + "message": { + "type": "string", + "nullable": true, + "readOnly": true }, - { - "in": "query", - "name": "pageSize", - "schema": { - "format": "int32", - "type": "integer" - } + "data": { + "$ref": "#/components/schemas/ShareLinkDto" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } + }, + "additionalProperties": false + }, + "SortOrder": { + "enum": [ + 0, + 1 ], - "responses": { - "200": { - "description": "OK" + "type": "integer", + "format": "int32" + }, + "SubmitEvaluationRequest": { + "type": "object", + "properties": { + "overallSatisfaction": { + "type": "integer", + "format": "int32" + }, + "easeOfUse": { + "type": "integer", + "format": "int32" + }, + "contentSuitability": { + "type": "integer", + "format": "int32" + }, + "feedback": { + "type": "string", + "nullable": true } }, - "tags": [ - "Search" - ] - } - }, - "/api/surveys/service-rating": { - "post": { - "operationId": "SubmitServiceRating", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ServiceRatingRequest" - } - } + "additionalProperties": false + }, + "SubmitExpertRequestRequest": { + "type": "object", + "properties": { + "requestedBioAr": { + "type": "string", + "nullable": true }, - "required": true + "requestedBioEn": { + "type": "string", + "nullable": true + }, + "requestedTags": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "cvAssetFileId": { + "type": "string", + "format": "uuid" + } }, - "responses": { - "200": { - "description": "OK" + "additionalProperties": false + }, + "TagDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "nameAr": { + "type": "string", + "nullable": true + }, + "nameEn": { + "type": "string", + "nullable": true + }, + "color": { + "type": "string", + "nullable": true } }, - "tags": [ - "Surveys" - ] - } - }, - "/api/topics": { - "get": { - "operationId": "ListPublicTopics", - "responses": { - "200": { - "description": "OK" + "additionalProperties": false + }, + "TagDtoListResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TagDto" + }, + "nullable": true, + "readOnly": true + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } }, - "tags": [ - "TopicsPublic" - ] - } - }, - "/api/users/expert-request": { - "post": { - "operationId": "SubmitExpertRequest", - "requestBody": { + "additionalProperties": false + }, + "UpdateDraftRequest": { + "type": "object", + "properties": { + "title": { + "type": "string", + "nullable": true + }, "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubmitExpertRequestRequest" - } - } + "type": "string", + "nullable": true }, - "required": true + "tagIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "nullable": true + } }, - "responses": { - "200": { - "description": "OK" + "additionalProperties": false + }, + "UpdateMediaMetadataCommand": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "titleAr": { + "type": "string", + "nullable": true + }, + "titleEn": { + "type": "string", + "nullable": true + }, + "descriptionAr": { + "type": "string", + "nullable": true + }, + "descriptionEn": { + "type": "string", + "nullable": true + }, + "altTextAr": { + "type": "string", + "nullable": true + }, + "altTextEn": { + "type": "string", + "nullable": true } }, - "tags": [ - "Profile" - ] - } - }, - "/api/users/register": { - "post": { - "operationId": "RegisterUser", - "responses": { - "200": { - "description": "OK" + "additionalProperties": false + }, + "UpdateMyNotificationSettingsRequest": { + "type": "object", + "properties": { + "channel": { + "$ref": "#/components/schemas/NotificationChannel" + }, + "isEnabled": { + "type": "boolean" + }, + "eventCode": { + "type": "string", + "nullable": true } }, - "tags": [ - "Profile" - ] - } - }, - "/auth/callback": { - "get": { - "operationId": "BffCallback", - "parameters": [ - { - "in": "query", - "name": "code", - "required": true, - "schema": { - "type": "string" - } + "additionalProperties": false + }, + "UpdateMyProfileRequest": { + "type": "object", + "properties": { + "firstName": { + "type": "string", + "nullable": true }, - { - "in": "query", - "name": "state", - "required": true, - "schema": { + "lastName": { + "type": "string", + "nullable": true + }, + "jobTitle": { + "type": "string", + "nullable": true + }, + "organizationName": { + "type": "string", + "nullable": true + }, + "localePreference": { + "type": "string", + "nullable": true + }, + "knowledgeLevel": { + "$ref": "#/components/schemas/KnowledgeLevel" + }, + "interests": { + "type": "array", + "items": { "type": "string" - } + }, + "nullable": true + }, + "avatarUrl": { + "type": "string", + "nullable": true + }, + "countryId": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "countryCodeId": { + "type": "string", + "format": "uuid", + "nullable": true } - ], - "responses": { - "200": { - "description": "OK" + }, + "additionalProperties": false + }, + "VerifyOtpRequest": { + "type": "object", + "properties": { + "verificationId": { + "type": "string", + "format": "uuid" + }, + "code": { + "type": "string", + "nullable": true } }, - "tags": [ - "Auth" - ] - } - }, - "/auth/echo": { - "get": { - "responses": { - "200": { - "description": "OK" + "additionalProperties": false + }, + "VerifyOtpResponseDto": { + "type": "object", + "properties": { + "verified": { + "type": "boolean" + }, + "userId": { + "type": "string", + "format": "uuid", + "nullable": true } }, - "tags": [ - "CCE.Api.External" - ] - } - }, - "/auth/login": { - "get": { - "operationId": "BffLogin", - "parameters": [ - { - "in": "query", - "name": "returnUrl", - "schema": { - "type": "string" - } + "additionalProperties": false + }, + "VerifyOtpResponseDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/VerifyOtpResponseDto" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } - ], - "responses": { - "200": { - "description": "OK" + }, + "additionalProperties": false + }, + "VoidData": { + "type": "object", + "additionalProperties": false + }, + "VoidDataResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/VoidData" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } }, - "tags": [ - "Auth" - ] - } - }, - "/auth/logout": { - "post": { - "operationId": "BffLogout", - "responses": { - "200": { - "description": "OK" + "additionalProperties": false + }, + "VoteDirection": { + "enum": [ + 0, + 1, + -1 + ], + "type": "integer", + "format": "int32" + }, + "VotePostRequest": { + "type": "object", + "properties": { + "direction": { + "$ref": "#/components/schemas/VoteDirection" } }, - "tags": [ - "Auth" - ] - } - }, - "/auth/refresh": { - "post": { - "operationId": "BffRefresh", - "responses": { - "200": { - "description": "OK" + "additionalProperties": false + }, + "VoteReplyRequest": { + "type": "object", + "properties": { + "direction": { + "$ref": "#/components/schemas/VoteDirection" } }, - "tags": [ - "Auth" - ] + "additionalProperties": false } }, - "/health": { - "get": { - "responses": { - "200": { - "description": "OK" - } - }, - "tags": [ - "CCE.Api.External" - ] + "securitySchemes": { + "Bearer": { + "type": "http", + "description": "Paste your JWT Bearer token (e.g. from Entra ID or /dev/sign-in).", + "scheme": "Bearer", + "bearerFormat": "JWT" } } - } -} + }, + "security": [ + { + "Bearer": [ ] + } + ] +} \ No newline at end of file diff --git a/contracts/openapi.internal.json b/contracts/openapi.internal.json index 00b517b5..81160a15 100644 --- a/contracts/openapi.internal.json +++ b/contracts/openapi.internal.json @@ -1,2965 +1,16162 @@ { - "components": { - "schemas": { - "ApproveCountryResourceRequestRequest": { - "additionalProperties": false, - "properties": { - "adminNotesAr": { - "nullable": true, - "type": "string" - }, - "adminNotesEn": { - "nullable": true, - "type": "string" - } - }, - "type": "object" - }, - "ApproveExpertRequestRequest": { - "additionalProperties": false, - "properties": { - "academicTitleAr": { - "nullable": true, - "type": "string" - }, - "academicTitleEn": { - "nullable": true, - "type": "string" + "openapi": "3.0.1", + "info": { + "title": "CCE Internal API", + "description": "CCE Knowledge Center — CCE Internal API", + "version": "v1" + }, + "paths": { + "/api/admin/assets": { + "post": { + "tags": [ + "Assets" + ], + "operationId": "UploadAsset", + "responses": { + "200": { + "description": "OK" } - }, - "type": "object" - }, - "AssignUserRolesRequest": { - "additionalProperties": false, - "properties": { - "roles": { - "items": { - "type": "string" - }, - "nullable": true, - "type": "array" + } + } + }, + "/api/admin/assets/{id}": { + "get": { + "tags": [ + "Assets" + ], + "operationId": "GetAssetById", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } } - }, - "type": "object" - }, - "CreateEventRequest": { - "additionalProperties": false, - "properties": { - "descriptionAr": { - "nullable": true, - "type": "string" - }, - "descriptionEn": { - "nullable": true, - "type": "string" - }, - "endsOn": { - "format": "date-time", - "type": "string" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssetFileDtoResponse" + } + } + } }, - "featuredImageUrl": { - "nullable": true, - "type": "string" + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssetFileDtoResponse" + } + } + } }, - "locationAr": { - "nullable": true, - "type": "string" + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssetFileDtoResponse" + } + } + } }, - "locationEn": { - "nullable": true, - "type": "string" + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssetFileDtoResponse" + } + } + } }, - "onlineMeetingUrl": { - "nullable": true, - "type": "string" + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssetFileDtoResponse" + } + } + } }, - "startsOn": { - "format": "date-time", - "type": "string" + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssetFileDtoResponse" + } + } + } }, - "titleAr": { - "nullable": true, - "type": "string" + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssetFileDtoResponse" + } + } + } }, - "titleEn": { - "nullable": true, - "type": "string" + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssetFileDtoResponse" + } + } + } } - }, - "type": "object" - }, - "CreateHomepageSectionRequest": { - "additionalProperties": false, - "properties": { - "contentAr": { - "nullable": true, - "type": "string" - }, - "contentEn": { - "nullable": true, - "type": "string" + } + } + }, + "/api/admin/audit-events": { + "get": { + "tags": [ + "Audit" + ], + "operationId": "ListAuditEvents", + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } }, - "orderIndex": { - "format": "int32", - "type": "integer" + { + "name": "pageSize", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } }, - "sectionType": { - "$ref": "#/components/schemas/HomepageSectionType" - } - }, - "type": "object" - }, - "CreateNewsRequest": { - "additionalProperties": false, - "properties": { - "contentAr": { - "nullable": true, - "type": "string" + { + "name": "actor", + "in": "query", + "schema": { + "type": "string" + } }, - "contentEn": { - "nullable": true, - "type": "string" + { + "name": "actionPrefix", + "in": "query", + "schema": { + "type": "string" + } }, - "featuredImageUrl": { - "nullable": true, - "type": "string" + { + "name": "resourceType", + "in": "query", + "schema": { + "type": "string" + } }, - "slug": { - "nullable": true, - "type": "string" + { + "name": "correlationId", + "in": "query", + "schema": { + "type": "string", + "format": "uuid" + } }, - "titleAr": { - "nullable": true, - "type": "string" + { + "name": "from", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } }, - "titleEn": { - "nullable": true, - "type": "string" + { + "name": "to", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } } - }, - "type": "object" - }, - "CreateNotificationTemplateRequest": { - "additionalProperties": false, - "properties": { - "bodyAr": { - "nullable": true, - "type": "string" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/auth/register": { + "post": { + "tags": [ + "Auth" + ], + "operationId": "InternalRegisterUser", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RegisterUserRequest" + } + } }, - "bodyEn": { - "nullable": true, - "type": "string" + "required": true + }, + "responses": { + "201": { + "description": "Created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthUserDtoResponse" + } + } + } }, - "channel": { - "$ref": "#/components/schemas/NotificationChannel" + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthUserDtoResponse" + } + } + } }, - "code": { - "nullable": true, - "type": "string" + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthUserDtoResponse" + } + } + } }, - "subjectAr": { - "nullable": true, - "type": "string" + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthUserDtoResponse" + } + } + } }, - "subjectEn": { - "nullable": true, - "type": "string" + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthUserDtoResponse" + } + } + } }, - "variableSchemaJson": { - "nullable": true, - "type": "string" - } - }, - "type": "object" - }, - "CreatePageRequest": { - "additionalProperties": false, - "properties": { - "contentAr": { - "nullable": true, - "type": "string" + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthUserDtoResponse" + } + } + } }, - "contentEn": { - "nullable": true, - "type": "string" + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthUserDtoResponse" + } + } + } }, - "pageType": { - "$ref": "#/components/schemas/PageType" + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthUserDtoResponse" + } + } + } + } + } + } + }, + "/api/auth/login": { + "post": { + "tags": [ + "Auth" + ], + "operationId": "InternalLogin", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LoginRequest" + } + } }, - "slug": { - "nullable": true, - "type": "string" + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokenDtoResponse" + } + } + } }, - "titleAr": { - "nullable": true, - "type": "string" + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokenDtoResponse" + } + } + } }, - "titleEn": { - "nullable": true, - "type": "string" - } - }, - "type": "object" - }, - "CreateResourceCategoryRequest": { - "additionalProperties": false, - "properties": { - "nameAr": { - "nullable": true, - "type": "string" + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokenDtoResponse" + } + } + } }, - "nameEn": { - "nullable": true, - "type": "string" + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokenDtoResponse" + } + } + } }, - "orderIndex": { - "format": "int32", - "type": "integer" + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokenDtoResponse" + } + } + } }, - "parentId": { - "format": "uuid", - "nullable": true, - "type": "string" + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokenDtoResponse" + } + } + } }, - "slug": { - "nullable": true, - "type": "string" + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokenDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokenDtoResponse" + } + } + } } + } + } + }, + "/api/auth/refresh": { + "post": { + "tags": [ + "Auth" + ], + "operationId": "InternalRefreshToken", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RefreshTokenRequest" + } + } + }, + "required": true }, - "type": "object" - }, - "CreateResourceRequest": { - "additionalProperties": false, - "properties": { - "assetFileId": { - "format": "uuid", - "type": "string" + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokenDtoResponse" + } + } + } }, - "categoryId": { - "format": "uuid", - "type": "string" + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokenDtoResponse" + } + } + } }, - "countryId": { - "format": "uuid", - "nullable": true, - "type": "string" + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokenDtoResponse" + } + } + } }, - "descriptionAr": { - "nullable": true, - "type": "string" + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokenDtoResponse" + } + } + } }, - "descriptionEn": { - "nullable": true, - "type": "string" + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokenDtoResponse" + } + } + } }, - "resourceType": { - "$ref": "#/components/schemas/ResourceType" + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokenDtoResponse" + } + } + } }, - "titleAr": { - "nullable": true, - "type": "string" + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokenDtoResponse" + } + } + } }, - "titleEn": { - "nullable": true, - "type": "string" + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokenDtoResponse" + } + } + } } - }, - "type": "object" - }, - "CreateStateRepAssignmentRequest": { - "additionalProperties": false, - "properties": { - "countryId": { - "format": "uuid", - "type": "string" + } + } + }, + "/api/auth/forgot-password": { + "post": { + "tags": [ + "Auth" + ], + "operationId": "InternalForgotPassword", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ForgotPasswordRequest" + } + } }, - "userId": { - "format": "uuid", - "type": "string" - } + "required": true }, - "type": "object" - }, - "CreateTopicRequest": { - "additionalProperties": false, - "properties": { - "descriptionAr": { - "nullable": true, - "type": "string" - }, - "descriptionEn": { - "nullable": true, - "type": "string" - }, - "iconUrl": { - "nullable": true, - "type": "string" + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } + } }, - "nameAr": { - "nullable": true, - "type": "string" + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } + } }, - "nameEn": { - "nullable": true, - "type": "string" + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } + } }, - "orderIndex": { - "format": "int32", - "type": "integer" + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } + } }, - "parentId": { - "format": "uuid", + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } + } + } + } + } + }, + "/api/auth/reset-password": { + "post": { + "tags": [ + "Auth" + ], + "operationId": "InternalResetPassword", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResetPasswordRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } + } + } + } + } + }, + "/api/auth/logout": { + "post": { + "tags": [ + "Auth" + ], + "operationId": "InternalLogout", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LogoutRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMessageDtoResponse" + } + } + } + } + } + } + }, + "/api/auth/ad-login": { + "post": { + "tags": [ + "Auth" + ], + "operationId": "InternalAdLogin", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdLoginRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokenDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokenDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokenDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokenDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokenDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokenDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokenDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokenDtoResponse" + } + } + } + } + } + } + }, + "/auth/login": { + "get": { + "tags": [ + "CCE.Api.Internal" + ], + "operationId": "AuthLoginShim", + "parameters": [ + { + "name": "returnUrl", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/auth/logout": { + "post": { + "tags": [ + "CCE.Api.Internal" + ], + "operationId": "AuthLogoutShim", + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/": { + "get": { + "tags": [ + "CCE.Api.Internal" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/auth/echo": { + "get": { + "tags": [ + "CCE.Api.Internal" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/health": { + "get": { + "tags": [ + "CCE.Api.Internal" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/health/authenticated": { + "get": { + "tags": [ + "CCE.Api.Internal" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/admin/community/posts": { + "get": { + "tags": [ + "CommunityModeration" + ], + "operationId": "ListAdminPosts", + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "pageSize", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "topicId", + "in": "query", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "search", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "status", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "locale", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/admin/community/posts/{id}": { + "delete": { + "tags": [ + "CommunityModeration" + ], + "operationId": "SoftDeletePost", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/admin/community/replies/{id}": { + "delete": { + "tags": [ + "CommunityModeration" + ], + "operationId": "SoftDeleteReply", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/admin/community/communities": { + "post": { + "tags": [ + "CommunityModeration" + ], + "operationId": "CreateCommunity", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateCommunityRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + } + } + } + }, + "/api/admin/community/communities/{id}": { + "put": { + "tags": [ + "CommunityModeration" + ], + "operationId": "UpdateCommunity", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateCommunityRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + } + } + } + }, + "/api/admin/community/communities/{id}/visibility": { + "post": { + "tags": [ + "CommunityModeration" + ], + "operationId": "ChangeCommunityVisibility", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChangeCommunityVisibilityRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + } + } + } + }, + "/api/admin/community/communities/{id}/join-requests": { + "get": { + "tags": [ + "CommunityModeration" + ], + "operationId": "ListJoinRequests", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "pageSize", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/JoinRequestDtoPagedResultResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/JoinRequestDtoPagedResultResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/JoinRequestDtoPagedResultResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/JoinRequestDtoPagedResultResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/JoinRequestDtoPagedResultResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/JoinRequestDtoPagedResultResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/JoinRequestDtoPagedResultResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/JoinRequestDtoPagedResultResponse" + } + } + } + } + } + } + }, + "/api/admin/community/join-requests/{id}/approve": { + "post": { + "tags": [ + "CommunityModeration" + ], + "operationId": "ApproveJoinRequest", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + } + } + } + }, + "/api/admin/community/join-requests/{id}/reject": { + "post": { + "tags": [ + "CommunityModeration" + ], + "operationId": "RejectJoinRequest", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + } + } + } + }, + "/api/admin/countries": { + "get": { + "tags": [ + "Countries" + ], + "operationId": "ListCountries", + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "pageSize", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "search", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "isActive", + "in": "query", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/admin/countries/{id}": { + "get": { + "tags": [ + "Countries" + ], + "operationId": "GetCountryById", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "put": { + "tags": [ + "Countries" + ], + "operationId": "UpdateCountry", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateCountryRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/admin/countries/{countryId}/profile": { + "get": { + "tags": [ + "Countries" + ], + "operationId": "GetCountryProfile", + "parameters": [ + { + "name": "countryId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "put": { + "tags": [ + "Countries" + ], + "operationId": "UpsertCountryProfile", + "parameters": [ + { + "name": "countryId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpsertCountryProfileRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryProfileDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryProfileDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryProfileDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryProfileDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryProfileDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryProfileDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryProfileDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryProfileDtoResponse" + } + } + } + } + } + } + }, + "/api/admin/country-codes": { + "get": { + "tags": [ + "CountryCodes" + ], + "operationId": "ListCountryCodes", + "parameters": [ + { + "name": "search", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "isActive", + "in": "query", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "post": { + "tags": [ + "CountryCodes" + ], + "operationId": "UpsertCountryCode", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpsertCountryCodeRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/admin/country-codes/{id}": { + "get": { + "tags": [ + "CountryCodes" + ], + "operationId": "GetCountryCodeById", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/admin/country-resource-requests": { + "get": { + "tags": [ + "CountryResourceRequests" + ], + "operationId": "ListAdminCountryContentRequests", + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "pageSize", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "status", + "in": "query", + "schema": { + "$ref": "#/components/schemas/CountryContentRequestStatus" + } + }, + { + "name": "type", + "in": "query", + "schema": { + "$ref": "#/components/schemas/ContentType" + } + }, + { + "name": "countryId", + "in": "query", + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoPagedResultResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoPagedResultResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoPagedResultResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoPagedResultResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoPagedResultResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoPagedResultResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoPagedResultResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoPagedResultResponse" + } + } + } + } + } + } + }, + "/api/admin/country-resource-requests/{id}": { + "get": { + "tags": [ + "CountryResourceRequests" + ], + "operationId": "GetAdminCountryContentRequest", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoResponse" + } + } + } + } + } + } + }, + "/api/admin/country-resource-requests/{id}/approve": { + "post": { + "tags": [ + "CountryResourceRequests" + ], + "operationId": "ApproveCountryResourceRequest", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApproveCountryResourceRequestRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoResponse" + } + } + } + } + } + } + }, + "/api/admin/country-resource-requests/{id}/reject": { + "post": { + "tags": [ + "CountryResourceRequests" + ], + "operationId": "RejectCountryResourceRequest", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RejectCountryResourceRequestRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoResponse" + } + } + } + } + } + } + }, + "/dev/sign-in": { + "get": { + "tags": [ + "DevAuth" + ], + "operationId": "DevSignIn", + "parameters": [ + { + "name": "role", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "returnUrl", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/dev/sign-out": { + "post": { + "tags": [ + "DevAuth" + ], + "operationId": "DevSignOut", + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/dev/whoami": { + "get": { + "tags": [ + "DevAuth" + ], + "operationId": "DevWhoAmI", + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/admin/evaluations": { + "get": { + "tags": [ + "Evaluations" + ], + "operationId": "GetAllEvaluations", + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "pageSize", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceEvaluationDtoPagedResultResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceEvaluationDtoPagedResultResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceEvaluationDtoPagedResultResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceEvaluationDtoPagedResultResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceEvaluationDtoPagedResultResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceEvaluationDtoPagedResultResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceEvaluationDtoPagedResultResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceEvaluationDtoPagedResultResponse" + } + } + } + } + } + } + }, + "/api/admin/evaluations/{id}": { + "get": { + "tags": [ + "Evaluations" + ], + "operationId": "GetEvaluationById", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceEvaluationDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceEvaluationDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceEvaluationDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceEvaluationDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceEvaluationDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceEvaluationDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceEvaluationDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceEvaluationDtoResponse" + } + } + } + } + } + } + }, + "/api/admin/events": { + "get": { + "tags": [ + "Events" + ], + "operationId": "ListEvents", + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "pageSize", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "search", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "fromDate", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "toDate", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "topicId", + "in": "query", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "tagIds", + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDtoPagedResultResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDtoPagedResultResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDtoPagedResultResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDtoPagedResultResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDtoPagedResultResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDtoPagedResultResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDtoPagedResultResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDtoPagedResultResponse" + } + } + } + } + } + }, + "post": { + "tags": [ + "Events" + ], + "operationId": "CreateEvent", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateEventRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDtoResponse" + } + } + } + } + } + } + }, + "/api/admin/events/{id}": { + "get": { + "tags": [ + "Events" + ], + "operationId": "GetEventById", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDtoResponse" + } + } + } + } + } + }, + "put": { + "tags": [ + "Events" + ], + "operationId": "UpdateEvent", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateEventRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDtoResponse" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Events" + ], + "operationId": "DeleteEvent", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + } + } + } + }, + "/api/admin/events/{id}/reschedule": { + "post": { + "tags": [ + "Events" + ], + "operationId": "RescheduleEvent", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RescheduleEventRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDtoResponse" + } + } + } + } + } + } + }, + "/api/admin/expert-requests": { + "get": { + "tags": [ + "Experts" + ], + "operationId": "ListExpertRequests", + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "pageSize", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "status", + "in": "query", + "schema": { + "$ref": "#/components/schemas/ExpertRegistrationStatus" + } + }, + { + "name": "requestedById", + "in": "query", + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/admin/expert-requests/{id}": { + "get": { + "tags": [ + "Experts" + ], + "operationId": "GetExpertRequestById", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExpertRequestDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExpertRequestDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExpertRequestDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExpertRequestDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExpertRequestDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExpertRequestDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExpertRequestDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExpertRequestDtoResponse" + } + } + } + } + } + } + }, + "/api/admin/expert-requests/{id}/approve": { + "post": { + "tags": [ + "Experts" + ], + "operationId": "ApproveExpertRequest", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApproveExpertRequestRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExpertProfileDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExpertProfileDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExpertProfileDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExpertProfileDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExpertProfileDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExpertProfileDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExpertProfileDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExpertProfileDtoResponse" + } + } + } + } + } + } + }, + "/api/admin/expert-requests/{id}/reject": { + "post": { + "tags": [ + "Experts" + ], + "operationId": "RejectExpertRequest", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RejectExpertRequestRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExpertRequestDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExpertRequestDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExpertRequestDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExpertRequestDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExpertRequestDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExpertRequestDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExpertRequestDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExpertRequestDtoResponse" + } + } + } + } + } + } + }, + "/api/admin/expert-profiles": { + "get": { + "tags": [ + "Experts" + ], + "operationId": "ListExpertProfiles", + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "pageSize", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "search", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/admin/homepage-sections": { + "get": { + "tags": [ + "HomepageSections" + ], + "operationId": "ListHomepageSections", + "responses": { + "200": { + "description": "OK" + } + } + }, + "post": { + "tags": [ + "HomepageSections" + ], + "operationId": "CreateHomepageSection", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateHomepageSectionRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/admin/homepage-sections/{id}": { + "put": { + "tags": [ + "HomepageSections" + ], + "operationId": "UpdateHomepageSection", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateHomepageSectionRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + } + } + }, + "delete": { + "tags": [ + "HomepageSections" + ], + "operationId": "DeleteHomepageSection", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/admin/homepage-sections/reorder": { + "post": { + "tags": [ + "HomepageSections" + ], + "operationId": "ReorderHomepageSections", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReorderHomepageSectionsRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/admin/users": { + "get": { + "tags": [ + "Identity" + ], + "operationId": "ListUsers", + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "pageSize", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "search", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "role", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserListItemDtoPagedResultResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserListItemDtoPagedResultResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserListItemDtoPagedResultResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserListItemDtoPagedResultResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserListItemDtoPagedResultResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserListItemDtoPagedResultResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserListItemDtoPagedResultResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserListItemDtoPagedResultResponse" + } + } + } + } + } + }, + "post": { + "tags": [ + "Identity" + ], + "operationId": "CreateUser", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateUserRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDetailDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDetailDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDetailDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDetailDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDetailDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDetailDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDetailDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDetailDtoResponse" + } + } + } + } + } + } + }, + "/api/admin/users/{id}": { + "get": { + "tags": [ + "Identity" + ], + "operationId": "GetUserById", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDetailDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDetailDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDetailDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDetailDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDetailDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDetailDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDetailDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDetailDtoResponse" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Identity" + ], + "operationId": "DeleteUser", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDetailDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDetailDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDetailDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDetailDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDetailDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDetailDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDetailDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDetailDtoResponse" + } + } + } + } + } + } + }, + "/api/admin/users/{id}/roles": { + "put": { + "tags": [ + "Identity" + ], + "operationId": "AssignUserRoles", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssignUserRolesRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDetailDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDetailDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDetailDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDetailDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDetailDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDetailDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDetailDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDetailDtoResponse" + } + } + } + } + } + } + }, + "/api/admin/users/{id}/status": { + "put": { + "tags": [ + "Identity" + ], + "operationId": "ChangeUserStatus", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChangeUserStatusRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDetailDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDetailDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDetailDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDetailDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDetailDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDetailDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDetailDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDetailDtoResponse" + } + } + } + } + } + } + }, + "/api/admin/users/sync": { + "post": { + "tags": [ + "Identity" + ], + "operationId": "SyncEntraIdUsers", + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/admin/state-rep-assignments": { + "get": { + "tags": [ + "Identity" + ], + "operationId": "ListStateRepAssignments", + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "pageSize", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "userId", + "in": "query", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "countryId", + "in": "query", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "active", + "in": "query", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "post": { + "tags": [ + "Identity" + ], + "operationId": "CreateStateRepAssignment", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateStateRepAssignmentRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StateRepAssignmentDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StateRepAssignmentDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StateRepAssignmentDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StateRepAssignmentDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StateRepAssignmentDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StateRepAssignmentDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StateRepAssignmentDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StateRepAssignmentDtoResponse" + } + } + } + } + } + } + }, + "/api/admin/state-rep-assignments/{id}": { + "delete": { + "tags": [ + "Identity" + ], + "operationId": "RevokeStateRepAssignment", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + } + } + } + }, + "/api/admin/countries/{countryId}/kapsarc/refresh": { + "post": { + "tags": [ + "Kapsarc" + ], + "operationId": "RefreshKapsarcSnapshot", + "parameters": [ + { + "name": "countryId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KapsarcSnapshotDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KapsarcSnapshotDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KapsarcSnapshotDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KapsarcSnapshotDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KapsarcSnapshotDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KapsarcSnapshotDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KapsarcSnapshotDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KapsarcSnapshotDtoResponse" + } + } + } + } + } + } + }, + "/api/media": { + "post": { + "tags": [ + "Media" + ], + "operationId": "UploadMediaInternal", + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "required": [ + "file" + ], + "type": "object", + "properties": { + "file": { + "type": "string", + "format": "binary" + }, + "titleAr": { + "type": "string" + }, + "titleEn": { + "type": "string" + }, + "descriptionAr": { + "type": "string" + }, + "descriptionEn": { + "type": "string" + }, + "altTextAr": { + "type": "string" + }, + "altTextEn": { + "type": "string" + } + } + }, + "encoding": { + "file": { + "style": "form" + }, + "titleAr": { + "style": "form" + }, + "titleEn": { + "style": "form" + }, + "descriptionAr": { + "style": "form" + }, + "descriptionEn": { + "style": "form" + }, + "altTextAr": { + "style": "form" + }, + "altTextEn": { + "style": "form" + } + } + } + } + }, + "responses": { + "201": { + "description": "Created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + } + } + } + }, + "/api/media/{id}": { + "get": { + "tags": [ + "Media" + ], + "operationId": "GetMediaInternal", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileDtoResponse" + } + } + } + } + } + }, + "put": { + "tags": [ + "Media" + ], + "operationId": "UpdateMediaMetadataInternal", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateMediaMetadataCommand" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Media" + ], + "operationId": "DeleteMediaInternal", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaFileBriefDtoResponse" + } + } + } + } + } + } + }, + "/api/media/{id}/download": { + "get": { + "tags": [ + "Media" + ], + "operationId": "DownloadMediaInternal", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/admin/news": { + "get": { + "tags": [ + "News" + ], + "operationId": "ListNews", + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "pageSize", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "search", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "isPublished", + "in": "query", + "schema": { + "type": "boolean" + } + }, + { + "name": "isFeatured", + "in": "query", + "schema": { + "type": "boolean" + } + }, + { + "name": "topicId", + "in": "query", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "tagIds", + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewsDtoPagedResultResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewsDtoPagedResultResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewsDtoPagedResultResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewsDtoPagedResultResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewsDtoPagedResultResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewsDtoPagedResultResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewsDtoPagedResultResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewsDtoPagedResultResponse" + } + } + } + } + } + }, + "post": { + "tags": [ + "News" + ], + "operationId": "CreateNews", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateNewsRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewsDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewsDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewsDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewsDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewsDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewsDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewsDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewsDtoResponse" + } + } + } + } + } + } + }, + "/api/admin/news/{id}": { + "get": { + "tags": [ + "News" + ], + "operationId": "GetNewsById", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewsDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewsDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewsDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewsDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewsDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewsDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewsDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewsDtoResponse" + } + } + } + } + } + }, + "put": { + "tags": [ + "News" + ], + "operationId": "UpdateNews", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateNewsRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewsDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewsDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewsDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewsDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewsDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewsDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewsDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewsDtoResponse" + } + } + } + } + } + }, + "delete": { + "tags": [ + "News" + ], + "operationId": "DeleteNews", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + } + } + } + }, + "/api/admin/news/{id}/publish": { + "post": { + "tags": [ + "News" + ], + "operationId": "PublishNews", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewsDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewsDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewsDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewsDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewsDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewsDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewsDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewsDtoResponse" + } + } + } + } + } + } + }, + "/api/admin/notification-logs": { + "get": { + "tags": [ + "Notification Logs" + ], + "operationId": "ListNotificationLogs", + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "pageSize", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "recipientUserId", + "in": "query", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "templateCode", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "channel", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "status", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationLogListItemDtoPagedResultResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationLogListItemDtoPagedResultResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationLogListItemDtoPagedResultResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationLogListItemDtoPagedResultResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationLogListItemDtoPagedResultResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationLogListItemDtoPagedResultResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationLogListItemDtoPagedResultResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationLogListItemDtoPagedResultResponse" + } + } + } + } + } + } + }, + "/api/admin/notification-logs/{id}": { + "get": { + "tags": [ + "Notification Logs" + ], + "operationId": "GetNotificationLogById", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationLogDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationLogDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationLogDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationLogDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationLogDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationLogDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationLogDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationLogDtoResponse" + } + } + } + } + } + } + }, + "/api/admin/notification-logs/{id}/retry": { + "post": { + "tags": [ + "Notification Logs" + ], + "operationId": "RetryNotificationLog", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + } + } + } + }, + "/api/admin/notification-templates": { + "get": { + "tags": [ + "NotificationTemplates" + ], + "operationId": "ListNotificationTemplates", + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "pageSize", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "channel", + "in": "query", + "schema": { + "$ref": "#/components/schemas/NotificationChannel" + } + }, + { + "name": "isActive", + "in": "query", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationTemplateDtoPagedResultResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationTemplateDtoPagedResultResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationTemplateDtoPagedResultResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationTemplateDtoPagedResultResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationTemplateDtoPagedResultResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationTemplateDtoPagedResultResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationTemplateDtoPagedResultResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationTemplateDtoPagedResultResponse" + } + } + } + } + } + }, + "post": { + "tags": [ + "NotificationTemplates" + ], + "operationId": "CreateNotificationTemplate", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateNotificationTemplateRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + } + } + } + }, + "/api/admin/notification-templates/{id}": { + "get": { + "tags": [ + "NotificationTemplates" + ], + "operationId": "GetNotificationTemplateById", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationTemplateDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationTemplateDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationTemplateDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationTemplateDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationTemplateDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationTemplateDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationTemplateDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationTemplateDtoResponse" + } + } + } + } + } + }, + "put": { + "tags": [ + "NotificationTemplates" + ], + "operationId": "UpdateNotificationTemplate", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateNotificationTemplateRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + } + } + } + }, + "/api/admin/pages": { + "get": { + "tags": [ + "Pages" + ], + "operationId": "ListPages", + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "pageSize", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "search", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "pageType", + "in": "query", + "schema": { + "$ref": "#/components/schemas/PageType" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "post": { + "tags": [ + "Pages" + ], + "operationId": "CreatePage", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreatePageRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/admin/pages/{id}": { + "get": { + "tags": [ + "Pages" + ], + "operationId": "GetPageById", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "put": { + "tags": [ + "Pages" + ], + "operationId": "UpdatePage", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdatePageRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + } + } + }, + "delete": { + "tags": [ + "Pages" + ], + "operationId": "DeletePage", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/admin/settings/homepage": { + "get": { + "tags": [ + "PlatformSettings" + ], + "operationId": "GetHomepageSettings", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HomepageSettingsDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HomepageSettingsDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HomepageSettingsDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HomepageSettingsDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HomepageSettingsDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HomepageSettingsDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HomepageSettingsDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HomepageSettingsDtoResponse" + } + } + } + } + } + }, + "put": { + "tags": [ + "PlatformSettings" + ], + "operationId": "UpdateHomepageSettings", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateHomepageSettingsRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + } + } + } + }, + "/api/admin/settings/about": { + "get": { + "tags": [ + "PlatformSettings" + ], + "operationId": "GetAboutSettings", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AboutSettingsDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AboutSettingsDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AboutSettingsDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AboutSettingsDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AboutSettingsDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AboutSettingsDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AboutSettingsDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AboutSettingsDtoResponse" + } + } + } + } + } + }, + "put": { + "tags": [ + "PlatformSettings" + ], + "operationId": "UpdateAboutSettings", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateAboutSettingsRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + } + } + } + }, + "/api/admin/settings/about/glossary": { + "post": { + "tags": [ + "PlatformSettings" + ], + "operationId": "CreateGlossaryEntry", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateGlossaryEntryRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + } + } + } + }, + "/api/admin/settings/about/glossary/{id}": { + "put": { + "tags": [ + "PlatformSettings" + ], + "operationId": "UpdateGlossaryEntry", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateGlossaryEntryRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + } + } + }, + "delete": { + "tags": [ + "PlatformSettings" + ], + "operationId": "DeleteGlossaryEntry", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + } + } + } + }, + "/api/admin/settings/about/knowledge-partners": { + "post": { + "tags": [ + "PlatformSettings" + ], + "operationId": "CreateKnowledgePartner", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateKnowledgePartnerRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + } + } + } + }, + "/api/admin/settings/about/knowledge-partners/{id}": { + "put": { + "tags": [ + "PlatformSettings" + ], + "operationId": "UpdateKnowledgePartner", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateKnowledgePartnerRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + } + } + }, + "delete": { + "tags": [ + "PlatformSettings" + ], + "operationId": "DeleteKnowledgePartner", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + } + } + } + }, + "/api/admin/settings/policies": { + "get": { + "tags": [ + "PlatformSettings" + ], + "operationId": "GetPoliciesSettings", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PoliciesSettingsDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PoliciesSettingsDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PoliciesSettingsDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PoliciesSettingsDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PoliciesSettingsDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PoliciesSettingsDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PoliciesSettingsDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PoliciesSettingsDtoResponse" + } + } + } + } + } + } + }, + "/api/admin/settings/policies/sections": { + "post": { + "tags": [ + "PlatformSettings" + ], + "operationId": "CreatePolicySection", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreatePolicySectionRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + } + } + } + }, + "/api/admin/settings/policies/sections/{id}": { + "put": { + "tags": [ + "PlatformSettings" + ], + "operationId": "UpdatePolicySection", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdatePolicySectionRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + } + } + }, + "delete": { + "tags": [ + "PlatformSettings" + ], + "operationId": "DeletePolicySection", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + } + } + } + }, + "/api/admin/settings/policies/sections/{id}/order": { + "put": { + "tags": [ + "PlatformSettings" + ], + "operationId": "ReorderPolicySection", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReorderPolicySectionRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + } + } + } + }, + "/api/admin/reports/users-registrations.csv": { + "get": { + "tags": [ + "Reports" + ], + "operationId": "UsersRegistrationsReport", + "parameters": [ + { + "name": "from", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "to", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/admin/reports/experts.csv": { + "get": { + "tags": [ + "Reports" + ], + "operationId": "ExpertsReport", + "parameters": [ + { + "name": "from", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "to", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/admin/reports/satisfaction-survey.csv": { + "get": { + "tags": [ + "Reports" + ], + "operationId": "SatisfactionSurveyReport", + "parameters": [ + { + "name": "from", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "to", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/admin/reports/community-posts.csv": { + "get": { + "tags": [ + "Reports" + ], + "operationId": "CommunityPostsReport", + "parameters": [ + { + "name": "from", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "to", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/admin/reports/news.csv": { + "get": { + "tags": [ + "Reports" + ], + "operationId": "NewsReport", + "parameters": [ + { + "name": "from", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "to", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/admin/reports/events.csv": { + "get": { + "tags": [ + "Reports" + ], + "operationId": "EventsReport", + "parameters": [ + { + "name": "from", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "to", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/admin/reports/resources.csv": { + "get": { + "tags": [ + "Reports" + ], + "operationId": "ResourcesReport", + "parameters": [ + { + "name": "from", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "to", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/admin/reports/country-profiles.csv": { + "get": { + "tags": [ + "Reports" + ], + "operationId": "CountryProfilesReport", + "parameters": [ + { + "name": "from", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "to", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/admin/resource-categories": { + "get": { + "tags": [ + "ResourceCategories" + ], + "operationId": "ListResourceCategories", + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "pageSize", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "parentId", + "in": "query", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "isActive", + "in": "query", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceCategoryDtoPagedResultResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceCategoryDtoPagedResultResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceCategoryDtoPagedResultResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceCategoryDtoPagedResultResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceCategoryDtoPagedResultResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceCategoryDtoPagedResultResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceCategoryDtoPagedResultResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceCategoryDtoPagedResultResponse" + } + } + } + } + } + }, + "post": { + "tags": [ + "ResourceCategories" + ], + "operationId": "CreateResourceCategory", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateResourceCategoryRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceCategoryDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceCategoryDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceCategoryDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceCategoryDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceCategoryDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceCategoryDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceCategoryDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceCategoryDtoResponse" + } + } + } + } + } + } + }, + "/api/admin/resource-categories/{id}": { + "get": { + "tags": [ + "ResourceCategories" + ], + "operationId": "GetResourceCategoryById", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceCategoryDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceCategoryDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceCategoryDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceCategoryDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceCategoryDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceCategoryDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceCategoryDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceCategoryDtoResponse" + } + } + } + } + } + }, + "put": { + "tags": [ + "ResourceCategories" + ], + "operationId": "UpdateResourceCategory", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateResourceCategoryRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceCategoryDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceCategoryDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceCategoryDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceCategoryDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceCategoryDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceCategoryDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceCategoryDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceCategoryDtoResponse" + } + } + } + } + } + }, + "delete": { + "tags": [ + "ResourceCategories" + ], + "operationId": "DeleteResourceCategory", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + } + } + } + }, + "/api/admin/resources": { + "get": { + "tags": [ + "Resources" + ], + "operationId": "ListResources", + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "pageSize", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "search", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "categoryId", + "in": "query", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "countryId", + "in": "query", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "isPublished", + "in": "query", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceDtoPagedResultResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceDtoPagedResultResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceDtoPagedResultResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceDtoPagedResultResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceDtoPagedResultResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceDtoPagedResultResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceDtoPagedResultResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceDtoPagedResultResponse" + } + } + } + } + } + }, + "post": { + "tags": [ + "Resources" + ], + "operationId": "CreateResource", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateResourceRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + } + } + } + }, + "/api/admin/resources/{id}": { + "get": { + "tags": [ + "Resources" + ], + "operationId": "GetResourceById", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceDtoResponse" + } + } + } + } + } + }, + "put": { + "tags": [ + "Resources" + ], + "operationId": "UpdateResource", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateResourceRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceDtoResponse" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Resources" + ], + "operationId": "DeleteResource", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + } + } + } + }, + "/api/admin/resources/{id}/publish": { + "post": { + "tags": [ + "Resources" + ], + "operationId": "PublishResource", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + } + } + } + }, + "/api/state/profile": { + "get": { + "tags": [ + "StateRepresentative" + ], + "operationId": "GetMyCountryProfile", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryProfileDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryProfileDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryProfileDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryProfileDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryProfileDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryProfileDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryProfileDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryProfileDtoResponse" + } + } + } + } + } + } + }, + "/api/state/profile/{countryId}": { + "put": { + "tags": [ + "StateRepresentative" + ], + "operationId": "UpdateMyCountryProfile", + "parameters": [ + { + "name": "countryId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpsertCountryProfileRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryProfileDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryProfileDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryProfileDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryProfileDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryProfileDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryProfileDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryProfileDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryProfileDtoResponse" + } + } + } + } + } + } + }, + "/api/state/requests": { + "get": { + "tags": [ + "StateRepresentative" + ], + "operationId": "ListMyCountryContentRequests", + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "pageSize", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "status", + "in": "query", + "schema": { + "$ref": "#/components/schemas/CountryContentRequestStatus" + } + }, + { + "name": "type", + "in": "query", + "schema": { + "$ref": "#/components/schemas/ContentType" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoPagedResultResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoPagedResultResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoPagedResultResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoPagedResultResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoPagedResultResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoPagedResultResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoPagedResultResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoPagedResultResponse" + } + } + } + } + } + }, + "post": { + "tags": [ + "StateRepresentative" + ], + "operationId": "SubmitCountryContentRequest", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubmitContentRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuidResponse" + } + } + } + } + } + } + }, + "/api/state/requests/{id}": { + "get": { + "tags": [ + "StateRepresentative" + ], + "operationId": "GetMyCountryContentRequest", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CountryContentRequestDtoResponse" + } + } + } + } + } + } + }, + "/api/admin/tags": { + "get": { + "tags": [ + "Tags" + ], + "operationId": "ListTags", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDtoListResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDtoListResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDtoListResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDtoListResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDtoListResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDtoListResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDtoListResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDtoListResponse" + } + } + } + } + } + }, + "post": { + "tags": [ + "Tags" + ], + "operationId": "CreateTag", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateTagRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDtoResponse" + } + } + } + } + } + } + }, + "/api/admin/tags/{id}": { + "get": { + "tags": [ + "Tags" + ], + "operationId": "GetTagById", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDtoResponse" + } + } + } + } + } + }, + "put": { + "tags": [ + "Tags" + ], + "operationId": "UpdateTag", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateTagRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDtoResponse" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Tags" + ], + "operationId": "DeleteTag", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + } + } + } + }, + "/api/admin/topics": { + "get": { + "tags": [ + "Topics" + ], + "operationId": "ListTopics", + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "pageSize", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "parentId", + "in": "query", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "isActive", + "in": "query", + "schema": { + "type": "boolean" + } + }, + { + "name": "search", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TopicDtoPagedResultResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TopicDtoPagedResultResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TopicDtoPagedResultResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TopicDtoPagedResultResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TopicDtoPagedResultResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TopicDtoPagedResultResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TopicDtoPagedResultResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TopicDtoPagedResultResponse" + } + } + } + } + } + }, + "post": { + "tags": [ + "Topics" + ], + "operationId": "CreateTopic", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateTopicRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TopicDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TopicDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TopicDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TopicDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TopicDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TopicDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TopicDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TopicDtoResponse" + } + } + } + } + } + } + }, + "/api/admin/topics/{id}": { + "get": { + "tags": [ + "Topics" + ], + "operationId": "GetTopicById", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TopicDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TopicDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TopicDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TopicDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TopicDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TopicDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TopicDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TopicDtoResponse" + } + } + } + } + } + }, + "put": { + "tags": [ + "Topics" + ], + "operationId": "UpdateTopic", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateTopicRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TopicDtoResponse" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TopicDtoResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TopicDtoResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TopicDtoResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TopicDtoResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TopicDtoResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TopicDtoResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TopicDtoResponse" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Topics" + ], + "operationId": "DeleteTopic", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "409": { + "description": "Conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidDataResponse" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "AboutSettingsDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "description": { + "$ref": "#/components/schemas/LocalizedTextDto" + }, + "howToUseVideoUrl": { + "type": "string", + "nullable": true + }, + "glossaryEntries": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GlossaryEntryDto" + }, + "nullable": true + }, + "knowledgePartners": { + "type": "array", + "items": { + "$ref": "#/components/schemas/KnowledgePartnerDto" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "AboutSettingsDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", "nullable": true, - "type": "string" + "readOnly": true }, - "slug": { + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/AboutSettingsDto" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, "nullable": true, - "type": "string" + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } }, - "type": "object" + "additionalProperties": false }, - "ExpertRegistrationStatus": { - "enum": [ - 0, - 1, - 2 - ], - "format": "int32", - "type": "integer" + "AdLoginRequest": { + "type": "object", + "properties": { + "username": { + "type": "string", + "nullable": true + }, + "password": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false }, - "HomepageSectionType": { - "enum": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 99 - ], - "format": "int32", - "type": "integer" + "ApproveCountryResourceRequestRequest": { + "type": "object", + "properties": { + "adminNotesAr": { + "type": "string", + "nullable": true + }, + "adminNotesEn": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false }, - "NotificationChannel": { + "ApproveExpertRequestRequest": { + "type": "object", + "properties": { + "academicTitleAr": { + "type": "string", + "nullable": true + }, + "academicTitleEn": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "AssetFileDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "url": { + "type": "string", + "nullable": true + }, + "originalFileName": { + "type": "string", + "nullable": true + }, + "sizeBytes": { + "type": "integer", + "format": "int64" + }, + "mimeType": { + "type": "string", + "nullable": true + }, + "uploadedById": { + "type": "string", + "format": "uuid" + }, + "uploadedOn": { + "type": "string", + "format": "date-time" + }, + "virusScanStatus": { + "$ref": "#/components/schemas/VirusScanStatus" + }, + "scannedOn": { + "type": "string", + "format": "date-time", + "nullable": true + } + }, + "additionalProperties": false + }, + "AssetFileDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/AssetFileDto" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" + } + }, + "additionalProperties": false + }, + "AssignUserRolesRequest": { + "type": "object", + "properties": { + "roles": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "AuthMessageDto": { + "type": "object", + "properties": { + "code": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "AuthMessageDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/AuthMessageDto" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" + } + }, + "additionalProperties": false + }, + "AuthTokenDto": { + "type": "object", + "properties": { + "accessToken": { + "type": "string", + "nullable": true + }, + "accessTokenExpiresAtUtc": { + "type": "string", + "format": "date-time" + }, + "refreshToken": { + "type": "string", + "nullable": true + }, + "refreshTokenExpiresAtUtc": { + "type": "string", + "format": "date-time" + }, + "tokenType": { + "type": "string", + "nullable": true + }, + "user": { + "$ref": "#/components/schemas/AuthUserDto" + } + }, + "additionalProperties": false + }, + "AuthTokenDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/AuthTokenDto" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" + } + }, + "additionalProperties": false + }, + "AuthUserDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "emailAddress": { + "type": "string", + "nullable": true + }, + "firstName": { + "type": "string", + "nullable": true + }, + "lastName": { + "type": "string", + "nullable": true + }, + "roles": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "AuthUserDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/AuthUserDto" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" + } + }, + "additionalProperties": false + }, + "ChangeCommunityVisibilityRequest": { + "type": "object", + "properties": { + "visibility": { + "$ref": "#/components/schemas/CommunityVisibility" + } + }, + "additionalProperties": false + }, + "ChangeUserStatusRequest": { + "type": "object", + "properties": { + "isActive": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "CommunityVisibility": { "enum": [ 0, - 1, - 2 + 1 ], - "format": "int32", - "type": "integer" + "type": "integer", + "format": "int32" }, - "PageType": { + "ContentType": { "enum": [ 0, 1, - 2, - 99 + 2 ], - "format": "int32", - "type": "integer" + "type": "integer", + "format": "int32" }, - "RejectCountryResourceRequestRequest": { - "additionalProperties": false, + "CountryContentRequestDto": { + "type": "object", "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "countryId": { + "type": "string", + "format": "uuid" + }, + "requestedById": { + "type": "string", + "format": "uuid" + }, + "type": { + "$ref": "#/components/schemas/ContentType" + }, + "status": { + "$ref": "#/components/schemas/CountryContentRequestStatus" + }, + "proposedTitleAr": { + "type": "string", + "nullable": true + }, + "proposedTitleEn": { + "type": "string", + "nullable": true + }, + "proposedDescriptionAr": { + "type": "string", + "nullable": true + }, + "proposedDescriptionEn": { + "type": "string", + "nullable": true + }, + "proposedResourceType": { + "$ref": "#/components/schemas/ResourceType" + }, + "proposedAssetFileId": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "proposedTopicId": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "proposedStartsOn": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "proposedEndsOn": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "proposedLocationAr": { + "type": "string", + "nullable": true + }, + "proposedLocationEn": { + "type": "string", + "nullable": true + }, + "proposedOnlineMeetingUrl": { + "type": "string", + "nullable": true + }, + "submittedOn": { + "type": "string", + "format": "date-time" + }, "adminNotesAr": { - "nullable": true, - "type": "string" + "type": "string", + "nullable": true }, "adminNotesEn": { - "nullable": true, - "type": "string" - } - }, - "type": "object" - }, - "RejectExpertRequestRequest": { - "additionalProperties": false, - "properties": { - "rejectionReasonAr": { - "nullable": true, - "type": "string" + "type": "string", + "nullable": true }, - "rejectionReasonEn": { - "nullable": true, - "type": "string" + "processedById": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "processedOn": { + "type": "string", + "format": "date-time", + "nullable": true } }, - "type": "object" + "additionalProperties": false }, - "ReorderHomepageSectionAssignmentRequest": { - "additionalProperties": false, + "CountryContentRequestDtoPagedResult": { + "type": "object", "properties": { - "id": { - "format": "uuid", - "type": "string" + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CountryContentRequestDto" + }, + "nullable": true }, - "orderIndex": { - "format": "int32", - "type": "integer" + "page": { + "type": "integer", + "format": "int32" + }, + "pageSize": { + "type": "integer", + "format": "int32" + }, + "total": { + "type": "integer", + "format": "int64" } }, - "type": "object" + "additionalProperties": false }, - "ReorderHomepageSectionsRequest": { - "additionalProperties": false, + "CountryContentRequestDtoPagedResultResponse": { + "type": "object", "properties": { - "assignments": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/CountryContentRequestDtoPagedResult" + }, + "errors": { + "type": "array", "items": { - "$ref": "#/components/schemas/ReorderHomepageSectionAssignmentRequest" + "$ref": "#/components/schemas/FieldError" }, "nullable": true, - "type": "array" + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } }, - "type": "object" + "additionalProperties": false }, - "RescheduleEventRequest": { - "additionalProperties": false, + "CountryContentRequestDtoResponse": { + "type": "object", "properties": { - "endsOn": { - "format": "date-time", - "type": "string" + "success": { + "type": "boolean", + "readOnly": true }, - "rowVersion": { + "code": { + "type": "string", "nullable": true, - "type": "string" + "readOnly": true }, - "startsOn": { - "format": "date-time", - "type": "string" + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/CountryContentRequestDto" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } }, - "type": "object" + "additionalProperties": false }, - "ResourceType": { + "CountryContentRequestStatus": { "enum": [ 0, 1, - 2, - 3, - 4 + 2 ], - "format": "int32", - "type": "integer" + "type": "integer", + "format": "int32" }, - "UpdateCountryRequest": { - "additionalProperties": false, + "CountryProfileDto": { + "type": "object", "properties": { - "isActive": { - "type": "boolean" + "id": { + "type": "string", + "format": "uuid" }, - "nameAr": { - "nullable": true, - "type": "string" + "countryId": { + "type": "string", + "format": "uuid" }, - "nameEn": { + "descriptionAr": { + "type": "string", + "nullable": true + }, + "descriptionEn": { + "type": "string", + "nullable": true + }, + "keyInitiativesAr": { + "type": "string", + "nullable": true + }, + "keyInitiativesEn": { + "type": "string", + "nullable": true + }, + "contactInfoAr": { + "type": "string", + "nullable": true + }, + "contactInfoEn": { + "type": "string", + "nullable": true + }, + "population": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "areaSqKm": { + "type": "number", + "format": "double", + "nullable": true + }, + "gdpPerCapita": { + "type": "number", + "format": "double", + "nullable": true + }, + "ndcAssetId": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "cceClassification": { + "type": "string", + "nullable": true + }, + "ccePerformanceScore": { + "type": "number", + "format": "double", + "nullable": true + }, + "cceTotalIndex": { + "type": "number", + "format": "double", + "nullable": true + }, + "cceSnapshotTakenOn": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "lastUpdatedById": { + "type": "string", + "format": "uuid" + }, + "lastUpdatedOn": { + "type": "string", + "format": "date-time" + } + }, + "additionalProperties": false + }, + "CountryProfileDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", "nullable": true, - "type": "string" + "readOnly": true }, - "regionAr": { + "message": { + "type": "string", "nullable": true, - "type": "string" + "readOnly": true }, - "regionEn": { + "data": { + "$ref": "#/components/schemas/CountryProfileDto" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, "nullable": true, - "type": "string" + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } }, - "type": "object" + "additionalProperties": false }, - "UpdateEventRequest": { - "additionalProperties": false, + "CreateCommunityRequest": { + "type": "object", "properties": { + "nameAr": { + "type": "string", + "nullable": true + }, + "nameEn": { + "type": "string", + "nullable": true + }, "descriptionAr": { - "nullable": true, - "type": "string" + "type": "string", + "nullable": true }, "descriptionEn": { - "nullable": true, - "type": "string" + "type": "string", + "nullable": true }, - "featuredImageUrl": { - "nullable": true, - "type": "string" + "slug": { + "type": "string", + "nullable": true + }, + "visibility": { + "$ref": "#/components/schemas/CommunityVisibility" + }, + "presentationJson": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "CreateEventRequest": { + "type": "object", + "properties": { + "titleAr": { + "type": "string", + "nullable": true + }, + "titleEn": { + "type": "string", + "nullable": true + }, + "descriptionAr": { + "type": "string", + "nullable": true + }, + "descriptionEn": { + "type": "string", + "nullable": true + }, + "startsOn": { + "type": "string", + "format": "date-time" + }, + "endsOn": { + "type": "string", + "format": "date-time" }, "locationAr": { - "nullable": true, - "type": "string" + "type": "string", + "nullable": true }, "locationEn": { - "nullable": true, - "type": "string" + "type": "string", + "nullable": true }, "onlineMeetingUrl": { - "nullable": true, - "type": "string" + "type": "string", + "nullable": true }, - "rowVersion": { - "nullable": true, - "type": "string" + "featuredImageUrl": { + "type": "string", + "nullable": true }, - "titleAr": { - "nullable": true, - "type": "string" + "topicId": { + "type": "string", + "format": "uuid" }, - "titleEn": { - "nullable": true, - "type": "string" + "tagIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "nullable": true } }, - "type": "object" + "additionalProperties": false }, - "UpdateHomepageSectionRequest": { - "additionalProperties": false, + "CreateGlossaryEntryRequest": { + "type": "object", "properties": { - "contentAr": { - "nullable": true, - "type": "string" + "termAr": { + "type": "string", + "nullable": true }, - "contentEn": { - "nullable": true, - "type": "string" + "termEn": { + "type": "string", + "nullable": true }, - "isActive": { - "type": "boolean" + "definitionAr": { + "type": "string", + "nullable": true + }, + "definitionEn": { + "type": "string", + "nullable": true } }, - "type": "object" + "additionalProperties": false }, - "UpdateNewsRequest": { - "additionalProperties": false, + "CreateHomepageSectionRequest": { + "type": "object", "properties": { + "sectionType": { + "$ref": "#/components/schemas/HomepageSectionType" + }, + "orderIndex": { + "type": "integer", + "format": "int32" + }, "contentAr": { - "nullable": true, - "type": "string" + "type": "string", + "nullable": true }, "contentEn": { - "nullable": true, - "type": "string" + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "CreateKnowledgePartnerRequest": { + "type": "object", + "properties": { + "nameAr": { + "type": "string", + "nullable": true }, - "featuredImageUrl": { - "nullable": true, - "type": "string" + "nameEn": { + "type": "string", + "nullable": true }, - "rowVersion": { - "nullable": true, - "type": "string" + "logoUrl": { + "type": "string", + "nullable": true }, - "slug": { - "nullable": true, - "type": "string" + "websiteUrl": { + "type": "string", + "nullable": true + }, + "descriptionAr": { + "type": "string", + "nullable": true }, + "descriptionEn": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "CreateNewsRequest": { + "type": "object", + "properties": { "titleAr": { - "nullable": true, - "type": "string" + "type": "string", + "nullable": true }, "titleEn": { - "nullable": true, - "type": "string" + "type": "string", + "nullable": true + }, + "contentAr": { + "type": "string", + "nullable": true + }, + "contentEn": { + "type": "string", + "nullable": true + }, + "topicId": { + "type": "string", + "format": "uuid" + }, + "featuredImageUrl": { + "type": "string", + "nullable": true + }, + "tagIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "nullable": true } }, - "type": "object" + "additionalProperties": false }, - "UpdateNotificationTemplateRequest": { - "additionalProperties": false, + "CreateNotificationTemplateRequest": { + "type": "object", "properties": { + "code": { + "type": "string", + "nullable": true + }, + "subjectAr": { + "type": "string", + "nullable": true + }, + "subjectEn": { + "type": "string", + "nullable": true + }, "bodyAr": { - "nullable": true, - "type": "string" + "type": "string", + "nullable": true }, "bodyEn": { - "nullable": true, - "type": "string" - }, - "isActive": { - "type": "boolean" + "type": "string", + "nullable": true }, - "subjectAr": { - "nullable": true, - "type": "string" + "channel": { + "$ref": "#/components/schemas/NotificationChannel" }, - "subjectEn": { - "nullable": true, - "type": "string" + "variableSchemaJson": { + "type": "string", + "nullable": true } }, - "type": "object" + "additionalProperties": false }, - "UpdatePageRequest": { - "additionalProperties": false, + "CreatePageRequest": { + "type": "object", "properties": { + "slug": { + "type": "string", + "nullable": true + }, + "pageType": { + "$ref": "#/components/schemas/PageType" + }, + "titleAr": { + "type": "string", + "nullable": true + }, + "titleEn": { + "type": "string", + "nullable": true + }, "contentAr": { - "nullable": true, - "type": "string" + "type": "string", + "nullable": true }, "contentEn": { - "nullable": true, - "type": "string" - }, - "rowVersion": { - "nullable": true, - "type": "string" + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "CreatePolicySectionRequest": { + "type": "object", + "properties": { + "type": { + "type": "integer", + "format": "int32" }, "titleAr": { - "nullable": true, - "type": "string" + "type": "string", + "nullable": true }, "titleEn": { - "nullable": true, - "type": "string" + "type": "string", + "nullable": true + }, + "contentAr": { + "type": "string", + "nullable": true + }, + "contentEn": { + "type": "string", + "nullable": true } }, - "type": "object" + "additionalProperties": false }, - "UpdateResourceCategoryRequest": { - "additionalProperties": false, + "CreateResourceCategoryRequest": { + "type": "object", "properties": { - "isActive": { - "type": "boolean" - }, "nameAr": { - "nullable": true, - "type": "string" + "type": "string", + "nullable": true + }, + "nameEn": { + "type": "string", + "nullable": true + }, + "slug": { + "type": "string", + "nullable": true }, - "nameEn": { - "nullable": true, - "type": "string" + "parentId": { + "type": "string", + "format": "uuid", + "nullable": true }, "orderIndex": { - "format": "int32", - "type": "integer" + "type": "integer", + "format": "int32" } }, - "type": "object" + "additionalProperties": false }, - "UpdateResourceRequest": { - "additionalProperties": false, + "CreateResourceRequest": { + "type": "object", "properties": { - "categoryId": { - "format": "uuid", - "type": "string" + "titleAr": { + "type": "string", + "nullable": true + }, + "titleEn": { + "type": "string", + "nullable": true }, "descriptionAr": { - "nullable": true, - "type": "string" + "type": "string", + "nullable": true }, "descriptionEn": { - "nullable": true, - "type": "string" + "type": "string", + "nullable": true }, "resourceType": { "$ref": "#/components/schemas/ResourceType" }, - "rowVersion": { - "nullable": true, - "type": "string" + "categoryId": { + "type": "string", + "format": "uuid" }, - "titleAr": { - "nullable": true, - "type": "string" + "countryId": { + "type": "string", + "format": "uuid", + "nullable": true }, - "titleEn": { - "nullable": true, - "type": "string" + "assetFileId": { + "type": "string", + "format": "uuid" + }, + "countryIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "nullable": true } }, - "type": "object" + "additionalProperties": false }, - "UpdateTopicRequest": { - "additionalProperties": false, + "CreateStateRepAssignmentRequest": { + "type": "object", "properties": { - "descriptionAr": { - "nullable": true, - "type": "string" - }, - "descriptionEn": { - "nullable": true, - "type": "string" - }, - "isActive": { - "type": "boolean" + "userId": { + "type": "string", + "format": "uuid" }, + "countryId": { + "type": "string", + "format": "uuid" + } + }, + "additionalProperties": false + }, + "CreateTagRequest": { + "type": "object", + "properties": { "nameAr": { - "nullable": true, - "type": "string" + "type": "string", + "nullable": true }, "nameEn": { - "nullable": true, - "type": "string" + "type": "string", + "nullable": true }, - "orderIndex": { - "format": "int32", - "type": "integer" + "color": { + "type": "string", + "nullable": true } }, - "type": "object" + "additionalProperties": false }, - "UpsertCountryProfileRequest": { - "additionalProperties": false, + "CreateTopicRequest": { + "type": "object", "properties": { - "contactInfoAr": { - "nullable": true, - "type": "string" + "nameAr": { + "type": "string", + "nullable": true }, - "contactInfoEn": { - "nullable": true, - "type": "string" + "nameEn": { + "type": "string", + "nullable": true }, "descriptionAr": { - "nullable": true, - "type": "string" + "type": "string", + "nullable": true }, "descriptionEn": { - "nullable": true, - "type": "string" + "type": "string", + "nullable": true }, - "keyInitiativesAr": { - "nullable": true, - "type": "string" + "slug": { + "type": "string", + "nullable": true }, - "keyInitiativesEn": { - "nullable": true, - "type": "string" + "parentId": { + "type": "string", + "format": "uuid", + "nullable": true }, - "rowVersion": { - "nullable": true, - "type": "string" - } - }, - "type": "object" - } - } - }, - "info": { - "description": "CCE Knowledge Center — CCE Internal API", - "title": "CCE Internal API", - "version": "v1" - }, - "openapi": "3.0.1", - "paths": { - "/": { - "get": { - "responses": { - "200": { - "content": { - "text/plain": { - "schema": { - "type": "string" - } - } - }, - "description": "OK" + "iconUrl": { + "type": "string", + "nullable": true + }, + "orderIndex": { + "type": "integer", + "format": "int32" } }, - "tags": [ - "CCE.Api.Internal" - ] - } - }, - "/api/admin/assets": { - "post": { - "operationId": "UploadAsset", - "responses": { - "200": { - "description": "OK" + "additionalProperties": false + }, + "CreateUserRequest": { + "type": "object", + "properties": { + "firstName": { + "type": "string", + "nullable": true + }, + "lastName": { + "type": "string", + "nullable": true + }, + "email": { + "type": "string", + "nullable": true + }, + "phoneNumber": { + "type": "string", + "nullable": true + }, + "countryId": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "countryCodeId": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "role": { + "type": "string", + "nullable": true } }, - "tags": [ - "Assets" - ] - } - }, - "/api/admin/assets/{id}": { - "get": { - "operationId": "GetAssetById", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } + "additionalProperties": false + }, + "EvaluationRating": { + "enum": [ + 0, + 1, + 2, + 3, + 4, + 5 ], - "responses": { - "200": { - "description": "OK" - } - }, - "tags": [ - "Assets" - ] - } - }, - "/api/admin/audit-events": { - "get": { - "operationId": "ListAuditEvents", - "parameters": [ - { - "in": "query", - "name": "page", - "schema": { - "format": "int32", - "type": "integer" - } + "type": "integer", + "format": "int32" + }, + "EventDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" }, - { - "in": "query", - "name": "pageSize", - "schema": { - "format": "int32", - "type": "integer" - } + "titleAr": { + "type": "string", + "nullable": true }, - { - "in": "query", - "name": "actor", - "schema": { - "type": "string" - } + "titleEn": { + "type": "string", + "nullable": true }, - { - "in": "query", - "name": "actionPrefix", - "schema": { - "type": "string" - } + "descriptionAr": { + "type": "string", + "nullable": true }, - { - "in": "query", - "name": "resourceType", - "schema": { - "type": "string" - } + "descriptionEn": { + "type": "string", + "nullable": true }, - { - "in": "query", - "name": "correlationId", - "schema": { - "format": "uuid", - "type": "string" - } + "startsOn": { + "type": "string", + "format": "date-time" }, - { - "in": "query", - "name": "from", - "schema": { - "format": "date-time", - "type": "string" - } + "endsOn": { + "type": "string", + "format": "date-time" }, - { - "in": "query", - "name": "to", - "schema": { - "format": "date-time", - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK" - } - }, - "tags": [ - "Audit" - ] - } - }, - "/api/admin/community/posts/{id}": { - "delete": { - "operationId": "SoftDeletePost", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK" - } - }, - "tags": [ - "CommunityModeration" - ] - } - }, - "/api/admin/community/replies/{id}": { - "delete": { - "operationId": "SoftDeleteReply", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK" + "locationAr": { + "type": "string", + "nullable": true + }, + "locationEn": { + "type": "string", + "nullable": true + }, + "onlineMeetingUrl": { + "type": "string", + "nullable": true + }, + "featuredImageUrl": { + "type": "string", + "nullable": true + }, + "iCalUid": { + "type": "string", + "nullable": true + }, + "topicId": { + "type": "string", + "format": "uuid" + }, + "topicNameAr": { + "type": "string", + "nullable": true + }, + "topicNameEn": { + "type": "string", + "nullable": true + }, + "tags": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TagDto" + }, + "nullable": true } }, - "tags": [ - "CommunityModeration" - ] - } - }, - "/api/admin/countries": { - "get": { - "operationId": "ListCountries", - "parameters": [ - { - "in": "query", - "name": "page", - "schema": { - "format": "int32", - "type": "integer" - } + "additionalProperties": false + }, + "EventDtoPagedResult": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EventDto" + }, + "nullable": true }, - { - "in": "query", - "name": "pageSize", - "schema": { - "format": "int32", - "type": "integer" - } + "page": { + "type": "integer", + "format": "int32" }, - { - "in": "query", - "name": "search", - "schema": { - "type": "string" - } + "pageSize": { + "type": "integer", + "format": "int32" }, - { - "in": "query", - "name": "isActive", - "schema": { - "type": "boolean" - } - } - ], - "responses": { - "200": { - "description": "OK" + "total": { + "type": "integer", + "format": "int64" } }, - "tags": [ - "Countries" - ] - } - }, - "/api/admin/countries/{countryId}/profile": { - "get": { - "operationId": "GetCountryProfile", - "parameters": [ - { - "in": "path", - "name": "countryId", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK" + "additionalProperties": false + }, + "EventDtoPagedResultResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/EventDtoPagedResult" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } }, - "tags": [ - "Countries" - ] + "additionalProperties": false }, - "put": { - "operationId": "UpsertCountryProfile", - "parameters": [ - { - "in": "path", - "name": "countryId", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpsertCountryProfileRequest" - } - } + "EventDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true }, - "required": true - }, - "responses": { - "200": { - "description": "OK" + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/EventDto" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } }, - "tags": [ - "Countries" - ] - } - }, - "/api/admin/countries/{id}": { - "get": { - "operationId": "GetCountryById", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", + "additionalProperties": false + }, + "ExpertProfileDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "userId": { + "type": "string", + "format": "uuid" + }, + "userName": { + "type": "string", + "nullable": true + }, + "bioAr": { + "type": "string", + "nullable": true + }, + "bioEn": { + "type": "string", + "nullable": true + }, + "expertiseTags": { + "type": "array", + "items": { "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK" + }, + "nullable": true + }, + "academicTitleAr": { + "type": "string", + "nullable": true + }, + "academicTitleEn": { + "type": "string", + "nullable": true + }, + "approvedOn": { + "type": "string", + "format": "date-time" + }, + "approvedById": { + "type": "string", + "format": "uuid" } }, - "tags": [ - "Countries" - ] + "additionalProperties": false }, - "put": { - "operationId": "UpdateCountry", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateCountryRequest" - } - } + "ExpertProfileDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true }, - "required": true - }, - "responses": { - "200": { - "description": "OK" + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/ExpertProfileDto" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } }, - "tags": [ - "Countries" - ] - } - }, - "/api/admin/country-resource-requests/{id}/approve": { - "post": { - "operationId": "ApproveCountryResourceRequest", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", + "additionalProperties": false + }, + "ExpertRegistrationStatus": { + "enum": [ + 0, + 1, + 2 + ], + "type": "integer", + "format": "int32" + }, + "ExpertRequestDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "requestedById": { + "type": "string", + "format": "uuid" + }, + "requestedByUserName": { + "type": "string", + "nullable": true + }, + "requestedBioAr": { + "type": "string", + "nullable": true + }, + "requestedBioEn": { + "type": "string", + "nullable": true + }, + "requestedTags": { + "type": "array", + "items": { "type": "string" - } + }, + "nullable": true + }, + "submittedOn": { + "type": "string", + "format": "date-time" + }, + "status": { + "$ref": "#/components/schemas/ExpertRegistrationStatus" + }, + "processedById": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "processedOn": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "rejectionReasonAr": { + "type": "string", + "nullable": true + }, + "rejectionReasonEn": { + "type": "string", + "nullable": true } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApproveCountryResourceRequestRequest" - } - } + }, + "additionalProperties": false + }, + "ExpertRequestDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/ExpertRequestDto" }, - "required": true + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" + } }, - "responses": { - "200": { - "description": "OK" + "additionalProperties": false + }, + "FieldError": { + "type": "object", + "properties": { + "field": { + "type": "string", + "nullable": true + }, + "code": { + "type": "string", + "nullable": true + }, + "message": { + "type": "string", + "nullable": true } }, - "tags": [ - "CountryResourceRequests" - ] - } - }, - "/api/admin/country-resource-requests/{id}/reject": { - "post": { - "operationId": "RejectCountryResourceRequest", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } + "additionalProperties": false + }, + "ForgotPasswordRequest": { + "type": "object", + "properties": { + "emailAddress": { + "type": "string", + "nullable": true } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RejectCountryResourceRequestRequest" - } - } - }, - "required": true }, - "responses": { - "200": { - "description": "OK" + "additionalProperties": false + }, + "GlossaryEntryDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "term": { + "$ref": "#/components/schemas/LocalizedTextDto" + }, + "definition": { + "$ref": "#/components/schemas/LocalizedTextDto" + }, + "orderIndex": { + "type": "integer", + "format": "int32" } }, - "tags": [ - "CountryResourceRequests" - ] - } - }, - "/api/admin/events": { - "get": { - "operationId": "ListEvents", - "parameters": [ - { - "in": "query", - "name": "page", - "schema": { - "format": "int32", - "type": "integer" - } + "additionalProperties": false + }, + "GuidResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true }, - { - "in": "query", - "name": "pageSize", - "schema": { - "format": "int32", - "type": "integer" - } + "code": { + "type": "string", + "nullable": true, + "readOnly": true }, - { - "in": "query", - "name": "search", - "schema": { - "type": "string" - } + "message": { + "type": "string", + "nullable": true, + "readOnly": true }, - { - "in": "query", - "name": "fromDate", - "schema": { - "format": "date-time", - "type": "string" - } + "data": { + "type": "string", + "format": "uuid", + "readOnly": true }, - { - "in": "query", - "name": "toDate", - "schema": { - "format": "date-time", - "type": "string" - } + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } - ], - "responses": { - "200": { - "description": "OK" + }, + "additionalProperties": false + }, + "HomepageCountryDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "countryId": { + "type": "string", + "format": "uuid" + }, + "orderIndex": { + "type": "integer", + "format": "int32" } }, - "tags": [ - "Events" - ] + "additionalProperties": false }, - "post": { - "operationId": "CreateEvent", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateEventRequest" - } - } + "HomepageSectionType": { + "enum": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 99 + ], + "type": "integer", + "format": "int32" + }, + "HomepageSettingsDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" }, - "required": true + "videoUrl": { + "type": "string", + "nullable": true + }, + "objective": { + "$ref": "#/components/schemas/LocalizedTextDto" + }, + "cceConceptsAr": { + "type": "string", + "nullable": true + }, + "cceConceptsEn": { + "type": "string", + "nullable": true + }, + "participatingCountries": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HomepageCountryDto" + }, + "nullable": true + } }, - "responses": { - "200": { - "description": "OK" + "additionalProperties": false + }, + "HomepageSettingsDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/HomepageSettingsDto" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } }, - "tags": [ - "Events" - ] - } - }, - "/api/admin/events/{id}": { - "delete": { - "operationId": "DeleteEvent", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } + "additionalProperties": false + }, + "JoinRequestDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "communityId": { + "type": "string", + "format": "uuid" + }, + "userId": { + "type": "string", + "format": "uuid" + }, + "status": { + "$ref": "#/components/schemas/JoinRequestStatus" + }, + "requestedOn": { + "type": "string", + "format": "date-time" + }, + "decidedOn": { + "type": "string", + "format": "date-time", + "nullable": true } - ], - "responses": { - "200": { - "description": "OK" + }, + "additionalProperties": false + }, + "JoinRequestDtoPagedResult": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/JoinRequestDto" + }, + "nullable": true + }, + "page": { + "type": "integer", + "format": "int32" + }, + "pageSize": { + "type": "integer", + "format": "int32" + }, + "total": { + "type": "integer", + "format": "int64" } }, - "tags": [ - "Events" - ] + "additionalProperties": false }, - "get": { - "operationId": "GetEventById", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } + "JoinRequestDtoPagedResultResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/JoinRequestDtoPagedResult" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } + }, + "additionalProperties": false + }, + "JoinRequestStatus": { + "enum": [ + 0, + 1, + 2 ], - "responses": { - "200": { - "description": "OK" + "type": "integer", + "format": "int32" + }, + "KapsarcSnapshotDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "countryId": { + "type": "string", + "format": "uuid" + }, + "classification": { + "type": "string", + "nullable": true + }, + "performanceScore": { + "type": "number", + "format": "double" + }, + "totalIndex": { + "type": "number", + "format": "double" + }, + "snapshotTakenOn": { + "type": "string", + "format": "date-time" + }, + "sourceVersion": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "KapsarcSnapshotDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/KapsarcSnapshotDto" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } }, - "tags": [ - "Events" - ] + "additionalProperties": false }, - "put": { - "operationId": "UpdateEvent", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } + "KnowledgeLevel": { + "enum": [ + 0, + 1, + 2 ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateEventRequest" - } - } + "type": "integer", + "format": "int32" + }, + "KnowledgePartnerDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" }, - "required": true - }, - "responses": { - "200": { - "description": "OK" + "name": { + "$ref": "#/components/schemas/LocalizedTextDto" + }, + "logoUrl": { + "type": "string", + "nullable": true + }, + "websiteUrl": { + "type": "string", + "nullable": true + }, + "description": { + "$ref": "#/components/schemas/LocalizedTextDto" + }, + "orderIndex": { + "type": "integer", + "format": "int32" } }, - "tags": [ - "Events" - ] - } - }, - "/api/admin/events/{id}/reschedule": { - "post": { - "operationId": "RescheduleEvent", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } + "additionalProperties": false + }, + "LocalizedTextDto": { + "type": "object", + "properties": { + "ar": { + "type": "string", + "nullable": true + }, + "en": { + "type": "string", + "nullable": true } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RescheduleEventRequest" - } - } + }, + "additionalProperties": false + }, + "LoginRequest": { + "type": "object", + "properties": { + "emailAddress": { + "type": "string", + "nullable": true }, - "required": true + "password": { + "type": "string", + "nullable": true + } }, - "responses": { - "200": { - "description": "OK" + "additionalProperties": false + }, + "LogoutRequest": { + "type": "object", + "properties": { + "refreshToken": { + "type": "string", + "nullable": true } }, - "tags": [ - "Events" - ] - } - }, - "/api/admin/expert-profiles": { - "get": { - "operationId": "ListExpertProfiles", - "parameters": [ - { - "in": "query", - "name": "page", - "schema": { - "format": "int32", - "type": "integer" - } + "additionalProperties": false + }, + "MediaFileBriefDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" }, - { - "in": "query", - "name": "pageSize", - "schema": { - "format": "int32", - "type": "integer" - } + "storageKey": { + "type": "string", + "nullable": true }, - { - "in": "query", - "name": "search", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK" + "url": { + "type": "string", + "nullable": true } }, - "tags": [ - "Experts" - ] - } - }, - "/api/admin/expert-requests": { - "get": { - "operationId": "ListExpertRequests", - "parameters": [ - { - "in": "query", - "name": "page", - "schema": { - "format": "int32", - "type": "integer" - } + "additionalProperties": false + }, + "MediaFileBriefDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true }, - { - "in": "query", - "name": "pageSize", - "schema": { - "format": "int32", - "type": "integer" - } + "code": { + "type": "string", + "nullable": true, + "readOnly": true }, - { - "in": "query", - "name": "status", - "schema": { - "$ref": "#/components/schemas/ExpertRegistrationStatus" - } + "message": { + "type": "string", + "nullable": true, + "readOnly": true }, - { - "in": "query", - "name": "requestedById", - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK" + "data": { + "$ref": "#/components/schemas/MediaFileBriefDto" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } }, - "tags": [ - "Experts" - ] - } - }, - "/api/admin/expert-requests/{id}/approve": { - "post": { - "operationId": "ApproveExpertRequest", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApproveExpertRequestRequest" - } - } + "additionalProperties": false + }, + "MediaFileDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" }, - "required": true - }, - "responses": { - "200": { - "description": "OK" + "storageKey": { + "type": "string", + "nullable": true + }, + "url": { + "type": "string", + "nullable": true + }, + "originalFileName": { + "type": "string", + "nullable": true + }, + "mimeType": { + "type": "string", + "nullable": true + }, + "sizeBytes": { + "type": "integer", + "format": "int64" + }, + "titleAr": { + "type": "string", + "nullable": true + }, + "titleEn": { + "type": "string", + "nullable": true + }, + "descriptionAr": { + "type": "string", + "nullable": true + }, + "descriptionEn": { + "type": "string", + "nullable": true + }, + "altTextAr": { + "type": "string", + "nullable": true + }, + "altTextEn": { + "type": "string", + "nullable": true + }, + "uploadedById": { + "type": "string", + "format": "uuid" + }, + "uploadedOn": { + "type": "string", + "format": "date-time" } }, - "tags": [ - "Experts" - ] - } - }, - "/api/admin/expert-requests/{id}/reject": { - "post": { - "operationId": "RejectExpertRequest", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } + "additionalProperties": false + }, + "MediaFileDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/MediaFileDto" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RejectExpertRequestRequest" - } - } + }, + "additionalProperties": false + }, + "NewsDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "titleAr": { + "type": "string", + "nullable": true + }, + "titleEn": { + "type": "string", + "nullable": true + }, + "contentAr": { + "type": "string", + "nullable": true + }, + "contentEn": { + "type": "string", + "nullable": true + }, + "topicId": { + "type": "string", + "format": "uuid" + }, + "topicNameAr": { + "type": "string", + "nullable": true + }, + "topicNameEn": { + "type": "string", + "nullable": true + }, + "authorId": { + "type": "string", + "format": "uuid" + }, + "featuredImageUrl": { + "type": "string", + "nullable": true }, - "required": true - }, - "responses": { - "200": { - "description": "OK" + "publishedOn": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "isFeatured": { + "type": "boolean" + }, + "isPublished": { + "type": "boolean" + }, + "tags": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TagDto" + }, + "nullable": true } }, - "tags": [ - "Experts" - ] - } - }, - "/api/admin/homepage-sections": { - "get": { - "operationId": "ListHomepageSections", - "responses": { - "200": { - "description": "OK" + "additionalProperties": false + }, + "NewsDtoPagedResult": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NewsDto" + }, + "nullable": true + }, + "page": { + "type": "integer", + "format": "int32" + }, + "pageSize": { + "type": "integer", + "format": "int32" + }, + "total": { + "type": "integer", + "format": "int64" } }, - "tags": [ - "HomepageSections" - ] + "additionalProperties": false }, - "post": { - "operationId": "CreateHomepageSection", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateHomepageSectionRequest" - } - } + "NewsDtoPagedResultResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true }, - "required": true - }, - "responses": { - "200": { - "description": "OK" + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/NewsDtoPagedResult" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } }, - "tags": [ - "HomepageSections" - ] - } - }, - "/api/admin/homepage-sections/reorder": { - "post": { - "operationId": "ReorderHomepageSections", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ReorderHomepageSectionsRequest" - } - } + "additionalProperties": false + }, + "NewsDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true }, - "required": true - }, - "responses": { - "200": { - "description": "OK" + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/NewsDto" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } }, - "tags": [ - "HomepageSections" - ] - } - }, - "/api/admin/homepage-sections/{id}": { - "delete": { - "operationId": "DeleteHomepageSection", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } + "additionalProperties": false + }, + "NotificationChannel": { + "enum": [ + 0, + 1, + 2 ], - "responses": { - "200": { - "description": "OK" - } - }, - "tags": [ - "HomepageSections" - ] + "type": "integer", + "format": "int32" }, - "put": { - "operationId": "UpdateHomepageSection", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } + "NotificationDeliveryStatus": { + "enum": [ + 0, + 1, + 2, + 3 ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateHomepageSectionRequest" - } - } + "type": "integer", + "format": "int32" + }, + "NotificationLogDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" }, - "required": true - }, - "responses": { - "200": { - "description": "OK" - } - }, - "tags": [ - "HomepageSections" - ] - } - }, - "/api/admin/news": { - "get": { - "operationId": "ListNews", - "parameters": [ - { - "in": "query", - "name": "page", - "schema": { - "format": "int32", - "type": "integer" - } + "recipientUserId": { + "type": "string", + "format": "uuid", + "nullable": true }, - { - "in": "query", - "name": "pageSize", - "schema": { - "format": "int32", - "type": "integer" - } + "templateCode": { + "type": "string", + "nullable": true }, - { - "in": "query", - "name": "search", - "schema": { - "type": "string" - } + "templateId": { + "type": "string", + "format": "uuid", + "nullable": true }, - { - "in": "query", - "name": "isPublished", - "schema": { - "type": "boolean" - } + "channel": { + "$ref": "#/components/schemas/NotificationChannel" }, - { - "in": "query", - "name": "isFeatured", - "schema": { - "type": "boolean" - } - } - ], - "responses": { - "200": { - "description": "OK" + "status": { + "$ref": "#/components/schemas/NotificationDeliveryStatus" + }, + "providerMessageId": { + "type": "string", + "nullable": true + }, + "error": { + "type": "string", + "nullable": true + }, + "attemptCount": { + "type": "integer", + "format": "int32" + }, + "createdOn": { + "type": "string", + "format": "date-time" + }, + "sentOn": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "failedOn": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "correlationId": { + "type": "string", + "nullable": true + }, + "payloadJson": { + "type": "string", + "nullable": true } }, - "tags": [ - "News" - ] + "additionalProperties": false }, - "post": { - "operationId": "CreateNews", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateNewsRequest" - } - } + "NotificationLogDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true }, - "required": true - }, - "responses": { - "200": { - "description": "OK" - } - }, - "tags": [ - "News" - ] - } - }, - "/api/admin/news/{id}": { - "delete": { - "operationId": "DeleteNews", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK" + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/NotificationLogDto" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } }, - "tags": [ - "News" - ] + "additionalProperties": false }, - "get": { - "operationId": "GetNewsById", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK" + "NotificationLogListItemDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "recipientUserId": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "templateCode": { + "type": "string", + "nullable": true + }, + "templateId": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "channel": { + "$ref": "#/components/schemas/NotificationChannel" + }, + "status": { + "$ref": "#/components/schemas/NotificationDeliveryStatus" + }, + "providerMessageId": { + "type": "string", + "nullable": true + }, + "error": { + "type": "string", + "nullable": true + }, + "attemptCount": { + "type": "integer", + "format": "int32" + }, + "createdOn": { + "type": "string", + "format": "date-time" + }, + "sentOn": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "failedOn": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "correlationId": { + "type": "string", + "nullable": true } }, - "tags": [ - "News" - ] + "additionalProperties": false }, - "put": { - "operationId": "UpdateNews", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateNewsRequest" - } - } + "NotificationLogListItemDtoPagedResult": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NotificationLogListItemDto" + }, + "nullable": true }, - "required": true - }, - "responses": { - "200": { - "description": "OK" + "page": { + "type": "integer", + "format": "int32" + }, + "pageSize": { + "type": "integer", + "format": "int32" + }, + "total": { + "type": "integer", + "format": "int64" } }, - "tags": [ - "News" - ] - } - }, - "/api/admin/news/{id}/publish": { - "post": { - "operationId": "PublishNews", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK" + "additionalProperties": false + }, + "NotificationLogListItemDtoPagedResultResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/NotificationLogListItemDtoPagedResult" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } }, - "tags": [ - "News" - ] - } - }, - "/api/admin/notification-templates": { - "get": { - "operationId": "ListNotificationTemplates", - "parameters": [ - { - "in": "query", - "name": "page", - "schema": { - "format": "int32", - "type": "integer" - } + "additionalProperties": false + }, + "NotificationTemplateDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" }, - { - "in": "query", - "name": "pageSize", - "schema": { - "format": "int32", - "type": "integer" - } + "code": { + "type": "string", + "nullable": true }, - { - "in": "query", - "name": "channel", - "schema": { - "$ref": "#/components/schemas/NotificationChannel" - } + "subjectAr": { + "type": "string", + "nullable": true }, - { - "in": "query", - "name": "isActive", - "schema": { - "type": "boolean" - } - } - ], - "responses": { - "200": { - "description": "OK" + "subjectEn": { + "type": "string", + "nullable": true + }, + "bodyAr": { + "type": "string", + "nullable": true + }, + "bodyEn": { + "type": "string", + "nullable": true + }, + "channel": { + "$ref": "#/components/schemas/NotificationChannel" + }, + "variableSchemaJson": { + "type": "string", + "nullable": true + }, + "isActive": { + "type": "boolean" } }, - "tags": [ - "NotificationTemplates" - ] + "additionalProperties": false }, - "post": { - "operationId": "CreateNotificationTemplate", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateNotificationTemplateRequest" - } - } + "NotificationTemplateDtoPagedResult": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NotificationTemplateDto" + }, + "nullable": true }, - "required": true + "page": { + "type": "integer", + "format": "int32" + }, + "pageSize": { + "type": "integer", + "format": "int32" + }, + "total": { + "type": "integer", + "format": "int64" + } }, - "responses": { - "200": { - "description": "OK" + "additionalProperties": false + }, + "NotificationTemplateDtoPagedResultResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/NotificationTemplateDtoPagedResult" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } }, - "tags": [ - "NotificationTemplates" - ] - } - }, - "/api/admin/notification-templates/{id}": { - "get": { - "operationId": "GetNotificationTemplateById", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } + "additionalProperties": false + }, + "NotificationTemplateDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/NotificationTemplateDto" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } + }, + "additionalProperties": false + }, + "PageType": { + "enum": [ + 0, + 1, + 2, + 99 ], - "responses": { - "200": { - "description": "OK" + "type": "integer", + "format": "int32" + }, + "PoliciesSettingsDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "sections": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PolicySectionDto" + }, + "nullable": true } }, - "tags": [ - "NotificationTemplates" - ] + "additionalProperties": false }, - "put": { - "operationId": "UpdateNotificationTemplate", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } + "PoliciesSettingsDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/PoliciesSettingsDto" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } - ], - "requestBody": { + }, + "additionalProperties": false + }, + "PolicySectionDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "type": { + "type": "integer", + "format": "int32" + }, + "title": { + "$ref": "#/components/schemas/LocalizedTextDto" + }, "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateNotificationTemplateRequest" - } - } + "$ref": "#/components/schemas/LocalizedTextDto" }, - "required": true + "orderIndex": { + "type": "integer", + "format": "int32" + } }, - "responses": { - "200": { - "description": "OK" + "additionalProperties": false + }, + "RefreshTokenRequest": { + "type": "object", + "properties": { + "refreshToken": { + "type": "string", + "nullable": true } }, - "tags": [ - "NotificationTemplates" - ] - } - }, - "/api/admin/pages": { - "get": { - "operationId": "ListPages", - "parameters": [ - { - "in": "query", - "name": "page", - "schema": { - "format": "int32", - "type": "integer" - } + "additionalProperties": false + }, + "RegisterUserRequest": { + "type": "object", + "properties": { + "firstName": { + "type": "string", + "nullable": true }, - { - "in": "query", - "name": "pageSize", - "schema": { - "format": "int32", - "type": "integer" - } + "lastName": { + "type": "string", + "nullable": true }, - { - "in": "query", - "name": "search", - "schema": { - "type": "string" - } + "emailAddress": { + "type": "string", + "nullable": true }, - { - "in": "query", - "name": "pageType", - "schema": { - "$ref": "#/components/schemas/PageType" - } - } - ], - "responses": { - "200": { - "description": "OK" + "jobTitle": { + "type": "string", + "nullable": true + }, + "organizationName": { + "type": "string", + "nullable": true + }, + "phoneNumber": { + "type": "string", + "nullable": true + }, + "password": { + "type": "string", + "nullable": true + }, + "confirmPassword": { + "type": "string", + "nullable": true + }, + "countryCodeId": { + "type": "string", + "format": "uuid", + "nullable": true } }, - "tags": [ - "Pages" - ] + "additionalProperties": false }, - "post": { - "operationId": "CreatePage", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreatePageRequest" - } - } + "RejectCountryResourceRequestRequest": { + "type": "object", + "properties": { + "adminNotesAr": { + "type": "string", + "nullable": true }, - "required": true - }, - "responses": { - "200": { - "description": "OK" + "adminNotesEn": { + "type": "string", + "nullable": true } }, - "tags": [ - "Pages" - ] - } - }, - "/api/admin/pages/{id}": { - "delete": { - "operationId": "DeletePage", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK" + "additionalProperties": false + }, + "RejectExpertRequestRequest": { + "type": "object", + "properties": { + "rejectionReasonAr": { + "type": "string", + "nullable": true + }, + "rejectionReasonEn": { + "type": "string", + "nullable": true } }, - "tags": [ - "Pages" - ] + "additionalProperties": false }, - "get": { - "operationId": "GetPageById", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } + "ReorderHomepageSectionAssignmentRequest": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "orderIndex": { + "type": "integer", + "format": "int32" } - ], - "responses": { - "200": { - "description": "OK" + }, + "additionalProperties": false + }, + "ReorderHomepageSectionsRequest": { + "type": "object", + "properties": { + "assignments": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ReorderHomepageSectionAssignmentRequest" + }, + "nullable": true } }, - "tags": [ - "Pages" - ] + "additionalProperties": false }, - "put": { - "operationId": "UpdatePage", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } + "ReorderPolicySectionRequest": { + "type": "object", + "properties": { + "orderIndex": { + "type": "integer", + "format": "int32" } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdatePageRequest" - } - } + }, + "additionalProperties": false + }, + "RescheduleEventRequest": { + "type": "object", + "properties": { + "startsOn": { + "type": "string", + "format": "date-time" }, - "required": true + "endsOn": { + "type": "string", + "format": "date-time" + } }, - "responses": { - "200": { - "description": "OK" + "additionalProperties": false + }, + "ResetPasswordRequest": { + "type": "object", + "properties": { + "emailAddress": { + "type": "string", + "nullable": true + }, + "token": { + "type": "string", + "nullable": true + }, + "newPassword": { + "type": "string", + "nullable": true + }, + "confirmPassword": { + "type": "string", + "nullable": true } }, - "tags": [ - "Pages" - ] - } - }, - "/api/admin/reports/community-posts.csv": { - "get": { - "operationId": "CommunityPostsReport", - "parameters": [ - { - "in": "query", - "name": "from", - "schema": { - "format": "date-time", - "type": "string" - } + "additionalProperties": false + }, + "ResourceCategoryDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" }, - { - "in": "query", - "name": "to", - "schema": { - "format": "date-time", - "type": "string" - } + "nameAr": { + "type": "string", + "nullable": true + }, + "nameEn": { + "type": "string", + "nullable": true + }, + "slug": { + "type": "string", + "nullable": true + }, + "parentId": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "orderIndex": { + "type": "integer", + "format": "int32" + }, + "isActive": { + "type": "boolean" } - ], - "responses": { - "200": { - "description": "OK" + }, + "additionalProperties": false + }, + "ResourceCategoryDtoPagedResult": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ResourceCategoryDto" + }, + "nullable": true + }, + "page": { + "type": "integer", + "format": "int32" + }, + "pageSize": { + "type": "integer", + "format": "int32" + }, + "total": { + "type": "integer", + "format": "int64" } }, - "tags": [ - "Reports" - ] - } - }, - "/api/admin/reports/country-profiles.csv": { - "get": { - "operationId": "CountryProfilesReport", - "parameters": [ - { - "in": "query", - "name": "from", - "schema": { - "format": "date-time", - "type": "string" - } + "additionalProperties": false + }, + "ResourceCategoryDtoPagedResultResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/ResourceCategoryDtoPagedResult" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true }, - { - "in": "query", - "name": "to", - "schema": { - "format": "date-time", - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK" + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } }, - "tags": [ - "Reports" - ] - } - }, - "/api/admin/reports/events.csv": { - "get": { - "operationId": "EventsReport", - "parameters": [ - { - "in": "query", - "name": "from", - "schema": { - "format": "date-time", - "type": "string" - } + "additionalProperties": false + }, + "ResourceCategoryDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true }, - { - "in": "query", - "name": "to", - "schema": { - "format": "date-time", - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK" + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/ResourceCategoryDto" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } }, - "tags": [ - "Reports" - ] - } - }, - "/api/admin/reports/experts.csv": { - "get": { - "operationId": "ExpertsReport", - "parameters": [ - { - "in": "query", - "name": "from", - "schema": { - "format": "date-time", - "type": "string" - } + "additionalProperties": false + }, + "ResourceDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" }, - { - "in": "query", - "name": "to", - "schema": { - "format": "date-time", + "titleAr": { + "type": "string", + "nullable": true + }, + "titleEn": { + "type": "string", + "nullable": true + }, + "descriptionAr": { + "type": "string", + "nullable": true + }, + "descriptionEn": { + "type": "string", + "nullable": true + }, + "resourceType": { + "$ref": "#/components/schemas/ResourceType" + }, + "categoryId": { + "type": "string", + "format": "uuid" + }, + "categoryNameAr": { + "type": "string", + "nullable": true + }, + "categoryNameEn": { + "type": "string", + "nullable": true + }, + "assetFileId": { + "type": "string", + "format": "uuid" + }, + "assetFileName": { + "type": "string", + "nullable": true + }, + "countryIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "nullable": true + }, + "countryNames": { + "type": "array", + "items": { "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK" + }, + "nullable": true + }, + "uploadedById": { + "type": "string", + "format": "uuid" + }, + "publishedOn": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "viewCount": { + "type": "integer", + "format": "int64" + }, + "isCenterManaged": { + "type": "boolean" + }, + "isPublished": { + "type": "boolean" } }, - "tags": [ - "Reports" - ] - } - }, - "/api/admin/reports/news.csv": { - "get": { - "operationId": "NewsReport", - "parameters": [ - { - "in": "query", - "name": "from", - "schema": { - "format": "date-time", - "type": "string" - } + "additionalProperties": false + }, + "ResourceDtoPagedResult": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ResourceDto" + }, + "nullable": true }, - { - "in": "query", - "name": "to", - "schema": { - "format": "date-time", - "type": "string" - } + "page": { + "type": "integer", + "format": "int32" + }, + "pageSize": { + "type": "integer", + "format": "int32" + }, + "total": { + "type": "integer", + "format": "int64" } - ], - "responses": { - "200": { - "description": "OK" + }, + "additionalProperties": false + }, + "ResourceDtoPagedResultResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/ResourceDtoPagedResult" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } }, - "tags": [ - "Reports" - ] - } - }, - "/api/admin/reports/resources.csv": { - "get": { - "operationId": "ResourcesReport", - "parameters": [ - { - "in": "query", - "name": "from", - "schema": { - "format": "date-time", - "type": "string" - } + "additionalProperties": false + }, + "ResourceDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true }, - { - "in": "query", - "name": "to", - "schema": { - "format": "date-time", - "type": "string" - } + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/ResourceDto" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } + }, + "additionalProperties": false + }, + "ResourceType": { + "enum": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 ], - "responses": { - "200": { - "description": "OK" + "type": "integer", + "format": "int32" + }, + "ServiceEvaluationDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "overallSatisfaction": { + "$ref": "#/components/schemas/EvaluationRating" + }, + "easeOfUse": { + "$ref": "#/components/schemas/EvaluationRating" + }, + "contentSuitability": { + "$ref": "#/components/schemas/EvaluationRating" + }, + "feedback": { + "type": "string", + "nullable": true + }, + "userId": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "createdOn": { + "type": "string", + "format": "date-time" + }, + "createdById": { + "type": "string", + "format": "uuid" } }, - "tags": [ - "Reports" - ] - } - }, - "/api/admin/reports/satisfaction-survey.csv": { - "get": { - "operationId": "SatisfactionSurveyReport", - "parameters": [ - { - "in": "query", - "name": "from", - "schema": { - "format": "date-time", - "type": "string" - } + "additionalProperties": false + }, + "ServiceEvaluationDtoPagedResult": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ServiceEvaluationDto" + }, + "nullable": true }, - { - "in": "query", - "name": "to", - "schema": { - "format": "date-time", - "type": "string" - } + "page": { + "type": "integer", + "format": "int32" + }, + "pageSize": { + "type": "integer", + "format": "int32" + }, + "total": { + "type": "integer", + "format": "int64" } - ], - "responses": { - "200": { - "description": "OK" + }, + "additionalProperties": false + }, + "ServiceEvaluationDtoPagedResultResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/ServiceEvaluationDtoPagedResult" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } }, - "tags": [ - "Reports" - ] - } - }, - "/api/admin/reports/users-registrations.csv": { - "get": { - "operationId": "UsersRegistrationsReport", - "parameters": [ - { - "in": "query", - "name": "from", - "schema": { - "format": "date-time", - "type": "string" - } + "additionalProperties": false + }, + "ServiceEvaluationDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true }, - { - "in": "query", - "name": "to", - "schema": { - "format": "date-time", - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK" + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/ServiceEvaluationDto" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } }, - "tags": [ - "Reports" - ] - } - }, - "/api/admin/resource-categories": { - "get": { - "operationId": "ListResourceCategories", - "parameters": [ - { - "in": "query", - "name": "page", - "schema": { - "format": "int32", - "type": "integer" - } + "additionalProperties": false + }, + "StateRepAssignmentDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" }, - { - "in": "query", - "name": "pageSize", - "schema": { - "format": "int32", - "type": "integer" - } + "userId": { + "type": "string", + "format": "uuid" }, - { - "in": "query", - "name": "parentId", - "schema": { - "format": "uuid", - "type": "string" - } + "userName": { + "type": "string", + "nullable": true }, - { - "in": "query", - "name": "isActive", - "schema": { - "type": "boolean" - } + "countryId": { + "type": "string", + "format": "uuid" + }, + "assignedOn": { + "type": "string", + "format": "date-time" + }, + "assignedById": { + "type": "string", + "format": "uuid" + }, + "revokedOn": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "revokedById": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "isActive": { + "type": "boolean" } - ], - "responses": { - "200": { - "description": "OK" + }, + "additionalProperties": false + }, + "StateRepAssignmentDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/StateRepAssignmentDto" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } }, - "tags": [ - "ResourceCategories" - ] + "additionalProperties": false }, - "post": { - "operationId": "CreateResourceCategory", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateResourceCategoryRequest" - } - } + "SubmitContentRequest": { + "type": "object", + "properties": { + "type": { + "$ref": "#/components/schemas/ContentType" }, - "required": true + "countryId": { + "type": "string", + "format": "uuid" + }, + "titleAr": { + "type": "string", + "nullable": true + }, + "titleEn": { + "type": "string", + "nullable": true + }, + "descriptionAr": { + "type": "string", + "nullable": true + }, + "descriptionEn": { + "type": "string", + "nullable": true + }, + "resourceType": { + "$ref": "#/components/schemas/ResourceType" + }, + "assetFileId": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "topicId": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "featuredImageAssetId": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "startsOn": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "endsOn": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "locationAr": { + "type": "string", + "nullable": true + }, + "locationEn": { + "type": "string", + "nullable": true + }, + "onlineMeetingUrl": { + "type": "string", + "nullable": true + } }, - "responses": { - "200": { - "description": "OK" + "additionalProperties": false + }, + "TagDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "nameAr": { + "type": "string", + "nullable": true + }, + "nameEn": { + "type": "string", + "nullable": true + }, + "color": { + "type": "string", + "nullable": true } }, - "tags": [ - "ResourceCategories" - ] - } - }, - "/api/admin/resource-categories/{id}": { - "delete": { - "operationId": "DeleteResourceCategory", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } + "additionalProperties": false + }, + "TagDtoListResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TagDto" + }, + "nullable": true, + "readOnly": true + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } - ], - "responses": { - "200": { - "description": "OK" + }, + "additionalProperties": false + }, + "TagDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/TagDto" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } }, - "tags": [ - "ResourceCategories" - ] + "additionalProperties": false }, - "get": { - "operationId": "GetResourceCategoryById", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } + "TopicDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "nameAr": { + "type": "string", + "nullable": true + }, + "nameEn": { + "type": "string", + "nullable": true + }, + "descriptionAr": { + "type": "string", + "nullable": true + }, + "descriptionEn": { + "type": "string", + "nullable": true + }, + "slug": { + "type": "string", + "nullable": true + }, + "parentId": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "iconUrl": { + "type": "string", + "nullable": true + }, + "orderIndex": { + "type": "integer", + "format": "int32" + }, + "isActive": { + "type": "boolean" } - ], - "responses": { - "200": { - "description": "OK" + }, + "additionalProperties": false + }, + "TopicDtoPagedResult": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TopicDto" + }, + "nullable": true + }, + "page": { + "type": "integer", + "format": "int32" + }, + "pageSize": { + "type": "integer", + "format": "int32" + }, + "total": { + "type": "integer", + "format": "int64" } }, - "tags": [ - "ResourceCategories" - ] + "additionalProperties": false }, - "put": { - "operationId": "UpdateResourceCategory", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateResourceCategoryRequest" - } - } + "TopicDtoPagedResultResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true }, - "required": true - }, - "responses": { - "200": { - "description": "OK" + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/TopicDtoPagedResult" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } }, - "tags": [ - "ResourceCategories" - ] - } - }, - "/api/admin/resources": { - "get": { - "operationId": "ListResources", - "parameters": [ - { - "in": "query", - "name": "page", - "schema": { - "format": "int32", - "type": "integer" - } + "additionalProperties": false + }, + "TopicDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true }, - { - "in": "query", - "name": "pageSize", - "schema": { - "format": "int32", - "type": "integer" - } + "code": { + "type": "string", + "nullable": true, + "readOnly": true }, - { - "in": "query", - "name": "search", - "schema": { - "type": "string" - } + "message": { + "type": "string", + "nullable": true, + "readOnly": true }, - { - "in": "query", - "name": "categoryId", - "schema": { - "format": "uuid", - "type": "string" - } + "data": { + "$ref": "#/components/schemas/TopicDto" }, - { - "in": "query", - "name": "countryId", - "schema": { - "format": "uuid", - "type": "string" - } + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true }, - { - "in": "query", - "name": "isPublished", - "schema": { - "type": "boolean" - } + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } - ], - "responses": { - "200": { - "description": "OK" + }, + "additionalProperties": false + }, + "UpdateAboutSettingsRequest": { + "type": "object", + "properties": { + "descriptionAr": { + "type": "string", + "nullable": true + }, + "descriptionEn": { + "type": "string", + "nullable": true + }, + "howToUseVideoUrl": { + "type": "string", + "nullable": true } }, - "tags": [ - "Resources" - ] + "additionalProperties": false }, - "post": { - "operationId": "CreateResource", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateResourceRequest" - } - } + "UpdateCommunityRequest": { + "type": "object", + "properties": { + "nameAr": { + "type": "string", + "nullable": true }, - "required": true + "nameEn": { + "type": "string", + "nullable": true + }, + "descriptionAr": { + "type": "string", + "nullable": true + }, + "descriptionEn": { + "type": "string", + "nullable": true + }, + "presentationJson": { + "type": "string", + "nullable": true + } }, - "responses": { - "200": { - "description": "OK" + "additionalProperties": false + }, + "UpdateCountryRequest": { + "type": "object", + "properties": { + "nameAr": { + "type": "string", + "nullable": true + }, + "nameEn": { + "type": "string", + "nullable": true + }, + "regionAr": { + "type": "string", + "nullable": true + }, + "regionEn": { + "type": "string", + "nullable": true + }, + "isActive": { + "type": "boolean" } }, - "tags": [ - "Resources" - ] - } - }, - "/api/admin/resources/{id}": { - "put": { - "operationId": "UpdateResource", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } + "additionalProperties": false + }, + "UpdateEventRequest": { + "type": "object", + "properties": { + "titleAr": { + "type": "string", + "nullable": true + }, + "titleEn": { + "type": "string", + "nullable": true + }, + "descriptionAr": { + "type": "string", + "nullable": true + }, + "descriptionEn": { + "type": "string", + "nullable": true + }, + "locationAr": { + "type": "string", + "nullable": true + }, + "locationEn": { + "type": "string", + "nullable": true + }, + "onlineMeetingUrl": { + "type": "string", + "nullable": true + }, + "featuredImageUrl": { + "type": "string", + "nullable": true + }, + "topicId": { + "type": "string", + "format": "uuid" + }, + "tagIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "nullable": true } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateResourceRequest" - } - } + }, + "additionalProperties": false + }, + "UpdateGlossaryEntryRequest": { + "type": "object", + "properties": { + "termAr": { + "type": "string", + "nullable": true }, - "required": true + "termEn": { + "type": "string", + "nullable": true + }, + "definitionAr": { + "type": "string", + "nullable": true + }, + "definitionEn": { + "type": "string", + "nullable": true + } }, - "responses": { - "200": { - "description": "OK" + "additionalProperties": false + }, + "UpdateHomepageSectionRequest": { + "type": "object", + "properties": { + "contentAr": { + "type": "string", + "nullable": true + }, + "contentEn": { + "type": "string", + "nullable": true + }, + "isActive": { + "type": "boolean" } }, - "tags": [ - "Resources" - ] - } - }, - "/api/admin/resources/{id}/publish": { - "post": { - "operationId": "PublishResource", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } + "additionalProperties": false + }, + "UpdateHomepageSettingsRequest": { + "type": "object", + "properties": { + "videoUrl": { + "type": "string", + "nullable": true + }, + "objectiveAr": { + "type": "string", + "nullable": true + }, + "objectiveEn": { + "type": "string", + "nullable": true + }, + "cceConceptsAr": { + "type": "string", + "nullable": true + }, + "cceConceptsEn": { + "type": "string", + "nullable": true + }, + "participatingCountryIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "nullable": true } - ], - "responses": { - "200": { - "description": "OK" + }, + "additionalProperties": false + }, + "UpdateKnowledgePartnerRequest": { + "type": "object", + "properties": { + "nameAr": { + "type": "string", + "nullable": true + }, + "nameEn": { + "type": "string", + "nullable": true + }, + "logoUrl": { + "type": "string", + "nullable": true + }, + "websiteUrl": { + "type": "string", + "nullable": true + }, + "descriptionAr": { + "type": "string", + "nullable": true + }, + "descriptionEn": { + "type": "string", + "nullable": true } }, - "tags": [ - "Resources" - ] - } - }, - "/api/admin/state-rep-assignments": { - "get": { - "operationId": "ListStateRepAssignments", - "parameters": [ - { - "in": "query", - "name": "page", - "schema": { - "format": "int32", - "type": "integer" - } + "additionalProperties": false + }, + "UpdateMediaMetadataCommand": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" }, - { - "in": "query", - "name": "pageSize", - "schema": { - "format": "int32", - "type": "integer" - } + "titleAr": { + "type": "string", + "nullable": true }, - { - "in": "query", - "name": "userId", - "schema": { - "format": "uuid", - "type": "string" - } + "titleEn": { + "type": "string", + "nullable": true }, - { - "in": "query", - "name": "countryId", - "schema": { - "format": "uuid", - "type": "string" - } + "descriptionAr": { + "type": "string", + "nullable": true }, - { - "in": "query", - "name": "active", - "schema": { - "type": "boolean" - } - } - ], - "responses": { - "200": { - "description": "OK" + "descriptionEn": { + "type": "string", + "nullable": true + }, + "altTextAr": { + "type": "string", + "nullable": true + }, + "altTextEn": { + "type": "string", + "nullable": true } }, - "tags": [ - "Identity" - ] + "additionalProperties": false }, - "post": { - "operationId": "CreateStateRepAssignment", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateStateRepAssignmentRequest" - } - } + "UpdateNewsRequest": { + "type": "object", + "properties": { + "titleAr": { + "type": "string", + "nullable": true }, - "required": true - }, - "responses": { - "200": { - "description": "OK" + "titleEn": { + "type": "string", + "nullable": true + }, + "contentAr": { + "type": "string", + "nullable": true + }, + "contentEn": { + "type": "string", + "nullable": true + }, + "topicId": { + "type": "string", + "format": "uuid" + }, + "featuredImageUrl": { + "type": "string", + "nullable": true + }, + "tagIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "nullable": true } }, - "tags": [ - "Identity" - ] - } - }, - "/api/admin/state-rep-assignments/{id}": { - "delete": { - "operationId": "RevokeStateRepAssignment", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK" + "additionalProperties": false + }, + "UpdateNotificationTemplateRequest": { + "type": "object", + "properties": { + "subjectAr": { + "type": "string", + "nullable": true + }, + "subjectEn": { + "type": "string", + "nullable": true + }, + "bodyAr": { + "type": "string", + "nullable": true + }, + "bodyEn": { + "type": "string", + "nullable": true + }, + "isActive": { + "type": "boolean" } }, - "tags": [ - "Identity" - ] - } - }, - "/api/admin/topics": { - "get": { - "operationId": "ListTopics", - "parameters": [ - { - "in": "query", - "name": "page", - "schema": { - "format": "int32", - "type": "integer" - } + "additionalProperties": false + }, + "UpdatePageRequest": { + "type": "object", + "properties": { + "titleAr": { + "type": "string", + "nullable": true }, - { - "in": "query", - "name": "pageSize", - "schema": { - "format": "int32", - "type": "integer" - } + "titleEn": { + "type": "string", + "nullable": true }, - { - "in": "query", - "name": "parentId", - "schema": { - "format": "uuid", - "type": "string" - } + "contentAr": { + "type": "string", + "nullable": true }, - { - "in": "query", - "name": "isActive", - "schema": { - "type": "boolean" - } + "contentEn": { + "type": "string", + "nullable": true }, - { - "in": "query", - "name": "search", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK" + "rowVersion": { + "type": "string", + "nullable": true } }, - "tags": [ - "Topics" - ] + "additionalProperties": false }, - "post": { - "operationId": "CreateTopic", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateTopicRequest" - } - } + "UpdatePolicySectionRequest": { + "type": "object", + "properties": { + "titleAr": { + "type": "string", + "nullable": true }, - "required": true - }, - "responses": { - "200": { - "description": "OK" + "titleEn": { + "type": "string", + "nullable": true + }, + "contentAr": { + "type": "string", + "nullable": true + }, + "contentEn": { + "type": "string", + "nullable": true } }, - "tags": [ - "Topics" - ] - } - }, - "/api/admin/topics/{id}": { - "delete": { - "operationId": "DeleteTopic", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } + "additionalProperties": false + }, + "UpdateResourceCategoryRequest": { + "type": "object", + "properties": { + "nameAr": { + "type": "string", + "nullable": true + }, + "nameEn": { + "type": "string", + "nullable": true + }, + "orderIndex": { + "type": "integer", + "format": "int32" + }, + "isActive": { + "type": "boolean" } - ], - "responses": { - "200": { - "description": "OK" + }, + "additionalProperties": false + }, + "UpdateResourceRequest": { + "type": "object", + "properties": { + "titleAr": { + "type": "string", + "nullable": true + }, + "titleEn": { + "type": "string", + "nullable": true + }, + "descriptionAr": { + "type": "string", + "nullable": true + }, + "descriptionEn": { + "type": "string", + "nullable": true + }, + "resourceType": { + "$ref": "#/components/schemas/ResourceType" + }, + "categoryId": { + "type": "string", + "format": "uuid" + }, + "countryIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "nullable": true + }, + "rowVersion": { + "type": "string", + "nullable": true } }, - "tags": [ - "Topics" - ] + "additionalProperties": false }, - "get": { - "operationId": "GetTopicById", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } + "UpdateTagRequest": { + "type": "object", + "properties": { + "nameAr": { + "type": "string", + "nullable": true + }, + "nameEn": { + "type": "string", + "nullable": true + }, + "color": { + "type": "string", + "nullable": true } - ], - "responses": { - "200": { - "description": "OK" + }, + "additionalProperties": false + }, + "UpdateTopicRequest": { + "type": "object", + "properties": { + "nameAr": { + "type": "string", + "nullable": true + }, + "nameEn": { + "type": "string", + "nullable": true + }, + "descriptionAr": { + "type": "string", + "nullable": true + }, + "descriptionEn": { + "type": "string", + "nullable": true + }, + "orderIndex": { + "type": "integer", + "format": "int32" + }, + "isActive": { + "type": "boolean" } }, - "tags": [ - "Topics" - ] + "additionalProperties": false }, - "put": { - "operationId": "UpdateTopic", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateTopicRequest" - } - } + "UpsertCountryCodeRequest": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" }, - "required": true + "nameAr": { + "type": "string", + "nullable": true + }, + "nameEn": { + "type": "string", + "nullable": true + }, + "dialCode": { + "type": "string", + "nullable": true + }, + "isActive": { + "type": "boolean" + } }, - "responses": { - "200": { - "description": "OK" + "additionalProperties": false + }, + "UpsertCountryProfileRequest": { + "type": "object", + "properties": { + "descriptionAr": { + "type": "string", + "nullable": true + }, + "descriptionEn": { + "type": "string", + "nullable": true + }, + "keyInitiativesAr": { + "type": "string", + "nullable": true + }, + "keyInitiativesEn": { + "type": "string", + "nullable": true + }, + "contactInfoAr": { + "type": "string", + "nullable": true + }, + "contactInfoEn": { + "type": "string", + "nullable": true + }, + "population": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "areaSqKm": { + "type": "number", + "format": "double", + "nullable": true + }, + "gdpPerCapita": { + "type": "number", + "format": "double", + "nullable": true + }, + "ndcAssetId": { + "type": "string", + "format": "uuid", + "nullable": true } }, - "tags": [ - "Topics" - ] - } - }, - "/api/admin/users": { - "get": { - "operationId": "ListUsers", - "parameters": [ - { - "in": "query", - "name": "page", - "schema": { - "format": "int32", - "type": "integer" - } + "additionalProperties": false + }, + "UserDetailDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" }, - { - "in": "query", - "name": "pageSize", - "schema": { - "format": "int32", - "type": "integer" - } + "email": { + "type": "string", + "nullable": true }, - { - "in": "query", - "name": "search", - "schema": { + "userName": { + "type": "string", + "nullable": true + }, + "localePreference": { + "type": "string", + "nullable": true + }, + "knowledgeLevel": { + "$ref": "#/components/schemas/KnowledgeLevel" + }, + "interests": { + "type": "array", + "items": { "type": "string" - } + }, + "nullable": true }, - { - "in": "query", - "name": "role", - "schema": { + "countryId": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "countryCodeId": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "avatarUrl": { + "type": "string", + "nullable": true + }, + "roles": { + "type": "array", + "items": { "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK" + }, + "nullable": true + }, + "isActive": { + "type": "boolean" } }, - "tags": [ - "Identity" - ] - } - }, - "/api/admin/users/{id}": { - "get": { - "operationId": "GetUserById", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK" + "additionalProperties": false + }, + "UserDetailDtoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/UserDetailDto" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } }, - "tags": [ - "Identity" - ] - } - }, - "/api/admin/users/{id}/roles": { - "put": { - "operationId": "AssignUserRoles", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", + "additionalProperties": false + }, + "UserListItemDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "email": { + "type": "string", + "nullable": true + }, + "userName": { + "type": "string", + "nullable": true + }, + "roles": { + "type": "array", + "items": { "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AssignUserRolesRequest" - } - } + }, + "nullable": true }, - "required": true + "isActive": { + "type": "boolean" + } }, - "responses": { - "200": { - "description": "OK" + "additionalProperties": false + }, + "UserListItemDtoPagedResult": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UserListItemDto" + }, + "nullable": true + }, + "page": { + "type": "integer", + "format": "int32" + }, + "pageSize": { + "type": "integer", + "format": "int32" + }, + "total": { + "type": "integer", + "format": "int64" } }, - "tags": [ - "Identity" - ] - } - }, - "/auth/echo": { - "get": { - "responses": { - "200": { - "description": "OK" + "additionalProperties": false + }, + "UserListItemDtoPagedResultResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/UserListItemDtoPagedResult" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } }, - "tags": [ - "CCE.Api.Internal" - ] - } - }, - "/health": { - "get": { - "responses": { - "200": { - "description": "OK" + "additionalProperties": false + }, + "VirusScanStatus": { + "enum": [ + 0, + 1, + 2, + 3 + ], + "type": "integer", + "format": "int32" + }, + "VoidData": { + "type": "object", + "additionalProperties": false + }, + "VoidDataResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "readOnly": true + }, + "code": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "data": { + "$ref": "#/components/schemas/VoidData" + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "nullable": true, + "readOnly": true + }, + "traceId": { + "type": "string", + "nullable": true + }, + "timestamp": { + "type": "string", + "format": "date-time" } }, - "tags": [ - "CCE.Api.Internal" - ] + "additionalProperties": false } }, - "/health/authenticated": { - "get": { - "responses": { - "200": { - "description": "OK" - } - }, - "tags": [ - "CCE.Api.Internal" - ] + "securitySchemes": { + "Bearer": { + "type": "http", + "description": "Paste your JWT Bearer token (e.g. from Entra ID or /dev/sign-in).", + "scheme": "Bearer", + "bearerFormat": "JWT" } } - } -} + }, + "security": [ + { + "Bearer": [ ] + } + ] +} \ No newline at end of file diff --git a/frontend/.stylelintrc.json b/frontend/.stylelintrc.json new file mode 100644 index 00000000..e57e30f3 --- /dev/null +++ b/frontend/.stylelintrc.json @@ -0,0 +1,35 @@ +{ + "//": "Minimal, focused config: ENFORCE the no-hardcoded-color rule (CLAUDE.md gotcha #7 / PERF001). Not the full standard ruleset — we don't want to flag pre-existing style nits, only hardcoded colors. All colors must be design tokens: var(--…) from libs/ui-kit/src/lib/styles/_palette.scss.", + "overrides": [ + { + "files": ["**/*.scss"], + "customSyntax": "postcss-scss" + } + ], + "rules": { + "color-no-hex": [ + true, + { + "message": "No hardcoded hex colors. Use a design token: var(--…) from _palette.scss. Need a new color? Add it to _palette.scss first. (CLAUDE.md #7 / PERF001)" + } + ], + "color-named": [ + "never", + { + "message": "No named colors. Use a design token: var(--…) from _palette.scss. (CLAUDE.md #7 / PERF001)" + } + ], + "function-disallowed-list": [ + ["hsl", "hsla"], + { + "message": "No raw hsl()/hsla(). Use a design token: var(--…), or rgba(var(--x-rgb), a). (CLAUDE.md #7 / PERF001)" + } + ] + }, + "ignoreFiles": [ + "**/node_modules/**", + "**/dist/**", + "**/coverage/**", + "libs/ui-kit/src/lib/styles/_palette.scss" + ] +} diff --git a/frontend/CLAUDE.md b/frontend/CLAUDE.md new file mode 100644 index 00000000..813939d4 --- /dev/null +++ b/frontend/CLAUDE.md @@ -0,0 +1,61 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## 📚 Full documentation lives in `../../cce-platform-docs/` + +| Doc | When to read | +|---|---| +| `cce-platform-docs/technical/FRONTEND_GUIDE.md` | **Read before coding** — architecture, auth, i18n, feature anatomy | +| `cce-platform-docs/technical/CONVENTIONS.md` | Code patterns to match | +| `cce-platform-docs/technical/API_INTEGRATION.md` | HTTP layer, endpoints, envelope rules | +| `cce-platform-docs/agile/PROGRESS.md` | ⭐ Story status tracker — **update it after completing any story** | +| `cce-platform-docs/agile/stories/` | Acceptance criteria per user story | +| `cce-platform-docs/reference/users.md` | Test credentials | + +## Commands (run from this directory, always pnpm) + +```bash +pnpm nx serve web-portal # public app :4200 +pnpm nx serve admin-cms # admin app :4201 +pnpm nx build +pnpm nx test --watch=false # add --testFile= for a single spec +pnpm nx lint +pnpm nx run-many -t build,lint,test --projects=web-portal,admin-cms # full smoke +``` + +## Critical gotchas (cause real bugs) + +1. **Envelope auto-unwrap (admin-cms):** any response from a URL containing `/api/admin/` is unwrapped by `apiEnvelopeInterceptor` — services type the **inner** data shape and must NOT access `.data`. Web-portal endpoints are NOT unwrapped. +2. **i18n:** translation keys must exist in BOTH `libs/i18n/src/lib/i18n/ar.json` and `en.json`. Default language is Arabic — always verify RTL (logical CSS properties, icon flips). +3. **Auth:** access token in a signal (memory), refresh token in `localStorage['cce_rt']`. `tokenInterceptor` skips `/api/auth/*`. Interceptor order differs per app — see FRONTEND_GUIDE §4.3. +4. **Style:** standalone components + signals + `OnPush` + new control flow (`@if`/`@for`) only. Material form fields are globally `outline`. Selector prefix `cce-`. +5. **Services return `Result`** (`{ok:true,value}|{ok:false,error}`) — components never try/catch; map `error.kind` to `('errors.'+kind) | transloco`. +6. **Definition of done includes updating** `cce-platform-docs/agile/PROGRESS.md` (status + dated log entry). +7. **NEVER hardcode a color.** No hex (`#fff`), named (`white`), `rgb()`, or `hsl()` literals in any `.scss`/`.ts`/`.html` — not even "just this once". All colors MUST be design tokens. The single source of truth is `libs/ui-kit/src/lib/styles/_palette.scss`; it emits CSS custom properties consumed everywhere as `var(--…)`. Use `var(--neutrals--50)`, `var(--color-brand)`, etc. For opacity use the auto-derived channels: `rgba(var(--color-brand-rgb), 0.5)`. Need a color the tokens don't have? Add it to `_palette.scss` first, then reference the var — never inline the literal. This applies to every AI agent. (Only `rgba(0,0,0,…)`/`rgba(255,255,255,…)` pure black/white scrims are tolerated, and even those prefer a token.) **Enforced** in `.scss` by stylelint (`.stylelintrc.json`): run `pnpm stylelint` or `pnpm nx run-many -t stylelint`. Inline `styles:` in `.ts` are not linted — keep them token-only by hand. + +## CSS & styling rules (read before touching any `.scss`) + +**Stack:** Angular Material (M2 theme) + token-driven SCSS (`cce-*` BEM). **No Tailwind** — it was removed; do NOT reintroduce utility classes (`flex`, `p-4`, `bg-primary`). No third styling paradigm. + +**Tokens & theme** +- All design values flow from `libs/ui-kit/src/lib/styles/_palette.scss` → `_css-vars.scss` (emits CSS vars + auto-derived `--x-rgb` channels) → `_dga-theme.scss` (Material M2 theme). To rebrand, edit `_palette.scss` only. +- Theme is **M2**. Do NOT add an M3 prebuilt theme (e.g. `prebuilt-themes/*.css`) — it conflicts and bloats. `--mat-sys-*` tokens are shimmed to the palette in `_css-vars.scss`; use those, don't reintroduce a prebuilt. + +**Performance (these caused real wins/regressions — keep them)** +- **Honor reduced-motion:** a global `prefers-reduced-motion` guard lives in `cce-theme`. New continuously-running (`infinite`) animations must be acceptable when neutralised; pause off-screen ones. +- **Blur is expensive:** avoid `backdrop-filter`/`filter: blur()` on large or scrolling surfaces; keep radius ≤ ~10px (shared glass = `--cce-fancy-glass-blur`). A radial-gradient is already soft — don't stack a big blur on it. +- **Never** `background-attachment: fixed` (full repaint per scroll frame). +- **Never** `transition: all` — list explicit compositor-friendly props (`transform`, `opacity`, `box-shadow`, `border-color`, …); prefer animating `transform`/`opacity`. +- Use `content-visibility: auto` + `contain-intrinsic-size` on repeated below-the-fold blocks (list cards already do). +- Feature-only CSS (e.g. Quill) must NOT be global — ship it as a lazy bundle (see `project.json` `styles` + `cce-rich-text-editor` on-demand load), not in `styles.scss`. + +**Architecture truths (don't waste effort fighting these)** +- Component styles are **automatically route-split** (lazy chunks) — do NOT try to "move page CSS out of the global bundle"; it's already isolated. The global `styles.css` is Material theme + `_fancy`/`_admin-polish` only. +- SCSS `@mixin`/`@extend` does **NOT** reduce shipped bytes (component styles are isolated; mixins re-emit per component). Dedup is a **maintainability** win, not a size one. The only real size lever for a heavy page is **splitting it into smaller sub-components**, not mangling its CSS. +- Keep a component `.scss` under the **20KB** budget (`anyComponentStyle`); if a page is legitimately larger (rich landing page), that's a *warning*, not a failure — split into section components rather than obfuscate. + +**Workflow — before calling CSS work done** +- Run `pnpm nx run-many -t stylelint` (color rule) **and** `-t build` (size budgets: `styles` bundle + `anyComponentStyle`). Both must pass. +- Verify **RTL** (logical properties: `margin-inline`, `inset-inline-*`; flip directional icons). +- Keep selector prefix `cce-`; avoid new `::ng-deep` and `!important` (existing debt — don't add to it). diff --git a/frontend/apps/admin-cms/jest.config.ts b/frontend/apps/admin-cms/jest.config.ts index 2c680741..500d5daa 100644 --- a/frontend/apps/admin-cms/jest.config.ts +++ b/frontend/apps/admin-cms/jest.config.ts @@ -9,10 +9,14 @@ export default { { tsconfig: '/tsconfig.spec.json', stringifyContentPathRegex: '\\.(html|svg)$', + // Material 21+ entry points are package-exports only; ts-jest's CJS + // type-checker can't resolve them. Transpile-only — Jest's resolver + // handles exports maps at runtime. + isolatedModules: true, }, ], }, - transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$|.*@jsverse)'], snapshotSerializers: [ 'jest-preset-angular/build/serializers/no-ng-attributes', 'jest-preset-angular/build/serializers/ng-snapshot', diff --git a/frontend/apps/admin-cms/project.json b/frontend/apps/admin-cms/project.json index 1fbaaeb7..fab83401 100644 --- a/frontend/apps/admin-cms/project.json +++ b/frontend/apps/admin-cms/project.json @@ -32,7 +32,11 @@ "output": "assets/i18n" } ], - "styles": ["apps/admin-cms/src/styles.scss"], + "styles": [ + "apps/admin-cms/src/styles.scss", + { "input": "node_modules/quill/dist/quill.core.css", "bundleName": "quill", "inject": false }, + { "input": "node_modules/quill/dist/quill.snow.css", "bundleName": "quill", "inject": false } + ], "scripts": [] }, "configurations": { @@ -40,13 +44,19 @@ "budgets": [ { "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" + "maximumWarning": "1mb", + "maximumError": "2mb" }, { "type": "anyComponentStyle", - "maximumWarning": "4kb", - "maximumError": "8kb" + "maximumWarning": "8kb", + "maximumError": "16kb" + }, + { + "type": "bundle", + "name": "styles", + "maximumWarning": "140kb", + "maximumError": "170kb" } ], "outputHashing": "all" @@ -84,6 +94,12 @@ "lint": { "executor": "@nx/eslint:lint" }, + "stylelint": { + "executor": "nx:run-commands", + "options": { + "command": "stylelint \"apps/admin-cms/**/*.scss\"" + } + }, "test": { "executor": "@nx/jest:jest", "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], diff --git a/frontend/apps/admin-cms/proxy.conf.json b/frontend/apps/admin-cms/proxy.conf.json index d3a575ef..6bf6acc1 100644 --- a/frontend/apps/admin-cms/proxy.conf.json +++ b/frontend/apps/admin-cms/proxy.conf.json @@ -1,20 +1,15 @@ { "/api": { - "target": "http://localhost:5002", - "secure": false, + "target": "https://cce-internal-api.runasp.net", + "secure": true, "changeOrigin": true, "logLevel": "warn" }, - "/auth": { - "target": "http://localhost:5002", - "secure": false, - "changeOrigin": true, - "logLevel": "warn" - }, - "/dev": { - "target": "http://localhost:5002", - "secure": false, + "/hubs": { + "target": "https://cce-internal-api.runasp.net", + "secure": true, "changeOrigin": true, + "ws": true, "logLevel": "warn" } } diff --git a/frontend/apps/admin-cms/src/_admin-polish.scss b/frontend/apps/admin-cms/src/_admin-polish.scss index 29a3b55a..e67c6b5f 100644 --- a/frontend/apps/admin-cms/src/_admin-polish.scss +++ b/frontend/apps/admin-cms/src/_admin-polish.scss @@ -18,13 +18,13 @@ .cce-app-shell__main-inner { /* ─── Page titles → branded gradient + eyebrow accent ─── */ - > :where(h1, .cce-page-h1) { + :where(h1, .cce-page-h1) { margin: 0 0 1.25rem; font-size: clamp(1.45rem, 2.4vw, 2rem); font-weight: 800; line-height: 1.18; letter-spacing: -0.018em; - background: linear-gradient(135deg, #003a2b 0%, #006c4f 60%, #0f8b6c 100%); + background: linear-gradient(135deg, var(--color-brand-dark) 0%, var(--color-brand) 60%, var(--color-brand-mid) 100%); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; @@ -41,24 +41,24 @@ width: 4px; height: 28px; border-radius: 999px; - background: linear-gradient(180deg, #006c4f 0%, #14b88f 60%, #c8a045 100%); + background: linear-gradient(180deg, var(--color-brand) 0%, var(--color-brand-accent) 60%, var(--color-accent) 100%); -webkit-text-fill-color: initial; } } /* ─── Filter rows ─────────────────────────────────────── */ - > :where(.cce-users-list__filters, - .cce-resources-list__filters, - .cce-news-list__filters, - .cce-events-list__filters, - .cce-pages-list__filters, - .cce-countries-list__filters, - .cce-experts-list__filters, - .cce-state-rep-list__filters, - .cce-country-resource-request__filters, - .cce-audit__filters, - .cce-list-filters-row, - [data-admin-filters]) { + :where(.cce-users-list__filters, + .cce-resources-list__filters, + .cce-news-list__filters, + .cce-events-list__filters, + .cce-pages-list__filters, + .cce-countries-list__filters, + .cce-experts-list__filters, + .cce-state-rep-list__filters, + .cce-country-resource-request__filters, + .cce-audit__filters, + .cce-list-filters-row, + [data-admin-filters]) { display: flex; gap: 0.75rem; flex-wrap: wrap; @@ -66,25 +66,25 @@ padding: 0.85rem 1rem; margin-bottom: 1.1rem; background: - radial-gradient(500px 140px at 0% 0%, rgba(20, 184, 143, 0.06), transparent 70%), - linear-gradient(180deg, #ffffff 0%, #fbfdfb 100%); - border: 1px solid rgba(0, 108, 79, 0.12); + radial-gradient(500px 140px at 0% 0%, rgba(var(--color-brand-accent-rgb), 0.06), transparent 70%), + linear-gradient(180deg, var(--white) 0%, var(--primary--50) 100%); + border: 1px solid rgba(var(--color-brand-rgb), 0.12); border-radius: 14px; - box-shadow: 0 6px 16px -14px rgba(0, 48, 31, 0.22); + box-shadow: 0 6px 16px -14px rgba(var(--color-brand-shadow-rgb), 0.22); } /* Inside filter rows, tighten the Material form-field bottom subscript */ - > :where(.cce-users-list__filters, - .cce-resources-list__filters, - .cce-news-list__filters, - .cce-events-list__filters, - .cce-pages-list__filters, - .cce-countries-list__filters, - .cce-experts-list__filters, - .cce-state-rep-list__filters, - .cce-country-resource-request__filters, - .cce-audit__filters, - .cce-list-filters-row, - [data-admin-filters]) { + :where(.cce-users-list__filters, + .cce-resources-list__filters, + .cce-news-list__filters, + .cce-events-list__filters, + .cce-pages-list__filters, + .cce-countries-list__filters, + .cce-experts-list__filters, + .cce-state-rep-list__filters, + .cce-country-resource-request__filters, + .cce-audit__filters, + .cce-list-filters-row, + [data-admin-filters]) { .mat-mdc-form-field-subscript-wrapper { display: none !important; } mat-form-field { width: auto; min-width: 220px; flex: 1 1 220px; max-width: 360px; } } @@ -103,46 +103,46 @@ .cce-translations__error, .cce-moderation__error, [data-admin-error]) { - background: linear-gradient(180deg, #fff5f4 0%, #ffece9 100%); - color: #8a1f0d; + background: linear-gradient(180deg, var(--danger--50) 0%, var(--danger--50) 100%); + color: var(--danger--800); padding: 0.85rem 1.05rem; border-radius: 14px; margin-bottom: 1rem; - border: 1px solid rgba(176, 0, 32, 0.18); + border: 1px solid rgba(var(--danger--600-rgb), 0.18); font-weight: 600; - box-shadow: 0 6px 16px -14px rgba(176, 0, 32, 0.30); + box-shadow: 0 6px 16px -14px rgba(var(--danger--600-rgb), 0.30); } } /* ─── Material tables — branded header + hover row ───────── */ .cce-app-shell__main-inner .mat-mdc-table { - background: #ffffff !important; - border: 1px solid rgba(0, 60, 44, 0.08); + background: var(--white) !important; + border: 1px solid rgba(var(--color-brand-shadow-rgb), 0.08); border-radius: 14px; overflow: hidden; - box-shadow: 0 8px 22px -18px rgba(0, 48, 31, 0.22); + box-shadow: 0 8px 22px -18px rgba(var(--color-brand-shadow-rgb), 0.22); } .cce-app-shell__main-inner .mat-mdc-header-row { - background: linear-gradient(180deg, #f4faf7 0%, #ecf6f1 100%) !important; - border-bottom: 1px solid rgba(0, 108, 79, 0.18) !important; + background: linear-gradient(180deg, var(--primary--50) 0%, var(--primary--50) 100%) !important; + border-bottom: 1px solid rgba(var(--color-brand-rgb), 0.18) !important; } .cce-app-shell__main-inner .mat-mdc-header-cell { font-weight: 800 !important; font-size: 0.74rem !important; letter-spacing: 0.08em !important; text-transform: uppercase; - color: rgba(0, 60, 44, 0.78) !important; + color: rgba(var(--color-brand-shadow-rgb), 0.78) !important; } .cce-app-shell__main-inner .mat-mdc-row { transition: background 0.15s ease; } .cce-app-shell__main-inner .mat-mdc-row:hover { - background: rgba(20, 184, 143, 0.05) !important; + background: rgba(var(--color-brand-accent-rgb), 0.05) !important; } .cce-app-shell__main-inner .mat-mdc-cell { font-size: 0.92rem !important; - color: #1c2724 !important; - border-bottom-color: rgba(0, 60, 44, 0.05) !important; + color: var(--color-text-primary) !important; + border-bottom-color: rgba(var(--color-brand-shadow-rgb), 0.05) !important; } /* ─── Paginator ──────────────────────────────────────────── */ @@ -152,32 +152,32 @@ } .cce-app-shell__main-inner .mat-mdc-paginator-page-size-label, .cce-app-shell__main-inner .mat-mdc-paginator-range-label { - color: rgba(28, 39, 36, 0.65) !important; + color: rgba(var(--color-text-primary-rgb), 0.65) !important; font-weight: 600 !important; } .cce-app-shell__main-inner .mat-mdc-icon-button.mat-mdc-paginator-navigation-next, .cce-app-shell__main-inner .mat-mdc-icon-button.mat-mdc-paginator-navigation-previous, .cce-app-shell__main-inner .mat-mdc-icon-button.mat-mdc-paginator-navigation-first, .cce-app-shell__main-inner .mat-mdc-icon-button.mat-mdc-paginator-navigation-last { - --mdc-icon-button-icon-color: #006c4f; + --mdc-icon-button-icon-color: var(--color-brand); } /* ─── Form fields → brand-green focus ─────────────────────── */ .cce-app-shell__main-inner { .mat-mdc-form-field.mat-focused .mat-mdc-form-field-focus-overlay { - background-color: rgba(15, 139, 108, 0.08) !important; + background-color: rgba(var(--color-brand-mid-rgb), 0.08) !important; } .mat-mdc-form-field.mat-focused .mdc-text-field--outlined .mdc-notched-outline__leading, .mat-mdc-form-field.mat-focused .mdc-text-field--outlined .mdc-notched-outline__notch, .mat-mdc-form-field.mat-focused .mdc-text-field--outlined .mdc-notched-outline__trailing { - border-color: #006c4f !important; + border-color: var(--color-brand) !important; } .mat-mdc-form-field.mat-focused .mdc-floating-label, .mat-mdc-form-field.mat-focused .mdc-floating-label--float-above { - color: #006c4f !important; + color: var(--color-brand) !important; } .mat-mdc-input-element { - caret-color: #006c4f !important; + caret-color: var(--color-brand) !important; } } @@ -187,29 +187,36 @@ .mat-mdc-flat-button.mat-primary, .mat-mdc-fab.mat-primary, .mat-mdc-mini-fab.mat-primary { - --mdc-protected-button-container-color: #006c4f; - --mdc-filled-button-container-color: #006c4f; - --mdc-fab-container-color: #006c4f; - --mat-mdc-button-persistent-ripple-color: #ffffff; + --mdc-protected-button-container-color: var(--color-brand); + --mdc-filled-button-container-color: var(--color-brand); + --mdc-fab-container-color: var(--color-brand); + --mat-mdc-button-persistent-ripple-color: var(--white); } .mat-mdc-stroked-button { - --mdc-outlined-button-outline-color: rgba(0, 108, 79, 0.30); - --mdc-outlined-button-label-text-color: #006c4f; + --mdc-outlined-button-outline-color: rgba(var(--color-brand-rgb), 0.30); + --mdc-outlined-button-label-text-color: var(--color-brand); } .mat-mdc-stroked-button:hover { - --mdc-outlined-button-outline-color: #006c4f; - background-color: rgba(0, 108, 79, 0.06) !important; + --mdc-outlined-button-outline-color: var(--color-brand); + background-color: rgba(var(--color-brand-rgb), 0.06) !important; } } /* ─── Cards & dialogs picked up by the same brand surface ── */ .cce-app-shell__main-inner .mat-mdc-card { - border: 1px solid rgba(0, 60, 44, 0.08); + border: 1px solid rgba(var(--color-brand-shadow-rgb), 0.08); border-radius: 16px !important; - box-shadow: 0 8px 22px -18px rgba(0, 48, 31, 0.20) !important; + box-shadow: 0 8px 22px -18px rgba(var(--color-brand-shadow-rgb), 0.20) !important; } .cce-app-shell__main-inner .mat-mdc-card-title { font-weight: 800 !important; letter-spacing: -0.01em; - color: #1c2724 !important; + color: var(--color-text-primary) !important; +} + +/* ── Global input height: 48px (Material default: 56px) ───── */ +.mat-mdc-form-field { + --mdc-outlined-text-field-container-height: 48px; + --mat-form-field-container-height: 48px; + --mat-form-field-container-vertical-padding: 12px; } diff --git a/frontend/apps/admin-cms/src/_bootstrap-grid.scss b/frontend/apps/admin-cms/src/_bootstrap-grid.scss deleted file mode 100644 index dd1edc54..00000000 --- a/frontend/apps/admin-cms/src/_bootstrap-grid.scss +++ /dev/null @@ -1,12 +0,0 @@ -// Bootstrap 5 grid + utilities ONLY (not components, per ADR-0003). -// Uses @import (deprecated but still supported) because Bootstrap 5.3's modular -// partials are not @use-safe — _variables.scss calls a mixin from _mixins.scss -// expecting the legacy @import-based scope. Deltas: ~15 KB vs full Bootstrap's ~190 KB. -@import "bootstrap/scss/functions"; -@import "bootstrap/scss/variables"; -@import "bootstrap/scss/variables-dark"; -@import "bootstrap/scss/maps"; -@import "bootstrap/scss/mixins"; -@import "bootstrap/scss/utilities"; -@import "bootstrap/scss/grid"; -@import "bootstrap/scss/utilities/api"; diff --git a/frontend/apps/admin-cms/src/_fancy.scss b/frontend/apps/admin-cms/src/_fancy.scss index cc8b2f77..2b7752b6 100644 --- a/frontend/apps/admin-cms/src/_fancy.scss +++ b/frontend/apps/admin-cms/src/_fancy.scss @@ -17,28 +17,25 @@ 1. CSS variables — gradient + motion + glass tokens ========================================================= */ :root { - --cce-fancy-grad-brand: linear-gradient(135deg, #006c4f 0%, #0f8b6c 45%, #c8a045 100%); + --cce-fancy-grad-brand: linear-gradient(135deg, var(--color-brand) 0%, var(--color-brand-mid) 45%, var(--color-accent) 100%); --cce-fancy-grad-brand-soft: - radial-gradient(1200px 600px at 12% -10%, rgba(0, 108, 79, 0.18), transparent 60%), - radial-gradient(900px 500px at 110% 110%, rgba(200, 160, 69, 0.20), transparent 55%); - --cce-fancy-grad-hero: - radial-gradient(1400px 700px at 20% 0%, rgba(15, 139, 108, 0.10), transparent 55%), - radial-gradient(1100px 700px at 100% 100%, rgba(244, 163, 0, 0.12), transparent 50%), - linear-gradient(180deg, #fafafa 0%, #f1f5f4 100%); + radial-gradient(1200px 600px at 12% -10%, rgba(var(--color-brand-rgb), 0.18), transparent 60%), + radial-gradient(900px 500px at 110% 110%, rgba(var(--color-accent-rgb), 0.20), transparent 55%); + --cce-fancy-grad-hero: var(--neutrals--50); --cce-fancy-glass-bg: rgba(255, 255, 255, 0.72); --cce-fancy-glass-bg-strong: rgba(255, 255, 255, 0.88); - --cce-fancy-glass-border: 1px solid rgba(0, 108, 79, 0.10); - --cce-fancy-glass-blur: blur(14px) saturate(140%); - --cce-fancy-shadow-soft: 0 6px 22px -8px rgba(0, 48, 31, 0.18); - --cce-fancy-shadow-hover: 0 14px 40px -10px rgba(0, 48, 31, 0.30); - --cce-fancy-shadow-glow: 0 0 0 6px rgba(0, 108, 79, 0.10); - --cce-fancy-ring: 0 0 0 3px rgba(15, 139, 108, 0.45); + --cce-fancy-glass-border: 1px solid rgba(var(--color-brand-rgb), 0.10); + --cce-fancy-glass-blur: blur(10px) saturate(140%); + --cce-fancy-shadow-soft: 0 6px 22px -8px rgba(var(--color-brand-shadow-rgb), 0.18); + --cce-fancy-shadow-hover: 0 14px 40px -10px rgba(var(--color-brand-shadow-rgb), 0.30); + --cce-fancy-shadow-glow: 0 0 0 6px rgba(var(--color-brand-rgb), 0.10); + --cce-fancy-ring: 0 0 0 3px rgba(var(--color-brand-mid-rgb), 0.45); --cce-fancy-easing-emphasized: cubic-bezier(0.22, 1, 0.36, 1); --cce-fancy-easing-soft: cubic-bezier(0.4, 0, 0.2, 1); - --cce-fancy-accent: #c8a045; - --cce-fancy-accent-bright: #f4a300; - --cce-fancy-primary: #006c4f; - --cce-fancy-primary-bright: #0f8b6c; + --cce-fancy-accent: var(--color-accent); + --cce-fancy-accent-bright: var(--warning--400); + --cce-fancy-primary: var(--color-brand); + --cce-fancy-primary-bright: var(--color-brand-mid); } /* ========================================================= @@ -50,16 +47,14 @@ html { } ::selection { - background: rgba(15, 139, 108, 0.28); + background: rgba(var(--color-brand-mid-rgb), 0.28); color: var(--cce-fancy-primary); } -/* Subtle gradient backdrop on the body so flat white surfaces don't - feel sterile. Routed pages can override with their own background. */ +/* Flat app background (token). Routed pages can override their own. */ body { background: var(--cce-fancy-grad-hero) !important; - background-attachment: fixed !important; - color: #1c2724; + color: var(--color-text-primary); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-rendering: optimizeLegibility; @@ -70,7 +65,7 @@ body { ========================================================= */ * { scrollbar-width: thin; - scrollbar-color: rgba(0, 108, 79, 0.35) transparent; + scrollbar-color: rgba(var(--color-brand-rgb), 0.35) transparent; } *::-webkit-scrollbar { width: 10px; @@ -80,21 +75,21 @@ body { background: transparent; } *::-webkit-scrollbar-thumb { - background: linear-gradient(180deg, rgba(0, 108, 79, 0.40), rgba(15, 139, 108, 0.35)); + background: linear-gradient(180deg, rgba(var(--color-brand-rgb), 0.40), rgba(var(--color-brand-mid-rgb), 0.35)); border-radius: 999px; border: 2px solid transparent; background-clip: padding-box; transition: background 0.2s; } *::-webkit-scrollbar-thumb:hover { - background: linear-gradient(180deg, rgba(0, 108, 79, 0.65), rgba(15, 139, 108, 0.6)); + background: linear-gradient(180deg, rgba(var(--color-brand-rgb), 0.65), rgba(var(--color-brand-mid-rgb), 0.6)); background-clip: padding-box; } /* ========================================================= 4. Universal focus ring — keyboard accessibility upgrade ========================================================= */ -:focus-visible { +:focus-visible:not(.mat-mdc-input-element):not(.mat-mdc-form-field-input-control) { outline: none !important; box-shadow: var(--cce-fancy-ring) !important; border-radius: 6px; @@ -126,7 +121,7 @@ body { mat-card, .mat-mdc-card { border-radius: 8px !important; - background: #ffffff !important; + background: var(--white) !important; backdrop-filter: none !important; -webkit-backdrop-filter: none !important; } @@ -168,7 +163,7 @@ mat-card, .mat-mdc-raised-button:hover, .mat-mdc-flat-button:hover { transform: translateY(-1px); - box-shadow: 0 6px 18px -6px rgba(0, 108, 79, 0.40) !important; + box-shadow: 0 6px 18px -6px rgba(var(--color-brand-rgb), 0.40) !important; } .mat-mdc-raised-button:hover::after, .mat-mdc-flat-button:hover::after { @@ -178,27 +173,27 @@ mat-card, /* Stroked / outlined buttons — branded green border */ .mat-mdc-stroked-button, .mat-mdc-outlined-button { - --mdc-outlined-button-outline-color: rgba(0, 108, 79, 0.40); - --mdc-outlined-button-label-text-color: #006c4f; + --mdc-outlined-button-outline-color: rgba(var(--color-brand-rgb), 0.40); + --mdc-outlined-button-label-text-color: var(--color-brand); } .mat-mdc-stroked-button:hover, .mat-mdc-outlined-button:hover { - background: rgba(15, 139, 108, 0.08) !important; - border-color: #006c4f !important; + background: rgba(var(--color-brand-mid-rgb), 0.08) !important; + border-color: var(--color-brand) !important; transform: translateY(-1px); } /* Text (basic) buttons — subtle hover tint */ .mat-mdc-button:hover:not([disabled]):not(.mat-mdc-icon-button) { - background: rgba(15, 139, 108, 0.08) !important; + background: rgba(var(--color-brand-mid-rgb), 0.08) !important; } /* Icon buttons — circular brand-tint hover */ .mat-mdc-icon-button { - --mat-mdc-button-persistent-ripple-color: rgba(15, 139, 108, 0.32); + --mat-mdc-button-persistent-ripple-color: rgba(var(--color-brand-mid-rgb), 0.32); transition: background-color 0.18s ease, transform 0.18s ease; &:hover:not([disabled]) { - background: rgba(15, 139, 108, 0.10) !important; + background: rgba(var(--color-brand-mid-rgb), 0.10) !important; transform: scale(1.05); } } @@ -220,17 +215,17 @@ mat-card, .mat-mdc-fab, .mat-mdc-mini-fab, .mat-mdc-extended-fab { - background: linear-gradient(135deg, #006c4f 0%, #14b88f 100%) !important; - color: #fff !important; + background: linear-gradient(135deg, var(--color-brand) 0%, var(--color-brand-accent) 100%) !important; + color: var(--white) !important; box-shadow: - 0 6px 18px -4px rgba(15, 139, 108, 0.55), + 0 6px 18px -4px rgba(var(--color-brand-mid-rgb), 0.55), 0 0 0 1px rgba(255, 255, 255, 0.20) inset !important; transition: transform 0.20s var(--cce-fancy-easing-emphasized), box-shadow 0.20s var(--cce-fancy-easing-emphasized) !important; &:hover { transform: translateY(-2px) scale(1.03); box-shadow: - 0 12px 28px -6px rgba(15, 139, 108, 0.65), + 0 12px 28px -6px rgba(var(--color-brand-mid-rgb), 0.65), 0 0 0 1px rgba(255, 255, 255, 0.30) inset !important; } } @@ -252,47 +247,41 @@ mat-card, .mat-mdc-form-field { /* CSS variables Material exposes — re-tinted to brand */ --mdc-outlined-text-field-container-shape: 10px; - --mdc-outlined-text-field-outline-color: rgba(0, 108, 79, 0.18); - --mdc-outlined-text-field-hover-outline-color: rgba(0, 108, 79, 0.45); - --mdc-outlined-text-field-focus-outline-color: #006c4f; - --mdc-outlined-text-field-error-outline-color: #dc2626; - --mdc-outlined-text-field-error-hover-outline-color: #b91c1c; - --mdc-outlined-text-field-error-focus-outline-color: #dc2626; - --mdc-outlined-text-field-label-text-color: rgba(28, 39, 36, 0.62); - --mdc-outlined-text-field-hover-label-text-color: rgba(28, 39, 36, 0.85); - --mdc-outlined-text-field-focus-label-text-color: #006c4f; - --mdc-outlined-text-field-input-text-color: #1c2724; - --mdc-outlined-text-field-input-text-placeholder-color: rgba(28, 39, 36, 0.45); + --mdc-outlined-text-field-outline-color: rgba(0, 0, 0, 0.38); + --mdc-outlined-text-field-hover-outline-color: rgba(var(--color-brand-rgb), 0.6); + --mdc-outlined-text-field-focus-outline-color: var(--color-brand); + --mdc-outlined-text-field-error-outline-color: var(--danger--500); + --mdc-outlined-text-field-error-hover-outline-color: var(--danger--600); + --mdc-outlined-text-field-error-focus-outline-color: var(--danger--500); + --mdc-outlined-text-field-label-text-color: rgba(var(--color-text-primary-rgb), 0.62); + --mdc-outlined-text-field-hover-label-text-color: rgba(var(--color-text-primary-rgb), 0.85); + --mdc-outlined-text-field-focus-label-text-color: var(--color-brand); + --mdc-outlined-text-field-input-text-color: var(--color-text-primary); + --mdc-outlined-text-field-input-text-placeholder-color: rgba(var(--color-text-primary-rgb), 0.45); --mdc-outlined-text-field-disabled-outline-color: rgba(0, 0, 0, 0.10); - --mdc-outlined-text-field-disabled-input-text-color: rgba(28, 39, 36, 0.40); + --mdc-outlined-text-field-disabled-input-text-color: rgba(var(--color-text-primary-rgb), 0.40); /* For filled variant */ - --mdc-filled-text-field-container-color: rgba(15, 139, 108, 0.05); - --mdc-filled-text-field-hover-state-layer-color: rgba(15, 139, 108, 0.08); - --mdc-filled-text-field-focus-state-layer-color: rgba(15, 139, 108, 0.10); - --mdc-filled-text-field-active-indicator-color: rgba(0, 108, 79, 0.32); - --mdc-filled-text-field-hover-active-indicator-color: #006c4f; - --mdc-filled-text-field-focus-active-indicator-color: #006c4f; + --mdc-filled-text-field-container-color: rgba(var(--color-brand-mid-rgb), 0.05); + --mdc-filled-text-field-hover-state-layer-color: rgba(var(--color-brand-mid-rgb), 0.08); + --mdc-filled-text-field-focus-state-layer-color: rgba(var(--color-brand-mid-rgb), 0.10); + --mdc-filled-text-field-active-indicator-color: rgba(var(--color-brand-rgb), 0.32); + --mdc-filled-text-field-hover-active-indicator-color: var(--color-brand); + --mdc-filled-text-field-focus-active-indicator-color: var(--color-brand); } -/* Soft glow ring around outlined fields on focus */ -.mat-mdc-text-field-wrapper.mdc-text-field--outlined:focus-within { - box-shadow: 0 0 0 3px rgba(15, 139, 108, 0.15); - border-radius: 10px; - transition: box-shadow 0.20s var(--cce-fancy-easing-soft); -} /* Filled variant — smooth corners + soft hover lift */ .mdc-text-field--filled:not(.mdc-text-field--disabled) { - background-color: rgba(15, 139, 108, 0.05) !important; + background-color: rgba(var(--color-brand-mid-rgb), 0.05) !important; border-radius: 12px 12px 0 0 !important; transition: background-color 0.20s, box-shadow 0.20s; } .mdc-text-field--filled:not(.mdc-text-field--disabled):hover { - background-color: rgba(15, 139, 108, 0.10) !important; + background-color: rgba(var(--color-brand-mid-rgb), 0.10) !important; } .mat-mdc-form-field-focus-overlay { - background-color: rgba(15, 139, 108, 0.06) !important; + background-color: rgba(var(--color-brand-mid-rgb), 0.06) !important; } /* Floating label tightening */ @@ -306,14 +295,14 @@ mat-card, /* Hint text more legible */ .mat-mdc-form-field-hint { - color: rgba(28, 39, 36, 0.55) !important; + color: rgba(var(--color-text-primary-rgb), 0.55) !important; font-size: 0.78rem !important; letter-spacing: 0.005em; } /* Error message — branded red, inline-icon vibe */ .mat-mdc-form-field-error { - color: #dc2626 !important; + color: var(--danger--500) !important; font-weight: 500 !important; font-size: 0.78rem !important; letter-spacing: 0.005em; @@ -326,42 +315,61 @@ mat-card, /* Required asterisk — brand-amber so it doesn't read as error */ .mat-mdc-form-field-required-marker { - color: #d97706 !important; + color: var(--warning--500) !important; } /* ── Inputs / textareas (any variant) ───────────────────── */ .mat-mdc-input-element, .mdc-text-field input.mat-mdc-form-field-input-control, .mdc-text-field textarea.mat-mdc-form-field-input-control { - caret-color: #006c4f !important; + caret-color: var(--color-brand) !important; letter-spacing: -0.005em; } .mat-mdc-input-element::placeholder { - color: rgba(28, 39, 36, 0.45) !important; + color: rgba(var(--color-text-primary-rgb), 0.45) !important; font-weight: 500; } /* Prefix / suffix icons inside form fields */ .mat-mdc-form-field-icon-prefix mat-icon, .mat-mdc-form-field-icon-suffix mat-icon { - color: rgba(15, 139, 108, 0.65) !important; + color: rgba(var(--color-brand-mid-rgb), 0.65) !important; transition: color 0.18s ease; } .mat-mdc-form-field.mat-focused .mat-mdc-form-field-icon-prefix mat-icon, .mat-mdc-form-field.mat-focused .mat-mdc-form-field-icon-suffix mat-icon { - color: #006c4f !important; + color: var(--color-brand) !important; +} + +/* ── RTL fix: floating label overlaps with matPrefix icon ── */ +// Angular Material computes the prefix width and applies it as `padding-left` +// on the label element (correct in LTR). In RTL, that padding-left physically +// pushes the label text toward the prefix icon instead of away from it. +[dir="rtl"] { + .mat-mdc-form-field .mdc-floating-label { + // Cancel the wrong LTR-direction offset Angular Material set in JS. + padding-left: 0 !important; + } + + // Re-apply the offset on the correct side for single-icon prefix fields. + // 52px = icon (24px) + prefix container padding (~16px) + infix gap (~12px). + .mat-mdc-form-field:has(.mat-mdc-form-field-icon-prefix) { + .mdc-floating-label:not(.mdc-floating-label--float-above) { + padding-inline-start: 52px !important; + } + } } /* ── Mat-select arrow + value ───────────────────────────── */ .mat-mdc-select-arrow { - color: rgba(15, 139, 108, 0.65) !important; + color: rgba(var(--color-brand-mid-rgb), 0.65) !important; transition: transform 0.20s var(--cce-fancy-easing-emphasized), color 0.18s ease; } .mat-mdc-select-trigger:hover .mat-mdc-select-arrow { - color: #006c4f !important; + color: var(--color-brand) !important; } .mat-mdc-form-field.mat-focused .mat-mdc-select-arrow { - color: #006c4f !important; + color: var(--color-brand) !important; transform: rotate(180deg); } .mat-mdc-select-value-text { font-weight: 500; } @@ -376,27 +384,27 @@ mat-card, } .mat-mdc-option:hover:not(.mdc-list-item--disabled), .mat-mdc-option.mdc-list-item--selected:not(.mdc-list-item--disabled) { - background: rgba(15, 139, 108, 0.10) !important; - color: #006c4f !important; + background: rgba(var(--color-brand-mid-rgb), 0.10) !important; + color: var(--color-brand) !important; } .mat-mdc-option.mdc-list-item--selected:not(.mdc-list-item--disabled) { font-weight: 700 !important; - background: linear-gradient(90deg, rgba(15, 139, 108, 0.14), rgba(200, 160, 69, 0.06)) !important; + background: linear-gradient(90deg, rgba(var(--color-brand-mid-rgb), 0.14), rgba(var(--color-accent-rgb), 0.06)) !important; } .mat-pseudo-checkbox-checked.mat-pseudo-checkbox-minimal::after { - color: #006c4f !important; + color: var(--color-brand) !important; } /* ── Checkboxes ─────────────────────────────────────────── */ .mat-mdc-checkbox { - --mdc-checkbox-selected-checkmark-color: #ffffff; - --mdc-checkbox-selected-focus-icon-color: #006c4f; - --mdc-checkbox-selected-hover-icon-color: #006c4f; - --mdc-checkbox-selected-icon-color: #006c4f; - --mdc-checkbox-selected-pressed-icon-color: #006c4f; - --mdc-checkbox-unselected-focus-icon-color: rgba(0, 108, 79, 0.55); - --mdc-checkbox-unselected-hover-icon-color: rgba(0, 108, 79, 0.55); - --mdc-checkbox-unselected-icon-color: rgba(28, 39, 36, 0.45); + --mdc-checkbox-selected-checkmark-color: var(--white); + --mdc-checkbox-selected-focus-icon-color: var(--color-brand); + --mdc-checkbox-selected-hover-icon-color: var(--color-brand); + --mdc-checkbox-selected-icon-color: var(--color-brand); + --mdc-checkbox-selected-pressed-icon-color: var(--color-brand); + --mdc-checkbox-unselected-focus-icon-color: rgba(var(--color-brand-rgb), 0.55); + --mdc-checkbox-unselected-hover-icon-color: rgba(var(--color-brand-rgb), 0.55); + --mdc-checkbox-unselected-icon-color: rgba(var(--color-text-primary-rgb), 0.45); --mdc-checkbox-state-layer-size: 36px; } .mat-mdc-checkbox label { @@ -406,31 +414,31 @@ mat-card, /* ── Radio buttons ──────────────────────────────────────── */ .mat-mdc-radio-button { - --mdc-radio-selected-focus-icon-color: #006c4f; - --mdc-radio-selected-hover-icon-color: #006c4f; - --mdc-radio-selected-icon-color: #006c4f; - --mdc-radio-selected-pressed-icon-color: #006c4f; - --mdc-radio-unselected-focus-icon-color: rgba(0, 108, 79, 0.55); - --mdc-radio-unselected-hover-icon-color: rgba(0, 108, 79, 0.55); - --mdc-radio-unselected-icon-color: rgba(28, 39, 36, 0.45); + --mdc-radio-selected-focus-icon-color: var(--color-brand); + --mdc-radio-selected-hover-icon-color: var(--color-brand); + --mdc-radio-selected-icon-color: var(--color-brand); + --mdc-radio-selected-pressed-icon-color: var(--color-brand); + --mdc-radio-unselected-focus-icon-color: rgba(var(--color-brand-rgb), 0.55); + --mdc-radio-unselected-hover-icon-color: rgba(var(--color-brand-rgb), 0.55); + --mdc-radio-unselected-icon-color: rgba(var(--color-text-primary-rgb), 0.45); } /* ── Slide-toggle (gradient when checked) ────────────────── */ .mat-mdc-slide-toggle { - --mdc-switch-selected-track-color: #14b88f; - --mdc-switch-selected-hover-track-color: #14b88f; - --mdc-switch-selected-pressed-track-color: #006c4f; - --mdc-switch-selected-focus-track-color: #14b88f; - --mdc-switch-selected-handle-color: #ffffff; - --mdc-switch-selected-hover-handle-color: #ffffff; - --mdc-switch-selected-pressed-handle-color: #ffffff; - --mdc-switch-selected-focus-handle-color: #ffffff; - --mdc-switch-selected-icon-color: #006c4f; + --mdc-switch-selected-track-color: var(--color-brand-accent); + --mdc-switch-selected-hover-track-color: var(--color-brand-accent); + --mdc-switch-selected-pressed-track-color: var(--color-brand); + --mdc-switch-selected-focus-track-color: var(--color-brand-accent); + --mdc-switch-selected-handle-color: var(--white); + --mdc-switch-selected-hover-handle-color: var(--white); + --mdc-switch-selected-pressed-handle-color: var(--white); + --mdc-switch-selected-focus-handle-color: var(--white); + --mdc-switch-selected-icon-color: var(--color-brand); --mdc-switch-handle-shape: 999px; --mdc-switch-track-shape: 999px; } .mat-mdc-slide-toggle.mat-mdc-slide-toggle-checked .mdc-switch__track::after { - background: linear-gradient(135deg, #006c4f 0%, #14b88f 100%) !important; + background: linear-gradient(135deg, var(--color-brand) 0%, var(--color-brand-accent) 100%) !important; } .mat-mdc-slide-toggle label { letter-spacing: -0.005em !important; @@ -439,41 +447,41 @@ mat-card, /* ── Date picker ─────────────────────────────────────────── */ .mat-datepicker-toggle .mat-mdc-icon-button mat-icon { - color: rgba(15, 139, 108, 0.65); + color: rgba(var(--color-brand-mid-rgb), 0.65); transition: color 0.18s ease; } .mat-datepicker-toggle:hover .mat-mdc-icon-button mat-icon { - color: #006c4f; + color: var(--color-brand); } .mat-datepicker-content { border-radius: 14px !important; box-shadow: var(--cce-fancy-shadow-hover) !important; } .mat-calendar-body-selected { - background: linear-gradient(135deg, #006c4f 0%, #14b88f 100%) !important; - color: #fff !important; + background: linear-gradient(135deg, var(--color-brand) 0%, var(--color-brand-accent) 100%) !important; + color: var(--white) !important; } .mat-calendar-body-today:not(.mat-calendar-body-selected) { - border-color: #006c4f !important; + border-color: var(--color-brand) !important; } /* ── Chips (filter / input chips) ────────────────────────── */ .mat-mdc-chip { --mdc-chip-container-shape: 999px; - --mdc-chip-elevated-container-color: rgba(15, 139, 108, 0.08); - --mdc-chip-label-text-color: #1c2724; + --mdc-chip-elevated-container-color: rgba(var(--color-brand-mid-rgb), 0.08); + --mdc-chip-label-text-color: var(--color-text-primary); font-weight: 600 !important; letter-spacing: 0.005em; transition: background-color 0.18s, transform 0.18s; } .mat-mdc-chip:hover { - background: rgba(15, 139, 108, 0.14) !important; + background: rgba(var(--color-brand-mid-rgb), 0.14) !important; transform: translateY(-1px); } .mat-mdc-chip.mat-mdc-chip-selected { - background: linear-gradient(135deg, #006c4f, #14b88f) !important; - color: #ffffff !important; - --mdc-chip-label-text-color: #ffffff; + background: linear-gradient(135deg, var(--color-brand), var(--color-brand-accent)) !important; + color: var(--white) !important; + --mdc-chip-label-text-color: var(--white); } /* ── Native HTML inputs (fallback for non-Material) ────── */ @@ -481,9 +489,9 @@ input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type=" textarea:not(.mat-mdc-input-element):not(.mat-mdc-form-field-input-control), select:not(.mat-mdc-select):not(.mat-mdc-form-field-input-control) { font: inherit; - color: #1c2724; - background: #ffffff; - border: 1px solid rgba(0, 108, 79, 0.18); + color: var(--color-text-primary); + background: var(--white); + border: 1px solid rgba(var(--color-brand-rgb), 0.18); border-radius: 8px; padding: 0.55rem 0.75rem; letter-spacing: -0.005em; @@ -491,20 +499,20 @@ select:not(.mat-mdc-select):not(.mat-mdc-form-field-input-control) { transition: border-color 0.18s, box-shadow 0.18s, background-color 0.18s; &::placeholder { - color: rgba(28, 39, 36, 0.45); + color: rgba(var(--color-text-primary-rgb), 0.45); font-weight: 500; } &:hover:not(:disabled):not([readonly]) { - border-color: rgba(0, 108, 79, 0.40); + border-color: rgba(var(--color-brand-rgb), 0.40); } &:focus:not(:disabled):not([readonly]) { - border-color: #006c4f; - box-shadow: 0 0 0 3px rgba(15, 139, 108, 0.18); + border-color: var(--color-brand); + box-shadow: 0 0 0 3px rgba(var(--color-brand-mid-rgb), 0.18); } &:disabled, &[readonly] { background: rgba(0, 0, 0, 0.03); - color: rgba(28, 39, 36, 0.50); + color: rgba(var(--color-text-primary-rgb), 0.50); border-color: rgba(0, 0, 0, 0.08); cursor: not-allowed; } @@ -513,7 +521,7 @@ select:not(.mat-mdc-select):not(.mat-mdc-form-field-input-control) { /* Native checkbox / radio — accent color */ input[type="checkbox"]:not(.mat-mdc-input-element), input[type="radio"]:not(.mat-mdc-input-element) { - accent-color: #006c4f; + accent-color: var(--color-brand); cursor: pointer; } @@ -525,7 +533,7 @@ input[type="search"]::-webkit-search-cancel-button { /* ── Form layout — better label/group spacing ──────────── */ fieldset:not(.mat-mdc-form-field) { - border: 1px solid rgba(0, 108, 79, 0.10); + border: 1px solid rgba(var(--color-brand-rgb), 0.10); border-radius: 12px; padding: 1rem 1.25rem 1.25rem; margin-block: 0.5rem 1.25rem; @@ -536,14 +544,14 @@ legend:not(.mat-mdc-form-field-label) { font-weight: 700; letter-spacing: 0.10em; text-transform: uppercase; - color: #006c4f; + color: var(--color-brand); } label:not(.mat-mdc-checkbox label):not(.mat-mdc-slide-toggle label):not(.mat-mdc-radio-button label):not(.mdc-floating-label):not(.mat-mdc-form-field-label) { display: inline-block; font-size: 0.85rem; font-weight: 600; - color: rgba(28, 39, 36, 0.78); + color: rgba(var(--color-text-primary-rgb), 0.78); margin-bottom: 0.3rem; letter-spacing: 0.005em; } @@ -569,7 +577,7 @@ label:not(.mat-mdc-checkbox label):not(.mat-mdc-slide-toggle label):not(.mat-mdc /* Snackbar — branded gradient */ .mat-mdc-snack-bar-container { - --mdc-snackbar-container-color: rgba(0, 48, 31, 0.95) !important; + --mdc-snackbar-container-color: rgba(var(--color-brand-shadow-rgb), 0.95) !important; --mat-mdc-snack-bar-button-color: var(--cce-fancy-accent-bright) !important; border-radius: 12px !important; box-shadow: var(--cce-fancy-shadow-hover) !important; @@ -577,8 +585,8 @@ label:not(.mat-mdc-checkbox label):not(.mat-mdc-slide-toggle label):not(.mat-mdc /* Tooltip — softer, branded edge */ .mat-mdc-tooltip { - --mdc-plain-tooltip-container-color: rgba(0, 48, 31, 0.94) !important; - --mdc-plain-tooltip-supporting-text-color: #fff !important; + --mdc-plain-tooltip-container-color: rgba(var(--color-brand-shadow-rgb), 0.94) !important; + --mdc-plain-tooltip-supporting-text-color: var(--white) !important; border-radius: 8px !important; font-size: 12px !important; letter-spacing: 0.02em; @@ -588,17 +596,17 @@ label:not(.mat-mdc-checkbox label):not(.mat-mdc-slide-toggle label):not(.mat-mdc /* Chips (filter chips) — branded gradient on selected */ .mat-mdc-chip.mat-mdc-chip-selected.mat-primary { background: var(--cce-fancy-grad-brand) !important; - color: #fff !important; + color: var(--white) !important; } /* Mat-icon-button — circular hover ring */ .mat-mdc-icon-button:hover { - background: rgba(15, 139, 108, 0.10) !important; + background: rgba(var(--color-brand-mid-rgb), 0.10) !important; } /* Toolbar — subtle glass when used as a header */ .mat-toolbar.mat-primary { - background: linear-gradient(135deg, #006c4f 0%, #008c66 100%) !important; + background: linear-gradient(135deg, var(--color-brand) 0%, var(--color-brand) 100%) !important; box-shadow: 0 1px 0 rgba(255, 255, 255, 0.12) inset, var(--cce-fancy-shadow-soft) !important; } @@ -675,8 +683,8 @@ label:not(.mat-mdc-checkbox label):not(.mat-mdc-slide-toggle label):not(.mat-mdc padding: 1px; background: var(--cce-fancy-grad-brand); -webkit-mask: - linear-gradient(#000 0 0) content-box, - linear-gradient(#000 0 0); + linear-gradient(var(--black) 0 0) content-box, + linear-gradient(var(--black) 0 0); -webkit-mask-composite: xor; mask-composite: exclude; pointer-events: none; @@ -753,8 +761,8 @@ cce-footer { /* No top margin: the footer sits flush against the routed content so full-bleed pages don't show a strip of body backdrop above it. */ margin-top: 0; - background: linear-gradient(180deg, transparent 0%, rgba(0, 48, 31, 0.04) 25%, rgba(0, 48, 31, 0.08) 100%); - border-top: 1px solid rgba(0, 108, 79, 0.10); + background: linear-gradient(180deg, transparent 0%, rgba(var(--color-brand-shadow-rgb), 0.04) 25%, rgba(var(--color-brand-shadow-rgb), 0.08) 100%); + border-top: 1px solid rgba(var(--color-brand-rgb), 0.10); } /* ========================================================= @@ -762,9 +770,9 @@ cce-footer { ========================================================= */ .cce-fancy-skeleton { background: linear-gradient(90deg, - rgba(0, 108, 79, 0.06) 0%, - rgba(0, 108, 79, 0.14) 50%, - rgba(0, 108, 79, 0.06) 100%); + rgba(var(--color-brand-rgb), 0.06) 0%, + rgba(var(--color-brand-rgb), 0.14) 50%, + rgba(var(--color-brand-rgb), 0.06) 100%); background-size: 200% 100%; animation: cceShimmer 1.4s ease-in-out infinite; border-radius: 8px; diff --git a/frontend/apps/admin-cms/src/app/app.component.html b/frontend/apps/admin-cms/src/app/app.component.html index bc934104..67e7bd4c 100644 --- a/frontend/apps/admin-cms/src/app/app.component.html +++ b/frontend/apps/admin-cms/src/app/app.component.html @@ -1 +1 @@ - + diff --git a/frontend/apps/admin-cms/src/app/app.component.spec.ts b/frontend/apps/admin-cms/src/app/app.component.spec.ts index 24938939..96f5ed17 100644 --- a/frontend/apps/admin-cms/src/app/app.component.spec.ts +++ b/frontend/apps/admin-cms/src/app/app.component.spec.ts @@ -3,7 +3,7 @@ import { provideHttpClientTesting } from '@angular/common/http/testing'; import { TestBed } from '@angular/core/testing'; import { provideRouter } from '@angular/router'; import { provideNoopAnimations } from '@angular/platform-browser/animations'; -import { TranslateModule } from '@ngx-translate/core'; +import { TranslocoModule } from '@jsverse/transloco'; import { OidcSecurityService } from 'angular-auth-oidc-client'; import { of } from 'rxjs'; import { LocaleService } from '@frontend/i18n'; @@ -13,7 +13,7 @@ import { AppComponent } from './app.component'; describe('AppComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [AppComponent, TranslateModule.forRoot()], + imports: [AppComponent, TranslocoModule.forRoot()], providers: [ provideHttpClient(), provideHttpClientTesting(), diff --git a/frontend/apps/admin-cms/src/app/app.component.ts b/frontend/apps/admin-cms/src/app/app.component.ts index 9dec8bea..d9032886 100644 --- a/frontend/apps/admin-cms/src/app/app.component.ts +++ b/frontend/apps/admin-cms/src/app/app.component.ts @@ -1,10 +1,10 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; -import { ShellComponent } from './core/layout/shell.component'; +import { RouterOutlet } from '@angular/router'; @Component({ selector: 'cce-root', standalone: true, - imports: [ShellComponent], + imports: [RouterOutlet], templateUrl: './app.component.html', changeDetection: ChangeDetectionStrategy.OnPush, }) diff --git a/frontend/apps/admin-cms/src/app/app.config.ts b/frontend/apps/admin-cms/src/app/app.config.ts index 11916594..34e81328 100644 --- a/frontend/apps/admin-cms/src/app/app.config.ts +++ b/frontend/apps/admin-cms/src/app/app.config.ts @@ -1,65 +1,56 @@ -import { provideHttpClient, withFetch, withInterceptors, HttpClient } from '@angular/common/http'; +import { provideHttpClient, withFetch, withInterceptors } from '@angular/common/http'; +import { ApplicationConfig, provideAppInitializer, provideZoneChangeDetection, inject, isDevMode } from '@angular/core'; +import { provideRouter } from '@angular/router'; +import { provideTransloco, TranslocoService } from '@jsverse/transloco'; +import { MAT_FORM_FIELD_DEFAULT_OPTIONS } from '@angular/material/form-field'; +import { apiEnvelopeInterceptor, serverErrorInterceptor, provideCceIcons } from '@frontend/ui-kit'; +import { localeInterceptor, LocaleService, TranslocoHttpLoader } from '@frontend/i18n'; +import { provideRealtime } from '@frontend/real-time'; +import { tokenInterceptor } from './core/http/token.interceptor'; import { authInterceptor } from './core/http/auth.interceptor'; -import { serverErrorInterceptor } from './core/http/server-error.interceptor'; import { correlationIdInterceptor } from './core/http/correlation-id.interceptor'; -import { ApplicationConfig, provideAppInitializer, provideZoneChangeDetection, inject } from '@angular/core'; -import { provideAnimationsAsync } from '@angular/platform-browser/animations/async'; -import { provideRouter } from '@angular/router'; -import { TranslateLoader, TranslateModule, TranslateService } from '@ngx-translate/core'; -import { provideAuth } from 'angular-auth-oidc-client'; -import { firstValueFrom } from 'rxjs'; -import { LocaleService } from '@frontend/i18n'; -import { buildCceOidcConfig } from '@frontend/auth'; import { appRoutes } from './app.routes'; import { AuthService } from './core/auth/auth.service'; import { EnvService } from './core/env.service'; -import { ngxTranslateHttpLoaderFactory } from './core/translate-loader.factory'; export const appConfig: ApplicationConfig = { providers: [ provideZoneChangeDetection({ eventCoalescing: true }), + { provide: MAT_FORM_FIELD_DEFAULT_OPTIONS, useValue: { appearance: 'outline' } }, + provideCceIcons(), provideRouter(appRoutes), provideHttpClient( withFetch(), - withInterceptors([correlationIdInterceptor, authInterceptor, serverErrorInterceptor]), + withInterceptors([localeInterceptor, correlationIdInterceptor, tokenInterceptor, serverErrorInterceptor, authInterceptor, apiEnvelopeInterceptor]), ), - provideAnimationsAsync(), - ...(TranslateModule.forRoot({ - loader: { - provide: TranslateLoader, - useFactory: ngxTranslateHttpLoaderFactory, - deps: [HttpClient], + provideTransloco({ + config: { + availableLangs: ['en', 'ar'], + defaultLang: 'ar', + reRenderOnLangChange: true, + prodMode: !isDevMode(), }, - defaultLanguage: 'ar', - }).providers ?? []), - // OIDC config is built dynamically AFTER env.json loads, so provideAuth uses a placeholder - // here and we re-configure it inside provideAppInitializer once env is available. - provideAuth({ - config: buildCceOidcConfig({ - authority: 'http://localhost:8080/realms/cce-internal', - clientId: 'cce-admin-cms', - redirectUri: - typeof window !== 'undefined' - ? `${window.location.origin}/auth/callback` - : 'http://localhost:4201/auth/callback', - postLogoutRedirectUri: - typeof window !== 'undefined' ? window.location.origin : 'http://localhost:4201', - }), + loader: TranslocoHttpLoader, }), provideAppInitializer(async () => { const env = inject(EnvService); - const translate = inject(TranslateService); + const translate = inject(TranslocoService); const locale = inject(LocaleService); const auth = inject(AuthService); await env.load(); - translate.setDefaultLang('ar'); - await firstValueFrom(translate.use(locale.locale())); - // Bootstrap user + permissions. Without this the side-nav stays - // empty (every nav item is gated by *ccePermission, and with - // currentUser = null every check fails). AuthService.refresh() - // tries /api/me first, then falls back to deriving the user - // and permissions from the cce-dev-role cookie. + translate.setActiveLang(locale.locale()); await auth.refresh(); }), + provideRealtime(() => { + const auth = inject(AuthService); + return { + // Relative path, same-origin — proxied to the Internal API hub (admin/ + // internal JWTs); the External hub only accepts external JWTs. + hubUrlFactory: () => '/hubs/notifications', + accessToken: auth.accessToken, + isAuthenticated: auth.isAuthenticated, + debug: isDevMode(), + }; + }), ], }; diff --git a/frontend/apps/admin-cms/src/app/app.routes.ts b/frontend/apps/admin-cms/src/app/app.routes.ts index dc06adfb..b4bdfc33 100644 --- a/frontend/apps/admin-cms/src/app/app.routes.ts +++ b/frontend/apps/admin-cms/src/app/app.routes.ts @@ -1,127 +1,168 @@ import { Route } from '@angular/router'; -import { devAuthGuard } from './core/auth/dev-auth.guard'; -import { AuthCallbackPage } from './auth-callback/auth-callback.page'; -import { ProfilePage } from './profile/profile.page'; +import { CcePermission } from '@frontend/contracts'; +import { authGuard } from './core/auth/auth.guard'; +import { guestGuard } from './core/auth/guest.guard'; +import { permissionGuard } from './core/auth/permission.guard'; +import { ShellComponent } from './core/layout/shell.component'; +import { LoginPage } from './features/account/login.page'; +import { ProfilePage } from './features/account/profile.page'; +import { ForgotPasswordPage } from './features/account/forgot-password.page'; +import { ResetPasswordPage } from './features/account/reset-password.page'; export const appRoutes: Route[] = [ - { path: '', pathMatch: 'full', redirectTo: 'profile' }, - // Public OIDC redirect target — must NOT have devAuthGuard. - // angular-auth-oidc-client reads the URL params from this page and - // navigates the user to the originally-requested route once tokens - // are stored. - { path: 'auth/callback', component: AuthCallbackPage, title: 'CCE — Signing in…' }, - { - path: 'profile', - component: ProfilePage, - canActivate: [devAuthGuard], - title: 'CCE — Profile', - }, - { - path: 'users', - canActivate: [devAuthGuard], - loadChildren: () => import('./features/identity/routes').then((m) => m.IDENTITY_ROUTES), - title: 'CCE — Users', - }, - { - path: 'state-rep-assignments', - canActivate: [devAuthGuard], - loadChildren: () => - import('./features/identity/state-rep-routes').then((m) => m.STATE_REP_ROUTES), - title: 'CCE — State-Rep Assignments', - }, - { - path: 'experts', - canActivate: [devAuthGuard], - loadChildren: () => import('./features/experts/routes').then((m) => m.EXPERTS_ROUTES), - title: 'CCE — Experts', - }, - { - path: 'resources', - canActivate: [devAuthGuard], - loadChildren: () => - import('./features/content/routes').then((m) => m.RESOURCES_ROUTES), - title: 'CCE — Resources', - }, - { - path: 'country-resource-requests', - canActivate: [devAuthGuard], - loadChildren: () => - import('./features/content/routes').then((m) => m.COUNTRY_RESOURCE_REQUEST_ROUTES), - title: 'CCE — Country resource requests', - }, - { - path: 'news', - canActivate: [devAuthGuard], - loadChildren: () => import('./features/publishing/routes').then((m) => m.NEWS_ROUTES), - title: 'CCE — News', - }, - { - path: 'events', - canActivate: [devAuthGuard], - loadChildren: () => import('./features/publishing/routes').then((m) => m.EVENTS_ROUTES), - title: 'CCE — Events', - }, - { - path: 'pages', - canActivate: [devAuthGuard], - loadChildren: () => import('./features/publishing/routes').then((m) => m.PAGES_ROUTES), - title: 'CCE — Pages', - }, - { - path: 'homepage', - canActivate: [devAuthGuard], - loadChildren: () => import('./features/publishing/routes').then((m) => m.HOMEPAGE_ROUTES), - title: 'CCE — Homepage', - }, - { - path: 'taxonomies', - canActivate: [devAuthGuard], - loadChildren: () => import('./features/taxonomies/routes').then((m) => m.TAXONOMIES_ROUTES), - title: 'CCE — Taxonomies', - }, - { - path: 'community-moderation', - canActivate: [devAuthGuard], - loadChildren: () => - import('./features/community-moderation/routes').then((m) => m.COMMUNITY_MODERATION_ROUTES), - title: 'CCE — Community moderation', - }, - { - path: 'countries', - canActivate: [devAuthGuard], - loadChildren: () => import('./features/countries/routes').then((m) => m.COUNTRIES_ROUTES), - title: 'CCE — Countries', - }, - { - path: 'notifications', - canActivate: [devAuthGuard], - loadChildren: () => - import('./features/notifications/routes').then((m) => m.NOTIFICATIONS_ROUTES), - title: 'CCE — Notifications', - }, - { - path: 'reports', - canActivate: [devAuthGuard], - loadChildren: () => import('./features/reports/routes').then((m) => m.REPORTS_ROUTES), - title: 'CCE — Reports', - }, - { - path: 'audit', - canActivate: [devAuthGuard], - loadChildren: () => import('./features/audit/routes').then((m) => m.AUDIT_ROUTES), - title: 'CCE — Audit log', - }, - { - path: 'translations', - canActivate: [devAuthGuard], - loadChildren: () => - import('./features/translations/routes').then((m) => m.TRANSLATIONS_ROUTES), - title: 'CCE — Translations', - }, - { - path: 'settings', - canActivate: [devAuthGuard], - loadChildren: () => import('./features/settings/routes').then((m) => m.SETTINGS_ROUTES), - title: 'CCE — Settings', + { path: 'login', component: LoginPage, canActivate: [guestGuard], title: 'CCE Admin — Sign in' }, + { path: 'forgot-password', component: ForgotPasswordPage, canActivate: [guestGuard], title: 'CCE Admin — Forgot password' }, + { path: 'reset-password', component: ResetPasswordPage, canActivate: [guestGuard], title: 'CCE Admin — Reset password' }, + { + path: '', + component: ShellComponent, + canActivate: [authGuard], + children: [ + { path: '', pathMatch: 'full', redirectTo: 'profile' }, + { path: 'profile', component: ProfilePage, title: 'CCE — Profile' }, + { + path: 'users', + canMatch: [permissionGuard], + data: { permission: CcePermission.UserRead }, + loadChildren: () => import('./features/identity/routes').then((m) => m.IDENTITY_ROUTES), + title: 'CCE — Users', + }, + { + path: 'state-rep-assignments', + canMatch: [permissionGuard], + data: { permission: CcePermission.RoleAssign }, + loadChildren: () => + import('./features/identity/state-rep-routes').then((m) => m.STATE_REP_ROUTES), + title: 'CCE — State-Rep Assignments', + }, + { + path: 'experts', + canMatch: [permissionGuard], + data: { permission: CcePermission.CommunityExpertApprove }, + loadChildren: () => import('./features/experts/routes').then((m) => m.EXPERTS_ROUTES), + title: 'CCE — Experts', + }, + { + path: 'resources', + canMatch: [permissionGuard], + data: { permission: CcePermission.ResourceCenterUpload }, + loadChildren: () => import('./features/content/routes').then((m) => m.RESOURCES_ROUTES), + title: 'CCE — Resources', + }, + { + path: 'country-resource-requests', + canMatch: [permissionGuard], + data: { permission: CcePermission.ResourceCountryApprove }, + loadChildren: () => + import('./features/content/routes').then((m) => m.COUNTRY_RESOURCE_REQUEST_ROUTES), + title: 'CCE — Country resource requests', + }, + { + path: 'news', + canMatch: [permissionGuard], + data: { permission: CcePermission.NewsUpdate }, + loadChildren: () => import('./features/publishing/routes').then((m) => m.NEWS_ROUTES), + title: 'CCE — News', + }, + { + path: 'events', + canMatch: [permissionGuard], + data: { permission: CcePermission.EventManage }, + loadChildren: () => import('./features/publishing/routes').then((m) => m.EVENTS_ROUTES), + title: 'CCE — Events', + }, + { + path: 'pages', + canMatch: [permissionGuard], + data: { permission: CcePermission.PageEdit }, + loadChildren: () => import('./features/publishing/routes').then((m) => m.PAGES_ROUTES), + title: 'CCE — Pages', + }, + { + path: 'homepage', + canMatch: [permissionGuard], + data: { permission: CcePermission.PageEdit }, + loadChildren: () => import('./features/publishing/routes').then((m) => m.HOMEPAGE_ROUTES), + title: 'CCE — Homepage', + }, + { + path: 'about-settings', + canMatch: [permissionGuard], + data: { permission: CcePermission.PageEdit }, + loadChildren: () => + import('./features/publishing/routes').then((m) => m.ABOUT_SETTINGS_ROUTES), + title: 'CCE — About Settings', + }, + { + path: 'policies-settings', + canMatch: [permissionGuard], + data: { permission: CcePermission.SettingsManage }, + loadChildren: () => + import('./features/publishing/routes').then((m) => m.POLICIES_SETTINGS_ROUTES), + title: 'CCE — Policies Settings', + }, + { + path: 'taxonomies', + canMatch: [permissionGuard], + data: { permission: CcePermission.ResourceCenterUpload }, + loadChildren: () => + import('./features/taxonomies/routes').then((m) => m.TAXONOMIES_ROUTES), + title: 'CCE — Taxonomies', + }, + { + path: 'community-moderation', + canMatch: [permissionGuard], + data: { permission: CcePermission.CommunityPostModerate }, + loadChildren: () => + import('./features/community-moderation/routes').then( + (m) => m.COMMUNITY_MODERATION_ROUTES, + ), + title: 'CCE — Community moderation', + }, + { + path: 'countries', + canMatch: [permissionGuard], + data: { permission: CcePermission.CountryProfileUpdate }, + loadChildren: () => import('./features/countries/routes').then((m) => m.COUNTRIES_ROUTES), + title: 'CCE — Countries', + }, + { + path: 'notifications', + canMatch: [permissionGuard], + data: { permission: CcePermission.NotificationTemplateManage }, + loadChildren: () => + import('./features/notifications/routes').then((m) => m.NOTIFICATIONS_ROUTES), + title: 'CCE — Notifications', + }, + { + path: 'reports', + canMatch: [permissionGuard], + data: { permission: CcePermission.ReportUserRegistrations }, + loadChildren: () => import('./features/reports/routes').then((m) => m.REPORTS_ROUTES), + title: 'CCE — Reports', + }, + { + path: 'audit', + canMatch: [permissionGuard], + data: { permission: CcePermission.AuditRead }, + loadChildren: () => import('./features/audit/routes').then((m) => m.AUDIT_ROUTES), + title: 'CCE — Audit log', + }, + { + path: 'translations', + canMatch: [permissionGuard], + data: { permission: CcePermission.TranslationManage }, + loadChildren: () => + import('./features/translations/routes').then((m) => m.TRANSLATIONS_ROUTES), + title: 'CCE — Translations', + }, + { + path: 'settings', + canMatch: [permissionGuard], + data: { permission: CcePermission.SettingsManage }, + loadChildren: () => import('./features/settings/routes').then((m) => m.SETTINGS_ROUTES), + title: 'CCE — Settings', + }, + ], }, ]; diff --git a/frontend/apps/admin-cms/src/app/auth-callback/auth-callback.page.ts b/frontend/apps/admin-cms/src/app/auth-callback/auth-callback.page.ts deleted file mode 100644 index 71788785..00000000 --- a/frontend/apps/admin-cms/src/app/auth-callback/auth-callback.page.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { CommonModule } from '@angular/common'; -import { ChangeDetectionStrategy, Component } from '@angular/core'; -import { TranslateModule } from '@ngx-translate/core'; - -/** - * Public landing route for the OIDC redirect URI configured in - * `buildCceOidcConfig` (`${origin}/auth/callback`). The - * `angular-auth-oidc-client` library processes the URL fragment / query - * (id_token, code, error, etc.) inside its own bootstrap flow; this page - * just gives the router a target to match so it does not throw NG04002, - * and renders a "signing in" message during the brief moment between - * redirect and the library's auto-navigation back to the original route. - * - * No guard — anyone landing on /auth/callback during the redirect dance - * must be allowed in, even when not yet authenticated. - */ -@Component({ - selector: 'cce-auth-callback', - standalone: true, - imports: [CommonModule, TranslateModule], - template: ` -
-

{{ 'common.loading' | translate }}

-
- `, - styles: [ - `:host { display: block; padding: 2rem; text-align: center; } - .cce-auth-callback { color: rgba(0, 0, 0, 0.6); }`, - ], - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class AuthCallbackPage {} diff --git a/frontend/apps/admin-cms/src/app/auth-toolbar/auth-toolbar.component.html b/frontend/apps/admin-cms/src/app/auth-toolbar/auth-toolbar.component.html deleted file mode 100644 index d9455099..00000000 --- a/frontend/apps/admin-cms/src/app/auth-toolbar/auth-toolbar.component.html +++ /dev/null @@ -1,13 +0,0 @@ -@if (isAuthenticated()) { - - - {{ displayLabel() }} - - -} @else { - -} diff --git a/frontend/apps/admin-cms/src/app/auth-toolbar/auth-toolbar.component.spec.ts b/frontend/apps/admin-cms/src/app/auth-toolbar/auth-toolbar.component.spec.ts deleted file mode 100644 index 3446bac4..00000000 --- a/frontend/apps/admin-cms/src/app/auth-toolbar/auth-toolbar.component.spec.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { TranslateModule } from '@ngx-translate/core'; -import { OidcSecurityService } from 'angular-auth-oidc-client'; -import { of } from 'rxjs'; -import { AuthToolbarComponent } from './auth-toolbar.component'; - -describe('AuthToolbarComponent', () => { - let fixture: ComponentFixture; - let component: AuthToolbarComponent; - let oidc: jest.Mocked>; - - beforeEach(async () => { - oidc = { - authorize: jest.fn(), - logoff: jest.fn().mockReturnValue(of({})), - } as unknown as jest.Mocked>; - await TestBed.configureTestingModule({ - imports: [AuthToolbarComponent, TranslateModule.forRoot()], - providers: [ - { - provide: OidcSecurityService, - useValue: { ...oidc, isAuthenticated$: of({ isAuthenticated: false }) }, - }, - ], - }).compileComponents(); - fixture = TestBed.createComponent(AuthToolbarComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('signIn() invokes oidc.authorize()', () => { - component.signIn(); - expect(TestBed.inject(OidcSecurityService).authorize).toHaveBeenCalledTimes(1); - }); - - it('signOut() invokes oidc.logoff()', () => { - component.signOut(); - expect(TestBed.inject(OidcSecurityService).logoff).toHaveBeenCalledTimes(1); - }); -}); diff --git a/frontend/apps/admin-cms/src/app/auth-toolbar/auth-toolbar.component.ts b/frontend/apps/admin-cms/src/app/auth-toolbar/auth-toolbar.component.ts deleted file mode 100644 index 2c46838d..00000000 --- a/frontend/apps/admin-cms/src/app/auth-toolbar/auth-toolbar.component.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { MatButtonModule } from '@angular/material/button'; -import { TranslateModule } from '@ngx-translate/core'; -import { DevAuthService } from '../core/auth/dev-auth.service'; - -/** - * Auth toolbar — shows sign-in / sign-out + the current dev role label. - * - * Uses the cookie-based DevAuthService (replaces OidcSecurityService) - * which reads the `cce-dev-role` cookie set by the BFF's - * `/dev/sign-in?role=...` shim. No real OIDC provider needed in dev. - */ -@Component({ - selector: 'cce-auth-toolbar', - standalone: true, - imports: [CommonModule, MatButtonModule, TranslateModule], - templateUrl: './auth-toolbar.component.html', - styleUrl: './auth-toolbar.component.scss', - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class AuthToolbarComponent { - private readonly auth = inject(DevAuthService); - - readonly isAuthenticated = this.auth.isAuthenticated; - readonly displayLabel = this.auth.displayLabel; - - signIn(): void { - // Default to platform-admin role; the dev sign-in cookie shim - // bounces back to the current page after setting the cookie. - this.auth.signIn('cce-admin', window.location.pathname); - } - - signOut(): void { - this.auth.signOut(); - } -} diff --git a/frontend/apps/admin-cms/src/app/core/auth/auth-api.service.ts b/frontend/apps/admin-cms/src/app/core/auth/auth-api.service.ts new file mode 100644 index 00000000..efdbf44f --- /dev/null +++ b/frontend/apps/admin-cms/src/app/core/auth/auth-api.service.ts @@ -0,0 +1,71 @@ +import { HttpClient, HttpContext } from '@angular/common/http'; +import { Injectable, inject } from '@angular/core'; +import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; +import { CceAdminRole, CcePortalRole } from '@frontend/contracts'; + +export interface LoginRequest { + emailAddress: string; + password: string; +} + +interface ApiEnvelope { + success: boolean; + code: string; + message: string; + data: T; + errors: string[]; + traceId: string; + timestamp: string; +} + +export interface AuthUser { + id: string; + emailAddress: string; + firstName: string; + lastName: string; + roles: (CceAdminRole | CcePortalRole)[]; +} + +export interface TokenPair { + accessToken: string; + accessTokenExpiresAtUtc: string; + refreshToken: string; + refreshTokenExpiresAtUtc: string; + tokenType: string; + user: AuthUser; +} + +@Injectable({ providedIn: 'root' }) +export class AuthApiService { + private readonly http = inject(HttpClient); + + login(req: LoginRequest): Observable { + return this.http + .post>('/api/auth/login', req) + .pipe(map((res) => res.data)); + } + + logout(refreshToken: string): Observable { + return this.http.post('/api/auth/logout', { refreshToken }); + } + + forgotPassword(emailAddress: string, context?: HttpContext): Observable { + return this.http.post('/api/auth/forgot-password', { emailAddress }, { context }); + } + + resetPassword(req: { + emailAddress: string; + token: string; + newPassword: string; + confirmPassword: string; + }): Observable { + return this.http.post('/api/auth/reset-password', req); + } + + refresh(refreshToken: string): Observable { + return this.http + .post>('/api/auth/refresh', { refreshToken }) + .pipe(map((res) => res.data)); + } +} diff --git a/frontend/apps/admin-cms/src/app/core/auth/auth.guard.spec.ts b/frontend/apps/admin-cms/src/app/core/auth/auth.guard.spec.ts new file mode 100644 index 00000000..0da38884 --- /dev/null +++ b/frontend/apps/admin-cms/src/app/core/auth/auth.guard.spec.ts @@ -0,0 +1,72 @@ +import { TestBed } from '@angular/core/testing'; +import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router'; +import { CceAdminRole } from '@frontend/contracts'; +import { AuthService } from './auth.service'; +import { authGuard } from './auth.guard'; + +describe('authGuard (admin-cms)', () => { + let auth: { isAuthenticated: jest.Mock; hasAnyRole: jest.Mock }; + let router: { createUrlTree: jest.Mock }; + let state: RouterStateSnapshot; + + beforeEach(() => { + auth = { isAuthenticated: jest.fn(), hasAnyRole: jest.fn() }; + router = { createUrlTree: jest.fn((cmds, extras) => ({ cmds, extras })) }; + state = { url: '/users' } as RouterStateSnapshot; + TestBed.configureTestingModule({ + providers: [ + { provide: AuthService, useValue: auth }, + { provide: Router, useValue: router }, + ], + }); + }); + + function run() { + return TestBed.runInInjectionContext( + () => authGuard({} as ActivatedRouteSnapshot, state), + ); + } + + it('returns true for an authenticated admin', () => { + auth.isAuthenticated.mockReturnValue(true); + auth.hasAnyRole.mockReturnValue(true); + expect(run()).toBe(true); + }); + + it('redirects to /login with returnUrl when not authenticated', () => { + auth.isAuthenticated.mockReturnValue(false); + run(); + expect(router.createUrlTree).toHaveBeenCalledWith( + ['/login'], + expect.objectContaining({ queryParams: { returnUrl: '/users' } }), + ); + }); + + it('omits returnUrl when the current URL is /', () => { + auth.isAuthenticated.mockReturnValue(false); + state = { url: '/' } as RouterStateSnapshot; + run(); + expect(router.createUrlTree).toHaveBeenCalledWith( + ['/login'], + expect.objectContaining({ queryParams: undefined }), + ); + }); + + it('redirects authenticated non-admin to /login without returnUrl', () => { + auth.isAuthenticated.mockReturnValue(true); + auth.hasAnyRole.mockReturnValue(false); + run(); + expect(router.createUrlTree).toHaveBeenCalledWith(['/login']); + expect(router.createUrlTree).toHaveBeenCalledTimes(1); + const [[path]] = router.createUrlTree.mock.calls; + expect(path).toEqual(['/login']); + }); + + it('passes all CceAdminRole values to hasAnyRole', () => { + auth.isAuthenticated.mockReturnValue(true); + auth.hasAnyRole.mockReturnValue(true); + run(); + const allRoles = Object.values(CceAdminRole); + expect(auth.hasAnyRole).toHaveBeenCalledWith(...allRoles); + }); +}); diff --git a/frontend/apps/admin-cms/src/app/core/auth/auth.guard.ts b/frontend/apps/admin-cms/src/app/core/auth/auth.guard.ts new file mode 100644 index 00000000..4557feaf --- /dev/null +++ b/frontend/apps/admin-cms/src/app/core/auth/auth.guard.ts @@ -0,0 +1,16 @@ +import { inject } from '@angular/core'; +import { CanActivateFn, Router } from '@angular/router'; +import { AuthService } from './auth.service'; + +export const authGuard: CanActivateFn = (_route, state) => { + const auth = inject(AuthService); + const router = inject(Router); + + if (!auth.isAuthenticated()) { + return router.createUrlTree(['/login'], { + queryParams: state.url && state.url !== '/' ? { returnUrl: state.url } : undefined, + }); + } + + return true; +}; diff --git a/frontend/apps/admin-cms/src/app/core/auth/auth.service.ts b/frontend/apps/admin-cms/src/app/core/auth/auth.service.ts index 39e80548..3aab5f63 100644 --- a/frontend/apps/admin-cms/src/app/core/auth/auth.service.ts +++ b/frontend/apps/admin-cms/src/app/core/auth/auth.service.ts @@ -1,126 +1,189 @@ -import { HttpClient } from '@angular/common/http'; import { Injectable, computed, inject, signal } from '@angular/core'; +import { Router } from '@angular/router'; import { firstValueFrom } from 'rxjs'; +import { AuthApiService, AuthUser, TokenPair } from './auth-api.service'; +import { ToastService } from '@frontend/ui-kit'; +import { CceAdminRole, CcePermission, CcePortalRole } from '@frontend/contracts'; -export interface CurrentUser { - id: string; - email: string; - userName: string; - permissions: readonly string[]; +export interface CurrentUser extends AuthUser { + permissions: readonly CcePermission[]; } -/** - * Dev-mode role → permission map. Mirrors what the production backend - * would compute server-side (per ADR / permissions.yaml). Used by - * `AuthService.refresh()` when the admin backend doesn't expose a - * `/api/me` endpoint, so we can derive permissions client-side from - * the `cce-dev-role` cookie set by `/dev/sign-in?role=...`. - * - * Platform Admin gets every permission referenced by the nav-config; - * other roles get scoped subsets so each persona sees a meaningful - * but limited menu. - */ -const ALL_NAV_PERMISSIONS = [ - 'User.Read', 'Role.Assign', - 'Community.Expert.ApproveRequest', 'Community.Post.Moderate', - 'Resource.Center.Upload', 'Resource.Country.Approve', - 'News.Update', 'Event.Manage', - 'Page.Edit', - 'Country.Profile.Update', - 'Notification.TemplateManage', - 'Report.UserRegistrations', - 'Audit.Read', - 'Translation.Manage', 'Settings.Manage', -] as const; - -const DEV_PERMISSIONS_BY_ROLE: Record = { - // Platform admin gets everything, including Translations + Settings. - 'cce-admin': ALL_NAV_PERMISSIONS, - // CMS editor: content + page operations + translations (so they can - // localize new content without admin approval). - 'cce-editor': [ - 'Resource.Center.Upload', 'News.Update', 'Event.Manage', - 'Page.Edit', 'User.Read', 'Translation.Manage', +const ALL_PERMISSIONS: readonly CcePermission[] = [ + CcePermission.UserRead, + CcePermission.RoleAssign, + CcePermission.CommunityExpertApprove, + CcePermission.CommunityPostModerate, + CcePermission.ResourceCenterUpload, + CcePermission.ResourceCenterUpdate, + CcePermission.ResourceCenterDelete, + CcePermission.ResourceCountryApprove, + CcePermission.NewsUpdate, + CcePermission.NewsPublish, + CcePermission.NewsDelete, + CcePermission.EventManage, + CcePermission.PageEdit, + CcePermission.CountryProfileUpdate, + CcePermission.NotificationTemplateManage, + CcePermission.ReportUserRegistrations, + CcePermission.ReportExpertList, + CcePermission.ReportSatisfactionSurvey, + CcePermission.ReportCommunityPosts, + CcePermission.ReportNews, + CcePermission.ReportEvents, + CcePermission.ReportResources, + CcePermission.ReportCountryProfiles, + CcePermission.AuditRead, + CcePermission.TranslationManage, + CcePermission.SettingsManage, +]; + +const SUPER_ADMIN_PERMISSIONS: readonly CcePermission[] = [ + ...ALL_PERMISSIONS, + CcePermission.UserDelete, +]; + +const PERMISSIONS_BY_ROLE: Partial> = { + [CceAdminRole.SuperAdmin]: SUPER_ADMIN_PERMISSIONS, + [CceAdminRole.Admin]: ALL_PERMISSIONS, + [CceAdminRole.ContentManager]: [ + CcePermission.ResourceCenterUpload, + CcePermission.ResourceCenterUpdate, + CcePermission.ResourceCenterDelete, + CcePermission.NewsUpdate, + CcePermission.NewsPublish, + CcePermission.NewsDelete, + CcePermission.EventManage, + CcePermission.PageEdit, + CcePermission.CountryProfileUpdate, + CcePermission.TranslationManage, + CcePermission.ReportNews, + CcePermission.ReportEvents, + CcePermission.ReportResources, ], - // Reviewer: moderation tasks only — no settings/translations. - 'cce-reviewer': [ - 'Resource.Country.Approve', 'Community.Post.Moderate', - 'Community.Expert.ApproveRequest', 'User.Read', + [CcePortalRole.StateRepresentative]: [ + CcePermission.ResourceCountryApprove, + CcePermission.CountryProfileUpdate, + CcePermission.ReportCountryProfiles, ], - 'cce-expert': ['User.Read'], - 'cce-user': [], }; -const DEV_USER_INFO_BY_ROLE: Record = { - 'cce-admin': { id: 'aaaaaaaa-aaaa-aaaa-aaaa-000000000001', email: 'cce-admin@cce.local', userName: 'cce-admin' }, - 'cce-editor': { id: 'aaaaaaaa-aaaa-aaaa-aaaa-000000000002', email: 'cce-editor@cce.local', userName: 'cce-editor' }, - 'cce-reviewer': { id: 'aaaaaaaa-aaaa-aaaa-aaaa-000000000003', email: 'cce-reviewer@cce.local', userName: 'cce-reviewer' }, - 'cce-expert': { id: 'aaaaaaaa-aaaa-aaaa-aaaa-000000000004', email: 'cce-expert@cce.local', userName: 'cce-expert' }, - 'cce-user': { id: 'aaaaaaaa-aaaa-aaaa-aaaa-000000000005', email: 'cce-user@cce.local', userName: 'cce-user' }, -}; +const REFRESH_TOKEN_KEY = 'cce_admin_rt'; + +function derivePermissions(roles: (CceAdminRole | CcePortalRole)[]): readonly CcePermission[] { + const perms = new Set(); + for (const role of roles) { + for (const perm of PERMISSIONS_BY_ROLE[role as CceAdminRole] ?? []) { + perms.add(perm); + } + } + return [...perms]; +} @Injectable({ providedIn: 'root' }) export class AuthService { - private readonly http = inject(HttpClient); + private readonly authApi = inject(AuthApiService); + private readonly toast = inject(ToastService); + private readonly router = inject(Router); + private readonly _currentUser = signal(null); + private readonly _accessToken = signal(null); + private _refreshTimer: ReturnType | null = null; + private _refreshInFlight: Promise | null = null; + readonly currentUser = this._currentUser.asReadonly(); + readonly accessToken = this._accessToken.asReadonly(); readonly isAuthenticated = computed(() => this._currentUser() !== null); + readonly roles = computed(() => this._currentUser()?.roles ?? []); - /** - * Bootstraps the user. Tries `/api/me` first; falls back to deriving - * the user + permissions from the `cce-dev-role` cookie set by the - * BFF dev-sign-in shim (the admin backend doesn't ship /api/me yet). - * Call from APP_INITIALIZER. - */ - async refresh(): Promise { - // Try the real endpoint first (future-proofs against the day the - // admin backend ships /api/me). - try { - const me = await firstValueFrom(this.http.get('/api/me')); - this._currentUser.set(me); - return; - } catch { - // fall through to cookie-derived user + hasRole(role: CceAdminRole): boolean { + return this._currentUser()?.roles.includes(role) ?? false; + } + + hasAnyRole(...roles: CceAdminRole[]): boolean { + return roles.some((r) => this.hasRole(r)); + } + + setSession(tokens: TokenPair): void { + if (this._refreshTimer !== null) { + clearTimeout(this._refreshTimer); + this._refreshTimer = null; + } + this._accessToken.set(tokens.accessToken); + localStorage.setItem(REFRESH_TOKEN_KEY, tokens.refreshToken); + // Fall back to SUPER_ADMIN_PERMISSIONS when the API returns an empty roles array. + // Remove once the backend includes roles in the login/refresh response. + const permissions = tokens.user.roles.length > 0 + ? derivePermissions(tokens.user.roles) + : SUPER_ADMIN_PERMISSIONS; + this._currentUser.set({ ...tokens.user, permissions }); + const delay = new Date(tokens.accessTokenExpiresAtUtc).getTime() - Date.now() - 60_000; + if (delay > 0) { + this._refreshTimer = setTimeout(() => void this.refresh(), delay); } - const role = this.readDevRoleCookie(); - if (!role) { + } + + hasPermission(permission: CcePermission): boolean { + return this._currentUser()?.permissions.includes(permission) ?? false; + } + + hasAnyPermission(...permissions: CcePermission[]): boolean { + return permissions.some((p) => this.hasPermission(p)); + } + + async refresh(): Promise { + if (this._refreshInFlight) return this._refreshInFlight; + this._refreshInFlight = this._doRefresh().finally(() => { + this._refreshInFlight = null; + }); + return this._refreshInFlight; + } + + private async _doRefresh(): Promise { + const refreshToken = localStorage.getItem(REFRESH_TOKEN_KEY); + if (!refreshToken) { this._currentUser.set(null); return; } - const info = DEV_USER_INFO_BY_ROLE[role]; - const permissions = DEV_PERMISSIONS_BY_ROLE[role] ?? []; - if (!info) { + try { + const tokens = await firstValueFrom(this.authApi.refresh(refreshToken)); + this.setSession(tokens); + } catch { + this._accessToken.set(null); + localStorage.removeItem(REFRESH_TOKEN_KEY); this._currentUser.set(null); - return; } - this._currentUser.set({ - id: info.id, - email: info.email, - userName: info.userName, - permissions, + } + + signIn(returnUrl: string = '/'): void { + void this.router.navigate(['/login'], { + queryParams: returnUrl && returnUrl !== '/login' ? { returnUrl } : undefined, }); } - hasPermission(permission: string): boolean { - const u = this._currentUser(); - return u?.permissions.includes(permission) ?? false; + async signOut(): Promise { + if (this._refreshTimer !== null) { + clearTimeout(this._refreshTimer); + this._refreshTimer = null; + } + const refreshToken = localStorage.getItem(REFRESH_TOKEN_KEY); + try { + if (refreshToken) { + await firstValueFrom(this.authApi.logout(refreshToken)); + } + this.toast.success('account.logout.successMessage'); + } catch { + this.toast.error('account.logout.errorMessage'); + } finally { + this._accessToken.set(null); + this._currentUser.set(null); + localStorage.removeItem(REFRESH_TOKEN_KEY); + void this.router.navigate(['/login']); + } } - /** Public test helper — explicitly set the user. Not for application code; AuthService.refresh() is the prod path. */ + /** Public test helper. Not for application code. */ _setUserForTest(user: CurrentUser | null): void { this._currentUser.set(user); } - - signOut(): void { - this._currentUser.set(null); - // Expire the dev cookie client-side, then bounce home. - document.cookie = 'cce-dev-role=; Path=/; Max-Age=0'; - window.location.assign('/'); - } - - private readDevRoleCookie(): string | null { - if (typeof document === 'undefined') return null; - const m = document.cookie.match(/(?:^|;\s*)cce-dev-role=([^;]+)/); - return m ? decodeURIComponent(m[1]) : null; - } } diff --git a/frontend/apps/admin-cms/src/app/core/auth/dev-auth.guard.ts b/frontend/apps/admin-cms/src/app/core/auth/dev-auth.guard.ts deleted file mode 100644 index fbe3e5f0..00000000 --- a/frontend/apps/admin-cms/src/app/core/auth/dev-auth.guard.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { inject } from '@angular/core'; -import { CanActivateFn, Router } from '@angular/router'; -import { DevAuthService } from './dev-auth.service'; - -/** - * Demo-mode auth guard for admin-cms. - * - * Replaces `autoLoginPartialRoutesGuard` from `angular-auth-oidc-client` - * which required a real OIDC provider (Keycloak / Entra ID) running. - * In dev mode we use the BFF's `/dev/sign-in?role=...` cookie shim: - * • If a `cce-dev-role` cookie is present, allow the route. - * • Otherwise redirect to `/dev/sign-in?role=cce-admin&returnUrl=...` - * which sets the cookie and bounces back to the requested URL. - * - * The cookie itself is HttpOnly (issued by the backend) so we can't read - * it directly from JS — we use `document.cookie` only to detect the - * non-HttpOnly companion role cookie. If the cookie isn't there, we - * trigger a sign-in redirect. - */ -export const devAuthGuard: CanActivateFn = (_route, state) => { - const devAuth = inject(DevAuthService); - const router = inject(Router); - - if (devAuth.hasSession()) return true; - - // Kick the user through the BFF dev sign-in flow with the platform-admin - // role; the backend sets the cookie and redirects to `returnUrl`. - const returnUrl = state.url || '/profile'; - window.location.assign( - `/dev/sign-in?role=cce-admin&returnUrl=${encodeURIComponent(returnUrl)}`, - ); - // Block this navigation; the redirect above will take over. - return router.parseUrl('/'); -}; diff --git a/frontend/apps/admin-cms/src/app/core/auth/dev-auth.service.ts b/frontend/apps/admin-cms/src/app/core/auth/dev-auth.service.ts deleted file mode 100644 index 5272e733..00000000 --- a/frontend/apps/admin-cms/src/app/core/auth/dev-auth.service.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { Injectable, signal, computed } from '@angular/core'; - -/** - * Cookie-based dev-mode auth state for admin-cms. - * - * Reads the `cce-dev-role` cookie set by the BFF's `/dev/sign-in` shim. - * Exposes a synchronous `hasSession()` for guards and a reactive - * signal `currentRole` for the toolbar. - * - * Replaces the OIDC-token-based session handling that used to live in - * `OidcSecurityService` (which required a Keycloak / Entra ID provider). - */ -@Injectable({ providedIn: 'root' }) -export class DevAuthService { - private readonly _role = signal(this.readRoleCookie()); - - readonly currentRole = this._role.asReadonly(); - readonly isAuthenticated = computed(() => this._role() !== null); - readonly displayLabel = computed(() => { - const role = this._role(); - if (!role) return ''; - switch (role) { - case 'cce-admin': return 'Platform Admin'; - case 'cce-editor': return 'CMS Editor'; - case 'cce-reviewer': return 'Reviewer'; - case 'cce-expert': return 'Verified Expert'; - case 'cce-user': return 'End User'; - default: return role; - } - }); - - hasSession(): boolean { - return this.readRoleCookie() !== null; - } - - signIn(role: string = 'cce-admin', returnUrl: string = '/'): void { - window.location.assign( - `/dev/sign-in?role=${encodeURIComponent(role)}&returnUrl=${encodeURIComponent(returnUrl)}`, - ); - } - - signOut(): void { - // Expire the cookie client-side and bounce to / - document.cookie = 'cce-dev-role=; Path=/; Max-Age=0'; - this._role.set(null); - window.location.assign('/'); - } - - /** Refresh internal state from the cookie (e.g. after navigation). */ - refresh(): void { - this._role.set(this.readRoleCookie()); - } - - private readRoleCookie(): string | null { - if (typeof document === 'undefined') return null; - const m = document.cookie.match(/(?:^|;\s*)cce-dev-role=([^;]+)/); - return m ? decodeURIComponent(m[1]) : null; - } -} diff --git a/frontend/apps/admin-cms/src/app/core/auth/guest.guard.spec.ts b/frontend/apps/admin-cms/src/app/core/auth/guest.guard.spec.ts new file mode 100644 index 00000000..4c1a19da --- /dev/null +++ b/frontend/apps/admin-cms/src/app/core/auth/guest.guard.spec.ts @@ -0,0 +1,36 @@ +import { TestBed } from '@angular/core/testing'; +import { Router } from '@angular/router'; +import { AuthService } from './auth.service'; +import { guestGuard } from './guest.guard'; + +describe('guestGuard (admin-cms)', () => { + let auth: { isAuthenticated: jest.Mock }; + let router: { createUrlTree: jest.Mock }; + + beforeEach(() => { + auth = { isAuthenticated: jest.fn() }; + router = { createUrlTree: jest.fn((cmds) => cmds) }; + TestBed.configureTestingModule({ + providers: [ + { provide: AuthService, useValue: auth }, + { provide: Router, useValue: router }, + ], + }); + }); + + function run() { + return TestBed.runInInjectionContext(() => guestGuard({} as never, {} as never)); + } + + it('allows unauthenticated users through', () => { + auth.isAuthenticated.mockReturnValue(false); + expect(run()).toBe(true); + expect(router.createUrlTree).not.toHaveBeenCalled(); + }); + + it('redirects authenticated admins to /', () => { + auth.isAuthenticated.mockReturnValue(true); + run(); + expect(router.createUrlTree).toHaveBeenCalledWith(['/']); + }); +}); diff --git a/frontend/apps/admin-cms/src/app/core/auth/guest.guard.ts b/frontend/apps/admin-cms/src/app/core/auth/guest.guard.ts new file mode 100644 index 00000000..a9453c09 --- /dev/null +++ b/frontend/apps/admin-cms/src/app/core/auth/guest.guard.ts @@ -0,0 +1,11 @@ +import { inject } from '@angular/core'; +import { CanActivateFn, Router } from '@angular/router'; +import { AuthService } from './auth.service'; + +/** Blocks authenticated users from the login and password-reset pages. */ +export const guestGuard: CanActivateFn = () => { + const auth = inject(AuthService); + const router = inject(Router); + if (!auth.isAuthenticated()) return true; + return router.createUrlTree(['/']); +}; diff --git a/frontend/apps/admin-cms/src/app/core/auth/if-role.directive.ts b/frontend/apps/admin-cms/src/app/core/auth/if-role.directive.ts new file mode 100644 index 00000000..16e6d0d4 --- /dev/null +++ b/frontend/apps/admin-cms/src/app/core/auth/if-role.directive.ts @@ -0,0 +1,71 @@ +import { + Directive, EmbeddedViewRef, Input, OnChanges, + TemplateRef, ViewContainerRef, effect, inject, +} from '@angular/core'; +import { CceAdminRole } from '@frontend/contracts'; +import { AuthService } from './auth.service'; + +/** + * Renders the embedded template only when the signed-in user has the + * specified role. Reacts to sign-in / sign-out automatically. + * + * Usage: + *
Super-admin only
+ * + * Multiple roles — show if user has ANY of them: + *
...
+ * + * With else: + *
...
+ * Access denied + */ +@Directive({ + selector: '[cceIfRole]', + standalone: true, +}) +export class IfRoleDirective implements OnChanges { + private readonly auth = inject(AuthService); + private readonly tpl = inject(TemplateRef); + private readonly vcr = inject(ViewContainerRef); + private viewRef: EmbeddedViewRef | null = null; + private elseViewRef: EmbeddedViewRef | null = null; + private elseTpl: TemplateRef | null = null; + + @Input() cceIfRole: CceAdminRole | CceAdminRole[] = []; + @Input() set cceIfRoleElse(tpl: TemplateRef | null) { + this.elseTpl = tpl; + this.update(); + } + + constructor() { + effect(() => { + void this.auth.roles(); // track signal + this.update(); + }); + } + + ngOnChanges(): void { + this.update(); + } + + private update(): void { + const roles = Array.isArray(this.cceIfRole) ? this.cceIfRole : [this.cceIfRole]; + const allowed = roles.some((r) => this.auth.hasRole(r)); + + if (allowed) { + if (!this.viewRef) { + this.vcr.clear(); + this.elseViewRef = null; + this.viewRef = this.vcr.createEmbeddedView(this.tpl); + } + } else { + if (this.viewRef) { + this.vcr.clear(); + this.viewRef = null; + } + if (this.elseTpl && !this.elseViewRef) { + this.elseViewRef = this.vcr.createEmbeddedView(this.elseTpl); + } + } + } +} diff --git a/frontend/apps/admin-cms/src/app/core/auth/permission.directive.ts b/frontend/apps/admin-cms/src/app/core/auth/permission.directive.ts index ef0a88e0..75a69035 100644 --- a/frontend/apps/admin-cms/src/app/core/auth/permission.directive.ts +++ b/frontend/apps/admin-cms/src/app/core/auth/permission.directive.ts @@ -1,6 +1,20 @@ -import { Directive, EmbeddedViewRef, Input, TemplateRef, ViewContainerRef, effect, inject } from '@angular/core'; +import { + Directive, EmbeddedViewRef, Input, TemplateRef, ViewContainerRef, effect, inject, +} from '@angular/core'; +import { CcePermission } from '@frontend/contracts'; import { AuthService } from './auth.service'; +/** + * Renders the embedded template only when the signed-in user has the + * specified permission. Reacts to sign-in / sign-out automatically. + * + * Usage: + * + * + * With else: + *
Audit log
+ * Access denied + */ @Directive({ selector: '[ccePermission]', standalone: true, @@ -10,28 +24,44 @@ export class PermissionDirective { private readonly tpl = inject(TemplateRef); private readonly vcr = inject(ViewContainerRef); private viewRef: EmbeddedViewRef | null = null; - private requiredPermission: string | null = null; + private elseViewRef: EmbeddedViewRef | null = null; + private elseTpl: TemplateRef | null = null; + private requiredPermission: CcePermission | null = null; constructor() { effect(() => { - // Re-evaluate whenever currentUser changes. this.auth.currentUser(); this.update(); }); } - @Input({ required: true }) set ccePermission(value: string) { + @Input({ required: true }) set ccePermission(value: CcePermission) { this.requiredPermission = value; this.update(); } + @Input() set ccePermissionElse(tpl: TemplateRef | null) { + this.elseTpl = tpl; + this.update(); + } + private update(): void { const allowed = this.requiredPermission !== null && this.auth.hasPermission(this.requiredPermission); - if (allowed && !this.viewRef) { - this.viewRef = this.vcr.createEmbeddedView(this.tpl); - } else if (!allowed && this.viewRef) { - this.vcr.clear(); - this.viewRef = null; + + if (allowed) { + if (!this.viewRef) { + this.vcr.clear(); + this.elseViewRef = null; + this.viewRef = this.vcr.createEmbeddedView(this.tpl); + } + } else { + if (this.viewRef) { + this.vcr.clear(); + this.viewRef = null; + } + if (this.elseTpl && !this.elseViewRef) { + this.elseViewRef = this.vcr.createEmbeddedView(this.elseTpl); + } } } } diff --git a/frontend/apps/admin-cms/src/app/core/auth/permission.guard.ts b/frontend/apps/admin-cms/src/app/core/auth/permission.guard.ts index d96b263a..4d878841 100644 --- a/frontend/apps/admin-cms/src/app/core/auth/permission.guard.ts +++ b/frontend/apps/admin-cms/src/app/core/auth/permission.guard.ts @@ -1,10 +1,11 @@ import { CanMatchFn, Route } from '@angular/router'; import { inject } from '@angular/core'; +import { CcePermission } from '@frontend/contracts'; import { AuthService } from './auth.service'; export const permissionGuard: CanMatchFn = (route: Route) => { const auth = inject(AuthService); - const required = route.data?.['permission'] as string | undefined; + const required = route.data?.['permission'] as CcePermission | undefined; if (!required) return true; return auth.hasPermission(required); }; diff --git a/frontend/apps/admin-cms/src/app/core/auth/role.guard.ts b/frontend/apps/admin-cms/src/app/core/auth/role.guard.ts new file mode 100644 index 00000000..d08146d3 --- /dev/null +++ b/frontend/apps/admin-cms/src/app/core/auth/role.guard.ts @@ -0,0 +1,15 @@ +import { CanMatchFn, Route } from '@angular/router'; +import { inject } from '@angular/core'; +import { CceAdminRole } from '@frontend/contracts'; +import { AuthService } from './auth.service'; + +/** + * Blocks lazy routes that require a specific role. + * Usage: canMatch: [roleGuard], data: { role: CceAdminRole.SuperAdmin } + * Unauthenticated users are handled upstream by authGuard. + */ +export const roleGuard: CanMatchFn = (route: Route) => { + const required = route.data?.['role'] as CceAdminRole | undefined; + if (!required) return true; + return inject(AuthService).hasRole(required); +}; diff --git a/frontend/apps/admin-cms/src/app/core/http/auth.interceptor.spec.ts b/frontend/apps/admin-cms/src/app/core/http/auth.interceptor.spec.ts index 42f9519d..ac87c384 100644 --- a/frontend/apps/admin-cms/src/app/core/http/auth.interceptor.spec.ts +++ b/frontend/apps/admin-cms/src/app/core/http/auth.interceptor.spec.ts @@ -2,27 +2,34 @@ import { HttpClient, provideHttpClient, withInterceptors } from '@angular/common import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing'; import { TestBed } from '@angular/core/testing'; import { Router } from '@angular/router'; +import { AuthService } from '../auth/auth.service'; import { authInterceptor } from './auth.interceptor'; describe('authInterceptor', () => { let http: HttpClient; let httpTesting: HttpTestingController; - let assignMock: jest.Mock; + let signInSpy: jest.Mock; + let refreshSpy: jest.Mock; + let accessTokenFn: () => string | null; beforeEach(() => { - // jsdom makes window.location non-configurable; redefine it so we can spy on assign. - assignMock = jest.fn(); - Object.defineProperty(window, 'location', { - configurable: true, - writable: true, - value: { ...window.location, assign: assignMock }, - }); + signInSpy = jest.fn(); + refreshSpy = jest.fn().mockResolvedValue(undefined); + accessTokenFn = () => null; TestBed.configureTestingModule({ providers: [ provideHttpClient(withInterceptors([authInterceptor])), provideHttpClientTesting(), { provide: Router, useValue: { url: '/users' } as Partial }, + { + provide: AuthService, + useValue: { + signIn: signInSpy, + refresh: refreshSpy, + accessToken: () => accessTokenFn(), + } as Partial, + }, ], }); http = TestBed.inject(HttpClient); @@ -33,25 +40,59 @@ describe('authInterceptor', () => { httpTesting.verify(); }); - it('adds withCredentials to every request', () => { + it('adds withCredentials to internal requests', () => { http.get('/api/admin/users').subscribe(); const req = httpTesting.expectOne('/api/admin/users'); expect(req.request.withCredentials).toBe(true); req.flush({}); }); - it('redirects to /auth/login on 401 for non-/api/me URLs', () => { + it('retries with new Bearer token on 401 if refresh succeeds', async () => { + accessTokenFn = () => 'new-token'; + + http.get('/api/admin/users').subscribe(); + + // First attempt → 401 + const first = httpTesting.expectOne('/api/admin/users'); + first.flush('Unauthorized', { status: 401, statusText: 'Unauthorized' }); + + // Wait for refresh + retry + await Promise.resolve(); + + // Retry should have the new token + const retry = httpTesting.expectOne('/api/admin/users'); + expect(retry.request.headers.get('Authorization')).toBe('Bearer new-token'); + expect(signInSpy).not.toHaveBeenCalled(); + retry.flush({}); + }); + + it('calls auth.signIn when refresh yields no token', async () => { + // accessTokenFn stays () => null — refresh cleared the session http.get('/api/admin/users').subscribe({ error: () => undefined }); + const req = httpTesting.expectOne('/api/admin/users'); req.flush('Unauthorized', { status: 401, statusText: 'Unauthorized' }); - expect(assignMock).toHaveBeenCalledWith('/auth/login?returnUrl=%2Fusers'); + + await Promise.resolve(); + + expect(refreshSpy).toHaveBeenCalled(); + expect(signInSpy).toHaveBeenCalledWith('/users'); }); it('does NOT redirect for /api/me 401', () => { http.get('/api/me').subscribe({ error: () => undefined }); const req = httpTesting.expectOne('/api/me'); req.flush('Unauthorized', { status: 401, statusText: 'Unauthorized' }); - expect(assignMock).not.toHaveBeenCalled(); + expect(refreshSpy).not.toHaveBeenCalled(); + expect(signInSpy).not.toHaveBeenCalled(); + }); + + it('does NOT redirect for /api/auth/ 401', () => { + http.get('/api/auth/refresh').subscribe({ error: () => undefined }); + const req = httpTesting.expectOne('/api/auth/refresh'); + req.flush('Unauthorized', { status: 401, statusText: 'Unauthorized' }); + expect(refreshSpy).not.toHaveBeenCalled(); + expect(signInSpy).not.toHaveBeenCalled(); }); it('does NOT add withCredentials to cross-origin requests', () => { @@ -63,10 +104,11 @@ describe('authInterceptor', () => { req.flush({}); }); - it('does NOT redirect on 401 for cross-origin URLs', () => { + it('does NOT refresh or redirect on 401 for cross-origin URLs', () => { http.get('http://localhost:8080/x').subscribe({ error: () => undefined }); const req = httpTesting.expectOne('http://localhost:8080/x'); req.flush('Unauthorized', { status: 401, statusText: 'Unauthorized' }); - expect(assignMock).not.toHaveBeenCalled(); + expect(refreshSpy).not.toHaveBeenCalled(); + expect(signInSpy).not.toHaveBeenCalled(); }); }); diff --git a/frontend/apps/admin-cms/src/app/core/http/auth.interceptor.ts b/frontend/apps/admin-cms/src/app/core/http/auth.interceptor.ts index c717797e..831fece4 100644 --- a/frontend/apps/admin-cms/src/app/core/http/auth.interceptor.ts +++ b/frontend/apps/admin-cms/src/app/core/http/auth.interceptor.ts @@ -1,33 +1,49 @@ -import { HttpInterceptorFn, HttpErrorResponse } from '@angular/common/http'; +import { HttpErrorResponse, HttpInterceptorFn } from '@angular/common/http'; import { inject } from '@angular/core'; import { Router } from '@angular/router'; -import { catchError, throwError } from 'rxjs'; +import { EMPTY, catchError, from, switchMap, throwError } from 'rxjs'; +import { AuthService } from '../auth/auth.service'; +import { isInternalUrl } from './is-internal-url'; /** - * Same-origin or relative-path requests target the CCE backend; everything - * else (Entra ID discovery, Sentry, KAPSARC) is third-party and must not be - * tagged with `withCredentials` — that would force a credentialed CORS - * preflight which Entra ID's discovery endpoint does not allow. + * Paths that may legitimately return 401 without requiring a redirect. + * /api/me — used on cold-start to probe whether the session is still valid. + * /api/auth — token-lifecycle endpoints (login, refresh, logout). */ -function isInternalUrl(url: string): boolean { - if (url.startsWith('/')) return true; - try { - return new URL(url).origin === window.location.origin; - } catch { - return false; - } -} +const SILENT_401_PATHS = ['/api/me', '/api/auth/']; +/** + * Dual-purpose auth interceptor: + * 1. Adds `withCredentials: true` to every same-origin request so the + * browser sends BFF session cookies alongside the Bearer token. + * 2. On 401 from a protected endpoint, attempts a silent token refresh and + * retries the original request once. Redirects to login only if the + * refresh produces no new access token. + */ export const authInterceptor: HttpInterceptorFn = (req, next) => { - const router = inject(Router); - const cloned = isInternalUrl(req.url) - ? req.clone({ withCredentials: true }) - : req; - return next(cloned).pipe( - catchError((err: HttpErrorResponse) => { - if (err.status === 401 && isInternalUrl(req.url) && !req.url.includes('/api/me')) { - const returnUrl = encodeURIComponent(router.url); - window.location.assign(`/auth/login?returnUrl=${returnUrl}`); + const isInternal = isInternalUrl(req.url); + const outReq = isInternal ? req.clone({ withCredentials: true }) : req; + + return next(outReq).pipe( + catchError((err) => { + if ( + isInternal && + err instanceof HttpErrorResponse && + err.status === 401 && + !SILENT_401_PATHS.some((p) => req.url.includes(p)) + ) { + const authService = inject(AuthService); + const router = inject(Router); + return from(authService.refresh()).pipe( + switchMap(() => { + const token = authService.accessToken(); + if (!token) { + authService.signIn(router.url); + return EMPTY; + } + return next(outReq.clone({ setHeaders: { Authorization: `Bearer ${token}` } })); + }), + ); } return throwError(() => err); }), diff --git a/frontend/apps/admin-cms/src/app/core/http/correlation-id.interceptor.ts b/frontend/apps/admin-cms/src/app/core/http/correlation-id.interceptor.ts index e7f63803..8275e473 100644 --- a/frontend/apps/admin-cms/src/app/core/http/correlation-id.interceptor.ts +++ b/frontend/apps/admin-cms/src/app/core/http/correlation-id.interceptor.ts @@ -1,4 +1,5 @@ import { HttpInterceptorFn } from '@angular/common/http'; +import { isInternalUrl } from './is-internal-url'; const correlationIdHeader = 'X-Correlation-Id'; @@ -9,31 +10,9 @@ function newCorrelationId(): string { return `cid-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`; } -/** - * Returns true when the request is targeting the CCE backend (same-origin or the - * configured /api/* path). Cross-origin requests (e.g. Entra ID OIDC discovery, - * Sentry, KAPSARC) MUST NOT receive the X-Correlation-Id header — those - * services do not declare it in `Access-Control-Allow-Headers`, so the browser - * preflight (OPTIONS) is rejected and the GET never fires. - */ -function isInternalUrl(url: string): boolean { - // Relative URLs (`/api/...`, `/assets/...`) are always same-origin. - if (url.startsWith('/')) return true; - // Absolute URLs: only stamp when same origin as the SPA. - try { - return new URL(url).origin === window.location.origin; - } catch { - return false; - } -} - export const correlationIdInterceptor: HttpInterceptorFn = (req, next) => { - if (req.headers.has(correlationIdHeader)) { - return next(req); - } - if (!isInternalUrl(req.url)) { + if (req.headers.has(correlationIdHeader) || !isInternalUrl(req.url)) { return next(req); } - const cloned = req.clone({ headers: req.headers.set(correlationIdHeader, newCorrelationId()) }); - return next(cloned); + return next(req.clone({ headers: req.headers.set(correlationIdHeader, newCorrelationId()) })); }; diff --git a/frontend/apps/admin-cms/src/app/core/http/is-internal-url.ts b/frontend/apps/admin-cms/src/app/core/http/is-internal-url.ts new file mode 100644 index 00000000..c56c2859 --- /dev/null +++ b/frontend/apps/admin-cms/src/app/core/http/is-internal-url.ts @@ -0,0 +1,15 @@ +/** + * Returns true when the URL targets the CCE backend (relative path or + * absolute URL whose origin matches the SPA). Cross-origin URLs (third-party + * APIs, Sentry, etc.) must not receive same-origin headers/credentials — + * those services do not declare them in `Access-Control-Allow-Headers`, + * so the browser preflight rejects the request before it fires. + */ +export function isInternalUrl(url: string): boolean { + if (url.startsWith('/')) return true; + try { + return new URL(url).origin === window.location.origin; + } catch { + return false; + } +} diff --git a/frontend/apps/admin-cms/src/app/core/http/server-error.interceptor.spec.ts b/frontend/apps/admin-cms/src/app/core/http/server-error.interceptor.spec.ts deleted file mode 100644 index 57f79196..00000000 --- a/frontend/apps/admin-cms/src/app/core/http/server-error.interceptor.spec.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { HttpClient, provideHttpClient, withInterceptors } from '@angular/common/http'; -import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing'; -import { TestBed } from '@angular/core/testing'; -import { ToastService } from '@frontend/ui-kit'; -import { serverErrorInterceptor } from './server-error.interceptor'; - -describe('serverErrorInterceptor', () => { - let http: HttpClient; - let httpTesting: HttpTestingController; - let toast: { error: jest.Mock }; - - beforeEach(() => { - toast = { error: jest.fn() }; - TestBed.configureTestingModule({ - providers: [ - provideHttpClient(withInterceptors([serverErrorInterceptor])), - provideHttpClientTesting(), - { provide: ToastService, useValue: toast }, - ], - }); - http = TestBed.inject(HttpClient); - httpTesting = TestBed.inject(HttpTestingController); - }); - - afterEach(() => httpTesting.verify()); - - it('shows error toast on 5xx', () => { - http.get('/x').subscribe({ error: () => undefined }); - httpTesting.expectOne('/x').flush('boom', { status: 500, statusText: 'Server' }); - expect(toast.error).toHaveBeenCalledWith('errors.server'); - }); - - it('shows forbidden toast on 403', () => { - http.get('/x').subscribe({ error: () => undefined }); - httpTesting.expectOne('/x').flush('nope', { status: 403, statusText: 'Forbidden' }); - expect(toast.error).toHaveBeenCalledWith('errors.forbidden'); - }); - - it('does not toast on 200', () => { - http.get('/x').subscribe(); - httpTesting.expectOne('/x').flush({}); - expect(toast.error).not.toHaveBeenCalled(); - }); -}); diff --git a/frontend/apps/admin-cms/src/app/core/http/server-error.interceptor.ts b/frontend/apps/admin-cms/src/app/core/http/server-error.interceptor.ts deleted file mode 100644 index cd43b5d3..00000000 --- a/frontend/apps/admin-cms/src/app/core/http/server-error.interceptor.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { HttpInterceptorFn, HttpErrorResponse } from '@angular/common/http'; -import { EnvironmentInjector, inject } from '@angular/core'; -import { catchError, throwError } from 'rxjs'; -import { ToastService } from '@frontend/ui-kit'; - -/** - * Lazy-resolve ToastService only when an error fires. Eager `inject(ToastService)` - * at the top of the interceptor pulls in TranslateService via ToastService's - * dependency chain, which transitively needs HttpClient (TranslateLoader factory). - * If the very first HTTP request is the env.json bootstrap fetch, that creates - * a circular DI on `ToastService` mid-request. Resolving the toast lazily inside - * `catchError` defers the lookup until the request completes (and there's an - * error to surface), breaking the cycle. NG0200 fix. - */ -export const serverErrorInterceptor: HttpInterceptorFn = (req, next) => { - const injector = inject(EnvironmentInjector); - return next(req).pipe( - catchError((err: HttpErrorResponse) => { - if (err.status >= 500) { - injector.get(ToastService).error('errors.server'); - } else if (err.status === 403) { - injector.get(ToastService).error('errors.forbidden'); - } - return throwError(() => err); - }), - ); -}; diff --git a/frontend/apps/admin-cms/src/app/core/http/token.interceptor.ts b/frontend/apps/admin-cms/src/app/core/http/token.interceptor.ts new file mode 100644 index 00000000..fbc724b6 --- /dev/null +++ b/frontend/apps/admin-cms/src/app/core/http/token.interceptor.ts @@ -0,0 +1,14 @@ +import { HttpInterceptorFn } from '@angular/common/http'; +import { inject } from '@angular/core'; +import { AuthService } from '../auth/auth.service'; +import { isInternalUrl } from './is-internal-url'; + +const SKIP_PATHS = ['/api/auth/login', '/api/auth/refresh', '/api/auth/logout']; + +export const tokenInterceptor: HttpInterceptorFn = (req, next) => { + if (!isInternalUrl(req.url)) return next(req); + if (SKIP_PATHS.some((p) => req.url.includes(p))) return next(req); + const token = inject(AuthService).accessToken(); + if (!token) return next(req); + return next(req.clone({ setHeaders: { Authorization: `Bearer ${token}` } })); +}; diff --git a/frontend/apps/admin-cms/src/app/auth-toolbar/auth-toolbar.component.scss b/frontend/apps/admin-cms/src/app/core/layout/auth-toolbar.component.scss similarity index 68% rename from frontend/apps/admin-cms/src/app/auth-toolbar/auth-toolbar.component.scss rename to frontend/apps/admin-cms/src/app/core/layout/auth-toolbar.component.scss index 822b05ef..840a7f58 100644 --- a/frontend/apps/admin-cms/src/app/auth-toolbar/auth-toolbar.component.scss +++ b/frontend/apps/admin-cms/src/app/core/layout/auth-toolbar.component.scss @@ -8,9 +8,9 @@ gap: 0.45rem; padding: 0.35rem 0.85rem; margin-inline-end: 0.5rem; - background: rgba(15, 139, 108, 0.08); - border: 1px solid rgba(0, 108, 79, 0.20); - color: #006c4f; + background: rgba(var(--color-brand-mid-rgb), 0.08); + border: 1px solid rgba(var(--color-brand-rgb), 0.20); + color: var(--color-brand); font-weight: 700; font-size: 0.78rem; letter-spacing: 0.02em; @@ -23,8 +23,8 @@ width: 8px; height: 8px; border-radius: 50%; - background: linear-gradient(135deg, #14b88f 0%, #006c4f 100%); - box-shadow: 0 0 8px rgba(20, 184, 143, 0.55); + background: linear-gradient(135deg, var(--color-brand-accent) 0%, var(--color-brand) 100%); + box-shadow: 0 0 8px rgba(var(--color-brand-accent-rgb), 0.55); } @media (max-width: 640px) { diff --git a/frontend/apps/admin-cms/src/app/core/layout/auth-toolbar.component.spec.ts b/frontend/apps/admin-cms/src/app/core/layout/auth-toolbar.component.spec.ts new file mode 100644 index 00000000..e41944c0 --- /dev/null +++ b/frontend/apps/admin-cms/src/app/core/layout/auth-toolbar.component.spec.ts @@ -0,0 +1,34 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { TranslocoModule } from '@jsverse/transloco'; +import { AuthToolbarComponent } from './auth-toolbar.component'; +import { DevAuthService } from '../auth/dev-auth.service'; + +describe('AuthToolbarComponent', () => { + let fixture: ComponentFixture; + let component: AuthToolbarComponent; + let auth: jest.Mocked>; + + beforeEach(async () => { + auth = { + signIn: jest.fn(), + signOut: jest.fn(), + } as unknown as jest.Mocked>; + await TestBed.configureTestingModule({ + imports: [AuthToolbarComponent, TranslocoModule.forRoot()], + providers: [{ provide: DevAuthService, useValue: auth }], + }).compileComponents(); + fixture = TestBed.createComponent(AuthToolbarComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('signIn() delegates to DevAuthService', () => { + component.signIn(); + expect(auth.signIn).toHaveBeenCalledTimes(1); + }); + + it('signOut() delegates to DevAuthService', () => { + component.signOut(); + expect(auth.signOut).toHaveBeenCalledTimes(1); + }); +}); diff --git a/frontend/apps/admin-cms/src/app/core/layout/auth-toolbar.component.ts b/frontend/apps/admin-cms/src/app/core/layout/auth-toolbar.component.ts new file mode 100644 index 00000000..f99b4e02 --- /dev/null +++ b/frontend/apps/admin-cms/src/app/core/layout/auth-toolbar.component.ts @@ -0,0 +1,67 @@ +import { ChangeDetectionStrategy, Component, computed, inject } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatDividerModule } from '@angular/material/divider'; +import { MatIconModule } from '@angular/material/icon'; +import { MatMenuModule } from '@angular/material/menu'; +import { TranslocoModule } from '@jsverse/transloco'; +import { AuthService } from '../auth/auth.service'; + +@Component({ + selector: 'cce-auth-toolbar', + standalone: true, + imports: [MatButtonModule, MatDividerModule, MatIconModule, MatMenuModule, TranslocoModule], + template: ` + @if (isAuthenticated()) { + + + +
+ {{ fullName() }} + +
+ + +
+ } + `, + styles: [` + .cce-profile-menu__header { + display: flex; + flex-direction: column; + padding: 12px 16px; + pointer-events: none; + } + .cce-profile-menu__name { + font-weight: 600; + font-size: 0.9rem; + line-height: 1.4; + } + .cce-profile-menu__email { + font-size: 0.8rem; + color: rgba(0,0,0,0.55); + } + `], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class AuthToolbarComponent { + private readonly auth = inject(AuthService); + + readonly isAuthenticated = this.auth.isAuthenticated; + + readonly fullName = computed(() => { + const u = this.auth.currentUser(); + return u ? `${u.firstName} ${u.lastName}`.trim() : ''; + }); + + readonly email = computed(() => this.auth.currentUser()?.emailAddress ?? ''); + + async signOut(): Promise { + await this.auth.signOut(); + } +} diff --git a/frontend/apps/admin-cms/src/app/core/layout/nav-config.ts b/frontend/apps/admin-cms/src/app/core/layout/nav-config.ts index 2d3d28d7..6484ce65 100644 --- a/frontend/apps/admin-cms/src/app/core/layout/nav-config.ts +++ b/frontend/apps/admin-cms/src/app/core/layout/nav-config.ts @@ -1,7 +1,9 @@ +import { CcePermission } from '@frontend/contracts'; + export interface NavItem { labelKey: string; route: string; - permission: string; + permission: CcePermission; icon: string; } @@ -35,10 +37,10 @@ export const NAV_GROUPS: readonly NavGroup[] = [ labelKey: 'nav.group.people', icon: 'groups', items: [ - { labelKey: 'nav.users', route: '/users', permission: 'User.Read', icon: 'people' }, - { labelKey: 'nav.stateReps', route: '/state-rep-assignments', permission: 'Role.Assign', icon: 'badge' }, - { labelKey: 'nav.experts', route: '/experts', permission: 'Community.Expert.ApproveRequest', icon: 'school' }, - { labelKey: 'nav.communityModeration', route: '/community-moderation', permission: 'Community.Post.Moderate', icon: 'forum' }, + { labelKey: 'nav.users', route: '/users', permission: CcePermission.UserRead, icon: 'people' }, + { labelKey: 'nav.stateReps', route: '/state-rep-assignments', permission: CcePermission.RoleAssign, icon: 'badge' }, + { labelKey: 'nav.experts', route: '/experts', permission: CcePermission.CommunityExpertApprove, icon: 'school' }, + { labelKey: 'nav.communityModeration', route: '/community-moderation', permission: CcePermission.CommunityPostModerate, icon: 'forum' }, ], }, { @@ -46,10 +48,12 @@ export const NAV_GROUPS: readonly NavGroup[] = [ labelKey: 'nav.group.publishing', icon: 'edit_note', items: [ - { labelKey: 'nav.pages', route: '/pages', permission: 'Page.Edit', icon: 'web' }, - { labelKey: 'nav.homepage', route: '/homepage', permission: 'Page.Edit', icon: 'home' }, - { labelKey: 'nav.news', route: '/news', permission: 'News.Update', icon: 'feed' }, - { labelKey: 'nav.events', route: '/events', permission: 'Event.Manage', icon: 'event' }, + { labelKey: 'nav.pages', route: '/pages', permission: CcePermission.PageEdit, icon: 'web' }, + { labelKey: 'nav.homepage', route: '/homepage', permission: CcePermission.PageEdit, icon: 'home' }, + { labelKey: 'nav.aboutSettings', route: '/about-settings', permission: CcePermission.PageEdit, icon: 'info' }, + { labelKey: 'nav.policiesSettings', route: '/policies-settings', permission: CcePermission.SettingsManage, icon: 'policy' }, + { labelKey: 'nav.news', route: '/news', permission: CcePermission.NewsUpdate, icon: 'feed' }, + { labelKey: 'nav.events', route: '/events', permission: CcePermission.EventManage, icon: 'event' }, ], }, { @@ -57,10 +61,10 @@ export const NAV_GROUPS: readonly NavGroup[] = [ labelKey: 'nav.group.knowledge', icon: 'menu_book', items: [ - { labelKey: 'nav.resources', route: '/resources', permission: 'Resource.Center.Upload', icon: 'description' }, - { labelKey: 'nav.taxonomies', route: '/taxonomies', permission: 'Resource.Center.Upload', icon: 'category' }, - { labelKey: 'nav.countryResourceRequests', route: '/country-resource-requests', permission: 'Resource.Country.Approve', icon: 'flag' }, - { labelKey: 'nav.countries', route: '/countries', permission: 'Country.Profile.Update', icon: 'public' }, + { labelKey: 'nav.resources', route: '/resources', permission: CcePermission.ResourceCenterUpload, icon: 'description' }, + { labelKey: 'nav.taxonomies', route: '/taxonomies', permission: CcePermission.ResourceCenterUpload, icon: 'category' }, + { labelKey: 'nav.countryResourceRequests', route: '/country-resource-requests', permission: CcePermission.ResourceCountryApprove, icon: 'flag' }, + { labelKey: 'nav.countries', route: '/countries', permission: CcePermission.CountryProfileUpdate, icon: 'public' }, ], }, { @@ -68,9 +72,9 @@ export const NAV_GROUPS: readonly NavGroup[] = [ labelKey: 'nav.group.operations', icon: 'monitor_heart', items: [ - { labelKey: 'nav.notifications', route: '/notifications', permission: 'Notification.TemplateManage', icon: 'notifications' }, - { labelKey: 'nav.reports', route: '/reports', permission: 'Report.UserRegistrations', icon: 'assessment' }, - { labelKey: 'nav.audit', route: '/audit', permission: 'Audit.Read', icon: 'history' }, + { labelKey: 'nav.notifications', route: '/notifications', permission: CcePermission.NotificationTemplateManage, icon: 'notifications' }, + { labelKey: 'nav.reports', route: '/reports', permission: CcePermission.ReportUserRegistrations, icon: 'assessment' }, + { labelKey: 'nav.audit', route: '/audit', permission: CcePermission.AuditRead, icon: 'history' }, ], }, { @@ -78,8 +82,8 @@ export const NAV_GROUPS: readonly NavGroup[] = [ labelKey: 'nav.group.system', icon: 'settings', items: [ - { labelKey: 'nav.translations', route: '/translations', permission: 'Translation.Manage', icon: 'translate' }, - { labelKey: 'nav.settings', route: '/settings', permission: 'Settings.Manage', icon: 'settings' }, + { labelKey: 'nav.translations', route: '/translations', permission: CcePermission.TranslationManage, icon: 'translate' }, + { labelKey: 'nav.settings', route: '/settings', permission: CcePermission.SettingsManage, icon: 'settings' }, ], }, ]; diff --git a/frontend/apps/admin-cms/src/app/core/layout/shell.component.html b/frontend/apps/admin-cms/src/app/core/layout/shell.component.html index 26aa6cb5..fbcf657d 100644 --- a/frontend/apps/admin-cms/src/app/core/layout/shell.component.html +++ b/frontend/apps/admin-cms/src/app/core/layout/shell.component.html @@ -1,9 +1,9 @@ - - + + - + diff --git a/frontend/apps/admin-cms/src/app/core/layout/shell.component.spec.ts b/frontend/apps/admin-cms/src/app/core/layout/shell.component.spec.ts index e11b3aab..87f2ea1c 100644 --- a/frontend/apps/admin-cms/src/app/core/layout/shell.component.spec.ts +++ b/frontend/apps/admin-cms/src/app/core/layout/shell.component.spec.ts @@ -1,7 +1,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { provideRouter } from '@angular/router'; import { provideNoopAnimations } from '@angular/platform-browser/animations'; -import { TranslateModule } from '@ngx-translate/core'; +import { TranslocoModule } from '@jsverse/transloco'; import { OidcSecurityService } from 'angular-auth-oidc-client'; import { of } from 'rxjs'; import { LocaleService } from '@frontend/i18n'; @@ -25,7 +25,7 @@ describe('ShellComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [ShellComponent, TranslateModule.forRoot()], + imports: [ShellComponent, TranslocoModule.forRoot()], providers: [ provideRouter([]), provideNoopAnimations(), diff --git a/frontend/apps/admin-cms/src/app/core/layout/shell.component.ts b/frontend/apps/admin-cms/src/app/core/layout/shell.component.ts index 7ce5639b..e0640876 100644 --- a/frontend/apps/admin-cms/src/app/core/layout/shell.component.ts +++ b/frontend/apps/admin-cms/src/app/core/layout/shell.component.ts @@ -1,31 +1,33 @@ -import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; -import { CommonModule } from '@angular/common'; +import { ChangeDetectionStrategy, Component, computed, inject } from '@angular/core'; +import { toSignal } from '@angular/core/rxjs-interop'; + import { RouterOutlet } from '@angular/router'; import { MatSidenavModule } from '@angular/material/sidenav'; -import { TranslateModule, TranslateService } from '@ngx-translate/core'; +import { TranslocoModule, TranslocoService } from '@jsverse/transloco'; import { AppShellComponent } from '@frontend/ui-kit'; -import { LocaleSwitcherComponent } from '../../locale-switcher/locale-switcher.component'; -import { AuthToolbarComponent } from '../../auth-toolbar/auth-toolbar.component'; +import { LocaleSwitcherComponent, LocaleService } from '@frontend/i18n'; +import { AuthToolbarComponent } from './auth-toolbar.component'; import { SideNavComponent } from './side-nav.component'; @Component({ selector: 'cce-shell', standalone: true, imports: [ - CommonModule, RouterOutlet, MatSidenavModule, AppShellComponent, SideNavComponent, LocaleSwitcherComponent, AuthToolbarComponent, - TranslateModule, - ], + TranslocoModule +], templateUrl: './shell.component.html', styleUrl: './shell.component.scss', changeDetection: ChangeDetectionStrategy.OnPush, }) export class ShellComponent { - private readonly translate = inject(TranslateService); - readonly title = this.translate.instant('common.appName') || 'CCE Admin'; + private readonly translate = inject(TranslocoService); + private readonly localeService = inject(LocaleService); + readonly title = toSignal(this.translate.selectTranslate('common.appName'), { initialValue: 'CCE' }); + readonly dir = computed(() => this.localeService.locale() === 'ar' ? 'rtl' : 'ltr'); } diff --git a/frontend/apps/admin-cms/src/app/core/layout/side-nav.component.html b/frontend/apps/admin-cms/src/app/core/layout/side-nav.component.html index c294f69f..715711a1 100644 --- a/frontend/apps/admin-cms/src/app/core/layout/side-nav.component.html +++ b/frontend/apps/admin-cms/src/app/core/layout/side-nav.component.html @@ -2,16 +2,16 @@
CCE - Admin Console + {{ 'nav.adminConsole' | transloco }}
-