asyncapi: '2.6.0'

info:
  title: Vault Service Async API
  version: 1.6.0
  description: >
    EventZR Vault Service — Kafka event streams for asset lifecycle,
    transforms, quota enforcement, and knowledge graph integration.
    All messages follow the CloudEvents 1.0 specification.
  contact:
    name: EventZR Platform Team
  license:
    name: Proprietary

servers:
  staging:
    url: 'kafka://b-1.eventzr-staging.xxx.kafka.us-east-1.amazonaws.com:9096'
    protocol: kafka
    description: 'Amazon MSK Serverless (staging)'
  localhost:
    url: 'kafka://localhost:9092'
    protocol: kafka
    description: 'Local development'

defaultContentType: application/cloudevents+json

channels:
  # ---------------------------------------------------------------------------
  # PUBLISHED EVENTS  (vault-svc produces these)
  # ---------------------------------------------------------------------------

  eventzr.vault.asset.created.v1:
    description: Emitted when a new asset is uploaded and persisted in the vault.
    publish:
      operationId: assetCreated
      summary: Asset created
      message:
        $ref: '#/components/messages/AssetCreatedEvent'
      bindings:
        kafka:
          key:
            type: string
            description: asset_id used as Kafka partition key.

  eventzr.vault.asset.updated.v1:
    description: Emitted when asset metadata or visibility is changed.
    publish:
      operationId: assetUpdated
      summary: Asset updated
      message:
        $ref: '#/components/messages/AssetUpdatedEvent'
      bindings:
        kafka:
          key:
            type: string
            description: asset_id used as Kafka partition key.

  eventzr.vault.asset.deleted.v1:
    description: Emitted when an asset is permanently deleted from the vault.
    publish:
      operationId: assetDeleted
      summary: Asset deleted
      message:
        $ref: '#/components/messages/AssetDeletedEvent'
      bindings:
        kafka:
          key:
            type: string
            description: asset_id used as Kafka partition key.

  vault.transforms:
    description: >
      Transform pipeline lifecycle events.
      Topic is configurable via KAFKA_TRANSFORM_TOPIC env var.
      Three event types share this topic, distinguished by the CloudEvents
      `ce-type` header: transform.queued, transform.completed, transform.failed.
    publish:
      operationId: transformLifecycle
      summary: Transform lifecycle events (queued / completed / failed)
      message:
        oneOf:
          - $ref: '#/components/messages/TransformQueuedEvent'
          - $ref: '#/components/messages/TransformCompletedEvent'
          - $ref: '#/components/messages/TransformFailedEvent'
      bindings:
        kafka:
          key:
            type: string
            description: transformId used as Kafka partition key.

  kg.events:
    description: >
      Knowledge-graph mutation events emitted when vault entities are projected
      into Neptune. Topic is configurable via KAFKA_KG_TOPIC env var.
      Four event types share this topic, distinguished by the CloudEvents
      `ce-type` header.
    publish:
      operationId: kgLifecycle
      summary: Knowledge-graph node and relationship events
      message:
        oneOf:
          - $ref: '#/components/messages/KgNodeCreatedEvent'
          - $ref: '#/components/messages/KgNodeUpdatedEvent'
          - $ref: '#/components/messages/KgNodeDeletedEvent'
          - $ref: '#/components/messages/KgRelationshipCreatedEvent'
      bindings:
        kafka:
          key:
            type: string
            description: nodeId (or fromNodeId for relationships) used as Kafka partition key.

  eventzr.vault.quota.exceeded.v1:
    description: >
      Emitted when a tenant exceeds a quota limit (storage, assets, transforms, etc.).
      Published from the QuotaExceededFilter for analytics and notification purposes.
    publish:
      operationId: quotaExceeded
      summary: Quota exceeded event
      message:
        $ref: '#/components/messages/QuotaExceededEvent'
      bindings:
        kafka:
          key:
            type: string
            description: tenantId used as Kafka partition key.

  # ---------------------------------------------------------------------------
  # SUBSCRIBED EVENTS  (vault-svc consumes these)
  # ---------------------------------------------------------------------------

  billing.subscription-tier-updated:
    description: >
      Consumed from the billing service (configurable via KAFKA_SUBSCRIPTION_TOPIC).
      Updates internal quota limits when a tenant changes subscription tier.
    subscribe:
      operationId: onSubscriptionTierUpdated
      summary: Subscription tier change
      bindings:
        kafka:
          groupId: vault-svc-subscription-tier-group
      message:
        $ref: '#/components/messages/SubscriptionTierUpdatedEvent'

  eventzr.tenant.deleted.v1:
    description: >
      Consumed from the tenant lifecycle topic.
      Triggers cascade cleanup of all assets, transforms, and KG nodes
      belonging to the deleted tenant.
    subscribe:
      operationId: onTenantDeleted
      summary: Tenant deletion cascade cleanup
      bindings:
        kafka:
          groupId: vault-svc-tenant-group
      message:
        $ref: '#/components/messages/TenantDeletedEvent'

