basePath: /
definitions:
  handlers.AdminChatPayload:
    properties:
      content:
        type: string
    type: object
  handlers.AdminVerifyTokenRequest:
    properties:
      token:
        type: string
    type: object
  handlers.ChatMessagePayload:
    properties:
      content:
        type: string
    type: object
  handlers.CheckoutPayload:
    properties:
      contactEmail:
        type: string
      contactPhone:
        type: string
      note:
        type: string
      notifyEmail:
        type: string
      paymentMethod:
        type: string
      productId:
        type: string
      quantity:
        type: integer
    type: object
  handlers.MaintenancePayload:
    properties:
      maintenance:
        type: boolean
      reason:
        type: string
    type: object
  handlers.ProductPayload:
    properties:
      active:
        type: boolean
      codes:
        items:
          type: string
        type: array
      coverUrl:
        type: string
      deliveryMode:
        type: string
      description:
        type: string
      discountPrice:
        type: number
      fixedContent:
        type: string
      fulfillmentType:
        type: string
      maxPerAccount:
        type: integer
      name:
        type: string
      paymentQrUrls:
        items:
          type: string
        type: array
      price:
        type: number
      requireLogin:
        type: boolean
      screenshotUrls:
        items:
          type: string
        type: array
      showContact:
        type: boolean
      showNote:
        type: boolean
      tags:
        type: string
    type: object
  handlers.SwaggerBoolOK:
    properties:
      ok:
        type: boolean
    type: object
  handlers.SwaggerBoolOKWrap:
    properties:
      data:
        $ref: '#/definitions/handlers.SwaggerBoolOK'
    type: object
  handlers.SwaggerCancelMsg:
    properties:
      message:
        type: string
      ok:
        type: boolean
    type: object
  handlers.SwaggerCancelWrap:
    properties:
      data:
        $ref: '#/definitions/handlers.SwaggerCancelMsg'
    type: object
  handlers.SwaggerCheckoutData:
    properties:
      orderId:
        type: string
      paymentExpectedTotal:
        type: number
      paymentExpiresAt:
        type: string
      paymentMethod:
        type: string
      paymentQrUrls:
        items:
          type: string
        type: array
      productId:
        type: string
      productQty:
        type: integer
      qrCodeUrl:
        type: string
      status:
        type: string
      viewCount:
        type: integer
    type: object
  handlers.SwaggerCheckoutWrap:
    properties:
      data:
        $ref: '#/definitions/handlers.SwaggerCheckoutData'
    type: object
  handlers.SwaggerConfirmData:
    properties:
      deliveredCodes:
        items:
          type: string
        type: array
      deliveryMode:
        type: string
      isManual:
        type: boolean
      orderId:
        type: string
      status:
        type: string
    type: object
  handlers.SwaggerConfirmWrap:
    properties:
      data:
        $ref: '#/definitions/handlers.SwaggerConfirmData'
    type: object
  handlers.SwaggerErrorBody:
    properties:
      error:
        type: string
    type: object
  handlers.SwaggerMaintenanceData:
    properties:
      maintenance:
        type: boolean
      reason:
        type: string
    type: object
  handlers.SwaggerMaintenanceWrap:
    properties:
      data:
        $ref: '#/definitions/handlers.SwaggerMaintenanceData'
    type: object
  handlers.SwaggerMessagesInner:
    properties:
      messages:
        items:
          $ref: '#/definitions/models.ChatMessage'
        type: array
    type: object
  handlers.SwaggerMessagesWrap:
    properties:
      data:
        $ref: '#/definitions/handlers.SwaggerMessagesInner'
    type: object
  handlers.SwaggerOneChatMsgWrap:
    properties:
      data:
        $ref: '#/definitions/handlers.SwaggerSingleChatWrap'
    type: object
  handlers.SwaggerOrdersBody:
    properties:
      data:
        items:
          $ref: '#/definitions/models.Order'
        type: array
    type: object
  handlers.SwaggerPaymentStatusData:
    properties:
      expectedTotal:
        type: number
      paymentExpiresAt:
        type: string
      paymentMethod:
        type: string
      status:
        type: string
    type: object
  handlers.SwaggerPaymentStatusWrap:
    properties:
      data:
        $ref: '#/definitions/handlers.SwaggerPaymentStatusData'
    type: object
  handlers.SwaggerProductListBody:
    properties:
      data:
        items:
          $ref: '#/definitions/models.Product'
        type: array
    type: object
  handlers.SwaggerProductOneBody:
    properties:
      data:
        $ref: '#/definitions/models.Product'
    type: object
  handlers.SwaggerProductViewData:
    properties:
      counted:
        type: boolean
      id:
        type: string
      viewCount:
        type: integer
    type: object
  handlers.SwaggerProductViewWrap:
    properties:
      data:
        $ref: '#/definitions/handlers.SwaggerProductViewData'
    type: object
  handlers.SwaggerSMTPWrap:
    properties:
      data:
        $ref: '#/definitions/storage.SMTPConfig'
    type: object
  handlers.SwaggerSingleChatWrap:
    properties:
      message:
        $ref: '#/definitions/models.ChatMessage'
    type: object
  handlers.SwaggerStatsData:
    properties:
      totalOrders:
        type: integer
      totalVisits:
        type: integer
    type: object
  handlers.SwaggerStatsWrap:
    properties:
      data:
        $ref: '#/definitions/handlers.SwaggerStatsData'
    type: object
  handlers.SwaggerStringOKBody:
    properties:
      data:
        type: string
    type: object
  handlers.SwaggerValidBody:
    properties:
      valid:
        type: boolean
    type: object
  handlers.SwaggerVisitData:
    properties:
      counted:
        type: boolean
      totalVisits:
        type: integer
    type: object
  handlers.SwaggerVisitWrap:
    properties:
      data:
        $ref: '#/definitions/handlers.SwaggerVisitData'
    type: object
  handlers.SwaggerWebhookMengyaResp:
    properties:
      matched:
        type: boolean
      matched_order_id:
        type: string
      ok:
        type: boolean
    type: object
  handlers.SwaggerWishlistItems:
    properties:
      items:
        items:
          type: string
        type: array
    type: object
  handlers.SwaggerWishlistWrap:
    properties:
      data:
        $ref: '#/definitions/handlers.SwaggerWishlistItems'
    type: object
  handlers.TogglePayload:
    properties:
      active:
        type: boolean
    type: object
  handlers.WishlistItemPayload:
    properties:
      productId:
        type: string
    type: object
  models.ChatMessage:
    properties:
      accountId:
        type: string
      accountName:
        type: string
      content:
        type: string
      fromAdmin:
        type: boolean
      id:
        type: string
      sentAt:
        type: string
    type: object
  models.Order:
    properties:
      contactEmail:
        type: string
      contactPhone:
        type: string
      createdAt:
        type: string
      deliveredCodes:
        items:
          type: string
        type: array
      deliveryMode:
        type: string
      id:
        type: string
      note:
        type: string
      notifyEmail:
        type: string
      paymentExpectedTotal:
        type: number
      paymentExpiresAt:
        type: string
      paymentMethod:
        type: string
      productId:
        type: string
      productName:
        type: string
      quantity:
        type: integer
      status:
        type: string
      userAccount:
        type: string
      userName:
        type: string
    type: object
  models.Product:
    properties:
      active:
        type: boolean
      codes:
        items:
          type: string
        type: array
      coverUrl:
        type: string
      createdAt:
        type: string
      deliveryMode:
        type: string
      description:
        type: string
      discountPrice:
        type: number
      fixedContent:
        type: string
      fulfillmentType:
        type: string
      id:
        type: string
      maxPerAccount:
        type: integer
      name:
        type: string
      paymentQrUrls:
        description: PaymentQrURLs 萌芽支付收款码图片链接（可多条）。
        items:
          type: string
        type: array
      price:
        type: number
      quantity:
        type: integer
      requireLogin:
        type: boolean
      screenshotUrls:
        items:
          type: string
        type: array
      showContact:
        type: boolean
      showNote:
        type: boolean
      tags:
        items:
          type: string
        type: array
      totalSold:
        type: integer
      updatedAt:
        type: string
      verificationUrl:
        type: string
      viewCount:
        type: integer
    type: object
  storage.SMTPConfig:
    properties:
      email:
        type: string
      enabled:
        type: boolean
      fromName:
        type: string
      host:
        type: string
      password:
        type: string
      port:
        type: string
    type: object
