turash/bugulma/backend/internal/service/trust_service.go
Damir Mukimov 000eab4740
Major repository reorganization and missing backend endpoints implementation
Repository Structure:
- Move files from cluttered root directory into organized structure
- Create archive/ for archived data and scraper results
- Create bugulma/ for the complete application (frontend + backend)
- Create data/ for sample datasets and reference materials
- Create docs/ for comprehensive documentation structure
- Create scripts/ for utility scripts and API tools

Backend Implementation:
- Implement 3 missing backend endpoints identified in gap analysis:
  * GET /api/v1/organizations/{id}/matching/direct - Direct symbiosis matches
  * GET /api/v1/users/me/organizations - User organizations
  * POST /api/v1/proposals/{id}/status - Update proposal status
- Add complete proposal domain model, repository, and service layers
- Create database migration for proposals table
- Fix CLI server command registration issue

API Documentation:
- Add comprehensive proposals.md API documentation
- Update README.md with Users and Proposals API sections
- Document all request/response formats, error codes, and business rules

Code Quality:
- Follow existing Go backend architecture patterns
- Add proper error handling and validation
- Match frontend expected response schemas
- Maintain clean separation of concerns (handler -> service -> repository)
2025-11-25 06:01:16 +01:00

234 lines
7.1 KiB
Go

