thread-master/apps/backend/internal/module/radar/usecase/promote.go

46 lines
2.1 KiB
Go
Raw Normal View History

2026-08-03 05:52:02 +00:00
package usecase
import (
"context"
"fmt"
"apps/backend/internal/module/radar/domain"
)
// PromoteFromScout creates an Opportunity from a scout post snapshot (copy, not shared state).
func (s *Service) PromoteFromScout(ctx context.Context, ownerUID int64, scoutPostID, externalID, permalink, author, text string, postedAt int64) (*domain.Opportunity, error) {
if ownerUID <= 0 || externalID == "" {
return nil, fmt.Errorf("%w: owner and external_id required", domain.ErrValidation)
}
profile, _ := s.Repo.GetServiceProfile(ctx, ownerUID)
cand := &domain.CandidatePost{
ExternalID: externalID, Permalink: permalink, AuthorHandle: author,
Text: text, PostedAt: postedAt, MatchedTerm: "scout_promote", Classification: "seeking_help",
}
res, _, err := s.JudgeCandidate(ctx, ownerUID, profile, nil, cand)
if err != nil || res == nil {
// still store as qualified mid with minimal reasons if judge fails
res = &JudgeResult{
Status: domain.OppQualified, IntentScore: 55, IntentBand: domain.BandMid,
Reasons: []domain.OpportunityReason{
{Dimension: domain.DimAuthenticity, Score: 20, Reason: "由海巡提升,人工可覆寫"},
{Dimension: domain.DimIntent, Score: 15, Reason: "海巡已標記為值得跟進"},
{Dimension: domain.DimRegion, Score: 7, Reason: "未重判地區"},
{Dimension: domain.DimFreshness, Score: 8, Reason: "沿用貼文時間"},
{Dimension: domain.DimFit, Score: 5, Reason: "海巡提升"},
},
RegionMatch: domain.RegionUnknown,
}
}
o := &domain.Opportunity{
ID: domain.NewID(), OwnerUID: ownerUID, Source: domain.OppSourceScoutPromote,
SourceScoutPostID: scoutPostID, ExternalID: externalID, Permalink: permalink,
AuthorHandle: author, Text: text, PostedAt: postedAt,
Status: res.Status, IntentScore: res.IntentScore, IntentBand: res.IntentBand,
Reasons: res.Reasons, RegionDetected: res.RegionDetected, RegionMatch: res.RegionMatch,
FreshnessHours: res.FreshnessHours, MatchedService: res.MatchedService,
MatchedTerms: []string{"scout_promote"}, RejectReason: res.RejectReason,
}
return s.Repo.UpsertByExternalID(ctx, o)
}