399 lines
8.6 KiB
Markdown
399 lines
8.6 KiB
Markdown
|
|
# Troubleshooting Guide
|
||
|
|
|
||
|
|
## Overview
|
||
|
|
|
||
|
|
Dokumentasi ini berisi panduan troubleshooting untuk masalah-masalah umum yang mungkin terjadi dalam sistem dynamic article approval.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🚨 Common Errors & Solutions
|
||
|
|
|
||
|
|
### **1. Swagger Documentation Errors**
|
||
|
|
|
||
|
|
#### **Error: `cannot find type definition: request.ApprovalWorkflowStepsQueryRequest`**
|
||
|
|
|
||
|
|
**Problem:**
|
||
|
|
|
||
|
|
- Controller menggunakan type yang tidak ada di request struct
|
||
|
|
- Swagger documentation reference ke type yang salah
|
||
|
|
|
||
|
|
**Solution:**
|
||
|
|
|
||
|
|
```go
|
||
|
|
// ❌ WRONG - Type tidak ada
|
||
|
|
@Param req query request.ApprovalWorkflowStepsQueryRequest false "query parameters"
|
||
|
|
|
||
|
|
// ✅ CORRECT - Gunakan type yang ada
|
||
|
|
@Param workflowId query int false "Workflow ID filter"
|
||
|
|
@Param stepOrder query int false "Step order filter"
|
||
|
|
@Param stepName query string false "Step name filter"
|
||
|
|
```
|
||
|
|
|
||
|
|
**Fix Steps:**
|
||
|
|
|
||
|
|
1. Periksa file `request/` untuk melihat struct yang tersedia
|
||
|
|
2. Update Swagger documentation dengan type yang benar
|
||
|
|
3. Update controller code untuk menggunakan struct yang ada
|
||
|
|
|
||
|
|
#### **Error: `undefined: request.ApprovalWorkflowStepsQueryRequestContext`**
|
||
|
|
|
||
|
|
**Problem:**
|
||
|
|
|
||
|
|
- Controller menggunakan struct yang tidak didefinisikan
|
||
|
|
|
||
|
|
**Solution:**
|
||
|
|
|
||
|
|
```go
|
||
|
|
// ❌ WRONG - Struct tidak ada
|
||
|
|
reqContext := request.ApprovalWorkflowStepsQueryRequestContext{...}
|
||
|
|
|
||
|
|
// ✅ CORRECT - Gunakan struct yang ada
|
||
|
|
req := request.GetApprovalWorkflowStepsRequest{
|
||
|
|
WorkflowID: parseUintPointer(c.Query("workflowId")),
|
||
|
|
StepOrder: parseIntPointer(c.Query("stepOrder")),
|
||
|
|
// ... other fields
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### **2. Missing Method Errors**
|
||
|
|
|
||
|
|
#### **Error: `req.ToEntity()` undefined**
|
||
|
|
|
||
|
|
**Problem:**
|
||
|
|
|
||
|
|
- Request struct tidak memiliki method `ToEntity()`
|
||
|
|
|
||
|
|
**Solution:**
|
||
|
|
|
||
|
|
```go
|
||
|
|
// ❌ WRONG - Method tidak ada
|
||
|
|
step := req.ToEntity()
|
||
|
|
|
||
|
|
// ✅ CORRECT - Manual conversion
|
||
|
|
step := &entity.ApprovalWorkflowSteps{
|
||
|
|
WorkflowId: req.WorkflowID,
|
||
|
|
StepOrder: req.StepOrder,
|
||
|
|
StepName: req.StepName,
|
||
|
|
// ... map other fields
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Fix Steps:**
|
||
|
|
|
||
|
|
1. Periksa request struct yang tersedia
|
||
|
|
2. Buat manual conversion dari request ke entity
|
||
|
|
3. Pastikan field mapping sesuai dengan entity structure
|
||
|
|
|
||
|
|
### **3. Import Errors**
|
||
|
|
|
||
|
|
#### **Error: `undefined: paginator.Paginate`**
|
||
|
|
|
||
|
|
**Problem:**
|
||
|
|
|
||
|
|
- Import path salah atau package tidak ada
|
||
|
|
|
||
|
|
**Solution:**
|
||
|
|
|
||
|
|
```go
|
||
|
|
// ❌ WRONG - Import path salah
|
||
|
|
import "web-qudo-be/utils/paginator"
|
||
|
|
|
||
|
|
// ✅ CORRECT - Import path yang benar
|
||
|
|
import "web-qudo-be/utils/paginator"
|
||
|
|
```
|
||
|
|
|
||
|
|
**Fix Steps:**
|
||
|
|
|
||
|
|
1. Periksa struktur folder `utils/`
|
||
|
|
2. Pastikan package name sesuai dengan folder
|
||
|
|
3. Update import path jika diperlukan
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🔧 Code Fixes Examples
|
||
|
|
|
||
|
|
### **Example 1: Fix Controller Query Parameter Parsing**
|
||
|
|
|
||
|
|
**Before (Broken):**
|
||
|
|
|
||
|
|
```go
|
||
|
|
reqContext := request.ApprovalWorkflowStepsQueryRequestContext{
|
||
|
|
WorkflowId: c.Query("workflowId"),
|
||
|
|
StepOrder: c.Query("stepOrder"),
|
||
|
|
// ... other fields
|
||
|
|
}
|
||
|
|
req := reqContext.ToParamRequest()
|
||
|
|
```
|
||
|
|
|
||
|
|
**After (Fixed):**
|
||
|
|
|
||
|
|
```go
|
||
|
|
req := request.GetApprovalWorkflowStepsRequest{
|
||
|
|
WorkflowID: parseUintPointer(c.Query("workflowId")),
|
||
|
|
StepOrder: parseIntPointer(c.Query("stepOrder")),
|
||
|
|
StepName: parseStringPointer(c.Query("stepName")),
|
||
|
|
UserLevelID: parseUintPointer(c.Query("userLevelId")),
|
||
|
|
IsOptional: parseBoolPointer(c.Query("isOptional")),
|
||
|
|
IsActive: parseBoolPointer(c.Query("isActive")),
|
||
|
|
Page: 1,
|
||
|
|
Limit: 10,
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Helper Functions:**
|
||
|
|
|
||
|
|
```go
|
||
|
|
func parseUintPointer(s string) *uint {
|
||
|
|
if s == "" {
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
if val, err := strconv.ParseUint(s, 10, 32); err == nil {
|
||
|
|
uval := uint(val)
|
||
|
|
return &uval
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func parseIntPointer(s string) *int {
|
||
|
|
if s == "" {
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
if val, err := strconv.Atoi(s); err == nil {
|
||
|
|
return &val
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func parseStringPointer(s string) *string {
|
||
|
|
if s == "" {
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
return &s
|
||
|
|
}
|
||
|
|
|
||
|
|
func parseBoolPointer(s string) *bool {
|
||
|
|
if s == "" {
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
if val, err := strconv.ParseBool(s); err == nil {
|
||
|
|
return &val
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### **Example 2: Fix Request to Entity Conversion**
|
||
|
|
|
||
|
|
**Before (Broken):**
|
||
|
|
|
||
|
|
```go
|
||
|
|
step := req.ToEntity()
|
||
|
|
```
|
||
|
|
|
||
|
|
**After (Fixed):**
|
||
|
|
|
||
|
|
```go
|
||
|
|
step := &entity.ApprovalWorkflowSteps{
|
||
|
|
WorkflowId: req.WorkflowID,
|
||
|
|
StepOrder: req.StepOrder,
|
||
|
|
StepName: req.StepName,
|
||
|
|
StepDescription: req.Description,
|
||
|
|
RequiredUserLevelId: req.ApproverRoleID,
|
||
|
|
CanSkip: req.IsOptional,
|
||
|
|
RequiresComment: req.RequiresComment,
|
||
|
|
AutoApprove: req.AutoApprove,
|
||
|
|
TimeoutHours: req.TimeoutHours,
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### **Example 3: Fix Update Method Conversion**
|
||
|
|
|
||
|
|
**Before (Broken):**
|
||
|
|
|
||
|
|
```go
|
||
|
|
step := req.ToEntity()
|
||
|
|
```
|
||
|
|
|
||
|
|
**After (Fixed):**
|
||
|
|
|
||
|
|
```go
|
||
|
|
step := &entity.ApprovalWorkflowSteps{}
|
||
|
|
if req.StepOrder != nil {
|
||
|
|
step.StepOrder = *req.StepOrder
|
||
|
|
}
|
||
|
|
if req.StepName != nil {
|
||
|
|
step.StepName = *req.StepName
|
||
|
|
}
|
||
|
|
if req.Description != nil {
|
||
|
|
step.StepDescription = req.Description
|
||
|
|
}
|
||
|
|
if req.ApproverRoleID != nil {
|
||
|
|
step.RequiredUserLevelId = req.ApproverRoleID
|
||
|
|
}
|
||
|
|
if req.IsOptional != nil {
|
||
|
|
step.CanSkip = *req.IsOptional
|
||
|
|
}
|
||
|
|
if req.RequiresComment != nil {
|
||
|
|
step.RequiresComment = *req.RequiresComment
|
||
|
|
}
|
||
|
|
if req.AutoApprove != nil {
|
||
|
|
step.AutoApprove = *req.AutoApprove
|
||
|
|
}
|
||
|
|
if req.TimeoutHours != nil {
|
||
|
|
step.TimeoutHours = req.TimeoutHours
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 📋 Debugging Checklist
|
||
|
|
|
||
|
|
### **When Controller Has Errors:**
|
||
|
|
|
||
|
|
- [ ] Periksa import statements
|
||
|
|
- [ ] Periksa struct names di request package
|
||
|
|
- [ ] Periksa method calls yang tidak ada
|
||
|
|
- [ ] Periksa Swagger documentation references
|
||
|
|
- [ ] Periksa type conversions
|
||
|
|
|
||
|
|
### **When Build Fails:**
|
||
|
|
|
||
|
|
- [ ] Run `go build -o web-qudo-be.exe .`
|
||
|
|
- [ ] Periksa error messages dengan teliti
|
||
|
|
- [ ] Periksa file yang disebutkan dalam error
|
||
|
|
- [ ] Periksa line number yang error
|
||
|
|
- [ ] Periksa dependencies dan imports
|
||
|
|
|
||
|
|
### **When API Returns Errors:**
|
||
|
|
|
||
|
|
- [ ] Periksa request payload format
|
||
|
|
- [ ] Periksa validation rules
|
||
|
|
- [ ] Periksa database connections
|
||
|
|
- [ ] Periksa middleware configuration
|
||
|
|
- [ ] Periksa client authentication
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🚀 Prevention Tips
|
||
|
|
|
||
|
|
### **1. Code Structure Best Practices**
|
||
|
|
|
||
|
|
- **Consistent Naming**: Gunakan naming convention yang konsisten
|
||
|
|
- **Type Safety**: Selalu gunakan type yang sudah didefinisikan
|
||
|
|
- **Documentation**: Update Swagger docs setiap kali ada perubahan
|
||
|
|
- **Testing**: Test build setelah setiap perubahan besar
|
||
|
|
|
||
|
|
### **2. Common Patterns to Follow**
|
||
|
|
|
||
|
|
```go
|
||
|
|
// ✅ GOOD - Consistent struct usage
|
||
|
|
type CreateRequest struct {
|
||
|
|
Field1 string `json:"field1" validate:"required"`
|
||
|
|
Field2 *int `json:"field2" validate:"omitempty,min=1"`
|
||
|
|
}
|
||
|
|
|
||
|
|
// ✅ GOOD - Proper conversion
|
||
|
|
func (r *CreateRequest) ToEntity() *Entity {
|
||
|
|
return &Entity{
|
||
|
|
Field1: r.Field1,
|
||
|
|
Field2: r.Field2,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// ✅ GOOD - Proper Swagger docs
|
||
|
|
// @Param payload body request.CreateRequest true "Required payload"
|
||
|
|
```
|
||
|
|
|
||
|
|
### **3. Error Handling Best Practices**
|
||
|
|
|
||
|
|
```go
|
||
|
|
// ✅ GOOD - Proper error handling
|
||
|
|
if err != nil {
|
||
|
|
return utilRes.ErrorBadRequest(c, "Invalid ID format")
|
||
|
|
}
|
||
|
|
|
||
|
|
// ✅ GOOD - Validation before processing
|
||
|
|
if req.Field1 == "" {
|
||
|
|
return utilRes.ErrorBadRequest(c, "Field1 is required")
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🔍 Debugging Commands
|
||
|
|
|
||
|
|
### **Build Commands:**
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Basic build
|
||
|
|
go build -o web-qudo-be.exe .
|
||
|
|
|
||
|
|
# Build with verbose output
|
||
|
|
go build -v -o web-qudo-be.exe .
|
||
|
|
|
||
|
|
# Build specific package
|
||
|
|
go build ./app/module/approval_workflow_steps/controller
|
||
|
|
```
|
||
|
|
|
||
|
|
### **Go Tools:**
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Format code
|
||
|
|
go fmt ./...
|
||
|
|
|
||
|
|
# Vet code for common mistakes
|
||
|
|
go vet ./...
|
||
|
|
|
||
|
|
# Run tests
|
||
|
|
go test ./...
|
||
|
|
|
||
|
|
# Check dependencies
|
||
|
|
go mod tidy
|
||
|
|
```
|
||
|
|
|
||
|
|
### **IDE Tools:**
|
||
|
|
|
||
|
|
- **GoLand**: Built-in error detection
|
||
|
|
- **VS Code**: Go extension with error highlighting
|
||
|
|
- **Vim**: Go plugins for syntax checking
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 📚 Reference Materials
|
||
|
|
|
||
|
|
### **Useful Go Documentation:**
|
||
|
|
|
||
|
|
- [Go Language Specification](https://golang.org/ref/spec)
|
||
|
|
- [Go Modules](https://golang.org/doc/modules)
|
||
|
|
- [Go Testing](https://golang.org/doc/testing)
|
||
|
|
|
||
|
|
### **Project-Specific:**
|
||
|
|
|
||
|
|
- `docs/notes/api-endpoints-documentation.md` - API documentation
|
||
|
|
- `docs/notes/end-to-end-test-scenarios.md` - Test scenarios
|
||
|
|
- `app/module/*/request/*.go` - Request structs
|
||
|
|
- `app/module/*/entity/*.go` - Database entities
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🆘 Getting Help
|
||
|
|
|
||
|
|
### **When to Ask for Help:**
|
||
|
|
|
||
|
|
- Error tidak bisa di-resolve setelah 30 menit
|
||
|
|
- Error message tidak jelas atau misleading
|
||
|
|
- Build berhasil tapi runtime error
|
||
|
|
- Performance issues yang tidak expected
|
||
|
|
|
||
|
|
### **Information to Provide:**
|
||
|
|
|
||
|
|
- Error message lengkap
|
||
|
|
- File dan line number yang error
|
||
|
|
- Steps to reproduce
|
||
|
|
- Environment details (OS, Go version, etc.)
|
||
|
|
- Code snippet yang bermasalah
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
_Dokumentasi ini akan diupdate sesuai dengan masalah-masalah baru yang ditemukan._
|