From df77b1c57608be6cefd6f00368715512d2f3f196 Mon Sep 17 00:00:00 2001 From: hanif salafi Date: Thu, 2 Oct 2025 12:28:10 +0700 Subject: [PATCH] feat: update approval workflows --- .../approval_workflows.module.go | 13 + .../approval_workflows.controller.go | 35 ++ .../mapper/approval_workflows.mapper.go | 21 +- .../request/approval_workflows.request.go | 5 + .../response/approval_workflows.response.go | 179 +++++-- .../service/approval_workflows.service.go | 288 +++++++++++ docs/COMPREHENSIVE_WORKFLOW_DETAIL_API.md | 456 ++++++++++++++++++ docs/FRONTEND_FORM_GENERATION_PROMPT.md | 412 ++++++++++++++++ docs/swagger/docs.go | 69 +++ docs/swagger/swagger.json | 69 +++ docs/swagger/swagger.yaml | 45 ++ 11 files changed, 1558 insertions(+), 34 deletions(-) create mode 100644 docs/COMPREHENSIVE_WORKFLOW_DETAIL_API.md create mode 100644 docs/FRONTEND_FORM_GENERATION_PROMPT.md diff --git a/app/module/approval_workflows/approval_workflows.module.go b/app/module/approval_workflows/approval_workflows.module.go index 825de48..f71c5a9 100644 --- a/app/module/approval_workflows/approval_workflows.module.go +++ b/app/module/approval_workflows/approval_workflows.module.go @@ -5,6 +5,12 @@ import ( "netidhub-saas-be/app/module/approval_workflows/repository" "netidhub-saas-be/app/module/approval_workflows/service" + // articleCategoriesRepo "netidhub-saas-be/app/module/article_categories/repository" + // clientApprovalSettingsRepo "netidhub-saas-be/app/module/client_approval_settings/repository" + // userLevelsRepo "netidhub-saas-be/app/module/user_levels/repository" + // userRolesRepo "netidhub-saas-be/app/module/user_roles/repository" + // usersRepo "netidhub-saas-be/app/module/users/repository" + "github.com/gofiber/fiber/v2" "go.uber.org/fx" ) @@ -20,6 +26,12 @@ var NewApprovalWorkflowsModule = fx.Options( // register repository of ApprovalWorkflows module fx.Provide(repository.NewApprovalWorkflowsRepository), + // fx.Provide(clientApprovalSettingsRepo.NewClientApprovalSettingsRepository), + // fx.Provide(usersRepo.NewUsersRepository), + // fx.Provide(userLevelsRepo.NewUserLevelsRepository), + // fx.Provide(userRolesRepo.NewUserRolesRepository), + // fx.Provide(articleCategoriesRepo.NewArticleCategoriesRepository), + // register service of ApprovalWorkflows module fx.Provide(service.NewApprovalWorkflowsService), @@ -52,6 +64,7 @@ func (_i *ApprovalWorkflowsRouter) RegisterApprovalWorkflowsRoutes() { router.Post("/", approvalWorkflowsController.Save) router.Post("/with-steps", approvalWorkflowsController.SaveWithSteps) router.Post("/with-client-settings", approvalWorkflowsController.SaveWithClientSettings) + router.Post("/comprehensive-details", approvalWorkflowsController.GetComprehensiveDetails) router.Put("/:id", approvalWorkflowsController.Update) router.Put("/:id/with-steps", approvalWorkflowsController.UpdateWithSteps) router.Put("/:id/set-default", approvalWorkflowsController.SetDefault) diff --git a/app/module/approval_workflows/controller/approval_workflows.controller.go b/app/module/approval_workflows/controller/approval_workflows.controller.go index 9f5d465..d38985f 100644 --- a/app/module/approval_workflows/controller/approval_workflows.controller.go +++ b/app/module/approval_workflows/controller/approval_workflows.controller.go @@ -33,6 +33,7 @@ type ApprovalWorkflowsController interface { SaveWithSteps(c *fiber.Ctx) error UpdateWithSteps(c *fiber.Ctx) error SaveWithClientSettings(c *fiber.Ctx) error + GetComprehensiveDetails(c *fiber.Ctx) error } func NewApprovalWorkflowsController(approvalWorkflowsService service.ApprovalWorkflowsService, log zerolog.Logger) ApprovalWorkflowsController { @@ -521,3 +522,37 @@ func (_i *approvalWorkflowsController) SaveWithClientSettings(c *fiber.Ctx) erro Data: responseData, }) } + +// GetComprehensiveDetails ApprovalWorkflows +// @Summary Get comprehensive approval workflow details +// @Description API for getting comprehensive details of approval workflow including steps, client settings, and related data +// @Tags ApprovalWorkflows +// @Security Bearer +// @Param Authorization header string true "Insert the Authorization" +// @Param req body request.ComprehensiveWorkflowDetailRequest true "Workflow detail request" +// @Success 200 {object} response.Response +// @Failure 400 {object} response.BadRequestError +// @Failure 401 {object} response.UnauthorizedError +// @Failure 500 {object} response.InternalServerError +// @Router /approval-workflows/comprehensive-details [post] +func (_i *approvalWorkflowsController) GetComprehensiveDetails(c *fiber.Ctx) error { + req := new(request.ComprehensiveWorkflowDetailRequest) + if err := utilVal.ParseAndValidate(c, req); err != nil { + return err + } + + // Get authToken from context + authToken := c.Get("Authorization") + + // Get comprehensive workflow details + details, err := _i.approvalWorkflowsService.GetComprehensiveWorkflowDetails(authToken, req.WorkflowId) + if err != nil { + return err + } + + return utilRes.Resp(c, utilRes.Response{ + Success: true, + Messages: utilRes.Messages{"Comprehensive workflow details retrieved successfully"}, + Data: details, + }) +} diff --git a/app/module/approval_workflows/mapper/approval_workflows.mapper.go b/app/module/approval_workflows/mapper/approval_workflows.mapper.go index 14a074d..6c927b9 100644 --- a/app/module/approval_workflows/mapper/approval_workflows.mapper.go +++ b/app/module/approval_workflows/mapper/approval_workflows.mapper.go @@ -1,14 +1,15 @@ package mapper import ( - "github.com/google/uuid" - "github.com/rs/zerolog" "netidhub-saas-be/app/database/entity" approvalWorkflowStepsMapper "netidhub-saas-be/app/module/approval_workflow_steps/mapper" approvalWorkflowStepsRepository "netidhub-saas-be/app/module/approval_workflow_steps/repository" approvalWorkflowStepsResponse "netidhub-saas-be/app/module/approval_workflow_steps/response" res "netidhub-saas-be/app/module/approval_workflows/response" usersRepository "netidhub-saas-be/app/module/users/repository" + + "github.com/google/uuid" + "github.com/rs/zerolog" ) func ApprovalWorkflowsResponseMapper( @@ -39,6 +40,12 @@ func ApprovalWorkflowsResponseMapper( isActive = *approvalWorkflowsReq.IsActive } + // Convert steps to interface{} slice + stepsInterface := make([]interface{}, len(workflowStepsArr)) + for i, step := range workflowStepsArr { + stepsInterface[i] = step + } + approvalWorkflowsRes = &res.ApprovalWorkflowsResponse{ ID: approvalWorkflowsReq.ID, Name: approvalWorkflowsReq.Name, @@ -47,7 +54,7 @@ func ApprovalWorkflowsResponseMapper( CreatedBy: 0, // Default value since entity doesn't have CreatedBy field CreatedAt: approvalWorkflowsReq.CreatedAt, UpdatedAt: approvalWorkflowsReq.UpdatedAt, - Steps: workflowStepsArr, + Steps: stepsInterface, } } @@ -82,6 +89,12 @@ func ApprovalWorkflowsWithStepsResponseMapper( isActive = *approvalWorkflowsReq.IsActive } + // Convert steps to interface{} slice + stepsInterface := make([]interface{}, len(workflowStepsArr)) + for i, step := range workflowStepsArr { + stepsInterface[i] = step + } + approvalWorkflowsRes = &res.ApprovalWorkflowsWithStepsResponse{ ID: approvalWorkflowsReq.ID, Name: approvalWorkflowsReq.Name, @@ -90,7 +103,7 @@ func ApprovalWorkflowsWithStepsResponseMapper( CreatedBy: 0, // Default value since entity doesn't have CreatedBy field CreatedAt: approvalWorkflowsReq.CreatedAt, UpdatedAt: approvalWorkflowsReq.UpdatedAt, - Steps: workflowStepsArr, + Steps: stepsInterface, } } diff --git a/app/module/approval_workflows/request/approval_workflows.request.go b/app/module/approval_workflows/request/approval_workflows.request.go index c159181..afea5ed 100644 --- a/app/module/approval_workflows/request/approval_workflows.request.go +++ b/app/module/approval_workflows/request/approval_workflows.request.go @@ -299,3 +299,8 @@ func (req ApprovalWorkflowsQueryRequestContext) ToParamRequest() ApprovalWorkflo IsDefault: isDefault, } } + +// ComprehensiveWorkflowDetailRequest - Request for getting comprehensive workflow details +type ComprehensiveWorkflowDetailRequest struct { + WorkflowId uint `json:"workflowId" validate:"required"` +} diff --git a/app/module/approval_workflows/response/approval_workflows.response.go b/app/module/approval_workflows/response/approval_workflows.response.go index d4f8695..99d493b 100644 --- a/app/module/approval_workflows/response/approval_workflows.response.go +++ b/app/module/approval_workflows/response/approval_workflows.response.go @@ -1,36 +1,32 @@ package response -import ( - approvalWorkflowStepsResponse "netidhub-saas-be/app/module/approval_workflow_steps/response" - "time" -) +import "time" +// ApprovalWorkflowsResponse - Basic workflow response type ApprovalWorkflowsResponse struct { - ID uint `json:"id"` - Name string `json:"name"` - Description *string `json:"description"` - IsActive bool `json:"isActive"` - CreatedBy uint `json:"createdBy"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` - - // Relations - Steps []*approvalWorkflowStepsResponse.ApprovalWorkflowStepsResponse `json:"steps,omitempty"` + ID uint `json:"id"` + Name string `json:"name"` + Description *string `json:"description"` + IsActive bool `json:"isActive"` + CreatedBy uint `json:"createdBy"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + Steps []interface{} `json:"steps"` } +// ApprovalWorkflowsWithStepsResponse - Workflow response with steps type ApprovalWorkflowsWithStepsResponse struct { - ID uint `json:"id"` - Name string `json:"name"` - Description *string `json:"description"` - IsActive bool `json:"isActive"` - CreatedBy uint `json:"createdBy"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` - - // Relations - Steps []*approvalWorkflowStepsResponse.ApprovalWorkflowStepsResponse `json:"steps"` + ID uint `json:"id"` + Name string `json:"name"` + Description *string `json:"description"` + IsActive bool `json:"isActive"` + CreatedBy uint `json:"createdBy"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + Steps []interface{} `json:"steps"` } +// ApprovalWorkflowsSummaryResponse - Summary workflow response type ApprovalWorkflowsSummaryResponse struct { ID uint `json:"id"` Name string `json:"name"` @@ -39,10 +35,133 @@ type ApprovalWorkflowsSummaryResponse struct { StepCount int `json:"stepCount"` } -type ApprovalWorkflowsStatsResponse struct { - TotalWorkflows int `json:"totalWorkflows"` - ActiveWorkflows int `json:"activeWorkflows"` - InactiveWorkflows int `json:"inactiveWorkflows"` - TotalSteps int `json:"totalSteps"` - AverageStepsPerFlow int `json:"averageStepsPerFlow"` +// ComprehensiveWorkflowDetailResponse - Comprehensive response for workflow details +type ComprehensiveWorkflowDetailResponse struct { + Workflow WorkflowDetailInfo `json:"workflow"` + Steps []WorkflowStepDetailInfo `json:"steps"` + ClientSettings ClientApprovalSettingsDetail `json:"clientSettings"` + RelatedData RelatedDataInfo `json:"relatedData"` + Statistics WorkflowStatisticsInfo `json:"statistics"` + LastUpdated time.Time `json:"lastUpdated"` +} + +// WorkflowDetailInfo - Detailed workflow information +type WorkflowDetailInfo struct { + ID uint `json:"id"` + Name string `json:"name"` + Description *string `json:"description"` + IsDefault *bool `json:"isDefault"` + IsActive *bool `json:"isActive"` + RequiresApproval *bool `json:"requiresApproval"` + AutoPublish *bool `json:"autoPublish"` + ClientId *string `json:"clientId"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + + // Additional workflow info + TotalSteps int `json:"totalSteps"` + ActiveSteps int `json:"activeSteps"` + HasBranches bool `json:"hasBranches"` + MaxStepOrder int `json:"maxStepOrder"` +} + +// WorkflowStepDetailInfo - Detailed step information +type WorkflowStepDetailInfo struct { + ID uint `json:"id"` + WorkflowId uint `json:"workflowId"` + StepOrder int `json:"stepOrder"` + StepName string `json:"stepName"` + RequiredUserLevelId uint `json:"requiredUserLevelId"` + RequiredUserLevelName string `json:"requiredUserLevelName"` + CanSkip *bool `json:"canSkip"` + AutoApproveAfterHours *int `json:"autoApproveAfterHours"` + IsActive *bool `json:"isActive"` + + // Multi-branch support fields + ParentStepId *uint `json:"parentStepId"` + ParentStepName *string `json:"parentStepName"` + ConditionType *string `json:"conditionType"` + ConditionValue *string `json:"conditionValue"` + IsParallel *bool `json:"isParallel"` + BranchName *string `json:"branchName"` + BranchOrder *int `json:"branchOrder"` + + // Additional step info + HasChildren bool `json:"hasChildren"` + IsFirstStep bool `json:"isFirstStep"` + IsLastStep bool `json:"isLastStep"` +} + +// ClientApprovalSettingsDetail - Detailed client approval settings +type ClientApprovalSettingsDetail struct { + ID uint `json:"id"` + ClientId string `json:"clientId"` + RequiresApproval *bool `json:"requiresApproval"` + DefaultWorkflowId *uint `json:"defaultWorkflowId"` + DefaultWorkflowName *string `json:"defaultWorkflowName"` + AutoPublishArticles *bool `json:"autoPublishArticles"` + ApprovalExemptUsers []uint `json:"approvalExemptUsers"` + ApprovalExemptRoles []uint `json:"approvalExemptRoles"` + ApprovalExemptCategories []uint `json:"approvalExemptCategories"` + RequireApprovalFor []string `json:"requireApprovalFor"` + SkipApprovalFor []string `json:"skipApprovalFor"` + IsActive *bool `json:"isActive"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + + // Additional client settings info + ExemptUsersDetails []UserDetailInfo `json:"exemptUsersDetails"` + ExemptRolesDetails []UserRoleDetailInfo `json:"exemptRolesDetails"` + ExemptCategoriesDetails []CategoryDetailInfo `json:"exemptCategoriesDetails"` +} + +// RelatedDataInfo - Related data information +type RelatedDataInfo struct { + UserLevels []UserLevelDetailInfo `json:"userLevels"` +} + +// WorkflowStatisticsInfo - Workflow statistics +type WorkflowStatisticsInfo struct { + TotalArticlesProcessed int `json:"totalArticlesProcessed"` + PendingArticles int `json:"pendingArticles"` + ApprovedArticles int `json:"approvedArticles"` + RejectedArticles int `json:"rejectedArticles"` + AverageProcessingTime int `json:"averageProcessingTime"` // in hours + MostActiveStep string `json:"mostActiveStep"` + LastUsedAt *string `json:"lastUsedAt"` +} + +// UserLevelDetailInfo - User level detail information +type UserLevelDetailInfo struct { + ID uint `json:"id"` + Name string `json:"name"` + AliasName string `json:"aliasName"` + LevelNumber int `json:"levelNumber"` + IsApprovalActive *bool `json:"isApprovalActive"` + IsActive *bool `json:"isActive"` +} + +// UserDetailInfo - User detail information +type UserDetailInfo struct { + ID uint `json:"id"` + Username string `json:"username"` + Fullname string `json:"fullname"` + Email string `json:"email"` + UserLevelId uint `json:"userLevelId"` + UserLevelName string `json:"userLevelName"` + IsActive *bool `json:"isActive"` +} + +// UserRoleDetailInfo - User role detail information +type UserRoleDetailInfo struct { + ID uint `json:"id"` + RoleName string `json:"roleName"` + IsActive *bool `json:"isActive"` +} + +// CategoryDetailInfo - Category detail information +type CategoryDetailInfo struct { + ID uint `json:"id"` + CategoryName string `json:"categoryName"` + IsActive *bool `json:"isActive"` } diff --git a/app/module/approval_workflows/service/approval_workflows.service.go b/app/module/approval_workflows/service/approval_workflows.service.go index fc239a6..97ad228 100644 --- a/app/module/approval_workflows/service/approval_workflows.service.go +++ b/app/module/approval_workflows/service/approval_workflows.service.go @@ -8,7 +8,13 @@ import ( stepRepo "netidhub-saas-be/app/module/approval_workflow_steps/repository" "netidhub-saas-be/app/module/approval_workflows/repository" "netidhub-saas-be/app/module/approval_workflows/request" + "netidhub-saas-be/app/module/approval_workflows/response" + articleApprovalFlowsRepo "netidhub-saas-be/app/module/article_approval_flows/repository" + articleCategoriesRepo "netidhub-saas-be/app/module/article_categories/repository" clientApprovalSettingsRepo "netidhub-saas-be/app/module/client_approval_settings/repository" + userLevelsRepo "netidhub-saas-be/app/module/user_levels/repository" + userLevelsReq "netidhub-saas-be/app/module/user_levels/request" + userRolesRepo "netidhub-saas-be/app/module/user_roles/repository" usersRepo "netidhub-saas-be/app/module/users/repository" "netidhub-saas-be/utils/paginator" utilSvc "netidhub-saas-be/utils/service" @@ -22,6 +28,10 @@ type approvalWorkflowsService struct { ApprovalWorkflowStepsRepository stepRepo.ApprovalWorkflowStepsRepository ClientApprovalSettingsRepository clientApprovalSettingsRepo.ClientApprovalSettingsRepository UsersRepository usersRepo.UsersRepository + UserLevelsRepository userLevelsRepo.UserLevelsRepository + UserRolesRepository userRolesRepo.UserRolesRepository + ArticleCategoriesRepository articleCategoriesRepo.ArticleCategoriesRepository + ArticleApprovalFlowsRepository articleApprovalFlowsRepo.ArticleApprovalFlowsRepository Log zerolog.Logger } @@ -51,6 +61,9 @@ type ApprovalWorkflowsService interface { // Comprehensive workflow creation with client settings CreateWorkflowWithClientSettings(authToken string, req request.CreateApprovalWorkflowWithClientSettingsRequest) (workflow *entity.ApprovalWorkflows, clientSettings *entity.ClientApprovalSettings, err error) + + // Comprehensive workflow details + GetComprehensiveWorkflowDetails(authToken string, workflowId uint) (details *response.ComprehensiveWorkflowDetailResponse, err error) } func NewApprovalWorkflowsService( @@ -58,6 +71,10 @@ func NewApprovalWorkflowsService( approvalWorkflowStepsRepository stepRepo.ApprovalWorkflowStepsRepository, clientApprovalSettingsRepository clientApprovalSettingsRepo.ClientApprovalSettingsRepository, usersRepository usersRepo.UsersRepository, + userLevelsRepository userLevelsRepo.UserLevelsRepository, + userRolesRepository userRolesRepo.UserRolesRepository, + articleCategoriesRepository articleCategoriesRepo.ArticleCategoriesRepository, + articleApprovalFlowsRepository articleApprovalFlowsRepo.ArticleApprovalFlowsRepository, log zerolog.Logger, ) ApprovalWorkflowsService { return &approvalWorkflowsService{ @@ -65,6 +82,10 @@ func NewApprovalWorkflowsService( ApprovalWorkflowStepsRepository: approvalWorkflowStepsRepository, ClientApprovalSettingsRepository: clientApprovalSettingsRepository, UsersRepository: usersRepository, + UserLevelsRepository: userLevelsRepository, + UserRolesRepository: userRolesRepository, + ArticleCategoriesRepository: articleCategoriesRepository, + ArticleApprovalFlowsRepository: articleApprovalFlowsRepository, Log: log, } } @@ -713,3 +734,270 @@ func (_i *approvalWorkflowsService) CreateWorkflowWithClientSettings(authToken s return workflow, clientSettings, nil } + +// GetComprehensiveWorkflowDetails retrieves comprehensive workflow details including all related data +func (_i *approvalWorkflowsService) GetComprehensiveWorkflowDetails(authToken string, workflowId uint) (details *response.ComprehensiveWorkflowDetailResponse, err error) { + // Extract clientId from authToken + var clientId *uuid.UUID + if authToken != "" { + user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepository, authToken) + if user != nil && user.ClientId != nil { + clientId = user.ClientId + _i.Log.Info().Interface("clientId", clientId).Msg("Extracted clientId from auth token") + } + } + + if clientId == nil { + return nil, errors.New("clientId not found in auth token") + } + + _i.Log.Info(). + Uint("workflowId", workflowId). + Interface("clientId", clientId). + Msg("Getting comprehensive workflow details") + + // Get workflow + workflow, err := _i.ApprovalWorkflowsRepository.FindOne(clientId, workflowId) + if err != nil { + return nil, fmt.Errorf("failed to get workflow: %w", err) + } + + if workflow == nil { + return nil, errors.New("workflow not found") + } + + // Get workflow steps + steps, err := _i.ApprovalWorkflowStepsRepository.GetByWorkflowId(clientId, workflowId) + if err != nil { + return nil, fmt.Errorf("failed to get workflow steps: %w", err) + } + + // Get client approval settings + clientSettings, err := _i.ClientApprovalSettingsRepository.FindByClientId(*clientId) + if err != nil { + _i.Log.Warn().Err(err).Msg("Failed to get client approval settings") + // Don't return error, just log warning + } + + // Build comprehensive response + details = &response.ComprehensiveWorkflowDetailResponse{ + LastUpdated: workflow.UpdatedAt, + } + + // Build workflow detail info + workflowDetail := response.WorkflowDetailInfo{ + ID: workflow.ID, + Name: workflow.Name, + Description: workflow.Description, + IsDefault: workflow.IsDefault, + IsActive: workflow.IsActive, + RequiresApproval: workflow.RequiresApproval, + AutoPublish: workflow.AutoPublish, + CreatedAt: workflow.CreatedAt, + UpdatedAt: workflow.UpdatedAt, + TotalSteps: len(steps), + MaxStepOrder: 0, + } + + if workflow.ClientId != nil { + clientIdStr := workflow.ClientId.String() + workflowDetail.ClientId = &clientIdStr + } + + // Calculate workflow statistics + activeSteps := 0 + hasBranches := false + for _, step := range steps { + if step.IsActive != nil && *step.IsActive { + activeSteps++ + } + if step.ParentStepId != nil { + hasBranches = true + } + if step.StepOrder > workflowDetail.MaxStepOrder { + workflowDetail.MaxStepOrder = step.StepOrder + } + } + + workflowDetail.ActiveSteps = activeSteps + workflowDetail.HasBranches = hasBranches + details.Workflow = workflowDetail + + // Build step details + stepDetails := make([]response.WorkflowStepDetailInfo, len(steps)) + for i, step := range steps { + stepDetail := response.WorkflowStepDetailInfo{ + ID: step.ID, + WorkflowId: step.WorkflowId, + StepOrder: step.StepOrder, + StepName: step.StepName, + RequiredUserLevelId: step.RequiredUserLevelId, + CanSkip: step.CanSkip, + AutoApproveAfterHours: step.AutoApproveAfterHours, + IsActive: step.IsActive, + ParentStepId: step.ParentStepId, + ConditionType: step.ConditionType, + ConditionValue: step.ConditionValue, + IsParallel: step.IsParallel, + BranchName: step.BranchName, + BranchOrder: step.BranchOrder, + } + + // Get user level name + userLevel, err := _i.UserLevelsRepository.FindOne(clientId, step.RequiredUserLevelId) + if err == nil && userLevel != nil { + stepDetail.RequiredUserLevelName = userLevel.Name + } + + // Get parent step name + if step.ParentStepId != nil { + for _, parentStep := range steps { + if parentStep.ID == *step.ParentStepId { + stepDetail.ParentStepName = &parentStep.StepName + break + } + } + } + + // Check if step has children + hasChildren := false + for _, childStep := range steps { + if childStep.ParentStepId != nil && *childStep.ParentStepId == step.ID { + hasChildren = true + break + } + } + stepDetail.HasChildren = hasChildren + + // Check if first/last step + stepDetail.IsFirstStep = step.StepOrder == 1 + stepDetail.IsLastStep = step.StepOrder == workflowDetail.MaxStepOrder + + stepDetails[i] = stepDetail + } + + details.Steps = stepDetails + + // Build client settings detail + if clientSettings != nil { + clientSettingsDetail := response.ClientApprovalSettingsDetail{ + ID: clientSettings.ID, + ClientId: clientSettings.ClientId.String(), + RequiresApproval: clientSettings.RequiresApproval, + DefaultWorkflowId: clientSettings.DefaultWorkflowId, + AutoPublishArticles: clientSettings.AutoPublishArticles, + ApprovalExemptUsers: clientSettings.ApprovalExemptUsers, + ApprovalExemptRoles: clientSettings.ApprovalExemptRoles, + ApprovalExemptCategories: clientSettings.ApprovalExemptCategories, + RequireApprovalFor: clientSettings.RequireApprovalFor, + SkipApprovalFor: clientSettings.SkipApprovalFor, + IsActive: clientSettings.IsActive, + CreatedAt: clientSettings.CreatedAt, + UpdatedAt: clientSettings.UpdatedAt, + } + + // Set default workflow name + if clientSettings.DefaultWorkflowId != nil { + defaultWorkflow, err := _i.ApprovalWorkflowsRepository.FindOne(clientId, *clientSettings.DefaultWorkflowId) + if err == nil && defaultWorkflow != nil { + clientSettingsDetail.DefaultWorkflowName = &defaultWorkflow.Name + } + } + + // Get exempt users details + exemptUsersDetails := make([]response.UserDetailInfo, 0) + for _, userId := range clientSettings.ApprovalExemptUsers { + user, err := _i.UsersRepository.FindOne(clientId, userId) + if err == nil && user != nil { + userLevel, _ := _i.UserLevelsRepository.FindOne(clientId, user.UserLevelId) + userLevelName := "" + if userLevel != nil { + userLevelName = userLevel.Name + } + exemptUsersDetails = append(exemptUsersDetails, response.UserDetailInfo{ + ID: user.ID, + Username: user.Username, + Fullname: user.Fullname, + Email: user.Email, + UserLevelId: user.UserLevelId, + UserLevelName: userLevelName, + IsActive: user.IsActive, + }) + } + } + clientSettingsDetail.ExemptUsersDetails = exemptUsersDetails + + // Get exempt roles details + exemptRolesDetails := make([]response.UserRoleDetailInfo, 0) + for _, roleId := range clientSettings.ApprovalExemptRoles { + role, err := _i.UserRolesRepository.FindOne(roleId) + if err == nil && role != nil { + exemptRolesDetails = append(exemptRolesDetails, response.UserRoleDetailInfo{ + ID: role.ID, + RoleName: role.Name, + IsActive: role.IsActive, + }) + } + } + clientSettingsDetail.ExemptRolesDetails = exemptRolesDetails + + // Get exempt categories details + exemptCategoriesDetails := make([]response.CategoryDetailInfo, 0) + for _, categoryId := range clientSettings.ApprovalExemptCategories { + category, err := _i.ArticleCategoriesRepository.FindOne(clientId, categoryId) + if err == nil && category != nil { + exemptCategoriesDetails = append(exemptCategoriesDetails, response.CategoryDetailInfo{ + ID: category.ID, + CategoryName: category.Title, + IsActive: category.IsActive, + }) + } + } + clientSettingsDetail.ExemptCategoriesDetails = exemptCategoriesDetails + + details.ClientSettings = clientSettingsDetail + } + + // Build related data + relatedData := response.RelatedDataInfo{} + + // Get all user levels for this client + userLevels, _, err := _i.UserLevelsRepository.GetAll(clientId, userLevelsReq.UserLevelsQueryRequest{ + Pagination: &paginator.Pagination{}, + }) + if err == nil { + userLevelDetails := make([]response.UserLevelDetailInfo, len(userLevels)) + for i, level := range userLevels { + userLevelDetails[i] = response.UserLevelDetailInfo{ + ID: level.ID, + Name: level.Name, + AliasName: level.AliasName, + LevelNumber: level.LevelNumber, + IsApprovalActive: level.IsApprovalActive, + IsActive: level.IsActive, + } + } + relatedData.UserLevels = userLevelDetails + } + + // Get workflow statistics (simplified - would need more complex queries in real implementation) + statistics := response.WorkflowStatisticsInfo{ + TotalArticlesProcessed: 0, // Would need to query article_approval_flows + PendingArticles: 0, // Would need to query active flows + ApprovedArticles: 0, // Would need to query completed flows + RejectedArticles: 0, // Would need to query rejected flows + AverageProcessingTime: 0, // Would need to calculate from flow durations + MostActiveStep: "", // Would need to analyze step activity + LastUsedAt: nil, // Would need to query last flow creation + } + + details.Statistics = statistics + details.RelatedData = relatedData + + _i.Log.Info(). + Uint("workflowId", workflowId). + Int("stepsCount", len(steps)). + Msg("Comprehensive workflow details retrieved successfully") + + return details, nil +} diff --git a/docs/COMPREHENSIVE_WORKFLOW_DETAIL_API.md b/docs/COMPREHENSIVE_WORKFLOW_DETAIL_API.md new file mode 100644 index 0000000..b05fff3 --- /dev/null +++ b/docs/COMPREHENSIVE_WORKFLOW_DETAIL_API.md @@ -0,0 +1,456 @@ +# Comprehensive Workflow Detail API + +## Overview +API endpoint untuk mendapatkan detail lengkap dari Approval Workflow beserta semua data terkait termasuk steps, client settings, dan informasi pendukung lainnya. + +## Endpoint +``` +POST /approval-workflows/comprehensive-details +``` + +## Request + +### Headers +``` +Authorization: Bearer +Content-Type: application/json +``` + +### Request Body +```json +{ + "workflowId": 1 +} +``` + +### Request Structure +```go +type ComprehensiveWorkflowDetailRequest struct { + WorkflowId uint `json:"workflowId" validate:"required"` +} +``` + +## Response + +### Success Response (200) +```json +{ + "success": true, + "messages": ["Comprehensive workflow details retrieved successfully"], + "data": { + "workflow": { + "id": 1, + "name": "Standard Article Approval", + "description": "Standard approval workflow for articles", + "isDefault": true, + "isActive": true, + "requiresApproval": true, + "autoPublish": false, + "clientId": "123e4567-e89b-12d3-a456-426614174000", + "createdAt": "2024-01-01T00:00:00Z", + "updatedAt": "2024-01-01T00:00:00Z", + "totalSteps": 3, + "activeSteps": 3, + "hasBranches": false, + "maxStepOrder": 3 + }, + "steps": [ + { + "id": 1, + "workflowId": 1, + "stepOrder": 1, + "stepName": "Content Review", + "requiredUserLevelId": 2, + "requiredUserLevelName": "Editor", + "canSkip": false, + "autoApproveAfterHours": null, + "isActive": true, + "parentStepId": null, + "parentStepName": null, + "conditionType": null, + "conditionValue": null, + "isParallel": false, + "branchName": null, + "branchOrder": null, + "hasChildren": false, + "isFirstStep": true, + "isLastStep": false + }, + { + "id": 2, + "workflowId": 1, + "stepOrder": 2, + "stepName": "Final Approval", + "requiredUserLevelId": 3, + "requiredUserLevelName": "Manager", + "canSkip": false, + "autoApproveAfterHours": null, + "isActive": true, + "parentStepId": null, + "parentStepName": null, + "conditionType": null, + "conditionValue": null, + "isParallel": false, + "branchName": null, + "branchOrder": null, + "hasChildren": false, + "isFirstStep": false, + "isLastStep": true + } + ], + "clientSettings": { + "id": 1, + "clientId": "123e4567-e89b-12d3-a456-426614174000", + "requiresApproval": true, + "defaultWorkflowId": 1, + "defaultWorkflowName": "Standard Article Approval", + "autoPublishArticles": false, + "approvalExemptUsers": [1, 2], + "approvalExemptRoles": [1], + "approvalExemptCategories": [1, 2], + "requireApprovalFor": ["articles", "news"], + "skipApprovalFor": ["announcements"], + "isActive": true, + "createdAt": "2024-01-01T00:00:00Z", + "updatedAt": "2024-01-01T00:00:00Z", + "exemptUsersDetails": [ + { + "id": 1, + "username": "admin", + "fullname": "Administrator", + "email": "admin@example.com", + "userLevelId": 1, + "userLevelName": "Super Admin", + "isActive": true + } + ], + "exemptRolesDetails": [ + { + "id": 1, + "roleName": "Super Admin", + "isActive": true + } + ], + "exemptCategoriesDetails": [ + { + "id": 1, + "categoryName": "Announcements", + "isActive": true + } + ] + }, + "relatedData": { + "userLevels": [ + { + "id": 1, + "name": "Super Admin", + "aliasName": "super_admin", + "levelNumber": 1, + "isApprovalActive": true, + "isActive": true + }, + { + "id": 2, + "name": "Editor", + "aliasName": "editor", + "levelNumber": 2, + "isApprovalActive": true, + "isActive": true + } + ] + }, + "statistics": { + "totalArticlesProcessed": 0, + "pendingArticles": 0, + "approvedArticles": 0, + "rejectedArticles": 0, + "averageProcessingTime": 0, + "mostActiveStep": "", + "lastUsedAt": null + }, + "lastUpdated": "2024-01-01T00:00:00Z" + } +} +``` + +## Response Structure + +### ComprehensiveWorkflowDetailResponse +```go +type ComprehensiveWorkflowDetailResponse struct { + Workflow WorkflowDetailInfo `json:"workflow"` + Steps []WorkflowStepDetailInfo `json:"steps"` + ClientSettings ClientApprovalSettingsDetail `json:"clientSettings"` + RelatedData RelatedDataInfo `json:"relatedData"` + Statistics WorkflowStatisticsInfo `json:"statistics"` + LastUpdated time.Time `json:"lastUpdated"` +} +``` + +### WorkflowDetailInfo +```go +type WorkflowDetailInfo struct { + ID uint `json:"id"` + Name string `json:"name"` + Description *string `json:"description"` + IsDefault *bool `json:"isDefault"` + IsActive *bool `json:"isActive"` + RequiresApproval *bool `json:"requiresApproval"` + AutoPublish *bool `json:"autoPublish"` + ClientId *string `json:"clientId"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + + // Additional workflow info + TotalSteps int `json:"totalSteps"` + ActiveSteps int `json:"activeSteps"` + HasBranches bool `json:"hasBranches"` + MaxStepOrder int `json:"maxStepOrder"` +} +``` + +### WorkflowStepDetailInfo +```go +type WorkflowStepDetailInfo struct { + ID uint `json:"id"` + WorkflowId uint `json:"workflowId"` + StepOrder int `json:"stepOrder"` + StepName string `json:"stepName"` + RequiredUserLevelId uint `json:"requiredUserLevelId"` + RequiredUserLevelName string `json:"requiredUserLevelName"` + CanSkip *bool `json:"canSkip"` + AutoApproveAfterHours *int `json:"autoApproveAfterHours"` + IsActive *bool `json:"isActive"` + + // Multi-branch support fields + ParentStepId *uint `json:"parentStepId"` + ParentStepName *string `json:"parentStepName"` + ConditionType *string `json:"conditionType"` + ConditionValue *string `json:"conditionValue"` + IsParallel *bool `json:"isParallel"` + BranchName *string `json:"branchName"` + BranchOrder *int `json:"branchOrder"` + + // Additional step info + HasChildren bool `json:"hasChildren"` + IsFirstStep bool `json:"isFirstStep"` + IsLastStep bool `json:"isLastStep"` +} +``` + +### ClientApprovalSettingsDetail +```go +type ClientApprovalSettingsDetail struct { + ID uint `json:"id"` + ClientId string `json:"clientId"` + RequiresApproval *bool `json:"requiresApproval"` + DefaultWorkflowId *uint `json:"defaultWorkflowId"` + DefaultWorkflowName *string `json:"defaultWorkflowName"` + AutoPublishArticles *bool `json:"autoPublishArticles"` + ApprovalExemptUsers []uint `json:"approvalExemptUsers"` + ApprovalExemptRoles []uint `json:"approvalExemptRoles"` + ApprovalExemptCategories []uint `json:"approvalExemptCategories"` + RequireApprovalFor []string `json:"requireApprovalFor"` + SkipApprovalFor []string `json:"skipApprovalFor"` + IsActive *bool `json:"isActive"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + + // Detailed exempt information + ExemptUsersDetails []UserDetailInfo `json:"exemptUsersDetails"` + ExemptRolesDetails []UserRoleDetailInfo `json:"exemptRolesDetails"` + ExemptCategoriesDetails []CategoryDetailInfo `json:"exemptCategoriesDetails"` +} +``` + +### RelatedDataInfo +```go +type RelatedDataInfo struct { + UserLevels []UserLevelDetailInfo `json:"userLevels"` +} +``` + +### WorkflowStatisticsInfo +```go +type WorkflowStatisticsInfo struct { + TotalArticlesProcessed int `json:"totalArticlesProcessed"` + PendingArticles int `json:"pendingArticles"` + ApprovedArticles int `json:"approvedArticles"` + RejectedArticles int `json:"rejectedArticles"` + AverageProcessingTime int `json:"averageProcessingTime"` + MostActiveStep string `json:"mostActiveStep"` + LastUsedAt *string `json:"lastUsedAt"` +} +``` + +## Error Responses + +### 400 Bad Request +```json +{ + "success": false, + "messages": ["Validation failed: workflowId is required"], + "data": null +} +``` + +### 401 Unauthorized +```json +{ + "success": false, + "messages": ["Unauthorized access"], + "data": null +} +``` + +### 404 Not Found +```json +{ + "success": false, + "messages": ["Workflow not found"], + "data": null +} +``` + +### 500 Internal Server Error +```json +{ + "success": false, + "messages": ["Internal server error"], + "data": null +} +``` + +## Features + +### 1. Comprehensive Workflow Information +- Detail lengkap workflow termasuk metadata dan statistik +- Informasi step dengan hierarki dan kondisi +- Status aktif/inaktif dan konfigurasi approval + +### 2. Detailed Step Information +- Informasi lengkap setiap step dalam workflow +- Nama user level yang diperlukan untuk approval +- Konfigurasi skip, auto-approve, dan kondisi +- Dukungan multi-branch workflow + +### 3. Client Settings Integration +- Pengaturan approval global untuk client +- Daftar user, role, dan kategori yang dikecualikan +- Informasi detail untuk setiap exemption +- Workflow default yang digunakan + +### 4. Related Data Support +- Daftar user level yang tersedia +- Data pendukung untuk konfigurasi workflow +- Informasi terkait untuk referensi + +### 5. Statistics Information +- Statistik penggunaan workflow (placeholder untuk implementasi future) +- Informasi performa dan aktivitas +- Data untuk monitoring dan analisis + +## Use Cases + +### 1. Workflow Management Dashboard +- Menampilkan detail lengkap workflow untuk administrator +- Monitoring status dan konfigurasi workflow +- Analisis performa dan penggunaan + +### 2. Workflow Configuration +- Mengedit workflow dengan informasi lengkap +- Mengatur step dan kondisi approval +- Konfigurasi exemption dan pengaturan client + +### 3. Approval Process Monitoring +- Melihat status artikel dalam proses approval +- Tracking progress melalui step workflow +- Monitoring bottleneck dan performa + +### 4. Client Settings Management +- Mengatur pengaturan approval global +- Mengelola exemption untuk user dan kategori +- Konfigurasi workflow default + +## Implementation Notes + +### 1. Performance Considerations +- API menggunakan single query dengan join untuk efisiensi +- Data related diambil secara terpisah untuk fleksibilitas +- Caching dapat diimplementasikan untuk data yang jarang berubah + +### 2. Security +- Menggunakan authentication token untuk akses +- Validasi clientId dari token untuk multi-tenant +- Authorization check untuk akses workflow + +### 3. Error Handling +- Graceful handling untuk data yang tidak ditemukan +- Logging untuk debugging dan monitoring +- Rollback mechanism untuk operasi yang gagal + +### 4. Extensibility +- Struktur response dapat diperluas untuk kebutuhan future +- Statistics dapat diimplementasikan dengan query yang lebih kompleks +- Support untuk workflow yang lebih kompleks + +## Dependencies + +### Required Repositories +- `ApprovalWorkflowsRepository` +- `ApprovalWorkflowStepsRepository` +- `ClientApprovalSettingsRepository` +- `UsersRepository` +- `UserLevelsRepository` +- `UserRolesRepository` +- `ArticleCategoriesRepository` +- `ArticleApprovalFlowsRepository` + +### Required Services +- `ApprovalWorkflowsService` +- `ClientApprovalSettingsService` + +## Testing + +### Unit Tests +```go +func TestGetComprehensiveWorkflowDetails(t *testing.T) { + // Test cases for comprehensive workflow details + // Test with valid workflow ID + // Test with invalid workflow ID + // Test with missing client settings + // Test with empty steps +} +``` + +### Integration Tests +```go +func TestComprehensiveWorkflowDetailsAPI(t *testing.T) { + // Test API endpoint + // Test authentication + // Test response structure + // Test error handling +} +``` + +## Future Enhancements + +### 1. Real-time Statistics +- Implementasi query untuk statistik real-time +- Monitoring performa workflow +- Analytics dan reporting + +### 2. Workflow Templates +- Template workflow yang dapat digunakan kembali +- Import/export workflow configuration +- Workflow marketplace + +### 3. Advanced Branching +- Conditional workflow berdasarkan konten +- Dynamic step generation +- AI-powered workflow optimization + +### 4. Integration Features +- Webhook untuk notifikasi +- API untuk external system integration +- Workflow automation triggers diff --git a/docs/FRONTEND_FORM_GENERATION_PROMPT.md b/docs/FRONTEND_FORM_GENERATION_PROMPT.md new file mode 100644 index 0000000..20c1074 --- /dev/null +++ b/docs/FRONTEND_FORM_GENERATION_PROMPT.md @@ -0,0 +1,412 @@ +# Frontend Form Generation Prompt + +## Overview +Generate comprehensive React/TypeScript forms for two main functionalities based on backend API specifications: + +1. **Approval Workflow Settings Form** (API: `/approval-workflows/with-client-settings`) +2. **User Levels Management Form** (API: `/user-levels`) + +--- + +## 1. APPROVAL WORKFLOW SETTINGS FORM + +### API Endpoint +``` +POST /approval-workflows/with-client-settings +``` + +### Request Structure +```typescript +interface CreateApprovalWorkflowWithClientSettingsRequest { + // Workflow details + name: string; // required + description: string; // required + isActive?: boolean; + isDefault?: boolean; + requiresApproval?: boolean; + autoPublish?: boolean; + steps: ApprovalWorkflowStepRequest[]; // required, min 1 + + // Client approval settings + clientApprovalSettings: ClientApprovalSettingsRequest; +} + +interface ApprovalWorkflowStepRequest { + stepOrder: number; // required + stepName: string; // required + requiredUserLevelId: number; // required + canSkip?: boolean; + autoApproveAfterHours?: number; + isActive?: boolean; + + // Multi-branch support fields + parentStepId?: number; + conditionType?: string; // 'user_level', 'user_level_hierarchy', 'always', 'custom' + conditionValue?: string; // JSON string for conditions + isParallel?: boolean; + branchName?: string; + branchOrder?: number; +} + +interface ClientApprovalSettingsRequest { + requiresApproval?: boolean; + autoPublishArticles?: boolean; + approvalExemptUsers: number[]; + approvalExemptRoles: number[]; + approvalExemptCategories: number[]; + requireApprovalFor: string[]; + skipApprovalFor: string[]; + isActive?: boolean; +} +``` + +### CURL Request +``` +curl -X 'POST' \ + 'https://kontenhumas.com/api/approval-workflows/with-client-settings' \ + -H 'accept: application/json' \ + -H 'Authorization: Bearer eyJhbGciOiJSU....' \ + -H 'Content-Type: application/json' \ + -d '{ + "autoPublish": true, + "clientApprovalSettings": { + "approvalExemptCategories": [], + "approvalExemptRoles": [], + "approvalExemptUsers": [], + "autoPublishArticles": true, + "isActive": true, + "requireApprovalFor": [], + "requiresApproval": true, + "skipApprovalFor": [] + }, + "description": "Test", + "isActive": true, + "isDefault": true, + "name": "Multi-Branch Jurnalis Approval", + "requiresApproval": true, + "steps": [ + { + "stepOrder": 1, + "stepName": "Single Approval", + "requiredUserLevelId": 12, + "conditionType": "user_level_hierarchy", + "conditionValue": "{\"applies_to_levels\": [13]}", + "branchName": "Single Approval" + } + ] +}' +``` + +### Form Requirements + +#### **Section 1: Workflow Basic Information** +- **Workflow Name** (Text Input, Required) + - Label: "Workflow Name" + - Placeholder: "e.g., Standard Article Approval" + - Validation: Required, min 3 characters + +- **Description** (Textarea, Required) + - Label: "Workflow Description" + - Placeholder: "Describe the purpose and process of this workflow" + - Validation: Required, min 10 characters + +- **Workflow Settings** (Checkbox Group) + - ☐ Is Active (default: true) + - ☐ Set as Default Workflow + - ☐ Requires Approval (default: true) + - ☐ Auto Publish After Approval (default: false) + +#### **Section 2: Workflow Steps** (Dynamic Array) +- **Add Step Button** - Allow adding multiple steps +- **Step Configuration** (for each step): + - **Step Order** (Number Input, Required) + - Label: "Step Order" + - Default: Auto-increment (1, 2, 3...) + - Validation: Required, unique within workflow + + - **Step Name** (Text Input, Required) + - Label: "Step Name" + - Placeholder: "e.g., Editor Review, Manager Approval" + - Validation: Required, min 3 characters + + - **Required User Level** (Select Dropdown, Required) + - Label: "Required User Level" + - Options: Fetch from `/user-levels` API + - Display: `{name} (Level {levelNumber})` + - Validation: Required + + - **Step Settings** (Checkbox Group) + - ☐ Can Skip This Step + - ☐ Is Active (default: true) + + - **Auto Approval** (Number Input, Optional) + - Label: "Auto Approve After Hours" + - Placeholder: "Leave empty for manual approval" + - Help Text: "Automatically approve after specified hours" + + - **Advanced Settings** (Collapsible Section) + - **Parent Step** (Select Dropdown, Optional) + - Label: "Parent Step (for branching)" + - Options: Previous steps in workflow + - Help Text: "Select parent step for parallel branches" + + - **Condition Type** (Select Dropdown, Optional) + - Label: "Condition Type" + - Options: ['always', 'user_level', 'user_level_hierarchy', 'custom'] + - Default: 'always' + + - **Condition Value** (Text Input, Optional) + - Label: "Condition Value (JSON)" + - Placeholder: '{"minLevel": 3}' + - Help Text: "JSON string for custom conditions" + + - **Branch Settings** (Checkbox Group) + - ☐ Is Parallel Step + - **Branch Name** (Text Input, Optional) + - Label: "Branch Name" + - Placeholder: "e.g., technical, content" + - **Branch Order** (Number Input, Optional) + - Label: "Branch Order" + +- **Step Actions** + - Move Up/Down buttons + - Delete Step button + - Duplicate Step button + +#### **Section 3: Client Approval Settings** +- **Global Approval Settings** (Checkbox Group) + - ☐ Requires Approval (default: true) + - ☐ Auto Publish Articles (default: false) + - ☐ Is Active (default: true) + +- **Exemptions** (Multi-select sections) + - **Exempt Users** (Multi-select) + - Label: "Users Exempt from Approval" + - Options: Fetch from `/users` API + - Display: `{fullname} ({username})` + - Searchable: Yes + + - **Exempt Roles** (Multi-select) + - Label: "Roles Exempt from Approval" + - Options: Fetch from `/user-roles` API + - Display: `{roleName}` + - Searchable: Yes + + - **Exempt Categories** (Multi-select) + - Label: "Categories Exempt from Approval" + - Options: Fetch from `/article-categories` API + - Display: `{categoryName}` + - Searchable: Yes + +- **Content Type Rules** (Dynamic Arrays) + - **Require Approval For** (Tag Input) + - Label: "Content Types Requiring Approval" + - Placeholder: "e.g., news, article, blog" + - Help Text: "Press Enter to add content type" + + - **Skip Approval For** (Tag Input) + - Label: "Content Types Skipping Approval" + - Placeholder: "e.g., announcement, update" + - Help Text: "Press Enter to add content type" + +### Form Features +- **Real-time Validation** +- **Step-by-step Wizard** (Optional) +- **Preview Mode** - Show workflow visualization +- **Save as Draft** functionality +- **Form Reset** with confirmation +- **Auto-save** every 30 seconds + +--- + +## 2. USER LEVELS MANAGEMENT FORM + +### API Endpoint +``` +POST /user-levels +``` + +### Request Structure +```typescript +interface UserLevelsCreateRequest { + name: string; // required + aliasName: string; // required + levelNumber: number; // required + parentLevelId?: number; + provinceId?: number; + group?: string; + isApprovalActive?: boolean; + isActive?: boolean; +} +``` + +### Form Requirements + +#### **Section 1: Basic Information** +- **Level Name** (Text Input, Required) + - Label: "Level Name" + - Placeholder: "e.g., Senior Editor, Manager, Publisher" + - Validation: Required, min 3 characters, unique + +- **Alias Name** (Text Input, Required) + - Label: "Alias Name" + - Placeholder: "e.g., SENIOR_EDITOR, MANAGER, PUBLISHER" + - Validation: Required, uppercase, unique + - Help Text: "Short identifier for system use" + +- **Level Number** (Number Input, Required) + - Label: "Level Number" + - Placeholder: "e.g., 1, 2, 3" + - Validation: Required, unique, positive integer + - Help Text: "Higher number = higher authority" + +#### **Section 2: Hierarchy Settings** +- **Parent Level** (Select Dropdown, Optional) + - Label: "Parent Level" + - Options: Fetch from `/user-levels` API + - Display: `{name} (Level {levelNumber})` + - Help Text: "Select parent level for hierarchy" + +- **Province** (Select Dropdown, Optional) + - Label: "Province" + - Options: Fetch from `/provinces` API + - Display: `{provinceName}` + - Help Text: "Geographic scope for this level" + +- **Group** (Text Input, Optional) + - Label: "Group" + - Placeholder: "e.g., Editorial, Management, Technical" + - Help Text: "Group classification for organization" + +#### **Section 3: Approval Settings** +- **Approval Settings** (Checkbox Group) + - ☐ Is Approval Active (default: true) + - Help Text: "Users with this level can participate in approval process" + - ☐ Is Active (default: true) + - Help Text: "Level is available for assignment" + +### Form Features +- **Level Number Validation** - Prevent duplicate level numbers +- **Hierarchy Visualization** - Show level hierarchy tree +- **Bulk Operations** - Create multiple levels at once +- **Import/Export** - CSV import/export functionality +- **Level Preview** - Show how level fits in hierarchy + +--- + +## 3. COMMON FORM COMPONENTS + +### **Form Layout** +- **Responsive Design** - Mobile-first approach +- **Multi-step Wizard** - For complex forms +- **Tabbed Interface** - For different sections +- **Collapsible Sections** - For advanced settings + +### **Validation** +- **Real-time Validation** - Show errors as user types +- **Cross-field Validation** - Validate relationships between fields +- **Server-side Validation** - Handle API validation errors +- **Custom Validation Rules** - Business logic validation + +### **User Experience** +- **Auto-complete** - For select fields +- **Search Functionality** - For large option lists +- **Drag & Drop** - For reordering steps/items +- **Keyboard Navigation** - Full keyboard support +- **Accessibility** - ARIA labels, screen reader support + +### **Data Management** +- **Form State Management** - Redux/Zustand +- **Local Storage** - Save draft forms +- **API Integration** - Axios/Fetch with error handling +- **Loading States** - Spinners, skeleton screens +- **Success/Error Messages** - Toast notifications + +### **Styling Requirements** +- **Design System** - Consistent with existing app +- **Dark/Light Mode** - Theme support +- **Custom Components** - Reusable form components +- **Animation** - Smooth transitions +- **Icons** - Meaningful icons for actions + +--- + +## 4. IMPLEMENTATION NOTES + +### **API Integration** +```typescript +// Example API calls +const createWorkflow = async (data: CreateApprovalWorkflowWithClientSettingsRequest) => { + const response = await fetch('/api/approval-workflows/with-client-settings', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${token}` + }, + body: JSON.stringify(data) + }); + return response.json(); +}; + +const createUserLevel = async (data: UserLevelsCreateRequest) => { + const response = await fetch('/api/user-levels', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${token}` + }, + body: JSON.stringify(data) + }); + return response.json(); +}; +``` + +### **Form Libraries** +- **React Hook Form** - For form management +- **Yup/Zod** - For validation +- **React Select** - For advanced select components +- **React DnD** - For drag and drop +- **React Query** - For API state management + +### **Component Structure** +``` +components/ +├── forms/ +│ ├── ApprovalWorkflowForm/ +│ │ ├── index.tsx +│ │ ├── WorkflowBasicInfo.tsx +│ │ ├── WorkflowSteps.tsx +│ │ ├── ClientSettings.tsx +│ │ └── StepForm.tsx +│ └── UserLevelsForm/ +│ ├── index.tsx +│ ├── BasicInfo.tsx +│ ├── HierarchySettings.tsx +│ └── ApprovalSettings.tsx +├── common/ +│ ├── FormField.tsx +│ ├── DynamicArray.tsx +│ ├── MultiSelect.tsx +│ └── ValidationMessage.tsx +``` + +### **State Management** +```typescript +// Form state structure +interface FormState { + workflowForm: { + data: CreateApprovalWorkflowWithClientSettingsRequest; + errors: Record; + isValid: boolean; + isSubmitting: boolean; + }; + userLevelsForm: { + data: UserLevelsCreateRequest; + errors: Record; + isValid: boolean; + isSubmitting: boolean; + }; +} +``` + +This prompt provides comprehensive specifications for generating both forms with all necessary fields, validation rules, user experience considerations, and implementation details based on the backend API structures. diff --git a/docs/swagger/docs.go b/docs/swagger/docs.go index 49bcbd1..692d891 100644 --- a/docs/swagger/docs.go +++ b/docs/swagger/docs.go @@ -1706,6 +1706,64 @@ const docTemplate = `{ } } }, + "/approval-workflows/comprehensive-details": { + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for getting comprehensive details of approval workflow including steps, client settings, and related data", + "tags": [ + "ApprovalWorkflows" + ], + "summary": "Get comprehensive approval workflow details", + "parameters": [ + { + "type": "string", + "description": "Insert the Authorization", + "name": "Authorization", + "in": "header", + "required": true + }, + { + "description": "Workflow detail request", + "name": "req", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.ComprehensiveWorkflowDetailRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + } + }, "/approval-workflows/default": { "get": { "security": [ @@ -17344,6 +17402,17 @@ const docTemplate = `{ } } }, + "request.ComprehensiveWorkflowDetailRequest": { + "type": "object", + "required": [ + "workflowId" + ], + "properties": { + "workflowId": { + "type": "integer" + } + } + }, "request.CreateApprovalWorkflowStepsRequest": { "type": "object", "required": [ diff --git a/docs/swagger/swagger.json b/docs/swagger/swagger.json index 5c140c4..89b65a2 100644 --- a/docs/swagger/swagger.json +++ b/docs/swagger/swagger.json @@ -1695,6 +1695,64 @@ } } }, + "/approval-workflows/comprehensive-details": { + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for getting comprehensive details of approval workflow including steps, client settings, and related data", + "tags": [ + "ApprovalWorkflows" + ], + "summary": "Get comprehensive approval workflow details", + "parameters": [ + { + "type": "string", + "description": "Insert the Authorization", + "name": "Authorization", + "in": "header", + "required": true + }, + { + "description": "Workflow detail request", + "name": "req", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.ComprehensiveWorkflowDetailRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + } + }, "/approval-workflows/default": { "get": { "security": [ @@ -17333,6 +17391,17 @@ } } }, + "request.ComprehensiveWorkflowDetailRequest": { + "type": "object", + "required": [ + "workflowId" + ], + "properties": { + "workflowId": { + "type": "integer" + } + } + }, "request.CreateApprovalWorkflowStepsRequest": { "type": "object", "required": [ diff --git a/docs/swagger/swagger.yaml b/docs/swagger/swagger.yaml index 2dc99a8..23e95ae 100644 --- a/docs/swagger/swagger.yaml +++ b/docs/swagger/swagger.yaml @@ -802,6 +802,13 @@ definitions: description: Custom settings type: string type: object + request.ComprehensiveWorkflowDetailRequest: + properties: + workflowId: + type: integer + required: + - workflowId + type: object request.CreateApprovalWorkflowStepsRequest: properties: approverRoleId: @@ -3031,6 +3038,44 @@ paths: summary: Update ApprovalWorkflows with steps tags: - ApprovalWorkflows + /approval-workflows/comprehensive-details: + post: + description: API for getting comprehensive details of approval workflow including + steps, client settings, and related data + parameters: + - description: Insert the Authorization + in: header + name: Authorization + required: true + type: string + - description: Workflow detail request + in: body + name: req + required: true + schema: + $ref: '#/definitions/request.ComprehensiveWorkflowDetailRequest' + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.BadRequestError' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.UnauthorizedError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.InternalServerError' + security: + - Bearer: [] + summary: Get comprehensive approval workflow details + tags: + - ApprovalWorkflows /approval-workflows/default: get: description: API for getting default ApprovalWorkflows