package service
import (
"bugulma/backend/internal/domain"
"bugulma/backend/internal/repository"
"context"
"fmt"
"time"
)
// TrustService provides trust metrics and data quality services
type TrustService struct {
trustRepo domain.TrustMetricsRepository
verifiedRepo *repository.VerifiedDataRepository
historicalRepo *repository.HistoricalSuccessRepository
}
// GetTrustRepository returns the trust metrics repository (for internal use)
func (s *TrustService) GetTrustRepository() domain.TrustMetricsRepository {
return s.trustRepo
}
// NewTrustService creates a new trust service
func NewTrustService(
trustRepo domain.TrustMetricsRepository,
verifiedRepo *repository.VerifiedDataRepository,
historicalRepo *repository.HistoricalSuccessRepository,
) *TrustService {
return &TrustService{
trustRepo: trustRepo,
verifiedRepo: verifiedRepo,
historicalRepo: historicalRepo,
}
}
// AssessDataQuality performs comprehensive data quality assessment for an organization
func (s *TrustService) AssessDataQuality(ctx context.Context, orgID string) (*domain.DataQualityProfile, error) {
profile, err := s.trustRepo.GetLatestProfile(ctx, orgID)
if err != nil {
return nil, fmt.Errorf("failed to get quality profile: %w", err)
}
// Enhance profile with additional calculations
profile.Timeliness = s.calculateTimelinessScore(profile)
profile.Consistency = s.calculateConsistencyScore(profile)
// Recalculate overall score with all components
profile.OverallScore = (profile.Completeness*0.3 + profile.Accuracy*0.3 +
profile.Timeliness*0.2 + profile.Consistency*0.2)
return profile, nil
}
// CalculateTrustScore calculates comprehensive trust score for an organization
func (s *TrustService) CalculateTrustScore(ctx context.Context, orgID string) (*domain.TrustScore, error) {
return s.historicalRepo.CalculateTrustScore(ctx, orgID)
}
// UpdateTrustMetrics updates trust metrics for an organization
func (s *TrustService) UpdateTrustMetrics(ctx context.Context, orgID string, metrics []*domain.TrustMetrics) error {
for _, metric := range metrics {
metric.OrganizationID = orgID
metric.LastUpdated = time.Now()
// Calculate score based on value
metric.Score = s.calculateScoreCategory(metric.Value)
if err := s.trustRepo.Create(ctx, metric); err != nil {
return fmt.Errorf("failed to create trust metric: %w", err)
}
}
return nil
}
// SubmitForVerification submits data for verification
func (s *TrustService) SubmitForVerification(ctx context.Context, verifiedData *domain.VerifiedData) error {
verifiedData.Status = domain.VerificationPending
return s.verifiedRepo.Create(ctx, verifiedData)
}
// VerifyData marks data as verified
func (s *TrustService) VerifyData(ctx context.Context, dataID string, verifiedBy string, notes string) error {
// Get existing verified data
existing, err := s.verifiedRepo.GetByID(ctx, dataID)
if err != nil {
return fmt.Errorf("failed to get verified data: %w", err)
}
// Update verification status
now := time.Now()
existing.Status = domain.VerificationVerified
existing.VerifiedBy = verifiedBy
existing.VerifiedAt = &now
existing.Notes = notes
existing.ExpiresAt = &time.Time{} // Set expiration if needed
return s.verifiedRepo.Update(ctx, existing)
}
// RecordHistoricalSuccess records historical success metrics
func (s *TrustService) RecordHistoricalSuccess(ctx context.Context, success *domain.HistoricalSuccess) error {
success.RecordedAt = time.Now()
return s.historicalRepo.Create(ctx, success)
}
// GetTrustDashboard returns trust dashboard data for an organization
func (s *TrustService) GetTrustDashboard(ctx context.Context, orgID string) (*TrustDashboard, error) {
// Get trust score
trustScore, err := s.CalculateTrustScore(ctx, orgID)
if err != nil {
return nil, fmt.Errorf("failed to calculate trust score: %w", err)
}
// Get quality profile
qualityProfile, err := s.AssessDataQuality(ctx, orgID)
if err != nil {
return nil, fmt.Errorf("failed to assess data quality: %w", err)
}
// Get recent historical metrics
historical, err := s.historicalRepo.GetByOrganization(ctx, orgID)
if err != nil {
return nil, fmt.Errorf("failed to get historical metrics: %w", err)
}
// Get verification status
verifiedData, err := s.verifiedRepo.GetByOrganization(ctx, orgID)
if err != nil {
return nil, fmt.Errorf("failed to get verified data: %w", err)
}
dashboard := &TrustDashboard{
OrganizationID: orgID,
TrustScore: trustScore,
QualityProfile: qualityProfile,
HistoricalMetrics: historical,
VerifiedData: verifiedData,
LastUpdated: time.Now(),
}
return dashboard, nil
}
// calculateTimelinessScore calculates how timely the data is
func (s *TrustService) calculateTimelinessScore(profile *domain.DataQualityProfile) float64 {
// Check how recent the metrics are
daysSinceAssessment := time.Since(profile.LastAssessed).Hours() / 24
// Score decreases with age
if daysSinceAssessment < 30 {
return 0.9
} else if daysSinceAssessment < 90 {
return 0.7
} else if daysSinceAssessment < 180 {
return 0.5
} else {
return 0.3
}
}
// calculateConsistencyScore calculates data consistency
func (s *TrustService) calculateConsistencyScore(profile *domain.DataQualityProfile) float64 {
// Check for conflicting or inconsistent metrics
// This is a simplified implementation
if len(profile.Metrics) < 3 {
return 0.5 // Not enough data to assess consistency
}
// Look for metrics with similar names but different values
metricGroups := make(map[string][]float64)
for _, metric := range profile.Metrics {
metricGroups[metric.MetricName] = append(metricGroups[metric.MetricName], metric.Value)
}
// Check variance within groups
consistentGroups := 0
totalGroups := len(metricGroups)
for _, values := range metricGroups {
if len(values) > 1 {
// Calculate simple variance
avg := 0.0
for _, v := range values {
avg += v
}
avg /= float64(len(values))
variance := 0.0
for _, v := range values {
diff := v - avg
variance += diff * diff
}
variance /= float64(len(values))
// Low variance indicates consistency
if variance < 0.1 { // Threshold for consistency
consistentGroups++
}
} else {
consistentGroups++ // Single value is consistent by definition
}
}
if totalGroups == 0 {
return 0.5
}
return float64(consistentGroups) / float64(totalGroups)
}
// calculateScoreCategory converts numeric score to category
func (s *TrustService) calculateScoreCategory(value float64) string {
switch {
case value >= 0.9:
return "excellent"
case value >= 0.8:
return "good"
case value >= 0.6:
return "fair"
default:
return "poor"
}
}
// TrustDashboard represents comprehensive trust dashboard data
type TrustDashboard struct {
OrganizationID string `json:"organization_id"`
TrustScore *domain.TrustScore `json:"trust_score"`
QualityProfile *domain.DataQualityProfile `json:"quality_profile"`
HistoricalMetrics []*domain.HistoricalSuccess `json:"historical_metrics"`
VerifiedData []*domain.VerifiedData `json:"verified_data"`
LastUpdated time.Time `json:"last_updated"`
}