asyncapi: 2.6.0

info:
  title: Reports Service Async API
  version: 1.0.0
  description: |
    Kafka event specification for the EventZR Reports Service (reports-svc).

    The reports service publishes events related to the lifecycle of report generation
    jobs and consumes events from other services to trigger automatic report generation
    and cache invalidation.

    All events use the CloudEvents 1.0 specification with EventZR extension attributes
    (tenantid, correlationid, userid, causationid).

    **Outbox Pattern:** Published events use the transactional outbox pattern. Events
    are first written to the `outbox_reports` table within the business transaction,
    then published to Kafka asynchronously by a background worker (or DynamoDB Streams
    in Lambda environments).
  contact:
    name: Eventzr Platform Team
    url: https://eventzr.io
    email: platform@eventzr.io
  license:
    name: Proprietary
    url: https://eventzr.io/legal/license

servers:
  staging:
    url: b-1.eventzr-msk.staging.kafka.ap-south-1.amazonaws.com:9098
    protocol: kafka
    description: Amazon MSK Serverless (Staging)
  production:
    url: b-1.eventzr-msk.prod.kafka.ap-south-1.amazonaws.com:9098
    protocol: kafka
    description: Amazon MSK Serverless (Production)
  localhost:
    url: localhost:9092
    protocol: kafka
    description: Local development (Docker Compose)

defaultContentType: application/json

