8dbd9927b0
continuous-integration/drone/push Build is passing
- Updated the dashboard service to integrate Redis caching for improved performance in statistics retrieval. - Modified the NewService function to accept a Redis client, enabling caching of dashboard statistics. - Implemented logic to retrieve statistics from Redis, falling back to the database if necessary, and introduced a background process to warm the cache. - Enhanced error handling and logging for Redis operations to ensure robust statistics management. - Increased cache duration for scraped documents and adjusted timeout settings for MongoDB queries to optimize performance. This update significantly improves the responsiveness and efficiency of the dashboard by leveraging Redis for caching statistics.
317 lines
16 KiB
Go
317 lines
16 KiB
Go
package main
|
|
|
|
// @title Opplens API
|
|
// @version 1.0.0
|
|
// @description This is a comprehensive API for the Opplens built with Clean Architecture principles and Domain-Driven Design (DDD) patterns. The API provides endpoints for user management, customer management, company management, and authentication for both web panel administration and mobile application access.
|
|
// @termsOfService https://opplens.com/terms
|
|
|
|
// @contact.name Opplens API Support
|
|
// @contact.url https://opplens.com
|
|
// @contact.email info@opplens.com
|
|
|
|
// @license.name MIT
|
|
// @license.url https://opensource.org/licenses/MIT
|
|
|
|
// @securityDefinitions.apikey BearerAuth
|
|
// @in header
|
|
// @name Authorization
|
|
// @description Type "Bearer" followed by a space and JWT token. Example: "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
|
|
|
// @tag.name Admin-Health
|
|
// @tag.description System health check operations for monitoring application status and dependencies
|
|
|
|
// @tag.name Admin-Authorization
|
|
// @tag.description User authentication and authorization operations including login, logout, token refresh, and password management for web panel administration
|
|
|
|
// @tag.name Admin-Users
|
|
// @tag.description Administrative user management operations including CRUD operations, role management, status updates, and profile management for web panel administrators
|
|
|
|
// @tag.name Admin-Customers
|
|
// @tag.description Administrative customer management operations for web panel including CRUD operations, company assignment, verification, status management, and comprehensive filtering with pagination
|
|
|
|
// @tag.name Admin-Companies
|
|
// @tag.description Administrative company management operations for web panel including CRUD operations, tag management, verification, status updates, comprehensive search and filtering, and statistical reporting
|
|
|
|
// @tag.name Admin-Company-Categories
|
|
// @tag.description Administrative company category management operations for web panel including CRUD operations, publish/unpublish status, and comprehensive filtering with pagination
|
|
|
|
// @tag.name Admin-Tenders
|
|
// @tag.description Administrative tender management operations for web panel including CRUD operations, search, statistics, and comprehensive filtering with pagination
|
|
|
|
// @tag.name Admin-Feedback
|
|
// @tag.description Administrative feedback management operations for web panel including CRUD operations, search, statistics, and comprehensive filtering with pagination
|
|
|
|
// @tag.name Admin-TenderApprovals
|
|
// @tag.description Administrative tender approval management operations for web panel including CRUD operations, search, statistics, and comprehensive filtering with pagination
|
|
|
|
// @tag.name Admin-Inquiries
|
|
// @tag.description Administrative inquiry management operations for web panel including CRUD operations, search, statistics, and comprehensive filtering with pagination
|
|
|
|
// @tag.name Admin-Flags
|
|
// @tag.description Administrative flag management operations for web panel including flag listing and retrieval
|
|
|
|
// @tag.name Admin-Notification
|
|
// @tag.description Administrative notification management operations for web panel including CRUD operations, bulk notifications, queue management, and comprehensive filtering with pagination
|
|
|
|
// @tag.name Admin-Contacts
|
|
// @tag.description Administrative contact management operations for web panel including CRUD operations, search, statistics, and comprehensive filtering with pagination
|
|
|
|
// @tag.name Admin-CMS
|
|
// @tag.description Administrative CMS management operations for web panel including CRUD operations, search, statistics, and comprehensive filtering with pagination
|
|
|
|
// @tag.name Admin-AI-Pipeline
|
|
// @tag.description Administrative Opplens AI pipeline operations including scrape, summarize, translate, sync, and background pipeline runs
|
|
|
|
// @tag.name Admin-AuditLogs
|
|
// @tag.description Administrative user action audit log search with filtering by actor, action, target, and time range
|
|
|
|
// @tag.name Authorization
|
|
// @tag.description Customer authentication and authorization operations for mobile application including login, logout, token refresh, and profile access
|
|
|
|
// @tag.name Company
|
|
// @tag.description Company information access for mobile application including company profile and company tenders
|
|
|
|
// @tag.name Tenders
|
|
// @tag.description Public tender information access for mobile application including active tender listings and detailed tender information
|
|
|
|
// @tag.name Feedback
|
|
// @tag.description Public feedback management operations for mobile application including like, dislike, and comment on tenders
|
|
|
|
// @tag.name TenderApprovals
|
|
// @tag.description Public tender approval management operations for mobile application including tender approval listing and detailed tender approval information
|
|
|
|
// @tag.name Inquiries
|
|
// @tag.description Public inquiry management operations for mobile application including inquiry submission and inquiry listing
|
|
|
|
// @tag.name Flags
|
|
// @tag.description Public flag management operations for mobile application including flag retrieval and listing
|
|
|
|
// @tag.name Notification
|
|
// @tag.description Public notification management operations for mobile application including notification listing and detailed notification information
|
|
|
|
// @tag.name Contacts
|
|
// @tag.description Public contact management operations for mobile application including contact submission and contact listing
|
|
|
|
// @tag.name CMS
|
|
// @tag.description Public CMS management operations for mobile application including CMS listing and detailed CMS information
|
|
|
|
// @tag.name Admin-Dashboard
|
|
// @tag.description Administrative dashboard analytics for the OppLens admin home page
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"time"
|
|
"tm/internal/ai_pipeline"
|
|
"tm/internal/assets"
|
|
"tm/internal/auditlog"
|
|
"tm/internal/cms"
|
|
"tm/internal/company"
|
|
"tm/internal/company_category"
|
|
"tm/internal/contact"
|
|
"tm/internal/customer"
|
|
"tm/internal/dashboard"
|
|
"tm/internal/document_scraper"
|
|
"tm/internal/feedback"
|
|
"tm/internal/inquiry"
|
|
"tm/internal/kanban"
|
|
"tm/internal/notification"
|
|
"tm/internal/tender"
|
|
"tm/internal/tender_approval"
|
|
"tm/internal/user"
|
|
"tm/pkg/filestore"
|
|
"tm/pkg/security"
|
|
|
|
"tm/cmd/web/bootstrap"
|
|
_ "tm/cmd/web/docs" // This is generated by swag
|
|
"tm/cmd/web/router"
|
|
)
|
|
|
|
func main() {
|
|
conf := bootstrap.InitConfig()
|
|
|
|
logger := bootstrap.InitLogger(conf.Logging)
|
|
defer logger.Sync()
|
|
|
|
// Initialize MongoDB connection manager
|
|
mongoManager := bootstrap.InitMongoDB(conf.Database.MongoDB, logger)
|
|
defer func() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
defer cancel()
|
|
if err := mongoManager.Close(ctx); err != nil {
|
|
logger.Error("Failed to close MongoDB connection", map[string]interface{}{
|
|
"error": err.Error(),
|
|
})
|
|
}
|
|
}()
|
|
|
|
// Initialize Redis connection manager
|
|
redisClient := bootstrap.InitRedis(conf.Cache.Redis, logger)
|
|
defer func() {
|
|
if err := redisClient.Close(); err != nil {
|
|
logger.Error("Failed to close Redis connection", map[string]interface{}{
|
|
"error": err.Error(),
|
|
})
|
|
}
|
|
}()
|
|
|
|
// Initialize notification service
|
|
notificationSDK := bootstrap.InitNotificationService(conf.Notification, logger)
|
|
xssPolicy := security.NewXSSPolicy()
|
|
|
|
// Initialize file store service
|
|
fileStoreService, err := bootstrap.InitFileStore(mongoManager, logger)
|
|
if err != nil {
|
|
logger.Fatal("Failed to initialize file store service", map[string]interface{}{
|
|
"error": err.Error(),
|
|
})
|
|
}
|
|
|
|
// Initialize hCaptcha verifier
|
|
hcaptchaVerifier := bootstrap.InitHCaptchaService(conf.HCaptcha, logger)
|
|
|
|
// Initialize AI Summarizer service
|
|
var aiSummarizerClient tender.AISummarizerClient
|
|
var aiSummarizerStorage tender.AISummarizerStorage
|
|
var procedureDocumentsLister dashboard.ProcedureDocumentsLister
|
|
var aiRecommendationClient company.AIRecommendationClient
|
|
var aiPipelineClient ai_pipeline.Client
|
|
|
|
if c := bootstrap.InitAISummarizerClient(conf.AISummarizer, mongoManager, logger); c != nil {
|
|
aiSummarizerClient = c
|
|
aiPipelineClient = c
|
|
aiRecommendationClient = c
|
|
}
|
|
if s := bootstrap.InitAISummarizerStorage(conf.AISummarizer, logger); s != nil {
|
|
aiSummarizerStorage = s
|
|
procedureDocumentsLister = s
|
|
}
|
|
|
|
// Initialize authorization service
|
|
userAuthService := bootstrap.InitAuthorizationService(conf.UserAuth.JWT, redisClient, logger)
|
|
customerAuthService := bootstrap.InitAuthorizationService(conf.CustomerAuth.JWT, redisClient, logger)
|
|
goRulesClient := bootstrap.InitGoRulesClient(conf.GoRules, logger)
|
|
|
|
// Initialize repositories with MongoDB connection manager
|
|
userRepository := user.NewRepository(mongoManager, logger)
|
|
customerRepository := customer.NewRepository(mongoManager, logger)
|
|
companyRepository := company.NewRepository(mongoManager, logger)
|
|
categoryRepository := company_category.NewRepository(mongoManager, logger)
|
|
tenderRepository := tender.NewRepository(mongoManager, logger)
|
|
feedbackRepo := feedback.NewRepository(mongoManager, logger)
|
|
tenderApprovalRepository := tender_approval.NewRepository(mongoManager, logger)
|
|
inquiryRepository := inquiry.NewRepository(mongoManager, logger)
|
|
contactRepository := contact.NewContactRepository(mongoManager, logger)
|
|
cmsRepository := cms.NewRepository(mongoManager, logger)
|
|
// noticeRepository := notice.NewRepository(mongoManager, logger)
|
|
boardRepository := kanban.NewBoardRepository(mongoManager, logger)
|
|
columnRepository := kanban.NewColumnRepository(mongoManager, logger)
|
|
cardRepository := kanban.NewCardRepository(mongoManager, logger)
|
|
notificationRepository := notification.NewRepository(mongoManager, logger)
|
|
logger.Info("Repositories initialized successfully", map[string]interface{}{
|
|
"repositories": []string{"customer", "user", "company", "category", "tender", "feedback", "tender_approval", "inquiry", "contact", "cms", "notice", "kanban_board", "kanban_column", "kanban_card", "notification"},
|
|
})
|
|
|
|
// Initialize validation services
|
|
userValidator := user.NewValidationService()
|
|
customerValidator := customer.NewValidationService()
|
|
_ = kanban.NewValidationService() // Register hexcolor validator
|
|
_ = cms.NewValidationService() // Register mediaRef validator
|
|
|
|
// Initialize services with repositories
|
|
esClient := bootstrap.InitElasticsearch(conf.Elasticsearch, logger)
|
|
defer func() {
|
|
if err := esClient.Close(); err != nil {
|
|
logger.Error("Failed to close Elasticsearch client", map[string]interface{}{
|
|
"error": err.Error(),
|
|
})
|
|
}
|
|
}()
|
|
|
|
auditLogger, auditStore := bootstrap.InitAuditLogger(logger, esClient)
|
|
defer func() {
|
|
if err := auditStore.Close(); err != nil {
|
|
logger.Error("Failed to close audit store", map[string]interface{}{
|
|
"error": err.Error(),
|
|
})
|
|
}
|
|
}()
|
|
|
|
userService := user.NewService(userRepository, logger, userAuthService, userValidator, notificationSDK, redisClient, auditLogger)
|
|
categoryService := company_category.NewService(categoryRepository, logger)
|
|
companyService := company.NewService(companyRepository, categoryService, fileStoreService, aiRecommendationClient, redisClient, conf.AISummarizer.RecommendationCacheTTL, logger)
|
|
customerService := customer.NewService(customerRepository, logger, customerAuthService, companyService, redisClient, notificationSDK, customerValidator, auditLogger)
|
|
tenderService := tender.NewService(tenderRepository, companyService, customerService, logger, aiSummarizerClient, aiSummarizerStorage, conf.AISummarizer.DefaultLanguage)
|
|
feedbackService := feedback.NewService(feedbackRepo, tenderService, companyService, logger)
|
|
tenderApprovalService := tender_approval.NewService(tenderApprovalRepository, tenderService, logger)
|
|
inquiryService := inquiry.NewService(inquiryRepository, notificationSDK, logger, xssPolicy)
|
|
flagService := assets.NewService(logger, conf.Assets.FlagsPath)
|
|
notificationService := notification.NewService(notificationSDK, notificationRepository, userService, customerService, logger)
|
|
contactService := contact.NewService(contactRepository, logger, notificationSDK)
|
|
cmsService := cms.NewService(cmsRepository, logger)
|
|
kanbanService := kanban.NewService(boardRepository, columnRepository, cardRepository, goRulesClient, conf.GoRules.RuleID, logger)
|
|
documentScraperService := document_scraper.NewService(tenderRepository, aiPipelineClient, logger)
|
|
dashboardRepository := dashboard.NewRepository(mongoManager, logger, procedureDocumentsLister)
|
|
dashboardService := dashboard.NewService(dashboardRepository, logger, redisClient)
|
|
aiPipelineService := ai_pipeline.NewService(aiPipelineClient, logger, tenderService)
|
|
auditLogRepository := auditlog.NewRepository(auditStore)
|
|
auditLogService := auditlog.NewService(auditLogRepository, logger)
|
|
logger.Info("Services initialized successfully", map[string]interface{}{
|
|
"services": []string{"customer", "user", "company", "category", "tender", "feedback", "tender_approval", "inquiry", "flag", "notification", "contact", "cms", "scraper", "kanban", "document_scraper", "dashboard", "ai_pipeline", "auditlog"},
|
|
})
|
|
|
|
// Initialize handlers with services
|
|
userHandler := user.NewHandler(userService, logger, userValidator, userAuthService)
|
|
customerHandler := customer.NewHandler(customerService, userHandler, customerAuthService, logger, customerValidator)
|
|
companyHandler := company.NewHandler(companyService, userHandler, logger)
|
|
categoryHandler := company_category.NewHandler(categoryService, logger)
|
|
tenderHandler := tender.NewHandler(tenderService, logger)
|
|
feedbackHandler := feedback.NewHandler(feedbackService, userHandler, customerHandler, logger)
|
|
tenderApprovalHandler := tender_approval.NewHandler(tenderApprovalService, logger)
|
|
inquiryHandler := inquiry.NewHandler(inquiryService, logger, hcaptchaVerifier, xssPolicy)
|
|
flagHandler := assets.NewHandler(flagService, logger)
|
|
notificationHandler := notification.NewHandler(notificationService)
|
|
contactHandler := contact.NewHandler(contactService, hcaptchaVerifier)
|
|
cmsHandler := cms.NewHandler(cmsService)
|
|
kanbanHandler := kanban.NewHandler(kanbanService)
|
|
fileStoreHandler := filestore.NewHandler(fileStoreService, logger, companyService)
|
|
documentScraperHandler := document_scraper.NewHandler(documentScraperService, logger)
|
|
dashboardHandler := dashboard.NewHandler(dashboardService)
|
|
aiPipelineHandler := ai_pipeline.NewHandler(aiPipelineService)
|
|
auditLogHandler := auditlog.NewHandler(auditLogService)
|
|
logger.Info("Handlers initialized successfully", map[string]interface{}{
|
|
"handlers": []string{"customer", "user", "company", "category", "tender", "feedback", "tender_approval", "inquiry", "flag", "notification", "contact", "cms", "scraper", "kanban", "filestore", "document_scraper", "dashboard", "ai_pipeline", "auditlog"},
|
|
})
|
|
|
|
// Initialize HTTP server
|
|
e := bootstrap.InitHTTPServer(conf, logger)
|
|
|
|
router.SetupCSPSecurity(e)
|
|
|
|
// Register routes
|
|
router.RegisterAdminRoutes(e, userHandler, companyHandler, customerHandler, tenderHandler, feedbackHandler, tenderApprovalHandler, inquiryHandler, categoryHandler, flagHandler, notificationHandler, contactHandler, cmsHandler, kanbanHandler, fileStoreHandler, dashboardHandler, aiPipelineHandler, auditLogHandler, xssPolicy)
|
|
router.RegisterPublicRoutes(e, customerHandler, tenderHandler, feedbackHandler, tenderApprovalHandler, companyHandler, inquiryHandler, categoryHandler, flagHandler, notificationHandler, contactHandler, cmsHandler, kanbanHandler, fileStoreHandler, xssPolicy)
|
|
router.RegisterDocumentScraperRoutes(e, documentScraperHandler, conf.DocumentScraper.APIKey)
|
|
|
|
// Start server
|
|
serverAddr := fmt.Sprintf("%s:%d", conf.Server.Host, conf.Server.Port)
|
|
logger.Info("HTTP server starting", map[string]interface{}{
|
|
"address": serverAddr,
|
|
"version": "1.0.0",
|
|
"host": conf.Server.Host,
|
|
"port": conf.Server.Port,
|
|
})
|
|
|
|
if err := e.Start(serverAddr); err != nil && err != http.ErrServerClosed {
|
|
logger.Error("Failed to start HTTP server", map[string]interface{}{
|
|
"error": err.Error(),
|
|
"address": serverAddr,
|
|
"version": "1.0.0",
|
|
"host": conf.Server.Host,
|
|
"port": conf.Server.Port,
|
|
})
|
|
panic(fmt.Sprintf("Failed to start HTTP server: %v", err))
|
|
}
|
|
}
|