Implement customer management domain with authorization and API enhancements

- Introduced a new customer management domain, including entities, services, handlers, and forms for customer operations.
- Added JWT-based user authorization settings in the configuration file for both user and customer management.
- Updated API endpoints to reflect the new structure, including changes to health check and user management routes.
- Enhanced Swagger documentation to include new customer-related endpoints and authorization details.
- Refactored the Makefile to include a target for generating API documentation.
- Removed obsolete documentation files to streamline the project structure.
This commit is contained in:
n.nakhostin
2025-08-11 12:55:08 +03:30
parent 29d859de37
commit 8c1e593686
23 changed files with 7485 additions and 2608 deletions
-214
View File
@@ -1,214 +0,0 @@
# User Management Service
This service provides comprehensive user management functionality for the Tender Management system, following Clean Architecture principles and Domain-Driven Design patterns.
## Features
### User Authentication
- **Login**: Authenticate users with email/username and password
- **Refresh Token**: Refresh access tokens
- **Logout**: Securely log out users
- **Password Management**: Change password and reset password functionality
### User Management
- **Create User**: Create new users with roles and permissions
- **Update User**: Update user information and profile
- **Delete User**: Soft delete users (set status to inactive)
- **Get User**: Retrieve user information by ID
- **List Users**: Search and filter users with pagination
### Role-Based Access Control
- **User Roles**: admin, manager, operator, viewer
- **Role Management**: Update user roles
- **Status Management**: Activate, deactivate, or suspend users
### Company Management
- **Company Users**: Get users by company ID
- **User Count**: Count users per company
## API Endpoints
### Public Endpoints
#### Authentication
```
POST /api/v1/users/login
POST /api/v1/users/refresh-token
POST /api/v1/users/reset-password
```
### Protected Endpoints (Require Authentication)
#### User Profile
```
GET /api/v1/users/profile
PUT /api/v1/users/profile
PUT /api/v1/users/change-password
POST /api/v1/users/logout
```
### Admin Endpoints (Require Admin Role)
#### User Management
```
POST /api/v1/users/admin/
GET /api/v1/users/admin/
GET /api/v1/users/admin/:id
PUT /api/v1/users/admin/:id
DELETE /api/v1/users/admin/:id
```
#### User Status & Role Management
```
PUT /api/v1/users/admin/:id/status
PUT /api/v1/users/admin/:id/role
```
#### Company & Role Queries
```
GET /api/v1/users/admin/company/:company_id
GET /api/v1/users/admin/role/:role
```
## Request/Response Examples
### Create User
```json
POST /api/v1/users/admin/
{
"full_name": "John Doe",
"username": "johndoe",
"email": "john.doe@example.com",
"password": "securepassword123",
"role": "manager",
"company_id": "550e8400-e29b-41d4-a716-446655440000",
"department": "Engineering",
"position": "Senior Manager",
"phone": "+1234567890",
"profile_image": "https://example.com/avatar.jpg"
}
```
### Login
```json
POST /api/v1/users/login
{
"email_or_username": "john.doe@example.com",
"password": "securepassword123"
}
```
### Update User
```json
PUT /api/v1/users/admin/:id
{
"full_name": "John Smith",
"department": "Product Management",
"status": "active"
}
```
### List Users with Filters
```
GET /api/v1/users/admin/?search=john&role=manager&status=active&limit=20&offset=0&sort_by=created_at&sort_order=desc
```
## Data Models
### User Entity
```go
type User struct {
ID uuid.UUID `bson:"_id"`
FullName string `bson:"full_name"`
Username string `bson:"username"`
Email string `bson:"email"`
Password string `bson:"password"`
Role UserRole `bson:"role"`
Status UserStatus `bson:"status"`
CompanyID *uuid.UUID `bson:"company_id,omitempty"`
Department *string `bson:"department,omitempty"`
Position *string `bson:"position,omitempty"`
Phone *string `bson:"phone,omitempty"`
ProfileImage *string `bson:"profile_image,omitempty"`
IsVerified bool `bson:"is_verified"`
LastLoginAt *int64 `bson:"last_login_at,omitempty"`
CreatedAt int64 `bson:"created_at"`
UpdatedAt int64 `bson:"updated_at"`
CreatedBy *uuid.UUID `bson:"created_by,omitempty"`
UpdatedBy *uuid.UUID `bson:"updated_by,omitempty"`
}
```
### User Roles
- `admin`: Full system access
- `manager`: Company and team management
- `operator`: Operational tasks
- `viewer`: Read-only access
### User Status
- `active`: User can access the system
- `inactive`: User account is disabled
- `suspended`: User account is temporarily suspended
## Security Features
### Password Security
- Passwords are hashed using bcrypt
- Minimum password length: 8 characters
- Maximum password length: 128 characters
### Authentication
- JWT-based authentication (to be implemented)
- Token refresh mechanism
- Secure logout with token invalidation
### Authorization
- Role-based access control
- Admin-only endpoints for user management
- Company-scoped access for multi-tenant support
## Database Indexes
The service creates the following MongoDB indexes for optimal performance:
- **Email Index**: Unique index on email field
- **Username Index**: Unique index on username field
- **Company ID Index**: For company-based queries
- **Role Index**: For role-based filtering
- **Status Index**: For status-based filtering
- **Created At Index**: For sorting by creation date
- **Text Search Index**: For full-text search across name, email, username, department, and position
## Error Handling
The service provides comprehensive error handling with:
- **Validation Errors**: Detailed validation messages using govalidator
- **Business Logic Errors**: Clear error messages for business rule violations
- **Database Errors**: Proper handling of database constraints and connection issues
- **Security Errors**: Secure error messages that don't leak sensitive information
## Logging
All operations are logged with structured logging including:
- **Operation Context**: User ID, company ID, operation type
- **Error Details**: Full error context for debugging
- **Security Events**: Login attempts, password changes, role updates
- **Performance Metrics**: Operation timing and resource usage
## Future Enhancements
### Planned Features
- **JWT Token Management**: Complete JWT implementation with refresh tokens
- **Email Verification**: Email verification for new user accounts
- **Password Reset**: Complete password reset flow with email
- **Audit Trail**: Comprehensive audit logging for all user operations
- **Bulk Operations**: Bulk user import/export functionality
- **Advanced Search**: Elasticsearch integration for advanced search capabilities
### Integration Points
- **Email Service**: For password reset and verification emails
- **Notification Service**: For user activity notifications
- **Audit Service**: For comprehensive audit logging
- **Permission Service**: For fine-grained permission management
+16 -16
View File
@@ -72,7 +72,7 @@ func (h *Handler) RegisterRoutes(e *echo.Echo) {
// @Failure 400 {object} response.APIResponse
// @Failure 401 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /login [post]
// @Router /admin/v1/login [post]
func (h *Handler) Login(c echo.Context) error {
form, err := response.Parse[LoginForm](c)
if err != nil {
@@ -99,7 +99,7 @@ func (h *Handler) Login(c echo.Context) error {
// @Failure 400 {object} response.APIResponse
// @Failure 401 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /refresh-token [post]
// @Router /admin/v1/refresh-token [post]
func (h *Handler) RefreshToken(c echo.Context) error {
form, err := response.Parse[RefreshTokenForm](c)
if err != nil {
@@ -124,7 +124,7 @@ func (h *Handler) RefreshToken(c echo.Context) error {
// @Success 200 {object} response.APIResponse
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /reset-password [post]
// @Router /admin/v1/reset-password [post]
func (h *Handler) ResetPassword(c echo.Context) error {
form, err := response.Parse[ResetPasswordForm](c)
if err != nil {
@@ -152,7 +152,7 @@ func (h *Handler) ResetPassword(c echo.Context) error {
// @Failure 401 {object} response.APIResponse
// @Failure 404 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /profile [get]
// @Router /admin/v1/profile [get]
func (h *Handler) GetProfile(c echo.Context) error {
// Extract user ID from JWT token context
userID, err := GetUserIDFromContext(c)
@@ -180,7 +180,7 @@ func (h *Handler) GetProfile(c echo.Context) error {
// @Failure 400 {object} response.APIResponse
// @Failure 401 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /profile [put]
// @Router /admin/v1/profile [put]
func (h *Handler) UpdateProfile(c echo.Context) error {
// Extract user ID from JWT token context
userID, err := GetUserIDFromContext(c)
@@ -213,7 +213,7 @@ func (h *Handler) UpdateProfile(c echo.Context) error {
// @Failure 400 {object} response.APIResponse
// @Failure 401 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /change-password [put]
// @Router /admin/v1/change-password [put]
func (h *Handler) ChangePassword(c echo.Context) error {
userID, err := GetUserIDFromContext(c)
if err != nil {
@@ -245,7 +245,7 @@ func (h *Handler) ChangePassword(c echo.Context) error {
// @Success 200 {object} response.APIResponse
// @Failure 401 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /logout [delete]
// @Router /admin/v1/logout [delete]
func (h *Handler) Logout(c echo.Context) error {
// Extract user ID and access token from context
userID, err := GetUserIDFromContext(c)
@@ -281,7 +281,7 @@ func (h *Handler) Logout(c echo.Context) error {
// @Failure 401 {object} response.APIResponse
// @Failure 403 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /users [post]
// @Router /admin/v1/users [post]
func (h *Handler) CreateUser(c echo.Context) error {
// Get current user ID from JWT token
currentUserID, err := GetUserIDFromContext(c)
@@ -328,7 +328,7 @@ func (h *Handler) CreateUser(c echo.Context) error {
// @Failure 401 {object} response.APIResponse
// @Failure 403 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /users [get]
// @Router /admin/v1/users [get]
func (h *Handler) ListUsers(c echo.Context) error {
var form ListUsersForm
if err := c.Bind(&form); err != nil {
@@ -363,7 +363,7 @@ func (h *Handler) ListUsers(c echo.Context) error {
// @Failure 403 {object} response.APIResponse
// @Failure 404 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /users/{id} [get]
// @Router /admin/v1/users/{id} [get]
func (h *Handler) GetUserByID(c echo.Context) error {
idStr := c.Param("id")
userID, err := uuid.Parse(idStr)
@@ -394,7 +394,7 @@ func (h *Handler) GetUserByID(c echo.Context) error {
// @Failure 403 {object} response.APIResponse
// @Failure 404 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /users/{id} [put]
// @Router /admin/v1/users/{id} [put]
func (h *Handler) UpdateUser(c echo.Context) error {
// Extract user ID from JWT token context
currentUserID, err := GetUserIDFromContext(c)
@@ -441,7 +441,7 @@ func (h *Handler) UpdateUser(c echo.Context) error {
// @Failure 403 {object} response.APIResponse
// @Failure 404 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /users/{id} [delete]
// @Router /admin/v1/users/{id} [delete]
func (h *Handler) DeleteUser(c echo.Context) error {
// Extract user ID from JWT token context
currentUserID, err := GetUserIDFromContext(c)
@@ -480,7 +480,7 @@ func (h *Handler) DeleteUser(c echo.Context) error {
// @Failure 403 {object} response.APIResponse
// @Failure 404 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /users/{id}/status [put]
// @Router /admin/v1/users/{id}/status [put]
func (h *Handler) UpdateUserStatus(c echo.Context) error {
currentUserID, err := GetUserIDFromContext(c)
if err != nil {
@@ -529,7 +529,7 @@ func (h *Handler) UpdateUserStatus(c echo.Context) error {
// @Failure 403 {object} response.APIResponse
// @Failure 404 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /users/{id}/role [put]
// @Router /admin/v1/users/{id}/role [put]
func (h *Handler) UpdateUserRole(c echo.Context) error {
// Extract user ID from JWT token context
currentUserID, err := GetUserIDFromContext(c)
@@ -579,7 +579,7 @@ func (h *Handler) UpdateUserRole(c echo.Context) error {
// @Failure 401 {object} response.APIResponse
// @Failure 403 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /users/company/{company_id} [get]
// @Router /admin/v1/users/company/{company_id} [get]
func (h *Handler) GetUsersByCompanyID(c echo.Context) error {
companyIDStr := c.Param("company_id")
companyID, err := uuid.Parse(companyIDStr)
@@ -643,7 +643,7 @@ func (h *Handler) GetUsersByCompanyID(c echo.Context) error {
// @Failure 401 {object} response.APIResponse
// @Failure 403 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /users/role/{role} [get]
// @Router /admin/v1/users/role/{role} [get]
func (h *Handler) GetUsersByRole(c echo.Context) error {
roleStr := c.Param("role")
role := UserRole(roleStr)