Initialize base
This commit is contained in:
+260
@@ -0,0 +1,260 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/labstack/echo/v4/middleware"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
|
||||
"tm/internal/domain"
|
||||
"tm/internal/handler"
|
||||
"tm/internal/infrastructure"
|
||||
"tm/internal/repository"
|
||||
"tm/internal/service"
|
||||
"tm/pkg/logger"
|
||||
customMiddleware "tm/pkg/middleware"
|
||||
"tm/pkg/response"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Load configuration
|
||||
config, err := infrastructure.LoadConfig("./configs")
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Failed to load config: %v", err))
|
||||
}
|
||||
|
||||
// Initialize logger
|
||||
logger.InitLogger(&config.Logging)
|
||||
log := logger.GetLogger()
|
||||
|
||||
log.Info("Starting Tender Management API Server", map[string]interface{}{
|
||||
"version": "1.0.0",
|
||||
"port": config.Server.Port,
|
||||
})
|
||||
|
||||
// Initialize MongoDB connection
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
mongoClient, err := mongo.Connect(ctx, options.Client().ApplyURI(config.Database.MongoDB.URI))
|
||||
if err != nil {
|
||||
log.Fatal("Failed to connect to MongoDB", map[string]interface{}{
|
||||
"error": err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
// Ping MongoDB to verify connection
|
||||
if err = mongoClient.Ping(ctx, nil); err != nil {
|
||||
log.Fatal("Failed to ping MongoDB", map[string]interface{}{
|
||||
"error": err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
log.Info("Connected to MongoDB successfully", map[string]interface{}{
|
||||
"database": config.Database.MongoDB.Name,
|
||||
})
|
||||
|
||||
// Get MongoDB database
|
||||
db := mongoClient.Database(config.Database.MongoDB.Name)
|
||||
|
||||
// Initialize validator
|
||||
validate := validator.New()
|
||||
|
||||
// Initialize repositories
|
||||
customerRepo := repository.NewCustomerRepository(db, log)
|
||||
userRepo := repository.NewUserRepository(db, log)
|
||||
companyRepo := repository.NewCompanyRepository(db, log)
|
||||
|
||||
// Initialize services
|
||||
customerAuthService := service.NewCustomerAuthService(customerRepo, companyRepo, &config.Auth, log)
|
||||
userAuthService := service.NewUserAuthService(userRepo, &config.Auth, log)
|
||||
// TODO: Initialize customer service when needed for admin customer management
|
||||
// customerService := service.NewCustomerService(customerRepo, log)
|
||||
|
||||
// Backward compatibility - create generic auth service
|
||||
authService := handler.NewAuthHandler(customerAuthService, userAuthService, validate, log)
|
||||
|
||||
// Initialize handlers
|
||||
customerAuthHandler := handler.NewCustomerAuthHandler(customerAuthService, validate, log)
|
||||
userAuthHandler := handler.NewUserAuthHandler(userAuthService, validate, log)
|
||||
|
||||
// Initialize Echo
|
||||
e := echo.New()
|
||||
|
||||
// Configure Echo
|
||||
e.HideBanner = true
|
||||
e.HidePort = true
|
||||
|
||||
// Add built-in middleware
|
||||
e.Use(middleware.Logger())
|
||||
e.Use(middleware.Recover())
|
||||
e.Use(middleware.CORS())
|
||||
e.Use(middleware.RequestID())
|
||||
|
||||
// Add custom middleware for logging
|
||||
e.Use(func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
start := time.Now()
|
||||
|
||||
err := next(c)
|
||||
|
||||
log.Info("HTTP Request", map[string]interface{}{
|
||||
"method": c.Request().Method,
|
||||
"path": c.Request().URL.Path,
|
||||
"status": c.Response().Status,
|
||||
"duration": time.Since(start).String(),
|
||||
"request_id": c.Response().Header().Get(echo.HeaderXRequestID),
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
||||
})
|
||||
|
||||
// Add authentication middleware
|
||||
e.Use(customMiddleware.AuthMiddleware(customerAuthService, userAuthService, log))
|
||||
|
||||
// Setup routes
|
||||
setupRoutes(e, authService, customerAuthHandler, userAuthHandler)
|
||||
|
||||
// Health check endpoint
|
||||
e.GET("/health", func(c echo.Context) error {
|
||||
return response.Success(c, map[string]interface{}{
|
||||
"status": "healthy",
|
||||
"timestamp": time.Now().UTC(),
|
||||
"version": "1.0.0",
|
||||
}, "Service is healthy")
|
||||
})
|
||||
|
||||
// Start server in a goroutine
|
||||
go func() {
|
||||
address := fmt.Sprintf("%s:%d", config.Server.Host, config.Server.Port)
|
||||
log.Info("Server starting", map[string]interface{}{
|
||||
"address": address,
|
||||
})
|
||||
|
||||
if err := e.Start(address); err != nil && err != http.ErrServerClosed {
|
||||
log.Fatal("Failed to start server", map[string]interface{}{
|
||||
"error": err.Error(),
|
||||
})
|
||||
}
|
||||
}()
|
||||
|
||||
// Wait for interrupt signal to gracefully shutdown the server
|
||||
quit := make(chan os.Signal, 1)
|
||||
signal.Notify(quit, os.Interrupt, syscall.SIGTERM)
|
||||
<-quit
|
||||
|
||||
log.Info("Server is shutting down...", nil)
|
||||
|
||||
// Create a deadline for graceful shutdown
|
||||
ctx, cancel = context.WithTimeout(context.Background(), config.Server.Timeout)
|
||||
defer cancel()
|
||||
|
||||
// Gracefully shutdown the server
|
||||
if err := e.Shutdown(ctx); err != nil {
|
||||
log.Fatal("Server forced to shutdown", map[string]interface{}{
|
||||
"error": err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
// Close MongoDB connection
|
||||
if err := mongoClient.Disconnect(context.Background()); err != nil {
|
||||
log.Error("Failed to disconnect from MongoDB", map[string]interface{}{
|
||||
"error": err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
log.Info("Server stopped gracefully", nil)
|
||||
|
||||
// Cleanup logger to flush any remaining logs
|
||||
logger.Cleanup()
|
||||
}
|
||||
|
||||
// setupRoutes configures all API routes
|
||||
func setupRoutes(
|
||||
e *echo.Echo,
|
||||
authHandler *handler.AuthHandler,
|
||||
customerAuthHandler *handler.CustomerAuthHandler,
|
||||
userAuthHandler *handler.UserAuthHandler,
|
||||
) {
|
||||
// Legacy/Generic authentication routes (backward compatibility)
|
||||
auth := e.Group("/auth")
|
||||
auth.POST("/register", authHandler.Register)
|
||||
auth.POST("/login", authHandler.Login)
|
||||
auth.POST("/refresh", authHandler.RefreshToken)
|
||||
auth.POST("/change-password", authHandler.ChangePassword)
|
||||
auth.GET("/profile", authHandler.GetProfile)
|
||||
auth.POST("/logout", authHandler.Logout)
|
||||
|
||||
// API version group
|
||||
api := e.Group("/api/v1")
|
||||
|
||||
// Mobile app routes (customers)
|
||||
mobile := api.Group("/mobile")
|
||||
mobileAuth := mobile.Group("/auth")
|
||||
mobileAuth.POST("/register", customerAuthHandler.Register)
|
||||
mobileAuth.POST("/login", customerAuthHandler.Login)
|
||||
mobileAuth.POST("/refresh", customerAuthHandler.RefreshToken)
|
||||
mobileAuth.POST("/verify-email", customerAuthHandler.VerifyEmail)
|
||||
mobileAuth.POST("/resend-verification", customerAuthHandler.ResendVerification)
|
||||
|
||||
// Protected mobile routes
|
||||
mobileAuth.POST("/change-password", customerAuthHandler.ChangePassword, customMiddleware.CustomerOnlyMiddleware())
|
||||
mobileAuth.GET("/profile", customerAuthHandler.GetProfile, customMiddleware.CustomerOnlyMiddleware())
|
||||
mobileAuth.POST("/logout", customerAuthHandler.Logout, customMiddleware.CustomerOnlyMiddleware())
|
||||
|
||||
// Mobile app tenders routes
|
||||
mobileTenders := mobile.Group("/tenders", customMiddleware.CustomerOnlyMiddleware())
|
||||
// TODO: Add tender routes for customers
|
||||
_ = mobileTenders
|
||||
|
||||
// Mobile app companies routes
|
||||
mobileCompanies := mobile.Group("/companies", customMiddleware.CustomerOnlyMiddleware())
|
||||
// TODO: Add company routes for customers
|
||||
_ = mobileCompanies
|
||||
|
||||
// Admin panel routes (panel users)
|
||||
admin := api.Group("/admin")
|
||||
adminAuth := admin.Group("/auth")
|
||||
adminAuth.POST("/login", userAuthHandler.Login)
|
||||
adminAuth.POST("/refresh", userAuthHandler.RefreshToken)
|
||||
|
||||
// Protected admin auth routes
|
||||
adminAuth.POST("/change-password", userAuthHandler.ChangePassword, customMiddleware.UserOnlyMiddleware())
|
||||
adminAuth.GET("/profile", userAuthHandler.GetProfile, customMiddleware.UserOnlyMiddleware())
|
||||
adminAuth.POST("/logout", userAuthHandler.Logout, customMiddleware.UserOnlyMiddleware())
|
||||
|
||||
// Admin user management routes (admin only)
|
||||
adminUsers := admin.Group("/users", customMiddleware.UserRoleMiddleware(domain.UserRoleAdmin))
|
||||
adminUsers.POST("", userAuthHandler.CreatePanelUser)
|
||||
adminUsers.PUT("/:user_id/permissions", userAuthHandler.UpdateUserPermissions)
|
||||
|
||||
// Admin customer management routes
|
||||
adminCustomers := admin.Group("/customers", customMiddleware.UserRoleMiddleware(domain.UserRoleAdmin, domain.UserRoleModerator))
|
||||
// TODO: Add customer management routes for admins
|
||||
_ = adminCustomers
|
||||
|
||||
// Admin tender management routes
|
||||
adminTenders := admin.Group("/tenders", customMiddleware.UserPermissionMiddleware("manage_tenders"))
|
||||
// TODO: Add tender management routes for admins
|
||||
_ = adminTenders
|
||||
|
||||
// Admin company management routes
|
||||
adminCompanies := admin.Group("/companies", customMiddleware.UserPermissionMiddleware("manage_companies"))
|
||||
// TODO: Add company management routes for admins
|
||||
_ = adminCompanies
|
||||
|
||||
// Admin reports routes
|
||||
adminReports := admin.Group("/reports", customMiddleware.UserPermissionMiddleware("view_reports"))
|
||||
// TODO: Add reporting routes for admins
|
||||
_ = adminReports
|
||||
}
|
||||
Reference in New Issue
Block a user