Implement Feedback Management System with CRUD Operations and API Enhancements

- Introduced a new feedback management system, including the creation of feedback entities, services, and repositories.
- Implemented CRUD operations for feedback, allowing users to submit likes and dislikes on tenders.
- Developed administrative endpoints for listing and retrieving feedback with comprehensive filtering options.
- Enhanced public API to allow users to view feedback related to tenders.
- Updated Swagger documentation to reflect new feedback endpoints and their functionalities.
- Removed obsolete configuration file `config.yaml` as part of the transition to a modular configuration system.
- Ensured adherence to Clean Architecture principles throughout the implementation.
This commit is contained in:
n.nakhostin
2025-08-16 16:00:03 +03:30
parent 126913365f
commit 21b736b55b
15 changed files with 3548 additions and 108 deletions
+933
View File
@@ -3431,6 +3431,436 @@ const docTemplate = `{
}
}
},
"/admin/v1/feedback": {
"get": {
"security": [
{
"BearerAuth": []
}
],
"description": "Retrieve paginated list of feedback with optional filtering by various criteria. This endpoint is for administrative use and provides comprehensive filtering options.",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Admin-Feedback"
],
"summary": "List feedback with filters",
"parameters": [
{
"type": "string",
"description": "Filter by tender ID (MongoDB ObjectID format)",
"name": "tender_id",
"in": "query"
},
{
"type": "string",
"description": "Filter by customer ID (MongoDB ObjectID format)",
"name": "customer_id",
"in": "query"
},
{
"type": "string",
"description": "Filter by company ID (MongoDB ObjectID format)",
"name": "company_id",
"in": "query"
},
{
"enum": [
"like",
"dislike"
],
"type": "string",
"description": "Filter by feedback type",
"name": "feedback_type",
"in": "query"
},
{
"type": "integer",
"format": "int64",
"description": "Filter by creation date from (Unix timestamp in seconds)",
"name": "date_from",
"in": "query"
},
{
"type": "integer",
"format": "int64",
"description": "Filter by creation date to (Unix timestamp in seconds)",
"name": "date_to",
"in": "query"
},
{
"maximum": 100,
"minimum": 1,
"type": "integer",
"description": "Number of items per page (default: 20, max: 100)",
"name": "limit",
"in": "query"
},
{
"minimum": 0,
"type": "integer",
"description": "Number of items to skip for pagination (default: 0)",
"name": "offset",
"in": "query"
}
],
"responses": {
"200": {
"description": "Feedback list retrieved successfully",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.APIResponse"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/feedback.FeedbackListResponse"
}
}
}
]
}
},
"400": {
"description": "Bad request - Invalid query parameters",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.APIResponse"
},
{
"type": "object",
"properties": {
"error": {
"type": "string"
},
"message": {
"type": "string"
}
}
}
]
}
},
"422": {
"description": "Validation error - Invalid filter criteria",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.APIResponse"
},
{
"type": "object",
"properties": {
"error": {
"type": "string"
},
"message": {
"type": "string"
}
}
}
]
}
},
"500": {
"description": "Internal server error",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.APIResponse"
},
{
"type": "object",
"properties": {
"error": {
"type": "string"
},
"message": {
"type": "string"
}
}
}
]
}
}
}
}
},
"/admin/v1/feedback/{id}": {
"get": {
"security": [
{
"BearerAuth": []
}
],
"description": "Retrieve feedback details by its unique identifier with loaded tender, customer, and company information. This endpoint provides comprehensive feedback data including related entity details.",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Admin-Feedback"
],
"summary": "Get feedback by ID",
"parameters": [
{
"maxLength": 24,
"minLength": 24,
"type": "string",
"description": "Feedback ID (MongoDB ObjectID format)",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "feedback retrieved successfully",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.APIResponse"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/feedback.FeedbackResponse"
}
}
}
]
}
},
"400": {
"description": "Bad request - Invalid feedback ID format",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.APIResponse"
},
{
"type": "object",
"properties": {
"error": {
"type": "string"
},
"message": {
"type": "string"
}
}
}
]
}
},
"404": {
"description": "Feedback not found",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.APIResponse"
},
{
"type": "object",
"properties": {
"error": {
"type": "string"
},
"message": {
"type": "string"
}
}
}
]
}
},
"500": {
"description": "Internal server error",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.APIResponse"
},
{
"type": "object",
"properties": {
"error": {
"type": "string"
},
"message": {
"type": "string"
}
}
}
]
}
}
}
},
"delete": {
"security": [
{
"BearerAuth": []
}
],
"description": "Mark feedback as deleted without permanently removing it from the database. The feedback will be marked as deleted and hidden from normal queries but can be restored if needed.",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Admin-Feedback"
],
"summary": "Soft delete feedback",
"parameters": [
{
"maxLength": 24,
"minLength": 24,
"type": "string",
"description": "Feedback ID (MongoDB ObjectID format)",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "Feedback soft deleted successfully",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.APIResponse"
},
{
"type": "object",
"properties": {
"message": {
"type": "string"
}
}
}
]
}
},
"400": {
"description": "Bad request - Invalid feedback ID format",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.APIResponse"
},
{
"type": "object",
"properties": {
"error": {
"type": "string"
},
"message": {
"type": "string"
}
}
}
]
}
},
"401": {
"description": "Unauthorized - User not authenticated",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.APIResponse"
},
{
"type": "object",
"properties": {
"error": {
"type": "string"
},
"message": {
"type": "string"
}
}
}
]
}
},
"403": {
"description": "Forbidden - User not authorized to delete this feedback",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.APIResponse"
},
{
"type": "object",
"properties": {
"error": {
"type": "string"
},
"message": {
"type": "string"
}
}
}
]
}
},
"404": {
"description": "Not found - Feedback not found",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.APIResponse"
},
{
"type": "object",
"properties": {
"error": {
"type": "string"
},
"message": {
"type": "string"
}
}
}
]
}
},
"500": {
"description": "Internal server error",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.APIResponse"
},
{
"type": "object",
"properties": {
"error": {
"type": "string"
},
"message": {
"type": "string"
}
}
}
]
}
}
}
}
},
"/admin/v1/health": {
"get": {
"description": "Get comprehensive server health status including system information, dependencies status, and performance metrics. This endpoint is used for monitoring and load balancer health checks.",
@@ -4663,6 +5093,417 @@ const docTemplate = `{
}
}
},
"/api/v1/feedback": {
"get": {
"security": [
{
"BearerAuth": []
}
],
"description": "Retrieve paginated list of feedback with optional filtering by various criteria. This endpoint is for public use and filters results based on the authenticated user's company.",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Feedback"
],
"summary": "List feedback with filters",
"parameters": [
{
"type": "string",
"description": "Filter by tender ID (MongoDB ObjectID format)",
"name": "tender_id",
"in": "query"
},
{
"type": "string",
"description": "Filter by customer ID (MongoDB ObjectID format)",
"name": "customer_id",
"in": "query"
},
{
"type": "string",
"description": "Filter by company ID (MongoDB ObjectID format)",
"name": "company_id",
"in": "query"
},
{
"enum": [
"like",
"dislike"
],
"type": "string",
"description": "Filter by feedback type",
"name": "feedback_type",
"in": "query"
},
{
"minimum": 0,
"type": "integer",
"format": "int64",
"description": "Filter by creation date from (Unix timestamp in seconds)",
"name": "date_from",
"in": "query"
},
{
"minimum": 0,
"type": "integer",
"format": "int64",
"description": "Filter by creation date to (Unix timestamp in seconds)",
"name": "date_to",
"in": "query"
},
{
"maximum": 100,
"minimum": 1,
"type": "integer",
"description": "Number of items per page (default: 20, max: 100)",
"name": "limit",
"in": "query"
},
{
"minimum": 0,
"type": "integer",
"description": "Number of items to skip for pagination (default: 0)",
"name": "offset",
"in": "query"
}
],
"responses": {
"200": {
"description": "Feedback list retrieved successfully",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.APIResponse"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/feedback.FeedbackListResponse"
}
}
}
]
}
},
"400": {
"description": "Bad request - Invalid query parameters or missing company association",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.APIResponse"
},
{
"type": "object",
"properties": {
"error": {
"type": "string"
},
"message": {
"type": "string"
}
}
}
]
}
},
"422": {
"description": "Validation error - Invalid filter criteria",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.APIResponse"
},
{
"type": "object",
"properties": {
"error": {
"type": "string"
},
"message": {
"type": "string"
}
}
}
]
}
},
"500": {
"description": "Internal server error",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.APIResponse"
},
{
"type": "object",
"properties": {
"error": {
"type": "string"
},
"message": {
"type": "string"
}
}
}
]
}
}
}
},
"post": {
"security": [
{
"BearerAuth": []
}
],
"description": "Toggle between like and dislike for a tender, or create a like if no feedback exists. This endpoint allows users to express their preference for tenders and automatically handles the toggle logic.",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Feedback"
],
"summary": "Toggle feedback for a tender",
"parameters": [
{
"description": "Feedback toggle request containing tender ID",
"name": "feedback",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/feedback.ToggleFeedbackForm"
}
}
],
"responses": {
"200": {
"description": "Feedback toggled successfully",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.APIResponse"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/feedback.FeedbackResponse"
}
}
}
]
}
},
"400": {
"description": "Bad request - Invalid input data or missing customer/company association",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.APIResponse"
},
{
"type": "object",
"properties": {
"error": {
"type": "string"
},
"message": {
"type": "string"
}
}
}
]
}
},
"401": {
"description": "Unauthorized - User not authenticated",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.APIResponse"
},
{
"type": "object",
"properties": {
"error": {
"type": "string"
},
"message": {
"type": "string"
}
}
}
]
}
},
"422": {
"description": "Validation error - Invalid request data format",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.APIResponse"
},
{
"type": "object",
"properties": {
"error": {
"type": "string"
},
"message": {
"type": "string"
}
}
}
]
}
},
"500": {
"description": "Internal server error",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.APIResponse"
},
{
"type": "object",
"properties": {
"error": {
"type": "string"
},
"message": {
"type": "string"
}
}
}
]
}
}
}
}
},
"/api/v1/feedback/{id}": {
"get": {
"security": [
{
"BearerAuth": []
}
],
"description": "Retrieve feedback details by its unique identifier. This endpoint provides basic feedback information for public users.",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Feedback"
],
"summary": "Get feedback by ID",
"parameters": [
{
"maxLength": 24,
"minLength": 24,
"type": "string",
"description": "Feedback ID (MongoDB ObjectID format)",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "Feedback retrieved successfully",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.APIResponse"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/feedback.FeedbackResponse"
}
}
}
]
}
},
"400": {
"description": "Bad request - Invalid feedback ID format",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.APIResponse"
},
{
"type": "object",
"properties": {
"error": {
"type": "string"
},
"message": {
"type": "string"
}
}
}
]
}
},
"404": {
"description": "Feedback not found",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.APIResponse"
},
{
"type": "object",
"properties": {
"error": {
"type": "string"
},
"message": {
"type": "string"
}
}
}
]
}
},
"500": {
"description": "Internal server error",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.APIResponse"
},
{
"type": "object",
"properties": {
"error": {
"type": "string"
},
"message": {
"type": "string"
}
}
}
]
}
}
}
}
},
"/api/v1/profile": {
"get": {
"security": [
@@ -4903,6 +5744,11 @@ const docTemplate = `{
},
"/api/v1/tenders": {
"get": {
"security": [
{
"BearerAuth": []
}
],
"description": "Retrieve active tenders for mobile application users with automatic company-based matching from customer profile",
"produces": [
"application/json"
@@ -4980,6 +5826,11 @@ const docTemplate = `{
},
"/api/v1/tenders/{id}": {
"get": {
"security": [
{
"BearerAuth": []
}
],
"description": "Retrieve detailed information about a specific tender for mobile application users",
"produces": [
"application/json"
@@ -6156,6 +7007,80 @@ const docTemplate = `{
}
}
},
"feedback.FeedbackListResponse": {
"type": "object",
"properties": {
"feedback": {
"type": "array",
"items": {
"$ref": "#/definitions/feedback.FeedbackResponse"
}
},
"meta": {
"$ref": "#/definitions/response.Meta"
}
}
},
"feedback.FeedbackResponse": {
"type": "object",
"properties": {
"company_id": {
"type": "string"
},
"created_at": {
"type": "integer"
},
"customer_id": {
"type": "string"
},
"feedback_type": {
"$ref": "#/definitions/feedback.FeedbackType"
},
"id": {
"type": "string"
},
"tender": {
"type": "string"
},
"updated_at": {
"type": "integer"
}
}
},
"feedback.FeedbackType": {
"type": "string",
"enum": [
"like",
"dislike"
],
"x-enum-varnames": [
"FeedbackTypeLike",
"FeedbackTypeDislike"
]
},
"feedback.ToggleFeedbackForm": {
"type": "object",
"required": [
"feedback_type",
"tender_id"
],
"properties": {
"feedback_type": {
"enum": [
"like",
"dislike"
],
"allOf": [
{
"$ref": "#/definitions/feedback.FeedbackType"
}
]
},
"tender_id": {
"type": "string"
}
}
},
"main.HealthResponse": {
"type": "object",
"properties": {
@@ -7271,6 +8196,10 @@ const docTemplate = `{
"description": "Administrative scraping job management operations for TED XML data collection including job control, monitoring, and status tracking",
"name": "Admin-Scraping"
},
{
"description": "Administrative feedback management operations for web panel including CRUD operations, search, statistics, and comprehensive filtering with pagination",
"name": "Admin-Feedback"
},
{
"description": "Customer authentication and authorization operations for mobile application including login, logout, token refresh, and profile access",
"name": "Authorization"
@@ -7278,6 +8207,10 @@ const docTemplate = `{
{
"description": "Public tender information access for mobile application including active tender listings and detailed tender information",
"name": "Tenders"
},
{
"description": "Public feedback management operations for mobile application including like, dislike, and comment on tenders",
"name": "Feedback"
}
]
}`