openapi: 3.1.0
info:
  title: Api
  version: 0.1.0
  description: CryptoEx Trading Platform API
servers:
  - url: /api
    description: Base API path
tags:
  - name: health
    description: Health operations
  - name: auth
    description: Authentication operations
  - name: users
    description: User management
  - name: kyc
    description: KYC verification
  - name: wallet
    description: Wallet operations
  - name: trading
    description: Trading operations
  - name: orders
    description: Order management
  - name: escrow
    description: Escrow transactions
  - name: admin
    description: Admin operations
  - name: market
    description: Market data
paths:
  /healthz:
    get:
      operationId: healthCheck
      tags: [health]
      summary: Health check
      responses:
        "200":
          description: Healthy
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/HealthStatus"

  # Auth
  /auth/register:
    post:
      operationId: register
      tags: [auth]
      summary: Register a new user
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/RegisterRequest"
      responses:
        "201":
          description: Created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AuthResponse"
        "400":
          description: Bad request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /auth/login:
    post:
      operationId: login
      tags: [auth]
      summary: Login user
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/LoginRequest"
      responses:
        "200":
          description: Success
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AuthResponse"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /auth/logout:
    post:
      operationId: logout
      tags: [auth]
      summary: Logout user
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Logged out
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MessageResponse"

  /auth/verify-email:
    post:
      operationId: verifyEmail
      tags: [auth]
      summary: Verify email with token
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/VerifyEmailRequest"
      responses:
        "200":
          description: Verified
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MessageResponse"

  /auth/2fa/setup:
    post:
      operationId: setup2fa
      tags: [auth]
      summary: Setup 2FA (returns QR code URL)
      security:
        - bearerAuth: []
      responses:
        "200":
          description: 2FA setup
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TwoFaSetupResponse"

  /auth/2fa/verify:
    post:
      operationId: verify2fa
      tags: [auth]
      summary: Verify 2FA token
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TwoFaVerifyRequest"
      responses:
        "200":
          description: Verified
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MessageResponse"

  # Users
  /users/me:
    get:
      operationId: getMe
      tags: [users]
      summary: Get current user profile
      security:
        - bearerAuth: []
      responses:
        "200":
          description: User profile
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/User"

    patch:
      operationId: updateMe
      tags: [users]
      summary: Update current user profile
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdateUserRequest"
      responses:
        "200":
          description: Updated user
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/User"

  # KYC
  /kyc/submit:
    post:
      operationId: submitKyc
      tags: [kyc]
      summary: Submit KYC documents
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/KycSubmitRequest"
      responses:
        "200":
          description: Submitted
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/KycRecord"

  /kyc/status:
    get:
      operationId: getKycStatus
      tags: [kyc]
      summary: Get KYC status
      security:
        - bearerAuth: []
      responses:
        "200":
          description: KYC status
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/KycRecord"

  # Wallet
  /wallet/balances:
    get:
      operationId: getWalletBalances
      tags: [wallet]
      summary: Get wallet balances
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Balances
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/WalletBalance"

  /wallet/deposit:
    post:
      operationId: deposit
      tags: [wallet]
      summary: Simulate deposit
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DepositRequest"
      responses:
        "200":
          description: Deposit recorded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Transaction"

  /wallet/withdraw:
    post:
      operationId: withdraw
      tags: [wallet]
      summary: Withdraw funds
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/WithdrawRequest"
      responses:
        "200":
          description: Withdrawal requested
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Transaction"

  /wallet/transactions:
    get:
      operationId: getTransactions
      tags: [wallet]
      summary: Get transaction history
      security:
        - bearerAuth: []
      parameters:
        - name: page
          in: query
          schema:
            type: integer
            default: 1
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
        - name: type
          in: query
          schema:
            type: string
            enum: [deposit, withdrawal, trade, escrow, fee]
      responses:
        "200":
          description: Transactions
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PaginatedTransactions"

  # Trading / Market
  /market/pairs:
    get:
      operationId: getTradingPairs
      tags: [market]
      summary: Get all trading pairs
      responses:
        "200":
          description: Trading pairs
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/TradingPair"

  /market/ticker/{pair}:
    get:
      operationId: getTicker
      tags: [market]
      summary: Get ticker for a pair
      parameters:
        - name: pair
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Ticker data
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Ticker"

  /market/orderbook/{pair}:
    get:
      operationId: getOrderBook
      tags: [market]
      summary: Get order book for a pair
      parameters:
        - name: pair
          in: path
          required: true
          schema:
            type: string
        - name: depth
          in: query
          schema:
            type: integer
            default: 20
      responses:
        "200":
          description: Order book
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/OrderBook"

  /market/trades/{pair}:
    get:
      operationId: getRecentTrades
      tags: [market]
      summary: Get recent trades for a pair
      parameters:
        - name: pair
          in: path
          required: true
          schema:
            type: string
        - name: limit
          in: query
          schema:
            type: integer
            default: 50
      responses:
        "200":
          description: Recent trades
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Trade"

  /market/klines/{pair}:
    get:
      operationId: getKlines
      tags: [market]
      summary: Get candlestick data
      parameters:
        - name: pair
          in: path
          required: true
          schema:
            type: string
        - name: interval
          in: query
          schema:
            type: string
            enum: [1m, 5m, 15m, 1h, 4h, 1d]
            default: 1h
        - name: limit
          in: query
          schema:
            type: integer
            default: 100
      responses:
        "200":
          description: Candlestick data
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Kline"

  # Orders
  /orders:
    post:
      operationId: placeOrder
      tags: [orders]
      summary: Place a new order
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PlaceOrderRequest"
      responses:
        "201":
          description: Order placed
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Order"

    get:
      operationId: getMyOrders
      tags: [orders]
      summary: Get my orders
      security:
        - bearerAuth: []
      parameters:
        - name: status
          in: query
          schema:
            type: string
            enum: [open, filled, cancelled, partial]
        - name: pair
          in: query
          schema:
            type: string
        - name: page
          in: query
          schema:
            type: integer
            default: 1
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
      responses:
        "200":
          description: Orders
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PaginatedOrders"

  /orders/{id}:
    delete:
      operationId: cancelOrder
      tags: [orders]
      summary: Cancel an order
      security:
        - bearerAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Cancelled
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Order"

  /orders/history:
    get:
      operationId: getTradeHistory
      tags: [orders]
      summary: Get my trade history
      security:
        - bearerAuth: []
      parameters:
        - name: pair
          in: query
          schema:
            type: string
        - name: page
          in: query
          schema:
            type: integer
            default: 1
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
      responses:
        "200":
          description: Trade history
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PaginatedTrades"

  # Escrow
  /escrow:
    post:
      operationId: createEscrow
      tags: [escrow]
      summary: Create an escrow transaction
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateEscrowRequest"
      responses:
        "201":
          description: Escrow created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Escrow"

    get:
      operationId: getMyEscrows
      tags: [escrow]
      summary: Get my escrow transactions
      security:
        - bearerAuth: []
      parameters:
        - name: status
          in: query
          schema:
            type: string
            enum: [pending, locked, released, cancelled, disputed]
        - name: role
          in: query
          schema:
            type: string
            enum: [buyer, seller]
      responses:
        "200":
          description: Escrow list
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Escrow"

  /escrow/{id}:
    get:
      operationId: getEscrow
      tags: [escrow]
      summary: Get escrow details
      security:
        - bearerAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Escrow details
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Escrow"

  /escrow/{id}/fund:
    post:
      operationId: fundEscrow
      tags: [escrow]
      summary: Seller funds the escrow (locks funds)
      security:
        - bearerAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Funded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Escrow"

  /escrow/{id}/release:
    post:
      operationId: releaseEscrow
      tags: [escrow]
      summary: Buyer confirms delivery, releases funds
      security:
        - bearerAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Released
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Escrow"

  /escrow/{id}/dispute:
    post:
      operationId: disputeEscrow
      tags: [escrow]
      summary: Open a dispute on escrow
      security:
        - bearerAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DisputeRequest"
      responses:
        "200":
          description: Disputed
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Escrow"

  /escrow/{id}/cancel:
    post:
      operationId: cancelEscrow
      tags: [escrow]
      summary: Cancel escrow
      security:
        - bearerAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Cancelled
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Escrow"

  # Admin
  /admin/users:
    get:
      operationId: adminGetUsers
      tags: [admin]
      summary: Get all users (admin)
      security:
        - bearerAuth: []
      parameters:
        - name: page
          in: query
          schema:
            type: integer
            default: 1
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
        - name: search
          in: query
          schema:
            type: string
        - name: status
          in: query
          schema:
            type: string
            enum: [active, frozen, pending]
      responses:
        "200":
          description: Users list
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PaginatedUsers"

  /admin/users/{id}/freeze:
    post:
      operationId: adminFreezeUser
      tags: [admin]
      summary: Freeze a user account
      security:
        - bearerAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Frozen
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/User"

  /admin/users/{id}/unfreeze:
    post:
      operationId: adminUnfreezeUser
      tags: [admin]
      summary: Unfreeze a user account
      security:
        - bearerAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Unfrozen
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/User"

  /admin/users/{id}/balance:
    patch:
      operationId: adminAdjustBalance
      tags: [admin]
      summary: Manually adjust user balance
      security:
        - bearerAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AdminAdjustBalanceRequest"
      responses:
        "200":
          description: Adjusted
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WalletBalance"

  /admin/kyc/pending:
    get:
      operationId: adminGetPendingKyc
      tags: [admin]
      summary: Get pending KYC applications
      security:
        - bearerAuth: []
      parameters:
        - name: page
          in: query
          schema:
            type: integer
            default: 1
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
      responses:
        "200":
          description: Pending KYC list
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PaginatedKyc"

  /admin/kyc/{id}/approve:
    post:
      operationId: adminApproveKyc
      tags: [admin]
      summary: Approve KYC application
      security:
        - bearerAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Approved
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/KycRecord"

  /admin/kyc/{id}/reject:
    post:
      operationId: adminRejectKyc
      tags: [admin]
      summary: Reject KYC application
      security:
        - bearerAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AdminRejectKycRequest"
      responses:
        "200":
          description: Rejected
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/KycRecord"

  /admin/escrow/disputes:
    get:
      operationId: adminGetDisputes
      tags: [admin]
      summary: Get all disputed escrows
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Disputes
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Escrow"

  /admin/escrow/{id}/resolve:
    post:
      operationId: adminResolveDispute
      tags: [admin]
      summary: Resolve escrow dispute
      security:
        - bearerAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AdminResolveDisputeRequest"
      responses:
        "200":
          description: Resolved
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Escrow"

  /admin/transactions:
    get:
      operationId: adminGetTransactions
      tags: [admin]
      summary: Get all platform transactions
      security:
        - bearerAuth: []
      parameters:
        - name: page
          in: query
          schema:
            type: integer
            default: 1
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
        - name: type
          in: query
          schema:
            type: string
      responses:
        "200":
          description: Transactions
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PaginatedTransactions"

  /admin/analytics:
    get:
      operationId: adminGetAnalytics
      tags: [admin]
      summary: Get platform analytics
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Analytics data
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Analytics"

  /admin/fees:
    get:
      operationId: adminGetFees
      tags: [admin]
      summary: Get fee settings
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Fee settings
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/FeeSettings"

    patch:
      operationId: adminUpdateFees
      tags: [admin]
      summary: Update fee settings
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/FeeSettings"
      responses:
        "200":
          description: Updated fees
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/FeeSettings"

  /admin/logs:
    get:
      operationId: adminGetLogs
      tags: [admin]
      summary: Get system logs
      security:
        - bearerAuth: []
      parameters:
        - name: page
          in: query
          schema:
            type: integer
            default: 1
        - name: limit
          in: query
          schema:
            type: integer
            default: 50
        - name: level
          in: query
          schema:
            type: string
            enum: [info, warn, error]
      responses:
        "200":
          description: System logs
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PaginatedLogs"

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

  schemas:
    HealthStatus:
      type: object
      properties:
        status:
          type: string
      required: [status]

    ErrorResponse:
      type: object
      properties:
        error:
          type: string
        message:
          type: string
      required: [error]

    MessageResponse:
      type: object
      properties:
        message:
          type: string
      required: [message]

    # Auth
    RegisterRequest:
      type: object
      properties:
        email:
          type: string
          format: email
        password:
          type: string
          minLength: 8
        username:
          type: string
          minLength: 3
        firstName:
          type: string
        lastName:
          type: string
      required: [email, password, username, firstName, lastName]

    LoginRequest:
      type: object
      properties:
        email:
          type: string
          format: email
        password:
          type: string
        totpCode:
          type: string
      required: [email, password]

    AuthResponse:
      type: object
      properties:
        token:
          type: string
        user:
          $ref: "#/components/schemas/User"
        requiresTwoFa:
          type: boolean
      required: [token, user]

    VerifyEmailRequest:
      type: object
      properties:
        token:
          type: string
      required: [token]

    TwoFaSetupResponse:
      type: object
      properties:
        qrCodeUrl:
          type: string
        secret:
          type: string
      required: [qrCodeUrl, secret]

    TwoFaVerifyRequest:
      type: object
      properties:
        code:
          type: string
      required: [code]

    # User
    User:
      type: object
      properties:
        id:
          type: string
        email:
          type: string
        username:
          type: string
        firstName:
          type: string
        lastName:
          type: string
        role:
          type: string
          enum: [user, admin]
        status:
          type: string
          enum: [active, frozen, pending]
        emailVerified:
          type: boolean
        twoFaEnabled:
          type: boolean
        kycStatus:
          type: string
          enum: [none, pending, approved, rejected]
        createdAt:
          type: string
          format: date-time
      required: [id, email, username, role, status, emailVerified, twoFaEnabled, kycStatus, createdAt]

    UpdateUserRequest:
      type: object
      properties:
        firstName:
          type: string
        lastName:
          type: string
        username:
          type: string

    # KYC
    KycSubmitRequest:
      type: object
      properties:
        fullName:
          type: string
        dateOfBirth:
          type: string
        nationality:
          type: string
        documentType:
          type: string
          enum: [passport, national_id, drivers_license]
        documentNumber:
          type: string
        documentFrontUrl:
          type: string
        documentBackUrl:
          type: string
        selfieUrl:
          type: string
        address:
          type: string
        city:
          type: string
        country:
          type: string
      required: [fullName, dateOfBirth, nationality, documentType, documentNumber, address, city, country]

    KycRecord:
      type: object
      properties:
        id:
          type: string
        userId:
          type: string
        status:
          type: string
          enum: [pending, approved, rejected]
        fullName:
          type: string
        documentType:
          type: string
        nationality:
          type: string
        rejectionReason:
          type: string
        submittedAt:
          type: string
          format: date-time
        reviewedAt:
          type: string
          format: date-time
      required: [id, userId, status, submittedAt]

    # Wallet
    WalletBalance:
      type: object
      properties:
        currency:
          type: string
        available:
          type: string
        locked:
          type: string
        total:
          type: string
      required: [currency, available, locked, total]

    DepositRequest:
      type: object
      properties:
        currency:
          type: string
        amount:
          type: string
        txHash:
          type: string
      required: [currency, amount]

    WithdrawRequest:
      type: object
      properties:
        currency:
          type: string
        amount:
          type: string
        address:
          type: string
        network:
          type: string
      required: [currency, amount, address]

    Transaction:
      type: object
      properties:
        id:
          type: string
        userId:
          type: string
        type:
          type: string
          enum: [deposit, withdrawal, trade, escrow, fee]
        currency:
          type: string
        amount:
          type: string
        fee:
          type: string
        status:
          type: string
          enum: [pending, completed, failed, cancelled]
        description:
          type: string
        txHash:
          type: string
        createdAt:
          type: string
          format: date-time
      required: [id, userId, type, currency, amount, status, createdAt]

    PaginatedTransactions:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/Transaction"
        total:
          type: integer
        page:
          type: integer
        limit:
          type: integer
      required: [data, total, page, limit]

    # Market
    TradingPair:
      type: object
      properties:
        symbol:
          type: string
        baseAsset:
          type: string
        quoteAsset:
          type: string
        lastPrice:
          type: string
        priceChange24h:
          type: string
        priceChangePercent24h:
          type: string
        volume24h:
          type: string
        high24h:
          type: string
        low24h:
          type: string
        status:
          type: string
          enum: [active, inactive]
      required: [symbol, baseAsset, quoteAsset, lastPrice, status]

    Ticker:
      type: object
      properties:
        symbol:
          type: string
        lastPrice:
          type: string
        bidPrice:
          type: string
        askPrice:
          type: string
        priceChange24h:
          type: string
        priceChangePercent24h:
          type: string
        volume24h:
          type: string
        high24h:
          type: string
        low24h:
          type: string
        timestamp:
          type: string
          format: date-time
      required: [symbol, lastPrice, timestamp]

    OrderBook:
      type: object
      properties:
        symbol:
          type: string
        bids:
          type: array
          items:
            type: array
            items:
              type: string
        asks:
          type: array
          items:
            type: array
            items:
              type: string
        timestamp:
          type: string
          format: date-time
      required: [symbol, bids, asks, timestamp]

    Trade:
      type: object
      properties:
        id:
          type: string
        symbol:
          type: string
        price:
          type: string
        quantity:
          type: string
        side:
          type: string
          enum: [buy, sell]
        timestamp:
          type: string
          format: date-time
      required: [id, symbol, price, quantity, side, timestamp]

    Kline:
      type: object
      properties:
        openTime:
          type: string
          format: date-time
        open:
          type: string
        high:
          type: string
        low:
          type: string
        close:
          type: string
        volume:
          type: string
        closeTime:
          type: string
          format: date-time
      required: [openTime, open, high, low, close, volume, closeTime]

    # Orders
    PlaceOrderRequest:
      type: object
      properties:
        symbol:
          type: string
        side:
          type: string
          enum: [buy, sell]
        type:
          type: string
          enum: [market, limit]
        quantity:
          type: string
        price:
          type: string
      required: [symbol, side, type, quantity]

    Order:
      type: object
      properties:
        id:
          type: string
        userId:
          type: string
        symbol:
          type: string
        side:
          type: string
          enum: [buy, sell]
        type:
          type: string
          enum: [market, limit]
        status:
          type: string
          enum: [open, filled, cancelled, partial]
        quantity:
          type: string
        price:
          type: string
        filledQuantity:
          type: string
        averagePrice:
          type: string
        fee:
          type: string
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
      required: [id, userId, symbol, side, type, status, quantity, createdAt, updatedAt]

    PaginatedOrders:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/Order"
        total:
          type: integer
        page:
          type: integer
        limit:
          type: integer
      required: [data, total, page, limit]

    PaginatedTrades:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/Trade"
        total:
          type: integer
        page:
          type: integer
        limit:
          type: integer
      required: [data, total, page, limit]

    # Escrow
    CreateEscrowRequest:
      type: object
      properties:
        sellerUserId:
          type: string
        currency:
          type: string
        amount:
          type: string
        description:
          type: string
        timeoutHours:
          type: integer
          default: 24
      required: [sellerUserId, currency, amount, description]

    Escrow:
      type: object
      properties:
        id:
          type: string
        buyerUserId:
          type: string
        sellerUserId:
          type: string
        currency:
          type: string
        amount:
          type: string
        fee:
          type: string
        netAmount:
          type: string
        status:
          type: string
          enum: [pending, locked, released, cancelled, disputed]
        description:
          type: string
        disputeReason:
          type: string
        adminNotes:
          type: string
        timeoutAt:
          type: string
          format: date-time
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
      required: [id, buyerUserId, sellerUserId, currency, amount, status, createdAt, updatedAt]

    DisputeRequest:
      type: object
      properties:
        reason:
          type: string
      required: [reason]

    AdminResolveDisputeRequest:
      type: object
      properties:
        decision:
          type: string
          enum: [release_to_seller, refund_to_buyer]
        notes:
          type: string
      required: [decision]

    # Admin
    PaginatedUsers:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/User"
        total:
          type: integer
        page:
          type: integer
        limit:
          type: integer
      required: [data, total, page, limit]

    PaginatedKyc:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/KycRecord"
        total:
          type: integer
        page:
          type: integer
        limit:
          type: integer
      required: [data, total, page, limit]

    AdminAdjustBalanceRequest:
      type: object
      properties:
        currency:
          type: string
        amount:
          type: string
        reason:
          type: string
      required: [currency, amount, reason]

    AdminRejectKycRequest:
      type: object
      properties:
        reason:
          type: string
      required: [reason]

    Analytics:
      type: object
      properties:
        totalUsers:
          type: integer
        activeUsers24h:
          type: integer
        totalTrades24h:
          type: integer
        totalVolume24h:
          type: string
        totalRevenue24h:
          type: string
        totalRevenue:
          type: string
        pendingWithdrawals:
          type: integer
        pendingKyc:
          type: integer
        openDisputes:
          type: integer
        dailyStats:
          type: array
          items:
            $ref: "#/components/schemas/DailyStat"
      required: [totalUsers, activeUsers24h, totalTrades24h, totalVolume24h, totalRevenue24h, totalRevenue, pendingWithdrawals, pendingKyc, openDisputes, dailyStats]

    DailyStat:
      type: object
      properties:
        date:
          type: string
        trades:
          type: integer
        volume:
          type: string
        revenue:
          type: string
        newUsers:
          type: integer
      required: [date, trades, volume, revenue, newUsers]

    FeeSettings:
      type: object
      properties:
        tradingFeePercent:
          type: string
        escrowFeePercent:
          type: string
        withdrawalFeePercent:
          type: string
        minWithdrawalAmount:
          type: string
      required: [tradingFeePercent, escrowFeePercent, withdrawalFeePercent, minWithdrawalAmount]

    SystemLog:
      type: object
      properties:
        id:
          type: string
        level:
          type: string
          enum: [info, warn, error]
        message:
          type: string
        userId:
          type: string
        action:
          type: string
        metadata:
          type: object
          additionalProperties: true
        createdAt:
          type: string
          format: date-time
      required: [id, level, message, action, createdAt]

    PaginatedLogs:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/SystemLog"
        total:
          type: integer
        page:
          type: integer
        limit:
          type: integer
      required: [data, total, page, limit]
