Files
gochat/internal/service/csat_template_service.go
T
2026-06-04 15:44:48 +08:00

132 lines
5.0 KiB
Go

package service
import (
"context"
"errors"
"gorm.io/gorm"
"github.com/gochat/gochat/internal/model"
"github.com/gochat/gochat/internal/repository"
applogger "github.com/gochat/gochat/pkg/logger"
pkgvalidator "github.com/gochat/gochat/pkg/validator"
)
// CsatTemplateService implements business logic for CSAT template management.
// Reference: Chatwoot app/controllers/api/v1/accounts/inboxes/inbox_csat_templates_controller.rb
// CSAT templates are singular resources per inbox — show (get template status), create (submit template),
// and analyze (check template quality via Captain AI).
type CsatTemplateService struct {
repo *repository.CsatTemplateRepo
}
// NewCsatTemplateService creates a new CsatTemplate service.
func NewCsatTemplateService(repo *repository.CsatTemplateRepo) *CsatTemplateService {
return &CsatTemplateService{repo: repo}
}
// CreateCsatTemplateRequest is the DTO for creating a CSAT template.
// Reference: Chatwoot InboxCsatTemplatesController#create — params: {message}
type CreateCsatTemplateRequest struct {
Message string `json:"message" validate:"required,min=1"`
}
// AnalyzeCsatTemplateRequest is the DTO for analyzing a CSAT template.
// Reference: Chatwoot InboxCsatTemplatesController#analyze — params: {message}
type AnalyzeCsatTemplateRequest struct {
Message string `json:"message" validate:"required,min=1"`
}
// CsatTemplateAnalysisResult represents the result of a CSAT template quality analysis.
// Placeholder implementation — real analysis requires Captain AI integration (WhatsApp template validation).
type CsatTemplateAnalysisResult struct {
Quality string `json:"quality"` // e.g. "good", "poor", "needs_improvement"
Suggestions []string `json:"suggestions"` // improvement suggestions
IsApproved bool `json:"is_approved"` // whether template would likely pass WhatsApp approval
Message string `json:"message"` // original message analyzed
}
// ShowTemplateStatus retrieves the CSAT template status for an inbox.
// If no template exists, returns nil to indicate "no template configured".
// Reference: Chatwoot InboxCsatTemplatesController#show
func (s *CsatTemplateService) ShowTemplateStatus(ctx context.Context, inboxID uint) (*model.CsatTemplate, error) {
template, err := s.repo.FindByInbox(ctx, inboxID)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
// No template configured — return nil to indicate "no template" (handler will return empty response)
return nil, nil
}
return nil, err
}
return template, nil
}
// CreateTemplate creates a new CSAT template for an inbox.
// If a template already exists for the inbox, updates it instead.
// Reference: Chatwoot InboxCsatTemplatesController#create
func (s *CsatTemplateService) CreateTemplate(ctx context.Context, inboxID uint, req CreateCsatTemplateRequest) (*model.CsatTemplate, error) {
if err := pkgvalidator.ValidateStruct(req); err != nil {
return nil, err
}
// Check if template already exists for this inbox
existing, err := s.repo.FindByInbox(ctx, inboxID)
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
return nil, err
}
if existing != nil {
// Update existing template
existing.Message = req.Message
existing.Status = "pending" // Reset status to pending after message change
if err := s.repo.Update(ctx, existing); err != nil {
return nil, err
}
applogger.L().Infof("CSAT template updated for inbox %d", inboxID)
return existing, nil
}
// Create new template
template := &model.CsatTemplate{
InboxID: inboxID,
Message: req.Message,
Status: "pending",
}
if err := s.repo.Create(ctx, template); err != nil {
return nil, err
}
applogger.L().Infof("CSAT template created for inbox %d", inboxID)
return template, nil
}
// AnalyzeTemplate analyzes a CSAT template message for quality.
// Placeholder implementation — real WhatsApp template analysis requires Captain AI integration.
// Reference: Chatwoot InboxCsatTemplatesController#analyze (captain_enabled check)
func (s *CsatTemplateService) AnalyzeTemplate(ctx context.Context, inboxID uint, req AnalyzeCsatTemplateRequest) (*CsatTemplateAnalysisResult, error) {
if err := pkgvalidator.ValidateStruct(req); err != nil {
return nil, err
}
// Placeholder analysis logic — real implementation would use Captain AI
// to validate template against WhatsApp Business API requirements.
result := &CsatTemplateAnalysisResult{
Message: req.Message,
Quality: "good",
IsApproved: true,
Suggestions: []string{},
}
// Basic heuristic checks
if len(req.Message) < 10 {
result.Quality = "poor"
result.IsApproved = false
result.Suggestions = append(result.Suggestions, "Message is too short for a CSAT survey template")
}
if len(req.Message) > 500 {
result.Quality = "needs_improvement"
result.Suggestions = append(result.Suggestions, "Message may be too long for WhatsApp template approval")
}
applogger.L().Infof("CSAT template analyzed for inbox %d, quality=%s", inboxID, result.Quality)
return result, nil
}