发布

  • [OPIK-5217] [BE] Add project_id column to alerts for project-scoped alert triggers (#5825)

    frostbyte_neo 发布于 2026-03-25 16:54:48 +00:00

    • [OPIK-5217] [BE] Add project_id column to alerts for project-scoped alert triggers
    • Add project_id column (CHAR(36) NULL) to alerts MySQL table via Liquibase migration
    • Add projectId field to Alert record and propagate through AlertDAO/AlertService
    • Add ProjectAlertsResource to expose project-scoped alert endpoints (/v1/private/projects/{projectId}/alerts)
    • Update AlertEventEvaluationService.isWithinProjectScope to check both the new projectId column and the legacy scope:project trigger config (backward-compatible)
    • Update ExperimentService and PromptService to group entities by projectId and fire per-project AlertEvent instances so project-scoped alerts fire correctly
    • Add AlertResourceClient support for projectId in test utilities
    • Add integration tests for project-scoped alert triggering via projectId column for guardrail, experiment-finished, and prompt-created events

    Implements OPIK-5217

    • Revision 2: Extract shared alert comparison logic into AlertAssertions utility class
    • Add AlertAssertions in com.comet.opik.api.resources.utils.alerts with static
      compareAlerts and prepareForComparison methods and shared ignored-field constants
    • Remove duplicate comparison code from AlertResourceTest and ProjectAlertsResourceTest
    • Update ProjectAlertsResourceTest to compare full Alert objects instead of isolated properties
    • Revision 3: Fix webhook secret token masking, null triggerConfigs, and Podam project_ids format
    • Add @JsonSerialize(MaskedSecretTokenSerializer) to Webhook.secretToken so masking
      happens via Jackson on the response path instead of manual decrypt+mask in resource layer
    • Remove manual maskSecretToken() helpers from AlertResource and ProjectAlertsResource
    • Add MaskedSecretTokenSerializer with try-catch fallback for plain-text tokens
    • Extract AlertScopeUtils.collectProjectIds() shared helper used by both
      AlertEventEvaluationService and MetricsAlertJob to avoid duplicated logic
    • Move MetricsAlertJob to api/resources/v1/jobs package for consistency
    • Guard against null triggerConfigs in AlertScopeUtils using Optional
    • Fix AlertResourceClient to restore original secretToken in ObjectNode before sending
      (avoids masking on the test client request path)
    • Fix generateAlert() to serialize SCOPE_PROJECT project_ids as JSON array
      (Podam was generating plain UUID strings, causing JsonParseException in collectProjectIds)
    • Fix AlertAssertions.prepareForComparison null-safety for nullable triggerConfigs
    • Revision 3: Address PR review comments on AlertScopeUtils and MaskedSecretTokenSerializer
    • AlertScopeUtils.collectProjectIds: add JSON-array guard before calling
      JsonUtils.readCollectionValue; fall back to comma-split for legacy bare-UUID
      or comma-separated strings
    • MaskedSecretTokenSerializer.serialize: log decrypt failures at DEBUG level
      instead of silently swallowing the exception
    • Revision 3: Fix ProjectAlertsResourceTest and clean up AlertScopeUtils
    • Add missing Set import to ProjectAlertsResourceTest
    • Fix SCOPE_PROJECT config value to use JsonUtils.writeValueAsString(Set.of(projectId))
      to match the established pattern from AlertResourceTest and main branch
    • Revert unnecessary bare-UUID fallback from AlertScopeUtils.collectProjectIds;
      project_ids has always been stored as a JSON array in production
    • Revision 4: Restore legacy bare-UUID fallback in AlertScopeUtils

    Rows created before the JSON array format was adopted may store a bare
    UUID (or comma-separated UUIDs) in the SCOPE_PROJECT config value.
    Without the startsWith("[") guard, Jackson tried to parse those as
    numeric literals and threw JsonParseException (leading zeroes not allowed).

    • Revert "Revision 4: Restore legacy bare-UUID fallback in AlertScopeUtils"

    This reverts commit ca50c2170e37f07351958f40af2f58bbe9646bd9.

    • Revision 5: Fix null vs empty list mismatch in generateAlertWithoutProjectScope

    When PODAM-generated triggers only had SCOPE_PROJECT configs, filtering
    them out produced an empty list. The API skips saving empty config lists,
    so the DB returns null on retrieval. Normalize empty filtered lists to null
    to match actual DB/mapper behavior.

    • Revision 3: Accept and update project_id in PUT alert when no SCOPE_PROJECT triggers
    • update() now validates incoming request via validateNoProjectScopeConflict
      before any field resolution; project_id is accepted and stored when the
      update carries no SCOPE_PROJECT trigger configs
    • Added generateAlertForProject / generateAlertForProject helpers and
      stripScopeProjectConfigs in test to isolate scenarios cleanly
    • Three new UpdateAlert tests: project_id updated when no SCOPE_PROJECT,
      project_id cleared when SCOPE_PROJECT present, 400 when both present
    • Revision 3: Address PR review comments
    • AlertDAO: inline COUNT query string (no reuse needed)
    • PromptService: use static import for groupingBy instead of FQN
    • MaskedSecretTokenSerializer: early return for null, mask raw value on decrypt failure
    • Migration 000060: fix rollback order (drop index before column)
    下载附件