Add Contact Management Functionality

- Introduced a new contact management feature, including the ability to create, retrieve, search, update, and delete contact messages.
- Implemented the Contact entity, repository, service, and handler layers following Clean Architecture principles.
- Added API endpoints for contact operations in Swagger documentation, ensuring comprehensive API specifications.
- Enhanced error handling and validation for contact data, improving robustness and user experience.
- Updated the main application to initialize the contact repository and service, integrating them into the existing system.
This commit is contained in:
n.nakhostin
2025-10-25 18:15:39 +03:30
parent 889a56a9f9
commit 875447ac58
11 changed files with 2151 additions and 10 deletions
+492
View File
@@ -1035,6 +1035,337 @@
}
}
},
"/admin/v1/contacts": {
"get": {
"description": "Search contacts with filters and pagination (admin only)",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"contacts"
],
"summary": "Search contacts",
"parameters": [
{
"type": "string",
"description": "Search query",
"name": "q",
"in": "query"
},
{
"enum": [
"pending",
"in_progress",
"resolved",
"closed"
],
"type": "string",
"description": "Contact status",
"name": "status",
"in": "query"
},
{
"type": "integer",
"description": "Date from (Unix timestamp)",
"name": "date_from",
"in": "query"
},
{
"type": "integer",
"description": "Date to (Unix timestamp)",
"name": "date_to",
"in": "query"
},
{
"maximum": 100,
"minimum": 1,
"type": "integer",
"default": 20,
"description": "Number of contacts per page (1-100)",
"name": "limit",
"in": "query"
},
{
"minimum": 0,
"type": "integer",
"default": 0,
"description": "Number of contacts to skip for pagination",
"name": "offset",
"in": "query"
},
{
"enum": [
"full_name",
"email",
"created_at",
"updated_at",
"status"
],
"type": "string",
"default": "created_at",
"description": "Field to sort by",
"name": "sort_by",
"in": "query"
},
{
"enum": [
"asc",
"desc"
],
"type": "string",
"default": "desc",
"description": "Sort order",
"name": "sort_order",
"in": "query"
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.APIResponse"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/contact.ContactListResponse"
}
}
}
]
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/response.APIResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.APIResponse"
}
}
}
}
},
"/admin/v1/contacts/stats": {
"get": {
"description": "Get contact statistics by status (admin only)",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"contacts"
],
"summary": "Get contact statistics",
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.APIResponse"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/contact.ContactStats"
}
}
}
]
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.APIResponse"
}
}
}
}
},
"/admin/v1/contacts/{id}": {
"get": {
"description": "Retrieve a contact message by its ID (admin only)",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"contacts"
],
"summary": "Get contact by ID",
"parameters": [
{
"type": "string",
"description": "Contact ID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.APIResponse"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/contact.ContactResponse"
}
}
}
]
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/response.APIResponse"
}
},
"404": {
"description": "Not Found",
"schema": {
"$ref": "#/definitions/response.APIResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.APIResponse"
}
}
}
},
"delete": {
"description": "Delete a contact message by ID (admin only)",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"contacts"
],
"summary": "Delete contact",
"parameters": [
{
"type": "string",
"description": "Contact ID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/response.APIResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/response.APIResponse"
}
},
"404": {
"description": "Not Found",
"schema": {
"$ref": "#/definitions/response.APIResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.APIResponse"
}
}
}
}
},
"/admin/v1/contacts/{id}/status": {
"put": {
"description": "Update the status of a contact message (admin only)",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"contacts"
],
"summary": "Update contact status",
"parameters": [
{
"type": "string",
"description": "Contact ID",
"name": "id",
"in": "path",
"required": true
},
{
"description": "Status update information",
"name": "status",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/contact.UpdateContactStatusForm"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/response.APIResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/response.APIResponse"
}
},
"404": {
"description": "Not Found",
"schema": {
"$ref": "#/definitions/response.APIResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.APIResponse"
}
}
}
}
},
"/admin/v1/customers": {
"get": {
"security": [
@@ -4691,6 +5022,64 @@
}
}
},
"/api/v1/contacts": {
"post": {
"description": "Create a new contact message from a user",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"contacts"
],
"summary": "Create a new contact message",
"parameters": [
{
"description": "Contact information",
"name": "contact",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/contact.CreateContactForm"
}
}
],
"responses": {
"201": {
"description": "Created",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.APIResponse"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/contact.ContactResponse"
}
}
}
]
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/response.APIResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.APIResponse"
}
}
}
}
},
"/api/v1/feedback": {
"get": {
"security": [
@@ -7361,6 +7750,109 @@
}
}
},
"contact.ContactListResponse": {
"type": "object",
"properties": {
"contacts": {
"type": "array",
"items": {
"$ref": "#/definitions/contact.ContactResponse"
}
}
}
},
"contact.ContactResponse": {
"type": "object",
"properties": {
"admin_notes": {
"type": "string"
},
"created_at": {
"type": "integer"
},
"email": {
"type": "string"
},
"full_name": {
"type": "string"
},
"id": {
"type": "string"
},
"message": {
"type": "string"
},
"phone": {
"type": "string"
},
"resolved_at": {
"type": "integer"
},
"resolved_by": {
"type": "string"
},
"status": {
"type": "string"
},
"updated_at": {
"type": "integer"
}
}
},
"contact.ContactStats": {
"type": "object",
"properties": {
"closed": {
"type": "integer"
},
"in_progress": {
"type": "integer"
},
"pending": {
"type": "integer"
},
"resolved": {
"type": "integer"
},
"total": {
"type": "integer"
}
}
},
"contact.CreateContactForm": {
"type": "object",
"properties": {
"email": {
"type": "string",
"example": "john.doe@example.com"
},
"full_name": {
"type": "string",
"example": "John Doe"
},
"message": {
"type": "string",
"example": "I have a question about your services"
},
"phone": {
"type": "string",
"example": "+1234567890"
}
}
},
"contact.UpdateContactStatusForm": {
"type": "object",
"properties": {
"admin_notes": {
"type": "string",
"example": "Customer inquiry handled"
},
"status": {
"type": "string",
"example": "in_progress"
}
}
},
"customer.AssignCompaniesForm": {
"type": "object",
"properties": {