openapi: 3.1.0
info:
  title: DesignGen Developer API
  version: 1.0.0
  description: |
    Public DTF halftone endpoint and developer key management endpoints.
servers:
  - url: https://your-domain.com
    description: Production
  - url: http://localhost:3000
    description: Local development
security:
  - bearerAuth: []
paths:
  /api/v1/dtf-halftone:
    post:
      tags:
        - DTF Halftone
      summary: Run DTF halftone processing
      description: |
        Processes an input image URL using ordered dot-screen DTF halftoning.
        Requires Authorization bearer token (Firebase ID token or developer API key)
        from a Pro or Enterprise account.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DtfHalftoneRequest'
            examples:
              default:
                value:
                  imageUrl: https://example.com/input.png
                  dtfHalftone: 40
                  dtfHalftoneAngle: 90
      responses:
        '200':
          description: Successful processing
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DtfHalftoneSuccessResponse'
        '400':
          description: Invalid request payload
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '402':
          description: Insufficient tokens
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Pro subscription required or insufficient API key scope
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '413':
          description: Source image too large
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Source image validation/decode failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Internal error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '502':
          description: Upstream worker failure
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

  /api/v1/design-analysis:
    post:
      tags:
        - Design Analysis
      summary: Analyze a design image for naming, search, and mockup metadata
      description: |
        Analyzes an HTTPS image URL and returns structured naming, search, and mockup recommendation data.
        Requires Authorization bearer token (Firebase ID token or developer API key)
        from a Pro or Enterprise account.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DesignAnalysisRequest'
      responses:
        '200':
          description: Successful analysis
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DesignAnalysisSuccessResponse'
        '400':
          description: Invalid request payload
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Pro subscription required or insufficient API key scope
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Internal error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

  /api/v1/developer/api-keys:
    get:
      tags:
        - Developer Keys
      summary: List developer API keys
      description: Requires Firebase bearer token from a Pro or Enterprise account.
      parameters:
        - in: query
          name: limit
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 100
      responses:
        '200':
          description: API key list
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListApiKeysResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Pro subscription required
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Internal error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

    post:
      tags:
        - Developer Keys
      summary: Create developer API key
      description: |
        Requires Firebase bearer token from a Pro or Enterprise account.
        Plaintext API key is returned once and cannot be fetched again.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateApiKeyRequest'
            examples:
              dtfOnly:
                value:
                  name: Production Integration
                  scopes:
                    - dtf_halftone
              wildcard:
                value:
                  name: Trusted Backend
                  scopes:
                    - '*'
      responses:
        '200':
          description: API key created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateApiKeyResponse'
        '400':
          description: Invalid request payload
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Pro subscription required
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Internal error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

  /api/v1/developer/api-keys/{keyId}:
    delete:
      tags:
        - Developer Keys
      summary: Revoke developer API key
      description: Requires Firebase bearer token from a Pro or Enterprise account.
      parameters:
        - in: path
          name: keyId
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Key revoked
          content:
            application/json:
              schema:
                type: object
                required:
                  - success
                  - keyId
                  - status
                properties:
                  success:
                    type: boolean
                    const: true
                  keyId:
                    type: string
                  status:
                    type: string
                    const: revoked
        '400':
          description: Missing/invalid key ID
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Pro subscription required
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Key not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Internal error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

  /api/v1/developer/usage:
    get:
      tags:
        - Developer Usage
      summary: List developer usage history
      description: |
        Requires Firebase bearer token from a Pro or Enterprise account.
        Supports filtering by API key and date range, with server-side pagination.
      parameters:
        - in: query
          name: limit
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 25
        - in: query
          name: page
          schema:
            type: integer
            minimum: 1
            default: 1
        - in: query
          name: offset
          schema:
            type: integer
            minimum: 0
            description: Optional. If provided, overrides page.
        - in: query
          name: apiKeyId
          schema:
            type: string
        - in: query
          name: startDate
          schema:
            type: string
            format: date-time
          description: ISO datetime or YYYY-MM-DD
        - in: query
          name: endDate
          schema:
            type: string
            format: date-time
          description: ISO datetime or YYYY-MM-DD (interpreted as end-of-day)
      responses:
        '200':
          description: Usage history
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListUsageResponse'
        '400':
          description: Invalid date/filter params
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Pro subscription required
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Internal error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT or API Key

  schemas:
    ErrorResponse:
      type: object
      properties:
        success:
          type: boolean
          default: false
        error:
          type: string
        code:
          type: string
        details:
          oneOf:
            - type: object
              additionalProperties: true
            - type: array
            - type: string
            - type: 'null'
      required:
        - error

    DtfHalftoneRequest:
      type: object
      required:
        - imageUrl
      properties:
        imageUrl:
          type: string
          format: uri
          pattern: '^https://'
        dtfHalftone:
          type: integer
          minimum: 1
          maximum: 100
          default: 70
        dtfHalftoneAngle:
          type: number
          minimum: 0
          maximum: 360
          default: 22.5
        sessionId:
          type: string
          minLength: 1
          maxLength: 256

    DtfHalftoneMetadata:
      type: object
      required:
        - requestId
        - width
        - height
        - contentType
        - cacheHit
        - outputPath
        - dtfHalftone
        - dtfHalftoneAngle
      properties:
        requestId:
          type: string
        width:
          type: integer
        height:
          type: integer
        contentType:
          type: string
        cacheHit:
          type: boolean
        outputPath:
          type: string
        dtfHalftone:
          type: integer
        dtfHalftoneAngle:
          type: number

    DtfHalftoneSuccessResponse:
      type: object
      required:
        - success
        - imageUrl
        - processingType
        - tokenCost
        - metadata
      properties:
        success:
          type: boolean
          const: true
        imageUrl:
          type: string
          format: uri
        processingType:
          type: string
          const: dtf-halftone
        tokenCost:
          type: integer
          const: 10
        metadata:
          $ref: '#/components/schemas/DtfHalftoneMetadata'

    DesignAnalysisRequest:
      type: object
      required:
        - imageUrl
      properties:
        imageUrl:
          type: string
          format: uri
          pattern: '^https://'
        designPrompt:
          type: string
          maxLength: 4000
        metadata:
          type: object
          additionalProperties: true

    DesignRiskSummary:
      type: object
      properties:
        high:
          type: integer
        medium:
          type: integer
        low:
          type: integer

    DesignMockupAudience:
      type: object
      properties:
        ageBand:
          type: string
        genderPresentation:
          type: string
        audienceTags:
          type: array
          items:
            type: string
        stylePersona:
          type: string

    DesignMockupModelRecommendation:
      type: object
      properties:
        presentation:
          type: string
        ageBand:
          type: string
        vibe:
          type: string
        pose:
          type: string
        setting:
          type: string
        reasoning:
          type: string

    DesignMockupGarmentRecommendation:
      type: object
      properties:
        styleCode:
          type: string
          enum:
            - BC3001
            - '1717'
        brand:
          type: string
        colorKey:
          type: string
        displayColorName:
          type: string
        reasoning:
          type: string

    DesignAnalysisResponseBody:
      type: object
      properties:
        canonicalTitle:
          type: string
        filenameStem:
          type: string
        primarySubject:
          type: string
        secondarySubjects:
          type: array
          items:
            type: string
        styleTags:
          type: array
          items:
            type: string
        intendedUseGuess:
          type: string
        contrastAssessment:
          type: string
        assetTypeGuess:
          type: string
        transparencyDetected:
          type: boolean
        paletteHexes:
          type: array
          items:
            type: string
        detectedTextSnippets:
          type: array
          items:
            type: string
        detectedBrandTerms:
          type: array
          items:
            type: string
        riskSummary:
          $ref: '#/components/schemas/DesignRiskSummary'
        searchKeywords:
          type: array
          items:
            type: string
        searchSummary:
          type: string
        mockupAudience:
          $ref: '#/components/schemas/DesignMockupAudience'
        mockupModelRecommendation:
          $ref: '#/components/schemas/DesignMockupModelRecommendation'
        mockupGarmentRecommendation:
          $ref: '#/components/schemas/DesignMockupGarmentRecommendation'
        metadata:
          type: object
          additionalProperties: true

    DesignAnalysisSuccessResponse:
      type: object
      required:
        - success
        - analysis
      properties:
        success:
          type: boolean
          const: true
        analysis:
          $ref: '#/components/schemas/DesignAnalysisResponseBody'

    CreateApiKeyRequest:
      type: object
      required:
        - name
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 64
        scopes:
          type: array
          maxItems: 20
          items:
            oneOf:
              - type: string
                enum:
                  - dtf_halftone
                  - design_analysis
                  - usage_read
                  - files_read
                  - '*'
              - type: string
                pattern: '^[a-z][a-z0-9_:-]*$'

    ApiKey:
      type: object
      required:
        - id
        - name
        - keyPrefix
        - last4
        - scopes
      properties:
        id:
          type: string
        name:
          type: string
        keyPrefix:
          type: string
        last4:
          type: string
        scopes:
          type: array
          items:
            type: string
        status:
          type: string
          enum: [active, revoked]
        usageCount:
          type: integer
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        lastUsedAt:
          oneOf:
            - type: string
              format: date-time
            - type: 'null'
        revokedAt:
          oneOf:
            - type: string
              format: date-time
            - type: 'null'

    ListApiKeysResponse:
      type: object
      required:
        - success
        - keys
        - availableScopes
      properties:
        success:
          type: boolean
          const: true
        keys:
          type: array
          items:
            $ref: '#/components/schemas/ApiKey'
        availableScopes:
          type: array
          items:
            type: string
            enum:
              - dtf_halftone
              - usage_read
              - files_read
              - '*'

    CreateApiKeyResponse:
      type: object
      required:
        - success
        - apiKey
        - key
        - availableScopes
      properties:
        success:
          type: boolean
          const: true
        apiKey:
          type: string
        availableScopes:
          type: array
          items:
            type: string
            enum:
              - dtf_halftone
              - usage_read
              - files_read
              - '*'
        key:
          type: object
          required:
            - id
            - name
            - keyPrefix
            - last4
            - scopes
            - createdAt
          properties:
            id:
              type: string
            name:
              type: string
            keyPrefix:
              type: string
            last4:
              type: string
            scopes:
              type: array
              items:
                type: string
            createdAt:
              type: string
              format: date-time
        note:
          type: string

    UsageItem:
      type: object
      required:
        - id
        - userId
        - apiKeyId
        - route
        - method
        - statusCode
        - success
        - latencyMs
        - timestamp
      properties:
        id:
          type: string
        userId:
          type: string
        apiKeyId:
          type: string
        route:
          type: string
        method:
          type: string
        statusCode:
          type: integer
        success:
          type: boolean
        latencyMs:
          type: number
        operationType:
          oneOf:
            - type: string
            - type: 'null'
        tokenCost:
          oneOf:
            - type: number
            - type: 'null'
        requestId:
          oneOf:
            - type: string
            - type: 'null'
        outputUrl:
          oneOf:
            - type: string
              format: uri
            - type: 'null'
        metadata:
          oneOf:
            - type: object
              additionalProperties: true
            - type: 'null'
        timestamp:
          type: string
          format: date-time

    UsagePagination:
      type: object
      required:
        - limit
        - offset
        - hasMore
        - nextOffset
      properties:
        limit:
          type: integer
        offset:
          type: integer
        page:
          oneOf:
            - type: integer
            - type: 'null'
        pageCount:
          oneOf:
            - type: integer
            - type: 'null'
        hasMore:
          type: boolean
        nextOffset:
          oneOf:
            - type: integer
            - type: 'null'

    ListUsageResponse:
      type: object
      required:
        - success
        - usage
        - count
        - total
        - pagination
      properties:
        success:
          type: boolean
          const: true
        usage:
          type: array
          items:
            $ref: '#/components/schemas/UsageItem'
        count:
          type: integer
        total:
          type: integer
        pagination:
          $ref: '#/components/schemas/UsagePagination'
        filters:
          type: object
          properties:
            apiKeyId:
              oneOf:
                - type: string
                - type: 'null'
            startDate:
              oneOf:
                - type: string
                  format: date-time
                - type: 'null'
            endDate:
              oneOf:
                - type: string
                  format: date-time
                - type: 'null'
