feat: add inbox capture workflow

This commit is contained in:
2026-07-18 15:59:34 +08:00
parent 18b2f30024
commit e6386bef91
3 changed files with 237 additions and 0 deletions

View File

@@ -0,0 +1,100 @@
package inbox
import (
"errors"
"gorm.io/gorm"
"senlinai-agent/backend/internal/domain"
)
type CaptureInput struct {
ProjectID uint
UserID uint
SourceType string
Title string
Body string
}
type Suggestion struct {
Kind string `json:"kind"`
Title string `json:"title"`
Body string `json:"body"`
}
type Analyzer interface {
Analyze(item domain.InboxItem, userID uint) ([]Suggestion, error)
}
type StaticAnalyzer struct {
Suggestions []Suggestion
}
func (a StaticAnalyzer) Analyze(item domain.InboxItem, userID uint) ([]Suggestion, error) {
return a.Suggestions, nil
}
type Service struct {
db *gorm.DB
analyzer Analyzer
}
func NewService(database *gorm.DB, analyzer Analyzer) *Service {
return &Service{db: database, analyzer: analyzer}
}
func (s *Service) Capture(input CaptureInput) (*domain.InboxItem, error) {
if input.ProjectID == 0 || input.UserID == 0 {
return nil, errors.New("project and user are required")
}
if input.SourceType == "" {
return nil, errors.New("source type is required")
}
item := &domain.InboxItem{
ProjectID: input.ProjectID,
CreatedBy: input.UserID,
SourceType: input.SourceType,
Title: input.Title,
Body: input.Body,
Status: "open",
}
return item, s.db.Create(item).Error
}
func (s *Service) Analyze(itemID uint, userID uint) ([]Suggestion, error) {
var item domain.InboxItem
if err := s.db.First(&item, itemID).Error; err != nil {
return nil, err
}
if s.analyzer == nil {
return []Suggestion{}, nil
}
return s.analyzer.Analyze(item, userID)
}
func (s *Service) Confirm(itemID uint, selected []Suggestion) error {
return s.db.Transaction(func(tx *gorm.DB) error {
var item domain.InboxItem
if err := tx.First(&item, itemID).Error; err != nil {
return err
}
for _, suggestion := range selected {
switch suggestion.Kind {
case "task":
if err := tx.Create(&domain.Task{ProjectID: item.ProjectID, CreatedBy: item.CreatedBy, Title: suggestion.Title, Description: suggestion.Body}).Error; err != nil {
return err
}
case "note":
if err := tx.Create(&domain.Note{ProjectID: item.ProjectID, CreatedBy: item.CreatedBy, Title: suggestion.Title, Markdown: suggestion.Body}).Error; err != nil {
return err
}
case "source":
if err := tx.Create(&domain.Source{ProjectID: item.ProjectID, CreatedBy: item.CreatedBy, Kind: "link", Title: suggestion.Title, ContentText: suggestion.Body}).Error; err != nil {
return err
}
default:
return errors.New("unsupported suggestion kind")
}
}
return tx.Model(&item).Update("status", "processed").Error
})
}