openapi: 3.0.3
info:
  title: 君鸿卡管系统 API
  description: |
    Card Management System API with unified response format and middleware integration.

    ## Unified Response Format

    All API endpoints return responses in the following unified format:

    ```json
    {
      "code": 0,
      "data": {},
      "msg": "success",
      "timestamp": "2025-11-10T15:30:45Z"
    }
    ```

    ## Error Codes

    | Code | HTTP Status | Description (EN) | Description (ZH) |
    |------|-------------|------------------|------------------|
    | 0    | 200         | Success | 成功 |
    | 1000 | 500         | Internal server error | 内部服务器错误 |
    | 1001 | 401         | Missing authentication token | 缺失认证令牌 |
    | 1002 | 401         | Invalid or expired token | 令牌无效或已过期 |
    | 1003 | 429         | Too many requests | 请求过于频繁 |
    | 1004 | 503         | Authentication service unavailable | 认证服务不可用 |

    ## Authentication

    Protected endpoints require a valid authentication token in the request header:

    ```
    token: your-auth-token-here
    ```

    ## Request Tracing

    Every response includes an `X-Request-ID` header containing a unique UUID v4 identifier for request tracing and correlation.

  version: 0.0.1
  contact:
    name: API Support
    email: support@example.com

servers:
  - url: http://localhost:3000
    description: Development server
  - url: https://api-staging.example.com
    description: Staging server
  - url: https://api.example.com
    description: Production server

tags:
  - name: health
    description: Health check and system status
  - name: users
    description: User management (example endpoints)

paths:
  /health:
    get:
      tags:
        - health
      summary: Health check endpoint
      description: Returns system health status. No authentication required.
      operationId: getHealth
      responses:
        '200':
          description: System is healthy
          headers:
            X-Request-ID:
              $ref: '#/components/headers/X-Request-ID'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SuccessResponse'
              example:
                code: 0
                data:
                  status: "healthy"
                  timestamp: "2025-11-10T15:30:45Z"
                msg: "success"
                timestamp: "2025-11-10T15:30:45Z"

  /api/v1/users:
    get:
      tags:
        - users
      summary: List users (example endpoint)
      description: |
        Returns a list of users. Demonstrates middleware integration:
        - Request ID generation
        - Authentication (keyauth)
        - Access logging
        - Rate limiting (if enabled)
      operationId: listUsers
      security:
        - TokenAuth: []
      parameters:
        - name: page
          in: query
          description: Page number (1-indexed)
          schema:
            type: integer
            default: 1
            minimum: 1
        - name: page_size
          in: query
          description: Number of items per page
          schema:
            type: integer
            default: 20
            minimum: 1
            maximum: 100
      responses:
        '200':
          description: Successfully retrieved user list
          headers:
            X-Request-ID:
              $ref: '#/components/headers/X-Request-ID'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SuccessResponse'
              example:
                code: 0
                data:
                  - id: "user-123"
                    name: "John Doe"
                    email: "john@example.com"
                  - id: "user-456"
                    name: "Jane Smith"
                    email: "jane@example.com"
                msg: "success"
                timestamp: "2025-11-10T15:30:45Z"
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'

    post:
      tags:
        - users
      summary: Create user (example endpoint)
      description: Creates a new user. Requires authentication.
      operationId: createUser
      security:
        - TokenAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - name
                - email
              properties:
                name:
                  type: string
                  example: "John Doe"
                email:
                  type: string
                  format: email
                  example: "john@example.com"
      responses:
        '200':
          description: User created successfully
          headers:
            X-Request-ID:
              $ref: '#/components/headers/X-Request-ID'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SuccessResponse'
              example:
                code: 0
                data:
                  id: "user-789"
                  name: "John Doe"
                  email: "john@example.com"
                  created_at: "2025-11-10T15:30:45Z"
                msg: "success"
                timestamp: "2025-11-10T15:30:45Z"
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /api/v1/users/{id}:
    get:
      tags:
        - users
      summary: Get user by ID (example endpoint)
      description: Returns a single user by ID. Requires authentication.
      operationId: getUserByID
      security:
        - TokenAuth: []
      parameters:
        - name: id
          in: path
          required: true
          description: User ID
          schema:
            type: string
            example: "user-123"
      responses:
        '200':
          description: Successfully retrieved user
          headers:
            X-Request-ID:
              $ref: '#/components/headers/X-Request-ID'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SuccessResponse'
              example:
                code: 0
                data:
                  id: "user-123"
                  name: "John Doe"
                  email: "john@example.com"
                  created_at: "2025-11-10T15:00:00Z"
                msg: "success"
                timestamp: "2025-11-10T15:30:45Z"
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: User not found
          headers:
            X-Request-ID:
              $ref: '#/components/headers/X-Request-ID'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                code: 2001
                data: null
                msg: "User not found"
                timestamp: "2025-11-10T15:30:45Z"
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/InternalServerError'

