feat(monitoring): generate daily tasks and optimize heartbeat writes

Adds a MonitoringDailyTaskWorker that materializes and dispatches
daily collect tasks from active subscription/desktop-client state,
with per-run atomic metrics and a Prometheus collector. Dashboard
and question-detail APIs now surface a platform_authorization_status
so the UI can distinguish no-desktop-client, no-authorized-platforms,
and authorized states; quota/access-state lookups resolve by request
workspace instead of tenant.

Hardens heartbeat: a desktop_client_primary_leases table gives
per-(tenant, workspace) sticky primary selection, read-mostly lease
resolution avoids a per-heartbeat transaction, and unchanged platform
access reports skip snapshot upserts outside a 10-minute refresh
window. Adds heartbeat primary/snapshot metrics exposed via
token-protected tenant-api /api/internal/metrics endpoints plus
Prometheus. Monitoring quota seed is removed from dev-seed since
daily plans now derive from desktop bindings, and the projection
uses the canonical six-platform catalog so platforms with zero
samples still render.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-24 22:19:57 +08:00
parent ffe4d335aa
commit ff86933c24
26 changed files with 3546 additions and 277 deletions
+248 -99
View File
@@ -30,6 +30,10 @@ const (
monitoringCollectorType = "desktop"
monitoringOnlineDuration = 20 * time.Minute
monitoringCollectNowQuestionLimit = 5
monitoringPlatformAuthorizationAuthorized = "authorized"
monitoringPlatformAuthorizationNoDesktopClient = "no_desktop_client"
monitoringPlatformAuthorizationNoAuthorizedPlatforms = "no_authorized_platforms"
)
type MonitoringService struct {
@@ -38,12 +42,14 @@ type MonitoringService struct {
rabbitMQ *rabbitmq.Client
logger *zap.Logger
desktopTasksRolloutPercentage int
brandLibraryConfig config.BrandLibraryConfig
}
func NewMonitoringService(
businessPool, monitoringPool *pgxpool.Pool,
rabbitMQClient *rabbitmq.Client,
dispatchCfg config.MonitoringDispatchConfig,
brandLibraryCfg config.BrandLibraryConfig,
logger *zap.Logger,
) *MonitoringService {
return &MonitoringService{
@@ -52,6 +58,7 @@ func NewMonitoringService(
rabbitMQ: rabbitMQClient,
logger: logger,
desktopTasksRolloutPercentage: dispatchCfg.DesktopTasksRolloutPercentage,
brandLibraryConfig: brandLibraryCfg,
}
}
@@ -65,7 +72,10 @@ type MonitoringDashboardCompositeResponse struct {
}
type MonitoringDashboardRuntime struct {
CurrentUserClientOnline bool `json:"current_user_client_online"`
CurrentUserClientOnline bool `json:"current_user_client_online"`
PlatformAuthorizationStatus string `json:"platform_authorization_status"`
AuthorizedMonitoringPlatformIDs []string `json:"authorized_monitoring_platform_ids"`
AuthorizedMonitoringPlatformCount int `json:"authorized_monitoring_platform_count"`
}
type MonitoringOverview struct {
@@ -124,13 +134,14 @@ type MonitoringCitedArticle struct {
}
type MonitoringQuestionDetailResponse struct {
QuestionID int64 `json:"question_id"`
QuestionHash string `json:"question_hash"`
QuestionText string `json:"question_text"`
TimeWindow MonitoringQuestionDetailTimeWindow `json:"time_window"`
Platforms []MonitoringQuestionDetailPlatform `json:"platforms"`
CitationAnalysis []MonitoringQuestionCitationStats `json:"citation_analysis"`
ContentCitations []MonitoringQuestionContentCitation `json:"content_citations"`
QuestionID int64 `json:"question_id"`
QuestionHash string `json:"question_hash"`
QuestionText string `json:"question_text"`
PlatformAuthorizationStatus string `json:"platform_authorization_status"`
TimeWindow MonitoringQuestionDetailTimeWindow `json:"time_window"`
Platforms []MonitoringQuestionDetailPlatform `json:"platforms"`
CitationAnalysis []MonitoringQuestionCitationStats `json:"citation_analysis"`
ContentCitations []MonitoringQuestionContentCitation `json:"content_citations"`
}
type MonitoringQuestionDetailTimeWindow struct {
@@ -216,6 +227,16 @@ type monitoringQuotaConfig struct {
EnabledPlatforms []string
}
func monitoringPlatformAuthorizationStatus(quota monitoringQuotaConfig) string {
if quota.PrimaryClientID == nil {
return monitoringPlatformAuthorizationNoDesktopClient
}
if len(quota.EnabledPlatforms) == 0 {
return monitoringPlatformAuthorizationNoAuthorizedPlatforms
}
return monitoringPlatformAuthorizationAuthorized
}
type monitoringBrandIdentity struct {
ID int64
Name string
@@ -290,6 +311,7 @@ func (s *MonitoringService) DashboardComposite(
aiPlatformID *string,
) (*MonitoringDashboardCompositeResponse, error) {
actor := auth.MustActor(ctx)
workspaceID := auth.CurrentWorkspaceID(ctx)
brand, err := s.resolveBrand(ctx, actor.TenantID, brandID)
if err != nil {
@@ -302,12 +324,12 @@ func (s *MonitoringService) DashboardComposite(
}
}
quota, err := s.loadQuota(ctx, actor.TenantID)
quota, err := s.loadQuota(ctx, actor, workspaceID)
if err != nil {
return nil, err
}
runtime, err := s.loadDashboardRuntime(ctx, actor)
runtime, err := s.loadDashboardRuntime(ctx, actor, workspaceID, quota)
if err != nil {
return nil, err
}
@@ -318,7 +340,7 @@ func (s *MonitoringService) DashboardComposite(
}
questionIDs := configuredQuestionIDs(configuredQuestions)
platforms := resolveMonitoringPlatforms(quota.EnabledPlatforms)
platforms := defaultMonitoringPlatformMetadata()
selectedPlatformID := normalizedOptionalMonitoringPlatformPointer(aiPlatformID)
filteredPlatforms := filterMonitoringPlatforms(platforms, selectedPlatformID)
startDate, endDate, err := resolveDashboardDateWindow(days, businessDate)
@@ -334,7 +356,7 @@ func (s *MonitoringService) DashboardComposite(
return nil, err
}
accessStates, err := s.loadAccessStates(ctx, actor.TenantID, quota.PrimaryClientID, endDate)
accessStates, err := s.loadAccessStates(ctx, actor.TenantID, workspaceID, quota.PrimaryClientID, endDate)
if err != nil {
return nil, err
}
@@ -369,19 +391,27 @@ func (s *MonitoringService) DashboardComposite(
}, nil
}
func (s *MonitoringService) loadDashboardRuntime(ctx context.Context, actor auth.Actor) (MonitoringDashboardRuntime, error) {
online, err := s.hasOnlineClientForUser(ctx, actor.TenantID, actor.PrimaryWorkspaceID, actor.UserID)
if err != nil {
return MonitoringDashboardRuntime{}, err
func (s *MonitoringService) loadDashboardRuntime(ctx context.Context, actor auth.Actor, workspaceID int64, quota monitoringQuotaConfig) (MonitoringDashboardRuntime, error) {
online := false
if quota.PrimaryClientID != nil {
var err error
online, err = s.isClientOnline(ctx, actor.TenantID, workspaceID, *quota.PrimaryClientID)
if err != nil {
return MonitoringDashboardRuntime{}, err
}
}
return MonitoringDashboardRuntime{
CurrentUserClientOnline: online,
CurrentUserClientOnline: online,
PlatformAuthorizationStatus: monitoringPlatformAuthorizationStatus(quota),
AuthorizedMonitoringPlatformIDs: append([]string(nil), quota.EnabledPlatforms...),
AuthorizedMonitoringPlatformCount: len(quota.EnabledPlatforms),
}, nil
}
func (s *MonitoringService) QuestionDetail(ctx context.Context, brandID, questionID int64, dateFrom, dateTo string, questionHash string, aiPlatformID *string) (*MonitoringQuestionDetailResponse, error) {
actor := auth.MustActor(ctx)
workspaceID := auth.CurrentWorkspaceID(ctx)
brand, err := s.resolveBrand(ctx, actor.TenantID, brandID)
if err != nil {
@@ -393,12 +423,12 @@ func (s *MonitoringService) QuestionDetail(ctx context.Context, brandID, questio
return nil, err
}
quota, err := s.loadQuota(ctx, actor.TenantID)
quota, err := s.loadQuota(ctx, actor, workspaceID)
if err != nil {
return nil, err
}
platforms := resolveMonitoringPlatforms(quota.EnabledPlatforms)
selectedPlatformID := normalizedOptionalMonitoringPlatformPointer(aiPlatformID)
platforms := filterMonitoringPlatforms(defaultMonitoringPlatformMetadata(), selectedPlatformID)
questionText, err := s.loadQuestionText(ctx, actor.TenantID, brand.ID, questionID)
if err != nil {
@@ -418,7 +448,7 @@ func (s *MonitoringService) QuestionDetail(ctx context.Context, brandID, questio
}
}
accessStates, err := s.loadAccessStates(ctx, actor.TenantID, quota.PrimaryClientID, toDate)
accessStates, err := s.loadAccessStates(ctx, actor.TenantID, workspaceID, quota.PrimaryClientID, toDate)
if err != nil {
return nil, err
}
@@ -481,9 +511,10 @@ func (s *MonitoringService) QuestionDetail(ctx context.Context, brandID, questio
}
return &MonitoringQuestionDetailResponse{
QuestionID: questionID,
QuestionHash: encodeQuestionHash(hashBytes),
QuestionText: questionText,
QuestionID: questionID,
QuestionHash: encodeQuestionHash(hashBytes),
QuestionText: questionText,
PlatformAuthorizationStatus: monitoringPlatformAuthorizationStatus(quota),
TimeWindow: MonitoringQuestionDetailTimeWindow{
DateFrom: fromDate.Format("2006-01-02"),
DateTo: toDate.Format("2006-01-02"),
@@ -501,6 +532,7 @@ func (s *MonitoringService) CollectNow(
options MonitoringCollectNowOptions,
) (*MonitoringCollectNowResponse, error) {
actor := auth.MustActor(ctx)
workspaceID := auth.CurrentWorkspaceID(ctx)
brand, err := s.resolveBrand(ctx, actor.TenantID, brandID)
if err != nil {
@@ -513,7 +545,7 @@ func (s *MonitoringService) CollectNow(
}
}
quota, err := s.loadQuota(ctx, actor.TenantID)
quota, err := s.loadQuota(ctx, actor, workspaceID)
if err != nil {
return nil, err
}
@@ -540,19 +572,7 @@ func (s *MonitoringService) CollectNow(
}, nil
}
platforms := resolveMonitoringPlatforms(quota.EnabledPlatforms)
platforms, err = intersectMonitoringPlatforms(platforms, options.PlatformIDs)
if err != nil {
return nil, err
}
questionIDs := configuredQuestionIDs(configuredQuestions)
platformIDs := monitoringPlatformIDs(platforms)
executionOwner := "legacy"
if s.shouldUseDesktopTasksExecution(actor.TenantID) {
executionOwner = "desktop_tasks"
}
clientID, err := s.resolveCollectNowClientID(ctx, actor.TenantID, actor.PrimaryWorkspaceID, actor.UserID, options.TargetClientID)
clientID, err := s.resolveCollectNowClientID(ctx, actor.TenantID, workspaceID, actor.UserID, quota.PrimaryClientID, options.TargetClientID)
if err != nil {
return nil, err
}
@@ -560,10 +580,37 @@ func (s *MonitoringService) CollectNow(
return nil, response.ErrConflict(40941, "desktop_client_offline", "current user's monitoring desktop client is offline")
}
if err := s.ensureClientOnline(ctx, actor.TenantID, actor.PrimaryWorkspaceID, *clientID); err != nil {
if err := s.ensureClientOnline(ctx, actor.TenantID, workspaceID, *clientID); err != nil {
return nil, err
}
targetPlatformIDs, err := s.loadMonitoringClientPlatformIDs(ctx, actor.TenantID, workspaceID, *clientID)
if err != nil {
return nil, err
}
platforms := resolveMonitoringPlatforms(targetPlatformIDs)
platforms, err = intersectMonitoringPlatforms(platforms, options.PlatformIDs)
if err != nil {
return nil, err
}
if len(platforms) == 0 {
return &MonitoringCollectNowResponse{
CollectionMode: quota.CollectionMode,
RefreshedTaskCount: 0,
CreatedTaskCount: 0,
LeasedTaskCount: 0,
CompletedTaskCount: 0,
HasEffectiveSnapshot: true,
Message: "当前桌面端暂无已授权的 AI 平台,未创建采集任务",
}, nil
}
questionIDs := configuredQuestionIDs(configuredQuestions)
platformIDs := monitoringPlatformIDs(platforms)
executionOwner := "legacy"
if s.shouldUseDesktopTasksExecution(actor.TenantID) {
executionOwner = "desktop_tasks"
}
now := time.Now().UTC()
todayTime, _ := monitoringBusinessDayAndDateAt(now)
requestID := uuid.New()
@@ -584,7 +631,7 @@ func (s *MonitoringService) CollectNow(
ctx,
tx,
actor.TenantID,
actor.PrimaryWorkspaceID,
workspaceID,
brand.ID,
actor.UserID,
scopeHash,
@@ -663,7 +710,7 @@ func (s *MonitoringService) CollectNow(
ctx,
tx,
actor.TenantID,
actor.PrimaryWorkspaceID,
workspaceID,
todayTime,
questionIDs,
platformIDs,
@@ -722,7 +769,7 @@ func (s *MonitoringService) CollectNow(
$12, $13, $14,
$15, $16
)
`, requestID, actor.TenantID, actor.PrimaryWorkspaceID, brand.ID, nullableInt64(keywordID), actor.UserID, *clientID, scopeHash, requestScopeJSON, affectedTaskCount, affectedTaskCount, abortedQueuedCount, int64(len(interruptTaskIDs)), interruptGeneration, message, ttlExpiresAt); err != nil {
`, requestID, actor.TenantID, workspaceID, brand.ID, nullableInt64(keywordID), actor.UserID, *clientID, scopeHash, requestScopeJSON, affectedTaskCount, affectedTaskCount, abortedQueuedCount, int64(len(interruptTaskIDs)), interruptGeneration, message, ttlExpiresAt); err != nil {
return nil, response.ErrInternal(50041, "request_create_failed", "failed to persist monitoring collect-now request")
}
@@ -730,7 +777,7 @@ func (s *MonitoringService) CollectNow(
ctx,
tx,
requestID,
actor.PrimaryWorkspaceID,
workspaceID,
*clientID,
affectedTaskCount,
interruptGeneration,
@@ -748,8 +795,6 @@ func (s *MonitoringService) CollectNow(
return nil, response.ErrInternal(50041, "commit_failed", "failed to commit monitoring collect-now")
}
_ = s.persistPrimaryClientID(ctx, actor.TenantID, actor.PrimaryWorkspaceID, *clientID)
phase2PublishedTasks := make([]*repository.DesktopTask, 0)
phase2DispatchReady := executionOwner == "desktop_tasks"
if len(phase2TaskSpecs) > 0 {
@@ -877,6 +922,7 @@ func (s *MonitoringService) CollectNow(
func (s *MonitoringService) resolveCollectNowClientID(
ctx context.Context,
tenantID, workspaceID, userID int64,
defaultClientID *uuid.UUID,
preferredClientID *uuid.UUID,
) (*uuid.UUID, error) {
if preferredClientID != nil {
@@ -885,7 +931,7 @@ func (s *MonitoringService) resolveCollectNowClientID(
}
return preferredClientID, nil
}
return s.findLatestOnlineClientForUser(ctx, tenantID, workspaceID, userID)
return defaultClientID, nil
}
func (s *MonitoringService) hasOnlineClientForUser(ctx context.Context, tenantID, workspaceID, userID int64) (bool, error) {
@@ -968,6 +1014,10 @@ func monitoringPlatformIDs(items []monitoringPlatformMetadata) []string {
return result
}
func defaultMonitoringPlatformMetadata() []monitoringPlatformMetadata {
return append([]monitoringPlatformMetadata(nil), defaultMonitoringPlatforms...)
}
func normalizeMonitoringPlatformID(platformID string) string {
return strings.ToLower(strings.TrimSpace(platformID))
}
@@ -996,10 +1046,30 @@ func monitoringPlatformQueryIDs(value *string) []string {
}
func reconcileEnabledMonitoringPlatforms(enabled []string) []string {
// Old quota rows may still contain partial or aliased platform ids. Admin monitoring
// should always expose the full canonical desktop-supported set for the tenant.
_ = enabled
return monitoringPlatformIDs(defaultMonitoringPlatforms)
if len(enabled) == 0 {
return nil
}
requested := make(map[string]struct{}, len(enabled))
for _, item := range enabled {
id := normalizeMonitoringPlatformID(item)
if id == "" {
continue
}
if _, supported := monitoringPlatformNames[id]; !supported {
continue
}
requested[id] = struct{}{}
}
if len(requested) == 0 {
return nil
}
result := make([]string, 0, len(requested))
for _, platform := range defaultMonitoringPlatforms {
if _, ok := requested[platform.ID]; ok {
result = append(result, platform.ID)
}
}
return result
}
func monitoringPlatformSortIndex(platformID string) int {
@@ -1054,26 +1124,6 @@ func (s *MonitoringService) findLatestOnlineClientForUser(ctx context.Context, t
return &clientID, nil
}
func (s *MonitoringService) persistPrimaryClientID(ctx context.Context, tenantID, workspaceID int64, clientID uuid.UUID) error {
if _, err := s.businessPool.Exec(ctx, `
INSERT INTO tenant_monitoring_quotas (
tenant_id, workspace_id, primary_client_id
)
VALUES (
$1,
$2,
$3
)
ON CONFLICT (tenant_id) DO UPDATE
SET workspace_id = EXCLUDED.workspace_id,
primary_client_id = EXCLUDED.primary_client_id,
updated_at = NOW()
`, tenantID, workspaceID, clientID); err != nil {
return response.ErrInternal(50041, "update_failed", "failed to persist primary monitoring desktop client")
}
return nil
}
func formatPgInterval(duration time.Duration) string {
return fmt.Sprintf("%d seconds", int64(duration/time.Second))
}
@@ -1431,40 +1481,117 @@ func (s *MonitoringService) deferQueuedNormalTasks(
return tag.RowsAffected(), nil
}
func (s *MonitoringService) loadQuota(ctx context.Context, tenantID int64) (monitoringQuotaConfig, error) {
func (s *MonitoringService) loadQuota(ctx context.Context, actor auth.Actor, workspaceID int64) (monitoringQuotaConfig, error) {
cfg := monitoringQuotaConfig{
CollectionMode: monitoringCollectorType,
EnabledPlatforms: reconcileEnabledMonitoringPlatforms(nil),
CollectionMode: monitoringCollectorType,
}
var enabledJSON []byte
var clientID uuid.NullUUID
clientID, err := s.findLatestRegisteredClientWithMonitoringAccountForUser(ctx, actor.TenantID, workspaceID, actor.UserID)
if err != nil {
return cfg, err
}
if clientID == nil {
clientID, err = s.findLatestRegisteredClientForUser(ctx, actor.TenantID, workspaceID, actor.UserID)
if err != nil {
return cfg, err
}
}
cfg.PrimaryClientID = clientID
if clientID == nil {
return cfg, nil
}
platforms, err := s.loadMonitoringClientPlatformIDs(ctx, actor.TenantID, workspaceID, *clientID)
if err != nil {
return cfg, err
}
cfg.EnabledPlatforms = platforms
return cfg, nil
}
// findLatestRegisteredClientWithMonitoringAccountForUser returns the newest
// non-revoked desktop client that has at least one bound monitoring platform
// account. Platform account health is not authorization.
func (s *MonitoringService) findLatestRegisteredClientWithMonitoringAccountForUser(ctx context.Context, tenantID, workspaceID, userID int64) (*uuid.UUID, error) {
var clientID uuid.UUID
err := s.businessPool.QueryRow(ctx, `
SELECT collection_mode, enabled_platforms, primary_client_id
FROM tenant_monitoring_quotas
WHERE tenant_id = $1
`, tenantID).Scan(&cfg.CollectionMode, &enabledJSON, &clientID)
SELECT dc.id
FROM desktop_clients dc
WHERE dc.tenant_id = $1
AND dc.workspace_id = $2
AND dc.user_id = $3
AND dc.revoked_at IS NULL
AND EXISTS (
SELECT 1
FROM platform_accounts pa
WHERE pa.tenant_id = dc.tenant_id
AND pa.workspace_id = dc.workspace_id
AND pa.client_id = dc.id
AND pa.deleted_at IS NULL
AND pa.platform_id = ANY($4::text[])
)
ORDER BY dc.created_at DESC, dc.id DESC
LIMIT 1
`, tenantID, workspaceID, userID, monitoringPlatformIDs(defaultMonitoringPlatforms)).Scan(&clientID)
if err != nil {
if err == pgx.ErrNoRows {
return cfg, nil
return nil, nil
}
return cfg, response.ErrInternal(50041, "query_failed", "failed to load monitoring quota")
return nil, response.ErrInternal(50041, "query_failed", "failed to inspect monitoring desktop client authorization")
}
return &clientID, nil
}
if len(enabledJSON) > 0 {
var enabled []string
if jsonErr := json.Unmarshal(enabledJSON, &enabled); jsonErr == nil {
cfg.EnabledPlatforms = reconcileEnabledMonitoringPlatforms(enabled)
// findLatestRegisteredClientForUser returns the newest non-revoked desktop client
// registered by creation order. It intentionally ignores last_seen_at and health;
// use findLatestOnlineClientForUser when online presence is required.
func (s *MonitoringService) findLatestRegisteredClientForUser(ctx context.Context, tenantID, workspaceID, userID int64) (*uuid.UUID, error) {
var clientID uuid.UUID
err := s.businessPool.QueryRow(ctx, `
SELECT id
FROM desktop_clients
WHERE tenant_id = $1
AND workspace_id = $2
AND user_id = $3
AND revoked_at IS NULL
ORDER BY created_at DESC, id DESC
LIMIT 1
`, tenantID, workspaceID, userID).Scan(&clientID)
if err != nil {
if err == pgx.ErrNoRows {
return nil, nil
}
return nil, response.ErrInternal(50041, "query_failed", "failed to inspect monitoring desktop client")
}
if clientID.Valid {
id := clientID.UUID
cfg.PrimaryClientID = &id
return &clientID, nil
}
func (s *MonitoringService) loadMonitoringClientPlatformIDs(ctx context.Context, tenantID, workspaceID int64, clientID uuid.UUID) ([]string, error) {
rows, err := s.businessPool.Query(ctx, `
SELECT DISTINCT platform_id
FROM platform_accounts
WHERE tenant_id = $1
AND workspace_id = $2
AND client_id = $3
AND deleted_at IS NULL
AND platform_id = ANY($4::text[])
`, tenantID, workspaceID, clientID, monitoringPlatformIDs(defaultMonitoringPlatforms))
if err != nil {
return nil, response.ErrInternal(50041, "query_failed", "failed to load monitoring desktop platform accounts")
}
if strings.TrimSpace(cfg.CollectionMode) == "" {
cfg.CollectionMode = monitoringCollectorType
defer rows.Close()
platformIDs := make([]string, 0)
for rows.Next() {
var platformID string
if scanErr := rows.Scan(&platformID); scanErr != nil {
return nil, response.ErrInternal(50041, "scan_failed", "failed to parse monitoring desktop platform accounts")
}
platformIDs = append(platformIDs, platformID)
}
return cfg, nil
if err := rows.Err(); err != nil {
return nil, response.ErrInternal(50041, "scan_failed", "failed to iterate monitoring desktop platform accounts")
}
return reconcileEnabledMonitoringPlatforms(platformIDs), nil
}
func newMonitoringDerivedMetrics() monitoringDerivedMetrics {
@@ -2021,11 +2148,18 @@ func applyDerivedRatesToOverviewSnapshot(snapshot *monitoringOverviewSnapshot, d
}
}
func (s *MonitoringService) loadAccessStates(ctx context.Context, tenantID int64, clientID *uuid.UUID, businessDate time.Time) (map[string]monitoringAccessState, error) {
func (s *MonitoringService) loadAccessStates(ctx context.Context, tenantID, workspaceID int64, clientID *uuid.UUID, businessDate time.Time) (map[string]monitoringAccessState, error) {
states := map[string]monitoringAccessState{}
if clientID == nil {
return states, nil
}
belongs, err := s.monitoringClientBelongsToWorkspace(ctx, tenantID, workspaceID, *clientID)
if err != nil {
return nil, err
}
if !belongs {
return states, nil
}
rows, err := s.monitoringPool.Query(ctx, `
SELECT ai_platform_id, access_status
@@ -2054,10 +2188,30 @@ func (s *MonitoringService) loadAccessStates(ctx context.Context, tenantID int64
}
states[platformID] = monitoringAccessState{AccessStatus: accessStatus}
}
if err := rows.Err(); err != nil {
return nil, response.ErrInternal(50041, "scan_failed", "failed to iterate platform access states")
}
return states, nil
}
func (s *MonitoringService) monitoringClientBelongsToWorkspace(ctx context.Context, tenantID, workspaceID int64, clientID uuid.UUID) (bool, error) {
var exists bool
if err := s.businessPool.QueryRow(ctx, `
SELECT EXISTS (
SELECT 1
FROM desktop_clients
WHERE id = $1
AND tenant_id = $2
AND workspace_id = $3
AND revoked_at IS NULL
)
`, clientID, tenantID, workspaceID).Scan(&exists); err != nil {
return false, response.ErrInternal(50041, "query_failed", "failed to validate monitoring desktop client workspace")
}
return exists, nil
}
func (s *MonitoringService) loadPlatformBreakdown(ctx context.Context, tenantID, brandID int64, businessDate time.Time, collectionMode string, platforms []monitoringPlatformMetadata, accessStates map[string]monitoringAccessState, derived monitoringDerivedMetrics) ([]MonitoringPlatformDaily, error) {
rows, err := s.monitoringPool.Query(ctx, `
SELECT
@@ -3117,7 +3271,7 @@ func normalizeTrackingDays(days int) int {
func resolveMonitoringPlatforms(enabled []string) []monitoringPlatformMetadata {
if len(enabled) == 0 {
return defaultMonitoringPlatforms
return nil
}
platforms := make([]monitoringPlatformMetadata, 0, len(enabled))
seen := make(map[string]struct{}, len(enabled))
@@ -3139,7 +3293,7 @@ func resolveMonitoringPlatforms(enabled []string) []monitoringPlatformMetadata {
})
}
if len(platforms) == 0 {
return defaultMonitoringPlatforms
return nil
}
return platforms
}
@@ -3192,12 +3346,7 @@ func filterMonitoringPlatforms(platforms []monitoringPlatformMetadata, aiPlatfor
}
}
return []monitoringPlatformMetadata{
{
ID: platformID,
Name: platformDisplayName(platformID),
},
}
return nil
}
func platformDisplayName(platformID string) string {