openapi: 3.1.0
info:
  title: BATbern Topics API
  version: 1.0.0
  description: |
    Topic Management API for BATbern Event Management Platform.

    This API provides topic backlog management capabilities with:
    - **Topic CRUD Operations**: Create, read, update, delete topics
    - **Staleness Scoring**: Automatic and manual staleness score management
    - **Similarity Detection**: Cosine similarity scoring for duplicate detection
    - **Usage History**: Track topic usage across events
    - **Event Integration**: Select topics for events

    **Story 5.2**: Topic Selection and Backlog Management

  contact:
    name: BATbern Platform Team
    email: platform@batbern.ch
  license:
    name: Proprietary
    identifier: Proprietary

servers:
  - url: https://api.batbern.ch/api/v1
    description: Production
  - url: https://api.batbern.ch/api/v1
    description: Staging
  - url: http://localhost:8080/api/v1
    description: Development

tags:
  - name: Topics
    description: Topic management, staleness, and similarity analysis operations
  - name: Event Topics
    description: Topic selection for events
  - name: Topic Similarity
    description: Blob topic selector cluster classification (Story 10.4)
  - name: Topic Session Data
    description: Blob topic selector canvas bootstrap data (Story 10.4)

paths:
  /topics:
    get:
      tags:
        - Topics
      summary: List topics with filtering
      description: |
        Retrieve a paginated list of topics with optional filtering by category, status, and staleness.

        **Acceptance Criteria**: AC1 (Story 5.2)

        **Filter Syntax Examples**:
        - Category filter: `{"category":"Architecture"}`
        - Status filter: `{"status":"available"}`
        - Combined: `{"category":"Architecture","status":"available"}`

        **Include Options**:
        - `similarity`: Include similarity scores to other topics
        - `history`: Include usage history records

      operationId: listTopics
      parameters:
        - name: filter
          in: query
          description: MongoDB-style JSON filter criteria
          required: false
          schema:
            type: string
            example: '{"category":"Architecture"}'
        - name: sort
          in: query
          description: Sort field (prefix with - for descending)
          required: false
          schema:
            type: string
            example: '-stalenessScore'
        - name: page
          in: query
          description: Page number (1-indexed)
          required: false
          schema:
            type: integer
            default: 1
        - name: limit
          in: query
          description: Items per page (max 100)
          required: false
          schema:
            type: integer
            default: 50
            maximum: 100
        - name: include
          in: query
          description: Comma-separated resources to include (similarity, history)
          required: false
          schema:
            type: string
            example: 'similarity,history'
      responses:
        '200':
          description: Paginated list of topics
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TopicListResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'

    post:
      tags:
        - Topics
      summary: Create new topic
      description: |
        Create a new topic in the backlog.

        **Acceptance Criteria**: AC8 (Story 5.2)

        **Validation Rules**:
        - Title must be unique
        - Category is required
        - Keywords are optional but improve similarity matching

      operationId: createTopic
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateTopicRequest'
      responses:
        '201':
          description: Topic created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Topic'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '409':
          $ref: '#/components/responses/Conflict'

  /topics/{topicCode}:
    get:
      tags:
        - Topics
      summary: Get topic by code
      description: Retrieve a specific topic with optional includes
      operationId: getTopicByCode
      parameters:
        - name: topicCode
          in: path
          required: true
          description: Topic code (slug-format identifier)
          schema:
            type: string
            pattern: '^[a-z0-9-]+$'
            example: 'cloud-native-security-2024'
        - name: include
          in: query
          description: Comma-separated resources to include
          required: false
          schema:
            type: string
            example: 'similarity,history'
      responses:
        '200':
          description: Topic retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Topic'
        '404':
          $ref: '#/components/responses/NotFound'
        '401':
          $ref: '#/components/responses/Unauthorized'

    put:
      tags:
        - Topics
      summary: Update topic
      description: |
        Update an existing topic.

        **Story 5.2a**: Edit Topic Feature
      operationId: updateTopic
      parameters:
        - name: topicCode
          in: path
          required: true
          description: Topic code (slug-format identifier)
          schema:
            type: string
            pattern: '^[a-z0-9-]+$'
            example: 'cloud-native-security-2024'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateTopicRequest'
      responses:
        '200':
          description: Topic updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Topic'
        '400':
          $ref: '#/components/responses/BadRequest'
        '404':
          $ref: '#/components/responses/NotFound'
        '401':
          $ref: '#/components/responses/Unauthorized'

    delete:
      tags:
        - Topics
      summary: Delete topic
      description: |
        Delete a topic. Only allowed if topic has never been used.

        **Story 5.2a**: Delete Topic Feature
      operationId: deleteTopic
      parameters:
        - name: topicCode
          in: path
          required: true
          description: Topic code (slug-format identifier)
          schema:
            type: string
            pattern: '^[a-z0-9-]+$'
            example: 'cloud-native-security-2024'
      responses:
        '204':
          description: Topic deleted successfully
        '400':
          description: Topic has been used and cannot be deleted
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          $ref: '#/components/responses/NotFound'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /topics/{topicCode}/similar:
    get:
      tags:
        - Topics
      summary: Get similar topics
      description: |
        Get topics with >70% similarity for duplicate detection.

        **Acceptance Criteria**: AC5 (Story 5.2)
      operationId: getSimilarTopics
      parameters:
        - name: topicCode
          in: path
          required: true
          description: Topic code (slug-format identifier)
          schema:
            type: string
            pattern: '^[a-z0-9-]+$'
            example: 'cloud-native-security-2024'
      responses:
        '200':
          description: List of similar topics
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Topic'
        '404':
          $ref: '#/components/responses/NotFound'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /topics/{topicCode}/usage-history:
    get:
      tags:
        - Topics
      summary: Get topic usage history
      description: |
        Get usage history for heat map visualization.

        **Acceptance Criteria**: AC2 (Story 5.2)
      operationId: getTopicUsageHistory
      parameters:
        - name: topicCode
          in: path
          required: true
          description: Topic code (slug-format identifier)
          schema:
            type: string
            pattern: '^[a-z0-9-]+$'
            example: 'cloud-native-security-2024'
      responses:
        '200':
          description: Usage history records
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/TopicUsageHistory'
        '404':
          $ref: '#/components/responses/NotFound'
        '401':
          $ref: '#/components/responses/Unauthorized'


  /topics/calculate-similarities:
    post:
      tags:
        - Topics
      summary: Calculate similarity scores
      description: |
        Calculate similarity scores for all topics.

        **Acceptance Criteria**: AC4 (Story 5.2)

        **Authorization**: ORGANIZER role required
      operationId: calculateSimilarities
      responses:
        '200':
          description: Calculation completed
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: 'Similarity scores calculated for 42 topics'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  /events/{eventCode}/topics:
    post:
      tags:
        - Event Topics
      summary: Select topic for event
      description: |
        Select a topic for an event and transition workflow state.

        **Acceptance Criteria**: AC14 (Story 5.2)
      operationId: selectTopicForEvent
      parameters:
        - name: eventCode
          in: path
          required: true
          description: Event code (e.g., BATbern56)
          schema:
            type: string
            example: 'BATbern56'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SelectTopicForEventRequest'
      responses:
        '200':
          description: Topic selected for event
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TopicSelectionResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '404':
          $ref: '#/components/responses/NotFound'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  /events/{eventCode}/topic-similarity:
    post:
      tags:
        - Topic Similarity
      summary: Classify a topic into a BATbern cluster
      description: |
        Classify a free-form topic text into a BATbern cluster and return related past event
        numbers, used by the blob topic selector canvas to place green blobs and ignite red stars.

        **Story 10.4** (AC32). The eventCode path segment is contextual only — classification
        depends solely on the topic text.

        **Authorization**: ORGANIZER role required
      operationId: getTopicSimilarity
      parameters:
        - name: eventCode
          in: path
          required: true
          description: Event code the topic is being evaluated for (contextual only)
          schema:
            type: string
            example: 'BATbern58'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TopicSimilarityRequest'
      responses:
        '200':
          description: Cluster affinity data for the topic
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TopicSimilarityResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  /events/{eventCode}/topic-session-data:
    get:
      tags:
        - Topic Session Data
      summary: Bootstrap data for the blob topic selector canvas
      description: |
        Return all data needed to bootstrap the blob topic selector canvas in one call:
        partner topics (green blobs), past events (red stars), organizer backlog (ghost blobs),
        and AI-generated trending topics (gold shimmer ghosts).

        **Story 10.4** (AC29–31). Each source degrades gracefully to an empty list on failure.
        The eventCode path segment is contextual only.

        **Authorization**: ORGANIZER role required
      operationId: getTopicSessionData
      parameters:
        - name: eventCode
          in: path
          required: true
          description: Event code the canvas is being opened for (contextual only)
          schema:
            type: string
            example: 'BATbern58'
      responses:
        '200':
          description: Aggregated canvas bootstrap data
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TopicSessionDataResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

