openapi: 3.0.3
info:
  title: Volatrade Homepage API
  version: 1.0.0
  description: |
    Volatrade 对外只读 API。

    主要用途：
    - 获取首页首屏卡片
    - 获取 watchlist 列表
    - 获取单个交易对的当前 live card 详情
    - 获取服务元数据
servers:
  - url: /
    description: Current deployment root
tags:
  - name: homepage
    description: 首页首屏相关接口
  - name: watchlist
    description: 监控列表相关接口
  - name: symbol
    description: 单个交易对详情接口
  - name: metadata
    description: 服务元数据与依赖快照接口
paths:
  /v1/homepage/cards:
    get:
      tags:
        - homepage
      summary: 获取首页首屏卡片
      description: |
        返回首页首屏卡片数据。

        说明：
        - 该接口返回的是首页首屏结果，不是全部 live card
        - 正常情况下最多返回 3 条
        - 当排序服务不可用时，可能返回 stale 数据
      operationId: getHomepageCards
      responses:
        "200":
          description: 首页快照
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/HomepageResponse"
              examples:
                success:
                  summary: 成功返回首页数据
                  value:
                    items:
                      - rank: 1
                        card_id: BTCUSDT-1743552000000
                        pair_key: BTCUSDT
                        display_symbol: BTC/USDT
                        card_type: OPPORTUNITY
                        archetype: BREAKOUT_EXPANSION
                        direction: LONG
                        market_scope: USDM_PERP_ONLY
                        action_band: ATTEND_NOW
                        confidence_band: HIGH
                        score_total: 82.4
                        reason_primary: 趋势延续且突破确认
                        reason_secondary: 量能配合
                        risk_note: 注意短线波动放大
                        publish_time_ms: 1743552000000
                        expire_time_ms: 1743555600000
                        normalized_priority: 88.7
                        contract_version: "1.0.0"
                    meta:
                      is_global_no_card: false
                      has_warning_only: false
                      is_stale: false
                      snapshot_at_ms: 1743552060000
                      node: api-01
                      version: "1.0.0"
        "405":
          description: 请求方法错误
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "503":
          description: 服务暂时不可用
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /v1/watchlist:
    get:
      tags:
        - watchlist
      summary: 获取 watchlist 列表
      description: |
        返回 watchlist 视图下的 live card 列表。

        说明：
        - 按 `normalized_priority DESC` 排序
        - 当前服务端上限为 20 条
      operationId: getWatchlist
      responses:
        "200":
          description: Watchlist 快照
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WatchlistResponse"
        "405":
          description: 请求方法错误
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "500":
          description: 服务内部错误
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /v1/symbol/{pair_key}/detail:
    get:
      tags:
        - symbol
      summary: 获取单个交易对当前卡片详情
      description: |
        根据 `pair_key` 返回该交易对当前的 live card。

        说明：
        - 如果该交易对当前没有 live card，则返回 404
        - 路径必须是 `/v1/symbol/{pair_key}/detail`
      operationId: getSymbolDetail
      parameters:
        - name: pair_key
          in: path
          required: true
          description: |
            交易对主键。

            常见示例：
            - `BTCUSDT`
            - `ETHUSDT`
          schema:
            type: string
            example: BTCUSDT
      responses:
        "200":
          description: 当前交易对 live card
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SymbolDetailResponse"
        "404":
          description: 无 live card，或路径格式不正确
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
              examples:
                noLiveCard:
                  summary: 当前没有线上卡片
                  value:
                    error: no live card for BTCUSDT
        "405":
          description: 请求方法错误
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "500":
          description: 服务内部错误
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /v1/metadata:
    get:
      tags:
        - metadata
      summary: 获取服务元数据
      description: |
        返回服务名、服务描述以及依赖连接快照。

        可用于：
        - 检查当前节点版本
        - 确认依赖地址配置
      operationId: getMetadata
      responses:
        "200":
          description: 服务元数据
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MetadataResponse"
        "405":
          description: 请求方法错误
