openapi: 3.0.3
info:
  title: Articles API - V1
  version: 1.3.0
  description: API for article search
#    _Changelog_
#    - **1.3.0**
#      - solo strategy serp: tag è ora parametro QS
#    - **1.2.0**
#      - refactoring controller Finder >> Search
#    - **1.1.0**
#      - Introduced `tags` strategy
#      - Introduced results caching
#    - **1.0.0**
#      - Initial API version
#      - `serp` strategy
servers:
  - url: https://api-staging.sharin.app
    description: Staging server
  - url: https://api.sharin.app
    description: Production server
  - url: http://api.sharinapp.local
    description: Local development server (used in tests)

security:
  - ApiKeyAuth: []

paths:
  /v1/articles:
    get:
      summary: Generic platform-level search, regardless of store affiliation
      operationId: globalSearch
      security:
        - ApiKeyAuth: []
      parameters:
        - $ref: './schemas/CommonSchemas.yaml#/ServerParamHeader'
        - $ref: './schemas/CommonSchemas.yaml#/LangParamHeader'

        - $ref: '#/components/parameters/StrategyParam'
        - $ref: '#/components/parameters/TagsQueryParam'
        - $ref: '#/components/parameters/SearchQueryParam'
        - $ref: '#/components/parameters/SortQueryParam'
        - $ref: '#/components/parameters/LimitQueryParam'
        - $ref: '#/components/parameters/OffsetQueryParam'
        - $ref: '#/components/parameters/CategoryCodeQueryParam'
        - $ref: '#/components/parameters/PriceMinQueryParam'
        - $ref: '#/components/parameters/PriceMaxQueryParam'
        - $ref: '#/components/parameters/BrandQueryParam'
#        - $ref: '#/components/parameters/TimeframeQueryParam'

      tags:
        - Articles
      responses:
        '200':
          description: Search results
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SearchResponse'
        default:
          description: Request error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

  /v1/articles/{identifier}:
    get:
      tags:
        - Articles
      summary: Retrieve article details by ID or slug
      description: Returns the full details of an article identified by its ID or slug.
      operationId: getArticleByIdentifier
      security:
        - ApiKeyAuth: []
      parameters:
        - $ref: './schemas/CommonSchemas.yaml#/ServerParamHeader'
        - $ref: './schemas/CommonSchemas.yaml#/LangParamHeader'

        - $ref: '#/components/parameters/IDOverSlugQueryParam'

      responses:
        '200':
          description: Article details retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ArticleDetail'
        default:
          description: Request error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-KEY
  parameters:
    StrategyParam:
      name: strategy
      in: query
      schema:
        type: string
        enum: [serp] # best-sellers, entrypoint, trending, random
        default: serp
      description: Search strategy/algorithm to apply

    SearchQueryParam:
      name: q
      in: query
      required: false
      schema:
        type: string
        maxLength: 200
      description: Search query text
    SortQueryParam:
      name: sort
      in: query
      required: false
      schema:
        type: string
        enum: [ price_asc, price_desc] # relevance, newest, rating,
      description: Applied if allowed by the strategy (strategy-dependent)
    LimitQueryParam:
      name: limit
      in: query
      required: false
      schema:
        type: integer
        minimum: 1
        maximum: 100
        default: 20
      description: Number of results to return
    OffsetQueryParam:
      name: offset
      in: query
      required: false
      schema:
        type: integer
        minimum: 0
        default: 0
      description: Pagination offset
    CategoryCodeQueryParam:
      name: category
      in: query
      required: false
      schema:
        type: string
      description: Filter by category code

    PriceMinQueryParam:
      name: price_min
      in: query
      required: false
      schema:
        type: number
        format: float
        minimum: 0
      description: Minimum price filter
    PriceMaxQueryParam:
      name: price_max
      in: query
      required: false
      schema:
        type: number
        format: float
        minimum: 0
      description: Maximum price filter
    BrandQueryParam:
      name: brand
      in: query
      required: false
      schema:
        type: string
      description: Filter by brand name
    IDOverSlugQueryParam:
      name: identifier
      in: path
      description: Article ID or slug
      required: true
      schema:
        type: string
    TagsQueryParam:
      name: tags
      in: query
      required: false
      description: |
        Filter by set of tags id or name.
        Send always the same type of data.
      schema:
        oneOf:
          - type: string
            description: Comma separated string of tags
          - type: array
            description: Array of tags
            items:
              type: string

#    TimeframeQueryParam:
#      name: timeframe
#      in: query
#      required: false
#      schema:
#        type: string
#        enum: [day, week, month]
#      description: Timeframe for trending strategy (trending strategy only)

  schemas:
    SearchResponse:
      type: object
      required:
        - meta
        - data
      properties:
        data:
          type: array
          description: Array of search results
          items:
            $ref: '#/components/schemas/Article'
        meta:
          allOf:
            - $ref: './schemas/CommonSchemas.yaml#/MetaDefaultResponse'
            - type: object
              properties:
                engine:
                  type: string
                  description: Indicates whether the search used database tables (`sql`) or Elasticsearch indexes (`elastic`)
                  example: "sql"
                total:
                  type: integer
                  description: Total count of available results
                  example: 1523
                count:
                  type: integer
                  description: Number of items in this response batch
                  example: 20
                limit:
                  type: integer
                  description: Pagination limit applied
                  example: 20
                offset:
                  type: integer
                  description: Pagination offset applied
                  example: 0
                has_more:
                  type: boolean
                  description: Whether more results exist beyond this batch
                  example: true
                strategy:
                  type: string
                  enum: [serp, random]
                  description: Search strategy applied
                  example: "best-sellers"
                resource_type:
                  type: string
                  enum: [product, category]
                  description: Type of resource searched
                  example: "product"
                pagination:
                  type: array
                  description: Pagination of the searched resource
#                facets:
#                  type: array
#                  description: Facets of the searched resource
                filters:
                  type: object
                  description: Filters actually applied in the search (i.e. non-empty SearchQueryParam values)
                  example:
                    q: "laptop"
                    category: "electronics"
                    price_min: 300
    DetailResponse:
      type: object
      required:
        - meta
        - data
      properties:
        data:
          type: array
          description: Article detail data
          items:
            $ref: '#/components/schemas/ArticleDetail'
        meta:
          allOf:
            - $ref: './schemas/CommonSchemas.yaml#/MetaDefaultResponse'
            - type: object
              properties:
                entity:
                  type: object
                  properties:
                    reselling:
                      type: string
                      example: ""
                    default_replacement:
                      type: string
                      example: "0"
                    created_at:
                      type: string
                      format: date-time
                      example: "2025-12-05T13:50:25+01:00"
                    updated_at:
                      type: string
                      format: date-time
                      example: "2025-12-05T22:02:33+01:00"
                    status:
                      type: string
                      example: "1"
                  required:
                    - reselling
                    - default_replacement
                    - created_at
                    - updated_at
                    - status


    Article:
      $ref: './schemas/article.yaml#/Article'
    ArticleDetail:
      $ref: './schemas/detail.yaml#/ArticleDetail'
    ErrorResponse:
      $ref: './schemas/CommonSchemas.yaml#/ErrorResponse'