components:
  schemas:
    TopicSimilarityRequest:
      type: object
      description: Request body for topic cluster classification (Story 10.4 AC32)
      required:
        - topic
      properties:
        topic:
          type: string
          minLength: 1
          description: Free-form topic text to classify
          example: 'AI Agents in Enterprise'
    TopicSimilarityResponse:
      type: object
      description: Cluster affinity data driving the blob canvas (Story 10.4 AC32)
      required:
        - cluster
        - similarityScore
        - relatedPastEventNumbers
      properties:
        cluster:
          type: string
          description: BATbern cluster name (e.g. AI_ML, SECURITY, CLOUD_INFRA, BUSINESS_OTHER)
          example: 'AI_ML'
        similarityScore:
          type: number
          format: double
          description: Confidence 0.0–1.0 that the topic belongs to this cluster
          example: 0.85
        relatedPastEventNumbers:
          type: array
          description: BATbern event numbers in the same cluster (drives red-star ignition)
          items:
            type: integer
          example: [40, 44, 49, 56, 58]
    TopicSessionDataResponse:
      type: object
      description: Aggregated bootstrap data for the blob topic selector canvas (Story 10.4 AC29–31)
      required:
        - partnerTopics
        - pastEvents
        - organizerBacklog
        - trendingTopics
      properties:
        partnerTopics:
          type: array
          description: Partner topics grouped by company (green blobs)
          items:
            $ref: '#/components/schemas/PartnerTopicGroup'
        pastEvents:
          type: array
          description: Past BATbern events with cluster classification (red star blobs)
          items:
            $ref: '#/components/schemas/PastEventEntry'
        organizerBacklog:
          type: array
          description: Available topics from the organizer's backlog (ghost blobs)
          items:
            $ref: '#/components/schemas/BacklogItem'
        trendingTopics:
          type: array
          description: AI-generated trending IT topics (gold shimmer ghost blobs)
          items:
            type: string
    PartnerTopicGroup:
      type: object
      description: Partner topic suggestions grouped by company
      required:
        - companyName
        - topics
      properties:
        companyName:
          type: string
          description: Partner company name
        logoUrl:
          type: string
          description: Company logo URL (may be null when not available)
        topics:
          type: array
          items:
            $ref: '#/components/schemas/TopicEntry'
    TopicEntry:
      type: object
      description: A single partner topic suggestion enriched with cluster, votes, and date
      required:
        - title
        - cluster
        - voteCount
        - createdAt
      properties:
        title:
          type: string
        cluster:
          type: string
          description: BatbernCluster name the topic was classified into
        voteCount:
          type: integer
          description: Number of partner votes cast on this topic suggestion
        createdAt:
          type: string
          format: date-time
          description: When the topic was first submitted (recency proxy for attraction strength)
    BacklogItem:
      type: object
      description: An available topic from the organizer's backlog (ghost blob)
      required:
        - title
        - topicCode
        - stalenessScore
      properties:
        title:
          type: string
        topicCode:
          type: string
          description: Stable slug identifier (e.g. cloud-native-security-2024)
        stalenessScore:
          type: integer
          description: Staleness score 0–100 (all backlog items >= 83); sizes the ghost blob
    PastEventEntry:
      type: object
      description: A past BATbern event with cluster classification (red star blob)
      required:
        - eventNumber
        - topicName
        - cluster
      properties:
        eventNumber:
          type: integer
        topicName:
          type: string
        cluster:
          type: string
    Topic:
      type: object
      description: Topic entity for event management
      required:
        - topicCode
        - title
        - category
        - stalenessScore
        - colorZone
        - status
      properties:
        topicCode:
          type: string
          description: Topic unique identifier (slug-format)
          pattern: '^[a-z0-9-]+$'
          example: 'cloud-native-security-2024'
        title:
          type: string
          description: Topic title
          example: 'Cloud Native Security Patterns'
        description:
          type: string
          description: Detailed topic description
          example: 'Best practices for securing cloud-native applications'
        category:
          type: string
          description: Topic category
          example: 'Security'
        createdDate:
          type: string
          format: date-time
          description: When the topic was created
        lastUsedDate:
          type: string
          format: date-time
          nullable: true
          description: When the topic was last used in an event
        usageCount:
          type: integer
          description: Number of times topic has been used
          example: 3
        stalenessScore:
          type: integer
          minimum: 0
          maximum: 100
          description: Staleness score (0-100, higher = safer to reuse)
          example: 75
        colorZone:
          $ref: '#/components/schemas/TopicColorZone'
        status:
          $ref: '#/components/schemas/TopicStatus'
        similarityScores:
          type: array
          description: Similarity scores to other topics
          items:
            $ref: '#/components/schemas/SimilarityScore'
        active:
          type: boolean
          description: Whether the topic is active
          default: true
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        usageHistory:
          type: array
          description: Usage history (populated when include=history)
          items:
            $ref: '#/components/schemas/TopicUsageHistory'

    TopicColorZone:
      type: string
      description: Color coding for topic freshness visualization
      enum:
        - red
        - yellow
        - green
        - gray
      example: 'green'

    TopicStatus:
      type: string
      description: Topic availability status
      enum:
        - AVAILABLE
        - CAUTION
        - UNAVAILABLE
      example: 'AVAILABLE'

    SimilarityScore:
      type: object
      description: Cosine similarity score to another topic
      required:
        - topicCode
        - score
      properties:
        topicCode:
          type: string
          description: Code of the similar topic (slug-format)
          pattern: '^[a-z0-9-]+$'
          example: 'cloud-architecture-patterns'
        score:
          type: number
          format: float
          minimum: 0
          maximum: 1
          description: Cosine similarity score (0-1)
          example: 0.85

    TopicUsageHistory:
      type: object
      description: Record of topic usage in an event
      required:
        - eventNumber
        - usedDate
        - attendance
        - engagementScore
      properties:
        eventNumber:
          type: integer
          description: Event number (e.g., 56 for BATbern56)
          example: 56
        eventCode:
          type: string
          description: Human-readable event code
          example: 'BATbern56'
        eventDate:
          type: string
          format: date
          description: Event date (ISO 8601)
          example: '2025-03-15'
        usedDate:
          type: string
          format: date-time
          description: When the topic was used
        attendance:
          type: integer
          description: Attendance count for this topic's session
          example: 120
        engagementScore:
          type: number
          format: float
          minimum: 0
          maximum: 1
          description: Engagement score (0-1)
          example: 0.78

    TopicListResponse:
      type: object
      required:
        - data
        - pagination
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/Topic'
        pagination:
          $ref: '#/components/schemas/PaginationMetadata'

    PaginationMetadata:
      $ref: './_shared.openapi.yml#/components/schemas/PaginationMetadata'
    CreateTopicRequest:
      type: object
      required:
        - title
        - category
      properties:
        title:
          type: string
          description: Topic title (must be unique)
          maxLength: 500
          example: 'Cloud Native Security Patterns'
        description:
          type: string
          description: Detailed topic description
          maxLength: 5000
        category:
          type: string
          description: Topic category
          example: 'Security'
        # Note: keywords and relatedTopics were removed during field reconciliation
        # (not implemented in current backend). Can be re-added when feature is implemented.

    SelectTopicForEventRequest:
      type: object
      required:
        - topicCode
      properties:
        topicCode:
          type: string
          description: Code of the topic to select (slug-format)
          pattern: '^[a-z0-9-]+$'
          example: 'cloud-native-security-2024'
        justification:
          type: string
          description: Optional justification for selection

    TopicSelectionResponse:
      type: object
      description: Response after selecting a topic for an event
      required:
        - eventCode
        - topicCode
        - workflowState
        - message
      properties:
        eventCode:
          type: string
          description: Event code
          example: 'BATbern56'
        topicCode:
          type: string
          description: Selected topic code
          pattern: '^[a-z0-9-]+$'
          example: 'cloud-native-security-2024'
        workflowState:
          type: string
          description: Event workflow state after topic selection
          example: 'SPEAKER_BRAINSTORMING'
        message:
          type: string
          description: Success message
          example: 'Topic selected successfully'

    ErrorResponse:
      $ref: './_shared.openapi.yml#/components/schemas/ErrorResponse'
  responses:
    BadRequest:
      description: Bad request - validation error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    Unauthorized:
      description: Unauthorized - missing or invalid JWT token
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    Forbidden:
      description: Forbidden - insufficient permissions
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    Conflict:
      description: Conflict - resource already exists
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'

  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: JWT token from AWS Cognito

security:
  - bearerAuth: []