components:
  messages:
    # --- Asset lifecycle -------------------------------------------------------

    AssetCreatedEvent:
      name: AssetCreatedEvent
      title: Asset Created
      contentType: application/cloudevents+json
      traits:
        - $ref: '#/components/messageTraits/CloudEventsHeaders'
      headers:
        type: object
        properties:
          ce-type:
            type: string
            const: com.eventzr.vault.asset.created
      payload:
        $ref: '#/components/schemas/AssetCreatedPayload'

    AssetUpdatedEvent:
      name: AssetUpdatedEvent
      title: Asset Updated
      contentType: application/cloudevents+json
      traits:
        - $ref: '#/components/messageTraits/CloudEventsHeaders'
      headers:
        type: object
        properties:
          ce-type:
            type: string
            const: com.eventzr.vault.asset.updated
      payload:
        $ref: '#/components/schemas/AssetUpdatedPayload'

    AssetDeletedEvent:
      name: AssetDeletedEvent
      title: Asset Deleted
      contentType: application/cloudevents+json
      traits:
        - $ref: '#/components/messageTraits/CloudEventsHeaders'
      headers:
        type: object
        properties:
          ce-type:
            type: string
            const: com.eventzr.vault.asset.deleted
      payload:
        $ref: '#/components/schemas/AssetDeletedPayload'

    # --- Transform lifecycle ---------------------------------------------------

    TransformQueuedEvent:
      name: TransformQueuedEvent
      title: Transform Queued
      contentType: application/cloudevents+json
      traits:
        - $ref: '#/components/messageTraits/CloudEventsHeaders'
      headers:
        type: object
        properties:
          ce-type:
            type: string
            const: com.eventzr.vault.transform.queued
      payload:
        $ref: '#/components/schemas/TransformQueuedPayload'

    TransformCompletedEvent:
      name: TransformCompletedEvent
      title: Transform Completed
      contentType: application/cloudevents+json
      traits:
        - $ref: '#/components/messageTraits/CloudEventsHeaders'
      headers:
        type: object
        properties:
          ce-type:
            type: string
            const: com.eventzr.vault.transform.completed
      payload:
        $ref: '#/components/schemas/TransformCompletedPayload'

    TransformFailedEvent:
      name: TransformFailedEvent
      title: Transform Failed
      contentType: application/cloudevents+json
      traits:
        - $ref: '#/components/messageTraits/CloudEventsHeaders'
      headers:
        type: object
        properties:
          ce-type:
            type: string
            const: com.eventzr.vault.transform.failed
      payload:
        $ref: '#/components/schemas/TransformFailedPayload'

    # --- Knowledge-graph events ------------------------------------------------

    KgNodeCreatedEvent:
      name: KgNodeCreatedEvent
      title: KG Node Created
      contentType: application/cloudevents+json
      traits:
        - $ref: '#/components/messageTraits/CloudEventsHeaders'
      headers:
        type: object
        properties:
          ce-type:
            type: string
            const: com.eventzr.kg.node.created
      payload:
        $ref: '#/components/schemas/KgNodeCreatedPayload'

    KgNodeUpdatedEvent:
      name: KgNodeUpdatedEvent
      title: KG Node Updated
      contentType: application/cloudevents+json
      traits:
        - $ref: '#/components/messageTraits/CloudEventsHeaders'
      headers:
        type: object
        properties:
          ce-type:
            type: string
            const: com.eventzr.kg.node.updated
      payload:
        $ref: '#/components/schemas/KgNodeUpdatedPayload'

    KgNodeDeletedEvent:
      name: KgNodeDeletedEvent
      title: KG Node Deleted
      contentType: application/cloudevents+json
      traits:
        - $ref: '#/components/messageTraits/CloudEventsHeaders'
      headers:
        type: object
        properties:
          ce-type:
            type: string
            const: com.eventzr.kg.node.deleted
      payload:
        $ref: '#/components/schemas/KgNodeDeletedPayload'

    KgRelationshipCreatedEvent:
      name: KgRelationshipCreatedEvent
      title: KG Relationship Created
      contentType: application/cloudevents+json
      traits:
        - $ref: '#/components/messageTraits/CloudEventsHeaders'
      headers:
        type: object
        properties:
          ce-type:
            type: string
            const: com.eventzr.kg.relationship.created
      payload:
        $ref: '#/components/schemas/KgRelationshipCreatedPayload'

    # --- Quota events ---------------------------------------------------------

    QuotaExceededEvent:
      name: QuotaExceededEvent
      title: Quota Exceeded
      contentType: application/cloudevents+json
      traits:
        - $ref: '#/components/messageTraits/CloudEventsHeaders'
      headers:
        type: object
        properties:
          ce-type:
            type: string
            const: com.eventzr.vault.quota.exceeded
      payload:
        $ref: '#/components/schemas/QuotaExceededPayload'

    # --- Consumed event messages -----------------------------------------------

    SubscriptionTierUpdatedEvent:
      name: SubscriptionTierUpdatedEvent
      title: Subscription Tier Updated
      contentType: application/cloudevents+json
      traits:
        - $ref: '#/components/messageTraits/CloudEventsHeaders'
      payload:
        $ref: '#/components/schemas/SubscriptionTierUpdatedPayload'

    TenantDeletedEvent:
      name: TenantDeletedEvent
      title: Tenant Deleted
      contentType: application/cloudevents+json
      traits:
        - $ref: '#/components/messageTraits/CloudEventsHeaders'
      payload:
        $ref: '#/components/schemas/TenantDeletedPayload'

  schemas:
    # --- Asset payloads --------------------------------------------------------

    AssetCreatedPayload:
      type: object
      required:
        - asset_id
        - tenantId
        - filename
        - mime_type
        - asset_type
        - size_bytes
        - storage_key
        - visibility
        - owner_type
        - owner_id
        - created_by
        - rag_seed
      properties:
        asset_id:
          type: string
          format: uuid
          description: Unique identifier of the created asset.
        tenantId:
          type: string
          format: uuid
          description: Tenant that owns the asset.
        filename:
          type: string
          description: Original filename as uploaded by the user.
        mime_type:
          type: string
          description: 'MIME type of the asset (e.g. image/png, application/pdf).'
        asset_type:
          type: string
          description: 'Logical asset category (e.g. image, document, video, audio).'
        size_bytes:
          type: integer
          format: int64
          description: Size of the asset in bytes.
        storage_key:
          type: string
          description: S3 object key where the asset is stored.
        visibility:
          type: string
          enum:
            - private
            - public
            - tenant
          description: Visibility scope of the asset.
        owner_type:
          type: string
          description: 'Type of entity that owns the asset (e.g. user, team, event).'
        owner_id:
          type: string
          format: uuid
          description: ID of the owning entity.
        created_by:
          type: string
          format: uuid
          description: ID of the user who uploaded the asset.
        rag_seed:
          type: boolean
          description: Whether the asset should be ingested into the RAG pipeline.

    AssetUpdatedPayload:
      type: object
      required:
        - asset_id
        - tenantId
        - changes
        - updated_by
      properties:
        asset_id:
          type: string
          format: uuid
          description: Unique identifier of the updated asset.
        tenantId:
          type: string
          format: uuid
          description: Tenant that owns the asset.
        changes:
          type: object
          additionalProperties: true
          description: Key-value map of changed fields and their new values.
        updated_by:
          type: string
          format: uuid
          description: ID of the user who performed the update.

    AssetDeletedPayload:
      type: object
      required:
        - asset_id
        - tenantId
        - storage_key
        - deleted_by
      properties:
        asset_id:
          type: string
          format: uuid
          description: Unique identifier of the deleted asset.
        tenantId:
          type: string
          format: uuid
          description: Tenant that owned the asset.
        storage_key:
          type: string
          description: S3 object key that was deleted.
        deleted_by:
          type: string
          format: uuid
          description: ID of the user who deleted the asset.

    # --- Transform payloads ----------------------------------------------------

    TransformQueuedPayload:
      type: object
      required:
        - transformId
        - assetId
        - tenantId
        - kind
        - userId
      properties:
        transformId:
          type: string
          format: uuid
          description: Unique identifier of the transform job.
        assetId:
          type: string
          format: uuid
          description: Source asset being transformed.
        tenantId:
          type: string
          format: uuid
          description: Tenant that owns the asset.
        kind:
          type: string
          description: 'Transform kind (e.g. thumbnail, watermark, transcode, ocr).'
        userId:
          type: string
          format: uuid
          description: ID of the user who requested the transform.

    TransformCompletedPayload:
      type: object
      required:
        - transformId
        - assetId
        - tenantId
        - kind
        - outputKey
        - sizeBytes
        - processingTimeMs
      properties:
        transformId:
          type: string
          format: uuid
          description: Unique identifier of the completed transform job.
        assetId:
          type: string
          format: uuid
          description: Source asset that was transformed.
        tenantId:
          type: string
          format: uuid
          description: Tenant that owns the asset.
        kind:
          type: string
          description: Transform kind that completed.
        outputKey:
          type: string
          description: S3 object key of the transform output.
        sizeBytes:
          type: integer
          format: int64
          description: Size of the output artifact in bytes.
        processingTimeMs:
          type: integer
          format: int64
          description: Wall-clock processing time in milliseconds.

    TransformFailedPayload:
      type: object
      required:
        - transformId
        - assetId
        - tenantId
        - kind
        - errorMessage
      properties:
        transformId:
          type: string
          format: uuid
          description: Unique identifier of the failed transform job.
        assetId:
          type: string
          format: uuid
          description: Source asset whose transform failed.
        tenantId:
          type: string
          format: uuid
          description: Tenant that owns the asset.
        kind:
          type: string
          description: Transform kind that failed.
        errorMessage:
          type: string
          description: Human-readable error message describing the failure.

    # --- Knowledge-graph payloads ----------------------------------------------

    KgNodeCreatedPayload:
      type: object
      required:
        - nodeType
        - nodeId
        - tenantId
        - labels
        - properties
      properties:
        nodeType:
          type: string
          enum:
            - Asset
            - Transform
          description: Neptune node label (Asset or Transform).
        nodeId:
          type: string
          format: uuid
          description: ID of the node in Neptune.
        tenantId:
          type: string
          format: uuid
          description: Tenant that owns the node.
        labels:
          type: array
          items:
            type: string
          description: Neptune vertex labels applied to the node.
        properties:
          type: object
          additionalProperties: true
          description: Key-value properties stored on the node.

    KgNodeUpdatedPayload:
      type: object
      required:
        - nodeType
        - nodeId
        - tenantId
        - properties
      properties:
        nodeType:
          type: string
          enum:
            - Asset
            - Transform
          description: Neptune node label (Asset or Transform).
        nodeId:
          type: string
          format: uuid
          description: ID of the node in Neptune.
        tenantId:
          type: string
          format: uuid
          description: Tenant that owns the node.
        properties:
          type: object
          additionalProperties: true
          description: Key-value properties that were updated on the node.

    KgNodeDeletedPayload:
      type: object
      required:
        - nodeType
        - nodeId
        - tenantId
        - deletedAt
      properties:
        nodeType:
          type: string
          enum:
            - Asset
            - Transform
          description: Neptune node label (Asset or Transform).
        nodeId:
          type: string
          format: uuid
          description: ID of the node that was deleted in Neptune.
        tenantId:
          type: string
          format: uuid
          description: Tenant that owned the node.
        deletedAt:
          type: string
          format: date-time
          description: ISO 8601 timestamp when the node was deleted.

    KgRelationshipCreatedPayload:
      type: object
      required:
        - relationshipType
        - fromNodeType
        - fromNodeId
        - toNodeType
        - toNodeId
        - tenantId
        - properties
      properties:
        relationshipType:
          type: string
          enum:
            - OWNED_BY
            - HAS_TRANSFORM
            - DERIVED_FROM
          description: Type of relationship created in Neptune.
        fromNodeType:
          type: string
          description: Label of the source node (e.g. Asset, Transform).
        fromNodeId:
          type: string
          format: uuid
          description: ID of the source node.
        toNodeType:
          type: string
          description: Label of the target node (e.g. Asset, Transform).
        toNodeId:
          type: string
          format: uuid
          description: ID of the target node.
        tenantId:
          type: string
          format: uuid
          description: Tenant that owns the relationship.
        properties:
          type: object
          additionalProperties: true
          description: Optional properties stored on the edge.

    # --- Quota payloads -------------------------------------------------------

    QuotaExceededPayload:
      type: object
      required:
        - tenantId
        - quotaType
        - limit
        - currentUsage
        - requestedAmount
        - percentageUsed
        - timestamp
        - path
        - method
      properties:
        tenantId:
          type: string
          format: uuid
          description: Tenant whose quota was exceeded.
        userId:
          type: string
          format: uuid
          description: User who triggered the quota check (may be null).
        quotaType:
          type: string
          description: 'Type of quota exceeded (e.g. storage_bytes, asset_count, transforms_per_day).'
        limit:
          type: integer
          description: The configured quota limit.
        currentUsage:
          type: integer
          description: Current usage at the time of the request.
        requestedAmount:
          type: integer
          description: Amount requested that caused the quota to be exceeded.
        percentageUsed:
          type: number
          format: float
          description: 'Percentage of quota used (e.g. 105.5 means 5.5% over limit).'
        timestamp:
          type: string
          format: date-time
          description: ISO 8601 timestamp when the quota was exceeded.
        path:
          type: string
          description: 'HTTP path of the request that exceeded the quota (e.g. /vault/v1/assets).'
        method:
          type: string
          description: 'HTTP method of the request (e.g. POST, PUT).'
        requestId:
          type: string
          description: x-request-id header value for tracing (may be null).

    # --- Consumed event payloads -----------------------------------------------

    SubscriptionTierUpdatedPayload:
      type: object
      required:
        - tenantId
        - old_tier
        - new_tier
        - effective_at
      properties:
        tenantId:
          type: string
          format: uuid
          description: Tenant whose subscription tier changed.
        old_tier:
          type: string
          description: Previous subscription tier.
        new_tier:
          type: string
          description: New subscription tier.
        effective_at:
          type: string
          format: date-time
          description: ISO 8601 timestamp when the tier change takes effect.

    TenantDeletedPayload:
      type: object
      required:
        - tenant_id
        - deleted_at
        - deleted_by
      properties:
        tenant_id:
          type: string
          format: uuid
          description: ID of the tenant being deleted.
        deleted_at:
          type: string
          format: date-time
          description: ISO 8601 timestamp of deletion.
        deleted_by:
          type: string
          format: uuid
          description: ID of the admin who initiated the deletion.

  messageTraits:
    CloudEventsHeaders:
      headers:
        type: object
        required:
          - ce-specversion
          - ce-type
          - ce-source
          - ce-id
          - ce-tenantid
          - ce-time
        properties:
          ce-specversion:
            type: string
            const: '1.0'
            description: CloudEvents specification version.
          ce-type:
            type: string
            description: CloudEvents event type string.
          ce-source:
            type: string
            const: vault-svc
            description: Originating service identifier.
          ce-id:
            type: string
            format: uuid
            description: Unique event identifier (UUID v4).
          ce-tenantid:
            type: string
            format: uuid
            description: Tenant UUID, also used as Kafka partition key.
          ce-time:
            type: string
            format: date-time
            description: ISO 8601 timestamp when the event was produced.