components:
  securitySchemes:
    TokenAuth:
      type: apiKey
      in: header
      name: token
      description: Authentication token stored in Redis (token → user ID mapping)

  headers:
    X-Request-ID:
      description: Unique request identifier (UUID v4) for tracing and correlation
      schema:
        type: string
        format: uuid
        example: "550e8400-e29b-41d4-a716-446655440000"

  schemas:
    SuccessResponse:
      type: object
      required:
        - code
        - data
        - msg
        - timestamp
      properties:
        code:
          type: integer
          description: Application status code (0 = success)
          example: 0
        data:
          description: Response data (object, array, or null)
          oneOf:
            - type: object
            - type: array
            - type: 'null'
        msg:
          type: string
          description: Human-readable message
          example: "success"
        timestamp:
          type: string
          format: date-time
          description: Response timestamp in ISO 8601 format (RFC3339)
          example: "2025-11-10T15:30:45Z"

    ErrorResponse:
      type: object
      required:
        - code
        - data
        - msg
        - timestamp
      properties:
        code:
          type: integer
          description: Application error code (non-zero)
          example: 1002
        data:
          type: 'null'
          description: Always null for error responses
          example: null
        msg:
          type: string
          description: Error message (bilingual support)
          example: "Invalid or expired token"
        timestamp:
          type: string
          format: date-time
          description: Response timestamp in ISO 8601 format (RFC3339)
          example: "2025-11-10T15:30:45Z"

  responses:
    Unauthorized:
      description: Authentication failed
      headers:
        X-Request-ID:
          $ref: '#/components/headers/X-Request-ID'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            missing_token:
              summary: Missing token
              value:
                code: 1001
                data: null
                msg: "Missing authentication token"
                timestamp: "2025-11-10T15:30:45Z"
            invalid_token:
              summary: Invalid or expired token
              value:
                code: 1002
                data: null
                msg: "Invalid or expired token"
                timestamp: "2025-11-10T15:30:45Z"

    TooManyRequests:
      description: Rate limit exceeded
      headers:
        X-Request-ID:
          $ref: '#/components/headers/X-Request-ID'
        Retry-After:
          description: Number of seconds to wait before retrying
          schema:
            type: integer
            example: 60
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            code: 1003
            data: null
            msg: "Too many requests"
            timestamp: "2025-11-10T15:30:45Z"

    InternalServerError:
      description: Internal server error
      headers:
        X-Request-ID:
          $ref: '#/components/headers/X-Request-ID'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            code: 1000
            data: null
            msg: "Internal server error"
            timestamp: "2025-11-10T15:30:45Z"

    ServiceUnavailable:
      description: Service unavailable (e.g., Redis down)
      headers:
        X-Request-ID:
          $ref: '#/components/headers/X-Request-ID'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            code: 1004
            data: null
            msg: "Authentication service unavailable"
            timestamp: "2025-11-10T15:30:45Z"

  examples:
    SuccessWithObject:
      summary: Success response with object data
      value:
        code: 0
        data:
          id: "user-123"
          name: "John Doe"
        msg: "success"
        timestamp: "2025-11-10T15:30:45Z"

    SuccessWithArray:
      summary: Success response with array data
      value:
        code: 0
        data:
          - id: "1"
            name: "Item 1"
          - id: "2"
            name: "Item 2"
        msg: "success"
        timestamp: "2025-11-10T15:30:45Z"

    SuccessWithNull:
      summary: Success response with null data
      value:
        code: 0
        data: null
        msg: "Operation completed"
        timestamp: "2025-11-10T15:30:45Z"