channels:
  # ==========================================================================
  # PUBLISHED CHANNELS (reports-svc produces)
  # ==========================================================================

  eventzr.reports.job.queued.v1:
    description: |
      Published when a new report export job is queued for processing.
      Partition key: jobId.
    publish:
      operationId: publishJobQueued
      summary: Report job queued
      message:
        $ref: '#/components/messages/ReportJobQueued'
      bindings:
        kafka:
          groupId: null
          clientId: reports-svc

  eventzr.reports.job.processing.v1:
    description: |
      Published when a report job transitions from queued to processing state.
      Includes progress percentage and estimated completion time.
      Partition key: jobId.
    publish:
      operationId: publishJobProcessing
      summary: Report job processing
      message:
        $ref: '#/components/messages/ReportJobProcessing'
      bindings:
        kafka:
          groupId: null
          clientId: reports-svc

  eventzr.reports.report.ready.v1:
    description: |
      Published when a report has been generated successfully and is ready for download.
      Contains the S3 location and optional pre-signed download URL.
      Partition key: jobId.
    publish:
      operationId: publishReportReady
      summary: Report ready for download
      message:
        $ref: '#/components/messages/ReportReady'
      bindings:
        kafka:
          groupId: null
          clientId: reports-svc

  eventzr.reports.report.failed.v1:
    description: |
      Published when a report generation job fails. Includes error details
      and retry information.
      Partition key: jobId.
    publish:
      operationId: publishReportFailed
      summary: Report generation failed
      message:
        $ref: '#/components/messages/ReportFailed'
      bindings:
        kafka:
          groupId: null
          clientId: reports-svc

  eventzr.reports.report.expired.v1:
    description: |
      Published when a generated report output expires and its S3 file
      is cleaned up. Includes download statistics.
      Partition key: jobId.
    publish:
      operationId: publishReportExpired
      summary: Report output expired
      message:
        $ref: '#/components/messages/ReportExpired'
      bindings:
        kafka:
          groupId: null
          clientId: reports-svc

  eventzr.reports.export.large.v1:
    description: |
      Published when a large export (exceeding 10,000 rows) starts processing.
      Notifies downstream services and users that the export may take longer.
      Partition key: jobId.
    publish:
      operationId: publishExportLarge
      summary: Large export started
      message:
        $ref: '#/components/messages/ReportExportLarge'
      bindings:
        kafka:
          groupId: null
          clientId: reports-svc

  # ==========================================================================
  # SUBSCRIBED CHANNELS (reports-svc consumes)
  # ==========================================================================

  eventzr.analytics.snapshot.created.v1:
    description: |
      Consumed from analytics-svc. Triggers cache invalidation and stores
      snapshot metadata for potential auto-report generation.
    subscribe:
      operationId: onAnalyticsSnapshotCreated
      summary: Analytics snapshot created
      message:
        $ref: '#/components/messages/AnalyticsSnapshotCreated'
      bindings:
        kafka:
          groupId: reports-svc-analytics
          clientId: reports-svc

  eventzr.analytics.snapshot.updated.v1:
    description: |
      Consumed from analytics-svc. Triggers cache invalidation and updates
      cached snapshot metadata.
    subscribe:
      operationId: onAnalyticsSnapshotUpdated
      summary: Analytics snapshot updated
      message:
        $ref: '#/components/messages/AnalyticsSnapshotUpdated'
      bindings:
        kafka:
          groupId: reports-svc-analytics
          clientId: reports-svc

  eventzr.studio.theme.updated.v1:
    description: |
      Consumed from studio-svc. Updates cached theme data used for report
      branding (colors, logos, fonts). Invalidates PDF template caches.
    subscribe:
      operationId: onStudioThemeUpdated
      summary: Studio theme updated
      message:
        $ref: '#/components/messages/StudioThemeUpdated'
      bindings:
        kafka:
          groupId: reports-svc-studio
          clientId: reports-svc

  eventzr.event.completed.v1:
    description: |
      Consumed from event-svc. When AUTO_REPORT_ON_EVENT_COMPLETE is enabled,
      automatically triggers an event summary report job.
    subscribe:
      operationId: onEventCompleted
      summary: Event completed
      message:
        $ref: '#/components/messages/EventCompleted'
      bindings:
        kafka:
          groupId: reports-svc-event
          clientId: reports-svc

  eventzr.campaign.completed.v1:
    description: |
      Consumed from campaign-svc. When AUTO_REPORT_ON_CAMPAIGN_COMPLETE is
      enabled, automatically triggers a campaign performance report job.
    subscribe:
      operationId: onCampaignCompleted
      summary: Campaign completed
      message:
        $ref: '#/components/messages/CampaignCompleted'
      bindings:
        kafka:
          groupId: reports-svc-campaign
          clientId: reports-svc

  eventzr.tour.leg.completed.v1:
    description: |
      Consumed from tour-svc. When AUTO_REPORT_ON_TOUR_COMPLETE is enabled
      and the completed leg is the final leg of the tour, automatically
      triggers a tour summary report job.
    subscribe:
      operationId: onTourLegCompleted
      summary: Tour leg completed
      message:
        $ref: '#/components/messages/TourLegCompleted'
      bindings:
        kafka:
          groupId: reports-svc-tour
          clientId: reports-svc

