Merge pull request 'kanban dashboard refactor' (#21) from kanban into develop

Reviewed-on: https://repo.ravanertebat.com/TM/tm_back/pulls/21
Reviewed-by: Hadi Barzegar <barzagarhadi@gmail.com>
This commit is contained in:
m.nazemi
2026-05-30 14:19:24 +03:30
15 changed files with 764 additions and 265 deletions
+34
View File
@@ -7,6 +7,7 @@ import (
"tm/pkg/authorization"
"tm/pkg/config"
"tm/pkg/filestore"
"tm/pkg/gorules"
"tm/pkg/hcaptcha"
"tm/pkg/logger"
"tm/pkg/mongo"
@@ -359,3 +360,36 @@ func InitAISummarizerStorage(conf AISummarizerConfig, log logger.Logger) *ai_sum
return storage
}
// InitGoRulesClient initializes the GoRules SDK client.
func InitGoRulesClient(conf GoRulesConfig, log logger.Logger) gorules.Client {
if conf.BaseURL == "" || conf.Token == "" || conf.RuleID == "" {
log.Warn("GoRules client not configured, falling back to static Kanban statuses", map[string]interface{}{})
return nil
}
timeout := conf.Timeout
if timeout <= 0 {
timeout = 10 * time.Second
}
client, err := gorules.New(gorules.Config{
BaseURL: conf.BaseURL,
Token: conf.Token,
Timeout: timeout,
}, log)
if err != nil {
log.Error("Failed to initialize GoRules client", map[string]interface{}{
"error": err.Error(),
})
return nil
}
log.Info("GoRules client initialized successfully", map[string]interface{}{
"base_url": conf.BaseURL,
"timeout": timeout,
"rule_id": conf.RuleID,
})
return client
}
+9
View File
@@ -22,6 +22,7 @@ type Config struct {
CustomerAuth AuthConfig
DocumentScraper DocumentScraperConfig
AISummarizer AISummarizerConfig
GoRules GoRulesConfig
}
type ScraperConfig struct {
@@ -77,3 +78,11 @@ type AISummarizerConfig struct {
MinioRegion string `env:"AI_SUMMARIZER_MINIO_REGION" envDefault:"us-east-1"`
MinioBucket string `env:"AI_SUMMARIZER_MINIO_BUCKET" envDefault:"opplens-documents"`
}
// GoRulesConfig holds configuration for the GoRules status engine.
type GoRulesConfig struct {
BaseURL string `env:"GORULES_BASE_URL"`
Token string `env:"GORULES_TOKEN"`
RuleID string `env:"GORULES_RULE_ID"`
Timeout time.Duration `env:"GORULES_TIMEOUT"`
}
+3 -2
View File
@@ -178,6 +178,7 @@ func main() {
// 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)
@@ -218,7 +219,7 @@ func main() {
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, logger)
kanbanService := kanban.NewService(boardRepository, columnRepository, cardRepository, goRulesClient, conf.GoRules.RuleID, logger)
documentScraperService := document_scraper.NewService(tenderRepository, logger)
dashboardRepository := dashboard.NewRepository(mongoManager, logger)
dashboardService := dashboard.NewService(dashboardRepository, logger)
@@ -254,7 +255,7 @@ func main() {
// Register routes
router.RegisterAdminRoutes(e, userHandler, companyHandler, customerHandler, tenderHandler, feedbackHandler, tenderApprovalHandler, inquiryHandler, categoryHandler, flagHandler, notificationHandler, contactHandler, cmsHandler, kanbanHandler, fileStoreHandler, dashboardHandler, xssPolicy)
router.RegisterPublicRoutes(e, customerHandler, tenderHandler, feedbackHandler, tenderApprovalHandler, companyHandler, inquiryHandler, categoryHandler, flagHandler, notificationHandler, contactHandler, cmsHandler, fileStoreHandler, 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
+9 -2
View File
@@ -192,7 +192,7 @@ func RegisterAdminRoutes(e *echo.Echo, userHandler *user.Handler, companyHandler
cmsGP.DELETE("/:id", cmsHandler.Delete)
}
// Kanban Routes
// Kanban Routes — paths are /admin/v1/kanban/* (RegisterRoutes expects this /kanban group)
kanbanGP := adminV1.Group("/kanban")
{
kanbanGP.Use(userHandler.AuthMiddleware())
@@ -223,7 +223,7 @@ func RegisterAdminRoutes(e *echo.Echo, userHandler *user.Handler, companyHandler
}
}
func RegisterPublicRoutes(e *echo.Echo, customerHandler *customer.Handler, tenderHandler *tender.TenderHandler, feedbackHandler *feedback.Handler, tenderApprovalHandler *tender_approval.Handler, companyHandler *company.Handler, inquiryHandler *inquiry.Handler, categoryHandler *company_category.Handler, flagHandler *assets.Handler, notificationHandler *notification.NotificationHandler, contactHandler *contact.Handler, cmsHandler *cms.Handler, fileStoreHandler *filestore.Handler, xssPolicy *security.XSSPolicy) {
func RegisterPublicRoutes(e *echo.Echo, customerHandler *customer.Handler, tenderHandler *tender.TenderHandler, feedbackHandler *feedback.Handler, tenderApprovalHandler *tender_approval.Handler, companyHandler *company.Handler, inquiryHandler *inquiry.Handler, categoryHandler *company_category.Handler, flagHandler *assets.Handler, notificationHandler *notification.NotificationHandler, contactHandler *contact.Handler, cmsHandler *cms.Handler, kanbanHandler *kanban.Handler, fileStoreHandler *filestore.Handler, xssPolicy *security.XSSPolicy) {
v1 := e.Group("/api/v1")
customerGP := v1.Group("/profile")
@@ -320,6 +320,13 @@ func RegisterPublicRoutes(e *echo.Echo, customerHandler *customer.Handler, tende
cmsGP.GET("/:key", cmsHandler.GetByKey)
}
// Kanban (mobile bid workflow board) — paths are /api/v1/kanban/*
kanbanGP := v1.Group("/kanban")
{
kanbanGP.Use(customerHandler.AuthMiddleware())
kanbanHandler.RegisterRoutes(kanbanGP)
}
// File Store Routes
publicFilesGP := v1.Group("/files")
{