host: localhost:8080
info:
  contact: {}
  description: |-
    萌芽小店电商后端 HTTP API：商品、下单结账、订单与支付、站点统计与访问、维护模式、收藏、用户/管理员聊天、萌芽支付 Webhook，以及管理端商品/订单/站点与运维状态等。用户身份由萌芽账户认证中心（SproutGate）签发令牌并完成校验。

    **运行环境与基地址**
    - **本地开发**：监听地址由环境变量 `HTTP_LISTEN_ADDR` 决定，未设置时默认为 `:8080`，即常见入口 `http://localhost:8080`。可在浏览器打开 `http://localhost:8080/swagger/index.html` 查看本页同款文档并调试。
    - **生产部署**：线上前台/API 域名为 `https://store.shumengya.top`（HTTPS）。若前面还有网关、路径前缀或端口映射，请在拼接请求 URL 时以实际对外发布地址为准；Swagger 中默认 Host 为本地，联调线上时请将浏览器地址或客户端 Base URL 换成生产基地址。

    **说明**：本 OpenAPI 由代码注释生成；与进程真实监听、反向代理头无关，仅作契约参考。
  title: 萌芽小店 API
  version: 1.0.0-go
paths:
  /:
    get:
      description: 访问服务根路径 `/` 返回 JSON：服务简介、本地与生产环境说明、主要业务路由分组、运行版本与时间戳。完整请求/响应模型请使用
        Swagger UI：`GET /swagger/index.html`。本地一般为 `http://localhost:8080/`，生产域名为
        `https://store.shumengya.top/`。
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            additionalProperties: true
            type: object
      summary: 根路径 API 说明与路由索引
      tags:
      - 元信息
  /api/admin/chat:
    get:
      description: 返回每个有过消息的用户账号等信息，供客服选择会话；需管理令牌 `X-Admin-Token`。
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            additionalProperties: true
            type: object
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
      security:
      - AdminToken: []
      summary: 管理端：列出全部聊天会话
      tags:
      - 管理端-聊天
  /api/admin/chat/{account}:
    delete:
      description: 删除该账号在系统中的全部聊天消息记录；不可恢复请谨慎使用。
      parameters:
      - description: 用户账号（路径）
        in: path
        name: account
        required: true
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/handlers.SwaggerBoolOKWrap'
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
      security:
      - AdminToken: []
      summary: 管理端：清空与某用户的会话
      tags:
      - 管理端-聊天
    get:
      description: 路径参数 `account` 为用户账号标识；返回按时间排列的消息数组；需管理令牌。
      parameters:
      - description: 用户账号（路径）
        in: path
        name: account
        required: true
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/handlers.SwaggerMessagesWrap'
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
      security:
      - AdminToken: []
      summary: 管理端：查看某用户的完整聊天记录
      tags:
      - 管理端-聊天
    post:
      consumes:
      - application/json
      description: 路径为对方账号，JSON body 含 `content`；写入后用户侧拉取可见。
      parameters:
      - description: 用户账号（路径）
        in: path
        name: account
        required: true
        type: string
      - description: 回复正文 JSON
        in: body
        name: body
        required: true
        schema:
          $ref: '#/definitions/handlers.AdminChatPayload'
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/handlers.SwaggerOneChatMsgWrap'
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
      security:
      - AdminToken: []
      summary: 管理端：向用户回复一条消息
      tags:
      - 管理端-聊天
  /api/admin/orders:
    get:
      description: 返回数据库中订单全量列表（含敏感字段），供后台管理；需 `X-Admin-Token`。
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/handlers.SwaggerOrdersBody'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
      security:
      - AdminToken: []
      summary: 管理端获取全部订单
      tags:
      - 管理端-订单
  /api/admin/orders/{id}:
    delete:
      description: 按路径中的订单 ID 删除记录；不可恢复请谨慎操作。
      parameters:
      - description: 订单ID
        in: path
        name: id
        required: true
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/handlers.SwaggerBoolOKWrap'
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
      security:
      - AdminToken: []
      summary: 管理端删除指定订单
      tags:
      - 管理端-订单
  /api/admin/products:
    get:
      description: 含下架商品、卡密字段等完整数据，仅限管理令牌访问。需在请求头携带 `X-Admin-Token`。
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/handlers.SwaggerProductListBody'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
      security:
      - AdminToken: []
      summary: 管理端获取全部商品列表
      tags:
      - 管理端-商品
    post:
      consumes:
      - application/json
      description: 提交完整商品载荷：价格、卡密/固定内容、收款码链接、是否上架等。校验失败返回 400。
      parameters:
      - description: 商品各字段（含可选卡密、截图、收款码等）
        in: body
        name: body
        required: true
        schema:
          $ref: '#/definitions/handlers.ProductPayload'
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/handlers.SwaggerProductOneBody'
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
      security:
      - AdminToken: []
      summary: 管理端创建商品
      tags:
      - 管理端-商品
  /api/admin/products/{id}:
    delete:
      description: 按 ID 永久删除商品记录（影响以数据库外键/业务逻辑为准），需管理令牌。
      parameters:
      - description: 商品ID
        in: path
        name: id
        required: true
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/handlers.SwaggerBoolOKWrap'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
      security:
      - AdminToken: []
      summary: 管理端删除商品
      tags:
      - 管理端-商品
    put:
      consumes:
      - application/json
      description: 路径参数为商品 ID，请求体为整包覆盖式更新（以服务端绑定逻辑为准）。未找到则 404。
      parameters:
      - description: 商品ID
        in: path
        name: id
        required: true
        type: string
      - description: 待写入的商品字段
        in: body
        name: body
        required: true
        schema:
          $ref: '#/definitions/handlers.ProductPayload'
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/handlers.SwaggerProductOneBody'
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "404":
          description: Not Found
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
      security:
      - AdminToken: []
      summary: 管理端更新商品
      tags:
      - 管理端-商品
  /api/admin/products/{id}/status:
    patch:
      consumes:
      - application/json
      description: 'PATCH 请求体为 `{ "active": true|false }`，用于快速上下架而不改其它字段。'
      parameters:
      - description: 商品ID
        in: path
        name: id
        required: true
        type: string
      - description: 上架开关 { \
        in: body
        name: body
        required: true
        schema:
          $ref: '#/definitions/handlers.TogglePayload'
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/handlers.SwaggerProductOneBody'
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "404":
          description: Not Found
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
      security:
      - AdminToken: []
      summary: 管理端切换商品上架状态
      tags:
      - 管理端-商品
  /api/admin/site/maintenance:
    post:
      consumes:
      - application/json
      description: 打开维护后前台可展示原因文案；需管理令牌。请求体含 `maintenance` 布尔与可选 `reason`。
      parameters:
      - description: maintenance 与 reason
        in: body
        name: body
        required: true
        schema:
          $ref: '#/definitions/handlers.MaintenancePayload'
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/handlers.SwaggerMaintenanceWrap'
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
      security:
      - AdminToken: []
      summary: 设置全站维护模式
      tags:
      - 管理端-站点
  /api/admin/site/smtp:
    get:
      description: 返回当前站点发件配置；密码字段以占位符脱敏显示，不会返回明文。
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/handlers.SwaggerSMTPWrap'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
      security:
      - AdminToken: []
      summary: 获取发信 SMTP 配置（脱敏）
      tags:
      - 管理端-站点
    post:
      consumes:
      - application/json
      description: 写入 SMTP 主机、端口、账号等；若密码仍为脱敏占位符则保留库中已有密码（实现细节见服务逻辑）。
      parameters:
      - description: SMTP 连接与发件人信息
        in: body
        name: body
        required: true
        schema:
          $ref: '#/definitions/storage.SMTPConfig'
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/handlers.SwaggerStringOKBody'
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
      security:
      - AdminToken: []
      summary: 保存发信 SMTP 配置
      tags:
      - 管理端-站点
  /api/admin/system-status:
    get:
      description: 聚合展示配置摘要、数据库/MySQL、RabbitMQ、Redis 等探测结果与进程启动时间，便于运维排查；需管理令牌。
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            additionalProperties: true
            type: object
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
      security:
      - AdminToken: []
      summary: 管理端系统运行状态与依赖探活
      tags:
      - 管理端-系统
  /api/admin/verify:
    post:
      consumes:
      - application/json
      description: '请求体 JSON 含 `token` 字段；响应仅返回 `{"valid": true|false}`，不会返回真实口令或敏感信息。'
      parameters:
      - description: 待校验的管理员 token（JSON）
        in: body
        name: body
        required: true
        schema:
          $ref: '#/definitions/handlers.AdminVerifyTokenRequest'
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/handlers.SwaggerValidBody'
      summary: 校验管理端令牌是否有效
      tags:
      - 管理端-认证
  /api/chat/messages:
    get:
      description: '需在请求头携带有效的 `Authorization: Bearer <token>`。返回该登录用户在客服系统中与管理员往来的全部消息列表。'
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/handlers.SwaggerMessagesWrap'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
      security:
      - BearerAuth: []
      summary: 拉取当前用户聊天记录
      tags:
      - 聊天（用户）
    post:
      consumes:
      - application/json
      description: 需在请求头携带 Bearer。正文为 JSON `content` 字段；可能因频率限制返回 429。
      parameters:
      - description: 消息正文（JSON）
        in: body
        name: body
        required: true
        schema:
          $ref: '#/definitions/handlers.ChatMessagePayload'
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/handlers.SwaggerOneChatMsgWrap'
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "429":
          description: Too Many Requests
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
      security:
      - BearerAuth: []
      summary: 用户发送聊天消息
      tags:
      - 聊天（用户）
  /api/checkout:
    post:
      consumes:
      - application/json
      description: '根据商品配置决定是否需要登录（`requireLogin`）。可附带 `Authorization: Bearer` 以关联账号、限购与通知邮箱。付费订单走萌芽支付时需商品已配置收款码；同一商品在他人待支付锁定期内可能返回
        409；同一账号存在待支付单时也可能冲突。成功返回订单概要及二维码链接等。'
      parameters:
      - description: 可选；格式 Bearer + 空格 + token，部分商品必填
        in: header
        name: Authorization
        type: string
      - description: 结账请求体：商品、数量、联系方式等
        in: body
        name: body
        required: true
        schema:
          $ref: '#/definitions/handlers.CheckoutPayload'
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/handlers.SwaggerCheckoutWrap'
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "404":
          description: Not Found
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "409":
          description: 库存锁定冲突（他人正在支付）或同账号待支付单未满间隔
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
      summary: 结账并创建订单
      tags:
      - 订单
  /api/health:
    get:
      description: 用于负载均衡或编排探活：`status` 恒为 ok 表示 HTTP 服务存活；`rabbitmq` 为 `disabled`（未启用消息队列客户端）、`ok`（连接可用）或以
        `error:` 开头的错误片段。
      produces:
      - application/json
      responses:
        "200":
          description: 'status 为 ok；rabbitmq 为 disabled、ok 或 error: 前缀错误信息'
          schema:
            additionalProperties: true
            type: object
      summary: 健康检查
      tags:
      - 健康检查
  /api/orders:
    get:
      description: 必须携带有效 Bearer。列表中处于待支付状态的订单不会包含已分配卡密等敏感字段，防止泄露。
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/handlers.SwaggerOrdersBody'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
      security:
      - BearerAuth: []
      summary: 查询当前登录用户的订单列表
      tags:
      - 订单
  /api/orders/{id}/cancel:
    post:
      description: 仅对允许取消的状态生效（如待支付）；已完成订单会冲突。成功时释放预留库存/卡密占用。请勿在公网暴露此能力时省略鉴权策略（实现以代码为准）。
      parameters:
      - description: 订单ID
        in: path
        name: id
        required: true
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/handlers.SwaggerCancelWrap'
        "404":
          description: Not Found
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "409":
          description: Conflict
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
      summary: 取消待支付订单
      tags:
      - 订单
  /api/orders/{id}/confirm:
    post:
      description: 用于用户侧「确认」动作：已完成订单直接返回数据；待支付时若仍未到账则 409；已取消或超时 410。手动发货等场景下会触发邮件通知（若配置）。
      parameters:
      - description: 订单ID
        in: path
        name: id
        required: true
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/handlers.SwaggerConfirmWrap'
        "404":
          description: Not Found
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "409":
          description: 待支付但金额未核对到账等
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "410":
          description: 订单已取消或已超过待支付时限
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
      summary: 确认订单（核销/完成流程）
      tags:
      - 订单
  /api/orders/{id}/payment-status:
    get:
      description: 供前端轮询待支付订单：返回状态、应付快照、过期时间等；不包含卡密等敏感发货内容。路径参数为订单 ID。
      parameters:
      - description: 订单ID
        in: path
        name: id
        required: true
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/handlers.SwaggerPaymentStatusWrap'
        "404":
          description: Not Found
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
      summary: 查询订单支付状态（轮询）
      tags:
      - 订单
  /api/products:
    get:
      description: 返回当前处于「上架」状态的商品集合，仅包含前台展示所需字段（不含卡密、管理字段等）。无需登录。
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/handlers.SwaggerProductListBody'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
      summary: 获取上架商品列表
      tags:
      - 公开
  /api/products/{id}/view:
    post:
      description: 对指定商品增加浏览计数；是否计入由服务端对访客指纹去重策略决定，用于热门统计。路径参数为商品 ID。
      parameters:
      - description: 商品ID（路径）
        in: path
        name: id
        required: true
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/handlers.SwaggerProductViewWrap'
        "404":
          description: Not Found
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
      summary: 记录商品浏览次数
      tags:
      - 公开
  /api/site/maintenance:
    get:
      description: 返回当前是否开启全站维护、以及展示给前端的维护原因文案（公开接口，无需管理令牌）。
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/handlers.SwaggerMaintenanceWrap'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
      summary: 获取维护模式状态
      tags:
      - 公开
  /api/site/visit:
    post:
      description: 记录访客一次访问并累加全站访问计数；是否计入由服务端指纹等策略决定，响应中含最新总访问量与本次是否计入。
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/handlers.SwaggerVisitWrap'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
      summary: 上报一次站点访问
      tags:
      - 公开
  /api/stats:
    get:
      description: 返回全站累计订单数与累计访问量（公开读，用于首页展示等）。
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/handlers.SwaggerStatsWrap'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
      summary: 获取站点聚合统计
      tags:
      - 公开
  /api/webhooks/mengya-pay:
    post:
      consumes:
      - application/json
      description: 由支付渠道/转发服务 POST 原始 JSON；服务端解析到账金额并尝试匹配待支付订单。若配置 `WEBHOOK_MENGYA_SECRET`，请求头
        `X-Webhook-Secret` 必须与其一致。本地联调与生产 `https://store.shumengya.top` 均使用同一路径，由部署时的域名与
        TLS 决定回调 URL。
      parameters:
      - description: 与进程环境变量 WEBHOOK_MENGYA_SECRET 一致；未配置密钥时可不填
        in: header
        name: X-Webhook-Secret
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/handlers.SwaggerWebhookMengyaResp'
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "403":
          description: Forbidden
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
      summary: 萌芽支付到账 Webhook
      tags:
      - Webhook
  /api/wishlist:
    get:
      description: 需 Bearer 登录。返回该账号已收藏的商品 ID 数组（顺序由存储实现决定）。
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/handlers.SwaggerWishlistWrap'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
      security:
      - BearerAuth: []
      summary: 获取当前用户收藏列表
      tags:
      - 收藏
    post:
      consumes:
      - application/json
      description: '需 Bearer。请求体为 `{ "productId": "..." }`；幂等语义由存储层实现（重复添加可忽略或报错以实际为准）。'
      parameters:
      - description: 包含 productId 的 JSON
        in: body
        name: body
        required: true
        schema:
          $ref: '#/definitions/handlers.WishlistItemPayload'
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/handlers.SwaggerWishlistWrap'
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
      security:
      - BearerAuth: []
      summary: 添加商品到收藏
      tags:
      - 收藏
  /api/wishlist/{id}:
    delete:
      description: 需 Bearer。路径参数为要移除的商品 ID。
      parameters:
      - description: 商品ID（路径）
        in: path
        name: id
        required: true
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/handlers.SwaggerWishlistWrap'
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/handlers.SwaggerErrorBody'
      security:
      - BearerAuth: []
      summary: 从收藏中移除商品
      tags:
      - 收藏
schemes:
- http
- https
securityDefinitions:
  AdminToken:
    description: 管理端访问令牌：与进程环境变量 `ADMIN_TOKEN` 一致。部分管理路由也可使用 `Authorization` 头或 Query
      `token`（以具体路由实现为准）。
    in: header
    name: X-Admin-Token
    type: apiKey
  BearerAuth:
    description: 用户访问令牌：请求头 `Authorization`，值为 `Bearer ` 后接 SproutGate 返回的 JWT/access
      token（部分公开接口可不携带）。
    in: header
    name: Authorization
    type: apiKey
  WebhookSecret:
    description: 当服务端配置了 `WEBHOOK_MENGYA_SECRET` 时，萌芽支付到账回调 `POST /api/webhooks/mengya-pay`
      需携带本头且值与密钥完全一致，否则返回 403。
    in: header
    name: X-Webhook-Secret
    type: apiKey
swagger: "2.0"
