feat: update approval workflows

This commit is contained in:
hanif salafi 2025-10-02 12:28:10 +07:00
parent 9ba425540e
commit df77b1c576
11 changed files with 1558 additions and 34 deletions

View File

@ -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)

View File

@ -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,
})
}

View File

@ -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,
}
}

View File

@ -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"`
}

View File

@ -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"`
}

View File

@ -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
}

View File

@ -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 <access_token>
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

View File

@ -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<string, string>;
isValid: boolean;
isSubmitting: boolean;
};
userLevelsForm: {
data: UserLevelsCreateRequest;
errors: Record<string, string>;
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.

View File

@ -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": [

View File

@ -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": [

View File

@ -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