diff --git a/server/cmd/server/router.go b/server/cmd/server/router.go index fcfcdf52d..147db5049 100644 --- a/server/cmd/server/router.go +++ b/server/cmd/server/router.go @@ -155,6 +155,7 @@ func NewRouterWithOptions(pool *pgxpool.Pool, hub *realtime.Hub, bus *events.Bus h := handler.New(queries, pool, hub, bus, emailSvc, store, cfSigner, analyticsClient, signupConfig, daemonHub) h.Metrics = opts.BusinessMetrics h.TaskService.Metrics = opts.BusinessMetrics + h.IssueService.Metrics = opts.BusinessMetrics if opts.BusinessMetrics != nil { // Wire the BusinessMetrics receiver into the cloud runtime client // so every outbound Fleet/Gateway request feeds the diff --git a/server/internal/service/issue.go b/server/internal/service/issue.go index ba9c50fca..a18a0badc 100644 --- a/server/internal/service/issue.go +++ b/server/internal/service/issue.go @@ -11,6 +11,7 @@ import ( "github.com/multica-ai/multica/server/internal/events" "github.com/multica-ai/multica/server/internal/issueguard" "github.com/multica-ai/multica/server/internal/issueposition" + obsmetrics "github.com/multica-ai/multica/server/internal/metrics" "github.com/multica-ai/multica/server/internal/util" db "github.com/multica-ai/multica/server/pkg/db/generated" "github.com/multica-ai/multica/server/pkg/protocol" @@ -23,10 +24,15 @@ import ( // service deliberately does NOT depend on http.Request — callers parse // their own transport and pass a fully-resolved IssueCreateParams. type IssueService struct { - Queries *db.Queries - TxStarter TxStarter - Bus *events.Bus - Analytics analytics.Client + Queries *db.Queries + TxStarter TxStarter + Bus *events.Bus + Analytics analytics.Client + // Metrics is the shared business-metrics collector. Wired by + // cmd/server/router.go after construction; nil in tests / self-hosted + // without the metrics listener — obsmetrics.RecordEvent treats a nil + // Metrics as "PostHog only", so leaving it unset is safe. + Metrics *obsmetrics.BusinessMetrics TaskService *TaskService } @@ -338,7 +344,7 @@ func (s *IssueService) captureCreatedAnalytics(issue db.Issue, creatorType, acto if creatorType == "agent" { analyticsActorID = "agent:" + actorID } - s.Analytics.Capture(analytics.IssueCreated( + obsmetrics.RecordEvent(s.Analytics, s.Metrics, analytics.IssueCreated( analyticsActorID, util.UUIDToString(issue.WorkspaceID), util.UUIDToString(issue.ID),