components:
  messages:
    # ========================================================================
    # PUBLISHED MESSAGES
    # ========================================================================

    ReportJobQueued:
      name: ReportJobQueued
      title: Report Job Queued
      summary: A new report export job has been queued for processing.
      contentType: application/json
      headers:
        type: object
        properties:
          ce-id:
            type: string
            description: CloudEvent ID (ULID)
          ce-type:
            type: string
            const: com.eventzr.reports.job.queued.v1
          ce-source:
            type: string
            const: com.eventzr.reports-svc
          ce-specversion:
            type: string
            const: '1.0'
          ce-tenantid:
            type: string
            format: uuid
      payload:
        $ref: '#/components/schemas/CloudEventJobQueued'

    ReportJobProcessing:
      name: ReportJobProcessing
      title: Report Job Processing
      summary: A report job has started processing.
      contentType: application/json
      headers:
        type: object
        properties:
          ce-id:
            type: string
          ce-type:
            type: string
            const: com.eventzr.reports.job.processing.v1
          ce-source:
            type: string
            const: com.eventzr.reports-svc
          ce-specversion:
            type: string
            const: '1.0'
          ce-tenantid:
            type: string
            format: uuid
      payload:
        $ref: '#/components/schemas/CloudEventJobProcessing'

    ReportReady:
      name: ReportReady
      title: Report Ready
      summary: A report has been generated and is ready for download.
      contentType: application/json
      headers:
        type: object
        properties:
          ce-id:
            type: string
          ce-type:
            type: string
            const: com.eventzr.reports.report.ready.v1
          ce-source:
            type: string
            const: com.eventzr.reports-svc
          ce-specversion:
            type: string
            const: '1.0'
          ce-tenantid:
            type: string
            format: uuid
      payload:
        $ref: '#/components/schemas/CloudEventReportReady'

    ReportFailed:
      name: ReportFailed
      title: Report Failed
      summary: A report generation job has failed.
      contentType: application/json
      headers:
        type: object
        properties:
          ce-id:
            type: string
          ce-type:
            type: string
            const: com.eventzr.reports.report.failed.v1
          ce-source:
            type: string
            const: com.eventzr.reports-svc
          ce-specversion:
            type: string
            const: '1.0'
          ce-tenantid:
            type: string
            format: uuid
      payload:
        $ref: '#/components/schemas/CloudEventReportFailed'

    ReportExpired:
      name: ReportExpired
      title: Report Expired
      summary: A generated report output has expired and been cleaned up.
      contentType: application/json
      headers:
        type: object
        properties:
          ce-id:
            type: string
          ce-type:
            type: string
            const: com.eventzr.reports.report.expired.v1
          ce-source:
            type: string
            const: com.eventzr.reports-svc
          ce-specversion:
            type: string
            const: '1.0'
          ce-tenantid:
            type: string
            format: uuid
      payload:
        $ref: '#/components/schemas/CloudEventReportExpired'

    ReportExportLarge:
      name: ReportExportLarge
      title: Large Export Started
      summary: A large report export (>10,000 rows) has started processing.
      contentType: application/json
      headers:
        type: object
        properties:
          ce-id:
            type: string
          ce-type:
            type: string
            const: com.eventzr.reports.export.large.v1
          ce-source:
            type: string
            const: com.eventzr.reports-svc
          ce-specversion:
            type: string
            const: '1.0'
          ce-tenantid:
            type: string
            format: uuid
      payload:
        $ref: '#/components/schemas/CloudEventExportLarge'

    # ========================================================================
    # CONSUMED MESSAGES
    # ========================================================================

    AnalyticsSnapshotCreated:
      name: AnalyticsSnapshotCreated
      title: Analytics Snapshot Created
      summary: An analytics snapshot has been created by analytics-svc.
      contentType: application/json
      payload:
        $ref: '#/components/schemas/CloudEventAnalyticsSnapshotCreated'

    AnalyticsSnapshotUpdated:
      name: AnalyticsSnapshotUpdated
      title: Analytics Snapshot Updated
      summary: An analytics snapshot has been updated by analytics-svc.
      contentType: application/json
      payload:
        $ref: '#/components/schemas/CloudEventAnalyticsSnapshotUpdated'

    StudioThemeUpdated:
      name: StudioThemeUpdated
      title: Studio Theme Updated
      summary: A theme has been updated in studio-svc.
      contentType: application/json
      payload:
        $ref: '#/components/schemas/CloudEventStudioThemeUpdated'

    EventCompleted:
      name: EventCompleted
      title: Event Completed
      summary: An event has been completed in event-svc.
      contentType: application/json
      payload:
        $ref: '#/components/schemas/CloudEventEventCompleted'

    CampaignCompleted:
      name: CampaignCompleted
      title: Campaign Completed
      summary: A campaign has been completed in campaign-svc.
      contentType: application/json
      payload:
        $ref: '#/components/schemas/CloudEventCampaignCompleted'

    TourLegCompleted:
      name: TourLegCompleted
      title: Tour Leg Completed
      summary: A tour leg has been completed in tour-svc.
      contentType: application/json
      payload:
        $ref: '#/components/schemas/CloudEventTourLegCompleted'

  schemas:
    # ========================================================================
    # CLOUDEVENT ENVELOPE SCHEMAS (PUBLISHED)
    # ========================================================================

    CloudEventJobQueued:
      type: object
      required:
        - id
        - source
        - specversion
        - type
        - time
        - tenantid
        - data
      properties:
        id:
          type: string
          description: Unique event identifier (ULID)
          example: 01HXYZ1234567890ABCDEF
        source:
          type: string
          const: com.eventzr.reports-svc
        specversion:
          type: string
          const: '1.0'
        type:
          type: string
          const: com.eventzr.reports.job.queued.v1
        datacontenttype:
          type: string
          const: application/json
        time:
          type: string
          format: date-time
        subject:
          type: string
          description: 'Format: job/{jobId}'
          example: job/01HXYZ1234567890ABCDEF
        tenantid:
          type: string
          format: uuid
        correlationid:
          type: string
        userid:
          type: string
        data:
          $ref: '#/components/schemas/ReportJobQueuedPayload'

    CloudEventJobProcessing:
      type: object
      required:
        - id
        - source
        - specversion
        - type
        - time
        - tenantid
        - data
      properties:
        id:
          type: string
        source:
          type: string
          const: com.eventzr.reports-svc
        specversion:
          type: string
          const: '1.0'
        type:
          type: string
          const: com.eventzr.reports.job.processing.v1
        datacontenttype:
          type: string
          const: application/json
        time:
          type: string
          format: date-time
        subject:
          type: string
          example: job/01HXYZ1234567890ABCDEF
        tenantid:
          type: string
          format: uuid
        correlationid:
          type: string
        userid:
          type: string
        data:
          $ref: '#/components/schemas/ReportJobProcessingPayload'

    CloudEventReportReady:
      type: object
      required:
        - id
        - source
        - specversion
        - type
        - time
        - tenantid
        - data
      properties:
        id:
          type: string
        source:
          type: string
          const: com.eventzr.reports-svc
        specversion:
          type: string
          const: '1.0'
        type:
          type: string
          const: com.eventzr.reports.report.ready.v1
        datacontenttype:
          type: string
          const: application/json
        time:
          type: string
          format: date-time
        subject:
          type: string
          description: 'Format: report/{outputId}'
          example: report/01HXYZ1234567890ABCDEF
        tenantid:
          type: string
          format: uuid
        correlationid:
          type: string
        userid:
          type: string
        data:
          $ref: '#/components/schemas/ReportReadyPayload'

    CloudEventReportFailed:
      type: object
      required:
        - id
        - source
        - specversion
        - type
        - time
        - tenantid
        - data
      properties:
        id:
          type: string
        source:
          type: string
          const: com.eventzr.reports-svc
        specversion:
          type: string
          const: '1.0'
        type:
          type: string
          const: com.eventzr.reports.report.failed.v1
        datacontenttype:
          type: string
          const: application/json
        time:
          type: string
          format: date-time
        subject:
          type: string
          example: job/01HXYZ1234567890ABCDEF
        tenantid:
          type: string
          format: uuid
        correlationid:
          type: string
        userid:
          type: string
        data:
          $ref: '#/components/schemas/ReportFailedPayload'

    CloudEventReportExpired:
      type: object
      required:
        - id
        - source
        - specversion
        - type
        - time
        - tenantid
        - data
      properties:
        id:
          type: string
        source:
          type: string
          const: com.eventzr.reports-svc
        specversion:
          type: string
          const: '1.0'
        type:
          type: string
          const: com.eventzr.reports.report.expired.v1
        datacontenttype:
          type: string
          const: application/json
        time:
          type: string
          format: date-time
        subject:
          type: string
          description: 'Format: report/{outputId}'
          example: report/01HXYZ1234567890ABCDEF
        tenantid:
          type: string
          format: uuid
        correlationid:
          type: string
        userid:
          type: string
        data:
          $ref: '#/components/schemas/ReportExpiredPayload'

    CloudEventExportLarge:
      type: object
      required:
        - id
        - source
        - specversion
        - type
        - time
        - tenantid
        - data
      properties:
        id:
          type: string
        source:
          type: string
          const: com.eventzr.reports-svc
        specversion:
          type: string
          const: '1.0'
        type:
          type: string
          const: com.eventzr.reports.export.large.v1
        datacontenttype:
          type: string
          const: application/json
        time:
          type: string
          format: date-time
        subject:
          type: string
          example: job/01HXYZ1234567890ABCDEF
        tenantid:
          type: string
          format: uuid
        correlationid:
          type: string
        userid:
          type: string
        data:
          $ref: '#/components/schemas/ReportExportLargePayload'

    # ========================================================================
    # CLOUDEVENT ENVELOPE SCHEMAS (CONSUMED)
    # ========================================================================

    CloudEventAnalyticsSnapshotCreated:
      type: object
      required:
        - id
        - source
        - specversion
        - type
        - tenantid
        - data
      properties:
        id:
          type: string
        source:
          type: string
          example: com.eventzr.analytics-svc
        specversion:
          type: string
          const: '1.0'
        type:
          type: string
          const: com.eventzr.analytics.snapshot.created.v1
        time:
          type: string
          format: date-time
        tenantid:
          type: string
          format: uuid
        data:
          $ref: '#/components/schemas/AnalyticsSnapshotCreatedPayload'

    CloudEventAnalyticsSnapshotUpdated:
      type: object
      required:
        - id
        - source
        - specversion
        - type
        - tenantid
        - data
      properties:
        id:
          type: string
        source:
          type: string
          example: com.eventzr.analytics-svc
        specversion:
          type: string
          const: '1.0'
        type:
          type: string
          const: com.eventzr.analytics.snapshot.updated.v1
        time:
          type: string
          format: date-time
        tenantid:
          type: string
          format: uuid
        data:
          $ref: '#/components/schemas/AnalyticsSnapshotUpdatedPayload'

    CloudEventStudioThemeUpdated:
      type: object
      required:
        - id
        - source
        - specversion
        - type
        - tenantid
        - data
      properties:
        id:
          type: string
        source:
          type: string
          example: com.eventzr.studio-svc
        specversion:
          type: string
          const: '1.0'
        type:
          type: string
          const: com.eventzr.studio.theme.updated.v1
        time:
          type: string
          format: date-time
        tenantid:
          type: string
          format: uuid
        data:
          $ref: '#/components/schemas/StudioThemeUpdatedPayload'

    CloudEventEventCompleted:
      type: object
      required:
        - id
        - source
        - specversion
        - type
        - tenantid
        - data
      properties:
        id:
          type: string
        source:
          type: string
          example: com.eventzr.event-svc
        specversion:
          type: string
          const: '1.0'
        type:
          type: string
          const: com.eventzr.event.completed.v1
        time:
          type: string
          format: date-time
        tenantid:
          type: string
          format: uuid
        data:
          $ref: '#/components/schemas/EventCompletedPayload'

    CloudEventCampaignCompleted:
      type: object
      required:
        - id
        - source
        - specversion
        - type
        - tenantid
        - data
      properties:
        id:
          type: string
        source:
          type: string
          example: com.eventzr.campaign-svc
        specversion:
          type: string
          const: '1.0'
        type:
          type: string
          const: com.eventzr.campaign.completed.v1
        time:
          type: string
          format: date-time
        tenantid:
          type: string
          format: uuid
        data:
          $ref: '#/components/schemas/CampaignCompletedPayload'

    CloudEventTourLegCompleted:
      type: object
      required:
        - id
        - source
        - specversion
        - type
        - tenantid
        - data
      properties:
        id:
          type: string
        source:
          type: string
          example: com.eventzr.tour-svc
        specversion:
          type: string
          const: '1.0'
        type:
          type: string
          const: com.eventzr.tour.leg.completed.v1
        time:
          type: string
          format: date-time
        tenantid:
          type: string
          format: uuid
        data:
          $ref: '#/components/schemas/TourLegCompletedPayload'

    # ========================================================================
    # DATA PAYLOAD SCHEMAS (PUBLISHED)
    # ========================================================================

    ReportEventBasePayload:
      type: object
      required:
        - jobId
        - tenantId
        - definitionId
        - definitionName
        - reportType
        - format
        - requestedBy
        - timestamp
      properties:
        jobId:
          type: string
          description: Report job ID (ULID)
        tenantId:
          type: string
          format: uuid
          description: Tenant ID for multi-tenant isolation
        definitionId:
          type: string
          description: Report definition/template ID (ULID)
        definitionName:
          type: string
          description: Human-readable report definition name
        reportType:
          type: string
          enum:
            - event_summary
            - event_attendance
            - event_revenue
            - event_performance
            - campaign_performance
            - campaign_reach
            - tour_summary
            - tour_itinerary
            - sales_dashboard
            - customer_analytics
            - financial_statement
            - custom
        format:
          type: string
          enum: [pdf, xlsx, csv, json]
        requestedBy:
          type: string
          description: User ID who requested the report
        timestamp:
          type: string
          format: date-time

    ReportJobQueuedPayload:
      allOf:
        - $ref: '#/components/schemas/ReportEventBasePayload'
        - type: object
          required:
            - priority
            - triggerType
            - parameters
          properties:
            priority:
              type: string
              enum: [critical, high, normal, low]
            triggerType:
              type: string
              enum: [manual, scheduled, event_driven, api]
            scheduleId:
              type: string
              description: Schedule ID if triggered by a schedule
            parameters:
              type: object
              additionalProperties: true
              description: Report-specific parameters
            dateFrom:
              type: string
              format: date-time
            dateTo:
              type: string
              format: date-time
            estimatedRows:
              type: integer
            queuePosition:
              type: integer

    ReportJobProcessingPayload:
      allOf:
        - $ref: '#/components/schemas/ReportEventBasePayload'
        - type: object
          required:
            - workerId
            - startedAt
            - progress
          properties:
            workerId:
              type: string
              description: ID of the worker processing this job
            startedAt:
              type: string
              format: date-time
            progress:
              type: number
              minimum: 0
              maximum: 100
              description: Completion percentage (0-100)
            progressMessage:
              type: string
              description: Human-readable progress description
            estimatedCompletionTime:
              type: string
              format: date-time

    ReportReadyPayload:
      allOf:
        - $ref: '#/components/schemas/ReportEventBasePayload'
        - type: object
          required:
            - outputId
            - filename
            - mimeType
            - fileSizeBytes
            - rowCount
            - s3Bucket
            - s3Key
            - completedAt
            - durationMs
          properties:
            outputId:
              type: string
              description: Report output ID (ULID)
            filename:
              type: string
              description: Generated filename
              example: event-summary-2026-02-24.pdf
            mimeType:
              type: string
              example: application/pdf
            fileSizeBytes:
              type: integer
              description: File size in bytes
            rowCount:
              type: integer
              description: Number of data rows in the report
            pageCount:
              type: integer
              description: Number of pages (PDF only)
            sheetCount:
              type: integer
              description: Number of sheets (XLSX only)
            s3Bucket:
              type: string
              description: S3 bucket where the file is stored
            s3Key:
              type: string
              description: S3 object key
            downloadUrl:
              type: string
              format: uri
              description: Pre-signed download URL (optional)
            downloadUrlExpiresAt:
              type: string
              format: date-time
            completedAt:
              type: string
              format: date-time
            durationMs:
              type: integer
              description: Total generation time in milliseconds
            expiresAt:
              type: string
              format: date-time
              description: When the report output will expire and be deleted

    ReportFailedPayload:
      allOf:
        - $ref: '#/components/schemas/ReportEventBasePayload'
        - type: object
          required:
            - errorCode
            - errorMessage
            - failedAt
            - retryCount
            - maxRetries
            - canRetry
          properties:
            errorCode:
              type: string
              description: Machine-readable error code
              example: ERR_REPORTS_DATA_SOURCE_TIMEOUT
            errorMessage:
              type: string
              description: Human-readable error message
            errorDetails:
              type: string
              description: Additional technical error details
            failedAt:
              type: string
              format: date-time
            retryCount:
              type: integer
              description: Number of retries attempted so far
            maxRetries:
              type: integer
              description: Maximum number of retries configured
            canRetry:
              type: boolean
              description: Whether the job can be retried
            retryScheduledAt:
              type: string
              format: date-time
              description: When the next automatic retry is scheduled

    ReportExpiredPayload:
      allOf:
        - $ref: '#/components/schemas/ReportEventBasePayload'
        - type: object
          required:
            - outputId
            - filename
            - s3Key
            - createdAt
            - expiredAt
            - wasDownloaded
            - downloadCount
            - fileDeleted
          properties:
            outputId:
              type: string
              description: Report output ID (ULID)
            filename:
              type: string
            s3Key:
              type: string
            createdAt:
              type: string
              format: date-time
            expiredAt:
              type: string
              format: date-time
            wasDownloaded:
              type: boolean
              description: Whether the report was ever downloaded
            downloadCount:
              type: integer
              description: Total number of times the report was downloaded
            fileDeleted:
              type: boolean
              description: Whether the S3 file was successfully deleted

    ReportExportLargePayload:
      allOf:
        - $ref: '#/components/schemas/ReportEventBasePayload'
        - type: object
          required:
            - estimatedRows
            - estimatedSizeBytes
            - estimatedDurationSeconds
            - notifyOnCompletion
          properties:
            estimatedRows:
              type: integer
              description: Estimated number of rows in the export
            estimatedSizeBytes:
              type: integer
              description: Estimated file size in bytes
            estimatedDurationSeconds:
              type: integer
              description: Estimated generation time in seconds
            notifyOnCompletion:
              type: boolean
              description: Whether to send notification when complete
            notifyEmails:
              type: array
              items:
                type: string
                format: email
              description: Email addresses to notify on completion
            notifyWebhook:
              type: string
              format: uri
              description: Webhook URL to call on completion

    # ========================================================================
    # DATA PAYLOAD SCHEMAS (CONSUMED)
    # ========================================================================

    AnalyticsSnapshotCreatedPayload:
      type: object
      required:
        - snapshotId
        - tenantId
        - snapshotType
        - entityType
        - entityId
        - periodStart
        - periodEnd
        - metrics
        - dimensions
        - createdAt
      properties:
        snapshotId:
          type: string
        tenantId:
          type: string
          format: uuid
        snapshotType:
          type: string
          description: Type of analytics snapshot
        entityType:
          type: string
          description: Entity type (event, campaign, tour, etc.)
        entityId:
          type: string
        periodStart:
          type: string
          format: date-time
        periodEnd:
          type: string
          format: date-time
        metrics:
          type: object
          additionalProperties:
            oneOf:
              - type: number
              - type: string
        dimensions:
          type: object
          additionalProperties:
            type: string
        createdAt:
          type: string
          format: date-time

    AnalyticsSnapshotUpdatedPayload:
      type: object
      required:
        - snapshotId
        - tenantId
        - snapshotType
        - entityType
        - entityId
        - previousMetrics
        - currentMetrics
        - changedFields
        - updatedAt
      properties:
        snapshotId:
          type: string
        tenantId:
          type: string
          format: uuid
        snapshotType:
          type: string
        entityType:
          type: string
        entityId:
          type: string
        previousMetrics:
          type: object
          additionalProperties:
            oneOf:
              - type: number
              - type: string
        currentMetrics:
          type: object
          additionalProperties:
            oneOf:
              - type: number
              - type: string
        changedFields:
          type: array
          items:
            type: string
        updatedAt:
          type: string
          format: date-time

    StudioThemeUpdatedPayload:
      type: object
      required:
        - themeId
        - tenantId
        - themeName
        - themeType
        - primaryColor
        - updatedBy
        - updatedAt
      properties:
        themeId:
          type: string
        tenantId:
          type: string
          format: uuid
        themeName:
          type: string
        themeType:
          type: string
          enum: [brand, event, campaign, custom]
        entityId:
          type: string
          description: Associated entity ID (event, campaign, etc.)
        primaryColor:
          type: string
          description: Primary brand color (hex)
          example: '#3b82f6'
        secondaryColor:
          type: string
        accentColor:
          type: string
        logoUrl:
          type: string
          format: uri
        fontFamily:
          type: string
        customCss:
          type: string
        updatedBy:
          type: string
          description: User ID who updated the theme
        updatedAt:
          type: string
          format: date-time

    EventCompletedPayload:
      type: object
      required:
        - eventId
        - tenantId
        - eventName
        - eventSlug
        - eventType
        - startDate
        - endDate
        - timezone
        - totalAttendees
        - status
        - completedAt
        - organizerId
      properties:
        eventId:
          type: string
        tenantId:
          type: string
          format: uuid
        seriesId:
          type: string
        eventName:
          type: string
        eventSlug:
          type: string
        eventType:
          type: string
        venueId:
          type: string
        venueName:
          type: string
        cityId:
          type: string
        cityName:
          type: string
        startDate:
          type: string
          format: date-time
        endDate:
          type: string
          format: date-time
        timezone:
          type: string
          example: Asia/Kolkata
        totalAttendees:
          type: integer
        totalRevenue:
          type: number
        currency:
          type: string
          example: INR
        status:
          type: string
        completedAt:
          type: string
          format: date-time
        organizerId:
          type: string
        teamId:
          type: string

    CampaignCompletedPayload:
      type: object
      required:
        - campaignId
        - tenantId
        - campaignName
        - campaignType
        - startDate
        - endDate
        - totalReach
        - totalEngagements
        - totalConversions
        - status
        - completedAt
        - createdBy
      properties:
        campaignId:
          type: string
        tenantId:
          type: string
          format: uuid
        campaignName:
          type: string
        campaignType:
          type: string
        brandId:
          type: string
        brandName:
          type: string
        startDate:
          type: string
          format: date-time
        endDate:
          type: string
          format: date-time
        targetAudience:
          type: string
        totalReach:
          type: integer
        totalEngagements:
          type: integer
        totalConversions:
          type: integer
        totalSpend:
          type: number
        currency:
          type: string
          example: INR
        status:
          type: string
        completedAt:
          type: string
          format: date-time
        createdBy:
          type: string
        teamId:
          type: string

    TourLegCompletedPayload:
      type: object
      required:
        - tourId
        - legId
        - tenantId
        - tourName
        - legName
        - venueId
        - venueName
        - cityId
        - cityName
        - countryCode
        - legNumber
        - totalLegs
        - eventDate
        - timezone
        - totalAttendees
        - status
        - completedAt
        - organizerId
      properties:
        tourId:
          type: string
        legId:
          type: string
        tenantId:
          type: string
          format: uuid
        tourName:
          type: string
        legName:
          type: string
        venueId:
          type: string
        venueName:
          type: string
        cityId:
          type: string
        cityName:
          type: string
        countryCode:
          type: string
          example: IN
        legNumber:
          type: integer
          description: Leg sequence number within the tour
        totalLegs:
          type: integer
          description: Total number of legs in the tour
        eventDate:
          type: string
          format: date-time
        timezone:
          type: string
          example: Asia/Kolkata
        totalAttendees:
          type: integer
        totalRevenue:
          type: number
        currency:
          type: string
          example: INR
        status:
          type: string
        completedAt:
          type: string
          format: date-time
        organizerId:
          type: string
        teamId:
          type: string