components:
  schemas:
    CardItem:
      type: object
      description: 单张对外展示卡片
      required:
        - card_id
        - pair_key
        - display_symbol
        - card_type
        - archetype
        - direction
        - market_scope
        - action_band
        - confidence_band
        - score_total
        - reason_primary
        - publish_time_ms
        - expire_time_ms
        - normalized_priority
        - contract_version
      properties:
        rank:
          type: integer
          description: |
            当前列表内的展示名次。

            仅首页和排序结果里通常会出现。
          example: 1
        card_id:
          type: string
          description: 卡片唯一标识
          example: BTCUSDT-1743552000000
        pair_key:
          type: string
          description: 交易对主键
          example: BTCUSDT
        display_symbol:
          type: string
          description: 展示用交易对名称
          example: BTC/USDT
        card_type:
          type: string
          description: 卡片类型，如 OPPORTUNITY 或 WARNING
          example: OPPORTUNITY
        archetype:
          type: string
          description: 机会原型或风险原型
          example: BREAKOUT_EXPANSION
        direction:
          type: string
          description: 方向，通常为 LONG 或 SHORT
          example: LONG
        market_scope:
          type: string
          description: 市场覆盖范围
          example: USDM_PERP_ONLY
        action_band:
          type: string
          description: 操作建议等级
          example: ATTEND_NOW
        confidence_band:
          type: string
          description: 置信度等级
          example: HIGH
        score_total:
          type: number
          format: double
          description: 卡片总评分
          example: 82.4
        reason_primary:
          type: string
          description: 主解释文案
          example: 趋势延续且突破确认
        reason_secondary:
          type: string
          description: 次解释文案，可为空
          example: 量能配合
        risk_note:
          type: string
          description: 风险提示，可为空
          example: 注意短线波动放大
        publish_time_ms:
          type: integer
          format: int64
          description: 发布时间，Unix 毫秒时间戳
          example: 1743552000000
        expire_time_ms:
          type: integer
          format: int64
          description: 失效时间，Unix 毫秒时间戳
          example: 1743555600000
        normalized_priority:
          type: number
          format: double
          description: 归一化优先级，数值越大排序越靠前
          example: 88.7
        contract_version:
          type: string
          description: 当前卡片遵循的合同版本
          example: "1.0.0"
    HomepageMeta:
      type: object
      description: 首页响应元数据
      required:
        - is_global_no_card
        - has_warning_only
        - is_stale
        - snapshot_at_ms
        - node
        - version
      properties:
        is_global_no_card:
          type: boolean
          description: 是否处于全局无卡状态
          example: false
        has_warning_only:
          type: boolean
          description: 是否只有 warning 卡而没有正向卡
          example: false
        is_stale:
          type: boolean
          description: 是否为缓存降级返回的数据
          example: false
        snapshot_at_ms:
          type: integer
          format: int64
          description: 本次快照生成时间，Unix 毫秒时间戳
          example: 1743552060000
        node:
          type: string
          description: 当前服务节点名
          example: api-01
        version:
          type: string
          description: 当前服务版本
          example: "1.0.0"
    GlobalNoCard:
      type: object
      description: 首页无卡解释对象
      required:
        - reason_primary
        - reason_codes
        - decision_time_ms
        - contract_version
        - quality_state
        - bundle_hash
      properties:
        reason_primary:
          type: string
          description: 主解释文案
          example: 当前无高质量机会
        reason_codes:
          type: array
          description: 解释原因代码列表
          items:
            type: string
          example:
            - ALL_CANDIDATES_BELOW_THRESHOLD
        decision_time_ms:
          type: integer
          format: int64
          description: 判定时间，Unix 毫秒时间戳
          example: 1743552060000
        contract_version:
          type: string
          description: 解释对象对应的合同版本
          example: "1.0.0"
        quality_state:
          type: string
          description: 当前质量状态
          example: INVALID
        bundle_hash:
          type: string
          description: 关联的 bundle hash，没有时可能为空字符串
          example: ""
    HomepageResponse:
      type: object
      description: 首页接口响应
      required:
        - items
        - meta
      properties:
        items:
          type: array
          description: 首页首屏卡片列表
          items:
            $ref: "#/components/schemas/CardItem"
        global_no_card:
          allOf:
            - $ref: "#/components/schemas/GlobalNoCard"
          description: |
            无正向卡时返回的解释对象。

            当首页存在正向卡时，该字段可能为空。
        meta:
          $ref: "#/components/schemas/HomepageMeta"
    WatchlistMeta:
      type: object
      description: 通用列表元数据
      required:
        - snapshot_at_ms
        - node
        - version
      properties:
        snapshot_at_ms:
          type: integer
          format: int64
          description: 快照生成时间，Unix 毫秒时间戳
          example: 1743552060000
        node:
          type: string
          description: 当前服务节点名
          example: api-01
        version:
          type: string
          description: 当前服务版本
          example: "1.0.0"
    WatchlistResponse:
      type: object
      description: Watchlist 接口响应
      required:
        - items
        - meta
      properties:
        items:
          type: array
          description: Watchlist 卡片列表
          items:
            $ref: "#/components/schemas/CardItem"
        meta:
          $ref: "#/components/schemas/WatchlistMeta"
    SymbolDetailResponse:
      type: object
      description: 单个交易对详情响应
      required:
        - item
        - meta
      properties:
        item:
          allOf:
            - $ref: "#/components/schemas/CardItem"
          description: 当前交易对的 live card
        meta:
          $ref: "#/components/schemas/WatchlistMeta"
    MetadataResponse:
      type: object
      description: 服务元数据响应
      required:
        - service
        - description
        - dependencies
      properties:
        service:
          type: string
          description: 服务名
          example: svc-api-homepage
        description:
          type: string
          description: 服务说明
          example: Public read-only homepage API
        dependencies:
          type: object
          description: 依赖快照，value 为当前配置的地址或连接串
          additionalProperties:
            type: string
          example:
            ranking_grpc_addr: svc-ranking:19090
            pg_dsn: postgresql://volatrade:***@postgres:5432/volatrade?sslmode=disable
    ErrorResponse:
      type: object
      description: 错误响应
      required:
        - error
      properties:
        error:
          type: string
          description: 错误信息
          example: method not allowed
