openapi: 3.1.0

# ============================================================================
# RISE Mini API - machine-readable contract (REQ-API-2)
#
# This file is the spec-first teaching artifact for the Innovation Day
# "Spec-First Build" session. It is intentionally PARTIAL:
#   - /compare   is FULLY specified - use it as the worked example.
#   - /recommend is DELIBERATELY incomplete - your team authors its response
#     schema FROM the product spec before writing any implementation code.
#
# Standard cited inline as (REQ-API-n) - see
# docs/corporate-standards-main/standards/architecture/requirements/01-API-Design-Requirements.md
# Keep this file in sync with the implementation (REQ-API-2).
# ============================================================================

info:
  title: RISE Mini API
  version: 1.0.0                     # explicit, governed version (REQ-API-4)
  description: >
    Assessment dashboard API for RISE Mini. Implemented identically by both
    stacks (Next.js, Spring Boot). The current user is hardcoded as
    `user-alice` (no auth in this teaching app). This contract covers the two
    Feature-Sprint endpoints; the three existing endpoints (scores, lessons,
    complete) are documented in API-CONTRACT.md.

servers:
  - url: /api                        # version would normally live here as /v1 (REQ-API-4)

paths:
  # --------------------------------------------------------------------------
  # WORKED EXAMPLE - fully specified. Read this to learn the shape, then write
  # /recommend the same way.
  # --------------------------------------------------------------------------
  /compare:
    get:
      operationId: compareScores
      summary: Compare the current user's scores against team or org averages
      description: >
        Returns the current user's per-dimension scores alongside the average
        scores for the chosen scope. GET - safe and idempotent (REQ-API-6);
        no Idempotency-Key needed. If this became a write, REQ-API-6 would
        require an Idempotency-Key header for safe retries (see ADR).
      parameters:
        - name: scope
          in: query
          required: false
          description: Compare against the user's own team, or the whole org.
          schema:
            type: string
            enum: [team, org]        # consistent conventions (REQ-API-5)
            default: team
      responses:
        '200':
          description: Comparison data for the current user.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CompareResponse'
              examples:
                team:
                  summary: Alice (team=Platform) vs her team average
                  value:
                    user:
                      - { dimension: ai_literacy, label: AI Literacy, value: 0.72, responded: true }
                      - { dimension: workflow, label: Workflow/SDLC, value: 0.58, responded: true }
                    comparison:
                      - { dimension: ai_literacy, label: AI Literacy, value: 0.62, responded: true }
                      - { dimension: workflow, label: Workflow/SDLC, value: 0.63, responded: true }
                    scope: team
        default:                     # consistent error envelope (REQ-API-5)
          description: Error
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'

  # --------------------------------------------------------------------------
  # YOUR TASK - author the 200 response schema from the product spec, freeze it
  # at Gate 1, THEN implement. Rules (from API-CONTRACT.md):
  #   - return the top 5 recommendations
  #   - gapScore = 1.0 - userDimensionScore  (higher = bigger gap)
  #   - only recommend lessons the user has NOT completed
  #   - order by gapScore desc, then by lesson stage (exploring first)
  # Replace the TODO below with a real $ref to RecommendResponse and add that
  # schema under components/schemas.
  # --------------------------------------------------------------------------
  /recommend:
    get:
      operationId: recommendLessons
      summary: Recommend lessons based on the user's weakest dimensions
      description: >
        GET - safe and idempotent (REQ-API-6). Returns personalised lesson
        recommendations. Response schema is intentionally left for your team
        to specify (spec-first).
      responses:
        '200':
          description: Personalised recommendations.
          content:
            application/json:
              schema:
                type: object
                # TODO(team): replace with $ref to a RecommendResponse schema
                #             that you define in components/schemas, matching
                #             the rules in the comment above.
                description: TODO - specify this from the product spec at Gate 1.
        default:
          description: Error
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'

components:
  schemas:
    # Reusable building blocks (REQ-API-5 - consistent shapes, reused not copied)
    DimensionScore:
      type: object
      required: [dimension, label, value, responded]
      properties:
        dimension:
          type: string
          enum: [ai_literacy, workflow, tooling, governance, collaboration, business_impact]
        label:
          type: string
          example: AI Literacy
        value:
          type: number
          format: float
          minimum: 0.0
          maximum: 1.0
          description: 0.0 when responded is false (N/A).
        responded:
          type: boolean
          description: false means the user skipped this dimension (N/A).

    Lesson:
      type: object
      required: [id, title, description, dimension, stage, duration, module]
      properties:
        id: { type: string, example: lesson-16 }
        title: { type: string, example: Measuring AI Productivity }
        description: { type: string }
        dimension:
          type: string
          enum: [ai_literacy, workflow, tooling, governance, collaboration, business_impact]
        stage:
          type: string
          enum: [exploring, building, applying]
        duration: { type: integer, description: minutes, example: 10 }
        module: { type: string, example: Business Impact }

    CompareResponse:
      type: object
      required: [user, comparison, scope]
      properties:
        user:
          type: array
          items: { $ref: '#/components/schemas/DimensionScore' }
        comparison:
          type: array
          description: Average scores for the chosen scope.
          items: { $ref: '#/components/schemas/DimensionScore' }
        scope:
          type: string
          enum: [team, org]

    # Recommendation is provided as a hint - you still must wire it into a
    # RecommendResponse and reference it from /recommend.
    Recommendation:
      type: object
      required: [lesson, reason, gapScore]
      properties:
        lesson: { $ref: '#/components/schemas/Lesson' }
        reason:
          type: string
          example: Your Business Impact score (0.0) is your lowest dimension
        gapScore:
          type: number
          format: float
          minimum: 0.0
          maximum: 1.0
          description: 1.0 - userDimensionScore. Higher = bigger gap.

    # Shared error envelope reused by every error response (REQ-API-5).
    # RFC 7807 problem+json.
    Problem:
      type: object
      required: [title, status]
      properties:
        type: { type: string, format: uri, default: about:blank }
        title: { type: string, example: Not Implemented }
        status: { type: integer, example: 501 }
        detail: { type: string }
        instance: { type: string }
